@geonosis/oxlint-plugin-biological-architecture 3.0.0 → 3.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 +50 -0
- package/README.md +48 -5
- package/RULES.md +201 -98
- package/corpus/.oxlintrc.json +6 -0
- package/corpus/data/bad-dynamic-orm.ts +5 -0
- package/corpus/data/bad-type-only-orm.ts +3 -0
- package/corpus/e2e/bad-list-response.spec.ts +5 -0
- package/corpus/e2e/bad-timeout.spec.ts +5 -0
- package/corpus/e2e/good-detail-response.spec.ts +5 -0
- package/corpus/e2e/good-state.spec.ts +5 -0
- package/corpus/icon-controls/bad-unnamed-icon-button.tsx +8 -0
- package/corpus/icon-controls/good-named-icon-button.tsx +19 -0
- package/corpus/manifest.json +3 -0
- package/corpus/tissues/bad-awaits-data.tsx +8 -0
- package/corpus/tissues/bad-fetches-data.tsx +7 -0
- package/corpus/tissues/good-takes-products.tsx +5 -0
- package/dist/discover-atoms.d.ts +2 -37
- package/dist/discover-atoms.js +1 -104
- package/dist/index.d.ts +3 -12
- package/dist/index.js +19 -174
- package/dist/presets.d.ts +11 -19
- package/dist/presets.js +89 -3
- package/dist/registry.d.ts +2 -0
- package/dist/registry.js +172 -0
- package/dist/rules/atom-no-deps.d.ts +1 -0
- package/dist/rules/atom-no-deps.js +10 -11
- package/dist/rules/boundary-time-is-primitive.d.ts +0 -7
- package/dist/rules/cell-must-be-stateful.d.ts +2 -2
- package/dist/rules/cell-must-be-stateful.js +24 -23
- package/dist/rules/cell-must-not-compose-cell.d.ts +1 -0
- package/dist/rules/cell-must-not-compose-cell.js +10 -3
- package/dist/rules/cell-no-cross-feature-organelles.d.ts +1 -0
- package/dist/rules/cell-no-cross-feature-organelles.js +7 -0
- package/dist/rules/cell-no-tissues.d.ts +1 -0
- package/dist/rules/cell-no-tissues.js +11 -7
- package/dist/rules/cells-folder-index-is-barrel.d.ts +12 -10
- package/dist/rules/cells-folder-index-is-barrel.js +66 -34
- package/dist/rules/compound-must-be-stateless.d.ts +2 -0
- package/dist/rules/compound-must-be-stateless.js +24 -26
- package/dist/rules/compound-no-stores.d.ts +1 -0
- package/dist/rules/compound-no-stores.js +12 -10
- package/dist/rules/constants-in-constants-file.d.ts +2 -8
- package/dist/rules/constants-in-constants-file.js +5 -6
- package/dist/rules/dialect-through-the-seam.d.ts +0 -13
- package/dist/rules/durable-body-reads-through-steps.d.ts +0 -14
- package/dist/rules/durable-body-reads-through-steps.js +8 -3
- package/dist/rules/effect-hook-naming.d.ts +9 -11
- package/dist/rules/effect-hook-naming.js +33 -31
- package/dist/rules/emit-declares-attempts.d.ts +0 -17
- package/dist/rules/emit-declares-attempts.js +5 -10
- package/dist/rules/font-roles-only.d.ts +0 -18
- package/dist/rules/font-roles-only.js +19 -22
- package/dist/rules/hermetic-e2e-no-wall-clock-waits.d.ts +53 -0
- package/dist/rules/hermetic-e2e-no-wall-clock-waits.js +100 -0
- package/dist/rules/icon-control-has-name.d.ts +53 -0
- package/dist/rules/icon-control-has-name.js +71 -0
- package/dist/rules/layer-walls.d.ts +0 -25
- package/dist/rules/layer-walls.js +7 -13
- package/dist/rules/lib/atom-map.d.ts +24 -0
- package/dist/rules/lib/atom-map.js +16 -0
- package/dist/rules/lib/cells-barrel.d.ts +0 -1
- package/dist/rules/lib/colors.d.ts +0 -19
- package/dist/rules/lib/colors.js +10 -243
- package/dist/rules/lib/comments.d.ts +19 -0
- package/dist/rules/lib/comments.js +5 -0
- package/dist/rules/lib/context.d.ts +0 -10
- package/dist/rules/lib/direction-rule.d.ts +3 -21
- package/dist/rules/lib/direction-rule.js +12 -3
- package/dist/rules/lib/doors.d.ts +2 -18
- package/dist/rules/lib/doors.js +79 -41
- package/dist/rules/lib/hooks.d.ts +2 -17
- package/dist/rules/lib/hooks.js +14 -9
- package/dist/rules/lib/imports.d.ts +2 -23
- package/dist/rules/lib/imports.js +7 -2
- package/dist/rules/lib/jsx.d.ts +31 -0
- package/dist/rules/lib/jsx.js +11 -0
- package/dist/rules/lib/landing.d.ts +0 -40
- package/dist/rules/lib/literal-call.d.ts +1 -0
- package/dist/rules/lib/literal-call.js +2 -0
- package/dist/rules/lib/module-text.d.ts +3 -27
- package/dist/rules/lib/module-text.js +19 -4
- package/dist/rules/lib/mutations.d.ts +0 -14
- package/dist/rules/lib/nodes.d.ts +1 -18
- package/dist/rules/lib/nodes.js +1 -0
- package/dist/rules/lib/objects.d.ts +2 -11
- package/dist/rules/lib/objects.js +21 -0
- package/dist/rules/lib/options.d.ts +2 -52
- package/dist/rules/lib/options.js +44 -18
- package/dist/rules/lib/package-imports.d.ts +0 -5
- package/dist/rules/lib/package-imports.js +4 -10
- package/dist/rules/lib/paths.d.ts +15 -41
- package/dist/rules/lib/paths.js +34 -1
- package/dist/rules/lib/pattern-match.d.ts +2 -12
- package/dist/rules/lib/pattern-match.js +5 -1
- package/dist/rules/lib/probe.d.ts +0 -43
- package/dist/rules/lib/reexports.d.ts +0 -18
- package/dist/rules/lib/render-tracking.d.ts +0 -8
- package/dist/rules/lib/shared-features.d.ts +0 -8
- package/dist/rules/lib/shared-features.js +2 -9
- package/dist/rules/lib/state-sources.d.ts +8 -0
- package/dist/rules/lib/state-sources.js +55 -0
- package/dist/rules/lib/steps.d.ts +3 -5
- package/dist/rules/lib/steps.js +6 -1
- package/dist/rules/lib/styling.d.ts +9 -42
- package/dist/rules/lib/styling.js +36 -10
- package/dist/rules/lib/tiers.d.ts +11 -24
- package/dist/rules/lib/tiers.js +41 -1
- package/dist/rules/lib/tissue-entrypoint.d.ts +0 -1
- package/dist/rules/lib/tissue-entrypoint.js +4 -5
- package/dist/rules/lib/tsconfig-paths.d.ts +0 -4
- package/dist/rules/lib/tsconfig-paths.js +47 -15
- package/dist/rules/lib/type-members.d.ts +6 -0
- package/dist/rules/lib/type-members.js +165 -0
- package/dist/rules/lib/visitors.d.ts +0 -22
- package/dist/rules/lib/workspace-members.d.ts +2 -0
- package/dist/rules/lib/workspace-members.js +115 -0
- package/dist/rules/list-take-without-order.js +2 -8
- package/dist/rules/max-comment-density.d.ts +3 -18
- package/dist/rules/max-comment-density.js +3 -3
- package/dist/rules/molecule-atoms-only.d.ts +1 -0
- package/dist/rules/molecule-atoms-only.js +11 -7
- package/dist/rules/molecule-must-compose.d.ts +3 -1
- package/dist/rules/molecule-must-compose.js +17 -21
- package/dist/rules/mutating-step-declares-retry.d.ts +2 -7
- package/dist/rules/mutating-step-declares-retry.js +29 -11
- package/dist/rules/named-when-block.d.ts +0 -2
- package/dist/rules/named-when-block.js +2 -8
- package/dist/rules/next-route-segment-is-thin-delegate.d.ts +4 -19
- package/dist/rules/next-route-segment-is-thin-delegate.js +47 -71
- package/dist/rules/no-brand-names.d.ts +0 -9
- package/dist/rules/no-brand-names.js +1 -1
- package/dist/rules/no-card-shaped-div.d.ts +4 -42
- package/dist/rules/no-card-shaped-div.js +12 -4
- package/dist/rules/no-cross-feature-stores.d.ts +1 -0
- package/dist/rules/no-cross-feature-stores.js +9 -5
- package/dist/rules/no-d1-transaction.d.ts +2 -5
- package/dist/rules/no-d1-transaction.js +7 -0
- package/dist/rules/no-date-string-compare.d.ts +2 -0
- package/dist/rules/no-date-string-compare.js +14 -8
- package/dist/rules/no-duplicate-jsx-patterns.d.ts +2 -0
- package/dist/rules/no-duplicate-jsx-patterns.js +16 -1
- package/dist/rules/no-generic-utility-package.d.ts +48 -2
- package/dist/rules/no-generic-utility-package.js +48 -9
- package/dist/rules/no-hook-in-component-disguise.d.ts +27 -13
- package/dist/rules/no-hook-in-component-disguise.js +38 -30
- package/dist/rules/no-index-count-as-exact.d.ts +0 -3
- package/dist/rules/no-inert-hidden-jsx.d.ts +4 -21
- package/dist/rules/no-inert-hidden-jsx.js +13 -12
- package/dist/rules/no-inline-data-in-jsx.d.ts +2 -0
- package/dist/rules/no-inline-data-in-jsx.js +17 -2
- package/dist/rules/no-invalid-feature-folders.d.ts +2 -0
- package/dist/rules/no-invalid-feature-folders.js +12 -4
- package/dist/rules/no-loader-side-effect-in-index-file.d.ts +0 -7
- package/dist/rules/no-logic-in-component-files.d.ts +6 -5
- package/dist/rules/no-logic-in-component-files.js +52 -31
- package/dist/rules/no-mock-db-in-integration.d.ts +0 -15
- package/dist/rules/no-mock-db-in-integration.js +3 -4
- package/dist/rules/no-orm-outside-db.d.ts +1 -0
- package/dist/rules/no-orm-outside-db.js +9 -7
- package/dist/rules/no-raw-html-atoms.d.ts +3 -22
- package/dist/rules/no-raw-html-atoms.js +5 -17
- package/dist/rules/no-raw-sql-outside-allowed.d.ts +2 -0
- package/dist/rules/no-raw-sql-outside-allowed.js +10 -15
- package/dist/rules/no-react-namespace.d.ts +2 -0
- package/dist/rules/no-react-namespace.js +13 -0
- package/dist/rules/no-renamed-html-props.d.ts +2 -0
- package/dist/rules/no-renamed-html-props.js +11 -2
- package/dist/rules/no-render-prop-reader.d.ts +4 -20
- package/dist/rules/no-render-prop-reader.js +13 -5
- package/dist/rules/no-runtime-dead-affordance.d.ts +3 -26
- package/dist/rules/no-runtime-dead-affordance.js +7 -20
- package/dist/rules/no-swallowed-catch.js +2 -8
- package/dist/rules/no-trivial-wrapper-component.d.ts +4 -19
- package/dist/rules/no-trivial-wrapper-component.js +24 -33
- package/dist/rules/no-ts-in-bio-folders.d.ts +2 -13
- package/dist/rules/no-ts-in-bio-folders.js +9 -7
- package/dist/rules/no-type-definitions-in-components.d.ts +2 -0
- package/dist/rules/no-type-definitions-in-components.js +12 -1
- package/dist/rules/no-unregistered-plugin-dir.d.ts +0 -41
- package/dist/rules/no-unregistered-plugin-dir.js +1 -9
- package/dist/rules/no-void-port.d.ts +2 -4
- package/dist/rules/no-void-port.js +7 -0
- package/dist/rules/organelle-dependency.d.ts +1 -0
- package/dist/rules/organelle-dependency.js +10 -8
- package/dist/rules/organelle-single-source.d.ts +2 -0
- package/dist/rules/organelle-single-source.js +58 -9
- package/dist/rules/plugin-route-namespaced.d.ts +0 -11
- package/dist/rules/plugin-route-namespaced.js +2 -2
- package/dist/rules/queries-require-org-scope.d.ts +0 -3
- package/dist/rules/queries-require-org-scope.js +3 -10
- package/dist/rules/queue-loop-is-the-library.js +3 -2
- package/dist/rules/route-no-inline-mutation.d.ts +1 -25
- package/dist/rules/route-no-inline-mutation.js +2 -7
- package/dist/rules/router-schema-parity.d.ts +0 -9
- package/dist/rules/router-schema-parity.js +5 -9
- package/dist/rules/service-name-not-reserved.d.ts +0 -3
- package/dist/rules/service-name-not-reserved.js +1 -34
- package/dist/rules/ssot-no-inline-facts.js +2 -5
- package/dist/rules/ssot-no-process-env.js +4 -12
- package/dist/rules/step-declares-compensation-or-none.d.ts +2 -1
- package/dist/rules/step-declares-compensation-or-none.js +17 -1
- package/dist/rules/step-opens-its-own-cell.d.ts +2 -25
- package/dist/rules/step-opens-its-own-cell.js +8 -13
- package/dist/rules/store-route-scopes-tenant-data.js +8 -26
- package/dist/rules/subpath-over-barrel.d.ts +2 -10
- package/dist/rules/subpath-over-barrel.js +48 -9
- package/dist/rules/subscriber-declares-id.d.ts +0 -2
- package/dist/rules/subscriber-declares-id.js +2 -8
- package/dist/rules/tables-declare-their-plane.d.ts +0 -2
- package/dist/rules/tables-declare-their-plane.js +4 -10
- package/dist/rules/tenant-tables-carry-org-id.d.ts +1 -4
- package/dist/rules/tenant-tables-carry-org-id.js +5 -12
- package/dist/rules/test-no-clock-polling-for-promise-flips.d.ts +2 -0
- package/dist/rules/test-no-clock-polling-for-promise-flips.js +18 -1
- package/dist/rules/time-through-the-door.d.ts +0 -24
- package/dist/rules/time-through-the-door.js +5 -5
- package/dist/rules/tissue-must-compose.d.ts +4 -2
- package/dist/rules/tissue-must-compose.js +25 -20
- package/dist/rules/tissue-no-data-props.d.ts +56 -0
- package/dist/rules/tissue-no-data-props.js +114 -32
- package/dist/rules/tissue-no-fetch.d.ts +26 -0
- package/dist/rules/tissue-no-fetch.js +57 -0
- package/dist/rules/tissue-no-hooks.d.ts +20 -22
- package/dist/rules/tissue-no-hooks.js +22 -4
- package/dist/rules/tissue-no-organelles.d.ts +1 -0
- package/dist/rules/tissue-no-organelles.js +9 -1
- package/dist/rules/tissue-no-stores.d.ts +1 -0
- package/dist/rules/tissue-no-stores.js +9 -1
- package/dist/rules/todo-names-its-plan.d.ts +1 -28
- package/dist/rules/todo-names-its-plan.js +2 -2
- package/dist/rules/tokens-only-colors.d.ts +2 -37
- package/dist/rules/tokens-only-colors.js +33 -18
- package/dist/rules/unique-query-step-name.d.ts +0 -7
- package/dist/rules/unique-query-step-name.js +6 -10
- package/dist/rules/worker-handles-are-scoped.d.ts +11 -8
- package/dist/rules/worker-handles-are-scoped.js +12 -5
- package/dist/rules/zustand-v5-best-practices.d.ts +8 -18
- package/dist/rules/zustand-v5-best-practices.js +32 -56
- package/package.json +2 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// src/rules/hermetic-e2e-no-wall-clock-waits.ts
|
|
2
|
+
import { calleeNameOf, propertyNameOf, walkNode } from "./lib/nodes.js";
|
|
3
|
+
import { normalise } from "./lib/paths.js";
|
|
4
|
+
import { bagOf, firstOf, pathMatching } from "./lib/probe.js";
|
|
5
|
+
import { optionsBag, STRINGS } from "./lib/schema.js";
|
|
6
|
+
var SPECS = [String.raw`(?:^|/)e2e[^/]*/.*\.(?:spec|test)\.[cm]?[jt]sx?$`];
|
|
7
|
+
var CLOCK_WAITS = ["setTimeout", "waitForTimeout"];
|
|
8
|
+
var NETWORK_WAITS = ["waitForResponse"];
|
|
9
|
+
var calledName = (node) => {
|
|
10
|
+
const callee = node.callee;
|
|
11
|
+
return calleeNameOf(node) ?? (callee === undefined ? null : propertyNameOf(callee));
|
|
12
|
+
};
|
|
13
|
+
var textsIn = (nodes) => {
|
|
14
|
+
const found = [];
|
|
15
|
+
walkNode(nodes, (node) => {
|
|
16
|
+
if (node.type === "Literal") {
|
|
17
|
+
const regex = node.regex;
|
|
18
|
+
if (typeof regex?.pattern === "string")
|
|
19
|
+
found.push(regex.pattern);
|
|
20
|
+
else if (typeof node.value === "string")
|
|
21
|
+
found.push(node.value);
|
|
22
|
+
}
|
|
23
|
+
if (node.type === "TemplateLiteral") {
|
|
24
|
+
for (const quasi of node.quasis ?? []) {
|
|
25
|
+
found.push(quasi.value?.raw ?? "");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return found;
|
|
30
|
+
};
|
|
31
|
+
var hermeticE2eNoWallClockWaits = {
|
|
32
|
+
create(context) {
|
|
33
|
+
const options = bagOf(context.options);
|
|
34
|
+
const specs = options.specs ?? SPECS;
|
|
35
|
+
if (!specs.some((pattern) => new RegExp(pattern).test(normalise(context.filename))))
|
|
36
|
+
return {};
|
|
37
|
+
const clockWaits = new Set(options.clockWaits ?? CLOCK_WAITS);
|
|
38
|
+
const networkWaits = new Set(options.networkWaits ?? NETWORK_WAITS);
|
|
39
|
+
const endpoints = (options.listEndpoints ?? []).map((pattern) => new RegExp(pattern));
|
|
40
|
+
return {
|
|
41
|
+
CallExpression(node) {
|
|
42
|
+
const call = calledName(node);
|
|
43
|
+
if (call === null)
|
|
44
|
+
return;
|
|
45
|
+
if (clockWaits.has(call)) {
|
|
46
|
+
context.report({ data: { call }, messageId: "clockWait", node });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!networkWaits.has(call) || endpoints.length === 0)
|
|
50
|
+
return;
|
|
51
|
+
const endpoint = textsIn(node.arguments).find((text) => endpoints.some((pattern) => pattern.test(text)));
|
|
52
|
+
if (endpoint !== undefined) {
|
|
53
|
+
context.report({ data: { call, endpoint }, messageId: "listResponseWait", node });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
fixShape: `An end-to-end spec waits for the state it asserts on, never for a time and never for the network
|
|
59
|
+
event that merely precedes it. \`page.waitForTimeout(500)\` or a promise sleep guesses how long the
|
|
60
|
+
page needs; the guess passes on a fast machine and flakes on a slow one. \`waitForResponse\` on a LIST
|
|
61
|
+
endpoint is the same guess with a better alibi: the response arriving says the request finished, not
|
|
62
|
+
that the page merged the rows into what the user sees. Assert on the page instead — a web-first
|
|
63
|
+
assertion on the element the data produces retries until it holds: \`await
|
|
64
|
+
expect(page.getByRole('row', { name })).toBeVisible()\`. The specs are the files \`specs\` names
|
|
65
|
+
(default: spec files under an \`e2e*\` directory), the calls that sleep are \`clockWaits\` (default
|
|
66
|
+
\`waitForTimeout\`, \`setTimeout\`), and the list endpoints whose response may not stand in for the
|
|
67
|
+
page are the regexes in \`listEndpoints\`, with \`networkWaits\` naming the calls that wait on one
|
|
68
|
+
(default \`waitForResponse\`); with no \`listEndpoints\` the response waits are not judged.`,
|
|
69
|
+
meta: {
|
|
70
|
+
docs: {
|
|
71
|
+
description: 'In an end-to-end spec, a fixed-time wait (`waitForTimeout`, a `setTimeout` sleep) guesses how long the page needs, and a `waitForResponse` on a list endpoint stands in for "the live data was merged" when only the page can say so. Assert on the page state instead. The spec files, the sleeping calls, the waiting calls and the list endpoints are options; the response wait is judged only for endpoints the repo names.'
|
|
72
|
+
},
|
|
73
|
+
messages: {
|
|
74
|
+
clockWait: "`{{call}}` waits for a time, not for a state: it passes when the machine is fast and flakes when it is slow. Wait for the state the next step needs — a web-first assertion on the element it produces retries until it holds.",
|
|
75
|
+
listResponseWait: "`{{call}}` on a list endpoint ({{endpoint}}) treats the response arriving as the data being shown, and the page merges it later: a race. Assert on what the page renders — a web-first assertion on the element the data produces retries until it holds."
|
|
76
|
+
},
|
|
77
|
+
schema: optionsBag({
|
|
78
|
+
clockWaits: STRINGS,
|
|
79
|
+
listEndpoints: STRINGS,
|
|
80
|
+
networkWaits: STRINGS,
|
|
81
|
+
specs: STRINGS
|
|
82
|
+
}),
|
|
83
|
+
type: "problem"
|
|
84
|
+
},
|
|
85
|
+
probe(options) {
|
|
86
|
+
const bag = bagOf(options);
|
|
87
|
+
const call = firstOf(bag.clockWaits, ["waitForTimeout"]);
|
|
88
|
+
return {
|
|
89
|
+
path: pathMatching(firstOf(bag.specs, SPECS), "geonosis-probe.spec.ts"),
|
|
90
|
+
source: `export const geonosisProbe = async (page) => {
|
|
91
|
+
await page.${call}(500)
|
|
92
|
+
}
|
|
93
|
+
`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
var hermetic_e2e_no_wall_clock_waits_default = hermeticE2eNoWallClockWaits;
|
|
98
|
+
export {
|
|
99
|
+
hermetic_e2e_no_wall_clock_waits_default as default
|
|
100
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { RuleContextWithRawOptions } from './lib/context.js';
|
|
2
|
+
import { type Probe } from './lib/probe.js';
|
|
3
|
+
type Name = {
|
|
4
|
+
name?: string;
|
|
5
|
+
object?: Name;
|
|
6
|
+
property?: Name;
|
|
7
|
+
type: string;
|
|
8
|
+
};
|
|
9
|
+
type Attribute = {
|
|
10
|
+
name?: Name;
|
|
11
|
+
type: string;
|
|
12
|
+
};
|
|
13
|
+
type Child = {
|
|
14
|
+
children?: Child[];
|
|
15
|
+
openingElement?: {
|
|
16
|
+
attributes?: Attribute[];
|
|
17
|
+
name: Name;
|
|
18
|
+
};
|
|
19
|
+
type: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
};
|
|
22
|
+
declare const iconControlHasName: {
|
|
23
|
+
create(context: RuleContextWithRawOptions): {
|
|
24
|
+
JSXElement(node: Child): void;
|
|
25
|
+
};
|
|
26
|
+
fixShape: string;
|
|
27
|
+
meta: {
|
|
28
|
+
docs: {
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
messages: {
|
|
32
|
+
unnamed: string;
|
|
33
|
+
};
|
|
34
|
+
schema: {
|
|
35
|
+
additionalProperties: boolean;
|
|
36
|
+
properties: {
|
|
37
|
+
controls: {
|
|
38
|
+
items: {
|
|
39
|
+
type: 'string';
|
|
40
|
+
};
|
|
41
|
+
type: 'array';
|
|
42
|
+
};
|
|
43
|
+
icons: {
|
|
44
|
+
type: 'string';
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
type: 'object';
|
|
48
|
+
}[];
|
|
49
|
+
type: 'problem';
|
|
50
|
+
};
|
|
51
|
+
probe(options: readonly unknown[]): Probe;
|
|
52
|
+
};
|
|
53
|
+
export default iconControlHasName;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/rules/icon-control-has-name.ts
|
|
2
|
+
import { bagOf, firstOf } from "./lib/probe.js";
|
|
3
|
+
import { optionsBag, STRING, STRINGS } from "./lib/schema.js";
|
|
4
|
+
var NATIVE_CONTROLS = ["button", "a"];
|
|
5
|
+
var ICONS = "Icon$";
|
|
6
|
+
var NAMED_BY = new Set(["aria-label", "aria-labelledby", "title"]);
|
|
7
|
+
var ICON_NAMED_BY = new Set(["aria-label", "aria-labelledby"]);
|
|
8
|
+
var nameOf = (node) => node === undefined ? "" : node.type === "JSXMemberExpression" ? `${nameOf(node.object)}.${nameOf(node.property)}` : node.name ?? "";
|
|
9
|
+
var said = (child) => child.type !== "JSXText" || (child.value ?? "").trim() !== "";
|
|
10
|
+
var namesItself = (icon) => icon.type === "JSXElement" && ((icon.openingElement?.attributes ?? []).some((one) => one.type === "JSXAttribute" && ICON_NAMED_BY.has(nameOf(one.name))) || nameOf(icon.openingElement?.name) === "svg" && (icon.children ?? []).some((one) => nameOf(one.openingElement?.name) === "title"));
|
|
11
|
+
var iconControlHasName = {
|
|
12
|
+
create(context) {
|
|
13
|
+
const options = bagOf(context.options);
|
|
14
|
+
const controls = new Set([...NATIVE_CONTROLS, ...options.controls ?? []]);
|
|
15
|
+
const icon = new RegExp(options.icons ?? ICONS);
|
|
16
|
+
return {
|
|
17
|
+
JSXElement(node) {
|
|
18
|
+
const control = nameOf(node.openingElement?.name);
|
|
19
|
+
if (!controls.has(control))
|
|
20
|
+
return;
|
|
21
|
+
const attributes = node.openingElement?.attributes ?? [];
|
|
22
|
+
if (attributes.some((one) => one.type !== "JSXAttribute" || NAMED_BY.has(nameOf(one.name)))) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const shown = (node.children ?? []).filter(said);
|
|
26
|
+
if (shown.some(namesItself))
|
|
27
|
+
return;
|
|
28
|
+
const icons = shown.map((one) => one.type === "JSXElement" ? nameOf(one.openingElement?.name) : "");
|
|
29
|
+
if (icons.length === 0 || !icons.every((name) => name === "svg" || icon.test(name)))
|
|
30
|
+
return;
|
|
31
|
+
context.report({
|
|
32
|
+
data: { control, icons: icons.join(", ") },
|
|
33
|
+
messageId: "unnamed",
|
|
34
|
+
node
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
fixShape: `A control whose only content is an icon has no name: the icon is decorative, so a screen reader
|
|
40
|
+
announces "button" and nothing else. Give it \`aria-label\` (or \`aria-labelledby\`, or \`title\`) in the
|
|
41
|
+
app's own words — a label prop the caller passes, never a string the component invents — or put text
|
|
42
|
+
beside the icon, visible or \`sr-only\`. \`<button>\` and \`<a>\` are read by default; \`controls\` names the
|
|
43
|
+
repo's control atoms, and \`icons\` is the pattern an icon component's name matches (\`Icon$\` by default);
|
|
44
|
+
an inline \`<svg>\` is always one.
|
|
45
|
+
An icon that carries its own \`aria-label\` or \`aria-labelledby\` (an icon component must forward it to its
|
|
46
|
+
svg), or an \`<svg>\` holding a \`<title>\`, names the control; a \`title\` attribute on an icon does not. A
|
|
47
|
+
spread may carry the name and is left alone.`,
|
|
48
|
+
meta: {
|
|
49
|
+
docs: {
|
|
50
|
+
description: "A button or link whose only content is an icon component, with no `aria-label`, `aria-labelledby` or `title`, has no accessible name — a screen reader announces a control that says nothing."
|
|
51
|
+
},
|
|
52
|
+
messages: {
|
|
53
|
+
unnamed: "<{{control}}> shows only {{icons}} and has no name a screen reader can read. Give it aria-label in the words the app passes in, or text beside the icon."
|
|
54
|
+
},
|
|
55
|
+
schema: optionsBag({ controls: STRINGS, icons: STRING }),
|
|
56
|
+
type: "problem"
|
|
57
|
+
},
|
|
58
|
+
probe(options) {
|
|
59
|
+
const bag = bagOf(options);
|
|
60
|
+
const control = firstOf(bag.controls, NATIVE_CONTROLS);
|
|
61
|
+
return {
|
|
62
|
+
path: "molecules/geonosis-probe.tsx",
|
|
63
|
+
source: `export const Probe = () => <${control}><svg /></${control}>
|
|
64
|
+
`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var icon_control_has_name_default = iconControlHasName;
|
|
69
|
+
export {
|
|
70
|
+
icon_control_has_name_default as default
|
|
71
|
+
};
|
|
@@ -1,30 +1,14 @@
|
|
|
1
1
|
import { type RuleContextWithOptions } from './lib/context.js';
|
|
2
2
|
import { type Probe } from './lib/probe.js';
|
|
3
3
|
interface Layer {
|
|
4
|
-
/** Layer names this one may import. A layer may always import itself; this lists the others. */
|
|
5
4
|
mayImport?: string[];
|
|
6
5
|
name: string;
|
|
7
|
-
/** Regex sources, tested against the normalised filename and against an import's source. */
|
|
8
6
|
paths: string[];
|
|
9
|
-
/** This layer's own answer to the rule-wide `typeOnly`, for the reason written there. */
|
|
10
7
|
typeOnly?: 'count' | 'skip';
|
|
11
8
|
}
|
|
12
9
|
interface Options {
|
|
13
|
-
/**
|
|
14
|
-
* Whether a bare package specifier or a `node:` builtin counts as crossing a wall. It does not by
|
|
15
|
-
* default: a layer that may import no other layer still runs on a machine with a filesystem, and
|
|
16
|
-
* a rule that called `node:path` a breach would be unusable in every repo that has one.
|
|
17
|
-
*/
|
|
18
10
|
externals?: 'allow' | 'deny';
|
|
19
11
|
layers?: Layer[];
|
|
20
|
-
/**
|
|
21
|
-
* D-034's named exception, and the default every layer keeps unless it says otherwise. A type the
|
|
22
|
-
* bundler erases is not a dependency, and three packages in this repo borrow one across a wall on
|
|
23
|
-
* purpose so their runtime graph stays clean. `count` is for walls that are about KNOWLEDGE
|
|
24
|
-
* rather than weight — a package floor, where `import type { Document }` in a foundation is the
|
|
25
|
-
* upward reach the floors exist to forbid, compiled away or not. One repo has both kinds, so a
|
|
26
|
-
* layer may override this for its own files.
|
|
27
|
-
*/
|
|
28
12
|
typeOnly?: 'count' | 'skip';
|
|
29
13
|
}
|
|
30
14
|
declare const layerWalls: {
|
|
@@ -83,15 +67,6 @@ declare const layerWalls: {
|
|
|
83
67
|
}[];
|
|
84
68
|
type: 'problem';
|
|
85
69
|
};
|
|
86
|
-
/**
|
|
87
|
-
* A file in one declared layer importing a specifier that lands in another it may not reach.
|
|
88
|
-
*
|
|
89
|
-
* Both halves come out of the same regex sources the walls are written in — the filename from the
|
|
90
|
-
* layer it must sit in, the import from the layer it must not reach — and both are re-tested
|
|
91
|
-
* against the patterns they were built from. A pair the inversion cannot express is a sentence
|
|
92
|
-
* rather than a silent zero: the walls are a repo's own vocabulary, so there is no fixture
|
|
93
|
-
* anywhere that could stand in for them.
|
|
94
|
-
*/
|
|
95
70
|
probe(options: readonly unknown[]): Probe;
|
|
96
71
|
};
|
|
97
72
|
export default layerWalls;
|
|
@@ -8,25 +8,19 @@ import { onImportSource } from "./lib/visitors.js";
|
|
|
8
8
|
var isExternal = (source) => !isRelative(source) && !source.startsWith("/");
|
|
9
9
|
var PROBE_TARGET = "geonosis-probe-target.ts";
|
|
10
10
|
var PROBE_WALL = "geonosis-probe-wall.ts";
|
|
11
|
-
var
|
|
11
|
+
var invert = (pattern, leaf) => {
|
|
12
12
|
try {
|
|
13
|
-
pathMatching(pattern, leaf);
|
|
14
|
-
return true;
|
|
13
|
+
return pathMatching(pattern, leaf);
|
|
15
14
|
} catch {
|
|
16
|
-
return
|
|
15
|
+
return;
|
|
17
16
|
}
|
|
18
17
|
};
|
|
19
18
|
var placeIn = (paths, tried) => {
|
|
20
19
|
for (const pattern of paths) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
candidate = pathMatching(pattern, PROBE_WALL);
|
|
24
|
-
} catch {
|
|
25
|
-
tried.push(pattern);
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (new RegExp(pattern).test(`/repo-root/${candidate}`))
|
|
20
|
+
const candidate = invert(pattern, PROBE_WALL);
|
|
21
|
+
if (candidate !== undefined && new RegExp(pattern).test(`/repo-root/${candidate}`)) {
|
|
29
22
|
return candidate;
|
|
23
|
+
}
|
|
30
24
|
tried.push(pattern);
|
|
31
25
|
}
|
|
32
26
|
return;
|
|
@@ -113,7 +107,7 @@ rule reports that once a run and judges nothing: walls nobody declared are not w
|
|
|
113
107
|
const tried = [];
|
|
114
108
|
for (const here of layers) {
|
|
115
109
|
const mayImport = new Set(here.mayImport ?? []);
|
|
116
|
-
const targetPath = layers.filter((other) => other.name !== here.name && !mayImport.has(other.name)).flatMap((other) => other.paths).find((one) =>
|
|
110
|
+
const targetPath = layers.filter((other) => other.name !== here.name && !mayImport.has(other.name)).flatMap((other) => other.paths).find((one) => invert(one, PROBE_TARGET) !== undefined);
|
|
117
111
|
const path = placeIn(here.paths, tried);
|
|
118
112
|
if (targetPath === undefined || path === undefined)
|
|
119
113
|
continue;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface Restriction {
|
|
2
|
+
atom: string;
|
|
3
|
+
element: string;
|
|
4
|
+
importPath: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const ATOM_MAP_SCHEMA: {
|
|
7
|
+
items: {
|
|
8
|
+
properties: {
|
|
9
|
+
atom: {
|
|
10
|
+
type: 'string';
|
|
11
|
+
};
|
|
12
|
+
element: {
|
|
13
|
+
type: 'string';
|
|
14
|
+
};
|
|
15
|
+
importPath: {
|
|
16
|
+
type: 'string';
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
required: string[];
|
|
20
|
+
type: 'object';
|
|
21
|
+
};
|
|
22
|
+
type: 'array';
|
|
23
|
+
};
|
|
24
|
+
export declare const atomMapOf: (options: readonly unknown[]) => Restriction[];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/rules/lib/atom-map.ts
|
|
2
|
+
import { STRING } from "./schema.js";
|
|
3
|
+
var ATOM_MAP_SCHEMA = {
|
|
4
|
+
items: {
|
|
5
|
+
properties: { atom: STRING, element: STRING, importPath: STRING },
|
|
6
|
+
required: ["element", "atom", "importPath"],
|
|
7
|
+
type: "object"
|
|
8
|
+
},
|
|
9
|
+
type: "array"
|
|
10
|
+
};
|
|
11
|
+
var isRestriction = (value) => typeof value === "object" && value !== null && ("atom" in value) && typeof value.atom === "string" && ("element" in value) && typeof value.element === "string" && ("importPath" in value) && typeof value.importPath === "string";
|
|
12
|
+
var atomMapOf = (options) => Array.isArray(options[0]) ? options[0].filter(isRestriction) : [];
|
|
13
|
+
export {
|
|
14
|
+
ATOM_MAP_SCHEMA,
|
|
15
|
+
atomMapOf
|
|
16
|
+
};
|
|
@@ -1,23 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What counts as a colour written out.
|
|
3
|
-
*
|
|
4
|
-
* A CSS fact, not a repo fact, so it lives in code rather than in an option (law 6 is about a
|
|
5
|
-
* repo's brands, features and tables — the notations CSS accepts for a colour are the same
|
|
6
|
-
* everywhere). Every one of them is here because a brand escapes through all of them equally: the
|
|
7
|
-
* component that hardcodes `oklch(0.91 0.17 102)` stops following the theme exactly as completely
|
|
8
|
-
* as the one that hardcodes `#ffe849`.
|
|
9
|
-
*/
|
|
10
|
-
/** A whole value that is one written-out colour: `#ff0000`, `rgb(1 2 3)`, `tan`. */
|
|
11
1
|
export declare const isColorLiteral: (value: string) => boolean;
|
|
12
|
-
/**
|
|
13
|
-
* A colour written out ANYWHERE inside a value — for the shorthands.
|
|
14
|
-
*
|
|
15
|
-
* `border: '1px solid #ff0000'` and `boxShadow: '0 1px 2px rgba(0,0,0,.2)'` hardcode a colour just
|
|
16
|
-
* as thoroughly as `color` does, and a check that only looked at whole values would pass both.
|
|
17
|
-
* Named colours are deliberately NOT searched for here: `1px solid tan` is real and so is a
|
|
18
|
-
* `transition` naming a property, and a substring search over 148 English words inside a free-form
|
|
19
|
-
* value is how a rule earns its reputation for false positives.
|
|
20
|
-
*/
|
|
21
2
|
export declare const containsColorLiteral: (value: string) => boolean;
|
|
22
3
|
export declare const isColorProperty: (property: string) => boolean;
|
|
23
4
|
export declare const isColorShorthand: (property: string) => boolean;
|
package/dist/rules/lib/colors.js
CHANGED
|
@@ -1,257 +1,24 @@
|
|
|
1
1
|
// src/rules/lib/colors.ts
|
|
2
|
-
var
|
|
3
|
-
"color",
|
|
4
|
-
"color-mix",
|
|
5
|
-
"hsl",
|
|
6
|
-
"hsla",
|
|
7
|
-
"hwb",
|
|
8
|
-
"lab",
|
|
9
|
-
"lch",
|
|
10
|
-
"oklab",
|
|
11
|
-
"oklch",
|
|
12
|
-
"rgb",
|
|
13
|
-
"rgba"
|
|
14
|
-
];
|
|
2
|
+
var words = (list) => new Set(list.split(" "));
|
|
15
3
|
var HEX = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
16
|
-
var
|
|
4
|
+
var FUNCTION_NAMES = "color|color-mix|hsl|hsla|hwb|lab|lch|oklab|oklch|rgb|rgba";
|
|
5
|
+
var FUNCTION_CALL = new RegExp(`\\b(?:${FUNCTION_NAMES})\\(`, "i");
|
|
6
|
+
var FUNCTION_START = new RegExp(`^(?:${FUNCTION_NAMES})\\(`, "i");
|
|
17
7
|
var HEX_ANYWHERE = /(?:^|[\s(,])#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})\b/i;
|
|
18
|
-
var NAMED =
|
|
19
|
-
"aliceblue",
|
|
20
|
-
"antiquewhite",
|
|
21
|
-
"aqua",
|
|
22
|
-
"aquamarine",
|
|
23
|
-
"azure",
|
|
24
|
-
"beige",
|
|
25
|
-
"bisque",
|
|
26
|
-
"black",
|
|
27
|
-
"blanchedalmond",
|
|
28
|
-
"blue",
|
|
29
|
-
"blueviolet",
|
|
30
|
-
"brown",
|
|
31
|
-
"burlywood",
|
|
32
|
-
"cadetblue",
|
|
33
|
-
"chartreuse",
|
|
34
|
-
"chocolate",
|
|
35
|
-
"coral",
|
|
36
|
-
"cornflowerblue",
|
|
37
|
-
"cornsilk",
|
|
38
|
-
"crimson",
|
|
39
|
-
"cyan",
|
|
40
|
-
"darkblue",
|
|
41
|
-
"darkcyan",
|
|
42
|
-
"darkgoldenrod",
|
|
43
|
-
"darkgray",
|
|
44
|
-
"darkgreen",
|
|
45
|
-
"darkgrey",
|
|
46
|
-
"darkkhaki",
|
|
47
|
-
"darkmagenta",
|
|
48
|
-
"darkolivegreen",
|
|
49
|
-
"darkorange",
|
|
50
|
-
"darkorchid",
|
|
51
|
-
"darkred",
|
|
52
|
-
"darksalmon",
|
|
53
|
-
"darkseagreen",
|
|
54
|
-
"darkslateblue",
|
|
55
|
-
"darkslategray",
|
|
56
|
-
"darkslategrey",
|
|
57
|
-
"darkturquoise",
|
|
58
|
-
"darkviolet",
|
|
59
|
-
"deeppink",
|
|
60
|
-
"deepskyblue",
|
|
61
|
-
"dimgray",
|
|
62
|
-
"dimgrey",
|
|
63
|
-
"dodgerblue",
|
|
64
|
-
"firebrick",
|
|
65
|
-
"floralwhite",
|
|
66
|
-
"forestgreen",
|
|
67
|
-
"fuchsia",
|
|
68
|
-
"gainsboro",
|
|
69
|
-
"ghostwhite",
|
|
70
|
-
"gold",
|
|
71
|
-
"goldenrod",
|
|
72
|
-
"gray",
|
|
73
|
-
"green",
|
|
74
|
-
"greenyellow",
|
|
75
|
-
"grey",
|
|
76
|
-
"honeydew",
|
|
77
|
-
"hotpink",
|
|
78
|
-
"indianred",
|
|
79
|
-
"indigo",
|
|
80
|
-
"ivory",
|
|
81
|
-
"khaki",
|
|
82
|
-
"lavender",
|
|
83
|
-
"lavenderblush",
|
|
84
|
-
"lawngreen",
|
|
85
|
-
"lemonchiffon",
|
|
86
|
-
"lightblue",
|
|
87
|
-
"lightcoral",
|
|
88
|
-
"lightcyan",
|
|
89
|
-
"lightgoldenrodyellow",
|
|
90
|
-
"lightgray",
|
|
91
|
-
"lightgreen",
|
|
92
|
-
"lightgrey",
|
|
93
|
-
"lightpink",
|
|
94
|
-
"lightsalmon",
|
|
95
|
-
"lightseagreen",
|
|
96
|
-
"lightskyblue",
|
|
97
|
-
"lightslategray",
|
|
98
|
-
"lightslategrey",
|
|
99
|
-
"lightsteelblue",
|
|
100
|
-
"lightyellow",
|
|
101
|
-
"lime",
|
|
102
|
-
"limegreen",
|
|
103
|
-
"linen",
|
|
104
|
-
"magenta",
|
|
105
|
-
"maroon",
|
|
106
|
-
"mediumaquamarine",
|
|
107
|
-
"mediumblue",
|
|
108
|
-
"mediumorchid",
|
|
109
|
-
"mediumpurple",
|
|
110
|
-
"mediumseagreen",
|
|
111
|
-
"mediumslateblue",
|
|
112
|
-
"mediumspringgreen",
|
|
113
|
-
"mediumturquoise",
|
|
114
|
-
"mediumvioletred",
|
|
115
|
-
"midnightblue",
|
|
116
|
-
"mintcream",
|
|
117
|
-
"mistyrose",
|
|
118
|
-
"moccasin",
|
|
119
|
-
"navajowhite",
|
|
120
|
-
"navy",
|
|
121
|
-
"oldlace",
|
|
122
|
-
"olive",
|
|
123
|
-
"olivedrab",
|
|
124
|
-
"orange",
|
|
125
|
-
"orangered",
|
|
126
|
-
"orchid",
|
|
127
|
-
"palegoldenrod",
|
|
128
|
-
"palegreen",
|
|
129
|
-
"paleturquoise",
|
|
130
|
-
"palevioletred",
|
|
131
|
-
"papayawhip",
|
|
132
|
-
"peachpuff",
|
|
133
|
-
"peru",
|
|
134
|
-
"pink",
|
|
135
|
-
"plum",
|
|
136
|
-
"powderblue",
|
|
137
|
-
"purple",
|
|
138
|
-
"rebeccapurple",
|
|
139
|
-
"red",
|
|
140
|
-
"rosybrown",
|
|
141
|
-
"royalblue",
|
|
142
|
-
"saddlebrown",
|
|
143
|
-
"salmon",
|
|
144
|
-
"sandybrown",
|
|
145
|
-
"seagreen",
|
|
146
|
-
"seashell",
|
|
147
|
-
"sienna",
|
|
148
|
-
"silver",
|
|
149
|
-
"skyblue",
|
|
150
|
-
"slateblue",
|
|
151
|
-
"slategray",
|
|
152
|
-
"slategrey",
|
|
153
|
-
"snow",
|
|
154
|
-
"springgreen",
|
|
155
|
-
"steelblue",
|
|
156
|
-
"tan",
|
|
157
|
-
"teal",
|
|
158
|
-
"thistle",
|
|
159
|
-
"tomato",
|
|
160
|
-
"turquoise",
|
|
161
|
-
"violet",
|
|
162
|
-
"wheat",
|
|
163
|
-
"white",
|
|
164
|
-
"whitesmoke",
|
|
165
|
-
"yellow",
|
|
166
|
-
"yellowgreen"
|
|
167
|
-
]);
|
|
8
|
+
var NAMED = words("aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen");
|
|
168
9
|
var isColorLiteral = (value) => {
|
|
169
10
|
const trimmed = value.trim();
|
|
170
11
|
if (trimmed === "")
|
|
171
12
|
return false;
|
|
172
|
-
|
|
173
|
-
return true;
|
|
174
|
-
if (NAMED.has(trimmed.toLowerCase()))
|
|
175
|
-
return true;
|
|
176
|
-
return new RegExp(`^(?:${FUNCTIONS.join("|")})\\(`, "i").test(trimmed);
|
|
13
|
+
return HEX.test(trimmed) || NAMED.has(trimmed.toLowerCase()) || FUNCTION_START.test(trimmed);
|
|
177
14
|
};
|
|
178
15
|
var containsColorLiteral = (value) => HEX_ANYWHERE.test(value) || FUNCTION_CALL.test(value);
|
|
179
|
-
var COLOR_PROPERTIES =
|
|
180
|
-
|
|
181
|
-
"backgroundColor",
|
|
182
|
-
"borderBlockColor",
|
|
183
|
-
"borderBlockEndColor",
|
|
184
|
-
"borderBlockStartColor",
|
|
185
|
-
"borderBottomColor",
|
|
186
|
-
"borderColor",
|
|
187
|
-
"borderInlineColor",
|
|
188
|
-
"borderInlineEndColor",
|
|
189
|
-
"borderInlineStartColor",
|
|
190
|
-
"borderLeftColor",
|
|
191
|
-
"borderRightColor",
|
|
192
|
-
"borderTopColor",
|
|
193
|
-
"caretColor",
|
|
194
|
-
"color",
|
|
195
|
-
"columnRuleColor",
|
|
196
|
-
"fill",
|
|
197
|
-
"floodColor",
|
|
198
|
-
"lightingColor",
|
|
199
|
-
"outlineColor",
|
|
200
|
-
"stopColor",
|
|
201
|
-
"stroke",
|
|
202
|
-
"textDecorationColor",
|
|
203
|
-
"textEmphasisColor",
|
|
204
|
-
"WebkitTextFillColor",
|
|
205
|
-
"WebkitTextStrokeColor",
|
|
206
|
-
"webkitTextFillColor",
|
|
207
|
-
"webkitTextStrokeColor"
|
|
208
|
-
]);
|
|
209
|
-
var COLOR_SHORTHANDS = new Set([
|
|
210
|
-
"background",
|
|
211
|
-
"border",
|
|
212
|
-
"borderBottom",
|
|
213
|
-
"borderLeft",
|
|
214
|
-
"borderRight",
|
|
215
|
-
"borderTop",
|
|
216
|
-
"boxShadow",
|
|
217
|
-
"columnRule",
|
|
218
|
-
"filter",
|
|
219
|
-
"outline",
|
|
220
|
-
"textDecoration",
|
|
221
|
-
"textShadow"
|
|
222
|
-
]);
|
|
16
|
+
var COLOR_PROPERTIES = words("accentColor backgroundColor borderBlockColor borderBlockEndColor borderBlockStartColor borderBottomColor borderColor borderInlineColor borderInlineEndColor borderInlineStartColor borderLeftColor borderRightColor borderTopColor caretColor color columnRuleColor fill floodColor lightingColor outlineColor stopColor stroke textDecorationColor textEmphasisColor WebkitTextFillColor WebkitTextStrokeColor webkitTextFillColor webkitTextStrokeColor");
|
|
17
|
+
var COLOR_SHORTHANDS = words("background border borderBottom borderLeft borderRight borderTop boxShadow columnRule filter outline textDecoration textShadow");
|
|
223
18
|
var isColorProperty = (property) => COLOR_PROPERTIES.has(property);
|
|
224
19
|
var isColorShorthand = (property) => COLOR_SHORTHANDS.has(property);
|
|
225
|
-
var COLOR_UTILITIES =
|
|
226
|
-
|
|
227
|
-
"bg",
|
|
228
|
-
"border",
|
|
229
|
-
"border-b",
|
|
230
|
-
"border-e",
|
|
231
|
-
"border-l",
|
|
232
|
-
"border-r",
|
|
233
|
-
"border-s",
|
|
234
|
-
"border-t",
|
|
235
|
-
"border-x",
|
|
236
|
-
"border-y",
|
|
237
|
-
"caret",
|
|
238
|
-
"decoration",
|
|
239
|
-
"divide",
|
|
240
|
-
"fill",
|
|
241
|
-
"from",
|
|
242
|
-
"inset-ring",
|
|
243
|
-
"inset-shadow",
|
|
244
|
-
"outline",
|
|
245
|
-
"placeholder",
|
|
246
|
-
"ring",
|
|
247
|
-
"ring-offset",
|
|
248
|
-
"shadow",
|
|
249
|
-
"stroke",
|
|
250
|
-
"text",
|
|
251
|
-
"to",
|
|
252
|
-
"via"
|
|
253
|
-
]);
|
|
254
|
-
var isColorUtility = (utility) => COLOR_UTILITIES.has(utility.replace(/^.*:/, ""));
|
|
20
|
+
var COLOR_UTILITIES = words("accent bg border border-b border-e border-l border-r border-s border-t border-x border-y caret decoration divide fill from inset-ring inset-shadow outline placeholder ring ring-offset shadow stroke text to via");
|
|
21
|
+
var isColorUtility = (utility) => COLOR_UTILITIES.has(utility);
|
|
255
22
|
export {
|
|
256
23
|
containsColorLiteral,
|
|
257
24
|
isColorLiteral,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type Comment = {
|
|
2
|
+
loc: {
|
|
3
|
+
end: {
|
|
4
|
+
line: number;
|
|
5
|
+
};
|
|
6
|
+
start: {
|
|
7
|
+
line: number;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
type: string;
|
|
11
|
+
value: string;
|
|
12
|
+
};
|
|
13
|
+
export type SourceCode = {
|
|
14
|
+
ast?: {
|
|
15
|
+
comments?: Comment[];
|
|
16
|
+
};
|
|
17
|
+
getAllComments?: () => Comment[];
|
|
18
|
+
};
|
|
19
|
+
export declare const commentsOf: (sourceCode: SourceCode | undefined) => Comment[];
|