@design.estate/wcctools 6.0.0 → 6.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/changelog.md +13 -0
- package/dist_shell/bundle.js +3 -3
- package/dist_shell/bundle.js.map +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/cli.js +8 -2
- package/dist_ts/plugins.d.ts +7 -2
- package/dist_ts/plugins.js +9 -3
- package/dist_ts/standards/baselines.d.ts +27 -0
- package/dist_ts/standards/baselines.js +83 -0
- package/dist_ts/standards/checker.d.ts +21 -0
- package/dist_ts/standards/checker.js +88 -0
- package/dist_ts/standards/classes.gitrepo.d.ts +13 -0
- package/dist_ts/standards/classes.gitrepo.js +43 -0
- package/dist_ts/standards/classes.sourceedits.d.ts +15 -0
- package/dist_ts/standards/classes.sourceedits.js +54 -0
- package/dist_ts/standards/classes.standardfixer.d.ts +40 -0
- package/dist_ts/standards/classes.standardfixer.js +210 -0
- package/dist_ts/standards/classes.standardproject.d.ts +80 -0
- package/dist_ts/standards/classes.standardproject.js +195 -0
- package/dist_ts/standards/classes.standardtree.d.ts +56 -0
- package/dist_ts/standards/classes.standardtree.js +207 -0
- package/dist_ts/standards/cli.d.ts +7 -0
- package/dist_ts/standards/cli.js +89 -0
- package/dist_ts/standards/config.d.ts +33 -0
- package/dist_ts/standards/config.js +139 -0
- package/dist_ts/standards/errors.d.ts +9 -0
- package/dist_ts/standards/errors.js +17 -0
- package/dist_ts/standards/helpers.ast.d.ts +56 -0
- package/dist_ts/standards/helpers.ast.js +172 -0
- package/dist_ts/standards/helpers.paths.d.ts +36 -0
- package/dist_ts/standards/helpers.paths.js +86 -0
- package/dist_ts/standards/index.d.ts +14 -0
- package/dist_ts/standards/index.js +15 -0
- package/dist_ts/standards/output.d.ts +7 -0
- package/dist_ts/standards/output.js +57 -0
- package/dist_ts/standards/ratchet.d.ts +15 -0
- package/dist_ts/standards/ratchet.js +45 -0
- package/dist_ts/standards/rule.d.ts +50 -0
- package/dist_ts/standards/rule.js +9 -0
- package/dist_ts/standards/rules/barrel.element-index.d.ts +7 -0
- package/dist_ts/standards/rules/barrel.element-index.js +108 -0
- package/dist_ts/standards/rules/barrel.no-demo-export.d.ts +3 -0
- package/dist_ts/standards/rules/barrel.no-demo-export.js +29 -0
- package/dist_ts/standards/rules/demo.fixture-not-exported.d.ts +3 -0
- package/dist_ts/standards/rules/demo.fixture-not-exported.js +29 -0
- package/dist_ts/standards/rules/demo.groups.d.ts +6 -0
- package/dist_ts/standards/rules/demo.groups.js +72 -0
- package/dist_ts/standards/rules/demo.required.d.ts +3 -0
- package/dist_ts/standards/rules/demo.required.js +48 -0
- package/dist_ts/standards/rules/demo.separate-file.d.ts +3 -0
- package/dist_ts/standards/rules/demo.separate-file.js +38 -0
- package/dist_ts/standards/rules/demo.shape.d.ts +3 -0
- package/dist_ts/standards/rules/demo.shape.js +38 -0
- package/dist_ts/standards/rules/docs.component-index.d.ts +8 -0
- package/dist_ts/standards/rules/docs.component-index.js +84 -0
- package/dist_ts/standards/rules/element.exported.d.ts +3 -0
- package/dist_ts/standards/rules/element.exported.js +33 -0
- package/dist_ts/standards/rules/element.literal-tag.d.ts +3 -0
- package/dist_ts/standards/rules/element.literal-tag.js +30 -0
- package/dist_ts/standards/rules/element.reachable.d.ts +3 -0
- package/dist_ts/standards/rules/element.reachable.js +48 -0
- package/dist_ts/standards/rules/element.tag-map.d.ts +3 -0
- package/dist_ts/standards/rules/element.tag-map.js +83 -0
- package/dist_ts/standards/rules/i18n.literals.d.ts +3 -0
- package/dist_ts/standards/rules/i18n.literals.js +52 -0
- package/dist_ts/standards/rules/index.d.ts +12 -0
- package/dist_ts/standards/rules/index.js +83 -0
- package/dist_ts/standards/rules/layout.element-folder.d.ts +3 -0
- package/dist_ts/standards/rules/layout.element-folder.js +47 -0
- package/dist_ts/standards/rules/layout.entry-file-name.d.ts +3 -0
- package/dist_ts/standards/rules/layout.entry-file-name.js +71 -0
- package/dist_ts/standards/rules/layout.entry.d.ts +3 -0
- package/dist_ts/standards/rules/layout.entry.js +38 -0
- package/dist_ts/standards/rules/layout.group-folder.d.ts +3 -0
- package/dist_ts/standards/rules/layout.group-folder.js +22 -0
- package/dist_ts/standards/rules/layout.shared-00.d.ts +3 -0
- package/dist_ts/standards/rules/layout.shared-00.js +36 -0
- package/dist_ts/standards/rules/naming.class-matches-tag.d.ts +3 -0
- package/dist_ts/standards/rules/naming.class-matches-tag.js +26 -0
- package/dist_ts/standards/rules/naming.lowercase-files.d.ts +3 -0
- package/dist_ts/standards/rules/naming.lowercase-files.js +26 -0
- package/dist_ts/standards/rules/naming.tag-prefix.d.ts +3 -0
- package/dist_ts/standards/rules/naming.tag-prefix.js +23 -0
- package/dist_ts/standards/rules/props.accessor.d.ts +3 -0
- package/dist_ts/standards/rules/props.accessor.js +35 -0
- package/dist_ts/standards/rules/props.object-no-attribute.d.ts +3 -0
- package/dist_ts/standards/rules/props.object-no-attribute.js +42 -0
- package/dist_ts/standards/rules/props.reflect-primitive.d.ts +5 -0
- package/dist_ts/standards/rules/props.reflect-primitive.js +41 -0
- package/dist_ts/standards/rules/props.typed.d.ts +6 -0
- package/dist_ts/standards/rules/props.typed.js +64 -0
- package/dist_ts/standards/rules/shared.d.ts +38 -0
- package/dist_ts/standards/rules/shared.js +103 -0
- package/dist_ts/standards/rules/style.bdtheme.d.ts +5 -0
- package/dist_ts/standards/rules/style.bdtheme.js +28 -0
- package/dist_ts_interfaces/index.d.ts +1 -0
- package/dist_ts_interfaces/index.js +2 -1
- package/dist_ts_interfaces/standard.d.ts +93 -0
- package/dist_ts_interfaces/standard.js +6 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +4 -2
- package/readme.md +34 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/cli.ts +8 -1
- package/ts/plugins.ts +10 -2
- package/ts/standards/baselines.ts +100 -0
- package/ts/standards/checker.ts +114 -0
- package/ts/standards/classes.gitrepo.ts +48 -0
- package/ts/standards/classes.sourceedits.ts +58 -0
- package/ts/standards/classes.standardfixer.ts +234 -0
- package/ts/standards/classes.standardproject.ts +250 -0
- package/ts/standards/classes.standardtree.ts +220 -0
- package/ts/standards/cli.ts +86 -0
- package/ts/standards/config.ts +160 -0
- package/ts/standards/errors.ts +18 -0
- package/ts/standards/helpers.ast.ts +208 -0
- package/ts/standards/helpers.paths.ts +119 -0
- package/ts/standards/index.ts +22 -0
- package/ts/standards/output.ts +65 -0
- package/ts/standards/ratchet.ts +63 -0
- package/ts/standards/rule.ts +58 -0
- package/ts/standards/rules/barrel.element-index.ts +112 -0
- package/ts/standards/rules/barrel.no-demo-export.ts +30 -0
- package/ts/standards/rules/demo.fixture-not-exported.ts +30 -0
- package/ts/standards/rules/demo.groups.ts +74 -0
- package/ts/standards/rules/demo.required.ts +49 -0
- package/ts/standards/rules/demo.separate-file.ts +40 -0
- package/ts/standards/rules/demo.shape.ts +42 -0
- package/ts/standards/rules/docs.component-index.ts +88 -0
- package/ts/standards/rules/element.exported.ts +35 -0
- package/ts/standards/rules/element.literal-tag.ts +30 -0
- package/ts/standards/rules/element.reachable.ts +49 -0
- package/ts/standards/rules/element.tag-map.ts +87 -0
- package/ts/standards/rules/i18n.literals.ts +58 -0
- package/ts/standards/rules/index.ts +87 -0
- package/ts/standards/rules/layout.element-folder.ts +49 -0
- package/ts/standards/rules/layout.entry-file-name.ts +73 -0
- package/ts/standards/rules/layout.entry.ts +40 -0
- package/ts/standards/rules/layout.group-folder.ts +23 -0
- package/ts/standards/rules/layout.shared-00.ts +37 -0
- package/ts/standards/rules/naming.class-matches-tag.ts +27 -0
- package/ts/standards/rules/naming.lowercase-files.ts +27 -0
- package/ts/standards/rules/naming.tag-prefix.ts +24 -0
- package/ts/standards/rules/props.accessor.ts +37 -0
- package/ts/standards/rules/props.object-no-attribute.ts +45 -0
- package/ts/standards/rules/props.reflect-primitive.ts +44 -0
- package/ts/standards/rules/props.typed.ts +70 -0
- package/ts/standards/rules/shared.ts +127 -0
- package/ts/standards/rules/style.bdtheme.ts +31 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { baseOf, dirOf, specifierFor } from '../helpers.paths.js';
|
|
2
|
+
import { addReexport, catalogElements, elementsDir, isInElementFolder } from './shared.js';
|
|
3
|
+
/**
|
|
4
|
+
* An element folder has `index.ts` re-exporting the entry file (and `types.ts`); a group folder's
|
|
5
|
+
* `index.ts` re-exports each element folder's `index.ts`; `ts_web/elements/index.ts` re-exports each
|
|
6
|
+
* group or element folder.
|
|
7
|
+
*/
|
|
8
|
+
export const barrelElementIndexRule = {
|
|
9
|
+
id: 'barrel/element-index',
|
|
10
|
+
severity: { base: 'warn' },
|
|
11
|
+
fixMode: 'auto',
|
|
12
|
+
detect: ({ project }) => {
|
|
13
|
+
const findings = new Map();
|
|
14
|
+
const add = (findingArg) => {
|
|
15
|
+
const id = `${findingArg.file}|${findingArg.message}`;
|
|
16
|
+
if (!findings.has(id)) {
|
|
17
|
+
findings.set(id, findingArg);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const folderElements = catalogElements(project).filter(isInElementFolder);
|
|
21
|
+
const folders = [...new Set(folderElements.map((elementArg) => dirOf(elementArg.file)))].sort();
|
|
22
|
+
const groupsWithFolders = new Set();
|
|
23
|
+
for (const element of folderElements) {
|
|
24
|
+
const folder = dirOf(element.file);
|
|
25
|
+
const index = `${folder}/index.ts`;
|
|
26
|
+
const types = `${folder}/types.ts`;
|
|
27
|
+
if (!project.files.has(index)) {
|
|
28
|
+
const exported = [element.file, ...(project.files.has(types) ? [types] : [])];
|
|
29
|
+
add({
|
|
30
|
+
file: index,
|
|
31
|
+
position: 0,
|
|
32
|
+
key: index,
|
|
33
|
+
message: `${folder}/ has no index.ts`,
|
|
34
|
+
fix: (builderArg) => builderArg.create(index, exported.map((fileArg) => `export * from '${specifierFor(index, fileArg, 'js')}';\n`).join('')),
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
for (const required of [element.file, types]) {
|
|
39
|
+
if (!project.files.has(required) || project.reexports(index).some((reexportArg) => reexportArg.target === required)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
add({
|
|
43
|
+
file: index,
|
|
44
|
+
position: 0,
|
|
45
|
+
key: index,
|
|
46
|
+
message: `${index} does not re-export ./${baseOf(required)}`,
|
|
47
|
+
fix: (builderArg) => addReexport(builderArg, project, index, required),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const parent = dirOf(folder);
|
|
51
|
+
const parentIndex = `${parent}/index.ts`;
|
|
52
|
+
if (parent !== elementsDir) {
|
|
53
|
+
groupsWithFolders.add(parent);
|
|
54
|
+
}
|
|
55
|
+
if (!project.files.has(parentIndex)) {
|
|
56
|
+
if (parent === elementsDir) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const groupFolders = folders.filter((folderArg) => dirOf(folderArg) === parent);
|
|
60
|
+
add({
|
|
61
|
+
file: parentIndex,
|
|
62
|
+
position: 0,
|
|
63
|
+
key: parentIndex,
|
|
64
|
+
message: `${parent}/ has no index.ts`,
|
|
65
|
+
fix: (builderArg) => builderArg.create(parentIndex, groupFolders.map((folderArg) => `export * from '${specifierFor(parentIndex, `${folderArg}/index.ts`, 'js')}';\n`).join('')),
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const parentReexports = project.reexports(parentIndex);
|
|
70
|
+
if (parentReexports.some((reexportArg) => reexportArg.target === index)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const inside = parentReexports.filter((reexportArg) => reexportArg.target?.startsWith(`${folder}/`));
|
|
74
|
+
const finding = {
|
|
75
|
+
file: parentIndex,
|
|
76
|
+
position: inside[0]?.statement.getStart() ?? 0,
|
|
77
|
+
key: parentIndex,
|
|
78
|
+
message: `${parentIndex} does not re-export ${baseOf(folder)}/index.ts`,
|
|
79
|
+
};
|
|
80
|
+
if (inside.length === 0) {
|
|
81
|
+
finding.fix = (builderArg) => addReexport(builderArg, project, parentIndex, index);
|
|
82
|
+
}
|
|
83
|
+
else if (inside.length === 1) {
|
|
84
|
+
const literal = inside[0].statement.moduleSpecifier;
|
|
85
|
+
finding.fix = (builderArg) => builderArg.edit(parentIndex, literal.getStart() + 1, literal.end - 1, specifierFor(parentIndex, index, 'js'));
|
|
86
|
+
}
|
|
87
|
+
add(finding);
|
|
88
|
+
}
|
|
89
|
+
const elementsIndex = `${elementsDir}/index.ts`;
|
|
90
|
+
if (project.files.has(elementsIndex)) {
|
|
91
|
+
for (const group of [...groupsWithFolders].sort()) {
|
|
92
|
+
const groupIndex = `${group}/index.ts`;
|
|
93
|
+
if (!project.files.has(groupIndex) || project.reexports(elementsIndex).some((reexportArg) => reexportArg.target === groupIndex)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
add({
|
|
97
|
+
file: elementsIndex,
|
|
98
|
+
position: 0,
|
|
99
|
+
key: elementsIndex,
|
|
100
|
+
message: `${elementsIndex} does not re-export ${baseOf(group)}/index.ts`,
|
|
101
|
+
fix: (builderArg) => addReexport(builderArg, project, elementsIndex, groupIndex),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return [...findings.values()];
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFycmVsLmVsZW1lbnQtaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9zdGFuZGFyZHMvcnVsZXMvYmFycmVsLmVsZW1lbnQtaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRTNGOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBa0I7SUFDbkQsRUFBRSxFQUFFLHNCQUFzQjtJQUMxQixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFO0lBQzFCLE9BQU8sRUFBRSxNQUFNO0lBQ2YsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFO1FBQ3RCLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxFQUF3QixDQUFDO1FBQ2pELE1BQU0sR0FBRyxHQUFHLENBQUMsVUFBd0IsRUFBUSxFQUFFO1lBQzdDLE1BQU0sRUFBRSxHQUFHLEdBQUcsVUFBVSxDQUFDLElBQUksSUFBSSxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDdEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDL0IsQ0FBQztRQUNILENBQUMsQ0FBQztRQUNGLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUMxRSxNQUFNLE9BQU8sR0FBRyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVB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
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { baseOf, isDemoFile } from '../helpers.paths.js';
|
|
2
|
+
import { removeStatement } from './shared.js';
|
|
3
|
+
/** No barrel exports a demo file. */
|
|
4
|
+
export const barrelNoDemoExportRule = {
|
|
5
|
+
id: 'barrel/no-demo-export',
|
|
6
|
+
severity: { base: 'error' },
|
|
7
|
+
fixMode: 'auto',
|
|
8
|
+
detect: ({ project }) => {
|
|
9
|
+
const findings = [];
|
|
10
|
+
for (const file of project.webFiles) {
|
|
11
|
+
if (baseOf(file) !== 'index.ts') {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
for (const reexport of project.reexports(file)) {
|
|
15
|
+
if (reexport.target && isDemoFile(reexport.target)) {
|
|
16
|
+
findings.push({
|
|
17
|
+
file,
|
|
18
|
+
position: reexport.statement.getStart(),
|
|
19
|
+
key: file,
|
|
20
|
+
message: `${file} exports the demo file ${reexport.target}`,
|
|
21
|
+
fix: (builderArg) => removeStatement(builderArg, file, reexport.statement),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return findings;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFycmVsLm5vLWRlbW8tZXhwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvc3RhbmRhcmRzL3J1bGVzL2JhcnJlbC5uby1kZW1vLWV4cG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXpELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFOUMscUNBQXFDO0FBQ3JDLE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFrQjtJQUNuRCxFQUFFLEVBQUUsdUJBQXVCO0lBQzNCLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7SUFDM0IsT0FBTyxFQUFFLE1BQU07SUFDZixNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7UUFDdEIsTUFBTSxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNwQyxLQUFLLE1BQU0sSUFBSSxJQUFJLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNwQyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxVQUFVLEVBQUUsQ0FBQztnQkFDaEMsU0FBUztZQUNYLENBQUM7WUFDRCxLQUFLLE1BQU0sUUFBUSxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDL0MsSUFBSSxRQUFRLENBQUMsTUFBTSxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztvQkFDbkQsUUFBUSxDQUFDLElBQUksQ0FBQzt3QkFDWixJQUFJO3dCQUNKLFFBQVEsRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRTt3QkFDdkMsR0FBRyxFQUFFLElBQUk7d0JBQ1QsT0FBTyxFQUFFLEdBQUcsSUFBSSwwQkFBMEIsUUFBUSxDQUFDLE1BQU0sRUFBRTt3QkFDM0QsR0FBRyxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDO3FCQUMzRSxDQUFDLENBQUM7Z0JBQ0wsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGLENBQUMifQ==
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { elementsBarrel } from '../classes.standardproject.js';
|
|
2
|
+
import { elementKey, removeStatement } from './shared.js';
|
|
3
|
+
/** Elements declared in demo files are not reachable from `ts_web/elements/index.ts`. */
|
|
4
|
+
export const demoFixtureNotExportedRule = {
|
|
5
|
+
id: 'demo/fixture-not-exported',
|
|
6
|
+
severity: { base: 'warn' },
|
|
7
|
+
fixMode: 'auto',
|
|
8
|
+
detect: ({ project }) => {
|
|
9
|
+
const findings = [];
|
|
10
|
+
const reached = project.reachableFrom(elementsBarrel);
|
|
11
|
+
for (const element of project.elements) {
|
|
12
|
+
if (!element.inDemoFile || !reached.has(element.file)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const exporters = [...reached].flatMap((fileArg) => project.reexports(fileArg)).filter((reexportArg) => reexportArg.target === element.file);
|
|
16
|
+
findings.push({
|
|
17
|
+
file: element.file,
|
|
18
|
+
position: element.decoratorCall.getStart(),
|
|
19
|
+
key: elementKey(element),
|
|
20
|
+
message: `fixture element <${element.tag ?? '?'}> in a demo file is reachable from ${elementsBarrel}`,
|
|
21
|
+
fix: exporters.length > 0
|
|
22
|
+
? (builderArg) => exporters.forEach((reexportArg) => removeStatement(builderArg, reexportArg.file, reexportArg.statement))
|
|
23
|
+
: undefined,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return findings;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVtby5maXh0dXJlLW5vdC1leHBvcnRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9kZW1vLmZpeHR1cmUtbm90LWV4cG9ydGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUUvRCxPQUFPLEVBQUUsVUFBVSxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUxRCx5RkFBeUY7QUFDekYsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQWtCO0lBQ3ZELEVBQUUsRUFBRSwyQkFBMkI7SUFDL0IsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRTtJQUMxQixPQUFPLEVBQUUsTUFBTTtJQUNmLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRTtRQUN0QixNQUFNLFFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDdEQsS0FBSyxNQUFNLE9BQU8sSUFBSSxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDdkMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUN0RCxTQUFTO1lBQ1gsQ0FBQztZQUNELE1BQU0sU0FBUyxHQUFHLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdJLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ1osSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO2dCQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUU7Z0JBQzFDLEdBQUcsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDO2dCQUN4QixPQUFPLEVBQUUsb0JBQW9CLE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxzQ0FBc0MsY0FBYyxFQUFFO2dCQUNyRyxHQUFHLEVBQUUsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDO29CQUN2QixDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLGVBQWUsQ0FBQyxVQUFVLEVBQUUsV0FBVyxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQzFILENBQUMsQ0FBQyxTQUFTO2FBQ2QsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRixDQUFDIn0=
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IStandardRule } from '../rule.js';
|
|
2
|
+
/**
|
|
3
|
+
* An element with a demo declares `static demoGroups`, a non-empty string or array of non-empty strings.
|
|
4
|
+
* dees: the first entry is `standard.groupNames[<area>]` of the element's `00group-<area>`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const demoGroupsRule: IStandardRule;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as ast from '../helpers.ast.js';
|
|
3
|
+
import { catalogElements, elementKey, groupAreaOf, nextLineStart } from './shared.js';
|
|
4
|
+
const ts = plugins.typescript;
|
|
5
|
+
const quote = (textArg) => `'${textArg.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
6
|
+
/**
|
|
7
|
+
* An element with a demo declares `static demoGroups`, a non-empty string or array of non-empty strings.
|
|
8
|
+
* dees: the first entry is `standard.groupNames[<area>]` of the element's `00group-<area>`.
|
|
9
|
+
*/
|
|
10
|
+
export const demoGroupsRule = {
|
|
11
|
+
id: 'demo/groups',
|
|
12
|
+
severity: { base: 'warn' },
|
|
13
|
+
fixMode: 'auto',
|
|
14
|
+
detect: ({ project, config, profile }) => {
|
|
15
|
+
const findings = [];
|
|
16
|
+
for (const element of catalogElements(project)) {
|
|
17
|
+
const demo = ast.findStaticProperty(element.classNode, 'demo');
|
|
18
|
+
if (!demo) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const area = profile === 'dees' ? groupAreaOf(element.file) : null;
|
|
22
|
+
const expected = area ? config.groupNames?.[area] ?? null : null;
|
|
23
|
+
const base = { file: element.file, key: elementKey(element) };
|
|
24
|
+
const member = ast.findStaticProperty(element.classNode, 'demoGroups');
|
|
25
|
+
const text = element.sourceFile.text;
|
|
26
|
+
if (!member) {
|
|
27
|
+
const finding = { ...base, position: demo.getStart(), message: `${element.className ?? '?'} has a demo but no static demoGroups` };
|
|
28
|
+
if (expected) {
|
|
29
|
+
const at = nextLineStart(text, demo.end);
|
|
30
|
+
finding.fix = (builderArg) => builderArg.edit(element.file, at, at, `${ast.indentationAt(text, demo.getStart())}public static demoGroups = [${quote(expected)}];\n`);
|
|
31
|
+
}
|
|
32
|
+
findings.push(finding);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const initializer = member.initializer;
|
|
36
|
+
let entries = null;
|
|
37
|
+
if (initializer && ast.isStringLiteralLike(initializer)) {
|
|
38
|
+
entries = [initializer.text];
|
|
39
|
+
}
|
|
40
|
+
else if (initializer && ts.isArrayLiteralExpression(initializer) && initializer.elements.every(ast.isStringLiteralLike)) {
|
|
41
|
+
entries = initializer.elements.map((entryArg) => entryArg.text);
|
|
42
|
+
}
|
|
43
|
+
else if (!initializer || ts.isArrayLiteralExpression(initializer) || ts.isLiteralExpression(initializer)) {
|
|
44
|
+
findings.push({ ...base, position: member.getStart(), message: `static demoGroups of ${element.className ?? '?'} is not a string or an array of strings` });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (entries && (entries.length === 0 || entries.some((entryArg) => entryArg.length === 0))) {
|
|
48
|
+
findings.push({ ...base, position: member.getStart(), message: `static demoGroups of ${element.className ?? '?'} is empty or has an empty entry` });
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (profile !== 'dees' || !area || !entries) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (!expected) {
|
|
55
|
+
findings.push({ ...base, position: member.getStart(), message: `standard.groupNames has no display name for the area '${area}'` });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (entries[0] !== expected) {
|
|
59
|
+
const target = initializer;
|
|
60
|
+
const reordered = [expected, ...entries.filter((entryArg) => entryArg !== expected)];
|
|
61
|
+
findings.push({
|
|
62
|
+
...base,
|
|
63
|
+
position: member.getStart(),
|
|
64
|
+
message: `the first demo group of ${element.className ?? '?'} is ${quote(entries[0])}; expected ${quote(expected)} (00group-${area})`,
|
|
65
|
+
fix: (builderArg) => builderArg.edit(element.file, target.getStart(), target.end, `[${reordered.map(quote).join(', ')}]`),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return findings;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVtby5ncm91cHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9zdGFuZGFyZHMvcnVsZXMvZGVtby5ncm91cHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUM1QyxPQUFPLEtBQUssR0FBRyxNQUFNLG1CQUFtQixDQUFDO0FBRXpDLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFdEYsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztBQUU5QixNQUFNLEtBQUssR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQUMsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUM7QUFFdEc7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFrQjtJQUMzQyxFQUFFLEVBQUUsYUFBYTtJQUNqQixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFO0lBQzFCLE9BQU8sRUFBRSxNQUFNO0lBQ2YsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7UUFDdkMsTUFBTSxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNwQyxLQUFLLE1BQU0sT0FBTyxJQUFJLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQy9DLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQy9ELElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDVixTQUFTO1lBQ1gsQ0FBQztZQUNELE1BQU0sSUFBSSxHQUFHLE9BQU8sS0FBSyxN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
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as ast from '../helpers.ast.js';
|
|
2
|
+
import { dirOf } from '../helpers.paths.js';
|
|
3
|
+
import { catalogElements, elementKey, isCustomElementName } from './shared.js';
|
|
4
|
+
/** Every exported element has `static demo`. The opt-in fix writes a stub that renders the bare tag. */
|
|
5
|
+
export const demoRequiredRule = {
|
|
6
|
+
id: 'demo/required',
|
|
7
|
+
severity: { base: 'warn' },
|
|
8
|
+
fixMode: 'opt-in',
|
|
9
|
+
allowlistCategories: ['subcomponent', 'base'],
|
|
10
|
+
detect: ({ project }) => {
|
|
11
|
+
const findings = [];
|
|
12
|
+
const elements = catalogElements(project);
|
|
13
|
+
for (const element of elements) {
|
|
14
|
+
if (!element.exported || ast.findStaticProperty(element.classNode, 'demo')) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const finding = {
|
|
18
|
+
file: element.file,
|
|
19
|
+
position: element.decoratorCall.getStart(),
|
|
20
|
+
key: elementKey(element),
|
|
21
|
+
message: `${element.className ?? '?'} (<${element.tag ?? '?'}>) has no static demo`,
|
|
22
|
+
};
|
|
23
|
+
const sourceFile = element.sourceFile;
|
|
24
|
+
// The stub's file name and markup come from the tag: only a valid custom element name is usable.
|
|
25
|
+
const usableTag = element.tag && isCustomElementName(element.tag) ? element.tag : null;
|
|
26
|
+
const demoFile = usableTag ? `${dirOf(element.file)}/${usableTag}.demo.ts` : null;
|
|
27
|
+
const firstMember = element.classNode.members[0];
|
|
28
|
+
const alone = elements.filter((otherArg) => otherArg.file === element.file).length === 1;
|
|
29
|
+
if (usableTag && demoFile && element.className && firstMember && alone && !project.exists(demoFile) && !/\bdemoFunc\b/.test(sourceFile.text)) {
|
|
30
|
+
const tag = usableTag;
|
|
31
|
+
const customElementSource = ast.importSourceOf(sourceFile, 'customElement');
|
|
32
|
+
const htmlSource = ast.importSourceOf(sourceFile, 'html')
|
|
33
|
+
?? (customElementSource && customElementSource !== 'lit/decorators.js' ? customElementSource : 'lit');
|
|
34
|
+
const text = sourceFile.text;
|
|
35
|
+
const importAt = ast.afterLastImport(sourceFile);
|
|
36
|
+
finding.fix = (builderArg) => {
|
|
37
|
+
builderArg.create(demoFile, `import { html } from '${htmlSource}';\n\nexport const demoFunc = () => html\`<${tag}></${tag}>\`;\n`);
|
|
38
|
+
builderArg.edit(element.file, importAt, importAt, `import { demoFunc } from './${tag}.demo.js';\n`);
|
|
39
|
+
const lineStart = text.lastIndexOf('\n', firstMember.getStart() - 1) + 1;
|
|
40
|
+
builderArg.edit(element.file, lineStart, lineStart, `${ast.indentationAt(text, firstMember.getStart())}public static demo = demoFunc;\n`);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
findings.push(finding);
|
|
44
|
+
}
|
|
45
|
+
return findings;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVtby5yZXF1aXJlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9kZW1vLnJlcXVpcmVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxHQUFHLE1BQU0sbUJBQW1CLENBQUM7QUFDekMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLG1CQUFtQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRS9FLHdHQUF3RztBQUN4RyxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBa0I7SUFDN0MsRUFBRSxFQUFFLGVBQWU7SUFDbkIsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRTtJQUMxQixPQUFPLEVBQUUsUUFBUTtJQUNqQixtQkFBbUIsRUFBRSxDQUFDLGNBQWMsRUFBRSxNQUFNLENBQUM7SUFDN0MsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFO1FBQ3RCLE1BQU0sUUFBUSxHQUFtQixFQUFFLENBQUM7UUFDcEMsTUFBTSxRQUFRLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzFDLEtBQUssTUFBTSxPQUFPLElBQUksUUFBUSxFQUFFLENBQUM7WUFDL0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksR0FBRyxDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDM0UsU0FBUztZQUNYLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBaUI7Z0JBQzVCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtnQkFDbEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsUUFBUSxFQUFFO2dCQUMxQyxHQUFHLEVBQUUsVUFBVSxDQUFDLE9BQU8sQ0FBQztnQkFDeEIsT0FBTyxFQUFFLEdBQUcs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
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as ast from '../helpers.ast.js';
|
|
3
|
+
import { isDemoFile, resolveSpecifier } from '../helpers.paths.js';
|
|
4
|
+
import { catalogElements, elementKey, rootIdentifier } from './shared.js';
|
|
5
|
+
const ts = plugins.typescript;
|
|
6
|
+
/** `static demo` refers to an export of the element's demo file. Report-only in 6.1. */
|
|
7
|
+
export const demoSeparateFileRule = {
|
|
8
|
+
id: 'demo/separate-file',
|
|
9
|
+
severity: { base: 'warn', dees: 'error' },
|
|
10
|
+
fixMode: 'none',
|
|
11
|
+
detect: ({ project }) => {
|
|
12
|
+
const findings = [];
|
|
13
|
+
for (const element of catalogElements(project)) {
|
|
14
|
+
const member = ast.findStaticProperty(element.classNode, 'demo');
|
|
15
|
+
if (!member?.initializer) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const initializer = member.initializer;
|
|
19
|
+
const references = ts.isArrayLiteralExpression(initializer) ? [...initializer.elements] : [initializer];
|
|
20
|
+
const separate = references.length > 0 && references.every((referenceArg) => {
|
|
21
|
+
const identifier = rootIdentifier(referenceArg);
|
|
22
|
+
const source = identifier ? ast.importSourceOf(element.sourceFile, identifier) : null;
|
|
23
|
+
const resolved = source ? resolveSpecifier(element.file, source, (fileArg) => project.files.has(fileArg)) : null;
|
|
24
|
+
return !!resolved && isDemoFile(resolved.target);
|
|
25
|
+
});
|
|
26
|
+
if (!separate) {
|
|
27
|
+
findings.push({
|
|
28
|
+
file: element.file,
|
|
29
|
+
position: member.getStart(),
|
|
30
|
+
key: elementKey(element),
|
|
31
|
+
message: `static demo of ${element.className ?? '?'} is not imported from its demo file (${element.tag ?? '<tag>'}.demo.ts)`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return findings;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVtby5zZXBhcmF0ZS1maWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvc3RhbmRhcmRzL3J1bGVzL2RlbW8uc2VwYXJhdGUtZmlsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxHQUFHLE1BQU0sbUJBQW1CLENBQUM7QUFDekMsT0FBTyxFQUFFLFVBQVUsRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRW5FLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUxRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDO0FBRTlCLHdGQUF3RjtBQUN4RixNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBa0I7SUFDakQsRUFBRSxFQUFFLG9CQUFvQjtJQUN4QixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7SUFDekMsT0FBTyxFQUFFLE1BQU07SUFDZixNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7UUFDdEIsTUFBTSxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNwQyxLQUFLLE1BQU0sT0FBTyxJQUFJLGVBQWUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQy9DLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ2pFLElBQUksQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLENBQUM7Z0JBQ3pCLFNBQVM7WUFDWCxDQUFDO1lBQ0QsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQztZQUN2QyxNQUFNLFVBQVUsR0FBRyxFQUFFLENBQUMsd0JBQXdCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDeEcsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDLFlBQVksRUFBRSxFQUFFO2dCQUMxRSxNQUFNLFVBQVUsR0FBRyxjQUFjLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQ2hELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7Z0JBQ3RGLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDakgsT0FBTyxDQUFDLENBQUMsUUFBUSxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDbkQsQ0FBQyxDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ2QsUUFBUSxDQUFDLElBQUksQ0FBQztvQkFDWixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7b0JBQ2xCLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxFQUFFO29CQUMzQixHQUFHLEVBQUUsVUFBVSxDQUFDLE9BQU8sQ0FBQztvQkFDeEIsT0FBTyxFQUFFLGtCQUFrQixPQUFPLENBQUMsU0FBUyxJQUFJLEdBQUcsd0NBQXdDLE9BQU8sQ0FBQyxHQUFHLElBQUksT0FBTyxXQUFXO2lCQUM3SCxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRixDQUFDIn0=
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as ast from '../helpers.ast.js';
|
|
3
|
+
import { catalogElements, elementKey } from './shared.js';
|
|
4
|
+
const ts = plugins.typescript;
|
|
5
|
+
/** A demo factory: a function, or a reference to one (identifier or property access). */
|
|
6
|
+
const isFactory = (expressionArg) => ts.isArrowFunction(expressionArg)
|
|
7
|
+
|| ts.isFunctionExpression(expressionArg)
|
|
8
|
+
|| ts.isIdentifier(expressionArg)
|
|
9
|
+
|| ts.isPropertyAccessExpression(expressionArg);
|
|
10
|
+
/** `static demo` is a function or a non-empty array of functions. */
|
|
11
|
+
export const demoShapeRule = {
|
|
12
|
+
id: 'demo/shape',
|
|
13
|
+
severity: { base: 'error' },
|
|
14
|
+
fixMode: 'none',
|
|
15
|
+
detect: ({ project }) => {
|
|
16
|
+
const findings = [];
|
|
17
|
+
for (const element of catalogElements(project)) {
|
|
18
|
+
const member = ast.findStaticProperty(element.classNode, 'demo');
|
|
19
|
+
if (!member) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const initializer = member.initializer;
|
|
23
|
+
const valid = !!initializer && (ts.isArrayLiteralExpression(initializer)
|
|
24
|
+
? initializer.elements.length > 0 && initializer.elements.every(isFactory)
|
|
25
|
+
: isFactory(initializer));
|
|
26
|
+
if (!valid) {
|
|
27
|
+
findings.push({
|
|
28
|
+
file: element.file,
|
|
29
|
+
position: member.getStart(),
|
|
30
|
+
key: elementKey(element),
|
|
31
|
+
message: `static demo of ${element.className ?? '?'} is not a function or a non-empty array of functions`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return findings;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVtby5zaGFwZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9kZW1vLnNoYXBlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxLQUFLLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQztBQUV6QyxPQUFPLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUUxRCxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDO0FBRTlCLHlGQUF5RjtBQUN6RixNQUFNLFNBQVMsR0FBRyxDQUFDLGFBQThCLEVBQVcsRUFBRSxDQUM1RCxFQUFFLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQztPQUM5QixFQUFFLENBQUMsb0JBQW9CLENBQUMsYUFBYSxDQUFDO09BQ3RDLEVBQUUsQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDO09BQzlCLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUVsRCxxRUFBcUU7QUFDckUsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFrQjtJQUMxQyxFQUFFLEVBQUUsWUFBWTtJQUNoQixRQUFRLEVBQUUsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFO0lBQzNCLE9BQU8sRUFBRSxNQUFNO0lBQ2YsTUFBTSxFQUFFLENBQUMsRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFO1FBQ3RCLE1BQU0sUUFBUSxHQUFtQixFQUFFLENBQUM7UUFDcEMsS0FBSyxNQUFNLE9BQU8sSUFBSSxlQUFlLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUMvQyxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNqRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ1osU0FBUztZQUNYLENBQUM7WUFDRCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDO1lBQ3ZDLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQyxXQUFXLElBQUksQ0FBQyxFQUFFLENBQUMsd0JBQXdCLENBQUMsV0FBVyxDQUFDO2dCQUN0RSxDQUFDLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQztnQkFDMUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1lBQzVCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDWCxRQUFRLENBQUMsSUFBSSxDQUFDO29CQUNaLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtvQkFDbEIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUU7b0JBQzNCLEdBQUcsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDO29CQUN4QixPQUFPLEVBQUUsa0JBQWtCLE9BQU8sQ0FBQyxTQUFTLElBQUksR0FBRyxzREFBc0Q7aUJBQzFHLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGLENBQUMifQ==
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StandardProject } from '../classes.standardproject.js';
|
|
2
|
+
import type { IStandardRule } from '../rule.js';
|
|
3
|
+
export declare const componentIndexStart = "<!-- component-index:start -->";
|
|
4
|
+
export declare const componentIndexEnd = "<!-- component-index:end -->";
|
|
5
|
+
/** The generated component index block: one row per element under `ts_web/elements`, sorted by tag. */
|
|
6
|
+
export declare const renderComponentIndex: (projectArg: StandardProject, readmeTextArg: string) => string;
|
|
7
|
+
/** dees: the readme's generated component index is current and its relative links resolve. */
|
|
8
|
+
export declare const docsComponentIndexRule: IStandardRule;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { joinPath } from '../helpers.paths.js';
|
|
2
|
+
import { catalogElements } from './shared.js';
|
|
3
|
+
export const componentIndexStart = '<!-- component-index:start -->';
|
|
4
|
+
export const componentIndexEnd = '<!-- component-index:end -->';
|
|
5
|
+
const readme = 'readme.md';
|
|
6
|
+
/** GitHub-style heading anchor. */
|
|
7
|
+
const slug = (headingArg) => headingArg.toLowerCase().replace(/[^\p{L}\p{N}\s_-]/gu, '').replace(/ /g, '-');
|
|
8
|
+
const headingsOf = (textArg) => new Set([...textArg.matchAll(/^#{1,6}\s+(.+)$/gm)].map((matchArg) => slug(matchArg[1])));
|
|
9
|
+
/** The generated component index block: one row per element under `ts_web/elements`, sorted by tag. */
|
|
10
|
+
export const renderComponentIndex = (projectArg, readmeTextArg) => {
|
|
11
|
+
const headings = headingsOf(readmeTextArg);
|
|
12
|
+
const rows = catalogElements(projectArg)
|
|
13
|
+
.filter((elementArg) => elementArg.tag && elementArg.className && elementArg.file.startsWith('ts_web/elements/'))
|
|
14
|
+
.map((elementArg) => {
|
|
15
|
+
const family = elementArg.file.split('/')[2].replace(/^00group-/, '').replace(/-/g, ' ');
|
|
16
|
+
const name = elementArg.className;
|
|
17
|
+
const api = headings.has(name.toLowerCase()) ? `[${name}](#${name.toLowerCase()})` : '—';
|
|
18
|
+
return { tag: elementArg.tag, row: `| \`${elementArg.tag}\` | ${family} | ${api} | [Source](${elementArg.file}) |` };
|
|
19
|
+
})
|
|
20
|
+
.sort((a, b) => a.tag.localeCompare(b.tag, 'en'));
|
|
21
|
+
return `${componentIndexStart}\n| Element | Family | API | Source |\n| --- | --- | --- | --- |\n${rows.map((rowArg) => rowArg.row).join('\n')}\n${componentIndexEnd}`;
|
|
22
|
+
};
|
|
23
|
+
/** dees: the readme's generated component index is current and its relative links resolve. */
|
|
24
|
+
export const docsComponentIndexRule = {
|
|
25
|
+
id: 'docs/component-index',
|
|
26
|
+
severity: { dees: 'error' },
|
|
27
|
+
fixMode: 'auto',
|
|
28
|
+
detect: ({ project }) => {
|
|
29
|
+
const findings = [];
|
|
30
|
+
const text = project.files.get(readme);
|
|
31
|
+
if (text === undefined) {
|
|
32
|
+
return [{ file: readme, position: 0, key: readme, message: 'readme.md is missing' }];
|
|
33
|
+
}
|
|
34
|
+
const first = text.indexOf(componentIndexStart);
|
|
35
|
+
const last = text.indexOf(componentIndexEnd);
|
|
36
|
+
if (first < 0 || last < first) {
|
|
37
|
+
findings.push({ file: readme, position: 0, key: readme, message: `readme.md has no ${componentIndexStart} … ${componentIndexEnd} block` });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const generated = renderComponentIndex(project, text);
|
|
41
|
+
const end = last + componentIndexEnd.length;
|
|
42
|
+
if (text.slice(first, end) !== generated) {
|
|
43
|
+
findings.push({
|
|
44
|
+
file: readme,
|
|
45
|
+
position: first,
|
|
46
|
+
key: readme,
|
|
47
|
+
message: 'the component index is stale',
|
|
48
|
+
fix: (builderArg) => builderArg.edit(readme, first, end, generated),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const headings = headingsOf(text);
|
|
53
|
+
const withoutCode = text.replace(/^```[^\n]*\n[\s\S]*?^```/gm, (blockArg) => blockArg.replace(/[^\n]/g, ' '));
|
|
54
|
+
for (const match of withoutCode.matchAll(/\[[^\]]*\]\(([^\s)]+)\)/g)) {
|
|
55
|
+
const target = match[1];
|
|
56
|
+
if (/^[a-z]+:/i.test(target)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (target.startsWith('#')) {
|
|
60
|
+
if (!headings.has(target.slice(1))) {
|
|
61
|
+
findings.push({ file: readme, position: match.index, key: readme, message: `link to a missing section: ${target}` });
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const file = target.split('#')[0];
|
|
66
|
+
if (!file) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
let decoded;
|
|
70
|
+
try {
|
|
71
|
+
decoded = decodeURIComponent(file);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
findings.push({ file: readme, position: match.index, key: readme, message: `malformed link: ${target}` });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!project.exists(joinPath(decoded))) {
|
|
78
|
+
findings.push({ file: readme, position: match.index, key: readme, message: `link to a missing file: ${target}` });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return findings;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jcy5jb21wb25lbnQtaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9zdGFuZGFyZHMvcnVsZXMvZG9jcy5jb21wb25lbnQtaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFOUMsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsZ0NBQWdDLENBQUM7QUFDcEUsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsOEJBQThCLENBQUM7QUFDaEUsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDO0FBRTNCLG1DQUFtQztBQUNuQyxNQUFNLElBQUksR0FBRyxDQUFDLFVBQWtCLEVBQVUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMscUJBQXFCLEVBQUUsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztBQUU1SCxNQUFNLFVBQVUsR0FBRyxDQUFDLE9BQWUsRUFBZSxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUU5SSx1R0FBdUc7QUFDdkcsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxVQUEyQixFQUFFLGFBQXFCLEVBQVUsRUFBRTtJQUNqRyxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDM0MsTUFBTSxJQUFJLEdBQUcsZUFBZSxDQUFDLFVBQVUsQ0FBQztTQUNyQyxNQUFNLENBQUMsQ0FBQyxV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
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { catalogElements, elementKey } from './shared.js';
|
|
3
|
+
const ts = plugins.typescript;
|
|
4
|
+
/** The element class is exported. */
|
|
5
|
+
export const elementExportedRule = {
|
|
6
|
+
id: 'element/exported',
|
|
7
|
+
severity: { base: 'error' },
|
|
8
|
+
fixMode: 'auto',
|
|
9
|
+
detect: ({ project }) => {
|
|
10
|
+
const findings = [];
|
|
11
|
+
for (const element of catalogElements(project)) {
|
|
12
|
+
if (element.exported) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const finding = {
|
|
16
|
+
file: element.file,
|
|
17
|
+
position: element.decoratorCall.getStart(),
|
|
18
|
+
key: elementKey(element),
|
|
19
|
+
message: `class ${element.className ?? '?'} (<${element.tag ?? '?'}>) is not exported`,
|
|
20
|
+
};
|
|
21
|
+
// `export` goes before the first keyword modifier (e.g. `abstract`) or the `class` keyword, after the decorators.
|
|
22
|
+
const firstModifier = (ts.getModifiers(element.classNode) ?? [])[0];
|
|
23
|
+
const classKeyword = element.classNode.getChildren().find((childArg) => childArg.kind === ts.SyntaxKind.ClassKeyword);
|
|
24
|
+
const position = firstModifier?.getStart() ?? classKeyword?.getStart();
|
|
25
|
+
if (position !== undefined && element.classNode.parent === element.sourceFile) {
|
|
26
|
+
finding.fix = (builderArg) => builderArg.edit(element.file, position, position, 'export ');
|
|
27
|
+
}
|
|
28
|
+
findings.push(finding);
|
|
29
|
+
}
|
|
30
|
+
return findings;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC5leHBvcnRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9lbGVtZW50LmV4cG9ydGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFMUQsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztBQUU5QixxQ0FBcUM7QUFDckMsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQWtCO0lBQ2hELEVBQUUsRUFBRSxrQkFBa0I7SUFDdEIsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRTtJQUMzQixPQUFPLEVBQUUsTUFBTTtJQUNmLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRTtRQUN0QixNQUFNLFFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBQ3BDLEtBQUssTUFBTSxPQUFPLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDL0MsSUFBSSxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUM7Z0JBQ3JCLFNBQVM7WUFDWCxDQUFDO1lBQ0QsTUFBTSxPQUFPLEdBQWlCO2dCQUM1QixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7Z0JBQ2xCLFFBQVEsRUFBRSxPQUFPLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRTtnQkFDMUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxPQUFPLENBQUM7Z0JBQ3hCLE9BQU8sRUFBRSxTQUFTLE9BQU8sQ0FBQyxTQUFTLElBQUksR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxvQkFBb0I7YUFDdkYsQ0FBQztZQUNGLGtIQUFrSDtZQUNsSCxNQUFNLGFBQWEsR0FBRyxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3BFLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDdEgsTUFBTSxRQUFRLEdBQUcsYUFBYSxFQUFFLFFBQVEsRUFBRSxJQUFJLFlBQVksRUFBRSxRQUFRLEVBQUUsQ0FBQztZQUN2RSxJQUFJLFFBQVEsS0FBSyxTQUFTLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEtBQUssT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO2dCQUM5RSxPQUFPLENBQUMsR0FBRyxHQUFHLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUM3RixDQUFDO1lBQ0QsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN6QixDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGLENBQUMifQ==
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { elementKey, isCustomElementName } from './shared.js';
|
|
2
|
+
/** `@customElement` takes a single string literal that is a valid custom element name. */
|
|
3
|
+
export const elementLiteralTagRule = {
|
|
4
|
+
id: 'element/literal-tag',
|
|
5
|
+
severity: { base: 'error' },
|
|
6
|
+
fixMode: 'none',
|
|
7
|
+
detect: ({ project }) => {
|
|
8
|
+
const findings = [];
|
|
9
|
+
for (const element of project.elements) {
|
|
10
|
+
if (element.tag === null) {
|
|
11
|
+
findings.push({
|
|
12
|
+
file: element.file,
|
|
13
|
+
position: element.decoratorCall.getStart(),
|
|
14
|
+
key: elementKey(element),
|
|
15
|
+
message: `@customElement of ${element.className ?? 'an anonymous class'} does not take a single string literal`,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else if (!isCustomElementName(element.tag)) {
|
|
19
|
+
findings.push({
|
|
20
|
+
file: element.file,
|
|
21
|
+
position: element.decoratorCall.getStart(),
|
|
22
|
+
key: elementKey(element),
|
|
23
|
+
message: `'${element.tag}' is not a valid custom element name (a lowercase letter, then lowercase letters, digits, '-', '.' or '_', with at least one '-')`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return findings;
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC5saXRlcmFsLXRhZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9lbGVtZW50LmxpdGVyYWwtdGFnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFOUQsMEZBQTBGO0FBQzFGLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFrQjtJQUNsRCxFQUFFLEVBQUUscUJBQXFCO0lBQ3pCLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7SUFDM0IsT0FBTyxFQUFFLE1BQU07SUFDZixNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7UUFDdEIsTUFBTSxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNwQyxLQUFLLE1BQU0sT0FBTyxJQUFJLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN2QyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ3pCLFFBQVEsQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUU7b0JBQzFDLEdBQUcsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDO29CQUN4QixPQUFPLEVBQUUscUJBQXFCLE9BQU8sQ0FBQyxTQUFTLElBQUksb0JBQW9CLHdDQUF3QztpQkFDaEgsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztpQkFBTSxJQUFJLENBQUMsbUJBQW1CLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzdDLFFBQVEsQ0FBQyxJQUFJLENBQUM7b0JBQ1osSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO29CQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUU7b0JBQzFDLEdBQUcsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDO29CQUN4QixPQUFPLEVBQUUsSUFBSSxPQUFPLENBQUMsR0FBRyxtSUFBbUk7aUJBQzVKLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGLENBQUMifQ==
|