zyzz 0.0.17 → 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.
Files changed (45) hide show
  1. package/dist/Style.d.ts.map +1 -1
  2. package/dist/Style.js +16 -3
  3. package/dist/Style.js.map +1 -1
  4. package/dist/oxlint/index.d.ts +6 -0
  5. package/dist/oxlint/index.d.ts.map +1 -0
  6. package/dist/oxlint/index.js +18 -0
  7. package/dist/oxlint/index.js.map +1 -0
  8. package/dist/oxlint/internal/Bindings.d.ts +20 -0
  9. package/dist/oxlint/internal/Bindings.d.ts.map +1 -0
  10. package/dist/oxlint/internal/Bindings.js +203 -0
  11. package/dist/oxlint/internal/Bindings.js.map +1 -0
  12. package/dist/oxlint/internal/Declarations.d.ts +19 -0
  13. package/dist/oxlint/internal/Declarations.d.ts.map +1 -0
  14. package/dist/oxlint/internal/Declarations.js +114 -0
  15. package/dist/oxlint/internal/Declarations.js.map +1 -0
  16. package/dist/oxlint/rules/noConflictingProps.d.ts +5 -0
  17. package/dist/oxlint/rules/noConflictingProps.d.ts.map +1 -0
  18. package/dist/oxlint/rules/noConflictingProps.js +45 -0
  19. package/dist/oxlint/rules/noConflictingProps.js.map +1 -0
  20. package/dist/oxlint/rules/noUnused.d.ts +5 -0
  21. package/dist/oxlint/rules/noUnused.d.ts.map +1 -0
  22. package/dist/oxlint/rules/noUnused.js +62 -0
  23. package/dist/oxlint/rules/noUnused.js.map +1 -0
  24. package/dist/oxlint/rules/restrictedProperties.d.ts +5 -0
  25. package/dist/oxlint/rules/restrictedProperties.d.ts.map +1 -0
  26. package/dist/oxlint/rules/restrictedProperties.js +82 -0
  27. package/dist/oxlint/rules/restrictedProperties.js.map +1 -0
  28. package/dist/oxlint/rules/useLogicalProperties.d.ts +5 -0
  29. package/dist/oxlint/rules/useLogicalProperties.d.ts.map +1 -0
  30. package/dist/oxlint/rules/useLogicalProperties.js +76 -0
  31. package/dist/oxlint/rules/useLogicalProperties.js.map +1 -0
  32. package/dist/oxlint/rules/validStyles.d.ts +5 -0
  33. package/dist/oxlint/rules/validStyles.d.ts.map +1 -0
  34. package/dist/oxlint/rules/validStyles.js +75 -0
  35. package/dist/oxlint/rules/validStyles.js.map +1 -0
  36. package/package.json +7 -1
  37. package/src/Style.ts +16 -3
  38. package/src/oxlint/index.ts +21 -0
  39. package/src/oxlint/internal/Bindings.ts +270 -0
  40. package/src/oxlint/internal/Declarations.ts +137 -0
  41. package/src/oxlint/rules/noConflictingProps.ts +52 -0
  42. package/src/oxlint/rules/noUnused.ts +67 -0
  43. package/src/oxlint/rules/restrictedProperties.ts +92 -0
  44. package/src/oxlint/rules/useLogicalProperties.ts +81 -0
  45. package/src/oxlint/rules/validStyles.ts +88 -0
