@objectstack/lint 10.2.0 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +323 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -5
- package/dist/index.d.ts +30 -5
- package/dist/index.js +317 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -67,7 +67,7 @@ interface WidgetBindingFinding {
|
|
|
67
67
|
/** How to fix (or deliberately suppress) it. */
|
|
68
68
|
hint: string;
|
|
69
69
|
}
|
|
70
|
-
type AnyRec$
|
|
70
|
+
type AnyRec$2 = Record<string, unknown>;
|
|
71
71
|
/**
|
|
72
72
|
* Validate every dashboard widget's dataset binding. Returns the list of
|
|
73
73
|
* findings (empty = clean). Caller decides how to surface them: `error`
|
|
@@ -75,7 +75,7 @@ type AnyRec$1 = Record<string, unknown>;
|
|
|
75
75
|
* should fail validate/build; `warning` findings are advisory and must
|
|
76
76
|
* never fail the build on their own.
|
|
77
77
|
*/
|
|
78
|
-
declare function validateWidgetBindings(stack: AnyRec$
|
|
78
|
+
declare function validateWidgetBindings(stack: AnyRec$2): WidgetBindingFinding[];
|
|
79
79
|
|
|
80
80
|
interface ExprIssue {
|
|
81
81
|
where: string;
|
|
@@ -88,11 +88,36 @@ interface ExprIssue {
|
|
|
88
88
|
*/
|
|
89
89
|
severity?: 'error' | 'warning';
|
|
90
90
|
}
|
|
91
|
-
type AnyRec = Record<string, unknown>;
|
|
91
|
+
type AnyRec$1 = Record<string, unknown>;
|
|
92
92
|
/**
|
|
93
93
|
* Validate every predicate in the stack. Returns the list of issues (empty =
|
|
94
94
|
* clean). Caller decides how to surface / whether to fail the build.
|
|
95
95
|
*/
|
|
96
|
-
declare function validateStackExpressions(stack: AnyRec): ExprIssue[];
|
|
96
|
+
declare function validateStackExpressions(stack: AnyRec$1): ExprIssue[];
|
|
97
|
+
|
|
98
|
+
type StyleSeverity = 'error' | 'warning';
|
|
99
|
+
interface StyleFinding {
|
|
100
|
+
severity: StyleSeverity;
|
|
101
|
+
rule: string;
|
|
102
|
+
/** Human-readable location, e.g. `page "pricing" › node "plan_solo"`. */
|
|
103
|
+
where: string;
|
|
104
|
+
/** Config path, e.g. `pages[0].regions[0].components[1]`. */
|
|
105
|
+
path: string;
|
|
106
|
+
message: string;
|
|
107
|
+
hint: string;
|
|
108
|
+
}
|
|
109
|
+
declare const STYLE_NODE_MISSING_ID = "style-node-missing-id";
|
|
110
|
+
declare const STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
111
|
+
declare const STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
112
|
+
declare const STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
113
|
+
declare const STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
114
|
+
type AnyRec = Record<string, unknown>;
|
|
115
|
+
/**
|
|
116
|
+
* Validate every page's component tree for SDUI styling correctness (ADR-0065).
|
|
117
|
+
* Returns findings (empty = clean). `error` findings describe styles that are
|
|
118
|
+
* silently dropped and should fail validate/build; `warning` findings are
|
|
119
|
+
* advisory (typos, drift, footguns).
|
|
120
|
+
*/
|
|
121
|
+
declare function validateResponsiveStyles(stack: AnyRec): StyleFinding[];
|
|
97
122
|
|
|
98
|
-
export { CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type ExprIssue, MEASURE_AGGREGATE_INCOHERENT, TABLE_COUNT_ONLY, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, validateStackExpressions, validateWidgetBindings };
|
|
123
|
+
export { CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type ExprIssue, MEASURE_AGGREGATE_INCOHERENT, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, validateResponsiveStyles, validateStackExpressions, validateWidgetBindings };
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ interface WidgetBindingFinding {
|
|
|
67
67
|
/** How to fix (or deliberately suppress) it. */
|
|
68
68
|
hint: string;
|
|
69
69
|
}
|
|
70
|
-
type AnyRec$
|
|
70
|
+
type AnyRec$2 = Record<string, unknown>;
|
|
71
71
|
/**
|
|
72
72
|
* Validate every dashboard widget's dataset binding. Returns the list of
|
|
73
73
|
* findings (empty = clean). Caller decides how to surface them: `error`
|
|
@@ -75,7 +75,7 @@ type AnyRec$1 = Record<string, unknown>;
|
|
|
75
75
|
* should fail validate/build; `warning` findings are advisory and must
|
|
76
76
|
* never fail the build on their own.
|
|
77
77
|
*/
|
|
78
|
-
declare function validateWidgetBindings(stack: AnyRec$
|
|
78
|
+
declare function validateWidgetBindings(stack: AnyRec$2): WidgetBindingFinding[];
|
|
79
79
|
|
|
80
80
|
interface ExprIssue {
|
|
81
81
|
where: string;
|
|
@@ -88,11 +88,36 @@ interface ExprIssue {
|
|
|
88
88
|
*/
|
|
89
89
|
severity?: 'error' | 'warning';
|
|
90
90
|
}
|
|
91
|
-
type AnyRec = Record<string, unknown>;
|
|
91
|
+
type AnyRec$1 = Record<string, unknown>;
|
|
92
92
|
/**
|
|
93
93
|
* Validate every predicate in the stack. Returns the list of issues (empty =
|
|
94
94
|
* clean). Caller decides how to surface / whether to fail the build.
|
|
95
95
|
*/
|
|
96
|
-
declare function validateStackExpressions(stack: AnyRec): ExprIssue[];
|
|
96
|
+
declare function validateStackExpressions(stack: AnyRec$1): ExprIssue[];
|
|
97
|
+
|
|
98
|
+
type StyleSeverity = 'error' | 'warning';
|
|
99
|
+
interface StyleFinding {
|
|
100
|
+
severity: StyleSeverity;
|
|
101
|
+
rule: string;
|
|
102
|
+
/** Human-readable location, e.g. `page "pricing" › node "plan_solo"`. */
|
|
103
|
+
where: string;
|
|
104
|
+
/** Config path, e.g. `pages[0].regions[0].components[1]`. */
|
|
105
|
+
path: string;
|
|
106
|
+
message: string;
|
|
107
|
+
hint: string;
|
|
108
|
+
}
|
|
109
|
+
declare const STYLE_NODE_MISSING_ID = "style-node-missing-id";
|
|
110
|
+
declare const STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
111
|
+
declare const STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
112
|
+
declare const STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
113
|
+
declare const STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
114
|
+
type AnyRec = Record<string, unknown>;
|
|
115
|
+
/**
|
|
116
|
+
* Validate every page's component tree for SDUI styling correctness (ADR-0065).
|
|
117
|
+
* Returns findings (empty = clean). `error` findings describe styles that are
|
|
118
|
+
* silently dropped and should fail validate/build; `warning` findings are
|
|
119
|
+
* advisory (typos, drift, footguns).
|
|
120
|
+
*/
|
|
121
|
+
declare function validateResponsiveStyles(stack: AnyRec): StyleFinding[];
|
|
97
122
|
|
|
98
|
-
export { CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type ExprIssue, MEASURE_AGGREGATE_INCOHERENT, TABLE_COUNT_ONLY, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, validateStackExpressions, validateWidgetBindings };
|
|
123
|
+
export { CHART_CONFIG_MISSING, CHART_FIELD_UNKNOWN, type ExprIssue, MEASURE_AGGREGATE_INCOHERENT, STYLE_CLASSNAME_TAILWIND, STYLE_NODE_MISSING_ID, STYLE_RESPONSIVE_NO_BASE, STYLE_UNKNOWN_CSS_PROPERTY, STYLE_UNKNOWN_TOKEN, type StyleFinding, type StyleSeverity, TABLE_COUNT_ONLY, WIDGET_DATASET_UNKNOWN, WIDGET_DIMENSION_UNKNOWN, WIDGET_MEASURE_UNKNOWN, type WidgetBindingFinding, type WidgetBindingSeverity, validateResponsiveStyles, validateStackExpressions, validateWidgetBindings };
|
package/dist/index.js
CHANGED
|
@@ -370,14 +370,331 @@ function validateStackExpressions(stack) {
|
|
|
370
370
|
}
|
|
371
371
|
return issues;
|
|
372
372
|
}
|
|
373
|
+
|
|
374
|
+
// src/validate-responsive-styles.ts
|
|
375
|
+
var STYLE_NODE_MISSING_ID = "style-node-missing-id";
|
|
376
|
+
var STYLE_CLASSNAME_TAILWIND = "style-classname-tailwind";
|
|
377
|
+
var STYLE_RESPONSIVE_NO_BASE = "style-responsive-no-base";
|
|
378
|
+
var STYLE_UNKNOWN_CSS_PROPERTY = "style-unknown-css-property";
|
|
379
|
+
var STYLE_UNKNOWN_TOKEN = "style-unknown-token";
|
|
380
|
+
var BREAKPOINTS = ["large", "medium", "small", "xsmall"];
|
|
381
|
+
var KNOWN_TOKENS = /* @__PURE__ */ new Set([
|
|
382
|
+
// SDUI tokens
|
|
383
|
+
"space-1",
|
|
384
|
+
"space-2",
|
|
385
|
+
"space-3",
|
|
386
|
+
"space-4",
|
|
387
|
+
"space-5",
|
|
388
|
+
"space-6",
|
|
389
|
+
"space-8",
|
|
390
|
+
"space-10",
|
|
391
|
+
"space-12",
|
|
392
|
+
"radius",
|
|
393
|
+
"radius-sm",
|
|
394
|
+
"radius-md",
|
|
395
|
+
"radius-lg",
|
|
396
|
+
"radius-xl",
|
|
397
|
+
"shadow-sm",
|
|
398
|
+
"shadow-md",
|
|
399
|
+
"shadow-lg",
|
|
400
|
+
"surface",
|
|
401
|
+
"surface-sunken",
|
|
402
|
+
"text-strong",
|
|
403
|
+
"text-muted",
|
|
404
|
+
"brand",
|
|
405
|
+
"brand-foreground",
|
|
406
|
+
"hairline",
|
|
407
|
+
// Base theme tokens (shadcn) — usually wrapped as hsl(var(--x)).
|
|
408
|
+
"background",
|
|
409
|
+
"foreground",
|
|
410
|
+
"card",
|
|
411
|
+
"card-foreground",
|
|
412
|
+
"popover",
|
|
413
|
+
"popover-foreground",
|
|
414
|
+
"primary",
|
|
415
|
+
"primary-foreground",
|
|
416
|
+
"secondary",
|
|
417
|
+
"secondary-foreground",
|
|
418
|
+
"muted",
|
|
419
|
+
"muted-foreground",
|
|
420
|
+
"accent",
|
|
421
|
+
"accent-foreground",
|
|
422
|
+
"destructive",
|
|
423
|
+
"destructive-foreground",
|
|
424
|
+
"border",
|
|
425
|
+
"input",
|
|
426
|
+
"ring",
|
|
427
|
+
"success",
|
|
428
|
+
"success-foreground",
|
|
429
|
+
"warning",
|
|
430
|
+
"warning-foreground",
|
|
431
|
+
"chart-1",
|
|
432
|
+
"chart-2",
|
|
433
|
+
"chart-3",
|
|
434
|
+
"chart-4",
|
|
435
|
+
"chart-5"
|
|
436
|
+
]);
|
|
437
|
+
var KNOWN_CSS_PROPERTIES = /* @__PURE__ */ new Set([
|
|
438
|
+
"display",
|
|
439
|
+
"position",
|
|
440
|
+
"top",
|
|
441
|
+
"right",
|
|
442
|
+
"bottom",
|
|
443
|
+
"left",
|
|
444
|
+
"inset",
|
|
445
|
+
"zIndex",
|
|
446
|
+
"overflow",
|
|
447
|
+
"overflowX",
|
|
448
|
+
"overflowY",
|
|
449
|
+
"visibility",
|
|
450
|
+
"boxSizing",
|
|
451
|
+
"float",
|
|
452
|
+
"clear",
|
|
453
|
+
"width",
|
|
454
|
+
"height",
|
|
455
|
+
"minWidth",
|
|
456
|
+
"minHeight",
|
|
457
|
+
"maxWidth",
|
|
458
|
+
"maxHeight",
|
|
459
|
+
"aspectRatio",
|
|
460
|
+
"margin",
|
|
461
|
+
"marginTop",
|
|
462
|
+
"marginRight",
|
|
463
|
+
"marginBottom",
|
|
464
|
+
"marginLeft",
|
|
465
|
+
"marginInline",
|
|
466
|
+
"marginBlock",
|
|
467
|
+
"padding",
|
|
468
|
+
"paddingTop",
|
|
469
|
+
"paddingRight",
|
|
470
|
+
"paddingBottom",
|
|
471
|
+
"paddingLeft",
|
|
472
|
+
"paddingInline",
|
|
473
|
+
"paddingBlock",
|
|
474
|
+
"flex",
|
|
475
|
+
"flexDirection",
|
|
476
|
+
"flexWrap",
|
|
477
|
+
"flexGrow",
|
|
478
|
+
"flexShrink",
|
|
479
|
+
"flexBasis",
|
|
480
|
+
"alignItems",
|
|
481
|
+
"alignContent",
|
|
482
|
+
"alignSelf",
|
|
483
|
+
"justifyContent",
|
|
484
|
+
"justifyItems",
|
|
485
|
+
"justifySelf",
|
|
486
|
+
"gap",
|
|
487
|
+
"rowGap",
|
|
488
|
+
"columnGap",
|
|
489
|
+
"order",
|
|
490
|
+
"placeItems",
|
|
491
|
+
"placeContent",
|
|
492
|
+
"grid",
|
|
493
|
+
"gridTemplate",
|
|
494
|
+
"gridTemplateColumns",
|
|
495
|
+
"gridTemplateRows",
|
|
496
|
+
"gridTemplateAreas",
|
|
497
|
+
"gridColumn",
|
|
498
|
+
"gridRow",
|
|
499
|
+
"gridArea",
|
|
500
|
+
"gridAutoFlow",
|
|
501
|
+
"gridAutoColumns",
|
|
502
|
+
"gridAutoRows",
|
|
503
|
+
"color",
|
|
504
|
+
"backgroundColor",
|
|
505
|
+
"background",
|
|
506
|
+
"backgroundImage",
|
|
507
|
+
"backgroundSize",
|
|
508
|
+
"backgroundPosition",
|
|
509
|
+
"backgroundRepeat",
|
|
510
|
+
"backgroundClip",
|
|
511
|
+
"opacity",
|
|
512
|
+
"mixBlendMode",
|
|
513
|
+
"fontSize",
|
|
514
|
+
"fontWeight",
|
|
515
|
+
"fontFamily",
|
|
516
|
+
"fontStyle",
|
|
517
|
+
"lineHeight",
|
|
518
|
+
"letterSpacing",
|
|
519
|
+
"textAlign",
|
|
520
|
+
"textTransform",
|
|
521
|
+
"textDecoration",
|
|
522
|
+
"textOverflow",
|
|
523
|
+
"whiteSpace",
|
|
524
|
+
"wordBreak",
|
|
525
|
+
"overflowWrap",
|
|
526
|
+
"fontVariantNumeric",
|
|
527
|
+
"verticalAlign",
|
|
528
|
+
"textShadow",
|
|
529
|
+
"border",
|
|
530
|
+
"borderTop",
|
|
531
|
+
"borderRight",
|
|
532
|
+
"borderBottom",
|
|
533
|
+
"borderLeft",
|
|
534
|
+
"borderColor",
|
|
535
|
+
"borderWidth",
|
|
536
|
+
"borderStyle",
|
|
537
|
+
"borderRadius",
|
|
538
|
+
"borderTopLeftRadius",
|
|
539
|
+
"borderTopRightRadius",
|
|
540
|
+
"borderBottomLeftRadius",
|
|
541
|
+
"borderBottomRightRadius",
|
|
542
|
+
"outline",
|
|
543
|
+
"outlineOffset",
|
|
544
|
+
"boxShadow",
|
|
545
|
+
"transform",
|
|
546
|
+
"transformOrigin",
|
|
547
|
+
"transition",
|
|
548
|
+
"transitionProperty",
|
|
549
|
+
"transitionDuration",
|
|
550
|
+
"transitionTimingFunction",
|
|
551
|
+
"transitionDelay",
|
|
552
|
+
"animation",
|
|
553
|
+
"filter",
|
|
554
|
+
"backdropFilter",
|
|
555
|
+
"willChange",
|
|
556
|
+
"cursor",
|
|
557
|
+
"pointerEvents",
|
|
558
|
+
"userSelect",
|
|
559
|
+
"objectFit",
|
|
560
|
+
"objectPosition",
|
|
561
|
+
"content"
|
|
562
|
+
]);
|
|
563
|
+
var VAR_RE = /var\(\s*--([a-zA-Z0-9-]+)\s*[,)]/g;
|
|
564
|
+
var TW_VARIANT = /^(sm|md|lg|xl|2xl|hover|focus|active|disabled|dark|group-hover|peer-[a-z]+|first|last|odd|even):/;
|
|
565
|
+
var TW_STEM_VALUE = /^-?(p|m|px|py|pt|pb|pl|pr|mx|my|mt|mb|ml|mr|gap|gap-x|gap-y|space-x|space-y|w|h|min-w|max-w|min-h|max-h|size|text|leading|tracking|bg|border|rounded|shadow|ring|opacity|inset|top|bottom|left|right|z|order|col|row|grid-cols|grid-rows|basis)-(\d+(\.\d+)?|\d+\/\d+|px|full|auto|none|screen|min|max|fit|xs|sm|md|lg|xl|2xl|3xl|4xl|5xl|6xl)$/;
|
|
566
|
+
var TW_BARE = /^(flex|grid|block|inline|inline-block|inline-flex|hidden|contents|table|flow-root|grow|shrink|truncate|italic|underline|uppercase|lowercase|capitalize|antialiased|absolute|relative|fixed|sticky|static|isolate|flex-col|flex-row|flex-wrap|flex-nowrap|items-center|items-start|items-end|items-stretch|justify-center|justify-between|justify-around|justify-start|justify-end|text-center|text-left|text-right|font-bold|font-semibold|font-medium|font-normal|tabular-nums)$/;
|
|
567
|
+
function looksLikeTailwind(className) {
|
|
568
|
+
return className.split(/\s+/).some((tok) => {
|
|
569
|
+
if (!tok) return false;
|
|
570
|
+
if (TW_VARIANT.test(tok)) return true;
|
|
571
|
+
if (/\[[^\]]+\]/.test(tok)) return true;
|
|
572
|
+
if (TW_STEM_VALUE.test(tok)) return true;
|
|
573
|
+
if (TW_BARE.test(tok)) return true;
|
|
574
|
+
return false;
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
function asArray3(v) {
|
|
578
|
+
if (Array.isArray(v)) return v;
|
|
579
|
+
if (v && typeof v === "object") {
|
|
580
|
+
return Object.entries(v).map(([name, def]) => ({ name, ...def }));
|
|
581
|
+
}
|
|
582
|
+
return [];
|
|
583
|
+
}
|
|
584
|
+
function childrenOf(node) {
|
|
585
|
+
const props = node.properties ?? {};
|
|
586
|
+
const out = [];
|
|
587
|
+
for (const c of [node.children, props.children, node.body, props.body]) {
|
|
588
|
+
if (Array.isArray(c)) out.push(...c.filter((x) => x && typeof x === "object"));
|
|
589
|
+
}
|
|
590
|
+
return out;
|
|
591
|
+
}
|
|
592
|
+
function checkNode(node, pageName, path, findings) {
|
|
593
|
+
const id = typeof node.id === "string" ? node.id : void 0;
|
|
594
|
+
const type = typeof node.type === "string" ? node.type : "node";
|
|
595
|
+
const where = `page "${pageName}" \u203A ${id ? `node "${id}"` : `<${type}>`}`;
|
|
596
|
+
const rs = node.responsiveStyles;
|
|
597
|
+
const hasRs = !!rs && typeof rs === "object" && BREAKPOINTS.some((b) => rs[b]);
|
|
598
|
+
if (hasRs && !id) {
|
|
599
|
+
findings.push({
|
|
600
|
+
severity: "error",
|
|
601
|
+
rule: STYLE_NODE_MISSING_ID,
|
|
602
|
+
where,
|
|
603
|
+
path,
|
|
604
|
+
message: `Node has responsiveStyles but no \`id\`; scoped CSS cannot be generated and the styles are silently dropped.`,
|
|
605
|
+
hint: `Add a stable \`id\` to this node.`
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
if (hasRs && !rs.large && BREAKPOINTS.slice(1).some((b) => rs[b])) {
|
|
609
|
+
findings.push({
|
|
610
|
+
severity: "warning",
|
|
611
|
+
rule: STYLE_RESPONSIVE_NO_BASE,
|
|
612
|
+
where,
|
|
613
|
+
path,
|
|
614
|
+
message: `responsiveStyles sets a smaller breakpoint but no \`large\` base; the node is unstyled at desktop width.`,
|
|
615
|
+
hint: `Put the unconditional/base styles under \`responsiveStyles.large\` (desktop-first).`
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (typeof node.className === "string" && node.className.trim() && looksLikeTailwind(node.className)) {
|
|
619
|
+
findings.push({
|
|
620
|
+
severity: "warning",
|
|
621
|
+
rule: STYLE_CLASSNAME_TAILWIND,
|
|
622
|
+
where,
|
|
623
|
+
path,
|
|
624
|
+
message: `\`className\` contains Tailwind-looking utilities ("${node.className.trim().slice(0, 60)}"); these are not compiled from metadata and will silently do nothing.`,
|
|
625
|
+
hint: `Style this node with \`responsiveStyles\` + design tokens instead of \`className\` (ADR-0065).`
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
if (rs && typeof rs === "object") {
|
|
629
|
+
for (const bp of BREAKPOINTS) {
|
|
630
|
+
const map = rs[bp];
|
|
631
|
+
if (!map || typeof map !== "object") continue;
|
|
632
|
+
for (const [prop, value] of Object.entries(map)) {
|
|
633
|
+
if (!prop.startsWith("--") && !KNOWN_CSS_PROPERTIES.has(prop)) {
|
|
634
|
+
findings.push({
|
|
635
|
+
severity: "warning",
|
|
636
|
+
rule: STYLE_UNKNOWN_CSS_PROPERTY,
|
|
637
|
+
where,
|
|
638
|
+
path: `${path}.responsiveStyles.${bp}`,
|
|
639
|
+
message: `Unknown CSS property "${prop}" (typo?); if unintended it will not apply.`,
|
|
640
|
+
hint: `Use a camelCase CSS property name (e.g. \`flexDirection\`, \`backgroundColor\`).`
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
if (typeof value === "string") {
|
|
644
|
+
let m;
|
|
645
|
+
VAR_RE.lastIndex = 0;
|
|
646
|
+
while (m = VAR_RE.exec(value)) {
|
|
647
|
+
const token = m[1];
|
|
648
|
+
if (!KNOWN_TOKENS.has(token) && !token.startsWith("tw-")) {
|
|
649
|
+
findings.push({
|
|
650
|
+
severity: "warning",
|
|
651
|
+
rule: STYLE_UNKNOWN_TOKEN,
|
|
652
|
+
where,
|
|
653
|
+
path: `${path}.responsiveStyles.${bp}.${prop}`,
|
|
654
|
+
message: `References unknown design token \`var(--${token})\` (typo?); it will not resolve.`,
|
|
655
|
+
hint: `Use a token from the ADR-0065 palette (e.g. \`var(--space-6)\`, \`var(--surface)\`, \`hsl(var(--primary))\`).`
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const kids = childrenOf(node);
|
|
664
|
+
for (let i = 0; i < kids.length; i++) {
|
|
665
|
+
checkNode(kids[i], pageName, `${path}.children[${i}]`, findings);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
function validateResponsiveStyles(stack) {
|
|
669
|
+
const findings = [];
|
|
670
|
+
const pages = asArray3(stack.pages);
|
|
671
|
+
for (let p = 0; p < pages.length; p++) {
|
|
672
|
+
const page = pages[p];
|
|
673
|
+
const pageName = typeof page.name === "string" ? page.name : `pages[${p}]`;
|
|
674
|
+
const regions = asArray3(page.regions);
|
|
675
|
+
for (let r = 0; r < regions.length; r++) {
|
|
676
|
+
const components = asArray3(regions[r].components);
|
|
677
|
+
for (let c = 0; c < components.length; c++) {
|
|
678
|
+
checkNode(components[c], pageName, `pages[${p}].regions[${r}].components[${c}]`, findings);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return findings;
|
|
683
|
+
}
|
|
373
684
|
export {
|
|
374
685
|
CHART_CONFIG_MISSING,
|
|
375
686
|
CHART_FIELD_UNKNOWN,
|
|
376
687
|
MEASURE_AGGREGATE_INCOHERENT,
|
|
688
|
+
STYLE_CLASSNAME_TAILWIND,
|
|
689
|
+
STYLE_NODE_MISSING_ID,
|
|
690
|
+
STYLE_RESPONSIVE_NO_BASE,
|
|
691
|
+
STYLE_UNKNOWN_CSS_PROPERTY,
|
|
692
|
+
STYLE_UNKNOWN_TOKEN,
|
|
377
693
|
TABLE_COUNT_ONLY,
|
|
378
694
|
WIDGET_DATASET_UNKNOWN,
|
|
379
695
|
WIDGET_DIMENSION_UNKNOWN,
|
|
380
696
|
WIDGET_MEASURE_UNKNOWN,
|
|
697
|
+
validateResponsiveStyles,
|
|
381
698
|
validateStackExpressions,
|
|
382
699
|
validateWidgetBindings
|
|
383
700
|
};
|