Skip to content

Commit 2bb23d2

Browse files
authored
fix(rule): support non-Markdown file (#23)
1 parent cc76d0f commit 2bb23d2

File tree

6 files changed

+578
-900
lines changed

6 files changed

+578
-900
lines changed

package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,15 @@
3232
"textlint"
3333
],
3434
"devDependencies": {
35-
"eslint": "6.0.1",
36-
"textlint-scripts": "^2.1.0"
35+
"@types/structured-source": "^3.0.0",
36+
"eslint": "6.5.1",
37+
"textlint-scripts": "^2.1.0",
38+
"textlint-plugin-asciidoctor": "^1.0.3"
3739
},
3840
"peerDependencies": {
3941
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0"
42+
},
43+
"dependencies": {
44+
"structured-source": "^3.0.2"
4045
}
4146
}

src/textlint-rule-eslint.js

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// LICENSE : MIT
22
"use strict";
3-
const CLIEngine = require("eslint").CLIEngine;
43
const path = require("path");
4+
const Source = require("structured-source");
5+
const CLIEngine = require("eslint").CLIEngine;
56
const defaultOptions = {
67
// path to .eslintrc file
78
"configFile": null,
@@ -37,7 +38,7 @@ const reporter = (context, options) => {
3738
}
3839
const raw = getSource(node);
3940
const code = getUntrimmedCode(node, raw);
40-
41+
const source = new Source(code);
4142
const resultLinting = engine.executeOnText(code, node.lang);
4243
if (resultLinting.errorCount === 0) {
4344
return;
@@ -54,24 +55,33 @@ const reporter = (context, options) => {
5455
ESLint message line and column start with 1
5556
*/
5657
if (options.ignoreParsingErrors && message.message.includes("Parsing error")) {
57-
return;
58+
return;
5859
}
5960

6061
const prefix = message.ruleId ? `${message.ruleId}: ` : "";
6162
if (message.fix) {
62-
const paddingIndex = raw.indexOf(code);
6363
const fixedRange = message.fix.range;
6464
const fixedText = message.fix.text;
65-
const fixedWithPadding = [fixedRange[0] + paddingIndex, fixedRange[1] + paddingIndex];
66-
report(node, new RuleError(`${prefix}${message.message}`, {
65+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
66+
const fixedWithPadding = [fixedRange[0] + sourceBlockDiffIndex, fixedRange[1] + sourceBlockDiffIndex];
67+
const index = source.positionToIndex({
6768
line: message.line,
68-
column: message.column - 1,
69+
column: message.column
70+
});
71+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
72+
report(node, new RuleError(`${prefix}${message.message}`, {
73+
index: adjustedIndex,
6974
fix: fixer.replaceTextRange(fixedWithPadding, fixedText)
7075
}));
7176
} else {
72-
report(node, new RuleError(`${prefix}${message.message}`, {
77+
const sourceBlockDiffIndex = (raw !== node.value) ? raw.indexOf(code) : 0;
78+
const index = source.positionToIndex({
7379
line: message.line,
74-
column: message.column - 1
80+
column: message.column
81+
});
82+
const adjustedIndex = index + sourceBlockDiffIndex - 1;
83+
report(node, new RuleError(`${prefix}${message.message}`, {
84+
index: adjustedIndex
7585
}));
7686
}
7787

@@ -82,7 +92,7 @@ const reporter = (context, options) => {
8292
};
8393

8494
/**
85-
* get actual code value from CodeBlock node
95+
* [Markdown] get actual code value from CodeBlock node
8696
* @param {Object} node
8797
* @param {string} raw raw value include CodeBlock syntax
8898
* @returns {string}
@@ -91,18 +101,23 @@ function getUntrimmedCode(node, raw) {
91101
if (node.type !== "CodeBlock") {
92102
return node.value
93103
}
94-
95104
// Space indented CodeBlock that has not lang
96105
if (!node.lang) {
97106
return node.value;
98107
}
99108

109+
// If it is not markdown codeBlock, just use node.value
110+
if (!(raw.startsWith("```") && raw.endsWith("```"))) {
111+
if (node.value.endsWith("\n")) {
112+
return node.value
113+
}
114+
return node.value + "\n";
115+
}
116+
// Markdown(remark) specific hack
100117
// https://github.com/wooorm/remark/issues/207#issuecomment-244620590
101118
const lines = raw.split("\n");
102-
103119
// code lines without the first line and the last line
104120
const codeLines = lines.slice(1, lines.length - 1);
105-
106121
// add last new line
107122
// \n```
108123
return codeLines.join("\n") + "\n";
@@ -111,4 +126,4 @@ function getUntrimmedCode(node, raw) {
111126
module.exports = {
112127
linter: reporter,
113128
fixer: reporter
114-
};
129+
};

test/asciidoc.disabled

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// LICENSE : MIT
2+
"use strict";
3+
import rule from "../src/textlint-rule-eslint";
4+
const path = require("path");
5+
const TextLintTester = require("textlint-tester");
6+
const asciidoctorPlugin = require("textlint-plugin-asciidoctor");
7+
const tester = new TextLintTester();
8+
const configFilePath = path.join(__dirname, "fixtures/style.eslintconfig.js");
9+
tester.run("textlint-rule-eslint with asciidoctor plugin", {
10+
plugins: [
11+
{
12+
pluginId: "asciidoc",
13+
plugin: asciidoctorPlugin,
14+
}
15+
],
16+
rules: [
17+
{
18+
ruleId: "eslint",
19+
rule: rule,
20+
options: {
21+
configFile: configFilePath
22+
}
23+
}
24+
]
25+
}, {
26+
valid: [
27+
{
28+
text: `
29+
[role="executable"]
30+
[source,javascript]
31+
.thenコード例
32+
----
33+
var promise = new Promise(function(resolve, reject) {
34+
resolve("thenに渡す値");
35+
});
36+
promise.then(function(value) {
37+
console.log(value);
38+
}, function(error) {
39+
console.error(error);
40+
});
41+
----
42+
`,
43+
ext: ".adoc",
44+
45+
}
46+
],
47+
invalid: [
48+
{
49+
text: `
50+
[source,javascript]
51+
----
52+
var a = 1
53+
----
54+
`,
55+
output: `
56+
[source,javascript]
57+
----
58+
var a = 1;
59+
----
60+
`,
61+
ext: ".adoc",
62+
errors: [{
63+
index: 35
64+
}]
65+
}
66+
]
67+
68+
});

test/mocha.opts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--require textlint-scripts/register

test/textlint-rule-eslint-test.js

Lines changed: 55 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// LICENSE : MIT
22
"use strict";
33
import rule from "../src/textlint-rule-eslint";
4+
45
const path = require("path");
56
const TextLintTester = require("textlint-tester");
67
const tester = new TextLintTester();
@@ -17,35 +18,35 @@ tester.run("textlint-rule-eslint", rule, {
1718
},
1819
{
1920
text: "```js\n" +
20-
"var a = 1;\n" +
21-
"```",
21+
"var a = 1;\n" +
22+
"```",
2223
options: {
23-
configFile: configFilePath
24+
configFile: configFilePath
2425
}
2526
},
2627
{
2728
text: "```js\n\n" +
28-
"var a = 1;\n\n" +
29-
"```",
29+
"var a = 1;\n\n" +
30+
"```",
3031
options: {
31-
configFile: configFilePath
32+
configFile: configFilePath
3233
}
3334
},
3435
{
3536
text: "```js\n\n" +
36-
"+++1+++\n" +
37-
"```",
37+
"+++1+++\n" +
38+
"```",
3839
options: {
39-
configFile: configFilePath,
40-
ignoreParsingErrors: true
40+
configFile: configFilePath,
41+
ignoreParsingErrors: true
4142
}
4243
},
4344
],
4445
invalid: [
4546
{
4647
text: "```js\n" +
47-
"+++1+++\n" +
48-
"```",
48+
"+++1+++\n" +
49+
"```",
4950
errors: [
5051
{
5152
message: "Parsing error: Assigning to rvalue",
@@ -59,11 +60,11 @@ tester.run("textlint-rule-eslint", rule, {
5960
},
6061
{
6162
text: "```js\n" +
62-
WrongCode1 + "\n" +
63-
"```",
63+
WrongCode1 + "\n" +
64+
"```",
6465
output: "```js\n" +
65-
WrongCode1 + ";\n" +
66-
"```",
66+
WrongCode1 + ";\n" +
67+
"```",
6768
errors: [
6869
{
6970
message: "semi: Missing semicolon.",
@@ -75,22 +76,47 @@ tester.run("textlint-rule-eslint", rule, {
7576
configFile: configFilePath
7677
}
7778
},
79+
{
80+
text: "```javascript\n" +
81+
"var a = 1\n" +
82+
"var b = 2\n" +
83+
"```",
84+
output: "```javascript\n" +
85+
"var a = 1;\n" +
86+
"var b = 2;\n" +
87+
"```",
88+
errors: [
89+
{
90+
message: "semi: Missing semicolon.",
91+
line: 2,
92+
column: 10
93+
},
94+
{
95+
message: "semi: Missing semicolon.",
96+
line: 3,
97+
column: 10
98+
}
99+
],
100+
options: {
101+
configFile: configFilePath
102+
}
103+
},
78104
// multiple
79105
{
80106
text: "```js\n" +
81-
WrongCode1 + "\n" +
82-
"```\n" +
83-
"This is text.\n" +
84-
"```js\n" +
85-
WrongCode2 + "\n" +
86-
"```",
107+
WrongCode1 + "\n" +
108+
"```\n" +
109+
"This is text.\n" +
110+
"```js\n" +
111+
WrongCode2 + "\n" +
112+
"```",
87113
output: "```js\n" +
88-
WrongCode1 + ";\n" +
89-
"```\n" +
90-
"This is text.\n" +
91-
"```js\n" +
92-
WrongCode2 + ";\n" +
93-
"```",
114+
WrongCode1 + ";\n" +
115+
"```\n" +
116+
"This is text.\n" +
117+
"```js\n" +
118+
WrongCode2 + ";\n" +
119+
"```",
94120
errors: [
95121
{
96122
message: "semi: Missing semicolon.",
@@ -107,4 +133,4 @@ tester.run("textlint-rule-eslint", rule, {
107133
}
108134
}
109135
]
110-
});
136+
});

0 commit comments

Comments
 (0)