@stilhq/core 0.6.0 → 0.6.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.
- package/dist/changeset/apply.d.ts +11 -0
- package/dist/changeset/apply.d.ts.map +1 -0
- package/dist/changeset/apply.js +239 -0
- package/dist/changeset/apply.js.map +1 -0
- package/dist/changeset/ci-report.d.ts +25 -0
- package/dist/changeset/ci-report.d.ts.map +1 -0
- package/dist/changeset/ci-report.js +206 -0
- package/dist/changeset/ci-report.js.map +1 -0
- package/dist/changeset/classify.d.ts +77 -0
- package/dist/changeset/classify.d.ts.map +1 -0
- package/dist/changeset/classify.js +285 -0
- package/dist/changeset/classify.js.map +1 -0
- package/dist/changeset/cli-gate.d.ts +46 -0
- package/dist/changeset/cli-gate.d.ts.map +1 -0
- package/dist/changeset/cli-gate.js +409 -0
- package/dist/changeset/cli-gate.js.map +1 -0
- package/dist/changeset/conflict.d.ts +11 -0
- package/dist/changeset/conflict.d.ts.map +1 -0
- package/dist/changeset/conflict.js +130 -0
- package/dist/changeset/conflict.js.map +1 -0
- package/dist/changeset/diff-components.d.ts +80 -0
- package/dist/changeset/diff-components.d.ts.map +1 -0
- package/dist/changeset/diff-components.js +264 -0
- package/dist/changeset/diff-components.js.map +1 -0
- package/dist/changeset/diff-text.d.ts +66 -0
- package/dist/changeset/diff-text.d.ts.map +1 -0
- package/dist/changeset/diff-text.js +284 -0
- package/dist/changeset/diff-text.js.map +1 -0
- package/dist/changeset/diff-tokens.d.ts +63 -0
- package/dist/changeset/diff-tokens.d.ts.map +1 -0
- package/dist/changeset/diff-tokens.js +483 -0
- package/dist/changeset/diff-tokens.js.map +1 -0
- package/dist/changeset/impact.d.ts +31 -0
- package/dist/changeset/impact.d.ts.map +1 -0
- package/dist/changeset/impact.js +188 -0
- package/dist/changeset/impact.js.map +1 -0
- package/dist/changeset/pr-body.d.ts +33 -0
- package/dist/changeset/pr-body.d.ts.map +1 -0
- package/dist/changeset/pr-body.js +421 -0
- package/dist/changeset/pr-body.js.map +1 -0
- package/dist/changeset/quality-gate.d.ts +10 -0
- package/dist/changeset/quality-gate.d.ts.map +1 -0
- package/dist/changeset/quality-gate.js +207 -0
- package/dist/changeset/quality-gate.js.map +1 -0
- package/dist/changeset/rollback.d.ts +19 -0
- package/dist/changeset/rollback.d.ts.map +1 -0
- package/dist/changeset/rollback.js +163 -0
- package/dist/changeset/rollback.js.map +1 -0
- package/dist/ci/template-generator.d.ts +22 -0
- package/dist/ci/template-generator.d.ts.map +1 -0
- package/dist/ci/template-generator.js +215 -0
- package/dist/ci/template-generator.js.map +1 -0
- package/dist/gate/engine.d.ts +20 -0
- package/dist/gate/engine.d.ts.map +1 -0
- package/dist/gate/engine.js +109 -0
- package/dist/gate/engine.js.map +1 -0
- package/dist/gate/types.d.ts +76 -0
- package/dist/gate/types.d.ts.map +1 -0
- package/dist/gate/types.js +6 -0
- package/dist/gate/types.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -1
- package/dist/index.js.map +1 -1
- package/dist/pr/comment-manager.d.ts +33 -0
- package/dist/pr/comment-manager.d.ts.map +1 -0
- package/dist/pr/comment-manager.js +137 -0
- package/dist/pr/comment-manager.js.map +1 -0
- package/dist/pr/conflict.d.ts +34 -0
- package/dist/pr/conflict.d.ts.map +1 -0
- package/dist/pr/conflict.js +127 -0
- package/dist/pr/conflict.js.map +1 -0
- package/dist/pr/generator.d.ts +70 -0
- package/dist/pr/generator.d.ts.map +1 -0
- package/dist/pr/generator.js +241 -0
- package/dist/pr/generator.js.map +1 -0
- package/dist/pr/github-api.d.ts +122 -0
- package/dist/pr/github-api.d.ts.map +1 -0
- package/dist/pr/github-api.js +269 -0
- package/dist/pr/github-api.js.map +1 -0
- package/dist/report/changeset-report.d.ts +10 -0
- package/dist/report/changeset-report.d.ts.map +1 -0
- package/dist/report/changeset-report.js +14 -0
- package/dist/report/changeset-report.js.map +1 -0
- package/dist/report/classification-report.d.ts +12 -0
- package/dist/report/classification-report.d.ts.map +1 -0
- package/dist/report/classification-report.js +157 -0
- package/dist/report/classification-report.js.map +1 -0
- package/dist/report/impact-report.d.ts +10 -0
- package/dist/report/impact-report.d.ts.map +1 -0
- package/dist/report/impact-report.js +47 -0
- package/dist/report/impact-report.js.map +1 -0
- package/dist/report/summary-report.d.ts +10 -0
- package/dist/report/summary-report.d.ts.map +1 -0
- package/dist/report/summary-report.js +96 -0
- package/dist/report/summary-report.js.map +1 -0
- package/dist/report/writer.d.ts +17 -0
- package/dist/report/writer.d.ts.map +1 -0
- package/dist/report/writer.js +41 -0
- package/dist/report/writer.js.map +1 -0
- package/dist/rules/engine.d.ts +46 -0
- package/dist/rules/engine.d.ts.map +1 -0
- package/dist/rules/engine.js +200 -0
- package/dist/rules/engine.js.map +1 -0
- package/dist/rules/index.d.ts +10 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +25 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/loader.d.ts +20 -0
- package/dist/rules/loader.d.ts.map +1 -0
- package/dist/rules/loader.js +93 -0
- package/dist/rules/loader.js.map +1 -0
- package/dist/rules/packs/core.d.ts +14 -0
- package/dist/rules/packs/core.d.ts.map +1 -0
- package/dist/rules/packs/core.js +377 -0
- package/dist/rules/packs/core.js.map +1 -0
- package/dist/rules/schema.d.ts +12 -0
- package/dist/rules/schema.d.ts.map +1 -0
- package/dist/rules/schema.js +149 -0
- package/dist/rules/schema.js.map +1 -0
- package/dist/rules/types.d.ts +86 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +9 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/types/changeset.d.ts +509 -0
- package/dist/types/changeset.d.ts.map +1 -0
- package/dist/types/changeset.js +14 -0
- package/dist/types/changeset.js.map +1 -0
- package/dist/w3c/__tests__/fixtures/tokens-studio-export.json +58 -0
- package/dist/w3c/parser.d.ts +44 -0
- package/dist/w3c/parser.d.ts.map +1 -0
- package/dist/w3c/parser.js +146 -0
- package/dist/w3c/parser.js.map +1 -0
- package/dist/w3c/types.d.ts +31 -0
- package/dist/w3c/types.d.ts.map +1 -0
- package/dist/w3c/types.js +7 -0
- package/dist/w3c/types.js.map +1 -0
- package/dist/w3c/validator.d.ts +14 -0
- package/dist/w3c/validator.d.ts.map +1 -0
- package/dist/w3c/validator.js +162 -0
- package/dist/w3c/validator.js.map +1 -0
- package/package.json +3 -2
- package/templates/stil-quality-gate.yml +122 -0
- package/templates/workspace/.github/PULL_REQUEST_TEMPLATE.md +14 -0
- package/templates/workspace/.github/workflows/stil-gate.yml +42 -0
- package/templates/workspace/.github/workflows/stil-preview.yml +29 -0
- package/templates/workspace/.stil/components/snapshots/.gitkeep +0 -0
- package/templates/workspace/.stil/reports/.gitkeep +0 -0
- package/templates/workspace/.stil/rules/.gitkeep +0 -0
- package/templates/workspace/.stil/text/snapshots/.gitkeep +0 -0
- package/templates/workspace/.stil/tokens/config/mapping.json +16 -0
- package/templates/workspace/.stil/tokens/raw/.gitkeep +0 -0
- package/templates/workspace/README.md +40 -0
- package/templates/workspace/package.json +19 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* W3C DTCG JSON parser and converter
|
|
4
|
+
*
|
|
5
|
+
* Converts between W3C Design Tokens format and flat TokenItem arrays.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.parseW3CTokens = parseW3CTokens;
|
|
9
|
+
exports.toW3CDocument = toW3CDocument;
|
|
10
|
+
exports.toW3CPath = toW3CPath;
|
|
11
|
+
exports.fromW3CPath = fromW3CPath;
|
|
12
|
+
exports.toChangeSetTokenItem = toChangeSetTokenItem;
|
|
13
|
+
const VALID_W3C_TYPES = new Set([
|
|
14
|
+
"color",
|
|
15
|
+
"dimension",
|
|
16
|
+
"fontFamily",
|
|
17
|
+
"fontWeight",
|
|
18
|
+
"duration",
|
|
19
|
+
"cubicBezier",
|
|
20
|
+
"number",
|
|
21
|
+
"strokeStyle",
|
|
22
|
+
"border",
|
|
23
|
+
"transition",
|
|
24
|
+
"shadow",
|
|
25
|
+
"gradient",
|
|
26
|
+
"typography",
|
|
27
|
+
"fontStyle",
|
|
28
|
+
]);
|
|
29
|
+
/**
|
|
30
|
+
* Check if a value looks like a W3C token value node (has $value)
|
|
31
|
+
*/
|
|
32
|
+
function isTokenValue(node) {
|
|
33
|
+
return (typeof node === "object" &&
|
|
34
|
+
node !== null &&
|
|
35
|
+
"$value" in node);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse W3C DTCG JSON into a flat array of parsed tokens.
|
|
39
|
+
*
|
|
40
|
+
* Handles:
|
|
41
|
+
* - Nested groups with dot-separated keys
|
|
42
|
+
* - $type inheritance from parent groups
|
|
43
|
+
* - alias references ({color.primary} syntax) preserved as-is
|
|
44
|
+
* - $extensions passed through
|
|
45
|
+
*/
|
|
46
|
+
function parseW3CTokens(doc) {
|
|
47
|
+
const result = [];
|
|
48
|
+
walkGroup(doc, [], undefined, result);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
function walkGroup(group, pathParts, inheritedType, result) {
|
|
52
|
+
// Check for group-level $type
|
|
53
|
+
const groupType = group.$type && VALID_W3C_TYPES.has(group.$type)
|
|
54
|
+
? group.$type
|
|
55
|
+
: inheritedType;
|
|
56
|
+
for (const key of Object.keys(group)) {
|
|
57
|
+
if (key.startsWith("$"))
|
|
58
|
+
continue; // skip meta keys
|
|
59
|
+
const value = group[key];
|
|
60
|
+
if (value === undefined || value === null)
|
|
61
|
+
continue;
|
|
62
|
+
if (typeof value === "string")
|
|
63
|
+
continue; // skip bare strings at group level
|
|
64
|
+
const childPath = [...pathParts, key];
|
|
65
|
+
if (isTokenValue(value)) {
|
|
66
|
+
// This is a token leaf
|
|
67
|
+
const tokenType = value.$type || groupType;
|
|
68
|
+
if (!tokenType)
|
|
69
|
+
continue; // skip tokens without any type
|
|
70
|
+
result.push({
|
|
71
|
+
tokenKey: childPath.join("."),
|
|
72
|
+
$type: tokenType,
|
|
73
|
+
$value: value.$value,
|
|
74
|
+
$description: value.$description,
|
|
75
|
+
$extensions: value.$extensions,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// This is a nested group
|
|
80
|
+
walkGroup(value, childPath, groupType, result);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert flat ParsedW3CToken array back to W3C DTCG document.
|
|
86
|
+
* Reconstructs nested structure from dot-separated keys.
|
|
87
|
+
*/
|
|
88
|
+
function toW3CDocument(tokens) {
|
|
89
|
+
const doc = {};
|
|
90
|
+
for (const token of tokens) {
|
|
91
|
+
const parts = token.tokenKey.split(".");
|
|
92
|
+
let current = doc;
|
|
93
|
+
// Navigate/create nested groups
|
|
94
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
95
|
+
if (!current[parts[i]] || typeof current[parts[i]] !== "object") {
|
|
96
|
+
current[parts[i]] = {};
|
|
97
|
+
}
|
|
98
|
+
current = current[parts[i]];
|
|
99
|
+
}
|
|
100
|
+
// Set the leaf value
|
|
101
|
+
const leaf = {
|
|
102
|
+
$type: token.$type,
|
|
103
|
+
$value: token.$value,
|
|
104
|
+
};
|
|
105
|
+
if (token.$description) {
|
|
106
|
+
leaf.$description = token.$description;
|
|
107
|
+
}
|
|
108
|
+
if (token.$extensions) {
|
|
109
|
+
leaf.$extensions = token.$extensions;
|
|
110
|
+
}
|
|
111
|
+
current[parts[parts.length - 1]] = leaf;
|
|
112
|
+
}
|
|
113
|
+
return doc;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convert dot-separated tokenKey to W3C path format (slash-separated).
|
|
117
|
+
*/
|
|
118
|
+
function toW3CPath(dotKey) {
|
|
119
|
+
return dotKey.replace(/\./g, "/");
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Convert W3C path (slash-separated) to dot-separated tokenKey.
|
|
123
|
+
*/
|
|
124
|
+
function fromW3CPath(w3cPath) {
|
|
125
|
+
return w3cPath.replace(/\//g, ".");
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Convert ParsedW3CToken to ChangeSetTokenItem format.
|
|
129
|
+
* Used internally when generating diffs from W3C documents.
|
|
130
|
+
*/
|
|
131
|
+
function toChangeSetTokenItem(parsed, before, after) {
|
|
132
|
+
const item = {
|
|
133
|
+
tokenKey: parsed.tokenKey,
|
|
134
|
+
before,
|
|
135
|
+
after,
|
|
136
|
+
changeType: "VALUE",
|
|
137
|
+
};
|
|
138
|
+
// Attach W3C metadata as optional fields
|
|
139
|
+
item.$type = parsed.$type;
|
|
140
|
+
item.$value = parsed.$value;
|
|
141
|
+
if (parsed.$description) {
|
|
142
|
+
item.$description = parsed.$description;
|
|
143
|
+
}
|
|
144
|
+
return item;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/w3c/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W3C Design Tokens Community Group Format 1.0
|
|
3
|
+
* @see https://tr.designtokens.org/format/
|
|
4
|
+
*/
|
|
5
|
+
/** W3C Token Types */
|
|
6
|
+
export type W3CTokenType = "color" | "dimension" | "fontFamily" | "fontWeight" | "duration" | "cubicBezier" | "number" | "strokeStyle" | "border" | "transition" | "shadow" | "gradient" | "typography" | "fontStyle";
|
|
7
|
+
/** W3C Token Value */
|
|
8
|
+
export interface W3CTokenValue {
|
|
9
|
+
$type: W3CTokenType;
|
|
10
|
+
$value: string | number | Record<string, unknown>;
|
|
11
|
+
$description?: string;
|
|
12
|
+
$extensions?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** W3C Token Group (nestable) */
|
|
15
|
+
export interface W3CTokenGroup {
|
|
16
|
+
[key: string]: W3CTokenValue | W3CTokenGroup | string | undefined;
|
|
17
|
+
$type?: W3CTokenType;
|
|
18
|
+
$description?: string;
|
|
19
|
+
}
|
|
20
|
+
/** W3C Design Tokens Document */
|
|
21
|
+
export interface W3CDesignTokensDocument {
|
|
22
|
+
[key: string]: W3CTokenGroup | W3CTokenValue;
|
|
23
|
+
}
|
|
24
|
+
/** Validation result for a single token or document */
|
|
25
|
+
export interface W3CValidationResult {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
path: string;
|
|
28
|
+
errors: string[];
|
|
29
|
+
warnings: string[];
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/w3c/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sBAAsB;AACtB,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,aAAa,GACb,QAAQ,GACR,aAAa,GACb,QAAQ,GACR,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,YAAY,GACZ,WAAW,CAAC;AAEhB,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,iCAAiC;AACjC,MAAM,WAAW,aAAa;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;IAClE,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,iCAAiC;AACjC,MAAM,WAAW,uBAAuB;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC;CAC9C;AAED,uDAAuD;AACvD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/w3c/types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W3C DTCG format validation
|
|
3
|
+
*/
|
|
4
|
+
import type { W3CDesignTokensDocument, W3CTokenValue, W3CValidationResult } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Validate a single W3C token value.
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateW3CToken(token: W3CTokenValue, path?: string): W3CValidationResult;
|
|
9
|
+
/**
|
|
10
|
+
* Validate an entire W3C Design Tokens document.
|
|
11
|
+
* Walks the tree and validates each token node.
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateW3CDocument(doc: W3CDesignTokensDocument): W3CValidationResult[];
|
|
14
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/w3c/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,uBAAuB,EAGvB,aAAa,EACb,mBAAmB,EACpB,MAAM,SAAS,CAAC;AA0BjB;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,IAAI,GAAE,MAAW,GAChB,mBAAmB,CAyCrB;AA2ED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,uBAAuB,GAC3B,mBAAmB,EAAE,CAIvB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* W3C DTCG format validation
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validateW3CToken = validateW3CToken;
|
|
7
|
+
exports.validateW3CDocument = validateW3CDocument;
|
|
8
|
+
const VALID_W3C_TYPES = new Set([
|
|
9
|
+
"color",
|
|
10
|
+
"dimension",
|
|
11
|
+
"fontFamily",
|
|
12
|
+
"fontWeight",
|
|
13
|
+
"duration",
|
|
14
|
+
"cubicBezier",
|
|
15
|
+
"number",
|
|
16
|
+
"strokeStyle",
|
|
17
|
+
"border",
|
|
18
|
+
"transition",
|
|
19
|
+
"shadow",
|
|
20
|
+
"gradient",
|
|
21
|
+
"typography",
|
|
22
|
+
"fontStyle",
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Check if a value is a W3C token node (has $value)
|
|
26
|
+
*/
|
|
27
|
+
function isTokenValue(node) {
|
|
28
|
+
return typeof node === "object" && node !== null && "$value" in node;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validate a single W3C token value.
|
|
32
|
+
*/
|
|
33
|
+
function validateW3CToken(token, path = "") {
|
|
34
|
+
const errors = [];
|
|
35
|
+
const warnings = [];
|
|
36
|
+
// $value is required
|
|
37
|
+
if (token.$value === undefined || token.$value === null) {
|
|
38
|
+
errors.push(`${path}: $value is required`);
|
|
39
|
+
}
|
|
40
|
+
// $type should be valid if present
|
|
41
|
+
if (token.$type !== undefined) {
|
|
42
|
+
if (!VALID_W3C_TYPES.has(token.$type)) {
|
|
43
|
+
errors.push(`${path}: invalid $type "${token.$type}". Valid types: ${[...VALID_W3C_TYPES].join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Type-specific value validation
|
|
47
|
+
if (token.$type && token.$value !== undefined && token.$value !== null) {
|
|
48
|
+
const valueErrors = validateValueForType(token.$type, token.$value, path);
|
|
49
|
+
errors.push(...valueErrors);
|
|
50
|
+
}
|
|
51
|
+
// Warn about missing $type (it might be inherited from parent)
|
|
52
|
+
if (!token.$type) {
|
|
53
|
+
warnings.push(`${path}: no $type specified (may be inherited from parent group)`);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
valid: errors.length === 0,
|
|
57
|
+
path,
|
|
58
|
+
errors,
|
|
59
|
+
warnings,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Validate $value against its $type
|
|
64
|
+
*/
|
|
65
|
+
function validateValueForType(type, value, path) {
|
|
66
|
+
const errors = [];
|
|
67
|
+
// Skip alias references
|
|
68
|
+
if (typeof value === "string" && value.startsWith("{") && value.endsWith("}")) {
|
|
69
|
+
return errors;
|
|
70
|
+
}
|
|
71
|
+
switch (type) {
|
|
72
|
+
case "color":
|
|
73
|
+
if (typeof value !== "string") {
|
|
74
|
+
errors.push(`${path}: color $value must be a string`);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case "dimension":
|
|
78
|
+
if (typeof value !== "string") {
|
|
79
|
+
errors.push(`${path}: dimension $value must be a string (e.g., "16px")`);
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
case "number":
|
|
83
|
+
if (typeof value !== "number") {
|
|
84
|
+
errors.push(`${path}: number $value must be a number`);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case "fontFamily":
|
|
88
|
+
if (typeof value !== "string") {
|
|
89
|
+
errors.push(`${path}: fontFamily $value must be a string`);
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case "fontWeight":
|
|
93
|
+
if (typeof value !== "number" && typeof value !== "string") {
|
|
94
|
+
errors.push(`${path}: fontWeight $value must be a number or string`);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
case "duration":
|
|
98
|
+
if (typeof value !== "string") {
|
|
99
|
+
errors.push(`${path}: duration $value must be a string (e.g., "200ms")`);
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "cubicBezier":
|
|
103
|
+
if (!Array.isArray(value)) {
|
|
104
|
+
errors.push(`${path}: cubicBezier $value must be an array of 4 numbers`);
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
case "typography":
|
|
108
|
+
case "shadow":
|
|
109
|
+
case "border":
|
|
110
|
+
case "transition":
|
|
111
|
+
case "gradient":
|
|
112
|
+
if (typeof value !== "object") {
|
|
113
|
+
errors.push(`${path}: ${type} $value must be an object`);
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
case "strokeStyle":
|
|
117
|
+
// Can be string or object
|
|
118
|
+
break;
|
|
119
|
+
case "fontStyle":
|
|
120
|
+
if (typeof value !== "string") {
|
|
121
|
+
errors.push(`${path}: fontStyle $value must be a string`);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
return errors;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Validate an entire W3C Design Tokens document.
|
|
129
|
+
* Walks the tree and validates each token node.
|
|
130
|
+
*/
|
|
131
|
+
function validateW3CDocument(doc) {
|
|
132
|
+
const results = [];
|
|
133
|
+
walkAndValidate(doc, [], undefined, results);
|
|
134
|
+
return results;
|
|
135
|
+
}
|
|
136
|
+
function walkAndValidate(group, pathParts, inheritedType, results) {
|
|
137
|
+
const groupType = group.$type && VALID_W3C_TYPES.has(group.$type)
|
|
138
|
+
? group.$type
|
|
139
|
+
: inheritedType;
|
|
140
|
+
for (const key of Object.keys(group)) {
|
|
141
|
+
if (key.startsWith("$"))
|
|
142
|
+
continue;
|
|
143
|
+
const value = group[key];
|
|
144
|
+
if (value === undefined || value === null)
|
|
145
|
+
continue;
|
|
146
|
+
if (typeof value === "string")
|
|
147
|
+
continue;
|
|
148
|
+
const childPath = [...pathParts, key];
|
|
149
|
+
const pathStr = childPath.join(".");
|
|
150
|
+
if (isTokenValue(value)) {
|
|
151
|
+
// Inject inherited type if token lacks its own
|
|
152
|
+
const tokenWithType = value.$type
|
|
153
|
+
? value
|
|
154
|
+
: Object.assign({}, value, { $type: groupType });
|
|
155
|
+
results.push(validateW3CToken(tokenWithType, pathStr));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
walkAndValidate(value, childPath, groupType, results);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/w3c/validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stilhq/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Design token, component, and text QA pipeline for Stil",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"dist",
|
|
37
37
|
"README.md",
|
|
38
38
|
"LICENSE",
|
|
39
|
-
"src/config"
|
|
39
|
+
"src/config",
|
|
40
|
+
"templates"
|
|
40
41
|
],
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@types/node": "^20.11.0",
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# .github/workflows/stil-quality-gate.yml
|
|
2
|
+
#
|
|
3
|
+
# Stil Quality Gate — CI Merge Block
|
|
4
|
+
#
|
|
5
|
+
# workspace_repo にコピーして使う GitHub Actions workflow テンプレート。
|
|
6
|
+
# .stil/ 配下の ChangeSet JSON を読み取り、Quality Gate を実行する。
|
|
7
|
+
#
|
|
8
|
+
# blocked items = CI fail(壊れた参照、key 衝突、placeholder 不一致)
|
|
9
|
+
# review items = approval label 必須(requireApprovalForReview を有効化した場合)
|
|
10
|
+
|
|
11
|
+
name: Stil Quality Gate
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
pull_request:
|
|
15
|
+
paths:
|
|
16
|
+
- '.stil/**'
|
|
17
|
+
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
pull-requests: write
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
quality-gate:
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup Node.js
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: '20'
|
|
33
|
+
|
|
34
|
+
- name: Install @stilhq/core
|
|
35
|
+
run: npm install @stilhq/core
|
|
36
|
+
|
|
37
|
+
- name: Check for ChangeSet files
|
|
38
|
+
id: check-changesets
|
|
39
|
+
run: |
|
|
40
|
+
if ls .stil/changesets/*.json 1>/dev/null 2>&1; then
|
|
41
|
+
echo "has_changesets=true" >> "$GITHUB_OUTPUT"
|
|
42
|
+
else
|
|
43
|
+
echo "has_changesets=false" >> "$GITHUB_OUTPUT"
|
|
44
|
+
echo "No ChangeSet files found in .stil/changesets/"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
- name: Run Stil Quality Gate
|
|
48
|
+
if: steps.check-changesets.outputs.has_changesets == 'true'
|
|
49
|
+
id: gate
|
|
50
|
+
run: |
|
|
51
|
+
mkdir -p .stil/reports
|
|
52
|
+
npx stil-gate \
|
|
53
|
+
--changesets .stil/changesets/*.json \
|
|
54
|
+
--format gh-annotations \
|
|
55
|
+
--output .stil/reports/gate-result.json
|
|
56
|
+
continue-on-error: true
|
|
57
|
+
|
|
58
|
+
- name: Generate PR Comment
|
|
59
|
+
if: steps.check-changesets.outputs.has_changesets == 'true'
|
|
60
|
+
id: pr-comment
|
|
61
|
+
run: |
|
|
62
|
+
npx stil-gate \
|
|
63
|
+
--changesets .stil/changesets/*.json \
|
|
64
|
+
--format pr-comment > .stil/reports/pr-comment.md
|
|
65
|
+
|
|
66
|
+
- name: Comment PR with Quality Gate results
|
|
67
|
+
if: steps.check-changesets.outputs.has_changesets == 'true' && github.event_name == 'pull_request'
|
|
68
|
+
uses: actions/github-script@v7
|
|
69
|
+
with:
|
|
70
|
+
script: |
|
|
71
|
+
const fs = require('fs');
|
|
72
|
+
const commentPath = '.stil/reports/pr-comment.md';
|
|
73
|
+
|
|
74
|
+
if (!fs.existsSync(commentPath)) {
|
|
75
|
+
console.log('No PR comment file found, skipping');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const body = fs.readFileSync(commentPath, 'utf8');
|
|
80
|
+
|
|
81
|
+
// Find existing Stil comment
|
|
82
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
83
|
+
owner: context.repo.owner,
|
|
84
|
+
repo: context.repo.repo,
|
|
85
|
+
issue_number: context.issue.number,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const stilComment = comments.find(c =>
|
|
89
|
+
c.body && c.body.includes('Stil Quality Gate')
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (stilComment) {
|
|
93
|
+
// Update existing comment
|
|
94
|
+
await github.rest.issues.updateComment({
|
|
95
|
+
owner: context.repo.owner,
|
|
96
|
+
repo: context.repo.repo,
|
|
97
|
+
comment_id: stilComment.id,
|
|
98
|
+
body,
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
// Create new comment
|
|
102
|
+
await github.rest.issues.createComment({
|
|
103
|
+
owner: context.repo.owner,
|
|
104
|
+
repo: context.repo.repo,
|
|
105
|
+
issue_number: context.issue.number,
|
|
106
|
+
body,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
- name: Upload Quality Gate report
|
|
111
|
+
if: steps.check-changesets.outputs.has_changesets == 'true'
|
|
112
|
+
uses: actions/upload-artifact@v4
|
|
113
|
+
with:
|
|
114
|
+
name: stil-quality-gate-report
|
|
115
|
+
path: .stil/reports/
|
|
116
|
+
retention-days: 30
|
|
117
|
+
|
|
118
|
+
- name: Fail if Quality Gate failed
|
|
119
|
+
if: steps.gate.outcome == 'failure'
|
|
120
|
+
run: |
|
|
121
|
+
echo "❌ Stil Quality Gate failed. See annotations above for details."
|
|
122
|
+
exit 1
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What changed and why -->
|
|
4
|
+
|
|
5
|
+
## Stil Gate Report
|
|
6
|
+
|
|
7
|
+
<!-- Stil will auto-post Gate results as a comment -->
|
|
8
|
+
<!-- If Gate failed, explain why the change is safe: -->
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
|
|
12
|
+
- [ ] Gate passed (or failure explained above)
|
|
13
|
+
- [ ] Storybook preview reviewed
|
|
14
|
+
- [ ] Design team notified (if review classification)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Stil Gate — Quality Gate CI for design system changes
|
|
2
|
+
name: Stil Gate
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
paths:
|
|
7
|
+
- '.stil/**'
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
gate:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: '18'
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: npm ci
|
|
21
|
+
|
|
22
|
+
- name: Run Stil Gate
|
|
23
|
+
run: npx stil gate --mode ${{ vars.STIL_GATE_MODE || 'warn' }} --ci
|
|
24
|
+
env:
|
|
25
|
+
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
26
|
+
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
|
|
27
|
+
STIL_PROJECT_ID: ${{ secrets.STIL_PROJECT_ID }}
|
|
28
|
+
|
|
29
|
+
- name: Upload Gate Report
|
|
30
|
+
if: always()
|
|
31
|
+
uses: actions/upload-artifact@v4
|
|
32
|
+
with:
|
|
33
|
+
name: stil-gate-report
|
|
34
|
+
path: .stil/reports/
|
|
35
|
+
|
|
36
|
+
- name: Post Gate Comment
|
|
37
|
+
if: github.event_name == 'pull_request'
|
|
38
|
+
run: npx stil gate-comment --pr ${{ github.event.pull_request.number }}
|
|
39
|
+
env:
|
|
40
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
|
|
42
|
+
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Stil Preview — Storybook preview deployment for design system PRs
|
|
2
|
+
name: Stil Preview
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
pull_request:
|
|
6
|
+
paths:
|
|
7
|
+
- '.stil/**'
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
preview:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: '18'
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: npm ci
|
|
21
|
+
|
|
22
|
+
- name: Build Storybook
|
|
23
|
+
run: npm run build-storybook
|
|
24
|
+
|
|
25
|
+
- name: Upload Storybook Artifact
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: storybook-preview
|
|
29
|
+
path: storybook-static/
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://stil.dev/schemas/mapping.json",
|
|
3
|
+
"version": "1.0",
|
|
4
|
+
"tokens": {
|
|
5
|
+
"collections": [],
|
|
6
|
+
"excludePatterns": []
|
|
7
|
+
},
|
|
8
|
+
"components": {
|
|
9
|
+
"mappings": [],
|
|
10
|
+
"excludePatterns": []
|
|
11
|
+
},
|
|
12
|
+
"text": {
|
|
13
|
+
"locales": ["en"],
|
|
14
|
+
"excludePatterns": []
|
|
15
|
+
}
|
|
16
|
+
}
|
|
File without changes
|