markuplint 2.0.0-rc.3 → 2.1.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 +87 -30
- package/lib/api/index.d.mts +2 -0
- package/lib/api/index.mjs +2 -0
- package/lib/api/lint.d.mts +4 -0
- package/lib/api/lint.mjs +15 -0
- package/lib/api/ml-engine.d.mts +27 -0
- package/lib/api/ml-engine.js +7 -3
- package/lib/api/ml-engine.mjs +232 -0
- package/lib/api/types.d.mts +43 -0
- package/lib/api/types.d.ts +1 -1
- package/lib/api/types.mjs +1 -0
- package/lib/api/v1.d.mts +51 -0
- package/lib/api/v1.d.ts +0 -9
- package/lib/api/v1.js +0 -1
- package/lib/api/v1.mjs +39 -0
- package/lib/cli/bootstrap.d.mts +52 -0
- package/lib/cli/bootstrap.d.ts +24 -9
- package/lib/cli/bootstrap.js +39 -20
- package/lib/cli/bootstrap.mjs +81 -0
- package/lib/cli/command.d.mts +3 -0
- package/lib/cli/command.js +15 -2
- package/lib/cli/command.mjs +50 -0
- package/lib/cli/create-rule/index.d.mts +1 -0
- package/lib/cli/create-rule/index.js +4 -1
- package/lib/cli/create-rule/index.mjs +51 -0
- package/lib/cli/index.d.mts +1 -0
- package/lib/cli/index.mjs +64 -0
- package/lib/cli/index.spec.d.mts +1 -0
- package/lib/cli/index.spec.mjs +48 -0
- package/lib/cli/init/index.d.mts +1 -0
- package/lib/cli/init/index.js +92 -55
- package/lib/cli/init/index.mjs +266 -0
- package/lib/cli/init/install-module.d.mts +5 -0
- package/lib/cli/init/install-module.mjs +61 -0
- package/lib/cli/output.d.mts +3 -0
- package/lib/cli/output.mjs +31 -0
- package/lib/cli/prompt.d.mts +18 -0
- package/lib/cli/prompt.mjs +68 -0
- package/lib/debug.d.mts +3 -0
- package/lib/debug.mjs +10 -0
- package/lib/global-settings.d.mts +5 -0
- package/lib/global-settings.mjs +10 -0
- package/lib/i18n.d.mts +6 -0
- package/lib/i18n.mjs +19 -0
- package/lib/index.d.mts +8 -0
- package/lib/index.mjs +8 -0
- package/lib/reporter/index.d.mts +2 -0
- package/lib/reporter/index.mjs +2 -0
- package/lib/reporter/simple-reporter.d.mts +3 -0
- package/lib/reporter/simple-reporter.js +7 -7
- package/lib/reporter/simple-reporter.mjs +30 -0
- package/lib/reporter/standard-reporter.d.mts +3 -0
- package/lib/reporter/standard-reporter.js +10 -10
- package/lib/reporter/standard-reporter.mjs +43 -0
- package/lib/testing-tool/index.d.mts +35 -0
- package/lib/testing-tool/index.js +2 -0
- package/lib/testing-tool/index.mjs +83 -0
- package/lib/types.d.mts +27 -0
- package/lib/types.mjs +1 -0
- package/lib/util.d.mts +19 -0
- package/lib/util.d.ts +16 -0
- package/lib/util.js +75 -1
- package/lib/util.mjs +73 -0
- package/lib/v1.d.mts +4 -0
- package/lib/v1.mjs +4 -0
- package/media/screenshot01.png +0 -0
- package/package.json +14 -14
- package/tsconfig.tsbuildinfo +1 -1
- package/RESOLVE_CONFIG.md +0 -77
- package/lib/reporter/utils.d.ts +0 -6
- package/lib/reporter/utils.js +0 -40
package/lib/cli/init/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const fs_1 = (0, tslib_1.__importDefault)(require("fs"));
|
|
|
6
6
|
const path_1 = (0, tslib_1.__importDefault)(require("path"));
|
|
7
7
|
const util_1 = (0, tslib_1.__importDefault)(require("util"));
|
|
8
8
|
const ml_config_1 = require("@markuplint/ml-config");
|
|
9
|
+
const util_2 = require("../../util");
|
|
9
10
|
const prompt_1 = require("../prompt");
|
|
10
11
|
const install_module_1 = require("./install-module");
|
|
11
12
|
const writeFile = util_1.default.promisify(fs_1.default.writeFile);
|
|
@@ -28,10 +29,43 @@ const defaultRules = {
|
|
|
28
29
|
category: 'validation',
|
|
29
30
|
default: true,
|
|
30
31
|
},
|
|
32
|
+
'attr-equal-space-after': {
|
|
33
|
+
category: 'style',
|
|
34
|
+
default: true,
|
|
35
|
+
},
|
|
36
|
+
'attr-equal-space-before': {
|
|
37
|
+
category: 'style',
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
40
|
+
'attr-spacing': {
|
|
41
|
+
category: 'style',
|
|
42
|
+
default: true,
|
|
43
|
+
},
|
|
44
|
+
'attr-value-quotes': {
|
|
45
|
+
category: 'style',
|
|
46
|
+
default: true,
|
|
47
|
+
},
|
|
48
|
+
'case-sensitive-attr-name': {
|
|
49
|
+
category: 'style',
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
'case-sensitive-attr-value': {
|
|
53
|
+
category: 'style',
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
'case-sensitive-tag-name': {
|
|
57
|
+
category: 'style',
|
|
58
|
+
default: true,
|
|
59
|
+
},
|
|
31
60
|
'character-reference': {
|
|
32
61
|
category: 'validation',
|
|
33
62
|
default: true,
|
|
34
63
|
},
|
|
64
|
+
'class-naming': {
|
|
65
|
+
category: 'naming-convention',
|
|
66
|
+
default: false,
|
|
67
|
+
recommendedValue: '/.+/',
|
|
68
|
+
},
|
|
35
69
|
'deprecated-attr': {
|
|
36
70
|
category: 'validation',
|
|
37
71
|
default: true,
|
|
@@ -40,19 +74,28 @@ const defaultRules = {
|
|
|
40
74
|
category: 'validation',
|
|
41
75
|
default: true,
|
|
42
76
|
},
|
|
77
|
+
'disallowed-element': {
|
|
78
|
+
category: 'validation',
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
43
81
|
doctype: {
|
|
44
82
|
category: 'validation',
|
|
45
83
|
default: true,
|
|
46
84
|
},
|
|
47
|
-
'
|
|
48
|
-
category: '
|
|
85
|
+
'end-tag': {
|
|
86
|
+
category: 'style',
|
|
49
87
|
default: true,
|
|
50
88
|
},
|
|
51
|
-
'
|
|
89
|
+
'id-duplication': {
|
|
52
90
|
category: 'validation',
|
|
53
91
|
default: true,
|
|
54
92
|
},
|
|
55
|
-
|
|
93
|
+
indentation: {
|
|
94
|
+
category: 'style',
|
|
95
|
+
default: false,
|
|
96
|
+
recommendedValue: 2,
|
|
97
|
+
},
|
|
98
|
+
'ineffective-attr': {
|
|
56
99
|
category: 'validation',
|
|
57
100
|
default: true,
|
|
58
101
|
},
|
|
@@ -64,52 +107,52 @@ const defaultRules = {
|
|
|
64
107
|
category: 'a11y',
|
|
65
108
|
default: true,
|
|
66
109
|
},
|
|
67
|
-
'
|
|
68
|
-
category: '
|
|
110
|
+
'no-boolean-attr-value': {
|
|
111
|
+
category: 'style',
|
|
69
112
|
default: true,
|
|
70
113
|
},
|
|
71
|
-
'
|
|
72
|
-
category: '
|
|
114
|
+
'no-default-value': {
|
|
115
|
+
category: 'style',
|
|
73
116
|
default: true,
|
|
74
117
|
},
|
|
75
|
-
'
|
|
76
|
-
category: 'naming-convention',
|
|
77
|
-
default: false,
|
|
78
|
-
recommendedValue: '/.+/',
|
|
79
|
-
},
|
|
80
|
-
'attr-equal-space-after': {
|
|
118
|
+
'no-hard-code-id': {
|
|
81
119
|
category: 'style',
|
|
82
120
|
default: true,
|
|
83
121
|
},
|
|
84
|
-
'
|
|
85
|
-
category: '
|
|
122
|
+
'no-refer-to-non-existent-id': {
|
|
123
|
+
category: 'a11y',
|
|
86
124
|
default: true,
|
|
87
125
|
},
|
|
88
|
-
'attr
|
|
126
|
+
'no-use-event-handler-attr': {
|
|
89
127
|
category: 'style',
|
|
90
128
|
default: true,
|
|
91
129
|
},
|
|
92
|
-
'
|
|
93
|
-
category: '
|
|
130
|
+
'permitted-contents': {
|
|
131
|
+
category: 'validation',
|
|
94
132
|
default: true,
|
|
95
133
|
},
|
|
96
|
-
'
|
|
97
|
-
category: '
|
|
134
|
+
'required-attr': {
|
|
135
|
+
category: 'validation',
|
|
98
136
|
default: true,
|
|
99
137
|
},
|
|
100
|
-
'
|
|
101
|
-
category: '
|
|
138
|
+
'required-element': {
|
|
139
|
+
category: 'validation',
|
|
102
140
|
default: true,
|
|
103
141
|
},
|
|
104
|
-
|
|
105
|
-
category: '
|
|
106
|
-
default:
|
|
107
|
-
|
|
142
|
+
'required-h1': {
|
|
143
|
+
category: 'a11y',
|
|
144
|
+
default: true,
|
|
145
|
+
},
|
|
146
|
+
'wai-aria': {
|
|
147
|
+
category: 'a11y',
|
|
148
|
+
default: true,
|
|
108
149
|
},
|
|
109
150
|
};
|
|
110
151
|
const extRExp = {
|
|
152
|
+
jsx: '\\.[jt]sx?$',
|
|
111
153
|
vue: '\\.vue$',
|
|
112
154
|
svelte: '\\.svelte$',
|
|
155
|
+
astro: '\\.astro',
|
|
113
156
|
pug: '\\.pug$',
|
|
114
157
|
php: '\\.php$',
|
|
115
158
|
erb: '\\.erb$',
|
|
@@ -120,14 +163,15 @@ const extRExp = {
|
|
|
120
163
|
};
|
|
121
164
|
async function initialize() {
|
|
122
165
|
let config = {};
|
|
123
|
-
write(
|
|
124
|
-
write.break();
|
|
166
|
+
(0, util_2.write)((0, util_2.head)('Initialization'));
|
|
167
|
+
util_2.write.break();
|
|
125
168
|
const langs = await (0, prompt_1.multiSelect)({
|
|
126
169
|
message: 'Which do you use template engines?',
|
|
127
170
|
choices: [
|
|
128
171
|
{ name: 'React (JSX)', value: 'jsx' },
|
|
129
172
|
{ name: 'Vue', value: 'vue' },
|
|
130
173
|
{ name: 'Svelte', value: 'svelte' },
|
|
174
|
+
{ name: 'Astro', value: 'astro' },
|
|
131
175
|
{ name: 'Pug', value: 'pug' },
|
|
132
176
|
{ name: 'PHP', value: 'php' },
|
|
133
177
|
{ name: 'eRuby', value: 'erb' },
|
|
@@ -139,13 +183,8 @@ async function initialize() {
|
|
|
139
183
|
});
|
|
140
184
|
const autoInstall = await (0, prompt_1.confirm)('May I install them automatically?');
|
|
141
185
|
const customize = await (0, prompt_1.confirm)('Do you customize rules?');
|
|
142
|
-
if (langs && langs.length) {
|
|
143
|
-
config.parser = {};
|
|
144
|
-
}
|
|
145
186
|
for (const lang of langs) {
|
|
146
|
-
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
187
|
+
config.parser = config.parser || {};
|
|
149
188
|
// @ts-ignore
|
|
150
189
|
const ext = extRExp[lang];
|
|
151
190
|
if (!ext) {
|
|
@@ -155,14 +194,14 @@ async function initialize() {
|
|
|
155
194
|
if (lang === 'vue') {
|
|
156
195
|
config = (0, ml_config_1.mergeConfig)(config, {
|
|
157
196
|
specs: {
|
|
158
|
-
'
|
|
197
|
+
'\\.vue$': '@markuplint/vue-spec',
|
|
159
198
|
},
|
|
160
199
|
});
|
|
161
200
|
}
|
|
162
201
|
if (lang === 'jsx') {
|
|
163
202
|
config = (0, ml_config_1.mergeConfig)(config, {
|
|
164
203
|
specs: {
|
|
165
|
-
'
|
|
204
|
+
'\\.[jt]sx?$': '@markuplint/react-spec',
|
|
166
205
|
},
|
|
167
206
|
});
|
|
168
207
|
}
|
|
@@ -191,18 +230,24 @@ async function initialize() {
|
|
|
191
230
|
}
|
|
192
231
|
}
|
|
193
232
|
else {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
233
|
+
const recommended = await (0, prompt_1.confirm)('Does it import the recommended config?');
|
|
234
|
+
if (recommended) {
|
|
235
|
+
config.extends = [...(config.extends || []), 'markuplint:recommended'];
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
config.rules = {};
|
|
239
|
+
const ruleNames = Object.keys(defaultRules);
|
|
240
|
+
for (const ruleName of ruleNames) {
|
|
241
|
+
const rule = defaultRules[ruleName];
|
|
242
|
+
config.rules[ruleName] = rule.default;
|
|
243
|
+
}
|
|
199
244
|
}
|
|
200
245
|
}
|
|
201
246
|
const filePath = path_1.default.resolve(process.cwd(), '.markuplintrc');
|
|
202
247
|
await writeFile(filePath, JSON.stringify(config, null, 2), { encoding: 'utf-8' });
|
|
203
|
-
write(`✨Created: ${filePath}`);
|
|
248
|
+
(0, util_2.write)(`✨Created: ${filePath}`);
|
|
204
249
|
if (autoInstall) {
|
|
205
|
-
write('Install automatically');
|
|
250
|
+
(0, util_2.write)('Install automatically');
|
|
206
251
|
const modules = ['markuplint', ...langs.map(lang => `@markuplint/${lang}-parser`)];
|
|
207
252
|
if (langs.includes('vue')) {
|
|
208
253
|
modules.push('@markuplint/vue-spec');
|
|
@@ -212,23 +257,15 @@ async function initialize() {
|
|
|
212
257
|
}
|
|
213
258
|
const result = await (0, install_module_1.installModule)(modules, true).catch(e => new Error(e));
|
|
214
259
|
if (result instanceof Error) {
|
|
215
|
-
error.exit();
|
|
260
|
+
util_2.error.exit();
|
|
216
261
|
return;
|
|
217
262
|
}
|
|
218
263
|
if (result.alreadyExists) {
|
|
219
|
-
write('Modules are installed already.');
|
|
264
|
+
(0, util_2.write)('Modules are installed already.');
|
|
220
265
|
}
|
|
221
266
|
else {
|
|
222
|
-
write('✨ Success');
|
|
267
|
+
(0, util_2.write)('✨ Success');
|
|
223
268
|
}
|
|
224
269
|
}
|
|
225
270
|
}
|
|
226
271
|
exports.initialize = initialize;
|
|
227
|
-
function write(message) {
|
|
228
|
-
process.stdout.write(message + '\n');
|
|
229
|
-
}
|
|
230
|
-
write.break = () => process.stdout.write('\n');
|
|
231
|
-
function error(message) {
|
|
232
|
-
process.stderr.write(message + '\n');
|
|
233
|
-
}
|
|
234
|
-
error.exit = () => process.exit(1);
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import util from 'util';
|
|
4
|
+
import { mergeConfig } from '@markuplint/ml-config';
|
|
5
|
+
import { head, write, error } from '../../util.mjs';
|
|
6
|
+
import { confirm, confirmSequence, multiSelect } from '../prompt.mjs';
|
|
7
|
+
import { installModule } from './install-module.mjs';
|
|
8
|
+
const writeFile = util.promisify(fs.writeFile);
|
|
9
|
+
const ruleCategories = {
|
|
10
|
+
validation: {
|
|
11
|
+
message: 'Are you going to conformance check according to HTML standard?',
|
|
12
|
+
},
|
|
13
|
+
a11y: {
|
|
14
|
+
message: 'Are you going to do with accessibility better practices?',
|
|
15
|
+
},
|
|
16
|
+
'naming-convention': {
|
|
17
|
+
message: 'Are you going to set the convention about naming?',
|
|
18
|
+
},
|
|
19
|
+
style: {
|
|
20
|
+
message: 'Are you going to check for the code styles?',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
const defaultRules = {
|
|
24
|
+
'attr-duplication': {
|
|
25
|
+
category: 'validation',
|
|
26
|
+
default: true,
|
|
27
|
+
},
|
|
28
|
+
'attr-equal-space-after': {
|
|
29
|
+
category: 'style',
|
|
30
|
+
default: true,
|
|
31
|
+
},
|
|
32
|
+
'attr-equal-space-before': {
|
|
33
|
+
category: 'style',
|
|
34
|
+
default: true,
|
|
35
|
+
},
|
|
36
|
+
'attr-spacing': {
|
|
37
|
+
category: 'style',
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
40
|
+
'attr-value-quotes': {
|
|
41
|
+
category: 'style',
|
|
42
|
+
default: true,
|
|
43
|
+
},
|
|
44
|
+
'case-sensitive-attr-name': {
|
|
45
|
+
category: 'style',
|
|
46
|
+
default: true,
|
|
47
|
+
},
|
|
48
|
+
'case-sensitive-attr-value': {
|
|
49
|
+
category: 'style',
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
'case-sensitive-tag-name': {
|
|
53
|
+
category: 'style',
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
'character-reference': {
|
|
57
|
+
category: 'validation',
|
|
58
|
+
default: true,
|
|
59
|
+
},
|
|
60
|
+
'class-naming': {
|
|
61
|
+
category: 'naming-convention',
|
|
62
|
+
default: false,
|
|
63
|
+
recommendedValue: '/.+/',
|
|
64
|
+
},
|
|
65
|
+
'deprecated-attr': {
|
|
66
|
+
category: 'validation',
|
|
67
|
+
default: true,
|
|
68
|
+
},
|
|
69
|
+
'deprecated-element': {
|
|
70
|
+
category: 'validation',
|
|
71
|
+
default: true,
|
|
72
|
+
},
|
|
73
|
+
'disallowed-element': {
|
|
74
|
+
category: 'validation',
|
|
75
|
+
default: false,
|
|
76
|
+
},
|
|
77
|
+
doctype: {
|
|
78
|
+
category: 'validation',
|
|
79
|
+
default: true,
|
|
80
|
+
},
|
|
81
|
+
'end-tag': {
|
|
82
|
+
category: 'style',
|
|
83
|
+
default: true,
|
|
84
|
+
},
|
|
85
|
+
'id-duplication': {
|
|
86
|
+
category: 'validation',
|
|
87
|
+
default: true,
|
|
88
|
+
},
|
|
89
|
+
indentation: {
|
|
90
|
+
category: 'style',
|
|
91
|
+
default: false,
|
|
92
|
+
recommendedValue: 2,
|
|
93
|
+
},
|
|
94
|
+
'ineffective-attr': {
|
|
95
|
+
category: 'validation',
|
|
96
|
+
default: true,
|
|
97
|
+
},
|
|
98
|
+
'invalid-attr': {
|
|
99
|
+
category: 'validation',
|
|
100
|
+
default: true,
|
|
101
|
+
},
|
|
102
|
+
'landmark-roles': {
|
|
103
|
+
category: 'a11y',
|
|
104
|
+
default: true,
|
|
105
|
+
},
|
|
106
|
+
'no-boolean-attr-value': {
|
|
107
|
+
category: 'style',
|
|
108
|
+
default: true,
|
|
109
|
+
},
|
|
110
|
+
'no-default-value': {
|
|
111
|
+
category: 'style',
|
|
112
|
+
default: true,
|
|
113
|
+
},
|
|
114
|
+
'no-hard-code-id': {
|
|
115
|
+
category: 'style',
|
|
116
|
+
default: true,
|
|
117
|
+
},
|
|
118
|
+
'no-refer-to-non-existent-id': {
|
|
119
|
+
category: 'a11y',
|
|
120
|
+
default: true,
|
|
121
|
+
},
|
|
122
|
+
'no-use-event-handler-attr': {
|
|
123
|
+
category: 'style',
|
|
124
|
+
default: true,
|
|
125
|
+
},
|
|
126
|
+
'permitted-contents': {
|
|
127
|
+
category: 'validation',
|
|
128
|
+
default: true,
|
|
129
|
+
},
|
|
130
|
+
'required-attr': {
|
|
131
|
+
category: 'validation',
|
|
132
|
+
default: true,
|
|
133
|
+
},
|
|
134
|
+
'required-element': {
|
|
135
|
+
category: 'validation',
|
|
136
|
+
default: true,
|
|
137
|
+
},
|
|
138
|
+
'required-h1': {
|
|
139
|
+
category: 'a11y',
|
|
140
|
+
default: true,
|
|
141
|
+
},
|
|
142
|
+
'wai-aria': {
|
|
143
|
+
category: 'a11y',
|
|
144
|
+
default: true,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
const extRExp = {
|
|
148
|
+
jsx: '\\.[jt]sx?$',
|
|
149
|
+
vue: '\\.vue$',
|
|
150
|
+
svelte: '\\.svelte$',
|
|
151
|
+
astro: '\\.astro',
|
|
152
|
+
pug: '\\.pug$',
|
|
153
|
+
php: '\\.php$',
|
|
154
|
+
erb: '\\.erb$',
|
|
155
|
+
ejs: '\\.ejs$',
|
|
156
|
+
mustache: '\\.(mustache|handlebars)$',
|
|
157
|
+
nunjucks: '\\.nunjucks$',
|
|
158
|
+
liquid: '\\.liquid$',
|
|
159
|
+
};
|
|
160
|
+
export async function initialize() {
|
|
161
|
+
let config = {};
|
|
162
|
+
write(head('Initialization'));
|
|
163
|
+
write.break();
|
|
164
|
+
const langs = await multiSelect({
|
|
165
|
+
message: 'Which do you use template engines?',
|
|
166
|
+
choices: [
|
|
167
|
+
{ name: 'React (JSX)', value: 'jsx' },
|
|
168
|
+
{ name: 'Vue', value: 'vue' },
|
|
169
|
+
{ name: 'Svelte', value: 'svelte' },
|
|
170
|
+
{ name: 'Astro', value: 'astro' },
|
|
171
|
+
{ name: 'Pug', value: 'pug' },
|
|
172
|
+
{ name: 'PHP', value: 'php' },
|
|
173
|
+
{ name: 'eRuby', value: 'erb' },
|
|
174
|
+
{ name: 'EJS', value: 'ejs' },
|
|
175
|
+
{ name: 'Mustache/Handlebars', value: 'mustache' },
|
|
176
|
+
{ name: 'Nunjucks', value: 'nunjucks' },
|
|
177
|
+
{ name: 'liquid (Shopify)', value: 'liquid' },
|
|
178
|
+
],
|
|
179
|
+
});
|
|
180
|
+
const autoInstall = await confirm('May I install them automatically?');
|
|
181
|
+
const customize = await confirm('Do you customize rules?');
|
|
182
|
+
for (const lang of langs) {
|
|
183
|
+
config.parser = config.parser || {};
|
|
184
|
+
// @ts-ignore
|
|
185
|
+
const ext = extRExp[lang];
|
|
186
|
+
if (!ext) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
config.parser[ext] = `@markuplint/${lang}-parser`;
|
|
190
|
+
if (lang === 'vue') {
|
|
191
|
+
config = mergeConfig(config, {
|
|
192
|
+
specs: {
|
|
193
|
+
'\\.vue$': '@markuplint/vue-spec',
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (lang === 'jsx') {
|
|
198
|
+
config = mergeConfig(config, {
|
|
199
|
+
specs: {
|
|
200
|
+
'\\.[jt]sx?$': '@markuplint/react-spec',
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (customize) {
|
|
206
|
+
const ruleNames = Object.keys(defaultRules);
|
|
207
|
+
const categories = Object.keys(ruleCategories);
|
|
208
|
+
const res = await confirmSequence(categories.map(catName => {
|
|
209
|
+
const cat = ruleCategories[catName];
|
|
210
|
+
return {
|
|
211
|
+
message: cat.message,
|
|
212
|
+
name: catName,
|
|
213
|
+
};
|
|
214
|
+
}));
|
|
215
|
+
for (const ruleName of ruleNames) {
|
|
216
|
+
const rule = defaultRules[ruleName];
|
|
217
|
+
if (!rule) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (res[rule.category]) {
|
|
221
|
+
if (!config.rules) {
|
|
222
|
+
config.rules = {};
|
|
223
|
+
}
|
|
224
|
+
config.rules[ruleName] = rule.recommendedValue || true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const recommended = await confirm('Does it import the recommended config?');
|
|
230
|
+
if (recommended) {
|
|
231
|
+
config.extends = [...(config.extends || []), 'markuplint:recommended'];
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
config.rules = {};
|
|
235
|
+
const ruleNames = Object.keys(defaultRules);
|
|
236
|
+
for (const ruleName of ruleNames) {
|
|
237
|
+
const rule = defaultRules[ruleName];
|
|
238
|
+
config.rules[ruleName] = rule.default;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const filePath = path.resolve(process.cwd(), '.markuplintrc');
|
|
243
|
+
await writeFile(filePath, JSON.stringify(config, null, 2), { encoding: 'utf-8' });
|
|
244
|
+
write(`✨Created: ${filePath}`);
|
|
245
|
+
if (autoInstall) {
|
|
246
|
+
write('Install automatically');
|
|
247
|
+
const modules = ['markuplint', ...langs.map(lang => `@markuplint/${lang}-parser`)];
|
|
248
|
+
if (langs.includes('vue')) {
|
|
249
|
+
modules.push('@markuplint/vue-spec');
|
|
250
|
+
}
|
|
251
|
+
if (langs.includes('jsx')) {
|
|
252
|
+
modules.push('@markuplint/react-spec');
|
|
253
|
+
}
|
|
254
|
+
const result = await installModule(modules, true).catch(e => new Error(e));
|
|
255
|
+
if (result instanceof Error) {
|
|
256
|
+
error.exit();
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (result.alreadyExists) {
|
|
260
|
+
write('Modules are installed already.');
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
write('✨ Success');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import c from 'cli-color';
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import detectInstalled from 'detect-installed';
|
|
5
|
+
import hasYarn from 'has-yarn';
|
|
6
|
+
export async function installModule(module, dev = false) {
|
|
7
|
+
module = module.map(m => m.trim());
|
|
8
|
+
const uninstallMods = [];
|
|
9
|
+
try {
|
|
10
|
+
for (const mod of module) {
|
|
11
|
+
const installed = await isInstalled(mod);
|
|
12
|
+
if (!installed) {
|
|
13
|
+
uninstallMods.push(mod);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch (_) {
|
|
18
|
+
// void
|
|
19
|
+
}
|
|
20
|
+
if (!uninstallMods.length) {
|
|
21
|
+
return {
|
|
22
|
+
success: true,
|
|
23
|
+
alreadyExists: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const mod = hasYarn() ? 'yarn' : 'npm';
|
|
27
|
+
const installOpt = hasYarn() ? 'add' : 'install';
|
|
28
|
+
const opt = [installOpt];
|
|
29
|
+
if (dev) {
|
|
30
|
+
opt.push('-D');
|
|
31
|
+
}
|
|
32
|
+
opt.push(...uninstallMods);
|
|
33
|
+
return new Promise((resolve, reject) => {
|
|
34
|
+
process.stdout.write(c.blackBright(`${mod} ${opt.join(' ')}\n`));
|
|
35
|
+
const result = spawnSync(mod, opt, { stdio: 'inherit' });
|
|
36
|
+
if (result.error || result.status !== 0) {
|
|
37
|
+
const message = 'Error running command.';
|
|
38
|
+
const error = new Error(message);
|
|
39
|
+
error.stack = message;
|
|
40
|
+
reject(error);
|
|
41
|
+
}
|
|
42
|
+
resolve({
|
|
43
|
+
success: true,
|
|
44
|
+
alreadyExists: false,
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function isInstalled(module) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
try {
|
|
51
|
+
detectInstalled(module, {
|
|
52
|
+
local: true,
|
|
53
|
+
}).then((exists) => {
|
|
54
|
+
resolve(exists);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
reject(err);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import stripAnsi from 'strip-ansi';
|
|
2
|
+
import { simpleReporter, standardReporter } from '../reporter/index.mjs';
|
|
3
|
+
export async function output(results, options) {
|
|
4
|
+
const format = options.format ?? 'Standard';
|
|
5
|
+
let out;
|
|
6
|
+
switch (format.toLowerCase()) {
|
|
7
|
+
case 'json': {
|
|
8
|
+
process.stdout.write(JSON.stringify(results.violations, null, 2));
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
case 'simple': {
|
|
12
|
+
out = simpleReporter(results, options);
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
default: {
|
|
16
|
+
out = standardReporter(results, options);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (!out.length) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
let msg = `${out.join('\n')}\n`;
|
|
23
|
+
msg = options.color ? msg : stripAnsi(msg);
|
|
24
|
+
// If it has errors, Write to `stderr` and failure and exit.
|
|
25
|
+
if (results.violations.length) {
|
|
26
|
+
process.stderr.write(msg);
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
process.stdout.write(msg);
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
declare type SelectQuestion<T> = {
|
|
2
|
+
message: string;
|
|
3
|
+
choices: {
|
|
4
|
+
name: string;
|
|
5
|
+
value: T;
|
|
6
|
+
}[];
|
|
7
|
+
};
|
|
8
|
+
export declare function select<T>(question: SelectQuestion<T>): Promise<T>;
|
|
9
|
+
export declare function multiSelect<T>(question: SelectQuestion<T>): Promise<T[]>;
|
|
10
|
+
export declare function input<T extends string = string>(question: string, validation?: RegExp): Promise<T>;
|
|
11
|
+
export declare function confirm(question: string, options?: {
|
|
12
|
+
initial?: boolean;
|
|
13
|
+
}): Promise<boolean>;
|
|
14
|
+
export declare function confirmSequence<T extends string = string>(questions: {
|
|
15
|
+
message: string;
|
|
16
|
+
name: T;
|
|
17
|
+
}[]): Promise<Record<T, boolean>>;
|
|
18
|
+
export {};
|