Skip to content

Commit

Permalink
support gts autofix
Browse files Browse the repository at this point in the history
  • Loading branch information
patricklx committed May 8, 2023
1 parent 208e6b6 commit 6ff7cf8
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 3 deletions.
14 changes: 14 additions & 0 deletions lib/preprocessors/glimmer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ const {
preprocessEmbeddedTemplates,
} = require('ember-template-imports/lib/preprocess-embedded-templates');
const util = require('ember-template-imports/src/util');
const DocumentLines = require('../utils/document');

const TRANSFORM_CACHE = new Map();
const TEXT_CACHE = new Map();
const RULE_CACHE = new Map();

Check failure on line 12 in lib/preprocessors/glimmer.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 14.x)

'RULE_CACHE' is assigned a value but never used

Check failure on line 12 in lib/preprocessors/glimmer.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 16.x)

'RULE_CACHE' is assigned a value but never used

Check failure on line 12 in lib/preprocessors/glimmer.js

View workflow job for this annotation

GitHub Actions / build (ubuntu, 18.x)

'RULE_CACHE' is assigned a value but never used

function arrayEq(arr1, arr2) {
return arr1.length === arr2.length && arr1.every((val, idx) => val === arr2[idx]);
Expand Down Expand Up @@ -135,7 +137,18 @@ function mapRange(messages, filename) {
);
}

const originalDoc = new DocumentLines(original);
const transformedDoc = new DocumentLines(transformed);

return flattened.map((message) => {
if (message.fix) {
const [start, end] = message.fix.range;
const startPos = transformedDoc.offsetToPosition(start);
const endPos = transformedDoc.offsetToPosition(end);
const fix = message.fix;
fix.range = [originalDoc.positionToOffset(startPos), originalDoc.positionToOffset(endPos)];
}

// 1. handle eslint diagnostics on single lines.
if (message.line === message.endLine) {
const originalLine = originalLines[message.line - 1];
Expand Down Expand Up @@ -238,4 +251,5 @@ function mapRange(messages, filename) {
module.exports = {
preprocess: gjs,
postprocess: mapRange,
supportsAutofix: true,
};
97 changes: 97 additions & 0 deletions lib/utils/document.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* @typedef {{ line: number; character: number }} Position
*/

class DocumentLines {
/**
* @param {string} contents
*/
constructor(contents) {
this.lineStarts = computeLineStarts(contents);
}

/**
* @param {Position} position
* @return {number}
*/
positionToOffset(position) {
const { line, character } = position;
return this.lineStarts[line] + character;
}

/**
*
* @param {number} position
* @return {Position}
*/
offsetToPosition(position) {
const lineStarts = this.lineStarts;
let line = 0;
while (line + 1 < lineStarts.length && lineStarts[line + 1] <= position) {
line++;
}
const character = position - lineStarts[line];
return { line, character };
}
}

/**
* @returns {number[]}
* @param {string} text
*/
function computeLineStarts(text) {
const result = [];
let pos = 0;
let lineStart = 0;
while (pos < text.length) {
const ch = text.codePointAt(pos);
pos++;
switch (ch) {
case 13 /* carriageReturn */: {
if (text.codePointAt(pos) === 10 /* lineFeed */) {
pos++;
}
}
// falls through
case 10 /* lineFeed */: {
result.push(lineStart);
lineStart = pos;
break;
}
default: {
if (ch > 127 /* maxAsciiCharacter */ && isLineBreak(ch)) {
result.push(lineStart);
lineStart = pos;
}
break;
}
}
}
result.push(lineStart);
return result;
}

/**
* @param {number} ch
* @return {boolean}
*/
function isLineBreak(ch) {
// ES5 7.3:
// The ECMAScript line terminator characters are listed in Table 3.
// Table 3: Line Terminator Characters
// Code Unit Value Name Formal Name
// \u000A Line Feed <LF>
// \u000D Carriage Return <CR>
// \u2028 Line separator <LS>
// \u2029 Paragraph separator <PS>
// Only the characters in Table 3 are treated as line terminators. Other new line or line
// breaking characters are treated as white space but not as line terminators.
return (
ch === 10 /* lineFeed */ ||
ch === 13 /* carriageReturn */ ||
ch === 8232 /* lineSeparator */ ||
ch === 8233 /* paragraphSeparator */
);
}

module.exports = DocumentLines;
38 changes: 35 additions & 3 deletions tests/lib/rules-preprocessor/gjs-gts-processor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function initESLint(options) {
plugins: ['ember'],
extends: ['plugin:ember/recommended'],
rules: {
quotes: ['error', 'single'],
'lines-between-class-members': 'error',
'no-undef': 'error',
'no-unused-vars': 'error',
Expand Down Expand Up @@ -171,7 +172,7 @@ const invalid = [
import Component from '@glimmer/component';
export default class MyComponent extends Component {
foo = "bar";
foo = 'bar';
<template>"hi"</template>
}
`,
Expand All @@ -191,7 +192,7 @@ const invalid = [
import Component from '@glimmer/component';
export default class MyComponent extends Component {
foo = "bar";
foo = 'bar';
<template>"hi"
</template>
}
Expand All @@ -206,6 +207,37 @@ const invalid = [
},
],
},
{
filename: 'my-component.gjs',
code: `
import Component from "@glimmer/component";
export default class MyComponent extends Component {
foo = 'bar';
<template>"hi"
</template>
}
`,
errors: [
{
message: 'Strings must use singlequote.',
line: 2,
endLine: 2,
endColumn: 49,
column: 29,
fix: {
range: [29, 49],
},
},
{
message: 'Expected blank line between class members.',
line: 6,
endLine: 7,
column: 9,
endColumn: 20,
},
],
},
];

describe('template-vars', () => {
Expand Down Expand Up @@ -388,7 +420,7 @@ describe('multiple tokens in same file', () => {
it('handles duplicate template tokens', async () => {
const eslint = initESLint();
const code = `
// comment Bad
// comment Bad
const tmpl = <template><Bad /></template>
`;
Expand Down

0 comments on commit 6ff7cf8

Please sign in to comment.