Skip to content

Commit

Permalink
Merge branch 'master' into blake.newman/make-vue-compiler-sfc-optional
Browse files Browse the repository at this point in the history
  • Loading branch information
byara committed Nov 24, 2022
2 parents 157c7f9 + 0dad01d commit a8635e3
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ Want to highlight your project or company ? Adding your project / company name w
Feel free to make a Pull Request to add your project / company name.

- [trivago](https://company.trivago.com)
- ADD YOUR PROJECT / COMPANY NAME
- [AuresKonnect](https://aures.com)

### Contribution

Expand Down
22 changes: 8 additions & 14 deletions src/preprocessors/preprocessor.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ParserOptions, parse as babelParser } from '@babel/parser';
import traverse, { NodePath } from '@babel/traverse';
import { ImportDeclaration, isTSModuleDeclaration } from '@babel/types';
import { Directive, ImportDeclaration } from '@babel/types';

import { PrettierOptions } from '../types';
import { extractASTNodes } from '../utils/extract-ast-nodes';
import { getCodeFromAst } from '../utils/get-code-from-ast';
import { getExperimentalParserPlugins } from '../utils/get-experimental-parser-plugins';
import { getSortedNodes } from '../utils/get-sorted-nodes';
Expand All @@ -17,7 +17,6 @@ export function preprocessor(code: string, options: PrettierOptions) {
importOrderSortSpecifiers,
} = options;

const importNodes: ImportDeclaration[] = [];
const parserOptions: ParserOptions = {
sourceType: 'module',
plugins: getExperimentalParserPlugins(importOrderParserPlugins),
Expand All @@ -26,16 +25,11 @@ export function preprocessor(code: string, options: PrettierOptions) {
const ast = babelParser(code, parserOptions);
const interpreter = ast.program.interpreter;

traverse(ast, {
ImportDeclaration(path: NodePath<ImportDeclaration>) {
const tsModuleParent = path.findParent((p) =>
isTSModuleDeclaration(p),
);
if (!tsModuleParent) {
importNodes.push(path.node);
}
},
});
const {
importNodes,
directives,
}: { importNodes: ImportDeclaration[]; directives: Directive[] } =
extractASTNodes(ast);

// short-circuit if there are no import declaration
if (importNodes.length === 0) return code;
Expand All @@ -48,5 +42,5 @@ export function preprocessor(code: string, options: PrettierOptions) {
importOrderSortSpecifiers,
});

return getCodeFromAst(allImports, code, interpreter);
return getCodeFromAst(allImports, directives, code, interpreter);
}
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { RequiredOptions } from 'prettier';

import { PluginConfig } from '../types';

export interface PrettierOptions extends PluginConfig, RequiredOptions {}
export interface PrettierOptions
extends Required<PluginConfig>,
RequiredOptions {}

export type ImportGroups = Record<string, ImportDeclaration[]>;
export type ImportOrLine = ImportDeclaration | ExpressionStatement;
Expand Down
32 changes: 31 additions & 1 deletion src/utils/__tests__/get-code-from-ast.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { parse as babelParser } from '@babel/core';
import { ParserOptions } from '@babel/parser';
import { format } from 'prettier';

import { extractASTNodes } from '../extract-ast-nodes';
import { getCodeFromAst } from '../get-code-from-ast';
import { getExperimentalParserPlugins } from '../get-experimental-parser-plugins';
import { getImportNodes } from '../get-import-nodes';
import { getSortedNodes } from '../get-sorted-nodes';

Expand All @@ -22,7 +26,7 @@ import a from 'a';
importOrderGroupNamespaceSpecifiers: false,
importOrderSortSpecifiers: false,
});
const formatted = getCodeFromAst(sortedNodes, code, null);
const formatted = getCodeFromAst(sortedNodes, [], code, null);
expect(format(formatted, { parser: 'babel' })).toEqual(
`// first comment
// second comment
Expand All @@ -35,3 +39,29 @@ import z from "z";
`,
);
});

