Skip to content

Commit 8b3eb2c

Browse files
committed
feat(deps): upgrade to eslint@8
- migrate to TypeScript - upgrade to ESLint 8 - change peerDependencies
1 parent 849b790 commit 8b3eb2c

File tree

7 files changed

+1536
-1552
lines changed

7 files changed

+1536
-1552
lines changed

package.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,21 @@
3232
"textlint"
3333
],
3434
"devDependencies": {
35+
"@types/eslint": "^8.2.1",
36+
"@types/node": "^17.0.4",
3537
"@types/structured-source": "^3.0.0",
36-
"eslint": "7.28.0",
38+
"eslint": "8.5.0",
3739
"textlint-plugin-asciidoctor": "^1.1.0",
38-
"textlint-scripts": "^12.0.1"
40+
"textlint-scripts": "^12.1.0",
41+
"ts-node": "^10.4.0",
42+
"typescript": "^4.5.4",
43+
"textlint-tester": "^12.1.0"
3944
},
4045
"peerDependencies": {
41-
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
46+
"eslint": "^8.0.0"
4247
},
4348
"dependencies": {
49+
"@textlint/types": "^12.1.0",
4450
"structured-source": "^3.0.2"
4551
}
4652
}

src/textlint-rule-eslint.js

Lines changed: 84 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
// LICENSE : MIT
22
"use strict";
3-
const path = require("path");
4-
const Source = require("structured-source");
5-
const CLIEngine = require("eslint").CLIEngine;
3+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5+
return new (P || (P = Promise))(function (resolve, reject) {
6+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9+
step((generator = generator.apply(thisArg, _arguments || [])).next());
10+
});
11+
};
12+
var __importDefault = (this && this.__importDefault) || function (mod) {
13+
return (mod && mod.__esModule) ? mod : { "default": mod };
14+
};
15+
Object.defineProperty(exports, "__esModule", { value: true });
16+
const path_1 = __importDefault(require("path"));
17+
const structured_source_1 = __importDefault(require("structured-source"));
18+
const eslint_1 = require("eslint");
619
const defaultOptions = {
720
// path to .eslintrc file
821
"configFile": null,
@@ -17,80 +30,84 @@ const getConfigBaseDir = (context) => {
1730
// https://github.com/textlint/textlint/issues/294
1831
const textlintRcFilePath = context.config ? context.config.configFile : null;
1932
// .textlinrc directory
20-
return textlintRcFilePath ? path.dirname(textlintRcFilePath) : process.cwd();
33+
return textlintRcFilePath ? path_1.default.dirname(textlintRcFilePath) : process.cwd();
2134
};
22-
2335
const reporter = (context, options) => {
24-
const { Syntax, RuleError, report, fixer, getSource } = context;
36+
const { Syntax, RuleError, report, fixer, getSource, getFilePath } = context;
37+
if (!options) {
38+
throw new Error(`Require options: { "configFile": "path/to/.eslintrc" }`);
39+
}
2540
if (!options.configFile) {
2641
throw new Error(`Require options: { "configFile": "path/to/.eslintrc" }`);
2742
}
2843
const availableLang = options.langs || defaultOptions.langs;
2944
const textlintRCDir = getConfigBaseDir(context);
30-
const ESLintOptions = {
31-
configFile: path.resolve(textlintRCDir, options.configFile)
32-
};
33-
const engine = new CLIEngine(ESLintOptions);
45+
const esLintConfigFilePath = textlintRCDir ? path_1.default.resolve(textlintRCDir, options.configFile) : options.configFile;
46+
const engine = new eslint_1.ESLint({
47+
useEslintrc: false,
48+
overrideConfigFile: esLintConfigFilePath
49+
});
3450
return {
3551
[Syntax.CodeBlock](node) {
36-
if (availableLang.indexOf(node.lang) === -1) {
37-
return;
38-
}
39-
const raw = getSource(node);
40-
const code = getUntrimmedCode(node, raw);
41-
const source = new Source(code);
42-
const resultLinting = engine.executeOnText(code, node.lang);
43-
if (resultLinting.errorCount === 0) {
44-
return;
45-
}
46-
const results = resultLinting.results;
47-
results.forEach(result => {
48-
result.messages.forEach(message => {
49-
/*
50-
51-
1. ```js
52-
2. CODE
53-
3. ```
54-
55-
ESLint message line and column start with 1
56-
*/
57-
if (options.ignoreParsingErrors && message.message.includes("Parsing error")) {
58-
return;
59-
}
60-
61-
const prefix = message.ruleId ? `${message.ruleId}: ` : "";
62-
if (message.fix) {
63-
const fixedRange = message.fix.range;
64-
const fixedText = message.fix.text;
65-
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
66-
const fixedWithPadding = [fixedRange[0] + sourceBlockDiffIndex, fixedRange[1] + sourceBlockDiffIndex];
67-
const index = source.positionToIndex({
68-
line: message.line,
69-
column: message.column
70-
});
71-
const adjustedIndex = index + sourceBlockDiffIndex - 1;
72-
report(node, new RuleError(`${prefix}${message.message}`, {
73-
index: adjustedIndex,
74-
fix: fixer.replaceTextRange(fixedWithPadding, fixedText)
75-
}));
76-
} else {
77-
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
78-
const index = source.positionToIndex({
79-
line: message.line,
80-
column: message.column
81-
});
82-
const adjustedIndex = index + sourceBlockDiffIndex - 1;
83-
report(node, new RuleError(`${prefix}${message.message}`, {
84-
index: adjustedIndex
85-
}));
86-
}
87-
52+
return __awaiter(this, void 0, void 0, function* () {
53+
if (availableLang.indexOf(node.lang) === -1) {
54+
return;
55+
}
56+
const raw = getSource(node);
57+
const code = getUntrimmedCode(node, raw);
58+
const source = new structured_source_1.default(code);
59+
const resultLinting = yield engine.lintText(code, {
60+
filePath: `test.${node.lang}`
61+
});
62+
if (resultLinting.length === 0) {
63+
return;
64+
}
65+
resultLinting.forEach(result => {
66+
result.messages.forEach(message => {
67+
/*
68+
69+
1. ```js
70+
2. CODE
71+
3. ```
72+
73+
ESLint message line and column start with 1
74+
*/
75+
if (options.ignoreParsingErrors && message.message.includes("Parsing error")) {
76+
return;
77+
}
78+
const prefix = message.ruleId ? `${message.ruleId}: ` : "";
79+
if (message.fix) {
80+
const fixedRange = message.fix.range;
81+
const fixedText = message.fix.text;
82+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
83+
const fixedWithPadding = [fixedRange[0] + sourceBlockDiffIndex, fixedRange[1] + sourceBlockDiffIndex];
84+
const index = source.positionToIndex({
85+
line: message.line,
86+
column: message.column
87+
});
88+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
89+
report(node, new RuleError(`${prefix}${message.message}`, {
90+
index: adjustedIndex,
91+
fix: fixer.replaceTextRange(fixedWithPadding, fixedText)
92+
}));
93+
}
94+
else {
95+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
96+
const index = source.positionToIndex({
97+
line: message.line,
98+
column: message.column
99+
});
100+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
101+
report(node, new RuleError(`${prefix}${message.message}`, {
102+
index: adjustedIndex
103+
}));
104+
}
105+
});
88106
});
89107
});
90108
}
91-
}
109+
};
92110
};
93-
94111
/**
95112
* [Markdown] get actual code value from CodeBlock node
96113
* @param {Object} node
@@ -99,17 +116,16 @@ const reporter = (context, options) => {
99116
*/
100117
function getUntrimmedCode(node, raw) {
101118
if (node.type !== "CodeBlock") {
102-
return node.value
119+
return node.value;
103120
}
104121
// Space indented CodeBlock that has not lang
105122
if (!node.lang) {
106123
return node.value;
107124
}
108-
109125
// If it is not markdown codeBlock, just use node.value
110126
if (!(raw.startsWith("```") && raw.endsWith("```"))) {
111127
if (node.value.endsWith("\n")) {
112-
return node.value
128+
return node.value;
113129
}
114130
return node.value + "\n";
115131
}
@@ -122,8 +138,7 @@ function getUntrimmedCode(node, raw) {
122138
// \n```
123139
return codeLines.join("\n") + "\n";
124140
}
125-
126-
module.exports = {
141+
exports.default = {
127142
linter: reporter,
128143
fixer: reporter
129144
};

src/textlint-rule-eslint.ts

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// LICENSE : MIT
2+
"use strict";
3+
import path from "path";
4+
import type { TextlintRuleContext, TextlintRuleModule } from "@textlint/types"
5+
import Source from "structured-source";
6+
import { ESLint } from "eslint";
7+
8+
const defaultOptions = {
9+
// path to .eslintrc file
10+
"configFile": null,
11+
// recognize lang of CodeBlock
12+
"langs": ["js", "javascript", "node", "jsx"]
13+
};
14+
const getConfigBaseDir = (context: TextlintRuleContext & { config?: any }) => {
15+
if (typeof context.getConfigBaseDir === "function") {
16+
return context.getConfigBaseDir();
17+
}
18+
// Fallback that use deprecated `config` value
19+
// https://github.com/textlint/textlint/issues/294
20+
const textlintRcFilePath = context.config ? context.config.configFile : null;
21+
// .textlinrc directory
22+
return textlintRcFilePath ? path.dirname(textlintRcFilePath) : process.cwd();
23+
};
24+
25+
export type Options = {
26+
configFile: string;
27+
langs: string[]
28+
}
29+
const reporter: TextlintRuleModule<Options> = (context, options) => {
30+
const { Syntax, RuleError, report, fixer, getSource, getFilePath} = context;
31+
if (!options) {
32+
throw new Error(`Require options: { "configFile": "path/to/.eslintrc" }`);
33+
}
34+
if (!options.configFile) {
35+
throw new Error(`Require options: { "configFile": "path/to/.eslintrc" }`);
36+
}
37+
const availableLang = options.langs || defaultOptions.langs;
38+
const textlintRCDir = getConfigBaseDir(context);
39+
const esLintConfigFilePath = textlintRCDir ? path.resolve(textlintRCDir, options.configFile) : options.configFile;
40+
const engine = new ESLint({
41+
useEslintrc: false,
42+
overrideConfigFile: esLintConfigFilePath
43+
});
44+
return {
45+
async [Syntax.CodeBlock](node) {
46+
if (availableLang.indexOf(node.lang) === -1) {
47+
return;
48+
}
49+
const raw = getSource(node);
50+
const code = getUntrimmedCode(node, raw);
51+
const source = new Source(code);
52+
const resultLinting = await engine.lintText(code, {
53+
filePath: `test.${node.lang}`
54+
});
55+
if (resultLinting.length === 0) {
56+
return;
57+
}
58+
resultLinting.forEach(result => {
59+
result.messages.forEach(message => {
60+
/*
61+
62+
1. ```js
63+
2. CODE
64+
3. ```
65+
66+
ESLint message line and column start with 1
67+
*/
68+
if (options.ignoreParsingErrors && message.message.includes("Parsing error")) {
69+
return;
70+
}
71+
72+
const prefix = message.ruleId ? `${message.ruleId}: ` : "";
73+
if (message.fix) {
74+
const fixedRange = message.fix.range;
75+
const fixedText = message.fix.text;
76+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
77+
const fixedWithPadding = [fixedRange[0] + sourceBlockDiffIndex, fixedRange[1] + sourceBlockDiffIndex] as const;
78+
const index = source.positionToIndex({
79+
line: message.line,
80+
column: message.column
81+
});
82+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
83+
report(node, new RuleError(`${prefix}${message.message}`, {
84+
index: adjustedIndex,
85+
fix: fixer.replaceTextRange(fixedWithPadding as [number, number], fixedText)
86+
}));
87+
} else {
88+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
89+
const index = source.positionToIndex({
90+
line: message.line,
91+
column: message.column
92+
});
93+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
94+
report(node, new RuleError(`${prefix}${message.message}`, {
95+
index: adjustedIndex
96+
}));
97+
}
98+
99+
});
100+
});
101+
}
102+
}
103+
};
104+
105+
/**
106+
* [Markdown] get actual code value from CodeBlock node
107+
* @param {Object} node
108+
* @param {string} raw raw value include CodeBlock syntax
109+
* @returns {string}
110+
*/
111+
function getUntrimmedCode(node: any, raw: string) {
112+
if (node.type !== "CodeBlock") {
113+
return node.value
114+
}
115+
// Space indented CodeBlock that has not lang
116+
if (!node.lang) {
117+
return node.value;
118+
}
119+
120+
// If it is not markdown codeBlock, just use node.value
121+
if (!(raw.startsWith("```") && raw.endsWith("```"))) {
122+
if (node.value.endsWith("\n")) {
123+
return node.value
124+
}
125+
return node.value + "\n";
126+
}
127+
// Markdown(remark) specific hack
128+
// https://github.com/wooorm/remark/issues/207#issuecomment-244620590
129+
const lines = raw.split("\n");
130+
// code lines without the first line and the last line
131+
const codeLines = lines.slice(1, lines.length - 1);
132+
// add last new line
133+
// \n```
134+
return codeLines.join("\n") + "\n";
135+
}
136+
137+
export default {
138+
linter: reporter,
139+
fixer: reporter
140+
};

test/textlint-rule-eslint-test.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
// LICENSE : MIT
22
"use strict";
3-
import rule from "../src/textlint-rule-eslint";
4-
5-
const path = require("path");
6-
import TextLintTester from "textlint-tester";
7-
const tester = new TextLintTester();
8-
const configFilePath = path.join(__dirname, "fixtures/style.eslintconfig.js");
3+
var __importDefault = (this && this.__importDefault) || function (mod) {
4+
return (mod && mod.__esModule) ? mod : { "default": mod };
5+
};
6+
Object.defineProperty(exports, "__esModule", { value: true });
7+
const textlint_rule_eslint_js_1 = __importDefault(require("../src/textlint-rule-eslint.js"));
8+
const textlint_tester_1 = __importDefault(require("textlint-tester"));
9+
const path_1 = __importDefault(require("path"));
10+
const tester = new textlint_tester_1.default();
11+
const configFilePath = path_1.default.join(__dirname, "fixtures/style.eslintconfig.js");
912
const WrongCode1 = "var a = 1";
1013
const WrongCode2 = "var a = 1; var b = 2";
11-
tester.run("textlint-rule-eslint", rule, {
14+
// @ts-expect-error
15+
tester.run("textlint-rule-eslint", textlint_rule_eslint_js_1.default, {
1216
valid: [
1317
{
1418
text: "`var a = 1;`",

0 commit comments

Comments
 (0)