ignore-lint-errors 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@ Step 2. Fix formatting.
34
34
 
35
35
  ```sh
36
36
  # Run prettier
37
- pnpm format
37
+ pnpm prettier . --write
38
38
  ```
39
39
 
40
40
 
@@ -7,8 +7,7 @@ function findDependencies(projectRoot) {
7
7
  ]);
8
8
  return {
9
9
  eslint: projectDependencies.has('eslint'),
10
- glint: projectDependencies.has('@glint/core') ||
11
- projectDependencies.has('@glint/ember-tsc'),
10
+ glint: projectDependencies.has('@glint/ember-tsc'),
12
11
  stylelint: projectDependencies.has('stylelint'),
13
12
  typescript: projectDependencies.has('typescript'),
14
13
  };
@@ -1,44 +1,22 @@
1
1
  import { EOL } from 'node:os';
2
- import { AST } from '@codemod-utils/ast-javascript';
3
- function getIgnoredEslintRules(lineOfCode) {
4
- const traverse = AST.traverse(true);
5
- let ignoredEslintRules = [];
6
- try {
7
- traverse(lineOfCode, {
8
- visitComment(node) {
9
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
10
- const comment = node.value.value.trim();
11
- if (comment.startsWith('eslint-disable-next-line')) {
12
- ignoredEslintRules = comment
13
- .replace(/^eslint-disable-next-line\s+/, '')
14
- .split(',')
15
- .map((token) => token.trim());
16
- }
17
- return false;
18
- },
19
- });
20
- }
21
- catch {
22
- // Do nothing
23
- }
24
- return ignoredEslintRules;
25
- }
2
+ import { getIgnoredRules } from './shared/index.js';
26
3
  export function ignoreErrors(file, lintErrors) {
27
4
  const lines = file.split(EOL);
5
+ const ignoreDirective = 'eslint-disable-next-line';
28
6
  lintErrors.forEach(({ line, message }) => {
29
7
  const currentIndex = line - 1;
30
8
  const previousIndex = Math.max(currentIndex - 1, 0);
31
- const ignoredEslintRules = getIgnoredEslintRules(lines[previousIndex]);
32
- if (ignoredEslintRules.length === 0) {
33
- const ignoreDirective = `// eslint-disable-next-line ${message}`;
34
- lines.splice(currentIndex, 0, ignoreDirective);
9
+ const ignoredRules = getIgnoredRules(lines[previousIndex], {
10
+ ignoreDirective,
11
+ });
12
+ if (ignoredRules.length === 0) {
13
+ lines.splice(currentIndex, 0, `// ${ignoreDirective} ${message}`);
35
14
  }
36
15
  else {
37
- const newMessage = [...ignoredEslintRules, ...message.split(', ')]
16
+ const newMessage = [...ignoredRules, ...message.split(', ')]
38
17
  .sort()
39
18
  .join(', ');
40
- const ignoreDirective = `// eslint-disable-next-line ${newMessage}`;
41
- lines.splice(previousIndex, 1, ignoreDirective);
19
+ lines.splice(previousIndex, 1, `// ${ignoreDirective} ${newMessage}`);
42
20
  }
43
21
  });
44
22
  return lines.join(EOL);
@@ -0,0 +1,24 @@
1
+ import { AST } from '@codemod-utils/ast-javascript';
2
+ export function getIgnoredRules(lineOfCode, options) {
3
+ const traverse = AST.traverse(true);
4
+ let ignoredRules = [];
5
+ try {
6
+ traverse(lineOfCode, {
7
+ visitComment(node) {
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
9
+ const comment = node.value.value.trim();
10
+ if (comment.startsWith(options.ignoreDirective)) {
11
+ ignoredRules = comment
12
+ .replace(new RegExp(`^${options.ignoreDirective}\\s+`, 'g'), '')
13
+ .split(',')
14
+ .map((token) => token.trim());
15
+ }
16
+ return false;
17
+ },
18
+ });
19
+ }
20
+ catch {
21
+ // Do nothing
22
+ }
23
+ return ignoredRules;
24
+ }
@@ -1,9 +1,23 @@
1
1
  import { EOL } from 'node:os';
2
+ import { getIgnoredRules } from './shared/index.js';
2
3
  export function ignoreErrors(file, lintErrors) {
3
4
  const lines = file.split(EOL);
5
+ const ignoreDirective = 'stylelint-disable-next-line';
4
6
  lintErrors.forEach(({ line, message }) => {
5
- const ignoreDirective = `/* stylelint-disable-next-line ${message} */`;
6
- lines.splice(line - 1, 0, ignoreDirective);
7
+ const currentIndex = line - 1;
8
+ const previousIndex = Math.max(currentIndex - 1, 0);
9
+ const ignoredRules = getIgnoredRules(lines[previousIndex], {
10
+ ignoreDirective,
11
+ });
12
+ if (ignoredRules.length === 0) {
13
+ lines.splice(currentIndex, 0, `/* ${ignoreDirective} ${message} */`);
14
+ }
15
+ else {
16
+ const newMessage = [...ignoredRules, ...message.split(', ')]
17
+ .sort()
18
+ .join(', ');
19
+ lines.splice(previousIndex, 1, `/* ${ignoreDirective} ${newMessage} */`);
20
+ }
7
21
  });
8
22
  return lines.join(EOL);
9
23
  }
@@ -1,56 +1,92 @@
1
1
  import { EOL } from 'node:os';
2
2
  import { AST } from '@codemod-utils/ast-template';
3
- import { findTemplateTags, updateTemplates, } from '@codemod-utils/ast-template-tag';
4
- export function findLinesWithTemplate(file) {
3
+ import { findTemplateTags as upstreamFindTemplateTags, updateTemplates, } from '@codemod-utils/ast-template-tag';
4
+ import { getIgnoredRules } from './shared/index.js';
5
+ function findTemplateTags(file) {
5
6
  function getLOC(file) {
6
7
  const matches = file.match(/\r?\n/g);
7
8
  return (matches ?? []).length;
8
9
  }
9
- const templateTags = findTemplateTags(file);
10
- const linesWithTemplate = [];
11
- templateTags.forEach((templateTag) => {
12
- const { range } = templateTag;
10
+ const templateTags = upstreamFindTemplateTags(file);
11
+ return templateTags.map((templateTag) => {
12
+ const { contents, range } = templateTag;
13
13
  const lineStart = getLOC(file.substring(0, range.startChar)) + 1;
14
14
  const lineEnd = getLOC(file.substring(0, range.endChar)) + 1;
15
- linesWithTemplate.push([lineStart, lineEnd]);
15
+ const lineRange = {
16
+ end: lineEnd,
17
+ start: lineStart,
18
+ };
19
+ return {
20
+ contents,
21
+ lineRange,
22
+ };
16
23
  });
17
- return linesWithTemplate;
18
24
  }
19
25
  export function ignoreErrors(file, lintErrors) {
20
- const linesWithTemplate = findLinesWithTemplate(file);
21
26
  const lines = file.split(EOL);
27
+ const templateTags = findTemplateTags(file);
22
28
  lintErrors.forEach(({ line, message }) => {
23
- const erroredInTemplate = linesWithTemplate.some(([lineStart, lineEnd]) => {
24
- return lineStart <= line && line <= lineEnd;
29
+ const currentIndex = line - 1;
30
+ const previousIndex = Math.max(currentIndex - 1, 0);
31
+ const templateTagIndex = templateTags.findIndex(({ lineRange }) => {
32
+ return lineRange.start <= line && line <= lineRange.end;
33
+ });
34
+ const erroredInTemplate = templateTagIndex >= 0;
35
+ if (erroredInTemplate) {
36
+ const ignoreDirective = `{{! @glint-expect-error: ${message} }}`;
37
+ const { contents, lineRange } = templateTags[templateTagIndex];
38
+ if (lineRange.start !== lineRange.end) {
39
+ lines.splice(currentIndex, 0, ignoreDirective);
40
+ return;
41
+ }
42
+ const newTemplate = lines[currentIndex].replace(/<template>(.+)<\/template>/, `<template>${ignoreDirective}${contents}</template>`);
43
+ lines.splice(currentIndex, 1, newTemplate);
44
+ return;
45
+ }
46
+ const ignoreDirective = `// @ts-expect-error: ${message}`;
47
+ const ignoredRules = getIgnoredRules(lines[previousIndex], {
48
+ ignoreDirective: 'eslint-disable-next-line',
25
49
  });
26
- const ignoreDirective = erroredInTemplate
27
- ? `{{! @glint-expect-error: ${message} }}`
28
- : `// @ts-expect-error: ${message}`;
29
- lines.splice(line - 1, 0, ignoreDirective);
50
+ if (ignoredRules.length === 0) {
51
+ lines.splice(currentIndex, 0, ignoreDirective);
52
+ }
53
+ else {
54
+ lines.splice(previousIndex, 0, ignoreDirective);
55
+ }
30
56
  });
31
57
  return lines.join(EOL);
32
58
  }
33
59
  // For fallback, ignore type checks in templates
34
60
  export function ignoreErrorsFallback(file, lintErrors) {
35
- const linesWithTemplate = findLinesWithTemplate(file);
36
61
  const lines = file.split(EOL);
62
+ const templateTags = findTemplateTags(file);
37
63
  let hasErrorInTemplate = false;
38
64
  lintErrors.forEach(({ line, message }) => {
39
- const erroredInTemplate = linesWithTemplate.some(([lineStart, lineEnd]) => {
40
- return lineStart <= line && line <= lineEnd;
65
+ const currentIndex = line - 1;
66
+ const previousIndex = Math.max(currentIndex - 1, 0);
67
+ const erroredInTemplate = templateTags.some(({ lineRange }) => {
68
+ return lineRange.start <= line && line <= lineRange.end;
41
69
  });
42
70
  if (erroredInTemplate) {
43
71
  hasErrorInTemplate = true;
44
72
  return;
45
73
  }
46
74
  const ignoreDirective = `// @ts-expect-error: ${message}`;
47
- lines.splice(line - 1, 0, ignoreDirective);
75
+ const ignoredRules = getIgnoredRules(lines[previousIndex], {
76
+ ignoreDirective: 'eslint-disable-next-line',
77
+ });
78
+ if (ignoredRules.length === 0) {
79
+ lines.splice(currentIndex, 0, ignoreDirective);
80
+ }
81
+ else {
82
+ lines.splice(previousIndex, 0, ignoreDirective);
83
+ }
48
84
  });
49
85
  let newFile = lines.join(EOL);
50
86
  if (hasErrorInTemplate) {
51
87
  newFile = updateTemplates(newFile, (code) => {
52
88
  const ignoreDirective = '{{! @glint-nocheck }}';
53
- return [ignoreDirective, code].join(EOL);
89
+ return [ignoreDirective, code].join('');
54
90
  });
55
91
  }
56
92
  return newFile;
@@ -60,8 +96,8 @@ export function isParseable(file) {
60
96
  let isParseable = true;
61
97
  try {
62
98
  const templateTags = findTemplateTags(file);
63
- templateTags.forEach((templateTag) => {
64
- traverse(templateTag.contents);
99
+ templateTags.forEach(({ contents }) => {
100
+ traverse(contents);
65
101
  });
66
102
  }
67
103
  catch {
@@ -1,48 +1,31 @@
1
1
  import { relative, sep } from 'node:path';
2
+ import { getFilesWithErrors } from './shared/index.js';
2
3
  export const outputFilePath = '.ignore-lint-errors/eslint.txt';
3
- export function parseOutputFile(file, projectRoot) {
4
+ function normalize(file, projectRoot) {
4
5
  const filePathToData = new Map();
5
6
  const records = JSON.parse(file);
6
7
  records.forEach((record) => {
7
8
  const { filePath: absoluteFilePath, messages } = record;
9
+ const filePath = relative(projectRoot, absoluteFilePath).replaceAll(sep, '/');
10
+ const lineToRules = new Map();
8
11
  const data = new Map();
9
12
  messages.forEach(({ line, ruleId }) => {
10
- if (data.has(line)) {
11
- data.get(line).push(ruleId);
13
+ if (lineToRules.has(line)) {
14
+ lineToRules.get(line).push(ruleId);
12
15
  }
13
16
  else {
14
- data.set(line, [ruleId]);
15
- }
16
- });
17
- const filePath = relative(projectRoot, absoluteFilePath).replaceAll(sep, '/');
18
- filePathToData.set(filePath, data);
19
- });
20
- const filesWithErrors = [];
21
- filePathToData.forEach((data, filePath) => {
22
- const lintErrors = [];
23
- data.forEach((allMessages, line) => {
24
- const ruleIds = Array.from(new Set(allMessages.sort()));
25
- lintErrors.push({
26
- line,
27
- message: ruleIds.join(', '),
28
- });
29
- });
30
- if (lintErrors.length === 0) {
31
- return;
32
- }
33
- lintErrors.sort((a, b) => {
34
- if (a.line < b.line) {
35
- return 1;
36
- }
37
- if (b.line < a.line) {
38
- return -1;
17
+ lineToRules.set(line, [ruleId]);
39
18
  }
40
- return 0;
41
19
  });
42
- filesWithErrors.push({
43
- filePath,
44
- lintErrors,
20
+ lineToRules.forEach((rules, line) => {
21
+ const message = Array.from(new Set(rules.sort())).join(', ');
22
+ data.set(line, message);
45
23
  });
24
+ filePathToData.set(filePath, data);
46
25
  });
47
- return filesWithErrors;
26
+ return filePathToData;
27
+ }
28
+ export function parseOutputFile(file, projectRoot) {
29
+ const filePathToData = normalize(file, projectRoot);
30
+ return getFilesWithErrors(filePathToData);
48
31
  }
@@ -0,0 +1,29 @@
1
+ export function getFilesWithErrors(filePathToData) {
2
+ const filesWithErrors = [];
3
+ filePathToData.forEach((data, filePath) => {
4
+ const lintErrors = [];
5
+ data.forEach((message, line) => {
6
+ lintErrors.push({
7
+ line,
8
+ message,
9
+ });
10
+ });
11
+ if (lintErrors.length === 0) {
12
+ return;
13
+ }
14
+ lintErrors.sort((a, b) => {
15
+ if (a.line < b.line) {
16
+ return 1;
17
+ }
18
+ if (b.line < a.line) {
19
+ return -1;
20
+ }
21
+ return 0;
22
+ });
23
+ filesWithErrors.push({
24
+ filePath,
25
+ lintErrors,
26
+ });
27
+ });
28
+ return filesWithErrors;
29
+ }
@@ -1,6 +1,7 @@
1
1
  import { relative, sep } from 'node:path';
2
+ import { getFilesWithErrors } from './shared/index.js';
2
3
  export const outputFilePath = '.ignore-lint-errors/stylelint.txt';
3
- export function parseOutputFile(file, projectRoot) {
4
+ function normalize(file, projectRoot) {
4
5
  const filePathToData = new Map();
5
6
  const records = JSON.parse(file);
6
7
  records.forEach((record) => {
@@ -8,44 +9,26 @@ export function parseOutputFile(file, projectRoot) {
8
9
  if (!errored) {
9
10
  return;
10
11
  }
12
+ const filePath = relative(projectRoot, absoluteFilePath).replaceAll(sep, '/');
13
+ const lineToRules = new Map();
11
14
  const data = new Map();
12
15
  warnings.forEach(({ line, rule }) => {
13
- if (data.has(line)) {
14
- data.get(line).push(rule);
16
+ if (lineToRules.has(line)) {
17
+ lineToRules.get(line).push(rule);
15
18
  }
16
19
  else {
17
- data.set(line, [rule]);
18
- }
19
- });
20
- const filePath = relative(projectRoot, absoluteFilePath).replaceAll(sep, '/');
21
- filePathToData.set(filePath, data);
22
- });
23
- const filesWithErrors = [];
24
- filePathToData.forEach((data, filePath) => {
25
- const lintErrors = [];
26
- data.forEach((allMessages, line) => {
27
- const ruleIds = Array.from(new Set(allMessages.sort()));
28
- lintErrors.push({
29
- line,
30
- message: ruleIds.join(', '),
31
- });
32
- });
33
- if (lintErrors.length === 0) {
34
- return;
35
- }
36
- lintErrors.sort((a, b) => {
37
- if (a.line < b.line) {
38
- return 1;
39
- }
40
- if (b.line < a.line) {
41
- return -1;
20
+ lineToRules.set(line, [rule]);
42
21
  }
43
- return 0;
44
22
  });
45
- filesWithErrors.push({
46
- filePath,
47
- lintErrors,
23
+ lineToRules.forEach((rules, line) => {
24
+ const message = Array.from(new Set(rules.sort())).join(', ');
25
+ data.set(line, message);
48
26
  });
27
+ filePathToData.set(filePath, data);
49
28
  });
50
- return filesWithErrors;
29
+ return filePathToData;
30
+ }
31
+ export function parseOutputFile(file, projectRoot) {
32
+ const filePathToData = normalize(file, projectRoot);
33
+ return getFilesWithErrors(filePathToData);
51
34
  }
@@ -1,6 +1,7 @@
1
1
  import { EOL } from 'node:os';
2
+ import { getFilesWithErrors } from './shared/index.js';
2
3
  export const outputFilePath = '.ignore-lint-errors/typescript.txt';
3
- export function parseOutputFile(file) {
4
+ function normalize(file) {
4
5
  const filePathToData = new Map();
5
6
  file.split(EOL).forEach((str) => {
6
7
  const matches = str.match(/^(.+)\((\d+),\d+\): error TS\d+: (.+)\.$/);
@@ -9,44 +10,17 @@ export function parseOutputFile(file) {
9
10
  }
10
11
  const filePath = matches[1];
11
12
  const line = Number.parseInt(matches[2]);
12
- const message = matches[3];
13
+ const message = 'Incorrect type';
13
14
  if (filePathToData.has(filePath)) {
14
- if (filePathToData.get(filePath).has(line)) {
15
- filePathToData.get(filePath).get(line).push(message);
16
- }
17
- else {
18
- filePathToData.get(filePath).set(line, [message]);
19
- }
15
+ filePathToData.get(filePath).set(line, message);
20
16
  }
21
17
  else {
22
- filePathToData.set(filePath, new Map([[line, [message]]]));
23
- }
24
- });
25
- const filesWithErrors = [];
26
- filePathToData.forEach((data, filePath) => {
27
- const lintErrors = [];
28
- data.forEach((_allMessages, line) => {
29
- lintErrors.push({
30
- line,
31
- message: 'Incorrect type',
32
- });
33
- });
34
- if (lintErrors.length === 0) {
35
- return;
18
+ filePathToData.set(filePath, new Map([[line, message]]));
36
19
  }
37
- lintErrors.sort((a, b) => {
38
- if (a.line < b.line) {
39
- return 1;
40
- }
41
- if (b.line < a.line) {
42
- return -1;
43
- }
44
- return 0;
45
- });
46
- filesWithErrors.push({
47
- filePath,
48
- lintErrors,
49
- });
50
20
  });
51
- return filesWithErrors;
21
+ return filePathToData;
22
+ }
23
+ export function parseOutputFile(file) {
24
+ const filePathToData = normalize(file);
25
+ return getFilesWithErrors(filePathToData);
52
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ignore-lint-errors",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "Codemod to ignore lint errors per line",
5
5
  "keywords": [
6
6
  "codemod",