stablekit.ts 0.6.1 → 0.6.2

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.
@@ -27,6 +27,7 @@ var pluginRuleName = "stablekit/no-functional-in-utility";
27
27
  var descendantColorRuleName = "stablekit/no-descendant-color-in-state";
28
28
  var duplicateRulesetRuleName = "stablekit/no-duplicate-ruleset";
29
29
  var nearDuplicateRuleName = "stablekit/no-near-duplicate-ruleset";
30
+ var undefinedTokenRuleName = "stablekit/no-undefined-token";
30
31
  function createFunctionalTokenPlugin(prefixes) {
31
32
  const rule = (enabled) => {
32
33
  return (root, result) => {
@@ -178,13 +179,53 @@ function createNearDuplicatePlugin() {
178
179
  rule
179
180
  };
180
181
  }
182
+ function createUndefinedTokenPlugin(runtimePrefixes) {
183
+ const varPattern = /var\(--([a-zA-Z0-9_-]+)/g;
184
+ const rule = (enabled) => {
185
+ return (root, result) => {
186
+ if (!enabled) return;
187
+ const defined = /* @__PURE__ */ new Set();
188
+ root.walkDecls((decl) => {
189
+ if (decl.prop.startsWith("--")) {
190
+ defined.add(decl.prop);
191
+ }
192
+ });
193
+ root.walkAtRules("theme", (atRule) => {
194
+ atRule.walkDecls((decl) => {
195
+ if (decl.prop.startsWith("--")) {
196
+ defined.add(decl.prop);
197
+ }
198
+ });
199
+ });
200
+ root.walkDecls((decl) => {
201
+ if (decl.prop.startsWith("--")) return;
202
+ let match;
203
+ varPattern.lastIndex = 0;
204
+ while ((match = varPattern.exec(decl.value)) !== null) {
205
+ const name = `--${match[1]}`;
206
+ if (defined.has(name)) continue;
207
+ if (runtimePrefixes.some((p) => name.startsWith(p))) continue;
208
+ result.warn(
209
+ `Reference to undefined custom property "${name}". This token is not defined anywhere in this file.`,
210
+ { node: decl }
211
+ );
212
+ }
213
+ });
214
+ };
215
+ };
216
+ return {
217
+ ruleName: undefinedTokenRuleName,
218
+ rule
219
+ };
220
+ }
181
221
  function createStyleLint(options = {}) {
182
222
  const {
183
223
  ignoreTypes = ["html", "body"],
184
224
  functionalTokens = [],
225
+ runtimeTokens = [],
185
226
  files = ["src/**/*.css"]
186
227
  } = options;
187
- const plugins = [createDescendantColorPlugin(), createDuplicateRulesetPlugin(), createNearDuplicatePlugin()];
228
+ const plugins = [createDescendantColorPlugin(), createDuplicateRulesetPlugin(), createNearDuplicatePlugin(), createUndefinedTokenPlugin(runtimeTokens)];
188
229
  if (functionalTokens.length > 0) {
189
230
  plugins.push(createFunctionalTokenPlugin(functionalTokens));
190
231
  }
@@ -204,6 +245,8 @@ function createStyleLint(options = {}) {
204
245
  [duplicateRulesetRuleName]: true,
205
246
  // Flag near-duplicate rulesets (same props, differ by 1 value).
206
247
  [nearDuplicateRuleName]: true,
248
+ // Flag var() references to custom properties not defined in this file.
249
+ [undefinedTokenRuleName]: true,
207
250
  // Ban animating layout properties — causes reflow on every frame.
208
251
  // Use transform (scaleY, translateY) or opacity instead.
209
252
  "declaration-property-value-disallowed-list": [
@@ -40,6 +40,11 @@ interface StyleLintOptions {
40
40
  * e.g. ["--color-status-", "--color-danger"]
41
41
  * Any var() referencing these inside @utility is a lint error. */
42
42
  functionalTokens?: string[];
43
+ /** Custom property prefixes set at runtime (JS, Radix, inline styles)
44
+ * that should not be flagged as undefined.
45
+ * e.g. ["--radix-", "--bar-"]
46
+ * @default [] */
47
+ runtimeTokens?: string[];
43
48
  /** Glob patterns for files to lint.
44
49
  * @default ["src/**\/*.css"] */
45
50
  files?: string[];
@@ -40,6 +40,11 @@ interface StyleLintOptions {
40
40
  * e.g. ["--color-status-", "--color-danger"]
41
41
  * Any var() referencing these inside @utility is a lint error. */
42
42
  functionalTokens?: string[];
43
+ /** Custom property prefixes set at runtime (JS, Radix, inline styles)
44
+ * that should not be flagged as undefined.
45
+ * e.g. ["--radix-", "--bar-"]
46
+ * @default [] */
47
+ runtimeTokens?: string[];
43
48
  /** Glob patterns for files to lint.
44
49
  * @default ["src/**\/*.css"] */
45
50
  files?: string[];
package/dist/stylelint.js CHANGED
@@ -3,6 +3,7 @@ var pluginRuleName = "stablekit/no-functional-in-utility";
3
3
  var descendantColorRuleName = "stablekit/no-descendant-color-in-state";
4
4
  var duplicateRulesetRuleName = "stablekit/no-duplicate-ruleset";
5
5
  var nearDuplicateRuleName = "stablekit/no-near-duplicate-ruleset";
6
+ var undefinedTokenRuleName = "stablekit/no-undefined-token";
6
7
  function createFunctionalTokenPlugin(prefixes) {
7
8
  const rule = (enabled) => {
8
9
  return (root, result) => {
@@ -154,13 +155,53 @@ function createNearDuplicatePlugin() {
154
155
  rule
155
156
  };
156
157
  }
158
+ function createUndefinedTokenPlugin(runtimePrefixes) {
159
+ const varPattern = /var\(--([a-zA-Z0-9_-]+)/g;
160
+ const rule = (enabled) => {
161
+ return (root, result) => {
162
+ if (!enabled) return;
163
+ const defined = /* @__PURE__ */ new Set();
164
+ root.walkDecls((decl) => {
165
+ if (decl.prop.startsWith("--")) {
166
+ defined.add(decl.prop);
167
+ }
168
+ });
169
+ root.walkAtRules("theme", (atRule) => {
170
+ atRule.walkDecls((decl) => {
171
+ if (decl.prop.startsWith("--")) {
172
+ defined.add(decl.prop);
173
+ }
174
+ });
175
+ });
176
+ root.walkDecls((decl) => {
177
+ if (decl.prop.startsWith("--")) return;
178
+ let match;
179
+ varPattern.lastIndex = 0;
180
+ while ((match = varPattern.exec(decl.value)) !== null) {
181
+ const name = `--${match[1]}`;
182
+ if (defined.has(name)) continue;
183
+ if (runtimePrefixes.some((p) => name.startsWith(p))) continue;
184
+ result.warn(
185
+ `Reference to undefined custom property "${name}". This token is not defined anywhere in this file.`,
186
+ { node: decl }
187
+ );
188
+ }
189
+ });
190
+ };
191
+ };
192
+ return {
193
+ ruleName: undefinedTokenRuleName,
194
+ rule
195
+ };
196
+ }
157
197
  function createStyleLint(options = {}) {
158
198
  const {
159
199
  ignoreTypes = ["html", "body"],
160
200
  functionalTokens = [],
201
+ runtimeTokens = [],
161
202
  files = ["src/**/*.css"]
162
203
  } = options;
163
- const plugins = [createDescendantColorPlugin(), createDuplicateRulesetPlugin(), createNearDuplicatePlugin()];
204
+ const plugins = [createDescendantColorPlugin(), createDuplicateRulesetPlugin(), createNearDuplicatePlugin(), createUndefinedTokenPlugin(runtimeTokens)];
164
205
  if (functionalTokens.length > 0) {
165
206
  plugins.push(createFunctionalTokenPlugin(functionalTokens));
166
207
  }
@@ -180,6 +221,8 @@ function createStyleLint(options = {}) {
180
221
  [duplicateRulesetRuleName]: true,
181
222
  // Flag near-duplicate rulesets (same props, differ by 1 value).
182
223
  [nearDuplicateRuleName]: true,
224
+ // Flag var() references to custom properties not defined in this file.
225
+ [undefinedTokenRuleName]: true,
183
226
  // Ban animating layout properties — causes reflow on every frame.
184
227
  // Use transform (scaleY, translateY) or opacity instead.
185
228
  "declaration-property-value-disallowed-list": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stablekit.ts",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "React toolkit for layout stability — zero-shift components for loading states, content swaps, and spatial containers.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",