zyzz 0.0.18 → 0.0.19
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/dist/oxlint/index.d.ts +6 -0
- package/dist/oxlint/index.d.ts.map +1 -0
- package/dist/oxlint/index.js +18 -0
- package/dist/oxlint/index.js.map +1 -0
- package/dist/oxlint/internal/Bindings.d.ts +20 -0
- package/dist/oxlint/internal/Bindings.d.ts.map +1 -0
- package/dist/oxlint/internal/Bindings.js +203 -0
- package/dist/oxlint/internal/Bindings.js.map +1 -0
- package/dist/oxlint/internal/Declarations.d.ts +19 -0
- package/dist/oxlint/internal/Declarations.d.ts.map +1 -0
- package/dist/oxlint/internal/Declarations.js +114 -0
- package/dist/oxlint/internal/Declarations.js.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts +5 -0
- package/dist/oxlint/rules/noConflictingProps.d.ts.map +1 -0
- package/dist/oxlint/rules/noConflictingProps.js +45 -0
- package/dist/oxlint/rules/noConflictingProps.js.map +1 -0
- package/dist/oxlint/rules/noUnused.d.ts +5 -0
- package/dist/oxlint/rules/noUnused.d.ts.map +1 -0
- package/dist/oxlint/rules/noUnused.js +62 -0
- package/dist/oxlint/rules/noUnused.js.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts +5 -0
- package/dist/oxlint/rules/restrictedProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/restrictedProperties.js +82 -0
- package/dist/oxlint/rules/restrictedProperties.js.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts +5 -0
- package/dist/oxlint/rules/useLogicalProperties.d.ts.map +1 -0
- package/dist/oxlint/rules/useLogicalProperties.js +76 -0
- package/dist/oxlint/rules/useLogicalProperties.js.map +1 -0
- package/dist/oxlint/rules/validStyles.d.ts +5 -0
- package/dist/oxlint/rules/validStyles.d.ts.map +1 -0
- package/dist/oxlint/rules/validStyles.js +75 -0
- package/dist/oxlint/rules/validStyles.js.map +1 -0
- package/package.json +7 -1
- package/src/oxlint/index.ts +21 -0
- package/src/oxlint/internal/Bindings.ts +270 -0
- package/src/oxlint/internal/Declarations.ts +137 -0
- package/src/oxlint/rules/noConflictingProps.ts +52 -0
- package/src/oxlint/rules/noUnused.ts +67 -0
- package/src/oxlint/rules/restrictedProperties.ts +92 -0
- package/src/oxlint/rules/useLogicalProperties.ts +81 -0
- package/src/oxlint/rules/validStyles.ts +88 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as Bindings from '../internal/Bindings.js';
|
|
2
|
+
import * as Declarations from '../internal/Declarations.js';
|
|
3
|
+
/** Reports forbidden properties or literal values outside an explicit allowlist. */
|
|
4
|
+
export const restrictedProperties = {
|
|
5
|
+
meta: {
|
|
6
|
+
messages: {
|
|
7
|
+
restricted: "Property '{{property}}' is restricted. {{reason}}",
|
|
8
|
+
},
|
|
9
|
+
schema: [
|
|
10
|
+
{
|
|
11
|
+
additionalProperties: {
|
|
12
|
+
additionalProperties: false,
|
|
13
|
+
properties: {
|
|
14
|
+
reason: { type: 'string' },
|
|
15
|
+
values: { items: { type: ['string', 'number'] }, type: 'array' },
|
|
16
|
+
},
|
|
17
|
+
type: 'object',
|
|
18
|
+
},
|
|
19
|
+
type: 'object',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
type: 'suggestion',
|
|
23
|
+
},
|
|
24
|
+
create(context) {
|
|
25
|
+
const bindings = Bindings.create(context);
|
|
26
|
+
const restrictions = context.options[0];
|
|
27
|
+
const reported = new Set();
|
|
28
|
+
return {
|
|
29
|
+
CallExpression(node) {
|
|
30
|
+
if (!restrictions ||
|
|
31
|
+
typeof restrictions !== 'object' ||
|
|
32
|
+
Array.isArray(restrictions))
|
|
33
|
+
return;
|
|
34
|
+
const binding = bindings.resolve(node.callee);
|
|
35
|
+
if (binding?.kind !== 'style' && binding?.kind !== 'variants')
|
|
36
|
+
return;
|
|
37
|
+
const input = node.arguments[0];
|
|
38
|
+
if (!input || input.type === 'SpreadElement')
|
|
39
|
+
return;
|
|
40
|
+
Declarations.visit(input, {
|
|
41
|
+
bindings,
|
|
42
|
+
recipe: binding.kind === 'variants',
|
|
43
|
+
visitors: {
|
|
44
|
+
declaration(property, name) {
|
|
45
|
+
if (!Object.hasOwn(restrictions, name) ||
|
|
46
|
+
reported.has(property.start))
|
|
47
|
+
return;
|
|
48
|
+
const restriction = restrictions[name];
|
|
49
|
+
if (!restriction ||
|
|
50
|
+
typeof restriction !== 'object' ||
|
|
51
|
+
Array.isArray(restriction))
|
|
52
|
+
return;
|
|
53
|
+
const allowed = restriction.values;
|
|
54
|
+
if (Array.isArray(allowed)) {
|
|
55
|
+
const literal = Declarations.literal(property.value, bindings);
|
|
56
|
+
if (!literal)
|
|
57
|
+
return;
|
|
58
|
+
const values = Array.isArray(literal.value)
|
|
59
|
+
? literal.value
|
|
60
|
+
: [literal.value];
|
|
61
|
+
if (values.every((value) => allowed.some((allowed) => allowed === value)))
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
reported.add(property.start);
|
|
65
|
+
context.report({
|
|
66
|
+
data: {
|
|
67
|
+
property: name,
|
|
68
|
+
reason: typeof restriction.reason === 'string'
|
|
69
|
+
? restriction.reason
|
|
70
|
+
: 'Use an approved property or value.',
|
|
71
|
+
},
|
|
72
|
+
messageId: 'restricted',
|
|
73
|
+
node: property.key,
|
|
74
|
+
});
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=restrictedProperties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restrictedProperties.js","sourceRoot":"","sources":["../../../src/oxlint/rules/restrictedProperties.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Encourages logical CSS properties in web style declarations. @module */
|
|
2
|
+
import type { Rule } from '@oxlint/plugins';
|
|
3
|
+
/** Reports physical properties without changing direction-dependent behavior. */
|
|
4
|
+
export declare const useLogicalProperties: Rule;
|
|
5
|
+
//# sourceMappingURL=useLogicalProperties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogicalProperties.d.ts","sourceRoot":"","sources":["../../../src/oxlint/rules/useLogicalProperties.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AA+B3C,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,EAAE,IA+ClC,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as Bindings from '../internal/Bindings.js';
|
|
2
|
+
import * as Declarations from '../internal/Declarations.js';
|
|
3
|
+
const replacements = {
|
|
4
|
+
borderBottomLeftRadius: 'borderEndStartRadius',
|
|
5
|
+
borderBottomRightRadius: 'borderEndEndRadius',
|
|
6
|
+
borderLeft: 'borderInlineStart',
|
|
7
|
+
borderLeftColor: 'borderInlineStartColor',
|
|
8
|
+
borderLeftStyle: 'borderInlineStartStyle',
|
|
9
|
+
borderLeftWidth: 'borderInlineStartWidth',
|
|
10
|
+
borderRight: 'borderInlineEnd',
|
|
11
|
+
borderRightColor: 'borderInlineEndColor',
|
|
12
|
+
borderRightStyle: 'borderInlineEndStyle',
|
|
13
|
+
borderRightWidth: 'borderInlineEndWidth',
|
|
14
|
+
borderTopLeftRadius: 'borderStartStartRadius',
|
|
15
|
+
borderTopRightRadius: 'borderStartEndRadius',
|
|
16
|
+
insetLeft: 'insetInlineStart',
|
|
17
|
+
insetRight: 'insetInlineEnd',
|
|
18
|
+
left: 'insetInlineStart',
|
|
19
|
+
marginLeft: 'marginInlineStart',
|
|
20
|
+
marginRight: 'marginInlineEnd',
|
|
21
|
+
paddingLeft: 'paddingInlineStart',
|
|
22
|
+
paddingRight: 'paddingInlineEnd',
|
|
23
|
+
right: 'insetInlineEnd',
|
|
24
|
+
scrollMarginLeft: 'scrollMarginInlineStart',
|
|
25
|
+
scrollMarginRight: 'scrollMarginInlineEnd',
|
|
26
|
+
scrollPaddingLeft: 'scrollPaddingInlineStart',
|
|
27
|
+
scrollPaddingRight: 'scrollPaddingInlineEnd',
|
|
28
|
+
};
|
|
29
|
+
/** Reports physical properties without changing direction-dependent behavior. */
|
|
30
|
+
export const useLogicalProperties = {
|
|
31
|
+
meta: {
|
|
32
|
+
messages: {
|
|
33
|
+
logical: "Use a CSS logical property instead of '{{property}}', such as '{{replacement}}' for horizontal LTR layouts.",
|
|
34
|
+
},
|
|
35
|
+
schema: [],
|
|
36
|
+
type: 'suggestion',
|
|
37
|
+
},
|
|
38
|
+
create(context) {
|
|
39
|
+
const bindings = Bindings.create(context);
|
|
40
|
+
const reported = new Set();
|
|
41
|
+
return {
|
|
42
|
+
CallExpression(node) {
|
|
43
|
+
const binding = bindings.resolve(node.callee);
|
|
44
|
+
if (binding?.kind !== 'style' && binding?.kind !== 'variants')
|
|
45
|
+
return;
|
|
46
|
+
const input = node.arguments[0];
|
|
47
|
+
if (!input || input.type === 'SpreadElement')
|
|
48
|
+
return;
|
|
49
|
+
Declarations.visit(input, {
|
|
50
|
+
bindings,
|
|
51
|
+
recipe: binding.kind === 'variants',
|
|
52
|
+
visitors: {
|
|
53
|
+
declaration(property, name) {
|
|
54
|
+
const replacement = Object.hasOwn(replacements, name)
|
|
55
|
+
? replacements[name]
|
|
56
|
+
: undefined;
|
|
57
|
+
if (!replacement || reported.has(property.start))
|
|
58
|
+
return;
|
|
59
|
+
if (context.sourceCode
|
|
60
|
+
.getCommentsBefore(property)
|
|
61
|
+
.some((comment) => comment.value.includes('allow-physical-property')))
|
|
62
|
+
return;
|
|
63
|
+
reported.add(property.start);
|
|
64
|
+
context.report({
|
|
65
|
+
data: { property: name, replacement },
|
|
66
|
+
messageId: 'logical',
|
|
67
|
+
node: property.key,
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=useLogicalProperties.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLogicalProperties.js","sourceRoot":"","sources":["../../../src/oxlint/rules/useLogicalProperties.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Reports statically known declaration errors using Zyzz's authoring validation. @module */
|
|
2
|
+
import type { Rule } from '@oxlint/plugins';
|
|
3
|
+
/** Validates known structure and values while leaving unresolved bindings to the compiler. */
|
|
4
|
+
export declare const validStyles: Rule;
|
|
5
|
+
//# sourceMappingURL=validStyles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validStyles.d.ts","sourceRoot":"","sources":["../../../src/oxlint/rules/validStyles.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAMnD,8FAA8F;AAC9F,eAAO,MAAM,WAAW,EAAE,IA+EzB,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as Bindings from '../internal/Bindings.js';
|
|
2
|
+
import * as Declarations from '../internal/Declarations.js';
|
|
3
|
+
import * as Literal from '../../internal/Literal.js';
|
|
4
|
+
import * as Style from '../../Style.js';
|
|
5
|
+
/** Validates known structure and values while leaving unresolved bindings to the compiler. */
|
|
6
|
+
export const validStyles = {
|
|
7
|
+
meta: { messages: { invalid: '{{message}}' }, schema: [], type: 'problem' },
|
|
8
|
+
create(context) {
|
|
9
|
+
const bindings = Bindings.create(context);
|
|
10
|
+
const reported = new Set();
|
|
11
|
+
function report(node, message) {
|
|
12
|
+
if (reported.has(node.start))
|
|
13
|
+
return;
|
|
14
|
+
reported.add(node.start);
|
|
15
|
+
context.report({ data: { message }, messageId: 'invalid', node });
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
CallExpression(node) {
|
|
19
|
+
const binding = bindings.resolve(node.callee);
|
|
20
|
+
if (binding?.kind !== 'style' && binding?.kind !== 'variants')
|
|
21
|
+
return;
|
|
22
|
+
const input = node.arguments[0];
|
|
23
|
+
if (!input || input.type === 'SpreadElement')
|
|
24
|
+
return;
|
|
25
|
+
Declarations.visit(input, {
|
|
26
|
+
bindings,
|
|
27
|
+
recipe: binding.kind === 'variants',
|
|
28
|
+
visitors: {
|
|
29
|
+
declaration(property, name) {
|
|
30
|
+
if (binding.themed && name === 'typography')
|
|
31
|
+
return;
|
|
32
|
+
if (!binding.themed &&
|
|
33
|
+
!name.startsWith('--') &&
|
|
34
|
+
!Object.hasOwn(Literal.rules, name)) {
|
|
35
|
+
report(property.key, `Unknown CSS property '${name}'.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const value = bindings.expression(property.value);
|
|
39
|
+
if (value.type === 'ObjectExpression') {
|
|
40
|
+
report(value, 'CSS declarations require scalar values or fallback arrays.');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (value.type === 'ArrayExpression' &&
|
|
44
|
+
value.elements.some((element) => !element)) {
|
|
45
|
+
report(value, 'Fallback arrays require dense data entries without holes.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const literal = Declarations.literal(value, bindings);
|
|
49
|
+
if (!literal)
|
|
50
|
+
return;
|
|
51
|
+
const values = Array.isArray(literal.value)
|
|
52
|
+
? literal.value
|
|
53
|
+
: [literal.value];
|
|
54
|
+
if (values.some((value) => typeof value !== 'string' && typeof value !== 'number')) {
|
|
55
|
+
report(value, 'CSS declarations require string or number values.');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
Style.define({ lint: { [name]: literal.value } });
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (!(error instanceof Style.InvalidError))
|
|
63
|
+
throw error;
|
|
64
|
+
for (const diagnostic of error.diagnostics)
|
|
65
|
+
report(value, diagnostic.message);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
invalid: report,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=validStyles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validStyles.js","sourceRoot":"","sources":["../../../src/oxlint/rules/validStyles.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zyzz",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Modern, universal, simple styling library for the Web and React Native",
|
|
6
6
|
"repository": {
|
|
@@ -78,6 +78,11 @@
|
|
|
78
78
|
"types": "./dist/node/index.d.ts",
|
|
79
79
|
"default": "./dist/node/index.js"
|
|
80
80
|
},
|
|
81
|
+
"./oxlint": {
|
|
82
|
+
"src": "./src/oxlint/index.ts",
|
|
83
|
+
"types": "./dist/oxlint/index.d.ts",
|
|
84
|
+
"default": "./dist/oxlint/index.js"
|
|
85
|
+
},
|
|
81
86
|
"./react-native": {
|
|
82
87
|
"src": "./src/react-native/index.ts",
|
|
83
88
|
"types": "./dist/react-native/index.d.ts",
|
|
@@ -127,6 +132,7 @@
|
|
|
127
132
|
"@jridgewell/gen-mapping": "^0.3.13",
|
|
128
133
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
129
134
|
"@oxc-project/types": "0.148.0",
|
|
135
|
+
"@oxlint/plugins": "1.68.0",
|
|
130
136
|
"css-tree": "3.2.1",
|
|
131
137
|
"incur": "^0.5.1",
|
|
132
138
|
"lightningcss": "^1.33.0",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Exposes opt-in Oxlint rules for Zyzz web authoring. @module */
|
|
2
|
+
import type { Plugin } from '@oxlint/plugins'
|
|
3
|
+
import { noConflictingProps } from './rules/noConflictingProps.js'
|
|
4
|
+
import { noUnused } from './rules/noUnused.js'
|
|
5
|
+
import { restrictedProperties } from './rules/restrictedProperties.js'
|
|
6
|
+
import { useLogicalProperties } from './rules/useLogicalProperties.js'
|
|
7
|
+
import { validStyles } from './rules/validStyles.js'
|
|
8
|
+
|
|
9
|
+
/** Register through jsPlugins and enable individual zyzz/* rules in the lint configuration. */
|
|
10
|
+
const plugin: Plugin = {
|
|
11
|
+
meta: { name: 'zyzz' },
|
|
12
|
+
rules: {
|
|
13
|
+
'no-conflicting-props': noConflictingProps,
|
|
14
|
+
'no-unused': noUnused,
|
|
15
|
+
'restricted-properties': restrictedProperties,
|
|
16
|
+
'use-logical-properties': useLogicalProperties,
|
|
17
|
+
'valid-styles': validStyles,
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export default plugin
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/** Resolves immutable authoring bindings without loading or evaluating modules. @module */
|
|
2
|
+
import type { Context, ESTree, Variable } from '@oxlint/plugins'
|
|
3
|
+
|
|
4
|
+
/** A recognized helper or locally declared style. */
|
|
5
|
+
export type Binding = {
|
|
6
|
+
readonly kind:
|
|
7
|
+
| 'config'
|
|
8
|
+
| 'configFactory'
|
|
9
|
+
| 'configNamespace'
|
|
10
|
+
| 'cx'
|
|
11
|
+
| 'definition'
|
|
12
|
+
| 'module'
|
|
13
|
+
| 'style'
|
|
14
|
+
| 'variants'
|
|
15
|
+
readonly themed: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Resolves helpers using lexical scope, configuration filenames, and explicit import sources. */
|
|
19
|
+
export function create(context: Context) {
|
|
20
|
+
const settings = context.settings.zyzz
|
|
21
|
+
const imports = new Set(['zyzz', 'zyzz/default'])
|
|
22
|
+
if (settings && typeof settings === 'object' && !Array.isArray(settings)) {
|
|
23
|
+
const sources = settings.imports
|
|
24
|
+
if (Array.isArray(sources))
|
|
25
|
+
for (const source of sources)
|
|
26
|
+
if (typeof source === 'string') imports.add(source)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function variable(
|
|
30
|
+
node: Extract<ESTree.Node, { type: 'Identifier' }>,
|
|
31
|
+
): Variable | undefined {
|
|
32
|
+
let scope = context.sourceCode.getScope(node)
|
|
33
|
+
while (scope) {
|
|
34
|
+
const found = scope.set.get(node.name)
|
|
35
|
+
if (found) return found
|
|
36
|
+
if (!scope.upper) break
|
|
37
|
+
scope = scope.upper
|
|
38
|
+
}
|
|
39
|
+
return undefined
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function initializer(
|
|
43
|
+
node: Extract<ESTree.Node, { type: 'Identifier' }>,
|
|
44
|
+
): ESTree.Node | undefined {
|
|
45
|
+
const binding = variable(node)
|
|
46
|
+
if (!binding || binding.defs.length !== 1) return undefined
|
|
47
|
+
const definition = binding.defs[0]!
|
|
48
|
+
if (definition.node.type !== 'VariableDeclarator') return undefined
|
|
49
|
+
if (
|
|
50
|
+
definition.node.parent.type !== 'VariableDeclaration' ||
|
|
51
|
+
definition.node.parent.kind !== 'const'
|
|
52
|
+
)
|
|
53
|
+
return undefined
|
|
54
|
+
if (
|
|
55
|
+
binding.references.some(
|
|
56
|
+
(reference) => reference.isWrite() && !reference.init,
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
return undefined
|
|
60
|
+
if (definition.node.id.type !== 'Identifier') return undefined
|
|
61
|
+
const input = definition.node.init && unwrap(definition.node.init)
|
|
62
|
+
if (
|
|
63
|
+
input?.type === 'ArrayExpression' ||
|
|
64
|
+
input?.type === 'ObjectExpression'
|
|
65
|
+
) {
|
|
66
|
+
const mutable = binding.references.some((reference) => {
|
|
67
|
+
let value: ESTree.Node = reference.identifier
|
|
68
|
+
while (
|
|
69
|
+
value.parent &&
|
|
70
|
+
((value.parent.type === 'MemberExpression' &&
|
|
71
|
+
value.parent.object === value) ||
|
|
72
|
+
unwrap(value.parent) === value)
|
|
73
|
+
)
|
|
74
|
+
value = value.parent
|
|
75
|
+
const parent = value.parent
|
|
76
|
+
if (
|
|
77
|
+
parent?.type === 'ArrayExpression' ||
|
|
78
|
+
(parent?.type === 'Property' && parent.value === value)
|
|
79
|
+
)
|
|
80
|
+
return true
|
|
81
|
+
if (parent?.type === 'AssignmentExpression' && parent.left === value)
|
|
82
|
+
return true
|
|
83
|
+
if (
|
|
84
|
+
parent?.type === 'UpdateExpression' ||
|
|
85
|
+
(parent?.type === 'UnaryExpression' && parent.operator === 'delete')
|
|
86
|
+
)
|
|
87
|
+
return true
|
|
88
|
+
if (parent?.type === 'CallExpression') {
|
|
89
|
+
if (parent.callee === value) return true
|
|
90
|
+
const callee = resolve(parent.callee)
|
|
91
|
+
return callee?.kind !== 'style' && callee?.kind !== 'variants'
|
|
92
|
+
}
|
|
93
|
+
return parent?.type === 'VariableDeclarator' && parent.init === value
|
|
94
|
+
})
|
|
95
|
+
if (mutable) return undefined
|
|
96
|
+
}
|
|
97
|
+
return definition.node.init ?? undefined
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function expression(
|
|
101
|
+
node: ESTree.Node,
|
|
102
|
+
seen = new Set<ESTree.Node>(),
|
|
103
|
+
): ESTree.Node {
|
|
104
|
+
node = unwrap(node)
|
|
105
|
+
if (seen.has(node)) return node
|
|
106
|
+
seen.add(node)
|
|
107
|
+
if (node.type === 'Identifier') {
|
|
108
|
+
const init = initializer(node)
|
|
109
|
+
if (init) return expression(init, seen)
|
|
110
|
+
}
|
|
111
|
+
return node
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function member(
|
|
115
|
+
binding: Binding | undefined,
|
|
116
|
+
name: string | undefined,
|
|
117
|
+
): Binding | undefined {
|
|
118
|
+
if (!binding || !name) return undefined
|
|
119
|
+
if (binding.kind === 'module') {
|
|
120
|
+
if (!binding.themed && name === 'Config')
|
|
121
|
+
return { kind: 'configNamespace', themed: true }
|
|
122
|
+
if (
|
|
123
|
+
name === 'style' ||
|
|
124
|
+
name === 'variants' ||
|
|
125
|
+
(!binding.themed && name === 'cx')
|
|
126
|
+
)
|
|
127
|
+
return { kind: name, themed: binding.themed }
|
|
128
|
+
}
|
|
129
|
+
if (binding.kind === 'configNamespace' && name === 'create')
|
|
130
|
+
return { kind: 'configFactory', themed: true }
|
|
131
|
+
if (binding.kind === 'config' && (name === 'style' || name === 'variants'))
|
|
132
|
+
return { kind: name, themed: true }
|
|
133
|
+
return undefined
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resolve(
|
|
137
|
+
node: ESTree.Node,
|
|
138
|
+
seen = new Set<ESTree.Node>(),
|
|
139
|
+
): Binding | undefined {
|
|
140
|
+
node = unwrap(node)
|
|
141
|
+
if (seen.has(node)) return undefined
|
|
142
|
+
seen.add(node)
|
|
143
|
+
|
|
144
|
+
if (node.type === 'Identifier') {
|
|
145
|
+
const binding = variable(node)
|
|
146
|
+
if (!binding || binding.defs.length !== 1) return undefined
|
|
147
|
+
const definition = binding.defs[0]!
|
|
148
|
+
const declaration = definition.node
|
|
149
|
+
if (definition.type === 'ImportBinding') {
|
|
150
|
+
const parent = declaration.parent
|
|
151
|
+
if (
|
|
152
|
+
parent?.type !== 'ImportDeclaration' ||
|
|
153
|
+
parent.importKind === 'type' ||
|
|
154
|
+
(!imports.has(parent.source.value) &&
|
|
155
|
+
!/(?:^|\/)zyzz\.config\.[^/]+$/.test(parent.source.value))
|
|
156
|
+
)
|
|
157
|
+
return undefined
|
|
158
|
+
const module: Binding = {
|
|
159
|
+
kind: 'module',
|
|
160
|
+
themed: parent.source.value !== 'zyzz',
|
|
161
|
+
}
|
|
162
|
+
if (declaration.type === 'ImportNamespaceSpecifier') return module
|
|
163
|
+
if (
|
|
164
|
+
declaration.type === 'ImportSpecifier' &&
|
|
165
|
+
declaration.importKind !== 'type'
|
|
166
|
+
)
|
|
167
|
+
return member(
|
|
168
|
+
module,
|
|
169
|
+
declaration.imported.type === 'Identifier'
|
|
170
|
+
? declaration.imported.name
|
|
171
|
+
: declaration.imported.value,
|
|
172
|
+
)
|
|
173
|
+
return undefined
|
|
174
|
+
}
|
|
175
|
+
if (
|
|
176
|
+
declaration.type !== 'VariableDeclarator' ||
|
|
177
|
+
!declaration.init ||
|
|
178
|
+
declaration.parent.type !== 'VariableDeclaration' ||
|
|
179
|
+
declaration.parent.kind !== 'const'
|
|
180
|
+
)
|
|
181
|
+
return undefined
|
|
182
|
+
if (
|
|
183
|
+
binding.references.some(
|
|
184
|
+
(reference) => reference.isWrite() && !reference.init,
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
return undefined
|
|
188
|
+
if (declaration.id.type === 'Identifier')
|
|
189
|
+
return resolve(declaration.init, seen)
|
|
190
|
+
if (declaration.id.type === 'ObjectPattern') {
|
|
191
|
+
const property = declaration.id.properties.find(
|
|
192
|
+
(property) =>
|
|
193
|
+
property.type === 'Property' &&
|
|
194
|
+
property.value.type === 'Identifier' &&
|
|
195
|
+
property.value.name === node.name,
|
|
196
|
+
)
|
|
197
|
+
if (property?.type === 'Property')
|
|
198
|
+
return member(resolve(declaration.init, seen), key(property))
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (node.type === 'MemberExpression') {
|
|
203
|
+
const name = key(node)
|
|
204
|
+
const known = member(resolve(node.object, new Set(seen)), name)
|
|
205
|
+
if (known) return known
|
|
206
|
+
if (node.object.type !== 'Identifier' || !name) return undefined
|
|
207
|
+
const namespace = variable(node.object)
|
|
208
|
+
if (!namespace || namespace.defs.length !== 1) return undefined
|
|
209
|
+
const declaration = namespace.defs[0]!.node
|
|
210
|
+
if (
|
|
211
|
+
declaration.type !== 'TSModuleDeclaration' ||
|
|
212
|
+
declaration.body?.type !== 'TSModuleBlock'
|
|
213
|
+
)
|
|
214
|
+
return undefined
|
|
215
|
+
for (const statement of declaration.body.body) {
|
|
216
|
+
if (
|
|
217
|
+
statement.type !== 'ExportNamedDeclaration' ||
|
|
218
|
+
statement.declaration?.type !== 'VariableDeclaration' ||
|
|
219
|
+
statement.declaration.kind !== 'const'
|
|
220
|
+
)
|
|
221
|
+
continue
|
|
222
|
+
for (const entry of statement.declaration.declarations)
|
|
223
|
+
if (
|
|
224
|
+
entry.id.type === 'Identifier' &&
|
|
225
|
+
entry.id.name === name &&
|
|
226
|
+
entry.init
|
|
227
|
+
)
|
|
228
|
+
return resolve(entry.init, seen)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (node.type === 'CallExpression') {
|
|
233
|
+
const callee = resolve(node.callee, seen)
|
|
234
|
+
if (callee?.kind === 'configFactory')
|
|
235
|
+
return { kind: 'config', themed: true }
|
|
236
|
+
if (callee?.kind === 'style' || callee?.kind === 'variants')
|
|
237
|
+
return { kind: 'definition', themed: callee.themed }
|
|
238
|
+
}
|
|
239
|
+
return undefined
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return { expression, resolve, variable }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Resolves only literal property names, never computed identifiers. */
|
|
246
|
+
export function key(
|
|
247
|
+
node:
|
|
248
|
+
| ESTree.ObjectProperty
|
|
249
|
+
| ESTree.BindingProperty
|
|
250
|
+
| ESTree.MemberExpression,
|
|
251
|
+
): string | undefined {
|
|
252
|
+
const property = node.type === 'Property' ? node.key : node.property
|
|
253
|
+
if (!node.computed && property.type === 'Identifier') return property.name
|
|
254
|
+
if (property.type === 'Literal' && typeof property.value === 'string')
|
|
255
|
+
return property.value
|
|
256
|
+
return undefined
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Removes type-only wrappers while retaining the original source node. */
|
|
260
|
+
export function unwrap(node: ESTree.Node): ESTree.Node {
|
|
261
|
+
while (
|
|
262
|
+
node.type === 'TSAsExpression' ||
|
|
263
|
+
node.type === 'TSSatisfiesExpression' ||
|
|
264
|
+
node.type === 'TSNonNullExpression' ||
|
|
265
|
+
node.type === 'TSTypeAssertion' ||
|
|
266
|
+
node.type === 'ParenthesizedExpression'
|
|
267
|
+
)
|
|
268
|
+
node = node.expression
|
|
269
|
+
return node
|
|
270
|
+
}
|