@@ -0,0 +1,45 @@
1
+ import * as Bindings from '../internal/Bindings.js';
2
+ /** Reports competing style spreads and explicit styling attributes without rewriting JSX. */
3
+ export const noConflictingProps = {
4
+ meta: {
5
+ messages: {
6
+ attribute: "Pass '{{property}}' into the Zyzz style call to merge styling props.",
7
+ spread: 'Compose Zyzz applications with cx() instead of overwriting them with multiple JSX spreads.',
8
+ },
9
+ schema: [],
10
+ type: 'problem',
11
+ },
12
+ create(context) {
13
+ const bindings = Bindings.create(context);
14
+ function application(node) {
15
+ node = bindings.expression(node);
16
+ if (node.type !== 'CallExpression')
17
+ return false;
18
+ const binding = bindings.resolve(node.callee);
19
+ return binding?.kind === 'definition' || binding?.kind === 'cx';
20
+ }
21
+ return {
22
+ JSXOpeningElement(node) {
23
+ const spreads = node.attributes.filter((attribute) => attribute.type === 'JSXSpreadAttribute' &&
24
+ application(attribute.argument));
25
+ if (!spreads.length)
26
+ return;
27
+ for (const attribute of node.attributes) {
28
+ if (attribute.type !== 'JSXAttribute' ||
29
+ attribute.name.type !== 'JSXIdentifier')
30
+ continue;
31
+ const property = attribute.name.name;
32
+ if (property === 'className' || property === 'style')
33
+ context.report({
34
+ data: { property },
35
+ messageId: 'attribute',
36
+ node: attribute,
37
+ });
38
+ }
39
+ for (const spread of spreads.slice(1))
40
+ context.report({ messageId: 'spread', node: spread });
41
+ },
42
+ };
43
+ },
44
+ };
45
+ //# sourceMappingURL=noConflictingProps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noConflictingProps.js","sourceRoot":"","sources":["../../../src/oxlint/rules/noConflictingProps.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAA;AAEnD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAS;IACtC,IAAI,EAAE;QACJ,QAAQ,EAAE;YACR,SAAS,EACP,sEAAsE;YACxE,MAAM,EACJ,4FAA4F;SAC/F;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KAChB;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACzC,SAAS,WAAW,CAAC,IAAiB;YACpC,IAAI,GAAG,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAChC,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB;gBAAE,OAAO,KAAK,CAAA;YAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7C,OAAO,OAAO,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,EAAE,IAAI,KAAK,IAAI,CAAA;QACjE,CAAC;QACD,OAAO;YACL,iBAAiB,CAAC,IAAI;gBACpB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CACpC,CAAC,SAAS,EAAE,EAAE,CACZ,SAAS,CAAC,IAAI,KAAK,oBAAoB;oBACvC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAClC,CAAA;gBACD,IAAI,CAAC,OAAO,CAAC,MAAM;oBAAE,OAAM;gBAC3B,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBACxC,IACE,SAAS,CAAC,IAAI,KAAK,cAAc;wBACjC,SAAS,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;wBAEvC,SAAQ;oBACV,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAA;oBACpC,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,OAAO;wBAClD,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,EAAE,QAAQ,EAAE;4BAClB,SAAS,EAAE,WAAW;4BACtB,IAAI,EAAE,SAAS;yBAChB,CAAC,CAAA;gBACN,CAAC;gBACD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;oBACnC,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;YACzD,CAAC;SACF,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -0,0 +1,5 @@
1
+ /** Finds unused style members in local TypeScript namespaces. @module */
2
+ import type { Rule } from '@oxlint/plugins';
3
+ /** Leaves module exports and escaped namespaces available to unknown consumers. */
4
+ export declare const noUnused: Rule;
5
+ //# sourceMappingURL=noUnused.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noUnused.d.ts","sourceRoot":"","sources":["../../../src/oxlint/rules/noUnused.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,OAAO,KAAK,EAAU,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAGnD,mFAAmF;AACnF,eAAO,MAAM,QAAQ,EAAE,IA6DtB,CAAA"}
@@ -0,0 +1,62 @@
1
+ import * as Bindings from '../internal/Bindings.js';
2
+ /** Leaves module exports and escaped namespaces available to unknown consumers. */
3
+ export const noUnused = {
4
+ meta: {
5
+ messages: { unused: "Style '{{name}}' is never used." },
6
+ schema: [],
7
+ type: 'suggestion',
8
+ },
9
+ create(context) {
10
+ const bindings = Bindings.create(context);
11
+ const declarations = [];
12
+ return {
13
+ VariableDeclarator(node) {
14
+ if (node.id.type === 'Identifier' &&
15
+ node.init &&
16
+ bindings.resolve(node.init)?.kind === 'definition')
17
+ declarations.push(node);
18
+ },
19
+ 'Program:exit'() {
20
+ for (const declaration of declarations) {
21
+ if (declaration.id.type !== 'Identifier')
22
+ continue;
23
+ let parent = declaration.parent;
24
+ while (parent.type === 'VariableDeclaration' ||
25
+ parent.type === 'ExportNamedDeclaration')
26
+ parent = parent.parent;
27
+ if (parent.type !== 'TSModuleBlock' ||
28
+ parent.parent.type !== 'TSModuleDeclaration')
29
+ continue;
30
+ const namespace = parent.parent;
31
+ if (namespace.id.type !== 'Identifier')
32
+ continue;
33
+ // Nested and exported namespaces may have consumers outside this local scope.
34
+ if (namespace.parent.type !== 'Program')
35
+ continue;
36
+ const variable = bindings.variable(declaration.id);
37
+ const owner = bindings.variable(namespace.id);
38
+ if (!variable || !owner || owner.defs.length !== 1)
39
+ continue;
40
+ if (variable.references.some((reference) => reference.isRead()))
41
+ continue;
42
+ const used = owner.references.some((reference) => {
43
+ if (!reference.isRead())
44
+ return false;
45
+ const member = reference.identifier.parent;
46
+ return (member.type !== 'MemberExpression' ||
47
+ member.object !== reference.identifier ||
48
+ Bindings.key(member) === undefined ||
49
+ Bindings.key(member) === variable.name);
50
+ });
51
+ if (!used)
52
+ context.report({
53
+ data: { name: `${namespace.id.name}.${variable.name}` },
54
+ messageId: 'unused',
55
+ node: declaration.id,
56
+ });
57
+ }
58
+ },
59
+ };
60
+ },
61
+ };
62
+ //# sourceMappingURL=noUnused.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noUnused.js","sourceRoot":"","sources":["../../../src/oxlint/rules/noUnused.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Applies explicit project restrictions to known web declarations. @module */
2
+ import type { Rule } from '@oxlint/plugins';
3
+ /** Reports forbidden properties or literal values outside an explicit allowlist. */
4
+ export declare const restrictedProperties: Rule;
5
+ //# sourceMappingURL=restrictedProperties.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restrictedProperties.d.ts","sourceRoot":"","sources":["../../../src/oxlint/rules/restrictedProperties.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAI3C,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,EAAE,IAqFlC,CAAA"}
@@ -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":"AAEA,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAA;AACnD,OAAO,KAAK,YAAY,MAAM,6BAA6B,CAAA;AAE3D,oFAAoF;AACpF,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,IAAI,EAAE;QACJ,QAAQ,EAAE;YACR,UAAU,EAAE,mDAAmD;SAChE;QACD,MAAM,EAAE;YACN;gBACE,oBAAoB,EAAE;oBACpB,oBAAoB,EAAE,KAAK;oBAC3B,UAAU,EAAE;wBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBAC1B,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;qBACjE;oBACD,IAAI,EAAE,QAAQ;iBACf;gBACD,IAAI,EAAE,QAAQ;aACf;SACF;QACD,IAAI,EAAE,YAAY;KACnB;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;QAClC,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,IACE,CAAC,YAAY;oBACb,OAAO,YAAY,KAAK,QAAQ;oBAChC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;oBAE3B,OAAM;gBACR,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC7C,IAAI,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,OAAO,EAAE,IAAI,KAAK,UAAU;oBAAE,OAAM;gBACrE,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;gBAC/B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe;oBAAE,OAAM;gBACpD,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE;oBACxB,QAAQ;oBACR,MAAM,EAAE,OAAO,CAAC,IAAI,KAAK,UAAU;oBACnC,QAAQ,EAAE;wBACR,WAAW,CAAC,QAAQ,EAAE,IAAI;4BACxB,IACE,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC;gCAClC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;gCAE5B,OAAM;4BACR,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;4BACtC,IACE,CAAC,WAAW;gCACZ,OAAO,WAAW,KAAK,QAAQ;gCAC/B,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;gCAE1B,OAAM;4BACR,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAA;4BAClC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gCAC3B,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;gCAC9D,IAAI,CAAC,OAAO;oCAAE,OAAM;gCACpB,MAAM,MAAM,GAAc,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;oCACpD,CAAC,CAAC,OAAO,CAAC,KAAK;oCACf,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;gCACnB,IACE,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CACrB,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK,CAAC,CAC7C;oCAED,OAAM;4BACV,CAAC;4BACD,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;4BAC5B,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE;oCACJ,QAAQ,EAAE,IAAI;oCACd,MAAM,EACJ,OAAO,WAAW,CAAC,MAAM,KAAK,QAAQ;wCACpC,CAAC,CAAC,WAAW,CAAC,MAAM;wCACpB,CAAC,CAAC,oCAAoC;iCAC3C;gCACD,SAAS,EAAE,YAAY;gCACvB,IAAI,EAAE,QAAQ,CAAC,GAAG;6BACnB,CAAC,CAAA;wBACJ,CAAC;qBACF;iBACF,CAAC,CAAA;YACJ,CAAC;SACF,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -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.17",
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",
package/src/Style.ts CHANGED
@@ -245,6 +245,17 @@ export function define(
245
245
  keyof Literal.Properties,
246
246
  Map<string | number, Token.Reference>
247
247
  >()
248
+ const validatedReferences = new WeakSet<object>()
249
+
250
+ function isReference(value: unknown): value is Token.Reference {
251
+ if (typeof value !== 'object' || value === null) return false
252
+ if (validatedReferences.has(value)) return true
253
+ if (!Token.is(value)) return false
254
+
255
+ // Frozen references can reuse validation across declarations in this definition.
256
+ validatedReferences.add(value)
257
+ return true
258
+ }
248
259
 
249
260
  function report(
250
261
  code: Diagnostic['code'],
@@ -629,7 +640,7 @@ export function define(
629
640
  theme,
630
641
  })
631
642
 
632
- if (Token.is(resolved)) {
643
+ if (isReference(resolved)) {
633
644
  let values = references.get(key)
634
645
 
635
646
  if (!values) references.set(key, (values = new Map()))
@@ -640,8 +651,10 @@ export function define(
640
651
  return resolved
641
652
  })()
642
653
 
654
+ const reference = isReference(resolved)
655
+
643
656
  if (
644
- Token.is(resolved) &&
657
+ reference &&
645
658
  resolved.contract.variableSet &&
646
659
  !Token.acceptsReference(resolved, key)
647
660
  ) {
@@ -656,7 +669,7 @@ export function define(
656
669
  if (
657
670
  theme &&
658
671
  !custom &&
659
- !Token.is(resolved) &&
672
+ !reference &&
660
673
  Token.mapped(theme, key) &&
661
674
  !(Binding.is(resolved) && !resolved.name.startsWith('--z-d')) &&
662
675
  !(
@@ -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