Skip to content

Commit d2c67ac

Browse files
Merge pull request #104 from ember-tooling/thow-usable-eslint-error
throw useful error message for eslint
2 parents 257787c + 4a66532 commit d2c67ac

File tree

6 files changed

+84
-5
lines changed

6 files changed

+84
-5
lines changed

scripts/eslint-plugin-ember-test.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ await fse.ensureDir(FOLDERS.testRoot);
1313

1414
// Using pnpm instead of yarn, because pnpm is way faster
1515
await execaCommand(`git clone ${REPO}`, { cwd: FOLDERS.testRoot, stdio: 'inherit' });
16-
await execaCommand(`pnpm import`, { cwd: FOLDERS.repo, stdio: 'inherit' }); // project uses a yarn lockfile
1716
await execaCommand(`pnpm install`, { cwd: FOLDERS.repo, stdio: 'inherit' });
1817
await execaCommand(`pnpm add ${FOLDERS.here}`, { cwd: FOLDERS.repo, stdio: 'inherit' });
1918
await execaCommand(`pnpm run test`, { cwd: FOLDERS.repo, stdio: 'inherit' });

src/parser/gjs-gts-parser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = {
2929
patchTs();
3030
registerParsedFile(options.filePath);
3131
let jsCode = code;
32-
const info = transformForLint(code);
32+
const info = transformForLint(code, options.filePath);
3333
jsCode = info.output;
3434

3535
const isTypescript = options.filePath.endsWith('.gts') || options.filePath.endsWith('.ts');

src/parser/transforms.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,39 @@ module.exports.replaceRange = replaceRange;
567567

568568
const processor = new ContentTag.Preprocessor();
569569

570-
module.exports.transformForLint = function transformForLint(code) {
570+
class EmberParserError extends Error {
571+
constructor(message, fileName, location) {
572+
super(message);
573+
this.location = location;
574+
this.fileName = fileName;
575+
Object.defineProperty(this, 'name', {
576+
configurable: true,
577+
enumerable: false,
578+
value: new.target.name,
579+
});
580+
}
581+
582+
// For old version of ESLint https://github.com/typescript-eslint/typescript-eslint/pull/6556#discussion_r1123237311
583+
get index() {
584+
return this.location.start.offset;
585+
}
586+
587+
// https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L853
588+
get lineNumber() {
589+
return this.location.start.line;
590+
}
591+
592+
// https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L854
593+
get column() {
594+
return this.location.start.column;
595+
}
596+
}
597+
598+
function createError(code, message, fileName, start, end = start) {
599+
return new EmberParserError(message, fileName, { end, start });
600+
}
601+
602+
module.exports.transformForLint = function transformForLint(code, fileName) {
571603
let jsCode = code;
572604
/**
573605
*
@@ -593,7 +625,26 @@ module.exports.transformForLint = function transformForLint(code) {
593625
* };
594626
* }[]}
595627
*/
596-
const result = processor.parse(code);
628+
let result = null;
629+
try {
630+
result = processor.parse(code);
631+
} catch (e) {
632+
// Parse Error at <anon>:1:19: 1:19
633+
if (e.message.includes('Parse Error at')) {
634+
const [line, column] = e.message
635+
.split(':')
636+
.slice(-2)
637+
.map((x) => parseInt(x));
638+
// e.source_code has actually usable info, e.g × Expected ',', got 'string literal (, '')'
639+
// ╭─[9:1]
640+
// 9 │
641+
// 10 │ console.log(test'');
642+
// · ──
643+
// ╰────
644+
throw createError(code, e.source_code, fileName, { line, column });
645+
}
646+
throw e;
647+
}
597648
for (const tplInfo of result.reverse()) {
598649
const content = tplInfo.contents.replace(/`/g, '\\`').replace(/\$/g, '\\$');
599650
if (tplInfo.type === 'class-member') {

test-projects/gjs/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
"name": "@test-project/gjs",
33
"private": true,
44
"scripts": {
5-
"test": "eslint . --max-warnings=0"
5+
"test": "pnpm run /test:.*/",
6+
"test:correct-handle-syntax-error": "eslint . | grep -q '26:15 error Parsing error: × Unexpected eof'",
7+
"test:only-one-error": "eslint --format compact . | egrep '^[0-9]+ problem[s]*' | wc -l | grep -q 1"
68
},
79
"devDependencies": {
810
"@typescript-eslint/eslint-plugin": "^6.21.0",

test-projects/gjs/src/placeholer.gjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ export const Placeholder = <template>
2121
><code class="{{orGlimdown (qp 'format')}} hljs">{{context.text}}</code></pre>
2222
{{/let}}
2323
</template>;
24+
25+
26+
console.log(')

tests/parser.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2677,4 +2677,28 @@ export const NotFound = <template>
26772677
}
26782678
`);
26792679
});
2680+
2681+
it('throws eslint syntax error', () => {
2682+
try {
2683+
result = parseForESLint(`console.log('test)`, {
2684+
filePath: 'example.gts',
2685+
comment: true,
2686+
loc: true,
2687+
range: true,
2688+
tokens: true,
2689+
});
2690+
} catch (e) {
2691+
expect(e.lineNumber).toBe(1);
2692+
expect(e.column).toBe(19);
2693+
expect(e.fileName).toBe('example.gts');
2694+
expect(e.message).toMatchInlineSnapshot(`
2695+
"
2696+
× Unexpected eof
2697+
╭────
2698+
1 │ console.log('test)
2699+
╰────
2700+
"
2701+
`);
2702+
}
2703+
});
26802704
});

0 commit comments

Comments
 (0)