@duro-app/eslint-plugin 1.0.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/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/index.d.ts +19 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +11 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/no-deprecated-table-parts.d.ts +17 -0
- package/dist/rules/no-deprecated-table-parts.d.ts.map +1 -0
- package/dist/rules/no-deprecated-table-parts.js +92 -0
- package/dist/rules/no-deprecated-table-parts.js.map +1 -0
- package/dist/rules/no-raw-design-values.d.ts +20 -0
- package/dist/rules/no-raw-design-values.d.ts.map +1 -0
- package/dist/rules/no-raw-design-values.js +178 -0
- package/dist/rules/no-raw-design-values.js.map +1 -0
- package/dist/rules/no-raw-html-element.d.ts +23 -0
- package/dist/rules/no-raw-html-element.d.ts.map +1 -0
- package/dist/rules/no-raw-html-element.js +108 -0
- package/dist/rules/no-raw-html-element.js.map +1 -0
- package/dist/rules/no-tokens-barrel-import.d.ts +17 -0
- package/dist/rules/no-tokens-barrel-import.d.ts.map +1 -0
- package/dist/rules/no-tokens-barrel-import.js +0 -0
- package/dist/rules/no-tokens-barrel-import.js.map +1 -0
- package/dist/util/imports.d.ts +20 -0
- package/dist/util/imports.d.ts.map +1 -0
- package/dist/util/imports.js +74 -0
- package/dist/util/imports.js.map +1 -0
- package/dist/util/jsx.d.ts +14 -0
- package/dist/util/jsx.d.ts.map +1 -0
- package/dist/util/jsx.js +121 -0
- package/dist/util/jsx.js.map +1 -0
- package/dist/util/tokens.d.ts +20 -0
- package/dist/util/tokens.d.ts.map +1 -0
- package/dist/util/tokens.js +177 -0
- package/dist/util/tokens.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Frederic Rousseau
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @duro-app/eslint-plugin
|
|
2
|
+
|
|
3
|
+
ESLint rules that enforce the Duro design system conventions mechanically —
|
|
4
|
+
what CLAUDE.md can only suggest, these rules gate.
|
|
5
|
+
|
|
6
|
+
Requires ESLint 9 (flat config). The plugin has zero runtime dependencies.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
// eslint.config.js
|
|
12
|
+
import duro from '@duro-app/eslint-plugin'
|
|
13
|
+
import tseslint from 'typescript-eslint'
|
|
14
|
+
|
|
15
|
+
export default [
|
|
16
|
+
...tseslint.configs.recommended,
|
|
17
|
+
duro.configs.recommended,
|
|
18
|
+
{
|
|
19
|
+
rules: {
|
|
20
|
+
// Example: a data grid the design system doesn't cover yet.
|
|
21
|
+
'duro/no-raw-html-element': ['error', {allow: ['table', 'thead', 'tbody', 'tr', 'th', 'td']}],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The `recommended` preset registers the plugin under the `duro` namespace, so
|
|
28
|
+
you never have to register it yourself. Don't also register it manually under
|
|
29
|
+
another key — you'd get two live namespaces and confusing config.
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
|
|
33
|
+
| Rule | Preset | Fix |
|
|
34
|
+
| -------------------------------- | ------ | -------------------- |
|
|
35
|
+
| `duro/no-raw-html-element` | error | suggestion |
|
|
36
|
+
| `duro/no-tokens-barrel-import` | error | autofix |
|
|
37
|
+
| `duro/no-deprecated-table-parts` | error | autofix / suggestion |
|
|
38
|
+
| `duro/no-raw-design-values` | warn | suggestion |
|
|
39
|
+
|
|
40
|
+
### no-raw-html-element
|
|
41
|
+
|
|
42
|
+
Raw lowercase JSX intrinsics (`<div>`, `<span>`, …) must be react-strict-dom
|
|
43
|
+
`html.*` elements. SVG subtrees are exempt (RSD has no SVG primitives).
|
|
44
|
+
Elements RSD doesn't export (`<table>`, `<canvas>`, …) report as non-portable;
|
|
45
|
+
allow them explicitly per-project via `allow`. The rewrite is a suggestion,
|
|
46
|
+
not an autofix, because `html.*` props are stricter than raw DOM props — a
|
|
47
|
+
mechanical `--fix` would trade lint errors for type errors.
|
|
48
|
+
|
|
49
|
+
Options: `{allow?: string[], reportUnsupported?: boolean, htmlModule?: string}`
|
|
50
|
+
|
|
51
|
+
### no-tokens-barrel-import
|
|
52
|
+
|
|
53
|
+
`import {colors} from '@duro-app/tokens'` breaks the StyleX babel plugin. The
|
|
54
|
+
autofix splits the barrel import into the right deep imports
|
|
55
|
+
(`@duro-app/tokens/tokens/colors.css`, …), preserving aliases and inline
|
|
56
|
+
`type` specifiers. Imports with any unmapped specifier report without a fix.
|
|
57
|
+
|
|
58
|
+
Options: `{packages?: string[]}`
|
|
59
|
+
|
|
60
|
+
### no-deprecated-table-parts
|
|
61
|
+
|
|
62
|
+
Flags `<Table.Container>` (Root owns the container query now; report-only —
|
|
63
|
+
unwrapping is layout-unsafe to automate) and the no-op `isActions` prop on
|
|
64
|
+
`<Table.HeaderCell>` (autofixed away for literal values; suggestion when the
|
|
65
|
+
value is an expression). Matches by identifier name (`Table`, `TableCore` by
|
|
66
|
+
default) — configure via `tableIdentifiers`.
|
|
67
|
+
|
|
68
|
+
### no-raw-design-values
|
|
69
|
+
|
|
70
|
+
Inside `css.create()` objects: hex colors report everywhere (palette matches
|
|
71
|
+
suggest the `colors.*` token; off-palette hexes report without a fix), and
|
|
72
|
+
numeric/`px` values matching the spacing or radius scale report on the
|
|
73
|
+
properties where that mapping is unambiguous (padding/margin/gap families →
|
|
74
|
+
`spacing.*`, border radius family → `radii.*`). `width: 16` or `fontSize: 16`
|
|
75
|
+
never report — same number, different meaning. Ships as `warn`: it informs,
|
|
76
|
+
it doesn't gate.
|
|
77
|
+
|
|
78
|
+
Options: `{factories?: string[], spacingProperties?: string[], radiiProperties?: string[]}`
|
|
79
|
+
(property lists replace the defaults, they don't merge)
|
|
80
|
+
|
|
81
|
+
## Token data
|
|
82
|
+
|
|
83
|
+
The rule data (deep-path map, spacing/radius px values, color palette) is
|
|
84
|
+
mirrored from `@duro-app/tokens` as literals so the published plugin stays
|
|
85
|
+
dependency-free. `test/token-drift.test.ts` rebuilds every table from the real
|
|
86
|
+
tokens package and fails CI when they drift.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
import { rules } from './rules/index.js';
|
|
3
|
+
declare const plugin: {
|
|
4
|
+
meta: {
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
rules: {
|
|
8
|
+
'no-raw-html-element': TSESLint.RuleModule<"useHtml" | "noEquivalent" | "suggestReplace", [({
|
|
9
|
+
allow?: string[];
|
|
10
|
+
reportUnsupported?: boolean;
|
|
11
|
+
htmlModule?: string;
|
|
12
|
+
} | undefined)?], unknown, TSESLint.RuleListener>;
|
|
13
|
+
'no-tokens-barrel-import': TSESLint.RuleModule<"barrelImport" | "barrelNamespace" | "barrelSideEffect" | "unknownSpecifiers", [({
|
|
14
|
+
packages?: string[];
|
|
15
|
+
} | undefined)?], unknown, TSESLint.RuleListener>;
|
|
16
|
+
'no-deprecated-table-parts': TSESLint.RuleModule<"deprecatedContainer" | "deprecatedIsActions" | "removeIsActions", [({
|
|
17
|
+
tableIdentifiers?: string[];
|
|
18
|
+
} | undefined)?], unknown, TSESLint.RuleListener>;
|
|
19
|
+
'no-raw-design-values': TSESLint.RuleModule<"rawColorToken" | "rawColor" | "rawSpacing" | "rawRadius" | "replaceWithToken", [({
|
|
20
|
+
factories?: string[];
|
|
21
|
+
spacingProperties?: string[];
|
|
22
|
+
radiiProperties?: string[];
|
|
23
|
+
} | undefined)?], unknown, TSESLint.RuleListener>;
|
|
24
|
+
};
|
|
25
|
+
configs: Record<string, TSESLint.FlatConfig.Config>;
|
|
26
|
+
};
|
|
27
|
+
export default plugin;
|
|
28
|
+
export { rules };
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAC,KAAK,EAAC,MAAM,kBAAkB,CAAA;AAEtC,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;aAGK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC;CAC1D,CAAA;AAiBD,eAAe,MAAM,CAAA;AACrB,OAAO,EAAC,KAAK,EAAC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { rules } from './rules/index.js';
|
|
2
|
+
const plugin = {
|
|
3
|
+
meta: { name: 'duro' },
|
|
4
|
+
rules,
|
|
5
|
+
configs: {},
|
|
6
|
+
};
|
|
7
|
+
// Assigned after construction because the config must reference the plugin
|
|
8
|
+
// object that contains it — the standard ESLint 9 self-referential shape.
|
|
9
|
+
Object.assign(plugin.configs, {
|
|
10
|
+
recommended: {
|
|
11
|
+
name: 'duro/recommended',
|
|
12
|
+
plugins: { duro: plugin },
|
|
13
|
+
rules: {
|
|
14
|
+
'duro/no-raw-html-element': 'error',
|
|
15
|
+
'duro/no-tokens-barrel-import': 'error',
|
|
16
|
+
'duro/no-deprecated-table-parts': 'error',
|
|
17
|
+
'duro/no-raw-design-values': 'warn',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
export default plugin;
|
|
22
|
+
export { rules };
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,KAAK,EAAC,MAAM,kBAAkB,CAAA;AAEtC,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC;IACpB,KAAK;IACL,OAAO,EAAE,EAAgD;CAC1D,CAAA;AAED,2EAA2E;AAC3E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;IAC5B,WAAW,EAAE;QACX,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC;QACvB,KAAK,EAAE;YACL,0BAA0B,EAAE,OAAO;YACnC,8BAA8B,EAAE,OAAO;YACvC,gCAAgC,EAAE,OAAO;YACzC,2BAA2B,EAAE,MAAM;SACpC;KACmC;CACvC,CAAC,CAAA;AAEF,eAAe,MAAM,CAAA;AACrB,OAAO,EAAC,KAAK,EAAC,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const rules: {
|
|
2
|
+
'no-raw-html-element': import("@typescript-eslint/utils/ts-eslint").RuleModule<"useHtml" | "noEquivalent" | "suggestReplace", [({
|
|
3
|
+
allow?: string[];
|
|
4
|
+
reportUnsupported?: boolean;
|
|
5
|
+
htmlModule?: string;
|
|
6
|
+
} | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
7
|
+
'no-tokens-barrel-import': import("@typescript-eslint/utils/ts-eslint").RuleModule<"barrelImport" | "barrelNamespace" | "barrelSideEffect" | "unknownSpecifiers", [({
|
|
8
|
+
packages?: string[];
|
|
9
|
+
} | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
10
|
+
'no-deprecated-table-parts': import("@typescript-eslint/utils/ts-eslint").RuleModule<"deprecatedContainer" | "deprecatedIsActions" | "removeIsActions", [({
|
|
11
|
+
tableIdentifiers?: string[];
|
|
12
|
+
} | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
13
|
+
'no-raw-design-values': import("@typescript-eslint/utils/ts-eslint").RuleModule<"rawColorToken" | "rawColor" | "rawSpacing" | "rawRadius" | "replaceWithToken", [({
|
|
14
|
+
factories?: string[];
|
|
15
|
+
spacingProperties?: string[];
|
|
16
|
+
radiiProperties?: string[];
|
|
17
|
+
} | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;CAKjB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { noRawHtmlElement } from './no-raw-html-element.js';
|
|
2
|
+
import { noTokensBarrelImport } from './no-tokens-barrel-import.js';
|
|
3
|
+
import { noDeprecatedTableParts } from './no-deprecated-table-parts.js';
|
|
4
|
+
import { noRawDesignValues } from './no-raw-design-values.js';
|
|
5
|
+
export const rules = {
|
|
6
|
+
'no-raw-html-element': noRawHtmlElement,
|
|
7
|
+
'no-tokens-barrel-import': noTokensBarrelImport,
|
|
8
|
+
'no-deprecated-table-parts': noDeprecatedTableParts,
|
|
9
|
+
'no-raw-design-values': noRawDesignValues,
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,0BAA0B,CAAA;AACzD,OAAO,EAAC,oBAAoB,EAAC,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAC,sBAAsB,EAAC,MAAM,gCAAgC,CAAA;AACrE,OAAO,EAAC,iBAAiB,EAAC,MAAM,2BAA2B,CAAA;AAE3D,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,qBAAqB,EAAE,gBAAgB;IACvC,yBAAyB,EAAE,oBAAoB;IAC/C,2BAA2B,EAAE,sBAAsB;IACnD,sBAAsB,EAAE,iBAAiB;CAC1C,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'deprecatedContainer' | 'deprecatedIsActions' | 'removeIsActions';
|
|
3
|
+
type Options = [
|
|
4
|
+
{
|
|
5
|
+
tableIdentifiers?: string[];
|
|
6
|
+
}?
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* Flag the deprecated Table API surface: <Table.Container> (Root owns the
|
|
10
|
+
* container query now) and the no-op `isActions` prop on <Table.HeaderCell>
|
|
11
|
+
* (it belongs on Table.Cell). Container is report-only — unwrapping children
|
|
12
|
+
* mechanically is layout-unsafe. isActions removal autofixes for literal
|
|
13
|
+
* values and falls back to a suggestion when the value is an expression.
|
|
14
|
+
*/
|
|
15
|
+
export declare const noDeprecatedTableParts: TSESLint.RuleModule<MessageIds, Options>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=no-deprecated-table-parts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-deprecated-table-parts.d.ts","sourceRoot":"","sources":["../../src/rules/no-deprecated-table-parts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAW,MAAM,0BAA0B,CAAA;AAEhE,KAAK,UAAU,GAAG,qBAAqB,GAAG,qBAAqB,GAAG,iBAAiB,CAAA;AACnF,KAAK,OAAO,GAAG;IACb;QACE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;KAC5B,CAAC;CACH,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CA0F3E,CAAA"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flag the deprecated Table API surface: <Table.Container> (Root owns the
|
|
3
|
+
* container query now) and the no-op `isActions` prop on <Table.HeaderCell>
|
|
4
|
+
* (it belongs on Table.Cell). Container is report-only — unwrapping children
|
|
5
|
+
* mechanically is layout-unsafe. isActions removal autofixes for literal
|
|
6
|
+
* values and falls back to a suggestion when the value is an expression.
|
|
7
|
+
*/
|
|
8
|
+
export const noDeprecatedTableParts = {
|
|
9
|
+
defaultOptions: [{}],
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Disallow deprecated Table parts (Table.Container, HeaderCell isActions)',
|
|
14
|
+
},
|
|
15
|
+
fixable: 'code',
|
|
16
|
+
hasSuggestions: true,
|
|
17
|
+
schema: [
|
|
18
|
+
{
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
tableIdentifiers: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
22
|
+
},
|
|
23
|
+
additionalProperties: false,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
messages: {
|
|
27
|
+
deprecatedContainer: '{{table}}.Container is deprecated — {{table}}.Root sets up its own container query. Remove the wrapper.',
|
|
28
|
+
deprecatedIsActions: '`isActions` has no effect on {{table}}.HeaderCell. Pass it on the matching {{table}}.Cell instead.',
|
|
29
|
+
removeIsActions: 'Remove the `isActions` attribute',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
create(context) {
|
|
33
|
+
const tableIdentifiers = new Set(context.options[0]?.tableIdentifiers ?? ['Table', 'TableCore']);
|
|
34
|
+
const sourceCode = context.sourceCode;
|
|
35
|
+
function removeAttribute(fixer, attr) {
|
|
36
|
+
const before = sourceCode.getTokenBefore(attr);
|
|
37
|
+
const start = before ? before.range[1] : attr.range[0];
|
|
38
|
+
return fixer.removeRange([start, attr.range[1]]);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
JSXOpeningElement(node) {
|
|
42
|
+
if (node.name.type !== 'JSXMemberExpression')
|
|
43
|
+
return;
|
|
44
|
+
const { object, property } = node.name;
|
|
45
|
+
if (object.type !== 'JSXIdentifier' || !tableIdentifiers.has(object.name))
|
|
46
|
+
return;
|
|
47
|
+
if (property.name === 'Container') {
|
|
48
|
+
context.report({
|
|
49
|
+
node: node.name,
|
|
50
|
+
messageId: 'deprecatedContainer',
|
|
51
|
+
data: { table: object.name },
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (property.name !== 'HeaderCell')
|
|
56
|
+
return;
|
|
57
|
+
const attr = node.attributes.find((a) => a.type === 'JSXAttribute' &&
|
|
58
|
+
a.name.type === 'JSXIdentifier' &&
|
|
59
|
+
a.name.name === 'isActions');
|
|
60
|
+
if (!attr)
|
|
61
|
+
return;
|
|
62
|
+
const value = attr.value;
|
|
63
|
+
const isLiteral = value === null ||
|
|
64
|
+
(value?.type === 'JSXExpressionContainer' &&
|
|
65
|
+
value.expression.type === 'Literal' &&
|
|
66
|
+
typeof value.expression.value === 'boolean');
|
|
67
|
+
if (isLiteral) {
|
|
68
|
+
context.report({
|
|
69
|
+
node: attr,
|
|
70
|
+
messageId: 'deprecatedIsActions',
|
|
71
|
+
data: { table: object.name },
|
|
72
|
+
fix: (fixer) => removeAttribute(fixer, attr),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
context.report({
|
|
77
|
+
node: attr,
|
|
78
|
+
messageId: 'deprecatedIsActions',
|
|
79
|
+
data: { table: object.name },
|
|
80
|
+
suggest: [
|
|
81
|
+
{
|
|
82
|
+
messageId: 'removeIsActions',
|
|
83
|
+
fix: (fixer) => removeAttribute(fixer, attr),
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=no-deprecated-table-parts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-deprecated-table-parts.js","sourceRoot":"","sources":["../../src/rules/no-deprecated-table-parts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'rawColorToken' | 'rawColor' | 'rawSpacing' | 'rawRadius' | 'replaceWithToken';
|
|
3
|
+
type Options = [
|
|
4
|
+
{
|
|
5
|
+
factories?: string[];
|
|
6
|
+
spacingProperties?: string[];
|
|
7
|
+
radiiProperties?: string[];
|
|
8
|
+
}?
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Inside css.create() style objects, flag raw design values that have a token
|
|
12
|
+
* equivalent: hex colors (anywhere — a hex is never right in this system) and
|
|
13
|
+
* spacing/radius px values on the properties where that mapping is unambiguous.
|
|
14
|
+
* Values with no token equivalent (0, negatives, rem, shorthands, off-scale
|
|
15
|
+
* numbers) are skipped, except off-palette hex colors, which report without a
|
|
16
|
+
* fix — surfacing them is the point.
|
|
17
|
+
*/
|
|
18
|
+
export declare const noRawDesignValues: TSESLint.RuleModule<MessageIds, Options>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=no-raw-design-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-raw-design-values.d.ts","sourceRoot":"","sources":["../../src/rules/no-raw-design-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAW,MAAM,0BAA0B,CAAA;AAWhE,KAAK,UAAU,GAAG,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,kBAAkB,CAAA;AAChG,KAAK,OAAO,GAAG;IACb;QACE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;QACpB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;QAC5B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;KAC3B,CAAC;CACH,CAAA;AAKD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CAgLtE,CAAA"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { COLOR_TOKENS, RADII_PROPERTIES, RADII_TOKENS_BY_PX, SPACING_PROPERTIES, SPACING_TOKENS_BY_PX, normalizeHex, } from '../util/tokens.js';
|
|
2
|
+
import { ensureNamedImport } from '../util/imports.js';
|
|
3
|
+
const HEX_RE = /#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{3,4})\b/;
|
|
4
|
+
const TOKENS_PKG = '@duro-app/tokens';
|
|
5
|
+
/**
|
|
6
|
+
* Inside css.create() style objects, flag raw design values that have a token
|
|
7
|
+
* equivalent: hex colors (anywhere — a hex is never right in this system) and
|
|
8
|
+
* spacing/radius px values on the properties where that mapping is unambiguous.
|
|
9
|
+
* Values with no token equivalent (0, negatives, rem, shorthands, off-scale
|
|
10
|
+
* numbers) are skipped, except off-palette hex colors, which report without a
|
|
11
|
+
* fix — surfacing them is the point.
|
|
12
|
+
*/
|
|
13
|
+
export const noRawDesignValues = {
|
|
14
|
+
defaultOptions: [{}],
|
|
15
|
+
meta: {
|
|
16
|
+
type: 'suggestion',
|
|
17
|
+
docs: {
|
|
18
|
+
description: 'Prefer design tokens over raw hex colors and px values in css.create styles',
|
|
19
|
+
},
|
|
20
|
+
hasSuggestions: true,
|
|
21
|
+
schema: [
|
|
22
|
+
{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
factories: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
26
|
+
spacingProperties: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
27
|
+
radiiProperties: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
28
|
+
},
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
messages: {
|
|
33
|
+
rawColorToken: "'{{value}}' is the {{token}} token. Use `colors.{{token}}` from {{pkg}}/tokens/colors.css so it follows the theme.",
|
|
34
|
+
rawColor: "'{{value}}' is not in the palette. Use a semantic token from {{pkg}}/tokens/colors.css instead of a raw color.",
|
|
35
|
+
rawSpacing: '{{value}} on `{{property}}` is the {{token}} spacing token. Use `spacing.{{token}}` from {{pkg}}/tokens/spacing.css.',
|
|
36
|
+
rawRadius: '{{value}} on `{{property}}` is the {{token}} radius token. Use `radii.{{token}}` from {{pkg}}/tokens/spacing.css.',
|
|
37
|
+
replaceWithToken: 'Replace with {{replacement}}',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
create(context) {
|
|
41
|
+
const options = context.options[0] ?? {};
|
|
42
|
+
const factories = options.factories ?? ['css.create'];
|
|
43
|
+
const spacingProperties = options.spacingProperties
|
|
44
|
+
? new Set(options.spacingProperties)
|
|
45
|
+
: SPACING_PROPERTIES;
|
|
46
|
+
const radiiProperties = options.radiiProperties
|
|
47
|
+
? new Set(options.radiiProperties)
|
|
48
|
+
: RADII_PROPERTIES;
|
|
49
|
+
const sourceCode = context.sourceCode;
|
|
50
|
+
function calleeText(node) {
|
|
51
|
+
return sourceCode.getText(node.callee);
|
|
52
|
+
}
|
|
53
|
+
function suggestReplacement(node, replacement, importName, importPath) {
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
messageId: 'replaceWithToken',
|
|
57
|
+
data: { replacement },
|
|
58
|
+
fix(fixer) {
|
|
59
|
+
const { local, fixes } = ensureNamedImport(sourceCode, fixer, `${TOKENS_PKG}/${importPath}`, importName);
|
|
60
|
+
const target = replacement.replace(`${importName}.`, `${local}.`);
|
|
61
|
+
return [...fixes, fixer.replaceText(node, target)];
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
function checkColorValue(node, raw) {
|
|
67
|
+
const match = HEX_RE.exec(raw);
|
|
68
|
+
if (!match)
|
|
69
|
+
return;
|
|
70
|
+
const hex = normalizeHex(match[0]);
|
|
71
|
+
const token = COLOR_TOKENS[hex] ?? COLOR_TOKENS[raw.toLowerCase()];
|
|
72
|
+
if (token) {
|
|
73
|
+
// Only suggest a direct replacement when the literal IS the color —
|
|
74
|
+
// inside a compound value (a boxShadow) the rewrite would be wrong.
|
|
75
|
+
const isWholeValue = raw.trim() === match[0];
|
|
76
|
+
context.report({
|
|
77
|
+
node,
|
|
78
|
+
messageId: 'rawColorToken',
|
|
79
|
+
data: { value: match[0], token, pkg: TOKENS_PKG },
|
|
80
|
+
suggest: isWholeValue
|
|
81
|
+
? suggestReplacement(node, `colors.${token}`, 'colors', 'tokens/colors.css')
|
|
82
|
+
: [],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
context.report({ node, messageId: 'rawColor', data: { value: match[0], pkg: TOKENS_PKG } });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function checkLengthValue(node, property, px, display) {
|
|
90
|
+
if (spacingProperties.has(property)) {
|
|
91
|
+
const token = SPACING_TOKENS_BY_PX[px];
|
|
92
|
+
if (!token)
|
|
93
|
+
return;
|
|
94
|
+
context.report({
|
|
95
|
+
node,
|
|
96
|
+
messageId: 'rawSpacing',
|
|
97
|
+
data: { value: display, property, token, pkg: TOKENS_PKG },
|
|
98
|
+
suggest: suggestReplacement(node, `spacing.${token}`, 'spacing', 'tokens/spacing.css'),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else if (radiiProperties.has(property)) {
|
|
102
|
+
const token = RADII_TOKENS_BY_PX[px];
|
|
103
|
+
if (!token)
|
|
104
|
+
return;
|
|
105
|
+
context.report({
|
|
106
|
+
node,
|
|
107
|
+
messageId: 'rawRadius',
|
|
108
|
+
data: { value: display, property, token, pkg: TOKENS_PKG },
|
|
109
|
+
suggest: suggestReplacement(node, `radii.${token}`, 'radii', 'tokens/spacing.css'),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function checkValue(node, property) {
|
|
114
|
+
if (node.type === 'Literal') {
|
|
115
|
+
if (typeof node.value === 'string') {
|
|
116
|
+
checkColorValue(node, node.value);
|
|
117
|
+
if (property) {
|
|
118
|
+
const pxMatch = /^(\d+)px$/.exec(node.value);
|
|
119
|
+
if (pxMatch)
|
|
120
|
+
checkLengthValue(node, property, Number(pxMatch[1]), `'${node.value}'`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (typeof node.value === 'number' && property && node.value > 0) {
|
|
124
|
+
checkLengthValue(node, property, node.value, String(node.value));
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (node.type === 'ObjectExpression') {
|
|
129
|
+
walkStyleObject(node, property);
|
|
130
|
+
}
|
|
131
|
+
// Everything else (identifiers, member expressions, template literals,
|
|
132
|
+
// calls, negatives via UnaryExpression) is deliberately skipped.
|
|
133
|
+
}
|
|
134
|
+
function walkStyleObject(obj, property) {
|
|
135
|
+
for (const prop of obj.properties) {
|
|
136
|
+
if (prop.type !== 'Property')
|
|
137
|
+
continue;
|
|
138
|
+
const key = prop.key.type === 'Identifier'
|
|
139
|
+
? prop.key.name
|
|
140
|
+
: prop.key.type === 'Literal'
|
|
141
|
+
? String(prop.key.value)
|
|
142
|
+
: null;
|
|
143
|
+
if (key === null) {
|
|
144
|
+
// Computed key — can't attribute a property; still scan for colors.
|
|
145
|
+
checkValue(prop.value, null);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// Condition keys (default, :hover, @media …) keep the enclosing
|
|
149
|
+
// property; anything else IS the property.
|
|
150
|
+
const isCondition = key === 'default' || /^[:@]/.test(key);
|
|
151
|
+
checkValue(prop.value, isCondition ? property : key);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
CallExpression(node) {
|
|
156
|
+
if (!factories.includes(calleeText(node)))
|
|
157
|
+
return;
|
|
158
|
+
const arg = node.arguments[0];
|
|
159
|
+
if (!arg || arg.type !== 'ObjectExpression')
|
|
160
|
+
return;
|
|
161
|
+
// Top level is the style-name level: css.create({styleName: {...}}).
|
|
162
|
+
for (const prop of arg.properties) {
|
|
163
|
+
if (prop.type !== 'Property')
|
|
164
|
+
continue;
|
|
165
|
+
const value = prop.value;
|
|
166
|
+
if (value.type === 'ObjectExpression')
|
|
167
|
+
walkStyleObject(value, null);
|
|
168
|
+
// Dynamic styles: css.create({x: (arg) => ({...})})
|
|
169
|
+
if ((value.type === 'ArrowFunctionExpression' || value.type === 'FunctionExpression') &&
|
|
170
|
+
value.body.type === 'ObjectExpression') {
|
|
171
|
+
walkStyleObject(value.body, null);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=no-raw-design-values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-raw-design-values.js","sourceRoot":"","sources":["../../src/rules/no-raw-design-values.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'useHtml' | 'noEquivalent' | 'suggestReplace';
|
|
3
|
+
type Options = [
|
|
4
|
+
{
|
|
5
|
+
allow?: string[];
|
|
6
|
+
reportUnsupported?: boolean;
|
|
7
|
+
htmlModule?: string;
|
|
8
|
+
}?
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Forbid raw lowercase JSX intrinsics (<div>, <span>, …) in favor of
|
|
12
|
+
* react-strict-dom's html.* elements. SVG subtrees are exempt: RSD has no SVG
|
|
13
|
+
* primitives, so anything inside <svg> (tracked by depth) or in the SVG-only
|
|
14
|
+
* tag set stays raw.
|
|
15
|
+
*
|
|
16
|
+
* The rewrite is a *suggestion*, never an autofix: html.* elements accept a
|
|
17
|
+
* strict prop subset (no className, etc.), so a mechanical `--fix` over a
|
|
18
|
+
* whole tree would mint type errors wholesale. A suggestion keeps a human at
|
|
19
|
+
* each site.
|
|
20
|
+
*/
|
|
21
|
+
export declare const noRawHtmlElement: TSESLint.RuleModule<MessageIds, Options>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=no-raw-html-element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-raw-html-element.d.ts","sourceRoot":"","sources":["../../src/rules/no-raw-html-element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAW,MAAM,0BAA0B,CAAA;AAIhE,KAAK,UAAU,GAAG,SAAS,GAAG,cAAc,GAAG,gBAAgB,CAAA;AAC/D,KAAK,OAAO,GAAG;IACb;QACE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;QAChB,iBAAiB,CAAC,EAAE,OAAO,CAAA;QAC3B,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAC;CACH,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CA2FrE,CAAA"}
|