@design.estate/wcctools 6.0.0 → 6.2.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 +33 -0
- package/dist_shell/bundle.js +405 -368
- package/dist_shell/bundle.js.map +1 -1
- package/dist_shell/bundle.js.third-party-notices.json +52 -0
- package/dist_shell/bundle.js.third-party-notices.txt +107 -1
- package/dist_shell/index.html +1 -1
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.bundlestatus.d.ts +36 -0
- package/dist_ts/classes.bundlestatus.js +110 -0
- package/dist_ts/classes.devapi.d.ts +3 -0
- package/dist_ts/classes.devapi.js +8 -1
- package/dist_ts/classes.devserver.d.ts +45 -10
- package/dist_ts/classes.devserver.js +123 -49
- package/dist_ts/cli.js +12 -3
- package/dist_ts/index.d.ts +0 -2
- package/dist_ts/index.js +1 -3
- 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/requests.d.ts +35 -0
- package/dist_ts_interfaces/standard.d.ts +93 -0
- package/dist_ts_interfaces/standard.js +6 -0
- package/dist_ts_shell/bundlestatus.d.ts +15 -0
- package/dist_ts_shell/bundlestatus.js +64 -0
- package/dist_ts_shell/elements/wcc-contextmenu.d.ts +3 -0
- package/dist_ts_shell/elements/wcc-contextmenu.js +18 -3
- package/dist_ts_shell/elements/wcc-preview-frame.d.ts +6 -0
- package/dist_ts_shell/elements/wcc-preview-frame.js +50 -2
- package/dist_ts_shell/elements/wcc-shell.d.ts +15 -0
- package/dist_ts_shell/elements/wcc-shell.js +45 -3
- package/dist_ts_shell/plugins.d.ts +2 -1
- package/dist_ts_shell/plugins.js +3 -2
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/package.json +8 -3
- package/readme.md +40 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.bundlestatus.ts +123 -0
- package/ts/classes.devapi.ts +9 -0
- package/ts/classes.devserver.ts +127 -47
- package/ts/cli.ts +12 -2
- package/ts/index.ts +0 -2
- 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_interfaces/bridge.ts +95 -0
- package/ts_interfaces/catalog.ts +37 -0
- package/ts_interfaces/index.ts +4 -0
- package/ts_interfaces/plugins.ts +3 -0
- package/ts_interfaces/requests.ts +65 -0
- package/ts_interfaces/standard.ts +103 -0
- package/ts_shared/index.ts +1 -0
- package/ts_shared/plugins.ts +3 -0
- package/ts_shared/previewroute.ts +58 -0
- package/ts_shell/bundlestatus.ts +68 -0
- package/ts_shell/elements/wcc-contextmenu.ts +306 -0
- package/ts_shell/elements/wcc-preview-frame.ts +167 -0
- package/ts_shell/elements/wcc-properties.ts +998 -0
- package/ts_shell/elements/wcc-record-button.ts +108 -0
- package/ts_shell/elements/wcc-recording-panel.ts +1005 -0
- package/ts_shell/elements/wcc-shell.ts +485 -0
- package/ts_shell/elements/wcc-sidebar.ts +1419 -0
- package/ts_shell/index.html +21 -0
- package/ts_shell/index.ts +4 -0
- package/ts_shell/plugins.ts +12 -0
- package/ts_shell/previewconnection.ts +103 -0
- package/ts_shell/services/recorder.service.ts +451 -0
- package/ts_shell/types/dom-mediacapture-stub/index.d.ts +12 -0
- package/ts_shell/types/dom-mediacapture-stub/package.json +6 -0
- package/ts_shell/types/dom-webcodecs-stub/index.d.ts +2 -0
- package/ts_shell/types/dom-webcodecs-stub/package.json +6 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
|
@@ -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==
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { rootBarrel } from '../classes.standardproject.js';
|
|
2
|
+
import { dirOf } from '../helpers.paths.js';
|
|
3
|
+
import { addReexport, catalogElements, elementKey } from './shared.js';
|
|
4
|
+
/** Every entry file outside demo files is reachable from `ts_web/index.ts`. */
|
|
5
|
+
export const elementReachableRule = {
|
|
6
|
+
id: 'element/reachable',
|
|
7
|
+
severity: { base: 'error' },
|
|
8
|
+
fixMode: 'auto',
|
|
9
|
+
allowlistCategories: ['internal'],
|
|
10
|
+
detect: ({ project }) => {
|
|
11
|
+
const findings = [];
|
|
12
|
+
const reached = project.reachableFrom(rootBarrel);
|
|
13
|
+
for (const element of catalogElements(project)) {
|
|
14
|
+
if (reached.has(element.file)) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const finding = {
|
|
18
|
+
file: element.file,
|
|
19
|
+
position: element.decoratorCall.getStart(),
|
|
20
|
+
key: elementKey(element),
|
|
21
|
+
message: `<${element.tag ?? '?'}> in ${element.file} is not reachable from ${rootBarrel}`,
|
|
22
|
+
};
|
|
23
|
+
// Walk up to the nearest reachable barrel; an unreachable barrel that already re-exports the file is exported instead.
|
|
24
|
+
let candidate = element.file;
|
|
25
|
+
let dir = dirOf(element.file);
|
|
26
|
+
while (dir.startsWith('ts_web')) {
|
|
27
|
+
const barrel = `${dir}/index.ts`;
|
|
28
|
+
if (barrel !== candidate && project.files.has(barrel)) {
|
|
29
|
+
if (reached.has(barrel)) {
|
|
30
|
+
const target = candidate;
|
|
31
|
+
finding.fix = (builderArg) => addReexport(builderArg, project, barrel, target);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
if (project.reexports(barrel).some((reexportArg) => reexportArg.target === candidate)) {
|
|
35
|
+
candidate = barrel;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (dir === 'ts_web') {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
dir = dirOf(dir);
|
|
42
|
+
}
|
|
43
|
+
findings.push(finding);
|
|
44
|
+
}
|
|
45
|
+
return findings;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC5yZWFjaGFibGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9zdGFuZGFyZHMvcnVsZXMvZWxlbWVudC5yZWFjaGFibGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzNELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUU1QyxPQUFPLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFdkUsK0VBQStFO0FBQy9FLE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFrQjtJQUNqRCxFQUFFLEVBQUUsbUJBQW1CO0lBQ3ZCLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUU7SUFDM0IsT0FBTyxFQUFFLE1BQU07SUFDZixtQkFBbUIsRUFBRSxDQUFDLFVBQVUsQ0FBQztJQUNqQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUU7UUFDdEIsTUFBTSxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNwQyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xELEtBQUssTUFBTSxPQUFPLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDL0MsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM5QixTQUFTO1lBQ1gsQ0FBQztZQUNELE1BQU0sT0FBTyxHQUFpQjtnQkFDNUIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO2dCQUNsQixRQUFRLEVBQUUsT0FBTyxDQUFDLGFBQWEsQ0FBQyxRQUFRLEVBQUU7Z0JBQzFDLEdBQUcsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDO2dCQUN4QixPQUFPLEVBQUUsSUFBSSxPQUFPLENBQUMsR0FBRyxJQUFJLEdBQUcsUUFBUSxPQUFPLENBQUMsSUFBSSwwQkFBMEIsVUFBVSxFQUFFO2FBQzFGLENBQUM7WUFDRix1SEFBdUg7WUFDdkgsSUFBSSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztZQUM3QixJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzlCLE9BQU8sR0FBRyxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxNQUFNLE1BQU0sR0FBRyxHQUFHLEdBQUcsV0FBVyxDQUFDO2dCQUNqQyxJQUFJLE1BQU0sS0FBSyxTQUFTLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztvQkFDdEQsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7d0JBQ3hCLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQzt3QkFDekIsT0FBTyxDQUFDLEdBQUcsR0FBRyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO3dCQUMvRSxNQUFNO29CQUNSLENBQUM7b0JBQ0QsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLE1BQU0sS0FBSyxTQUFTLENBQUMsRUFBRSxDQUFDO3dCQUN0RixTQUFTLEdBQUcsTUFBTSxDQUFDO29CQUNyQixDQUFDO2dCQUNILENBQUM7Z0JBQ0QsSUFBSSxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQ3JCLE1BQU07Z0JBQ1IsQ0FBQztnQkFDRCxHQUFHLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25CLENBQUM7WUFDRCxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3pCLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0NBQ0YsQ0FBQyJ9
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as ast from '../helpers.ast.js';
|
|
3
|
+
import { catalogElements, elementKey, isCustomElementName } from './shared.js';
|
|
4
|
+
const ts = plugins.typescript;
|
|
5
|
+
/** The tags of a file's `declare global { interface HTMLElementTagNameMap { … } }` and the first such interface. */
|
|
6
|
+
const tagMapOf = (sourceFileArg) => {
|
|
7
|
+
const tags = new Set();
|
|
8
|
+
let declaration = null;
|
|
9
|
+
for (const statement of sourceFileArg.statements) {
|
|
10
|
+
if (!ts.isModuleDeclaration(statement) || !ts.isIdentifier(statement.name) || statement.name.text !== 'global'
|
|
11
|
+
|| !statement.body || !ts.isModuleBlock(statement.body)) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
for (const inner of statement.body.statements) {
|
|
15
|
+
if (ts.isInterfaceDeclaration(inner) && inner.name.text === 'HTMLElementTagNameMap') {
|
|
16
|
+
declaration ??= inner;
|
|
17
|
+
for (const member of inner.members) {
|
|
18
|
+
if (ts.isPropertySignature(member) && member.name && (ts.isStringLiteral(member.name) || ts.isIdentifier(member.name))) {
|
|
19
|
+
tags.add(member.name.text);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return { tags, declaration };
|
|
26
|
+
};
|
|
27
|
+
/** Adds every missing element of one file to its tag map, or appends a tag map block to the file. */
|
|
28
|
+
const tagMapFix = (missingArg) => (builderArg) => {
|
|
29
|
+
const sourceFile = missingArg[0].sourceFile;
|
|
30
|
+
const file = missingArg[0].file;
|
|
31
|
+
const text = sourceFile.text;
|
|
32
|
+
const { declaration } = tagMapOf(sourceFile);
|
|
33
|
+
if (declaration) {
|
|
34
|
+
const closeBrace = declaration.end - 1;
|
|
35
|
+
const lineStart = text.lastIndexOf('\n', closeBrace - 1) + 1;
|
|
36
|
+
const firstMember = declaration.members[0];
|
|
37
|
+
const indentation = firstMember
|
|
38
|
+
? ast.indentationAt(text, firstMember.getStart())
|
|
39
|
+
: `${ast.indentationAt(text, declaration.getStart())} `;
|
|
40
|
+
const lines = missingArg.map((elementArg) => `${indentation}'${elementArg.tag}': ${elementArg.className};\n`).join('');
|
|
41
|
+
if (/^[ \t]*$/.test(text.slice(lineStart, closeBrace))) {
|
|
42
|
+
builderArg.edit(file, lineStart, lineStart, lines);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
builderArg.edit(file, closeBrace, closeBrace, `\n${lines}`);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const members = missingArg.map((elementArg) => ` '${elementArg.tag}': ${elementArg.className};\n`).join('');
|
|
50
|
+
const prefix = text.length === 0 || text.endsWith('\n') ? '' : '\n';
|
|
51
|
+
builderArg.edit(file, text.length, text.length, `${prefix}\ndeclare global {\n interface HTMLElementTagNameMap {\n${members} }\n}\n`);
|
|
52
|
+
};
|
|
53
|
+
/** The entry file declares `declare global { interface HTMLElementTagNameMap { '<tag>': <Class> } }`. */
|
|
54
|
+
export const elementTagMapRule = {
|
|
55
|
+
id: 'element/tag-map',
|
|
56
|
+
severity: { base: 'warn' },
|
|
57
|
+
fixMode: 'auto',
|
|
58
|
+
detect: ({ project }) => {
|
|
59
|
+
const findings = [];
|
|
60
|
+
const byFile = new Map();
|
|
61
|
+
for (const element of catalogElements(project)) {
|
|
62
|
+
if (element.tag && !tagMapOf(element.sourceFile).tags.has(element.tag)) {
|
|
63
|
+
byFile.set(element.file, [...(byFile.get(element.file) ?? []), element]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const missing of byFile.values()) {
|
|
67
|
+
// The tag is written into the source: only valid custom element names are.
|
|
68
|
+
const fixable = missing.every((elementArg) => elementArg.className && isCustomElementName(elementArg.tag));
|
|
69
|
+
const fix = fixable ? tagMapFix(missing) : undefined;
|
|
70
|
+
for (const element of missing) {
|
|
71
|
+
findings.push({
|
|
72
|
+
file: element.file,
|
|
73
|
+
position: element.decoratorCall.getStart(),
|
|
74
|
+
key: elementKey(element),
|
|
75
|
+
message: `HTMLElementTagNameMap of ${element.file} does not declare '${element.tag}'`,
|
|
76
|
+
fix,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return findings;
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC50YWctbWFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvc3RhbmRhcmRzL3J1bGVzL2VsZW1lbnQudGFnLW1hcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sS0FBSyxHQUFHLE1BQU0sbUJBQW1CLENBQUM7QUFHekMsT0FBTyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFL0UsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztBQUU5QixvSEFBb0g7QUFDcEgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxhQUE4QixFQUFzRixFQUFFO0lBQ3RJLE1BQU0sSUFBSSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDL0IsSUFBSSxXQUFXLEdBQW1ELElBQUksQ0FBQztJQUN2RSxLQUFLLE1BQU0sU0FBUyxJQUFJLGFBQWEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNqRCxJQUFJLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUTtlQUN6RyxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzFELFNBQVM7UUFDWCxDQUFDO1FBQ0QsS0FBSyxNQUFNLEtBQUssSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzlDLElBQUksRUFBRSxDQUFDLHNCQUFzQixDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLHVCQUF1QixFQUFFLENBQUM7Z0JBQ3BGLFdBQVcsS0FBSyxLQUFLLENBQUM7Z0JBQ3RCLEtBQUssTUFBTSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO29CQUNuQyxJQUFJLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDO3dCQUN2SCxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQzdCLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLENBQUM7QUFDL0IsQ0FBQyxDQUFDO0FBRUYscUdBQXFHO0FBQ3JHLE1BQU0sU0FBUyxHQUFHLENBQUMsVUFBOEIsRUFBYyxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRTtJQUMvRSxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQzVDLE1BQU0sSUFBSSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDaEMsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQztJQUM3QixNQUFNLEVBQUUsV0FBVyxFQUFFLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzdDLElBQUksV0FBVyxFQUFFLENBQUM7UUFDaEIsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDdkMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsVUFBVSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM3RCxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNDLE1BQU0sV0FBVyxHQUFHLFdBQVc7WUFDN0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNqRCxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxXQUFXLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDO1FBQzNELE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLEdBQUcsV0FBVyxJQUFJLFVBQVUsQ0FBQyxHQUFHLE1BQU0sVUFBVSxDQUFDLFNBQVMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZILElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDdkQsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyRCxDQUFDO2FBQU0sQ0FBQztZQUNOLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsS0FBSyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFDRCxPQUFPO0lBQ1QsQ0FBQztJQUNELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFFBQVEsVUFBVSxDQUFDLEdBQUcsTUFBTSxVQUFVLENBQUMsU0FBUyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDL0csTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDcEUsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsTUFBTSw0REFBNEQsT0FBTyxVQUFVLENBQUMsQ0FBQztBQUMxSSxDQUFDLENBQUM7QUFFRix5R0FBeUc7QUFDekcsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQWtCO0lBQzlDLEVBQUUsRUFBRSxpQkFBaUI7SUFDckIsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRTtJQUMxQixPQUFPLEVBQUUsTUFBTTtJQUNmLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRTtRQUN0QixNQUFNLFFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUE4QixDQUFDO1FBQ3JELEtBQUssTUFBTSxPQUFPLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDL0MsSUFBSSxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN2RSxNQUFNLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUMzRSxDQUFDO1FBQ0gsQ0FBQztRQUNELEtBQUssTUFBTSxPQUFPLElBQUksTUFBTSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDdEMsMkVBQTJFO1lBQzNFLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxTQUFTLElBQUksbUJBQW1CLENBQUMsVUFBVSxDQUFDLEdBQUksQ0FBQyxDQUFDLENBQUM7WUFDNUcsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztZQUNyRCxLQUFLLE1BQU0sT0FBTyxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUM5QixRQUFRLENBQUMsSUFBSSxDQUFDO29CQUNaLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtvQkFDbEIsUUFBUSxFQUFFLE9BQU8sQ0FBQyxhQUFhLENBQUMsUUFBUSxFQUFFO29CQUMxQyxHQUFHLEVBQUUsVUFBVSxDQUFDLE9BQU8sQ0FBQztvQkFDeEIsT0FBTyxFQUFFLDRCQUE0QixPQUFPLENBQUMsSUFBSSxzQkFBc0IsT0FBTyxDQUFDLEdBQUcsR0FBRztvQkFDckYsR0FBRztpQkFDSixDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7Q0FDRixDQUFDIn0=
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import * as ast from '../helpers.ast.js';
|
|
3
|
+
import { isDemoFile } from '../helpers.paths.js';
|
|
4
|
+
const ts = plugins.typescript;
|
|
5
|
+
/** The words belong to the catalog; demos, demo data, the i18n catalog and the demo pages show sample content. */
|
|
6
|
+
const isExempt = (fileArg) => isDemoFile(fileArg)
|
|
7
|
+
|| fileArg.startsWith('ts_web/i18n/')
|
|
8
|
+
|| fileArg.startsWith('ts_web/demos/')
|
|
9
|
+
|| fileArg.startsWith('ts_web/pages/');
|
|
10
|
+
const wordAttributes = 'aria-label|aria-description|aria-valuetext|title|placeholder|label|text|heading|subheading|alt';
|
|
11
|
+
const wordProperties = new Set(['name', 'label', 'text', 'heading', 'subheading', 'title', 'placeholder', 'message', 'description', 'confirmLabel', 'cancelLabel', 'emptyText', 'tooltip', 'hint']);
|
|
12
|
+
const word = /^[A-Z][a-z]+(?:[ '’,.?!…-]+[A-Za-z]+)*[.?!…]?$/;
|
|
13
|
+
/** The patterns of dees-catalog's scripts/check-literal-ratchet.cjs that apply to template and string text. */
|
|
14
|
+
const textPatterns = () => [
|
|
15
|
+
// aria-label="Progress"
|
|
16
|
+
new RegExp(`\\s(?:${wordAttributes})="([A-Za-z][^"$]*[a-z][^"$]*)"`, 'g'),
|
|
17
|
+
// >Cancel< and > Back <
|
|
18
|
+
/(?<![=-])>\s*([A-Z][a-z]+(?:[ '’,.?!…-]+[A-Za-z]+)*[.?!…]?)\s*</g,
|
|
19
|
+
];
|
|
20
|
+
/** dees: no English literal a reader sees outside demo files, `ts_web/i18n/`, `ts_web/demos/` and `ts_web/pages/`. A ratchet. */
|
|
21
|
+
export const i18nLiteralsRule = {
|
|
22
|
+
id: 'i18n/literals',
|
|
23
|
+
severity: { dees: 'error' },
|
|
24
|
+
fixMode: 'none',
|
|
25
|
+
detect: ({ project }) => {
|
|
26
|
+
const findings = [];
|
|
27
|
+
for (const file of project.webFiles) {
|
|
28
|
+
if (isExempt(file)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const visit = (nodeArg) => {
|
|
32
|
+
if (ts.isStringLiteral(nodeArg) || ts.isNoSubstitutionTemplateLiteral(nodeArg)
|
|
33
|
+
|| ts.isTemplateHead(nodeArg) || ts.isTemplateMiddle(nodeArg) || ts.isTemplateTail(nodeArg)) {
|
|
34
|
+
const text = nodeArg.getText();
|
|
35
|
+
for (const pattern of textPatterns()) {
|
|
36
|
+
for (const match of text.matchAll(pattern)) {
|
|
37
|
+
findings.push({ file, position: nodeArg.getStart() + match.index, key: file, message: `English literal ${match[0].trim()}` });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (ts.isPropertyAssignment(nodeArg) && (ts.isIdentifier(nodeArg.name) || ts.isStringLiteral(nodeArg.name))
|
|
42
|
+
&& wordProperties.has(nodeArg.name.text) && ts.isStringLiteral(nodeArg.initializer) && word.test(nodeArg.initializer.text)) {
|
|
43
|
+
findings.push({ file, position: nodeArg.getStart(), key: file, message: `English literal ${nodeArg.getText()}` });
|
|
44
|
+
}
|
|
45
|
+
ts.forEachChild(nodeArg, visit);
|
|
46
|
+
};
|
|
47
|
+
visit(project.sourceFile(file));
|
|
48
|
+
}
|
|
49
|
+
return findings;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaTE4bi5saXRlcmFscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL3N0YW5kYXJkcy9ydWxlcy9pMThuLmxpdGVyYWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxLQUFLLEdBQUcsTUFBTSxtQkFBbUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFHakQsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQztBQUU5QixrSEFBa0g7QUFDbEgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxPQUFlLEVBQVcsRUFBRSxDQUM1QyxVQUFVLENBQUMsT0FBTyxDQUFDO09BQ2hCLE9BQU8sQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDO09BQ2xDLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDO09BQ25DLE9BQU8sQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLENBQUM7QUFFekMsTUFBTSxjQUFjLEdBQUcsZ0dBQWdHLENBQUM7QUFDeEgsTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLGFBQWEsRUFBRSxjQUFjLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztBQUNwTSxNQUFNLElBQUksR0FBRyxnREFBZ0QsQ0FBQztBQUU5RCwrR0FBK0c7QUFDL0csTUFBTSxZQUFZLEdBQUcsR0FBYSxFQUFFLENBQUM7SUFDbkMsd0JBQXdCO0lBQ3hCLElBQUksTUFBTSxDQUFDLFNBQVMsY0FBYyxpQ0FBaUMsRUFBRSxHQUFHLENBQUM7SUFDekUsd0JBQXdCO0lBQ3hCLGtFQUFrRTtDQUNuRSxDQUFD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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IStandardRule } from '../rule.js';
|
|
2
|
+
export { reflectExemptNames } from './props.reflect-primitive.js';
|
|
3
|
+
export { renderComponentIndex } from './docs.component-index.js';
|
|
4
|
+
/** Every rule of docs/standard.md, in the order of the document. */
|
|
5
|
+
export declare const standardRules: readonly IStandardRule[];
|
|
6
|
+
/**
|
|
7
|
+
* The order `wcctools fix` applies rules in: content edits first, then file moves (which rewrite imports),
|
|
8
|
+
* then barrels and reachability on the final layout, then the generated docs.
|
|
9
|
+
*/
|
|
10
|
+
export declare const fixOrder: readonly string[];
|
|
11
|
+
/** Findings the checker itself produces for the allowlist. */
|
|
12
|
+
export declare const allowlistStaleRuleId = "allowlist/stale";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { barrelElementIndexRule } from './barrel.element-index.js';
|
|
2
|
+
import { barrelNoDemoExportRule } from './barrel.no-demo-export.js';
|
|
3
|
+
import { demoFixtureNotExportedRule } from './demo.fixture-not-exported.js';
|
|
4
|
+
import { demoGroupsRule } from './demo.groups.js';
|
|
5
|
+
import { demoRequiredRule } from './demo.required.js';
|
|
6
|
+
import { demoSeparateFileRule } from './demo.separate-file.js';
|
|
7
|
+
import { demoShapeRule } from './demo.shape.js';
|
|
8
|
+
import { docsComponentIndexRule } from './docs.component-index.js';
|
|
9
|
+
import { elementExportedRule } from './element.exported.js';
|
|
10
|
+
import { elementLiteralTagRule } from './element.literal-tag.js';
|
|
11
|
+
import { elementReachableRule } from './element.reachable.js';
|
|
12
|
+
import { elementTagMapRule } from './element.tag-map.js';
|
|
13
|
+
import { i18nLiteralsRule } from './i18n.literals.js';
|
|
14
|
+
import { layoutElementFolderRule } from './layout.element-folder.js';
|
|
15
|
+
import { layoutEntryFileNameRule } from './layout.entry-file-name.js';
|
|
16
|
+
import { layoutEntryRule } from './layout.entry.js';
|
|
17
|
+
import { layoutGroupFolderRule } from './layout.group-folder.js';
|
|
18
|
+
import { layoutShared00Rule } from './layout.shared-00.js';
|
|
19
|
+
import { namingClassMatchesTagRule } from './naming.class-matches-tag.js';
|
|
20
|
+
import { namingLowercaseFilesRule } from './naming.lowercase-files.js';
|
|
21
|
+
import { namingTagPrefixRule } from './naming.tag-prefix.js';
|
|
22
|
+
import { propsAccessorRule } from './props.accessor.js';
|
|
23
|
+
import { propsObjectNoAttributeRule } from './props.object-no-attribute.js';
|
|
24
|
+
import { propsReflectPrimitiveRule } from './props.reflect-primitive.js';
|
|
25
|
+
import { propsTypedRule } from './props.typed.js';
|
|
26
|
+
import { styleBdThemeRule } from './style.bdtheme.js';
|
|
27
|
+
export { reflectExemptNames } from './props.reflect-primitive.js';
|
|
28
|
+
export { renderComponentIndex } from './docs.component-index.js';
|
|
29
|
+
/** Every rule of docs/standard.md, in the order of the document. */
|
|
30
|
+
export const standardRules = [
|
|
31
|
+
layoutEntryRule,
|
|
32
|
+
layoutElementFolderRule,
|
|
33
|
+
layoutEntryFileNameRule,
|
|
34
|
+
layoutGroupFolderRule,
|
|
35
|
+
layoutShared00Rule,
|
|
36
|
+
namingLowercaseFilesRule,
|
|
37
|
+
namingTagPrefixRule,
|
|
38
|
+
namingClassMatchesTagRule,
|
|
39
|
+
elementLiteralTagRule,
|
|
40
|
+
elementExportedRule,
|
|
41
|
+
elementTagMapRule,
|
|
42
|
+
elementReachableRule,
|
|
43
|
+
barrelElementIndexRule,
|
|
44
|
+
barrelNoDemoExportRule,
|
|
45
|
+
demoShapeRule,
|
|
46
|
+
demoRequiredRule,
|
|
47
|
+
demoSeparateFileRule,
|
|
48
|
+
demoGroupsRule,
|
|
49
|
+
demoFixtureNotExportedRule,
|
|
50
|
+
propsAccessorRule,
|
|
51
|
+
propsTypedRule,
|
|
52
|
+
propsReflectPrimitiveRule,
|
|
53
|
+
propsObjectNoAttributeRule,
|
|
54
|
+
styleBdThemeRule,
|
|
55
|
+
i18nLiteralsRule,
|
|
56
|
+
docsComponentIndexRule,
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* The order `wcctools fix` applies rules in: content edits first, then file moves (which rewrite imports),
|
|
60
|
+
* then barrels and reachability on the final layout, then the generated docs.
|
|
61
|
+
*/
|
|
62
|
+
export const fixOrder = [
|
|
63
|
+
'element/exported',
|
|
64
|
+
'element/tag-map',
|
|
65
|
+
'props/accessor',
|
|
66
|
+
'props/typed',
|
|
67
|
+
'props/object-no-attribute',
|
|
68
|
+
'props/reflect-primitive',
|
|
69
|
+
'demo/groups',
|
|
70
|
+
'demo/required',
|
|
71
|
+
'barrel/no-demo-export',
|
|
72
|
+
'demo/fixture-not-exported',
|
|
73
|
+
'naming/lowercase-files',
|
|
74
|
+
'layout/shared-00',
|
|
75
|
+
'layout/entry-file-name',
|
|
76
|
+
'layout/element-folder',
|
|
77
|
+
'barrel/element-index',
|
|
78
|
+
'element/reachable',
|
|
79
|
+
'docs/component-index',
|
|
80
|
+
];
|
|
81
|
+
/** Findings the checker itself produces for the allowlist. */
|
|
82
|
+
export const allowlistStaleRuleId = 'allowlist/stale';
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9zdGFuZGFyZHMvcnVsZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDbkUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDcEUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDNUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNuRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUM1RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNqRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDakUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDM0QsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDMUUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDdkUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDNUUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDekUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXRELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRWpFLG9FQUFvRTtBQUNwRSxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQTZCO0lBQ3JELGVBQWU7SUFDZix1QkFBdUI7SUFDdkIsdUJBQXVCO0lBQ3ZCLHFCQUFxQjtJQUNyQixrQkFBa0I7SUFDbEIsd0JBQXdCO0lBQ3hCLG1CQUFtQjtJQUNuQix5QkFBeUI7SUFDekIscUJBQXFCO0lBQ3JCLG1CQUFtQjtJQUNuQixpQkFBaUI7SUFDakIsb0JBQW9CO0lBQ3BCLHNCQUFzQjtJQUN0QixzQkFBc0I7SUFDdEIsYUFBYTtJQUNiLGdCQUFnQjtJQUNoQixvQkFBb0I7SUFDcEIsY0FBYztJQUNkLDBCQUEwQjtJQUMxQixpQkFBaUI7SUFDakIsY0FBYztJQUNkLHlCQUF5QjtJQUN6QiwwQkFBMEI7SUFDMUIsZ0JBQWdCO0lBQ2hCLGdCQUFnQjtJQUNoQixzQkFBc0I7Q0FDdkIsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBc0I7SUFDekMsa0JBQWtCO0lBQ2xCLGlCQUFpQjtJQUNqQixnQkFBZ0I7SUFDaEIsYUFBYTtJQUNiLDJCQUEyQjtJQUMzQix5QkFBeUI7SUFDekIsYUFBYTtJQUNiLGVBQWU7SUFDZix1QkFBdUI7SUFDdkIsMkJBQTJCO0lBQzNCLHdCQUF3QjtJQUN4QixrQkFBa0I7SUFDbEIsd0JBQXdCO0lBQ3hCLHVCQUF1QjtJQUN2QixzQkFBc0I7SUFDdEIsbUJBQW1CO0lBQ25CLHNCQUFzQjtDQUN2QixDQUFDO0FBRUYsOERBQThEO0FBQzlELE1BQU0sQ0FBQyxNQUFNLG9CQUFvQixHQUFHLGlCQUFpQixDQUFDIn0=
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { baseOf, dirOf } from '../helpers.paths.js';
|
|
2
|
+
import { catalogElements, elementKey, elementsDir, isCustomElementName, isElementParentDir, isInElementFolder } from './shared.js';
|
|
3
|
+
/** Every element's entry file lives in its own element folder `ts_web/elements/[00group-<area>/]<tag>/<tag>.ts`. */
|
|
4
|
+
export const layoutElementFolderRule = {
|
|
5
|
+
id: 'layout/element-folder',
|
|
6
|
+
severity: { base: 'warn' },
|
|
7
|
+
fixMode: 'auto',
|
|
8
|
+
detect: ({ project }) => {
|
|
9
|
+
const findings = [];
|
|
10
|
+
const elements = catalogElements(project);
|
|
11
|
+
for (const element of elements) {
|
|
12
|
+
if (!element.tag || isInElementFolder(element)) {
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
const currentDir = dirOf(element.file);
|
|
16
|
+
const group = /^ts_web\/elements\/(00group-[^/]+)(\/|$)/.exec(currentDir)?.[1];
|
|
17
|
+
const folder = `${elementsDir}/${group ? `${group}/` : ''}${element.tag}`;
|
|
18
|
+
const finding = {
|
|
19
|
+
file: element.file,
|
|
20
|
+
position: element.decoratorCall.getStart(),
|
|
21
|
+
key: elementKey(element),
|
|
22
|
+
message: `<${element.tag}> is declared in ${element.file}; its element folder is ${folder}/`,
|
|
23
|
+
};
|
|
24
|
+
const elementsInFile = elements.filter((otherArg) => otherArg.file === element.file);
|
|
25
|
+
const folderTaken = [...project.files.keys()].some((fileArg) => fileArg.startsWith(`${folder}/`)) || project.exists(folder);
|
|
26
|
+
// Only flat files move mechanically: a misnamed folder holds more than this element. The folder
|
|
27
|
+
// is named after the tag, so only a valid custom element name is usable.
|
|
28
|
+
if (isCustomElementName(element.tag) && elementsInFile.length === 1 && isElementParentDir(currentDir) && !folderTaken) {
|
|
29
|
+
const tag = element.tag;
|
|
30
|
+
const companions = [...project.files.keys()].filter((fileArg) => fileArg !== element.file && dirOf(fileArg) === currentDir && baseOf(fileArg).startsWith(`${tag}.`) && baseOf(fileArg) !== 'index.ts');
|
|
31
|
+
finding.fix = (builderArg) => {
|
|
32
|
+
const entry = `${folder}/${tag}.ts`;
|
|
33
|
+
const index = `${folder}/index.ts`;
|
|
34
|
+
builderArg.create(index, `export * from './${tag}.js';\n`);
|
|
35
|
+
builderArg.move(element.file, entry);
|
|
36
|
+
for (const companion of companions) {
|
|
37
|
+
builderArg.move(companion, `${folder}/${baseOf(companion)}`);
|
|
38
|
+
}
|
|
39
|
+
builderArg.redirectBarrelExports(element.file, index);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
findings.push(finding);
|
|
43
|
+
}
|
|
44
|
+
return findings;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF5b3V0LmVsZW1lbnQtZm9sZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvc3RhbmRhcmRzL3J1bGVzL2xheW91dC5lbGVtZW50LWZvbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXBELE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLFdBQVcsRUFBRSxtQkFBbUIsRUFBRSxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUVuSSxvSEFBb0g7QUFDcEgsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQWtCO0lBQ3BELEVBQUUsRUFBRSx1QkFBdUI7SUFDM0IsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRTtJQUMxQixPQUFPLEVBQUUsTUFBTTtJQUNmLE1BQU0sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRTtRQUN0QixNQUFNLFFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sUUFBUSxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxQyxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxJQUFJLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQy9DLFNBQVM7WUFDWCxDQUFDO1lBQ0QsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUN2QyxNQUFNLEtBQUssR0FBRywwQ0FBMEMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvRSxNQUFNLE1BQU0sR0FBRyxHQUFHLFdBQVcsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLENBQUMs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
|