Skip to content

Commit 624bac6

Browse files
authored
Be more tolerant of babel parse errors (#230)
Closes #219 Closes #222 This change makes our babel parsing and node traversal more tolerant of errors, matching the settings and behavior of Prettier itself. Now, rather than this plugin causing an error and failing to format the file, it will continue to attempt to sort imports. It may still fail on invalid code, but in those cases prettier itself would as well, so we shouldn't end up in a case where prettier runs but imports aren't sorted, or where prettier would have run as long as this plugin wasn't being used. I chose not to emit a warning when invalid syntax is encountered, again matching the behavior or prettier. I don't think it's the responsibility of a import sorting plugin to alert the user to invalid syntax, since it may be intentional and handled later-on in their build pipeline (for instance, Astro files allow returning from the top-level).
1 parent 040fa5e commit 624bac6

File tree

7 files changed

+93
-5
lines changed

7 files changed

+93
-5
lines changed

src/preprocessors/preprocessor.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export function preprocessor(code: string, options: PrettierOptions): string {
1414
const parserOptions: ParserOptions = {
1515
sourceType: 'module',
1616
attachComment: true,
17+
errorRecovery: true,
18+
allowReturnOutsideFunction: true,
19+
allowNewTargetOutsideFunction: true,
20+
allowSuperOutsideMethod: true,
21+
allowUndeclaredExports: true,
1722
plugins,
1823
};
1924

@@ -22,11 +27,6 @@ export function preprocessor(code: string, options: PrettierOptions): string {
2227
return code;
2328
}
2429

25-
// Astro component scripts allow returning a response
26-
if (options.parentParser === 'astro') {
27-
parserOptions.allowReturnOutsideFunction = true;
28-
}
29-
3030
let ast: ReturnType<typeof babelParser>;
3131
try {
3232
ast = babelParser(code, parserOptions);
@@ -43,10 +43,12 @@ export function preprocessor(code: string, options: PrettierOptions): string {
4343

4444
const allOriginalImportNodes: ImportDeclaration[] = [];
4545
traverse(ast, {
46+
noScope: true, // This is required in order to avoid traverse errors if a variable is redefined (https://github.com/babel/babel/issues/12950#issuecomment-788974837)
4647
ImportDeclaration(path: NodePath<ImportDeclaration>) {
4748
const tsModuleParent = path.findParent((p) =>
4849
isTSModuleDeclaration(p.node),
4950
);
51+
// Do not sort imports inside of typescript module declarations. See `import-inside-ts-declare.ts` test.
5052
if (!tsModuleParent) {
5153
allOriginalImportNodes.push(path.node);
5254
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`invalidSet.ts - typescript-verify > invalidSet.ts 1`] = `
4+
import b from './b';
5+
import a from './a';
6+
7+
const c = {set name(){}}
8+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9+
import a from "./a";
10+
import b from "./b";
11+
12+
const c = { set name() {} };
13+
14+
`;
15+
16+
exports[`redeclare.js - typescript-verify > redeclare.js 1`] = `
17+
import b from './b';
18+
import a from './a';
19+
20+
// Here's an invalid example of redeclaring a variable
21+
let name = "error" ;
22+
let name = "error";
23+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24+
import a from "./a";
25+
import b from "./b";
26+
27+
// Here's an invalid example of redeclaring a variable
28+
let name = "error";
29+
let name = "error";
30+
31+
`;
32+
33+
exports[`returnOutsideFunction.ts - typescript-verify > returnOutsideFunction.ts 1`] = `
34+
import b from './b';
35+
import a from './a';
36+
37+
// Can't return outside of a function
38+
return 123;
39+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40+
import a from "./a";
41+
import b from "./b";
42+
43+
// Can't return outside of a function
44+
return 123;
45+
46+
`;
47+
48+
exports[`superOutsideMethod.ts - typescript-verify > superOutsideMethod.ts 1`] = `
49+
import b from './b';
50+
import a from './a';
51+
52+
function F() { super(); }
53+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54+
import a from "./a";
55+
import b from "./b";
56+
57+
function F() {
58+
super();
59+
}
60+
61+
`;

tests/InvalidSyntax/invalidSet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import b from './b';
2+
import a from './a';
3+
4+
const c = {set name(){}}

tests/InvalidSyntax/ppsi.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { run_spec } from '../../test-setup/run_spec';
2+
3+
run_spec(__dirname, ['typescript'], {
4+
importOrder: ['^@core/(.*)$', '^@server/(.*)', '^@ui/(.*)$', '^[./]'],
5+
importOrderParserPlugins : ['typescript'],
6+
});

tests/InvalidSyntax/redeclare.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import b from './b';
2+
import a from './a';
3+
4+
// Here's an invalid example of redeclaring a variable
5+
let name = "error" ;
6+
let name = "error";
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import b from './b';
2+
import a from './a';
3+
4+
// Can't return outside of a function
5+
return 123;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import b from './b';
2+
import a from './a';
3+
4+
function F() { super(); }

0 commit comments

Comments
 (0)