@elmeragroup/internal 0.1.1-canary.1

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.
@@ -0,0 +1,2029 @@
1
+
2
+ import { defineRule, eslintCompatPlugin } from "@oxlint/plugins";
3
+ //#region ../oxlint-plugin/filename-normalizer.js
4
+ /**
5
+ * @param {string} filename
6
+ */
7
+ function normalizeFilename(filename) {
8
+ return filename.replaceAll("\\", "/");
9
+ }
10
+ //#endregion
11
+ //#region ../oxlint-plugin/rules/enforce-variant-standard.js
12
+ /**
13
+ * Component entry: src/components/<name>/<name>.tsx
14
+ * @param {string} filename
15
+ */
16
+ function isComponentEntry(filename) {
17
+ return /(?:^|\/)src\/components\/([^/]+)\/\1\.tsx$/.test(normalizeFilename(filename));
18
+ }
19
+ /**
20
+ * Colocated recipe module: src/components/<name>/<name>-variants.ts
21
+ * @param {string} filename
22
+ */
23
+ function isVariantsModule(filename) {
24
+ return /(?:^|\/)src\/components\/([^/]+)\/\1-variants\.ts$/.test(normalizeFilename(filename));
25
+ }
26
+ /**
27
+ * @param {import("estree").Node | null | undefined} callee
28
+ */
29
+ function isTvCall(callee) {
30
+ return callee?.type === "Identifier" && callee.name === "tv";
31
+ }
32
+ /**
33
+ * @param {import("estree").ObjectExpression} obj
34
+ * @param {string} name
35
+ */
36
+ function getObjectProp(obj, name) {
37
+ for (const prop of obj.properties) {
38
+ if (prop.type !== "Property" || prop.computed) continue;
39
+ if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" ? String(prop.key.value) : null) === name) return prop.value;
40
+ }
41
+ }
42
+ /**
43
+ * A recipe has axes when `variants` is present and not an empty object.
44
+ * Identifiers and spreads count as axes; we cannot see through them.
45
+ *
46
+ * @param {import("estree").ObjectExpression} obj
47
+ */
48
+ function recipeHasAxes(obj) {
49
+ const variants = getObjectProp(obj, "variants");
50
+ if (!variants) return false;
51
+ if (variants.type !== "ObjectExpression") return true;
52
+ return variants.properties.length > 0;
53
+ }
54
+ var enforce_variant_standard_default = defineRule({
55
+ meta: {
56
+ type: "problem",
57
+ docs: { description: "Enforce tv recipe structure: named recipe, variants/defaultVariants on recipes with axes, VariantProps typing" },
58
+ messages: {
59
+ unnamedRecipe: "tv() recipes must be assigned to a named const (e.g. buttonVariants).",
60
+ inlineObject: "tv() must receive an inline object.",
61
+ missingDefaultVariants: "tv() recipe '{{name}}' must declare defaultVariants when it has a variants axis.",
62
+ missingVariantProps: "Component files that define a tv() recipe with axes must type props with VariantProps<typeof recipe>."
63
+ },
64
+ schema: []
65
+ },
66
+ defaultOptions: [],
67
+ createOnce(context) {
68
+ let shouldCheck = false;
69
+ let requireVariantProps = false;
70
+ /** @type {import("estree").CallExpression[]} */
71
+ const tvCalls = [];
72
+ return {
73
+ Program() {
74
+ const filename = context.filename;
75
+ shouldCheck = isComponentEntry(filename) || isVariantsModule(filename);
76
+ requireVariantProps = isComponentEntry(filename);
77
+ tvCalls.length = 0;
78
+ },
79
+ CallExpression(node) {
80
+ if (!shouldCheck || !isTvCall(node.callee)) return;
81
+ tvCalls.push(node);
82
+ },
83
+ "Program:exit"() {
84
+ if (!shouldCheck || tvCalls.length === 0) return;
85
+ for (const node of tvCalls) {
86
+ const parent = node.parent;
87
+ const named = parent?.type === "VariableDeclarator" && parent.id.type === "Identifier" ? parent.id.name : null;
88
+ if (!named) {
89
+ context.report({
90
+ node,
91
+ messageId: "unnamedRecipe"
92
+ });
93
+ continue;
94
+ }
95
+ const firstArg = node.arguments[0];
96
+ if (firstArg?.type !== "ObjectExpression") {
97
+ context.report({
98
+ node,
99
+ messageId: "inlineObject"
100
+ });
101
+ continue;
102
+ }
103
+ if (recipeHasAxes(firstArg) && !getObjectProp(firstArg, "defaultVariants")) context.report({
104
+ node,
105
+ messageId: "missingDefaultVariants",
106
+ data: { name: named }
107
+ });
108
+ }
109
+ const anyHasAxes = tvCalls.some((call) => {
110
+ const arg = call.arguments[0];
111
+ return arg?.type === "ObjectExpression" && recipeHasAxes(arg);
112
+ });
113
+ if (requireVariantProps && anyHasAxes && !context.sourceCode.getText().includes("VariantProps")) context.report({
114
+ loc: tvCalls[0]?.loc,
115
+ messageId: "missingVariantProps"
116
+ });
117
+ }
118
+ };
119
+ }
120
+ });
121
+ //#endregion
122
+ //#region ../oxlint-plugin/rules/facade-reexport-grammar.js
123
+ /**
124
+ * Facades are `src/<name>.ts(x)` and `src/react-aria/<name>.ts(x)`.
125
+ * The generated root barrel may use `export *` and is excluded.
126
+ * @param {string} filename
127
+ */
128
+ function isEntryFacadeFile(filename) {
129
+ const posix = normalizeFilename(filename);
130
+ if (posix.endsWith("/src/index.ts") || posix.endsWith("/src/index.tsx")) return false;
131
+ if (/\/src\/[a-z0-9-]+\.tsx?$/.test(posix)) return true;
132
+ return /\/src\/react-aria\/[a-z0-9-]+\.tsx?$/.test(posix);
133
+ }
134
+ var facade_reexport_grammar_default = defineRule({
135
+ meta: {
136
+ type: "problem",
137
+ docs: { description: "Require src/<name>.ts and src/react-aria/<name>.ts facades to be explicit named re-exports only" },
138
+ messages: { grammar: "Entry facades must be explicit named re-exports only: no export *, no local declarations, no directives." },
139
+ schema: []
140
+ },
141
+ defaultOptions: [],
142
+ createOnce(context) {
143
+ return { Program(program) {
144
+ if (!isEntryFacadeFile(context.filename)) return;
145
+ for (const statement of program.body) {
146
+ if (statement.type === "ExportNamedDeclaration") {
147
+ if (statement.declaration != null || statement.source == null) context.report({
148
+ node: statement,
149
+ messageId: "grammar"
150
+ });
151
+ continue;
152
+ }
153
+ context.report({
154
+ node: statement,
155
+ messageId: "grammar"
156
+ });
157
+ }
158
+ } };
159
+ }
160
+ });
161
+ //#endregion
162
+ //#region ../oxlint-plugin/rules/no-field-part-jsx.js
163
+ const BANNED_PARTS = /* @__PURE__ */ new Set([
164
+ "Label",
165
+ "Description",
166
+ "Error",
167
+ "Root",
168
+ "Set",
169
+ "Legend"
170
+ ]);
171
+ const LABELED_COMPOSITES = [
172
+ "/src/components/text-field/text-field.tsx",
173
+ "/src/components/number-field/number-field.tsx",
174
+ "/src/components/textarea-field/textarea-field.tsx",
175
+ "/src/components/phone-number-field/phone-number-field.tsx",
176
+ "/src/components/checkbox/checkbox.tsx",
177
+ "/src/components/radio-group/radio-group.tsx"
178
+ ];
179
+ /**
180
+ * @param {string} filename
181
+ */
182
+ function isLabeledComposite(filename) {
183
+ const normalized = normalizeFilename(filename);
184
+ return LABELED_COMPOSITES.some((suffix) => normalized.endsWith(suffix));
185
+ }
186
+ /**
187
+ * @param {import("estree").Node | null | undefined} nameNode
188
+ * @returns {string | null}
189
+ */
190
+ function fieldPartName(nameNode) {
191
+ if (nameNode?.type !== "JSXMemberExpression") return null;
192
+ const object = nameNode.object;
193
+ const property = nameNode.property;
194
+ if (object?.type !== "JSXIdentifier" || object.name !== "Field") return null;
195
+ if (property?.type !== "JSXIdentifier") return null;
196
+ return property.name;
197
+ }
198
+ var no_field_part_jsx_default = defineRule({
199
+ meta: {
200
+ type: "problem",
201
+ docs: { description: "Forbid Field.Label/Description/Error/Root/Set/Legend JSX in labeled composites that must go through FieldFrame" },
202
+ messages: { fieldPart: "Labeled composites render <Field.{{part}}> through FieldFrame. Do not reopen that markup here." },
203
+ schema: []
204
+ },
205
+ defaultOptions: [],
206
+ createOnce(context) {
207
+ let skipFile = true;
208
+ return {
209
+ Program() {
210
+ skipFile = !isLabeledComposite(context.filename);
211
+ },
212
+ JSXOpeningElement(node) {
213
+ if (skipFile) return;
214
+ const part = fieldPartName(node.name);
215
+ if (part === null || !BANNED_PARTS.has(part)) return;
216
+ context.report({
217
+ node,
218
+ messageId: "fieldPart",
219
+ data: { part }
220
+ });
221
+ }
222
+ };
223
+ }
224
+ });
225
+ //#endregion
226
+ //#region ../oxlint-plugin/extract-strings.js
227
+ /**
228
+ * Collect string literals from an ESTree node (class names, tv/cn args).
229
+ * Lifted from kumo lint helpers (MIT, Copyright (c) 2026 Cloudflare, Inc.).
230
+ *
231
+ * @param {import("estree").Node | null | undefined} node
232
+ * @returns {string[]}
233
+ */
234
+ function extractStrings(node) {
235
+ if (!node) return [];
236
+ const out = [];
237
+ switch (node.type) {
238
+ case "Literal":
239
+ if (typeof node.value === "string") out.push(node.value);
240
+ break;
241
+ case "TemplateLiteral":
242
+ for (const q of node.quasis) if (typeof q.value.cooked === "string") out.push(q.value.cooked);
243
+ break;
244
+ case "BinaryExpression":
245
+ if (node.operator === "+") {
246
+ out.push(...extractStrings(node.left));
247
+ out.push(...extractStrings(node.right));
248
+ }
249
+ break;
250
+ case "ArrayExpression":
251
+ for (const el of node.elements) if (el) out.push(...extractStrings(el));
252
+ break;
253
+ case "ObjectExpression":
254
+ for (const prop of node.properties) if (prop.type === "Property") {
255
+ out.push(...extractStrings(prop.key));
256
+ out.push(...extractStrings(prop.value));
257
+ }
258
+ break;
259
+ case "CallExpression":
260
+ for (const arg of node.arguments) {
261
+ if (arg.type === "SpreadElement") continue;
262
+ out.push(...extractStrings(arg));
263
+ }
264
+ break;
265
+ case "ConditionalExpression":
266
+ out.push(...extractStrings(node.consequent));
267
+ out.push(...extractStrings(node.alternate));
268
+ out.push(...extractStrings(node.test));
269
+ break;
270
+ case "UnaryExpression":
271
+ out.push(...extractStrings(node.argument));
272
+ break;
273
+ case "LogicalExpression":
274
+ out.push(...extractStrings(node.left));
275
+ out.push(...extractStrings(node.right));
276
+ break;
277
+ case "JSXText":
278
+ out.push(node.value);
279
+ break;
280
+ case "JSXExpressionContainer": out.push(...extractStrings(node.expression));
281
+ }
282
+ return out;
283
+ }
284
+ /**
285
+ * @param {import("estree").Node | null | undefined} callee
286
+ * @param {string} name
287
+ */
288
+ function isNamedCall(callee, name) {
289
+ return callee?.type === "Identifier" && callee.name === name;
290
+ }
291
+ //#endregion
292
+ //#region ../oxlint-plugin/rules/no-hardcoded-density-metrics.js
293
+ const CONTROL_VAR_RE = /--control-(?:h|px-icon|px|gap)-|--control-(?:text|leading)\b/;
294
+ const KEYWORD_BOX = /* @__PURE__ */ new Set([
295
+ "auto",
296
+ "full",
297
+ "min",
298
+ "max",
299
+ "fit",
300
+ "screen",
301
+ "svh",
302
+ "lvh",
303
+ "dvh",
304
+ "svw",
305
+ "lvw",
306
+ "dvw",
307
+ "px",
308
+ "lh",
309
+ "none",
310
+ "svmin",
311
+ "lvmin",
312
+ "dvmin",
313
+ "svmax",
314
+ "lvmax",
315
+ "dvmax"
316
+ ]);
317
+ const ICON_GLYPH_SIZES = /* @__PURE__ */ new Set(["3", "4"]);
318
+ const TYPE_SCALE = /* @__PURE__ */ new Set([
319
+ "xs",
320
+ "sm",
321
+ "base",
322
+ "lg",
323
+ "xl",
324
+ "2xl",
325
+ "3xl",
326
+ "4xl",
327
+ "5xl",
328
+ "6xl",
329
+ "7xl",
330
+ "8xl",
331
+ "9xl"
332
+ ]);
333
+ const MD_LG_KEYS = /* @__PURE__ */ new Set([
334
+ "md",
335
+ "lg",
336
+ "default"
337
+ ]);
338
+ const BUTTON_SIZE_KEYS = /* @__PURE__ */ new Set([
339
+ "default",
340
+ "xs",
341
+ "sm",
342
+ "md",
343
+ "lg",
344
+ "icon",
345
+ "icon-xxs",
346
+ "icon-xs",
347
+ "icon-sm",
348
+ "icon-inline",
349
+ "icon-lg"
350
+ ]);
351
+ /**
352
+ * @param {import("estree").ObjectExpression} obj
353
+ * @param {string} name
354
+ * @returns {import("estree").Node | null}
355
+ */
356
+ function objectPropValue(obj, name) {
357
+ for (const prop of obj.properties) {
358
+ if (prop.type !== "Property") continue;
359
+ if ((prop.key.type === "Identifier" ? prop.key.name : prop.key.type === "Literal" ? prop.key.value : null) === name) return prop.value;
360
+ }
361
+ return null;
362
+ }
363
+ /**
364
+ * @param {import("estree").Property} prop
365
+ * @returns {string | null}
366
+ */
367
+ function propertyName(prop) {
368
+ if (prop.computed && prop.key.type !== "Literal") return null;
369
+ if (prop.key.type === "Identifier") return prop.key.name;
370
+ if (prop.key.type === "Literal" && typeof prop.key.value === "string") return prop.key.value;
371
+ return null;
372
+ }
373
+ /**
374
+ * @param {string} str
375
+ * @param {number} start
376
+ */
377
+ function matchingBracket(str, start) {
378
+ if (str[start] !== "[") return -1;
379
+ let depth = 0;
380
+ for (let i = start; i < str.length; i++) {
381
+ const ch = str[i];
382
+ if (ch === "[") depth += 1;
383
+ else if (ch === "]") {
384
+ depth -= 1;
385
+ if (depth === 0) return i;
386
+ }
387
+ }
388
+ return -1;
389
+ }
390
+ /**
391
+ * Strip Tailwind variant prefixes, including arbitrary and data variants.
392
+ * @param {string} className
393
+ */
394
+ function stripVariantPrefixes(className) {
395
+ let rest = className;
396
+ while (rest.length > 0) {
397
+ if (rest.startsWith("[")) {
398
+ const end = matchingBracket(rest, 0);
399
+ if (end !== -1 && rest[end + 1] === ":") {
400
+ rest = rest.slice(end + 2);
401
+ continue;
402
+ }
403
+ break;
404
+ }
405
+ if (rest.startsWith("*:") || rest.startsWith("**:")) {
406
+ rest = rest.slice(rest.indexOf(":") + 1);
407
+ continue;
408
+ }
409
+ const nameMatch = /^[a-zA-Z@][\w-]*(?:\/[\w-]+)?/.exec(rest);
410
+ if (!nameMatch) break;
411
+ let i = nameMatch[0].length;
412
+ if (rest[i] === "[") {
413
+ const end = matchingBracket(rest, i);
414
+ if (end === -1) break;
415
+ i = end + 1;
416
+ }
417
+ if (rest[i] === ":") {
418
+ rest = rest.slice(i + 1);
419
+ continue;
420
+ }
421
+ break;
422
+ }
423
+ return rest;
424
+ }
425
+ /**
426
+ * @param {string} className
427
+ */
428
+ function isDescendantTargeted(className) {
429
+ return /\[[^\]]*&/.test(className);
430
+ }
431
+ /**
432
+ * @param {string} utility
433
+ */
434
+ function stripImportant(utility) {
435
+ let next = utility;
436
+ if (next.startsWith("!")) next = next.slice(1);
437
+ if (next.endsWith("!")) next = next.slice(0, -1);
438
+ return next;
439
+ }
440
+ /**
441
+ * @param {string} utility
442
+ */
443
+ function readsDensityVariable(utility) {
444
+ return CONTROL_VAR_RE.test(utility);
445
+ }
446
+ /**
447
+ * @param {string} sizeKey
448
+ */
449
+ function isMdLgRung(sizeKey) {
450
+ return MD_LG_KEYS.has(sizeKey);
451
+ }
452
+ /**
453
+ * @param {string} value
454
+ */
455
+ function isKeywordBox(value) {
456
+ return KEYWORD_BOX.has(value);
457
+ }
458
+ /**
459
+ * @param {string} utility
460
+ * @param {string} prefix
461
+ * @returns {string | null}
462
+ */
463
+ function valueAfter(utility, prefix) {
464
+ if (!utility.startsWith(prefix)) return null;
465
+ return utility.slice(prefix.length);
466
+ }
467
+ /**
468
+ * @param {string} utility
469
+ * @returns {string | null}
470
+ */
471
+ function boxFamily(utility) {
472
+ const height = valueAfter(utility, "h-");
473
+ if (height !== null) {
474
+ if (!height || isKeywordBox(height)) return null;
475
+ return "height";
476
+ }
477
+ const square = valueAfter(utility, "size-");
478
+ if (square !== null) {
479
+ if (!square || isKeywordBox(square) || ICON_GLYPH_SIZES.has(square)) return null;
480
+ return "height";
481
+ }
482
+ const gapX = valueAfter(utility, "gap-x-");
483
+ if (gapX !== null) return gapX && !isKeywordBox(gapX) ? "gap" : null;
484
+ if (valueAfter(utility, "gap-y-") !== null) return null;
485
+ const gap = valueAfter(utility, "gap-");
486
+ if (gap !== null) return gap && !isKeywordBox(gap) ? "gap" : null;
487
+ const px = valueAfter(utility, "px-");
488
+ if (px !== null) return px && !isKeywordBox(px) ? "inline padding" : null;
489
+ const pl = valueAfter(utility, "pl-");
490
+ if (pl !== null) return pl && !isKeywordBox(pl) ? "icon-edge padding" : null;
491
+ const pr = valueAfter(utility, "pr-");
492
+ if (pr !== null) return pr && !isKeywordBox(pr) ? "icon-edge padding" : null;
493
+ const ps = valueAfter(utility, "ps-");
494
+ if (ps !== null) return ps && !isKeywordBox(ps) ? "icon-edge padding" : null;
495
+ const pe = valueAfter(utility, "pe-");
496
+ if (pe !== null) return pe && !isKeywordBox(pe) ? "icon-edge padding" : null;
497
+ return null;
498
+ }
499
+ /**
500
+ * @param {string} utility
501
+ * @returns {string | null}
502
+ */
503
+ function typeFamily(utility) {
504
+ if (utility.startsWith("[font-size:") || utility.startsWith("[line-height:")) return "type";
505
+ if (utility.startsWith("leading-")) return "type";
506
+ const text = valueAfter(utility, "text-");
507
+ if (text === null) return null;
508
+ const scale = text.split("/")[0];
509
+ if (scale && (TYPE_SCALE.has(scale) || scale.startsWith("[") || scale.startsWith("("))) return "type";
510
+ return null;
511
+ }
512
+ /**
513
+ * @param {string} className
514
+ */
515
+ function isControlBoxHeightClass(className) {
516
+ if (isDescendantTargeted(className)) return false;
517
+ const utility = stripImportant(stripVariantPrefixes(className));
518
+ if (!utility) return false;
519
+ if (utility.includes("--control-h-")) return true;
520
+ const height = valueAfter(utility, "h-");
521
+ if (height !== null) return Boolean(height) && !isKeywordBox(height);
522
+ const square = valueAfter(utility, "size-");
523
+ if (square === null) return false;
524
+ if (ICON_GLYPH_SIZES.has(square) || isKeywordBox(square)) return false;
525
+ return Boolean(square);
526
+ }
527
+ /**
528
+ * @param {string} utility
529
+ */
530
+ function isOpticalArbitrary(utility) {
531
+ return /^(?:h|w|size|min-h|min-w|px|pl|pr|ps|pe|gap(?:-[xy])?)-\[\d+(?:\.\d+)?px\]$/.test(utility);
532
+ }
533
+ /**
534
+ * @param {string} className
535
+ */
536
+ function isDataSizeToken(className) {
537
+ return /(?:^|:)data-\[size=/.test(className) && !className.includes("has-data-[size=");
538
+ }
539
+ /**
540
+ * @param {string} className
541
+ * @param {boolean} checkType
542
+ * @returns {string | null}
543
+ */
544
+ function densityOwnedFamily(className, checkType) {
545
+ if (isDescendantTargeted(className)) return null;
546
+ const utility = stripImportant(stripVariantPrefixes(className));
547
+ if (!utility) return null;
548
+ if (readsDensityVariable(utility)) return null;
549
+ if (/\(--[\w-]+\)/.test(utility) || /var\(--/.test(utility)) return null;
550
+ if (/^(?:h|w|size|min-h|min-w|px|pl|pr|ps|pe|gap(?:-[xy])?)-\[/.test(utility)) return null;
551
+ if (isOpticalArbitrary(utility)) return null;
552
+ const box = boxFamily(utility);
553
+ if (box) return box;
554
+ if (!checkType) return null;
555
+ return typeFamily(utility);
556
+ }
557
+ /**
558
+ * @param {string} str
559
+ * @returns {string[]}
560
+ */
561
+ function classTokens$1(str) {
562
+ return str.split(/\s+/).filter(Boolean);
563
+ }
564
+ /**
565
+ * Class tokens from a tv/cn/record arm, excluding `data-[size=…]` tokens
566
+ * which are reported from the literal/template visitors instead.
567
+ *
568
+ * @param {import("estree").Node | null | undefined} node
569
+ * @returns {string[]}
570
+ */
571
+ function recipeTokens(node) {
572
+ return extractStrings(node).flatMap(classTokens$1).filter((token) => !isDataSizeToken(token));
573
+ }
574
+ /**
575
+ * @param {import("estree").Node | null | undefined} node
576
+ * @param {string} name
577
+ */
578
+ function isInsideNamedCall(node, name) {
579
+ for (let current = node?.parent; current; current = current.parent) if (current.type === "CallExpression" && isNamedCall(current.callee, name)) return true;
580
+ return false;
581
+ }
582
+ /**
583
+ * @param {string[]} tokens
584
+ */
585
+ function tokensHaveControlHeightPin(tokens) {
586
+ return tokens.some((token) => token.includes("--control-h-"));
587
+ }
588
+ /**
589
+ * @param {string[]} tokens
590
+ */
591
+ function tokensHaveControlVar(tokens) {
592
+ return tokens.some((token) => CONTROL_VAR_RE.test(token));
593
+ }
594
+ /**
595
+ * @param {string[]} tokens
596
+ */
597
+ function checkTypeForTokens(tokens) {
598
+ return tokens.some((token) => /--control-h-(?:md|lg)\b/.test(token) || /--control-text\b/.test(token));
599
+ }
600
+ /**
601
+ * @param {import("estree").ObjectExpression} obj
602
+ * @returns {Array<{ key: string; value: import("estree").Node }> | null}
603
+ */
604
+ function recordArms(obj) {
605
+ /** @type {Array<{ key: string; value: import("estree").Node }>} */
606
+ const arms = [];
607
+ for (const prop of obj.properties) {
608
+ if (prop.type !== "Property") return null;
609
+ const key = propertyName(prop);
610
+ if (key === null) return null;
611
+ arms.push({
612
+ key,
613
+ value: prop.value
614
+ });
615
+ }
616
+ return arms;
617
+ }
618
+ /**
619
+ * @param {import("estree").ObjectExpression} obj
620
+ */
621
+ function isButtonSizeKeyedRecord(obj) {
622
+ const arms = recordArms(obj);
623
+ if (arms === null || arms.length === 0) return false;
624
+ return arms.every((arm) => BUTTON_SIZE_KEYS.has(arm.key));
625
+ }
626
+ var no_hardcoded_density_metrics_default = defineRule({
627
+ meta: {
628
+ type: "suggestion",
629
+ docs: { description: "Warn when control-box recipes, data-[size] class strings, cn() strings, tv slots, or Button-size-keyed records hardcode density-owned metrics instead of reading --control-* variables" },
630
+ messages: { hardcodedMetric: "Hardcoded density-owned {{family}} `{{utility}}`. Read the matching `--control-*` variable instead." },
631
+ schema: []
632
+ },
633
+ defaultOptions: [],
634
+ createOnce(context) {
635
+ let fileHasControlH = false;
636
+ /**
637
+ * @param {import("estree").Node} node
638
+ * @param {string[]} tokens
639
+ * @param {boolean} checkType
640
+ */
641
+ function reportTokens(node, tokens, checkType) {
642
+ for (const token of tokens) {
643
+ const family = densityOwnedFamily(token, checkType);
644
+ if (!family) continue;
645
+ context.report({
646
+ node,
647
+ messageId: "hardcodedMetric",
648
+ data: {
649
+ family,
650
+ utility: token
651
+ }
652
+ });
653
+ }
654
+ }
655
+ /**
656
+ * @param {import("estree").Node} node
657
+ * @param {string} value
658
+ */
659
+ function reportDataSizeLiterals(node, value) {
660
+ reportTokens(node, classTokens$1(value).filter(isDataSizeToken), false);
661
+ }
662
+ /**
663
+ * @param {import("estree").CallExpression} node
664
+ */
665
+ function reportCnLiterals(node) {
666
+ if (isInsideNamedCall(node, "tv")) return;
667
+ const tokens = recipeTokens(node);
668
+ if (!fileHasControlH && !tokensHaveControlHeightPin(tokens)) return;
669
+ reportTokens(node, tokens, checkTypeForTokens(tokens));
670
+ }
671
+ /**
672
+ * @param {import("estree").ObjectExpression} recipe
673
+ */
674
+ function reportTvSlots(recipe) {
675
+ const slots = objectPropValue(recipe, "slots");
676
+ if (slots?.type !== "ObjectExpression") return;
677
+ for (const prop of slots.properties) {
678
+ if (prop.type !== "Property") continue;
679
+ const tokens = recipeTokens(prop.value);
680
+ if (!fileHasControlH && !tokensHaveControlHeightPin(tokens) && !tokensHaveControlVar(tokens)) continue;
681
+ reportTokens(prop.value, tokens, checkTypeForTokens(tokens));
682
+ }
683
+ }
684
+ /**
685
+ * @param {import("estree").ObjectExpression} node
686
+ */
687
+ function reportSizeKeyedRecord(node) {
688
+ if (isInsideNamedCall(node, "tv")) return;
689
+ if (!isButtonSizeKeyedRecord(node)) return;
690
+ const arms = recordArms(node);
691
+ if (arms === null) return;
692
+ const groups = arms.map((arm) => ({
693
+ key: arm.key,
694
+ node: arm.value,
695
+ tokens: recipeTokens(arm.value)
696
+ }));
697
+ const allTokens = groups.flatMap((group) => group.tokens);
698
+ if (!fileHasControlH && !tokensHaveControlHeightPin(allTokens) && !allTokens.some(isControlBoxHeightClass)) return;
699
+ for (const group of groups) reportTokens(group.node, group.tokens, isMdLgRung(group.key));
700
+ }
701
+ return {
702
+ Program() {
703
+ fileHasControlH = context.sourceCode.getText().includes("--control-h-");
704
+ },
705
+ Literal(node) {
706
+ if (typeof node.value === "string") reportDataSizeLiterals(node, node.value);
707
+ },
708
+ TemplateLiteral(node) {
709
+ for (const quasi of node.quasis) if (typeof quasi.value.cooked === "string") reportDataSizeLiterals(quasi, quasi.value.cooked);
710
+ },
711
+ ObjectExpression(node) {
712
+ reportSizeKeyedRecord(node);
713
+ },
714
+ CallExpression(node) {
715
+ if (isNamedCall(node.callee, "cn")) {
716
+ reportCnLiterals(node);
717
+ return;
718
+ }
719
+ if (!isNamedCall(node.callee, "tv")) return;
720
+ if (node.arguments.length === 0) return;
721
+ const recipe = node.arguments[0];
722
+ if (recipe.type !== "ObjectExpression") return;
723
+ const variants = objectPropValue(recipe, "variants");
724
+ const size = variants?.type === "ObjectExpression" ? objectPropValue(variants, "size") : null;
725
+ if (size?.type === "ObjectExpression") for (const prop of size.properties) {
726
+ if (prop.type !== "Property") continue;
727
+ const sizeKey = propertyName(prop);
728
+ if (sizeKey === null) continue;
729
+ const tokens = recipeTokens(prop.value);
730
+ if (!tokens.some(isControlBoxHeightClass)) continue;
731
+ const checkType = isMdLgRung(sizeKey);
732
+ reportTokens(prop.value, tokens, checkType);
733
+ }
734
+ else {
735
+ /** @type {Array<{ node: import("estree").Node; tokens: string[] }>} */
736
+ const groups = [];
737
+ const base = objectPropValue(recipe, "base");
738
+ if (base) groups.push({
739
+ node: base,
740
+ tokens: recipeTokens(base)
741
+ });
742
+ const box = variants?.type === "ObjectExpression" ? objectPropValue(variants, "box") : null;
743
+ if (box?.type === "ObjectExpression") for (const arm of box.properties) {
744
+ if (arm.type !== "Property") continue;
745
+ groups.push({
746
+ node: arm.value,
747
+ tokens: recipeTokens(arm.value)
748
+ });
749
+ }
750
+ if (groups.some((group) => group.tokens.some(isControlBoxHeightClass))) for (const group of groups) reportTokens(group.node, group.tokens, false);
751
+ }
752
+ reportTvSlots(recipe);
753
+ }
754
+ };
755
+ }
756
+ });
757
+ //#endregion
758
+ //#region ../oxlint-plugin/rules/no-internal-dynamic-import.js
759
+ var no_internal_dynamic_import_default = defineRule({
760
+ createOnce(context) {
761
+ return {
762
+ /** @param {import("estree").ImportExpression} node */
763
+ ImportExpression(node) {
764
+ context.report({
765
+ loc: node.loc,
766
+ messageId: "noDynamicImport"
767
+ });
768
+ } };
769
+ },
770
+ meta: {
771
+ type: "problem",
772
+ docs: { description: "Disallow dynamic import() in library source; apps own code splitting" },
773
+ schema: [],
774
+ messages: { noDynamicImport: "The library never lazy-loads internally. Dynamic import() is forbidden in packages/ui/src." }
775
+ }
776
+ });
777
+ //#endregion
778
+ //#region ../oxlint-plugin/rules/no-local-focus-ring.js
779
+ const ALLOWED_UTILS_SUFFIX = "/src/styles/utils.ts";
780
+ const FOCUS_RING_RE = /(?:^|[\s"'`[])(?:[\w-[\]]+:)*(?:focus(?:-visible|-within)?|has-focus|in-focus|data-\[focus(?:-visible)?\]):(?:[\w-[\]]+:)*ring(?:-|\b)/;
781
+ const OUTLINE_SUPPRESSION_RE = /(?:^|[\s"'`])(?:[\w-[\]./*]+?:)*outline-(?:none|hidden)(?:\s|"|'|`|$)/;
782
+ const FOCUS_WITHIN_BORDER_RE = /(?:^|[\s"'`])(?:[\w-[\]./*]+?:)*(?:group-|peer-)?focus-within(?:\/[\w-]+)?:(?:[\w-[\]./*]+?:)*border(?:-|\b)/;
783
+ /**
784
+ * @param {string} filename
785
+ */
786
+ function isFocusRingUtils(filename) {
787
+ return normalizeFilename(filename).endsWith(ALLOWED_UTILS_SUFFIX);
788
+ }
789
+ /**
790
+ * @param {import("estree").Node | null | undefined} node
791
+ */
792
+ function isFocusVisibleIdentifier(node) {
793
+ return node?.type === "Identifier" && node.name === "isFocusVisible";
794
+ }
795
+ /**
796
+ * @param {string} str
797
+ */
798
+ function hasBareRingClass(str) {
799
+ return /(?:^|[\s"'`])(?:[\w-]+:)*ring(?:-\S+)?/.test(str);
800
+ }
801
+ var no_local_focus_ring_default = defineRule({
802
+ meta: {
803
+ type: "problem",
804
+ docs: { description: "Forbid focus-state ring classes, outline-(none|hidden), and focus-within border colours outside packages/ui/src/styles/utils.ts" },
805
+ messages: { localFocusRing: "Focus-state rings must come from the package-private focusRing recipe in src/styles/utils.ts." },
806
+ schema: []
807
+ },
808
+ defaultOptions: [],
809
+ createOnce(context) {
810
+ /**
811
+ * @param {import("estree").Node} node
812
+ * @param {string[]} collected
813
+ */
814
+ function reportFocusRingStrings(node, collected) {
815
+ for (const value of collected) if (FOCUS_RING_RE.test(value) || OUTLINE_SUPPRESSION_RE.test(value) || FOCUS_WITHIN_BORDER_RE.test(value)) {
816
+ context.report({
817
+ node,
818
+ messageId: "localFocusRing"
819
+ });
820
+ return;
821
+ }
822
+ }
823
+ /**
824
+ * @param {import("estree").Node} node
825
+ */
826
+ function reportRacFocusVisibleRing(node) {
827
+ if (extractStrings(node).some(hasBareRingClass)) context.report({
828
+ node,
829
+ messageId: "localFocusRing"
830
+ });
831
+ }
832
+ let skipFile = false;
833
+ return {
834
+ Program() {
835
+ skipFile = isFocusRingUtils(context.filename);
836
+ },
837
+ Literal(node) {
838
+ if (skipFile) return;
839
+ if (typeof node.value === "string") reportFocusRingStrings(node, [node.value]);
840
+ },
841
+ TemplateLiteral(node) {
842
+ if (skipFile) return;
843
+ reportFocusRingStrings(node, extractStrings(node));
844
+ },
845
+ ConditionalExpression(node) {
846
+ if (skipFile) return;
847
+ if (isFocusVisibleIdentifier(node.test)) reportRacFocusVisibleRing(node);
848
+ },
849
+ LogicalExpression(node) {
850
+ if (skipFile) return;
851
+ if (isFocusVisibleIdentifier(node.left) || isFocusVisibleIdentifier(node.right)) reportRacFocusVisibleRing(node);
852
+ }
853
+ };
854
+ }
855
+ });
856
+ //#endregion
857
+ //#region ../oxlint-plugin/rules/no-primitive-colors.js
858
+ const RULE_NAME$1 = "no-primitive-colors";
859
+ const LITERAL_RULE = "color-literal";
860
+ const ROLE_TOKENS = /* @__PURE__ */ new Set([
861
+ "background",
862
+ "foreground",
863
+ "card",
864
+ "card-foreground",
865
+ "card-soft",
866
+ "card-soft-foreground",
867
+ "popover",
868
+ "popover-foreground",
869
+ "muted",
870
+ "muted-foreground",
871
+ "accent",
872
+ "accent-foreground",
873
+ "feature",
874
+ "feature-bright",
875
+ "feature-foreground",
876
+ "primary",
877
+ "primary-foreground",
878
+ "primary-soft",
879
+ "primary-soft-foreground",
880
+ "secondary",
881
+ "secondary-foreground",
882
+ "secondary-soft",
883
+ "secondary-soft-foreground",
884
+ "brand",
885
+ "brand-foreground",
886
+ "error",
887
+ "error-foreground",
888
+ "error-soft",
889
+ "error-soft-foreground",
890
+ "info",
891
+ "info-foreground",
892
+ "info-soft",
893
+ "info-soft-foreground",
894
+ "success",
895
+ "success-foreground",
896
+ "success-soft",
897
+ "success-soft-foreground",
898
+ "warning",
899
+ "warning-foreground",
900
+ "warning-soft",
901
+ "warning-soft-foreground",
902
+ "border",
903
+ "input",
904
+ "ring",
905
+ "sidebar",
906
+ "sidebar-foreground",
907
+ "sidebar-accent",
908
+ "sidebar-accent-foreground",
909
+ "sidebar-border",
910
+ "sidebar-ring",
911
+ "sidebar-brand",
912
+ "sidebar-brand-foreground",
913
+ "right-panel",
914
+ "right-panel-foreground",
915
+ "chart-1",
916
+ "chart-2",
917
+ "chart-3",
918
+ "chart-4",
919
+ "chart-5",
920
+ "chart-6",
921
+ "chart-7",
922
+ "chart-8",
923
+ "sh-identifier",
924
+ "sh-keyword",
925
+ "sh-string",
926
+ "sh-class",
927
+ "sh-property",
928
+ "sh-entity",
929
+ "sh-jsxliterals",
930
+ "sh-sign",
931
+ "sh-comment"
932
+ ]);
933
+ const TAILWIND_COLOR_FAMILIES = /* @__PURE__ */ new Set([
934
+ "red",
935
+ "orange",
936
+ "amber",
937
+ "yellow",
938
+ "lime",
939
+ "green",
940
+ "emerald",
941
+ "teal",
942
+ "cyan",
943
+ "sky",
944
+ "blue",
945
+ "indigo",
946
+ "violet",
947
+ "purple",
948
+ "fuchsia",
949
+ "pink",
950
+ "slate",
951
+ "gray",
952
+ "zinc",
953
+ "neutral",
954
+ "stone",
955
+ "black",
956
+ "white"
957
+ ]);
958
+ const NON_COLOR_UTILITIES = /* @__PURE__ */ new Set([
959
+ "xs",
960
+ "sm",
961
+ "base",
962
+ "lg",
963
+ "xl",
964
+ "2xl",
965
+ "3xl",
966
+ "4xl",
967
+ "left",
968
+ "center",
969
+ "right",
970
+ "justify",
971
+ "wrap",
972
+ "nowrap",
973
+ "balance",
974
+ "pretty",
975
+ "ellipsis",
976
+ "clip",
977
+ "transparent",
978
+ "current",
979
+ "inherit",
980
+ "none",
981
+ "auto",
982
+ "color",
983
+ "0",
984
+ "2",
985
+ "4",
986
+ "8",
987
+ "t",
988
+ "r",
989
+ "b",
990
+ "l",
991
+ "x",
992
+ "y",
993
+ "solid",
994
+ "dashed",
995
+ "dotted",
996
+ "double",
997
+ "hidden",
998
+ "collapse",
999
+ "separate",
1000
+ "1",
1001
+ "inset",
1002
+ "inner"
1003
+ ]);
1004
+ const NON_COLOR_PATTERNS = [
1005
+ /^linear-to-[trbl]{1,2}$/,
1006
+ /^[trblxy]-\d+$/,
1007
+ /^offset-\d+$/,
1008
+ /^\d+$/,
1009
+ /^clip-.+$/
1010
+ ];
1011
+ const TOKEN_RE = /(?:^|[^a-zA-Z0-9-])(((?:[a-z-]+:)*)?(?:bg|border|text|ring(?:-offset)?|fill|stroke|placeholder|caret|accent|decoration|divide|outline|from|via|to)-([a-z][a-z0-9-]*)(?:-\d{2,3})?(?:\/[0-9]{1,3})?)/gim;
1012
+ const ARBITRARY_COLOR_RE = /\[(?:#[0-9a-fA-F]{3,8}(?:\/[\d.]+)?|(?:oklch|oklab|lab|lch|rgb|rgba|hsl|hsla|hwb)\()/i;
1013
+ const ALLOWED_EXACT_CLASSES = [
1014
+ "bg-black/10",
1015
+ "outline-black/10",
1016
+ "bg-[repeating-linear-gradient(45deg,transparent,transparent_8px,rgb(0_0_0/0.02)_8px,rgb(0_0_0/0.02)_16px)]"
1017
+ ];
1018
+ /**
1019
+ * @param {string} tokenName
1020
+ */
1021
+ function isNonColorUtility(tokenName) {
1022
+ if (NON_COLOR_UTILITIES.has(tokenName)) return true;
1023
+ return NON_COLOR_PATTERNS.some((pattern) => pattern.test(tokenName));
1024
+ }
1025
+ /**
1026
+ * @param {string} token
1027
+ */
1028
+ function isAllowedExactClass(token) {
1029
+ return ALLOWED_EXACT_CLASSES.includes(token);
1030
+ }
1031
+ /**
1032
+ * Whole class tokens only. Variant prefixes are part of the
1033
+ * token, so `hover:bg-black/10` is not the documented `bg-black/10` literal.
1034
+ *
1035
+ * @param {string} str
1036
+ */
1037
+ function stripAllowedClasses(str) {
1038
+ return str.split(/\s+/).filter((token) => token.length > 0 && !isAllowedExactClass(token)).join(" ");
1039
+ }
1040
+ /**
1041
+ * @param {string} str
1042
+ */
1043
+ function findPrimitiveColor(str) {
1044
+ TOKEN_RE.lastIndex = 0;
1045
+ let match;
1046
+ while (match = TOKEN_RE.exec(str)) {
1047
+ const fullToken = match[1];
1048
+ const colorFamily = match[3];
1049
+ if (!fullToken || !colorFamily) continue;
1050
+ const tokenName = colorFamily.replace(/\/\d+$/, "");
1051
+ if (isNonColorUtility(tokenName)) continue;
1052
+ if (ROLE_TOKENS.has(tokenName)) continue;
1053
+ const primitiveFamily = tokenName.replace(/-\d+$/, "");
1054
+ if (TAILWIND_COLOR_FAMILIES.has(primitiveFamily) || TAILWIND_COLOR_FAMILIES.has(tokenName)) return fullToken;
1055
+ }
1056
+ return null;
1057
+ }
1058
+ /**
1059
+ * @param {string} str
1060
+ */
1061
+ function hasForbiddenColorLiteral(str) {
1062
+ return ARBITRARY_COLOR_RE.test(str);
1063
+ }
1064
+ var no_primitive_colors_default = defineRule({
1065
+ meta: {
1066
+ type: "problem",
1067
+ docs: { description: "Disallow raw palette classes and color literals; use role tokens" },
1068
+ messages: {
1069
+ [RULE_NAME$1]: "Avoid raw palette classes (e.g. `bg-white`, `text-slate-500`). Style with role tokens only.",
1070
+ [LITERAL_RULE]: "Avoid hex/oklch/rgb color literals in class strings. Style with role tokens only."
1071
+ },
1072
+ schema: []
1073
+ },
1074
+ defaultOptions: [],
1075
+ createOnce(context) {
1076
+ /**
1077
+ * @param {import("estree").Node} node
1078
+ * @param {string[]} collected
1079
+ */
1080
+ function reportColorIssues(node, collected) {
1081
+ for (const raw of collected) {
1082
+ const value = stripAllowedClasses(raw);
1083
+ if (findPrimitiveColor(value)) {
1084
+ context.report({
1085
+ node,
1086
+ messageId: RULE_NAME$1
1087
+ });
1088
+ return;
1089
+ }
1090
+ if (hasForbiddenColorLiteral(value)) {
1091
+ context.report({
1092
+ node,
1093
+ messageId: LITERAL_RULE
1094
+ });
1095
+ return;
1096
+ }
1097
+ }
1098
+ }
1099
+ return {
1100
+ JSXAttribute(node) {
1101
+ const name = node.name.type === "JSXIdentifier" ? node.name.name : void 0;
1102
+ if (name !== "className" && name !== "class") return;
1103
+ if (node.value) reportColorIssues(node, extractStrings(node.value));
1104
+ },
1105
+ CallExpression(node) {
1106
+ if (!isNamedCall(node.callee, "tv") && !isNamedCall(node.callee, "cn")) return;
1107
+ reportColorIssues(node, extractStrings(node));
1108
+ },
1109
+ Literal(node) {
1110
+ if (typeof node.value === "string") reportColorIssues(node, [node.value]);
1111
+ },
1112
+ TemplateLiteral(node) {
1113
+ reportColorIssues(node, extractStrings(node));
1114
+ }
1115
+ };
1116
+ }
1117
+ });
1118
+ //#endregion
1119
+ //#region ../oxlint-plugin/forbidden-rac-packages.js
1120
+ /**
1121
+ * React Aria packages restricted to the quarantine directory, including
1122
+ * their `@react-aria/*` and `@react-stately/*` dependencies.
1123
+ *
1124
+ * Package-owned policy used by `elmera/no-rac-outside-quarantine`.
1125
+ *
1126
+ * @type {readonly string[]}
1127
+ */
1128
+ const FORBIDDEN_RAC_PACKAGES = Object.freeze([
1129
+ "react-aria-components",
1130
+ "react-aria",
1131
+ "@internationalized/date",
1132
+ "@react-aria",
1133
+ "@react-stately"
1134
+ ]);
1135
+ /**
1136
+ * @param {string} specifier
1137
+ * @returns {boolean}
1138
+ */
1139
+ function isForbiddenRacSpecifier(specifier) {
1140
+ for (const name of FORBIDDEN_RAC_PACKAGES) if (specifier === name || specifier.startsWith(`${name}/`)) return true;
1141
+ return false;
1142
+ }
1143
+ //#endregion
1144
+ //#region ../oxlint-plugin/rules/no-rac-outside-quarantine.js
1145
+ /**
1146
+ * @param {string} filename
1147
+ */
1148
+ function isReactAriaQuarantine(filename) {
1149
+ return normalizeFilename(filename).includes("/src/react-aria/");
1150
+ }
1151
+ /**
1152
+ * @param {import("estree").Node | null | undefined} source
1153
+ * @returns {string | null}
1154
+ */
1155
+ function specifierFromSource(source) {
1156
+ if (source?.type === "Literal" && typeof source.value === "string") return source.value;
1157
+ return null;
1158
+ }
1159
+ var no_rac_outside_quarantine_default = defineRule({
1160
+ meta: {
1161
+ type: "problem",
1162
+ docs: { description: "Forbid react-aria-components, react-aria, @internationalized/date, and the scoped @react-aria/* / @react-stately/* packages outside src/react-aria/**" },
1163
+ messages: { quarantined: "`{{specifier}}` may only be imported from packages/ui/src/react-aria/** (quarantine)." },
1164
+ schema: []
1165
+ },
1166
+ defaultOptions: [],
1167
+ createOnce(context) {
1168
+ let skipFile = false;
1169
+ /**
1170
+ * @param {import("estree").Node} node
1171
+ * @param {string | null} specifier
1172
+ */
1173
+ function reportIfForbidden(node, specifier) {
1174
+ if (skipFile || specifier === null || !isForbiddenRacSpecifier(specifier)) return;
1175
+ context.report({
1176
+ node,
1177
+ messageId: "quarantined",
1178
+ data: { specifier }
1179
+ });
1180
+ }
1181
+ return {
1182
+ Program() {
1183
+ skipFile = isReactAriaQuarantine(context.filename);
1184
+ },
1185
+ ImportDeclaration(node) {
1186
+ reportIfForbidden(node, specifierFromSource(node.source));
1187
+ },
1188
+ ExportNamedDeclaration(node) {
1189
+ reportIfForbidden(node, specifierFromSource(node.source));
1190
+ },
1191
+ ExportAllDeclaration(node) {
1192
+ reportIfForbidden(node, specifierFromSource(node.source));
1193
+ },
1194
+ ImportExpression(node) {
1195
+ reportIfForbidden(node, specifierFromSource(node.source));
1196
+ }
1197
+ };
1198
+ }
1199
+ });
1200
+ //#endregion
1201
+ //#region ../oxlint-plugin/rules/no-raw-class-map.js
1202
+ /**
1203
+ * Exact utilities that are legal class tokens without a hyphenated suffix.
1204
+ * `z-*` is omitted on purpose: `overlayLayer = "z-50"` is the one-owner keep.
1205
+ */
1206
+ const EXACT_UTILITIES = /* @__PURE__ */ new Set([
1207
+ "flex",
1208
+ "grid",
1209
+ "block",
1210
+ "inline",
1211
+ "inline-block",
1212
+ "inline-flex",
1213
+ "inline-grid",
1214
+ "inline-table",
1215
+ "contents",
1216
+ "hidden",
1217
+ "visible",
1218
+ "invisible",
1219
+ "collapse",
1220
+ "isolate",
1221
+ "relative",
1222
+ "absolute",
1223
+ "sticky",
1224
+ "fixed",
1225
+ "static",
1226
+ "grow",
1227
+ "shrink",
1228
+ "truncate",
1229
+ "underline",
1230
+ "overline",
1231
+ "line-through",
1232
+ "no-underline",
1233
+ "italic",
1234
+ "not-italic",
1235
+ "uppercase",
1236
+ "lowercase",
1237
+ "capitalize",
1238
+ "normal-case",
1239
+ "border",
1240
+ "rounded",
1241
+ "shadow",
1242
+ "ring",
1243
+ "outline",
1244
+ "blur",
1245
+ "group",
1246
+ "peer",
1247
+ "container",
1248
+ "table",
1249
+ "table-cell",
1250
+ "table-row",
1251
+ "table-column",
1252
+ "list-item",
1253
+ "flow-root",
1254
+ "antialiased",
1255
+ "subpixel-antialiased",
1256
+ "sr-only",
1257
+ "not-sr-only",
1258
+ "tabular-nums",
1259
+ "select-none",
1260
+ "select-text",
1261
+ "select-all",
1262
+ "select-auto",
1263
+ "pointer-events-none",
1264
+ "pointer-events-auto",
1265
+ "appearance-none",
1266
+ "resize",
1267
+ "resize-none",
1268
+ "resize-x",
1269
+ "resize-y",
1270
+ "not-prose",
1271
+ "prose"
1272
+ ]);
1273
+ /**
1274
+ * Hyphenated (or bracket/paren) Tailwind prefixes. Single-letter prefixes keep the
1275
+ * hyphen so `p-` does not match `px-`/`previous`.
1276
+ */
1277
+ const UTILITY_PREFIXES = [
1278
+ "text-",
1279
+ "bg-",
1280
+ "border-",
1281
+ "flex-",
1282
+ "grid-",
1283
+ "gap-",
1284
+ "p-",
1285
+ "px-",
1286
+ "py-",
1287
+ "pt-",
1288
+ "pr-",
1289
+ "pb-",
1290
+ "pl-",
1291
+ "ps-",
1292
+ "pe-",
1293
+ "m-",
1294
+ "mx-",
1295
+ "my-",
1296
+ "mt-",
1297
+ "mr-",
1298
+ "mb-",
1299
+ "ml-",
1300
+ "ms-",
1301
+ "me-",
1302
+ "size-",
1303
+ "h-",
1304
+ "w-",
1305
+ "min-h-",
1306
+ "min-w-",
1307
+ "max-h-",
1308
+ "max-w-",
1309
+ "rounded-",
1310
+ "font-",
1311
+ "items-",
1312
+ "justify-",
1313
+ "self-",
1314
+ "content-",
1315
+ "place-",
1316
+ "shadow-",
1317
+ "ring-",
1318
+ "outline-",
1319
+ "opacity-",
1320
+ "scale-",
1321
+ "blur-",
1322
+ "rotate-",
1323
+ "translate-",
1324
+ "skew-",
1325
+ "origin-",
1326
+ "duration-",
1327
+ "ease-",
1328
+ "delay-",
1329
+ "transition-",
1330
+ "animate-",
1331
+ "slide-",
1332
+ "fade-",
1333
+ "zoom-",
1334
+ "spin-",
1335
+ "cursor-",
1336
+ "pointer-events-",
1337
+ "select-",
1338
+ "overflow-",
1339
+ "overscroll-",
1340
+ "whitespace-",
1341
+ "break-",
1342
+ "leading-",
1343
+ "tracking-",
1344
+ "indent-",
1345
+ "align-",
1346
+ "list-",
1347
+ "decoration-",
1348
+ "underline-offset-",
1349
+ "line-clamp-",
1350
+ "from-",
1351
+ "via-",
1352
+ "to-",
1353
+ "divide-",
1354
+ "space-",
1355
+ "basis-",
1356
+ "grow-",
1357
+ "shrink-",
1358
+ "col-",
1359
+ "row-",
1360
+ "order-",
1361
+ "inset-",
1362
+ "top-",
1363
+ "right-",
1364
+ "bottom-",
1365
+ "left-",
1366
+ "start-",
1367
+ "end-",
1368
+ "object-",
1369
+ "aspect-",
1370
+ "fill-",
1371
+ "stroke-",
1372
+ "accent-",
1373
+ "caret-",
1374
+ "scroll-",
1375
+ "snap-",
1376
+ "touch-",
1377
+ "will-change-",
1378
+ "backdrop-",
1379
+ "drop-shadow-",
1380
+ "brightness-",
1381
+ "contrast-",
1382
+ "saturate-",
1383
+ "hue-rotate-",
1384
+ "grayscale-",
1385
+ "invert-",
1386
+ "sepia-",
1387
+ "mix-blend-",
1388
+ "filter-",
1389
+ "transform-",
1390
+ "caption-",
1391
+ "hyphens-",
1392
+ "columns-",
1393
+ "float-",
1394
+ "clear-",
1395
+ "box-",
1396
+ "isolation-",
1397
+ "hit-area-",
1398
+ "auto-rows-",
1399
+ "auto-cols-",
1400
+ "@container"
1401
+ ];
1402
+ /**
1403
+ * @param {string} filename
1404
+ */
1405
+ function isTestFile$1(filename) {
1406
+ return filename.endsWith(".test.ts") || filename.endsWith(".test.tsx") || filename.endsWith(".browser.test.tsx") || filename.endsWith(".test-d.tsx");
1407
+ }
1408
+ /**
1409
+ * @param {string} filename
1410
+ */
1411
+ function isSkippedPath(filename) {
1412
+ const normalized = normalizeFilename(filename);
1413
+ if (isTestFile$1(normalized)) return true;
1414
+ if (normalized.includes("/intl/")) return true;
1415
+ if (normalized.includes("/generated/")) return true;
1416
+ return false;
1417
+ }
1418
+ /**
1419
+ * @param {import("estree").Node | null | undefined} node
1420
+ */
1421
+ function unwrap(node) {
1422
+ let current = node;
1423
+ while (current) {
1424
+ if (current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "ParenthesizedExpression" || current.type === "ChainExpression") {
1425
+ current = current.expression;
1426
+ continue;
1427
+ }
1428
+ break;
1429
+ }
1430
+ return current;
1431
+ }
1432
+ /**
1433
+ * @param {string} str
1434
+ */
1435
+ function classTokens(str) {
1436
+ return str.split(/\s+/).filter(Boolean);
1437
+ }
1438
+ /**
1439
+ * Last `:` outside brackets, then strip important/negative modifiers.
1440
+ * @param {string} token
1441
+ */
1442
+ function utilityOf(token) {
1443
+ let depth = 0;
1444
+ let lastColon = -1;
1445
+ for (let i = 0; i < token.length; i += 1) {
1446
+ const ch = token[i];
1447
+ if (ch === "[") depth += 1;
1448
+ else if (ch === "]") depth = Math.max(0, depth - 1);
1449
+ else if (ch === ":" && depth === 0) lastColon = i;
1450
+ }
1451
+ let utility = lastColon === -1 ? token : token.slice(lastColon + 1);
1452
+ if (utility.startsWith("!")) utility = utility.slice(1);
1453
+ if (utility.endsWith("!")) utility = utility.slice(0, -1);
1454
+ if (utility.startsWith("-") && utility.length > 1 && /[a-z@]/i.test(utility[1])) utility = utility.slice(1);
1455
+ return utility;
1456
+ }
1457
+ /**
1458
+ * @param {string} token
1459
+ */
1460
+ function isArbitraryProperty(token) {
1461
+ return token.startsWith("[") && token.endsWith("]") && (token.startsWith("[--") || token.includes(":"));
1462
+ }
1463
+ /**
1464
+ * @param {string} token
1465
+ */
1466
+ function isPrefixedOrArbitraryUtility(token) {
1467
+ if (!token) return false;
1468
+ if (isArbitraryProperty(token)) return true;
1469
+ if (token.startsWith("group/") || token.startsWith("peer/")) return true;
1470
+ return UTILITY_PREFIXES.some((prefix) => token.startsWith(prefix));
1471
+ }
1472
+ /**
1473
+ * @param {string} token
1474
+ */
1475
+ function isTailwindUtility(token) {
1476
+ if (!token) return false;
1477
+ if (isPrefixedOrArbitraryUtility(token)) return true;
1478
+ return EXACT_UTILITIES.has(token);
1479
+ }
1480
+ /**
1481
+ * @param {string} raw
1482
+ */
1483
+ function isTailwindToken(raw) {
1484
+ return isTailwindUtility(utilityOf(raw));
1485
+ }
1486
+ /**
1487
+ * A string looks like a class list when it has a hyphenated/arbitrary utility, or when
1488
+ * every token is a utility (`"flex isolate"`). Exact-only hits such as the English word
1489
+ * `block` in a comment are not enough.
1490
+ *
1491
+ * @param {string} str
1492
+ */
1493
+ function looksLikeClassString(str) {
1494
+ const tokens = classTokens(str);
1495
+ if (tokens.length === 0) return false;
1496
+ const hits = tokens.filter(isTailwindToken);
1497
+ if (hits.length === 0) return false;
1498
+ if (hits.some((token) => isPrefixedOrArbitraryUtility(utilityOf(token)))) return true;
1499
+ return hits.length === tokens.length;
1500
+ }
1501
+ /**
1502
+ * @param {string} name
1503
+ */
1504
+ function looksLikeClassIdentifier(name) {
1505
+ return /(?:Class(?:es|Name)?|classNames)$/.test(name);
1506
+ }
1507
+ /**
1508
+ * @param {import("estree").Node | null | undefined} node
1509
+ * @param {string[]} out
1510
+ */
1511
+ function collectValueStrings(node, out) {
1512
+ const current = unwrap(node);
1513
+ if (!current) return;
1514
+ switch (current.type) {
1515
+ case "Literal":
1516
+ if (typeof current.value === "string") out.push(current.value);
1517
+ break;
1518
+ case "TemplateLiteral":
1519
+ out.push(...extractStrings(current));
1520
+ break;
1521
+ case "ObjectExpression":
1522
+ for (const prop of current.properties) if (prop.type === "Property") collectValueStrings(prop.value, out);
1523
+ break;
1524
+ case "ArrayExpression": for (const el of current.elements) if (el) collectValueStrings(el, out);
1525
+ }
1526
+ }
1527
+ /**
1528
+ * @param {import("estree").ObjectExpression} node
1529
+ */
1530
+ function objectLooksLikeClassMap(node) {
1531
+ /** @type {string[]} */
1532
+ const values = [];
1533
+ collectValueStrings(node, values);
1534
+ return values.some(looksLikeClassString);
1535
+ }
1536
+ /**
1537
+ * @param {import("estree").TemplateLiteral} node
1538
+ */
1539
+ function templateLooksLikeClassString(node) {
1540
+ if (looksLikeClassString(node.quasis.map((quasi) => quasi.value.cooked ?? "").join(" "))) return true;
1541
+ if (node.expressions.length === 0) return false;
1542
+ if (!node.expressions.every((expr) => expr.type === "Identifier")) return false;
1543
+ return node.expressions.some((expr) => expr.type === "Identifier" && looksLikeClassIdentifier(expr.name));
1544
+ }
1545
+ var no_raw_class_map_default = defineRule({
1546
+ meta: {
1547
+ type: "problem",
1548
+ docs: { description: "Forbid raw Tailwind class maps and hand-spelled class constants. Maps with an axis or two-plus slots are tv() recipes; a single axis-less string is cn(). Any call-expression initializer is accepted. EXACT_UTILITIES and UTILITY_PREFIXES are the heuristic boundary for 'looks like Tailwind'. Skips tests, *.test-d.tsx, intl dictionaries, and generated files" },
1549
+ messages: { rawClassMap: "Class maps with an axis or two or more slots are `tv()` recipes; a single axis-less class string is `cn(\"…\")`. Resolved string constants are legal when they are `cn(…)` or a recipe call, never spelled by hand." },
1550
+ schema: []
1551
+ },
1552
+ defaultOptions: [],
1553
+ createOnce(context) {
1554
+ let skipFile = false;
1555
+ /**
1556
+ * @param {import("estree").Node} node
1557
+ */
1558
+ function report(node) {
1559
+ context.report({
1560
+ node,
1561
+ messageId: "rawClassMap"
1562
+ });
1563
+ }
1564
+ return {
1565
+ Program() {
1566
+ skipFile = isSkippedPath(context.filename);
1567
+ },
1568
+ VariableDeclarator(node) {
1569
+ if (skipFile || !node.init) return;
1570
+ const init = unwrap(node.init);
1571
+ if (!init) return;
1572
+ if (init.type === "CallExpression") return;
1573
+ if (init.type === "ObjectExpression") {
1574
+ if (objectLooksLikeClassMap(init)) report(init);
1575
+ return;
1576
+ }
1577
+ if (init.type === "Literal" && typeof init.value === "string") {
1578
+ if (looksLikeClassString(init.value)) report(init);
1579
+ return;
1580
+ }
1581
+ if (init.type === "TemplateLiteral" && templateLooksLikeClassString(init)) report(init);
1582
+ }
1583
+ };
1584
+ }
1585
+ });
1586
+ //#endregion
1587
+ //#region ../oxlint-plugin/rules/no-tailwind-dark-variant.js
1588
+ const RULE_NAME = "no-tailwind-dark-variant";
1589
+ /**
1590
+ * @param {string} str
1591
+ */
1592
+ function hasDarkVariant(str) {
1593
+ return /\bdark:[a-z]+[-\w]*/.test(str);
1594
+ }
1595
+ /**
1596
+ * @param {import("estree").Node} node
1597
+ */
1598
+ function isInsideJsxAttribute(node) {
1599
+ let current = node.parent;
1600
+ while (current) {
1601
+ if (current.type === "JSXAttribute") return true;
1602
+ current = current.parent;
1603
+ }
1604
+ return false;
1605
+ }
1606
+ var no_tailwind_dark_variant_default = defineRule({
1607
+ meta: {
1608
+ type: "problem",
1609
+ docs: { description: "Disallow Tailwind dark: variant usage in library source" },
1610
+ messages: { [RULE_NAME]: "Avoid Tailwind's dark: variant. The dark axis is token-reserved behind [data-theme=\"dark\"]." },
1611
+ schema: []
1612
+ },
1613
+ defaultOptions: [],
1614
+ createOnce(context) {
1615
+ /**
1616
+ * @param {import("estree").Node} node
1617
+ * @param {string[]} collected
1618
+ */
1619
+ function reportIfDark(node, collected) {
1620
+ for (const s of collected) if (hasDarkVariant(s)) {
1621
+ context.report({
1622
+ node,
1623
+ messageId: RULE_NAME
1624
+ });
1625
+ return;
1626
+ }
1627
+ }
1628
+ return {
1629
+ JSXAttribute(node) {
1630
+ const name = node.name.type === "JSXIdentifier" ? node.name.name : void 0;
1631
+ if (name !== "className" && name !== "class") return;
1632
+ if (node.value) reportIfDark(node, extractStrings(node.value));
1633
+ },
1634
+ Literal(node) {
1635
+ if (typeof node.value !== "string" || !hasDarkVariant(node.value) || isInsideJsxAttribute(node)) return;
1636
+ context.report({
1637
+ node,
1638
+ messageId: RULE_NAME
1639
+ });
1640
+ },
1641
+ TemplateLiteral(node) {
1642
+ if (isInsideJsxAttribute(node)) return;
1643
+ if (extractStrings(node).some(hasDarkVariant)) context.report({
1644
+ node,
1645
+ messageId: RULE_NAME
1646
+ });
1647
+ }
1648
+ };
1649
+ }
1650
+ });
1651
+ //#endregion
1652
+ //#region ../oxlint-plugin/rules/require-icon-button-label.js
1653
+ const ICON_SIZE_PREFIX = "icon";
1654
+ const TEXT_CONTENT_NAMES = /* @__PURE__ */ new Set([
1655
+ "Span",
1656
+ "Text",
1657
+ "ItemTitle",
1658
+ "Title"
1659
+ ]);
1660
+ /**
1661
+ * Statically known string from a JSX attribute value or child expression.
1662
+ * Identifiers and interpolated templates stay unknown.
1663
+ *
1664
+ * @param {import("estree").Node | null | undefined} node
1665
+ * @returns {string | null}
1666
+ */
1667
+ function getStaticString(node) {
1668
+ if (!node) return null;
1669
+ if (node.type === "Literal") return typeof node.value === "string" ? node.value : null;
1670
+ if (node.type === "TemplateLiteral") {
1671
+ if (node.expressions.length !== 0) return null;
1672
+ const cooked = node.quasis[0]?.value.cooked;
1673
+ return typeof cooked === "string" ? cooked : null;
1674
+ }
1675
+ if (node.type === "JSXExpressionContainer") return getStaticString(node.expression);
1676
+ return null;
1677
+ }
1678
+ /**
1679
+ * Known nonempty strings count. Known empty/whitespace, bare, null, and false do not.
1680
+ * Unresolved expressions stay permissive.
1681
+ *
1682
+ * @param {import("estree").JSXOpeningElement} node
1683
+ */
1684
+ function hasUsableAriaLabel(node) {
1685
+ return node.attributes.some((attr) => {
1686
+ if (attr.type !== "JSXAttribute" || attr.name.name !== "aria-label") return false;
1687
+ if (!attr.value) return false;
1688
+ const staticString = getStaticString(attr.value);
1689
+ if (staticString !== null) return staticString.trim().length > 0;
1690
+ if ((attr.value.type === "JSXExpressionContainer" ? attr.value.expression : attr.value).type === "Literal") return false;
1691
+ return true;
1692
+ });
1693
+ }
1694
+ function hasSlot(node) {
1695
+ return node.attributes.some((attr) => attr.type === "JSXAttribute" && attr.name.name === "slot");
1696
+ }
1697
+ /**
1698
+ * Size/variant may also use an identifier's name as a heuristic (size={icon}).
1699
+ * That heuristic is not a known runtime string.
1700
+ *
1701
+ * @param {import("estree").JSXAttribute} attr
1702
+ * @returns {string | null}
1703
+ */
1704
+ function getSizeOrVariantValue(attr) {
1705
+ const staticValue = getStaticString(attr.value);
1706
+ if (staticValue !== null) return staticValue;
1707
+ if (attr.value?.type === "JSXExpressionContainer" && attr.value.expression.type === "Identifier") return attr.value.expression.name;
1708
+ return null;
1709
+ }
1710
+ function isIconVariant(node) {
1711
+ return node.attributes.some((attr) => {
1712
+ if (attr.type !== "JSXAttribute" || attr.name.name !== "variant") return false;
1713
+ return getSizeOrVariantValue(attr) === "icon";
1714
+ });
1715
+ }
1716
+ function isIconSize(node) {
1717
+ return node.attributes.some((attr) => {
1718
+ if (attr.type !== "JSXAttribute" || attr.name.name !== "size") return false;
1719
+ const value = getSizeOrVariantValue(attr);
1720
+ if (!value) return false;
1721
+ return value.startsWith(ICON_SIZE_PREFIX);
1722
+ });
1723
+ }
1724
+ function getElementName(nameNode) {
1725
+ if (nameNode.type === "JSXIdentifier") return nameNode.name;
1726
+ if (nameNode.type === "JSXMemberExpression") return nameNode.property.name;
1727
+ return null;
1728
+ }
1729
+ function hasTextContent(node) {
1730
+ if (!node.children || node.children.length === 0) return false;
1731
+ return node.children.some((child) => {
1732
+ if (child.type === "JSXText") return child.value.trim().length > 0;
1733
+ if (child.type === "JSXExpressionContainer") {
1734
+ const expr = child.expression;
1735
+ if (expr.type === "CallExpression") return true;
1736
+ const staticString = getStaticString(expr);
1737
+ if (staticString !== null) return staticString.trim().length > 0;
1738
+ if (expr.type === "TemplateLiteral") return true;
1739
+ }
1740
+ if (child.type === "JSXElement") {
1741
+ const name = getElementName(child.openingElement.name);
1742
+ if (name && TEXT_CONTENT_NAMES.has(name)) return true;
1743
+ if (hasTextContent(child)) return true;
1744
+ }
1745
+ if (child.type === "JSXFragment") return hasTextContent(child);
1746
+ return false;
1747
+ });
1748
+ }
1749
+ var require_icon_button_label_default = defineRule({
1750
+ createOnce(context) {
1751
+ return {
1752
+ /** @param {import("estree").JSXOpeningElement} node */
1753
+ JSXOpeningElement(node) {
1754
+ const name = getElementName(node.name);
1755
+ if (name === null || !name.endsWith("Button")) return;
1756
+ if (!isIconVariant(node) && !isIconSize(node)) return;
1757
+ if (hasUsableAriaLabel(node)) return;
1758
+ if (hasSlot(node)) return;
1759
+ const parent = node.parent.type === "JSXElement" ? node.parent : null;
1760
+ if (parent && hasTextContent(parent)) return;
1761
+ context.report({
1762
+ loc: node.loc,
1763
+ messageId: "missingAriaLabel",
1764
+ data: { component: name }
1765
+ });
1766
+ } };
1767
+ },
1768
+ meta: {
1769
+ type: "problem",
1770
+ docs: { description: "Require a nonempty aria-label on icon-only *Button JSX (any name ending in Button, including InputGroup.Button) whose size starts with icon or variant is icon; static expression strings and templates count" },
1771
+ schema: [],
1772
+ messages: { missingAriaLabel: "Icon-only <{{component}}> must have an aria-label for accessibility. Add aria-label={t(\"...\")} to provide a screen reader label." }
1773
+ }
1774
+ });
1775
+ //#endregion
1776
+ //#region ../oxlint-plugin/rules/restrict-browser-helper-copy.js
1777
+ const HELPERS = /* @__PURE__ */ new Set([
1778
+ "roleNamed",
1779
+ "headingNamed",
1780
+ "cssVarColor",
1781
+ "textNamed",
1782
+ "textboxNamed",
1783
+ "stampDensity",
1784
+ "px"
1785
+ ]);
1786
+ const OWNER_SUFFIX$1 = "/test/themed-browser-render.tsx";
1787
+ /**
1788
+ * @param {string} filename
1789
+ */
1790
+ function isOwner$1(filename) {
1791
+ return normalizeFilename(filename).endsWith(OWNER_SUFFIX$1);
1792
+ }
1793
+ /**
1794
+ * @param {import("estree").Node | null | undefined} id
1795
+ * @returns {string | null}
1796
+ */
1797
+ function helperName(id) {
1798
+ if (id?.type !== "Identifier" || !HELPERS.has(id.name)) return null;
1799
+ return id.name;
1800
+ }
1801
+ var restrict_browser_helper_copy_default = defineRule({
1802
+ meta: {
1803
+ type: "problem",
1804
+ docs: { description: "Forbid local declarations of the shared browser-harness helpers (roleNamed, headingNamed, cssVarColor, textNamed, textboxNamed, stampDensity, px) outside packages/ui/test/themed-browser-render.tsx" },
1805
+ messages: { localCopy: "Import {{helper}} from packages/ui/test/themed-browser-render.tsx. Suites do not re-declare harness helpers." },
1806
+ schema: []
1807
+ },
1808
+ defaultOptions: [],
1809
+ createOnce(context) {
1810
+ let skipFile = false;
1811
+ return {
1812
+ Program() {
1813
+ skipFile = isOwner$1(context.filename);
1814
+ },
1815
+ FunctionDeclaration(node) {
1816
+ if (skipFile) return;
1817
+ const helper = helperName(node.id);
1818
+ if (helper === null) return;
1819
+ context.report({
1820
+ node: node.id,
1821
+ messageId: "localCopy",
1822
+ data: { helper }
1823
+ });
1824
+ },
1825
+ VariableDeclarator(node) {
1826
+ if (skipFile) return;
1827
+ const helper = helperName(node.id);
1828
+ if (helper === null) return;
1829
+ context.report({
1830
+ node: node.id,
1831
+ messageId: "localCopy",
1832
+ data: { helper }
1833
+ });
1834
+ }
1835
+ };
1836
+ }
1837
+ });
1838
+ //#endregion
1839
+ //#region ../oxlint-plugin/rules/restrict-focus-ring-call.js
1840
+ const ALLOWED_SUFFIXES = ["/src/styles/utils.ts", "/src/react-aria/link/link.tsx"];
1841
+ /**
1842
+ * @param {string} filename
1843
+ */
1844
+ function isTestFile(filename) {
1845
+ return filename.endsWith(".test.ts") || filename.endsWith(".test.tsx") || filename.endsWith(".browser.test.tsx") || filename.endsWith(".test-d.tsx");
1846
+ }
1847
+ /**
1848
+ * @param {string} filename
1849
+ */
1850
+ function isAllowedOwner(filename) {
1851
+ const normalized = normalizeFilename(filename);
1852
+ if (isTestFile(normalized)) return true;
1853
+ return ALLOWED_SUFFIXES.some((suffix) => normalized.endsWith(suffix));
1854
+ }
1855
+ var restrict_focus_ring_call_default = defineRule({
1856
+ meta: {
1857
+ type: "problem",
1858
+ docs: { description: "Forbid focusRing({…}) calls outside styles/utils.ts except the live isFocusVisible call in react-aria/link" },
1859
+ messages: { restrictedCall: "Fixed focus-ring rungs are the constants exported from styles/utils.ts. The only live `focusRing({…})` call is react-aria/link, which passes `isFocusVisible` per render." },
1860
+ schema: []
1861
+ },
1862
+ defaultOptions: [],
1863
+ createOnce(context) {
1864
+ let skipFile = false;
1865
+ return {
1866
+ Program() {
1867
+ skipFile = isAllowedOwner(context.filename);
1868
+ },
1869
+ CallExpression(node) {
1870
+ if (skipFile || !isNamedCall(node.callee, "focusRing")) return;
1871
+ context.report({
1872
+ node,
1873
+ messageId: "restrictedCall"
1874
+ });
1875
+ }
1876
+ };
1877
+ }
1878
+ });
1879
+ //#endregion
1880
+ //#region ../oxlint-plugin/rules/restrict-package-root-from-script.js
1881
+ const OWNER_SUFFIX = "/scripts/paths.ts";
1882
+ /**
1883
+ * @param {string} filename
1884
+ */
1885
+ function isOwner(filename) {
1886
+ return normalizeFilename(filename).endsWith(OWNER_SUFFIX);
1887
+ }
1888
+ /**
1889
+ * @param {import("estree").Node | null | undefined} node
1890
+ */
1891
+ function isImportMetaUrl(node) {
1892
+ return node?.type === "MemberExpression" && node.object?.type === "MetaProperty" && node.object.meta?.name === "import" && node.object.property?.name === "meta" && node.property?.type === "Identifier" && node.property.name === "url";
1893
+ }
1894
+ /**
1895
+ * @param {import("estree").Node | null | undefined} node
1896
+ */
1897
+ function isFileUrlToPathOfImportMetaUrl(node) {
1898
+ return node?.type === "CallExpression" && isNamedCall(node.callee, "fileURLToPath") && node.arguments.length > 0 && isImportMetaUrl(node.arguments[0]);
1899
+ }
1900
+ var restrict_package_root_from_script_default = defineRule({
1901
+ meta: {
1902
+ type: "problem",
1903
+ docs: { description: "Forbid dirname(fileURLToPath(import.meta.url)) outside packages/ui/scripts/paths.ts" },
1904
+ messages: { usePackageRootFromScript: "Locate the package root with packageRootFromScript(import.meta.url). dirname(fileURLToPath(import.meta.url)) lives only in scripts/paths.ts." },
1905
+ schema: []
1906
+ },
1907
+ defaultOptions: [],
1908
+ createOnce(context) {
1909
+ let skipFile = false;
1910
+ return {
1911
+ Program() {
1912
+ skipFile = isOwner(context.filename);
1913
+ },
1914
+ CallExpression(node) {
1915
+ if (skipFile || !isNamedCall(node.callee, "dirname")) return;
1916
+ if (!isFileUrlToPathOfImportMetaUrl(node.arguments[0])) return;
1917
+ context.report({
1918
+ node,
1919
+ messageId: "usePackageRootFromScript"
1920
+ });
1921
+ }
1922
+ };
1923
+ }
1924
+ });
1925
+ //#endregion
1926
+ //#region ../oxlint-plugin/rules/restrict-process-env.js
1927
+ const MESSAGE = "Direct process.env access is forbidden except the process.env.NODE_ENV comparison in the theme validator module.";
1928
+ const ALLOWED_VALIDATOR_SUFFIX = "/src/theme/validate-theme.ts";
1929
+ /**
1930
+ * @param {import("estree").Node | null | undefined} node
1931
+ * @returns {node is import("estree").Identifier}
1932
+ */
1933
+ function isProcessIdentifier(node) {
1934
+ return node?.type === "Identifier" && node.name === "process";
1935
+ }
1936
+ /**
1937
+ * @param {import("estree").Node | null | undefined} node
1938
+ * @param {boolean} isComputed
1939
+ */
1940
+ function isEnvProperty(node, isComputed) {
1941
+ if (!isComputed) return node?.type === "Identifier" && node.name === "env";
1942
+ return node?.type === "Literal" && node.value === "env";
1943
+ }
1944
+ /**
1945
+ * @param {import("estree").Node | null | undefined} node
1946
+ * @returns {node is import("estree").MemberExpression}
1947
+ */
1948
+ function isProcessEnvMemberExpression(node) {
1949
+ return node?.type === "MemberExpression" && isProcessIdentifier(node.object) && isEnvProperty(node.property, node.computed);
1950
+ }
1951
+ /**
1952
+ * @param {import("estree").Node | null | undefined} node
1953
+ * @param {boolean} isComputed
1954
+ */
1955
+ function isNodeEnvProperty(node, isComputed) {
1956
+ if (!isComputed) return node?.type === "Identifier" && node.name === "NODE_ENV";
1957
+ return node?.type === "Literal" && node.value === "NODE_ENV";
1958
+ }
1959
+ /**
1960
+ * @param {import("estree").MemberExpression} processEnvNode
1961
+ */
1962
+ function isProcessEnvNodeEnv(processEnvNode) {
1963
+ const parent = processEnvNode.parent;
1964
+ return parent?.type === "MemberExpression" && parent.object === processEnvNode && isNodeEnvProperty(parent.property, parent.computed);
1965
+ }
1966
+ /**
1967
+ * @param {string} operator
1968
+ */
1969
+ function isComparisonOperator(operator) {
1970
+ return operator === "===" || operator === "!==" || operator === "==" || operator === "!=";
1971
+ }
1972
+ /**
1973
+ * @param {import("estree").MemberExpression} processEnvNode
1974
+ */
1975
+ function isNodeEnvComparison(processEnvNode) {
1976
+ if (!isProcessEnvNodeEnv(processEnvNode)) return false;
1977
+ const comparison = processEnvNode.parent.parent;
1978
+ return comparison?.type === "BinaryExpression" && isComparisonOperator(comparison.operator);
1979
+ }
1980
+ /**
1981
+ * @param {string} filename
1982
+ */
1983
+ function isThemeValidatorModule(filename) {
1984
+ return normalizeFilename(filename).endsWith(ALLOWED_VALIDATOR_SUFFIX);
1985
+ }
1986
+ var restrict_process_env_default = defineRule({
1987
+ createOnce(context) {
1988
+ return {
1989
+ /** @param {import("estree").MemberExpression} node */
1990
+ MemberExpression(node) {
1991
+ if (!isProcessEnvMemberExpression(node)) return;
1992
+ if (isThemeValidatorModule(context.filename) && isNodeEnvComparison(node)) return;
1993
+ context.report({
1994
+ loc: node.loc,
1995
+ messageId: "restrictedAccess"
1996
+ });
1997
+ } };
1998
+ },
1999
+ meta: {
2000
+ type: "problem",
2001
+ docs: { description: "Disallow direct process.env access except the process.env.NODE_ENV comparison in the theme validator" },
2002
+ schema: [],
2003
+ messages: { restrictedAccess: MESSAGE }
2004
+ }
2005
+ });
2006
+ //#endregion
2007
+ //#region src/oxlint.ts
2008
+ const plugin = eslintCompatPlugin({
2009
+ meta: { name: "elmera" },
2010
+ rules: {
2011
+ "enforce-variant-standard": enforce_variant_standard_default,
2012
+ "facade-reexport-grammar": facade_reexport_grammar_default,
2013
+ "no-field-part-jsx": no_field_part_jsx_default,
2014
+ "no-hardcoded-density-metrics": no_hardcoded_density_metrics_default,
2015
+ "no-internal-dynamic-import": no_internal_dynamic_import_default,
2016
+ "no-local-focus-ring": no_local_focus_ring_default,
2017
+ "no-primitive-colors": no_primitive_colors_default,
2018
+ "no-rac-outside-quarantine": no_rac_outside_quarantine_default,
2019
+ "no-raw-class-map": no_raw_class_map_default,
2020
+ "no-tailwind-dark-variant": no_tailwind_dark_variant_default,
2021
+ "require-icon-button-label": require_icon_button_label_default,
2022
+ "restrict-browser-helper-copy": restrict_browser_helper_copy_default,
2023
+ "restrict-focus-ring-call": restrict_focus_ring_call_default,
2024
+ "restrict-package-root-from-script": restrict_package_root_from_script_default,
2025
+ "restrict-process-env": restrict_process_env_default
2026
+ }
2027
+ });
2028
+ //#endregion
2029
+ export { plugin as default };