test('it renders directives correctly', () => {
const code = `
"use client";
// first comment
import b from 'b';
import a from 'a';`;

const parserOptions: ParserOptions = {
sourceType: 'module',
plugins: getExperimentalParserPlugins([]),
};
const ast = babelParser(code, parserOptions);
if (!ast) throw new Error('ast is null');
const { directives, importNodes } = extractASTNodes(ast);

const formatted = getCodeFromAst(importNodes, directives, code, null);
expect(format(formatted, { parser: 'babel' })).toEqual(
`"use client";
// first comment
import b from "b";
import a from "a";
`,
);
});
31 changes: 31 additions & 0 deletions src/utils/extract-ast-nodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ParseResult } from '@babel/parser';
import traverse, { NodePath } from '@babel/traverse';
import {
Directive,
File,
ImportDeclaration,
isTSModuleDeclaration,
} from '@babel/types';

export function extractASTNodes(ast: ParseResult<File>) {
const importNodes: ImportDeclaration[] = [];
const directives: Directive[] = [];
traverse(ast, {
Directive({ node }) {
directives.push(node);

// Trailing comments probably shouldn't be attached to the directive
node.trailingComments = null;
},

ImportDeclaration(path: NodePath<ImportDeclaration>) {
const tsModuleParent = path.findParent((p) =>
isTSModuleDeclaration(p),
);
if (!tsModuleParent) {
importNodes.push(path.node);
}
},
});
return { importNodes, directives };
}
6 changes: 4 additions & 2 deletions src/utils/get-code-from-ast.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import generate from '@babel/generator';
import { InterpreterDirective, Statement, file } from '@babel/types';
import { Directive, InterpreterDirective, Statement, file } from '@babel/types';

