@drupal-canvas/eslint-config 0.1.2 → 0.1.4
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 +17 -8
- package/dist/index.js +204 -179
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,11 +4,12 @@ ESLint config for validating Drupal Canvas Code Components.
|
|
|
4
4
|
|
|
5
5
|
## Config variants
|
|
6
6
|
|
|
7
|
-
| Config
|
|
8
|
-
|
|
|
9
|
-
| `required`
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
7
|
+
| Config | Description |
|
|
8
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
9
|
+
| `required` | Base settings for parsing JavaScript and TypeScript files, YAML parsing for component metadata files, and custom rules for Drupal Canvas Code Component validation. Automatically used by [`@drupal-canvas/cli`](https://www.npmjs.com/package/@drupal-canvas/cli) when validating, building, or uploading components. |
|
|
10
|
+
| `requiredDeprecated` | @deprecated Legacy version of the `required` config used by `build-d` command of [`@drupal-canvas/cli`](https://www.npmjs.com/package/@drupal-canvas/cli#deprecated-build-d). |
|
|
11
|
+
| `recommended` | `required` + recommended rules from [`@eslint/js`](https://www.npmjs.com/package/@eslint/js), [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react), [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks), [`eslint-plugin-jsx-a11y`](https://www.npmjs.com/package/eslint-plugin-jsx-a11y), [`eslint-plugin-yml`](https://www.npmjs.com/package/eslint-plugin-yml) and [`typescript-eslint`](https://www.npmjs.com/package/typescript-eslint). |
|
|
12
|
+
| `strict` | `recommended` + strict rules from [`eslint-plugin-jsx-a11y`](https://www.npmjs.com/package/eslint-plugin-jsx-a11y) and [`typescript-eslint`](https://www.npmjs.com/package/typescript-eslint). |
|
|
12
13
|
|
|
13
14
|
## Usage
|
|
14
15
|
|
|
@@ -32,14 +33,22 @@ export default defineConfig([
|
|
|
32
33
|
The following custom rules are part of the `required` config and validate Drupal
|
|
33
34
|
Canvas Code Components:
|
|
34
35
|
|
|
36
|
+
| Rule | Description |
|
|
37
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
38
|
+
| `component-dir-name` | Validates that `machineName` matches the directory name (index-style) or filename prefix (named-style). |
|
|
39
|
+
| `component-exports` | Validates that component has a default export. |
|
|
40
|
+
| `component-prop-names` | Validates that component prop IDs match the camelCase version of their titles. |
|
|
41
|
+
|
|
42
|
+
### Deprecated rules
|
|
43
|
+
|
|
44
|
+
The following rules are deprecated and only used in the `requiredDeprecated`
|
|
45
|
+
config:
|
|
46
|
+
|
|
35
47
|
| Rule | Description |
|
|
36
48
|
| ------------------------ | ----------------------------------------------------------------------------------------- |
|
|
37
|
-
| `component-dir-name` | Validates that component directory name matches the `machineName` in component.yml. |
|
|
38
|
-
| `component-exports` | Validates that component has a default export. |
|
|
39
49
|
| `component-files` | Validates that component directory contains only allowed files. |
|
|
40
50
|
| `component-imports` | Validates that component imports only from supported import sources and patterns. |
|
|
41
51
|
| `component-no-hierarchy` | Validates that all component directories are at the same level with no nesting hierarchy. |
|
|
42
|
-
| `component-prop-names` | Validates that component prop IDs match the camelCase version of their titles. |
|
|
43
52
|
|
|
44
53
|
## Development
|
|
45
54
|
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,37 @@
|
|
|
1
|
+
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
2
|
+
import react from 'eslint-plugin-react';
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
1
4
|
import eslintPluginYml from 'eslint-plugin-yml';
|
|
2
5
|
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
6
|
+
import tseslint from 'typescript-eslint';
|
|
7
|
+
import js from '@eslint/js';
|
|
3
8
|
import globals from 'globals';
|
|
4
9
|
import { dirname, basename } from 'path';
|
|
5
10
|
import { existsSync, readdirSync } from 'fs';
|
|
6
11
|
import { camelCase } from 'lodash-es';
|
|
7
|
-
import jsxA11y from 'eslint-plugin-jsx-a11y';
|
|
8
|
-
import react from 'eslint-plugin-react';
|
|
9
|
-
import reactHooks from 'eslint-plugin-react-hooks';
|
|
10
|
-
import js from '@eslint/js';
|
|
11
12
|
|
|
12
|
-
// src/configs/
|
|
13
|
+
// src/configs/recommended.ts
|
|
14
|
+
var JS_EXTENSIONS = ["ts", "tsx", "js", "jsx"];
|
|
15
|
+
var NAMED_SUFFIX = ".component.yml";
|
|
16
|
+
function isComponentEntrypoint(context) {
|
|
17
|
+
if (!isInComponentDir(context)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
const componentDir = dirname(context.filename);
|
|
21
|
+
const files = getFilesInDirectory(componentDir);
|
|
22
|
+
const namedMetadataFile = files.find((file) => file.endsWith(NAMED_SUFFIX));
|
|
23
|
+
const componentBaseName = namedMetadataFile ? namedMetadataFile.slice(0, -NAMED_SUFFIX.length) : "index";
|
|
24
|
+
return JS_EXTENSIONS.some(
|
|
25
|
+
(ext) => basename(context.filename) === componentBaseName + "." + ext
|
|
26
|
+
);
|
|
27
|
+
}
|
|
13
28
|
function isInComponentDir(context) {
|
|
14
29
|
try {
|
|
15
30
|
const componentDir = dirname(context.filename);
|
|
16
31
|
const files = getFilesInDirectory(componentDir);
|
|
17
|
-
return files.
|
|
32
|
+
return files.filter(
|
|
33
|
+
(file) => basename(file) === "component.yml" || file.endsWith(NAMED_SUFFIX)
|
|
34
|
+
).length > 0;
|
|
18
35
|
} catch {
|
|
19
36
|
return false;
|
|
20
37
|
}
|
|
@@ -22,7 +39,7 @@ function isInComponentDir(context) {
|
|
|
22
39
|
function isComponentYmlFile(context) {
|
|
23
40
|
try {
|
|
24
41
|
const fileName = basename(context.filename);
|
|
25
|
-
return fileName === "component.yml";
|
|
42
|
+
return fileName === "component.yml" || fileName.endsWith(NAMED_SUFFIX);
|
|
26
43
|
} catch {
|
|
27
44
|
return false;
|
|
28
45
|
}
|
|
@@ -47,11 +64,23 @@ function getYAMLStringValue(node) {
|
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
// src/rules/component-dir-name.ts
|
|
67
|
+
var NAMED_SUFFIX2 = ".component.yml";
|
|
68
|
+
function getExpectedMachineName(filename) {
|
|
69
|
+
const fileName = basename(filename);
|
|
70
|
+
if (fileName !== "component.yml" && fileName.endsWith(NAMED_SUFFIX2)) {
|
|
71
|
+
return {
|
|
72
|
+
name: fileName.slice(0, -NAMED_SUFFIX2.length),
|
|
73
|
+
source: `metadata filename "${fileName}"`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const dirName = basename(dirname(filename));
|
|
77
|
+
return { name: dirName, source: `directory name "${dirName}"` };
|
|
78
|
+
}
|
|
50
79
|
var rule = {
|
|
51
80
|
meta: {
|
|
52
81
|
type: "problem",
|
|
53
82
|
docs: {
|
|
54
|
-
description: "Validates that component directory name
|
|
83
|
+
description: "Validates that the machineName in component metadata matches the component directory name (index-style) or filename prefix (named-style)"
|
|
55
84
|
}
|
|
56
85
|
},
|
|
57
86
|
create(context) {
|
|
@@ -59,6 +88,7 @@ var rule = {
|
|
|
59
88
|
return {};
|
|
60
89
|
}
|
|
61
90
|
let hasMachineName = false;
|
|
91
|
+
const { name: expectedName, source: expectedSource } = getExpectedMachineName(context.filename);
|
|
62
92
|
return {
|
|
63
93
|
YAMLPair(node) {
|
|
64
94
|
const keyName = getYAMLStringValue(node.key);
|
|
@@ -74,22 +104,18 @@ var rule = {
|
|
|
74
104
|
});
|
|
75
105
|
return;
|
|
76
106
|
}
|
|
77
|
-
|
|
78
|
-
const componentDirName = basename(componentDir);
|
|
79
|
-
if (componentDirName !== machineName) {
|
|
107
|
+
if (expectedName !== machineName) {
|
|
80
108
|
context.report({
|
|
81
109
|
node: node.value,
|
|
82
|
-
message:
|
|
110
|
+
message: `${expectedSource[0].toUpperCase()}${expectedSource.slice(1)} does not match machineName "${machineName}".`
|
|
83
111
|
});
|
|
84
112
|
}
|
|
85
113
|
},
|
|
86
114
|
"Program:exit"() {
|
|
87
115
|
if (!hasMachineName) {
|
|
88
|
-
const componentDir = dirname(context.filename);
|
|
89
|
-
const componentDirName = basename(componentDir);
|
|
90
116
|
context.report({
|
|
91
117
|
loc: { line: 1, column: 0 },
|
|
92
|
-
message: `machineName key is missing. Its value should
|
|
118
|
+
message: `machineName key is missing. Its value should be "${expectedName}" based on ${expectedSource.toLowerCase()}.`
|
|
93
119
|
});
|
|
94
120
|
}
|
|
95
121
|
}
|
|
@@ -107,10 +133,7 @@ var rule2 = {
|
|
|
107
133
|
}
|
|
108
134
|
},
|
|
109
135
|
create(context) {
|
|
110
|
-
if (!
|
|
111
|
-
return {};
|
|
112
|
-
}
|
|
113
|
-
if (!isInComponentDir(context)) {
|
|
136
|
+
if (!isComponentEntrypoint(context)) {
|
|
114
137
|
return {};
|
|
115
138
|
}
|
|
116
139
|
let hasDefaultExport = false;
|
|
@@ -130,6 +153,150 @@ var rule2 = {
|
|
|
130
153
|
}
|
|
131
154
|
};
|
|
132
155
|
var component_exports_default = rule2;
|
|
156
|
+
function extractProps(propsNode) {
|
|
157
|
+
if (!propsNode.value || propsNode.value.type !== "YAMLMapping") {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
const propsMapping = propsNode.value;
|
|
161
|
+
const propertiesPair = propsMapping.pairs.find(
|
|
162
|
+
(p) => getYAMLStringValue(p.key) === "properties"
|
|
163
|
+
);
|
|
164
|
+
if (!propertiesPair || !propertiesPair.value || propertiesPair.value.type !== "YAMLMapping") {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const propertiesMapping = propertiesPair.value;
|
|
168
|
+
const props = [];
|
|
169
|
+
for (const pair of propertiesMapping.pairs) {
|
|
170
|
+
const propId = getYAMLStringValue(pair.key);
|
|
171
|
+
if (!propId) continue;
|
|
172
|
+
if (!pair.value || pair.value.type !== "YAMLMapping") continue;
|
|
173
|
+
const propMapping = pair.value;
|
|
174
|
+
const titlePair = propMapping.pairs.find(
|
|
175
|
+
(p) => getYAMLStringValue(p.key) === "title"
|
|
176
|
+
);
|
|
177
|
+
let title = null;
|
|
178
|
+
if (titlePair) {
|
|
179
|
+
title = getYAMLStringValue(titlePair.value);
|
|
180
|
+
}
|
|
181
|
+
props.push({
|
|
182
|
+
id: propId,
|
|
183
|
+
title,
|
|
184
|
+
node: pair
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return props;
|
|
188
|
+
}
|
|
189
|
+
var rule3 = {
|
|
190
|
+
meta: {
|
|
191
|
+
type: "problem",
|
|
192
|
+
docs: {
|
|
193
|
+
description: "Validates that component prop IDs match the camelCase version of their titles"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
create(context) {
|
|
197
|
+
if (!isComponentYmlFile(context)) {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
YAMLPair(node) {
|
|
202
|
+
const keyName = getYAMLStringValue(node.key);
|
|
203
|
+
if (keyName !== "props") {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const props = extractProps(node);
|
|
207
|
+
if (props.length === 0) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
for (const prop of props) {
|
|
211
|
+
if (!prop.title) {
|
|
212
|
+
context.report({
|
|
213
|
+
node: prop.node,
|
|
214
|
+
message: `Prop "${prop.id}" is missing a title.`
|
|
215
|
+
});
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const expectedId = camelCase(prop.title);
|
|
219
|
+
if (prop.id !== expectedId) {
|
|
220
|
+
context.report({
|
|
221
|
+
node: prop.node,
|
|
222
|
+
message: `Prop machine name "${prop.id}" should be the camelCase version of its title. Expected: "${expectedId}". https://drupal.org/i/3524675`
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
var component_prop_names_default = rule3;
|
|
231
|
+
|
|
232
|
+
// src/configs/required.ts
|
|
233
|
+
var required = defineConfig([
|
|
234
|
+
globalIgnores(["**/dist/**"]),
|
|
235
|
+
{
|
|
236
|
+
files: ["**/*.{ts,tsx,js,jsx}"],
|
|
237
|
+
languageOptions: {
|
|
238
|
+
parser: tseslint.parser,
|
|
239
|
+
ecmaVersion: 2020,
|
|
240
|
+
globals: globals.browser,
|
|
241
|
+
parserOptions: {
|
|
242
|
+
ecmaVersion: "latest",
|
|
243
|
+
ecmaFeatures: { jsx: true },
|
|
244
|
+
sourceType: "module"
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
settings: { react: { version: "19.0" } }
|
|
248
|
+
},
|
|
249
|
+
eslintPluginYml.configs["flat/base"],
|
|
250
|
+
{
|
|
251
|
+
plugins: {
|
|
252
|
+
"drupal-canvas": {
|
|
253
|
+
rules: {
|
|
254
|
+
"component-dir-name": component_dir_name_default,
|
|
255
|
+
"component-exports": component_exports_default,
|
|
256
|
+
"component-prop-names": component_prop_names_default
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
rules: {
|
|
261
|
+
"drupal-canvas/component-dir-name": "error",
|
|
262
|
+
"drupal-canvas/component-exports": "error",
|
|
263
|
+
"drupal-canvas/component-prop-names": "error"
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
]);
|
|
267
|
+
var required_default = required;
|
|
268
|
+
|
|
269
|
+
// src/configs/recommended.ts
|
|
270
|
+
var recommended = defineConfig([
|
|
271
|
+
required_default,
|
|
272
|
+
{
|
|
273
|
+
files: ["**/*.{ts,tsx,js,jsx}"],
|
|
274
|
+
plugins: {
|
|
275
|
+
react,
|
|
276
|
+
"react-hooks": reactHooks,
|
|
277
|
+
"jsx-a11y": jsxA11y
|
|
278
|
+
},
|
|
279
|
+
settings: {
|
|
280
|
+
"jsx-a11y": {
|
|
281
|
+
components: {
|
|
282
|
+
Image: "img"
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
rules: {
|
|
287
|
+
...js.configs.recommended.rules,
|
|
288
|
+
...react.configs.recommended.rules,
|
|
289
|
+
...react.configs["jsx-runtime"].rules,
|
|
290
|
+
...reactHooks.configs.recommended.rules,
|
|
291
|
+
...jsxA11y.flatConfigs.recommended.rules,
|
|
292
|
+
"react/jsx-no-target-blank": "off",
|
|
293
|
+
"react/prop-types": "off"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
...tseslint.configs.recommended,
|
|
297
|
+
...eslintPluginYml.configs["flat/recommended"]
|
|
298
|
+
]);
|
|
299
|
+
var recommended_default = recommended;
|
|
133
300
|
var REQUIRED_FILES = ["component.yml", "index.jsx"];
|
|
134
301
|
var ALLOWED_FILES = ["component.yml", "index.jsx", "index.css"];
|
|
135
302
|
var IGNORED_FILES = [
|
|
@@ -139,12 +306,13 @@ var IGNORED_FILES = [
|
|
|
139
306
|
function isFileAllowed(fileName, allowedFiles) {
|
|
140
307
|
return allowedFiles.some((allowedFile) => allowedFile === fileName);
|
|
141
308
|
}
|
|
142
|
-
var
|
|
309
|
+
var rule4 = {
|
|
143
310
|
meta: {
|
|
144
311
|
type: "problem",
|
|
145
312
|
docs: {
|
|
146
313
|
description: "Validates that component directory contains only allowed files"
|
|
147
|
-
}
|
|
314
|
+
},
|
|
315
|
+
deprecated: true
|
|
148
316
|
},
|
|
149
317
|
create(context) {
|
|
150
318
|
if (!isComponentYmlFile(context)) {
|
|
@@ -177,7 +345,7 @@ var rule3 = {
|
|
|
177
345
|
};
|
|
178
346
|
}
|
|
179
347
|
};
|
|
180
|
-
var component_files_default =
|
|
348
|
+
var component_files_default = rule4;
|
|
181
349
|
|
|
182
350
|
// src/rules/component-imports.ts
|
|
183
351
|
function checkImportSource(context, node, source) {
|
|
@@ -308,13 +476,14 @@ function checkImportSource(context, node, source) {
|
|
|
308
476
|
message: `Importing "${source}" is not supported. If this is a local import via a path alias, use the "@/components/" alias instead. If you are importing a third-party package, see the list of supported packages at https://project.pages.drupalcode.org/canvas/code-components/packages. (The status of supporting any third-party package can be tracked at https://drupal.org/i/3560197.)`
|
|
309
477
|
});
|
|
310
478
|
}
|
|
311
|
-
var
|
|
479
|
+
var rule5 = {
|
|
312
480
|
meta: {
|
|
313
481
|
type: "problem",
|
|
314
482
|
docs: {
|
|
315
483
|
description: "Validates that component imports only from supported import sources and patterns"
|
|
316
484
|
},
|
|
317
|
-
fixable: "code"
|
|
485
|
+
fixable: "code",
|
|
486
|
+
deprecated: true
|
|
318
487
|
},
|
|
319
488
|
create(context) {
|
|
320
489
|
if (!isInComponentDir(context)) {
|
|
@@ -334,7 +503,7 @@ var rule4 = {
|
|
|
334
503
|
};
|
|
335
504
|
}
|
|
336
505
|
};
|
|
337
|
-
var component_imports_default =
|
|
506
|
+
var component_imports_default = rule5;
|
|
338
507
|
function findTopmostComponentsParentDir(currentParentDir, rootDir) {
|
|
339
508
|
if (currentParentDir === rootDir) {
|
|
340
509
|
return currentParentDir;
|
|
@@ -355,12 +524,13 @@ function hasComponentSubdirectories(dirPath) {
|
|
|
355
524
|
}
|
|
356
525
|
return false;
|
|
357
526
|
}
|
|
358
|
-
var
|
|
527
|
+
var rule6 = {
|
|
359
528
|
meta: {
|
|
360
529
|
type: "problem",
|
|
361
530
|
docs: {
|
|
362
531
|
description: "Validates that all component directories are at the same level with no nesting hierarchy"
|
|
363
|
-
}
|
|
532
|
+
},
|
|
533
|
+
deprecated: true
|
|
364
534
|
},
|
|
365
535
|
create(context) {
|
|
366
536
|
if (!isComponentYmlFile(context)) {
|
|
@@ -389,124 +559,9 @@ var rule5 = {
|
|
|
389
559
|
};
|
|
390
560
|
}
|
|
391
561
|
};
|
|
392
|
-
var component_no_hierarchy_default =
|
|
393
|
-
function extractProps(propsNode) {
|
|
394
|
-
if (!propsNode.value || propsNode.value.type !== "YAMLMapping") {
|
|
395
|
-
return [];
|
|
396
|
-
}
|
|
397
|
-
const propsMapping = propsNode.value;
|
|
398
|
-
const propertiesPair = propsMapping.pairs.find(
|
|
399
|
-
(p) => getYAMLStringValue(p.key) === "properties"
|
|
400
|
-
);
|
|
401
|
-
if (!propertiesPair || !propertiesPair.value || propertiesPair.value.type !== "YAMLMapping") {
|
|
402
|
-
return [];
|
|
403
|
-
}
|
|
404
|
-
const propertiesMapping = propertiesPair.value;
|
|
405
|
-
const props = [];
|
|
406
|
-
for (const pair of propertiesMapping.pairs) {
|
|
407
|
-
const propId = getYAMLStringValue(pair.key);
|
|
408
|
-
if (!propId) continue;
|
|
409
|
-
if (!pair.value || pair.value.type !== "YAMLMapping") continue;
|
|
410
|
-
const propMapping = pair.value;
|
|
411
|
-
const titlePair = propMapping.pairs.find(
|
|
412
|
-
(p) => getYAMLStringValue(p.key) === "title"
|
|
413
|
-
);
|
|
414
|
-
let title = null;
|
|
415
|
-
if (titlePair) {
|
|
416
|
-
title = getYAMLStringValue(titlePair.value);
|
|
417
|
-
}
|
|
418
|
-
props.push({
|
|
419
|
-
id: propId,
|
|
420
|
-
title,
|
|
421
|
-
node: pair
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
return props;
|
|
425
|
-
}
|
|
426
|
-
var rule6 = {
|
|
427
|
-
meta: {
|
|
428
|
-
type: "problem",
|
|
429
|
-
docs: {
|
|
430
|
-
description: "Validates that component prop IDs match the camelCase version of their titles"
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
create(context) {
|
|
434
|
-
if (!isComponentYmlFile(context)) {
|
|
435
|
-
return {};
|
|
436
|
-
}
|
|
437
|
-
return {
|
|
438
|
-
YAMLPair(node) {
|
|
439
|
-
const keyName = getYAMLStringValue(node.key);
|
|
440
|
-
if (keyName !== "props") {
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
const props = extractProps(node);
|
|
444
|
-
if (props.length === 0) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
for (const prop of props) {
|
|
448
|
-
if (!prop.title) {
|
|
449
|
-
context.report({
|
|
450
|
-
node: prop.node,
|
|
451
|
-
message: `Prop "${prop.id}" is missing a title.`
|
|
452
|
-
});
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
|
-
const expectedId = camelCase(prop.title);
|
|
456
|
-
if (prop.id !== expectedId) {
|
|
457
|
-
context.report({
|
|
458
|
-
node: prop.node,
|
|
459
|
-
message: `Prop machine name "${prop.id}" should be the camelCase version of its title. Expected: "${expectedId}". https://drupal.org/i/3524675`
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
var component_prop_names_default = rule6;
|
|
562
|
+
var component_no_hierarchy_default = rule6;
|
|
468
563
|
|
|
469
|
-
// src/configs/
|
|
470
|
-
var required = defineConfig([
|
|
471
|
-
globalIgnores(["**/dist/**"]),
|
|
472
|
-
{
|
|
473
|
-
files: ["**/*.{js,jsx}"],
|
|
474
|
-
languageOptions: {
|
|
475
|
-
ecmaVersion: 2020,
|
|
476
|
-
globals: globals.browser,
|
|
477
|
-
parserOptions: {
|
|
478
|
-
ecmaVersion: "latest",
|
|
479
|
-
ecmaFeatures: { jsx: true },
|
|
480
|
-
sourceType: "module"
|
|
481
|
-
}
|
|
482
|
-
},
|
|
483
|
-
settings: { react: { version: "19.0" } }
|
|
484
|
-
},
|
|
485
|
-
eslintPluginYml.configs["flat/base"],
|
|
486
|
-
{
|
|
487
|
-
plugins: {
|
|
488
|
-
"drupal-canvas": {
|
|
489
|
-
rules: {
|
|
490
|
-
"component-dir-name": component_dir_name_default,
|
|
491
|
-
"component-exports": component_exports_default,
|
|
492
|
-
"component-files": component_files_default,
|
|
493
|
-
"component-imports": component_imports_default,
|
|
494
|
-
"component-no-hierarchy": component_no_hierarchy_default,
|
|
495
|
-
"component-prop-names": component_prop_names_default
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
},
|
|
499
|
-
rules: {
|
|
500
|
-
"drupal-canvas/component-dir-name": "error",
|
|
501
|
-
// 'drupal-canvas/component-exports': 'error',
|
|
502
|
-
// 'drupal-canvas/component-files': 'error',
|
|
503
|
-
// 'drupal-canvas/component-imports': 'error',
|
|
504
|
-
// 'drupal-canvas/component-no-hierarchy': 'error',
|
|
505
|
-
"drupal-canvas/component-prop-names": "error"
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
]);
|
|
509
|
-
var next_default = required;
|
|
564
|
+
// src/configs/requiredDeprecated.ts
|
|
510
565
|
var required2 = defineConfig([
|
|
511
566
|
globalIgnores(["**/dist/**"]),
|
|
512
567
|
{
|
|
@@ -546,47 +601,17 @@ var required2 = defineConfig([
|
|
|
546
601
|
}
|
|
547
602
|
}
|
|
548
603
|
]);
|
|
549
|
-
var
|
|
550
|
-
|
|
551
|
-
// src/configs/recommended.ts
|
|
552
|
-
var recommended = defineConfig([
|
|
553
|
-
required_default,
|
|
554
|
-
{
|
|
555
|
-
files: ["**/*.{js,jsx}"],
|
|
556
|
-
plugins: {
|
|
557
|
-
react,
|
|
558
|
-
"react-hooks": reactHooks,
|
|
559
|
-
"jsx-a11y": jsxA11y
|
|
560
|
-
},
|
|
561
|
-
settings: {
|
|
562
|
-
"jsx-a11y": {
|
|
563
|
-
components: {
|
|
564
|
-
Image: "img"
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
},
|
|
568
|
-
rules: {
|
|
569
|
-
...js.configs.recommended.rules,
|
|
570
|
-
...react.configs.recommended.rules,
|
|
571
|
-
...react.configs["jsx-runtime"].rules,
|
|
572
|
-
...reactHooks.configs.recommended.rules,
|
|
573
|
-
...jsxA11y.flatConfigs.recommended.rules,
|
|
574
|
-
"react/jsx-no-target-blank": "off",
|
|
575
|
-
"react/prop-types": "off"
|
|
576
|
-
}
|
|
577
|
-
},
|
|
578
|
-
...eslintPluginYml.configs["flat/recommended"]
|
|
579
|
-
]);
|
|
580
|
-
var recommended_default = recommended;
|
|
604
|
+
var requiredDeprecated_default = required2;
|
|
581
605
|
var strict = defineConfig([
|
|
582
606
|
recommended_default,
|
|
583
607
|
{
|
|
584
|
-
files: ["**/*.{js,jsx}"],
|
|
608
|
+
files: ["**/*.{ts,tsx,js,jsx}"],
|
|
585
609
|
rules: {
|
|
586
610
|
...jsxA11y.flatConfigs.strict.rules
|
|
587
611
|
}
|
|
588
|
-
}
|
|
612
|
+
},
|
|
613
|
+
...tseslint.configs.strict
|
|
589
614
|
]);
|
|
590
615
|
var strict_default = strict;
|
|
591
616
|
|
|
592
|
-
export {
|
|
617
|
+
export { recommended_default as recommended, required_default as required, requiredDeprecated_default as requiredDeprecated, strict_default as strict };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drupal-canvas/eslint-config",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "ESLint config for validating Drupal Canvas Code Components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
33
33
|
"eslint-plugin-yml": "^1.19.0",
|
|
34
34
|
"globals": "^16.5.0",
|
|
35
|
-
"lodash-es": "^4.17.21"
|
|
35
|
+
"lodash-es": "^4.17.21",
|
|
36
|
+
"typescript-eslint": "^8.56.1"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
39
|
"@types/eslint-plugin-jsx-a11y": "^6.5.6",
|