import { newLineCharacters } from '../constants';
import { getAllCommentsFromNodes } from './get-all-comments-from-nodes';
Expand All @@ -12,12 +12,14 @@ import { removeNodesFromOriginalCode } from './remove-nodes-from-original-code';
*/
export const getCodeFromAst = (
nodes: Statement[],
directives: Directive[],
originalCode: string,
interpreter?: InterpreterDirective | null,
) => {
const allCommentsFromImports = getAllCommentsFromNodes(nodes);

const nodesToRemoveFromCode = [
...directives,
...nodes,
...allCommentsFromImports,
...(interpreter ? [interpreter] : []),
Expand All @@ -31,7 +33,7 @@ export const getCodeFromAst = (
const newAST = file({
type: 'Program',
body: nodes,
directives: [],
directives,
sourceType: 'module',
interpreter: interpreter,
sourceFile: '',
Expand Down
2 changes: 2 additions & 0 deletions src/utils/remove-nodes-from-original-code.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
CommentBlock,
CommentLine,
Directive,
ImportDeclaration,
InterpreterDirective,
Statement,
Expand All @@ -21,6 +22,7 @@ export const removeNodesFromOriginalCode = (
nodes: (
| Statement
| CommentBlock
| Directive
| CommentLine
| ImportDeclaration
| InterpreterDirective
Expand Down
23 changes: 23 additions & 0 deletions tests/ImportsNotSeparated/__snapshots__/ppsi.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,29 @@ function add(a: number, b: number) {
`;

exports[`imports-with-directives.ts - typescript-verify: imports-with-directives.ts 1`] = `
'use strict';
'use client';
import otherthing from "@core/otherthing";
import abc from "@core/abc";
// Comment
function add(a:number,b:number) {
return a + b;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"use strict";
"use client";
import abc from "@core/abc";
import otherthing from "@core/otherthing";
// Comment
function add(a: number, b: number) {
return a + b;
}
`;

exports[`imports-with-file-level-comments.ts - typescript-verify: imports-with-file-level-comments.ts 1`] = `
//@ts-ignore
// I am file top level comments
Expand Down
8 changes: 8 additions & 0 deletions tests/ImportsNotSeparated/imports-with-directives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';
'use client';
import otherthing from "@core/otherthing";
import abc from "@core/abc";
// Comment
function add(a:number,b:number) {
return a + b;
}
29 changes: 29 additions & 0 deletions tests/ImportsSeparated/__snapshots__/ppsi.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,35 @@ function add(a: number, b: number) {
`;

exports[`imports-with-directives.ts - typescript-verify: imports-with-directives.ts 1`] = `
'use strict';
'use client';
// comment after directives
import otherthing from "@core/otherthing";
import abc from "@core/abc";
// Comment
function add(a:number,b:number) {
return a + b;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"use strict";
"use client";
// comment after directives
import abc from "@core/abc";
import otherthing from "@core/otherthing";
// Comment
function add(a: number, b: number) {
return a + b;
}
`;

exports[`imports-with-file-level-comments.ts - typescript-verify: imports-with-file-level-comments.ts 1`] = `
//@ts-ignore
// I am file top level comments
Expand Down
12 changes: 12 additions & 0 deletions tests/ImportsSeparated/imports-with-directives.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';
'use client';

// comment after directives
import otherthing from "@core/otherthing";
import abc from "@core/abc";

// Comment

function add(a:number,b:number) {
return a + b;
}
96 changes: 90 additions & 6 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,97 @@
import { ParserPlugin } from '@babel/parser';
import { Config } from 'prettier';

export type ImportOrderParserPlugin =
| Extract<ParserPlugin, string>
| `[${string},${string}]`;

export interface PluginConfig {
/**
* A collection of Regular expressions in string format.
*
* ```
* "importOrder": ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
* ```
*
* _Default behavior:_ The plugin moves the third party imports to the top which are not part of the `importOrder` list.
* To move the third party imports at desired place, you can use `<THIRD_PARTY_MODULES>` to assign third party imports to the appropriate position:
*
* ```
* "importOrder": ["^@core/(.*)$", "<THIRD_PARTY_MODULES>", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
* ```
*/
importOrder: string[];
importOrderCaseInsensitive: boolean;
// should be of type ParserPlugin from '@babel/parser' but prettier does not support nested arrays in options
importOrderParserPlugins: string[];
importOrderSeparation: boolean;
importOrderGroupNamespaceSpecifiers: boolean;
importOrderSortSpecifiers: boolean;

/**
* A boolean value to enable or disable the new line separation
* between sorted import declarations group. The separation takes place according to the `importOrder`.
*
* @default false
*/
importOrderSeparation?: boolean;

/**
* A boolean value to enable or disable sorting of the specifiers in an import declarations.
*
* @default false
*/
importOrderSortSpecifiers?: boolean;

/**
* A boolean value to enable or disable sorting the namespace specifiers to the top of the import group.
*
* @default false
*/
importOrderGroupNamespaceSpecifiers?: boolean;

/**
* A boolean value to enable case-insensitivity in the sorting algorithm
used to order imports within each match group.
*
* For example, when false (or not specified):
*
* ```js
* import ExampleView from './ExampleView';
* import ExamplesList from './ExamplesList';
* ```
*
* compared with `"importOrderCaseInsensitive": true`:
*
* ```js
* import ExamplesList from './ExamplesList';
* import ExampleView from './ExampleView';
* ```
*
* @default false
*/
importOrderCaseInsensitive?: boolean;

/**
* Previously known as `experimentalBabelParserPluginsList`.
*
* A collection of plugins for babel parser. The plugin passes this list to babel parser, so it can understand the syntaxes
* used in the file being formatted. The plugin uses prettier itself to figure out the parser it needs to use but if that fails,
* you can use this field to enforce the usage of the plugins' babel parser needs.
*
* **To pass the plugins to babel parser**:
*
* ```
* "importOrderParserPlugins" : ["classProperties", "decorators-legacy"]
* ```
*
* **To pass the options to the babel parser plugins**: Since prettier options are limited to string, you can pass plugins
* with options as a JSON string of the plugin array:
* `"[\"plugin-name\", { \"pluginOption\": true }]"`.
*
* ```
* "importOrderParserPlugins" : ["classProperties", "[\"decorators\", { \"decoratorsBeforeExport\": true }]"]
* ```
*
* **To disable default plugins for babel parser, pass an empty array**:
*
* @default ["typescript", "jsx"]
*/
importOrderParserPlugins?: ImportOrderParserPlugin[];
}

export type PrettierConfig = PluginConfig & Config;

0 comments on commit a8635e3

Please sign in to comment.