@cristianormazabal/triton-core 0.1.14 → 0.1.16
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/contracts/anchors.d.ts +6 -0
- package/dist/contracts/anchors.d.ts.map +1 -1
- package/dist/contracts/icons.d.ts +228 -0
- package/dist/contracts/icons.d.ts.map +1 -0
- package/dist/contracts/icons.js +28 -0
- package/dist/contracts/icons.js.map +1 -0
- package/dist/contracts/index.d.ts +2 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/result.d.ts +1 -1
- package/dist/contracts/result.d.ts.map +1 -1
- package/dist/contracts/result.js.map +1 -1
- package/dist/contracts/scene.d.ts +47 -1
- package/dist/contracts/scene.d.ts.map +1 -1
- package/dist/diagrams/mermaid/flowchart/index.d.ts.map +1 -1
- package/dist/diagrams/mermaid/flowchart/index.js +19 -1
- package/dist/diagrams/mermaid/flowchart/index.js.map +1 -1
- package/dist/diagrams/mermaid/flowchart/ir.d.ts +4 -1
- package/dist/diagrams/mermaid/flowchart/ir.d.ts.map +1 -1
- package/dist/diagrams/mermaid/flowchart/layout.d.ts.map +1 -1
- package/dist/diagrams/mermaid/flowchart/layout.js +177 -19
- package/dist/diagrams/mermaid/flowchart/layout.js.map +1 -1
- package/dist/diagrams/triton/ds/queue/shared.js +2 -0
- package/dist/diagrams/triton/ds/queue/shared.js.map +1 -1
- package/dist/diagrams/triton/ds/struct/array.d.ts.map +1 -1
- package/dist/diagrams/triton/ds/struct/array.js +2 -0
- package/dist/diagrams/triton/ds/struct/array.js.map +1 -1
- package/dist/frontend/index.d.ts +4 -3
- package/dist/frontend/index.d.ts.map +1 -1
- package/dist/frontend/index.js +7 -6
- package/dist/frontend/index.js.map +1 -1
- package/dist/icons/discover.d.ts +51 -0
- package/dist/icons/discover.d.ts.map +1 -0
- package/dist/icons/discover.js +124 -0
- package/dist/icons/discover.js.map +1 -0
- package/dist/icons/resolver.d.ts +84 -0
- package/dist/icons/resolver.d.ts.map +1 -0
- package/dist/icons/resolver.js +226 -0
- package/dist/icons/resolver.js.map +1 -0
- package/dist/icons/validate.d.ts +36 -0
- package/dist/icons/validate.d.ts.map +1 -0
- package/dist/icons/validate.js +257 -0
- package/dist/icons/validate.js.map +1 -0
- package/dist/index.js +1150 -492
- package/dist/index.js.map +4 -4
- package/dist/overlay/layout.js +2 -0
- package/dist/overlay/layout.js.map +1 -1
- package/dist/render/svg.d.ts.map +1 -1
- package/dist/render/svg.js +104 -0
- package/dist/render/svg.js.map +1 -1
- package/dist/scene/build.d.ts +16 -1
- package/dist/scene/build.d.ts.map +1 -1
- package/dist/scene/build.js +7 -0
- package/dist/scene/build.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon resolution — pure, no I/O.
|
|
3
|
+
*
|
|
4
|
+
* Three exported functions:
|
|
5
|
+
*
|
|
6
|
+
* parseIconRef(token) — parse "prefix:name" → Result<IconRef>
|
|
7
|
+
* resolveIcon(ref, packs) — resolve IconRef against IconPackMap → Result<ResolvedIcon>
|
|
8
|
+
* detectColorMode(body) — classify body as 'monochrome' | 'brand'
|
|
9
|
+
*
|
|
10
|
+
* All functions are pure: they take data in and return data out.
|
|
11
|
+
* No filesystem access, no network, no process.
|
|
12
|
+
*
|
|
13
|
+
* ViewBox merge order (highest priority first):
|
|
14
|
+
* 1. Alias-level dimension overrides (if the reference was an alias)
|
|
15
|
+
* 2. Icon-level dimension overrides
|
|
16
|
+
* 3. Pack-level dimension defaults
|
|
17
|
+
* 4. System defaults: width=16, height=16, left=0, top=0
|
|
18
|
+
*
|
|
19
|
+
* Transform composition (alias-level on top of icon-level):
|
|
20
|
+
* rotate : (aliasRotate + iconRotate) mod 4
|
|
21
|
+
* hFlip : aliasHFlip XOR iconHFlip
|
|
22
|
+
* vFlip : aliasVFlip XOR iconVFlip
|
|
23
|
+
*
|
|
24
|
+
* Color-mode detection heuristic (precise, documented):
|
|
25
|
+
* Scan body for fill="..." and stroke="..." attribute values.
|
|
26
|
+
* If any value is not in {none, currentColor, inherit} → brand.
|
|
27
|
+
* If body contains <linearGradient or <radialGradient → brand.
|
|
28
|
+
* Otherwise → monochrome.
|
|
29
|
+
*
|
|
30
|
+
* Alias depth limit: MAX_ALIAS_DEPTH (4) to prevent infinite loops.
|
|
31
|
+
*/
|
|
32
|
+
import { ok, err } from '../contracts/result.js';
|
|
33
|
+
// ─── Token grammar ────────────────────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Valid prefix: starts with a lowercase letter, followed by lowercase alnum or hyphens.
|
|
36
|
+
* Examples: "azure", "mdi", "my-pack"
|
|
37
|
+
*/
|
|
38
|
+
const PREFIX_RE = /^[a-z][a-z0-9-]*$/;
|
|
39
|
+
/**
|
|
40
|
+
* Valid name: starts with lowercase alnum, followed by lowercase alnum or hyphens.
|
|
41
|
+
* Examples: "app-service", "server", "12px" (unusual but valid per grammar)
|
|
42
|
+
*/
|
|
43
|
+
const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
44
|
+
// ─── System defaults ──────────────────────────────────────────────────────────
|
|
45
|
+
const DEFAULT_WIDTH = 16;
|
|
46
|
+
const DEFAULT_HEIGHT = 16;
|
|
47
|
+
const DEFAULT_LEFT = 0;
|
|
48
|
+
const DEFAULT_TOP = 0;
|
|
49
|
+
/** Maximum alias chain depth. Prevents infinite loops from circular aliases. */
|
|
50
|
+
const MAX_ALIAS_DEPTH = 4;
|
|
51
|
+
// ─── parseIconRef ─────────────────────────────────────────────────────────────
|
|
52
|
+
/**
|
|
53
|
+
* Parse an icon token string of the form "prefix:name" into an IconRef.
|
|
54
|
+
*
|
|
55
|
+
* Valid: "azure:app-service", "mdi:server", "lucide:0-circle"
|
|
56
|
+
* Invalid: "no-colon", ":name" (empty prefix), "prefix:" (empty name),
|
|
57
|
+
* "Azure:App" (uppercase), "prefix:name:extra" (too many colons)
|
|
58
|
+
*
|
|
59
|
+
* Returns err(ICON_NOT_FOUND, ...) on parse failure (not ICON_VALIDATION_ERROR
|
|
60
|
+
* since this is a reference parse, not a pack-structure validation).
|
|
61
|
+
*/
|
|
62
|
+
export function parseIconRef(token) {
|
|
63
|
+
if (typeof token !== 'string' || token.length === 0) {
|
|
64
|
+
return err('ICON_NOT_FOUND', `Icon token must be a non-empty string, got ${JSON.stringify(token)}`);
|
|
65
|
+
}
|
|
66
|
+
const colonIdx = token.indexOf(':');
|
|
67
|
+
if (colonIdx === -1) {
|
|
68
|
+
return err('ICON_NOT_FOUND', `Invalid icon token ${JSON.stringify(token)}: must be "prefix:name"`);
|
|
69
|
+
}
|
|
70
|
+
// Only one colon allowed
|
|
71
|
+
if (token.indexOf(':', colonIdx + 1) !== -1) {
|
|
72
|
+
return err('ICON_NOT_FOUND', `Invalid icon token ${JSON.stringify(token)}: too many colons — expected "prefix:name"`);
|
|
73
|
+
}
|
|
74
|
+
const prefix = token.slice(0, colonIdx);
|
|
75
|
+
const name = token.slice(colonIdx + 1);
|
|
76
|
+
if (!PREFIX_RE.test(prefix)) {
|
|
77
|
+
return err('ICON_NOT_FOUND', `Invalid icon token ${JSON.stringify(token)}: prefix ${JSON.stringify(prefix)} must match ^[a-z][a-z0-9-]*$`);
|
|
78
|
+
}
|
|
79
|
+
if (!NAME_RE.test(name)) {
|
|
80
|
+
return err('ICON_NOT_FOUND', `Invalid icon token ${JSON.stringify(token)}: name ${JSON.stringify(name)} must match ^[a-z0-9][a-z0-9-]*$`);
|
|
81
|
+
}
|
|
82
|
+
return ok({ prefix, name });
|
|
83
|
+
}
|
|
84
|
+
// ─── detectColorMode ──────────────────────────────────────────────────────────
|
|
85
|
+
/**
|
|
86
|
+
* Classify an icon body as 'monochrome' or 'brand'.
|
|
87
|
+
*
|
|
88
|
+
* Heuristic (precise):
|
|
89
|
+
* 1. Scan body for fill="..." and stroke="..." attribute values.
|
|
90
|
+
* If any value is not one of {none, currentColor, inherit} → brand.
|
|
91
|
+
* 2. If body contains "<linearGradient" or "<radialGradient" → brand.
|
|
92
|
+
* 3. Otherwise → monochrome.
|
|
93
|
+
*
|
|
94
|
+
* Rationale:
|
|
95
|
+
* Monochrome icons (MDI, Lucide, Heroicons) use only fill="currentColor" or
|
|
96
|
+
* fill="none", allowing the renderer to tint them via CSS color inheritance.
|
|
97
|
+
* Brand icons (Azure architecture icons, logos) embed hardcoded hex fills
|
|
98
|
+
* and/or gradient definitions that must render verbatim.
|
|
99
|
+
*
|
|
100
|
+
* The gradient check is necessary because some icons use fill="url(#grad1)"
|
|
101
|
+
* which would pass the fill-value check but still requires brand rendering.
|
|
102
|
+
*
|
|
103
|
+
* Note: this is a string scan heuristic, not a full SVG parser. It handles
|
|
104
|
+
* well-formed IconifyJSON bodies as produced by @iconify/tools. Pathological
|
|
105
|
+
* bodies with fill/stroke in non-attribute contexts (e.g. CSS text) could
|
|
106
|
+
* produce false positives, but this is acceptable for the BYOP use case.
|
|
107
|
+
*/
|
|
108
|
+
export function detectColorMode(body) {
|
|
109
|
+
// Gradient definitions always → brand
|
|
110
|
+
if (body.includes('<linearGradient') || body.includes('<radialGradient')) {
|
|
111
|
+
return 'brand';
|
|
112
|
+
}
|
|
113
|
+
// Scan fill="..." and stroke="..." attribute values
|
|
114
|
+
// Match: fill="value" or stroke="value" (handles single/double quotes)
|
|
115
|
+
const ATTR_RE = /(?:fill|stroke)=["']([^"']+)["']/g;
|
|
116
|
+
const NEUTRAL = new Set(['none', 'currentcolor', 'inherit']);
|
|
117
|
+
let match;
|
|
118
|
+
while ((match = ATTR_RE.exec(body)) !== null) {
|
|
119
|
+
const value = match[1];
|
|
120
|
+
if (value === undefined)
|
|
121
|
+
continue;
|
|
122
|
+
// Normalize to lowercase for case-insensitive comparison
|
|
123
|
+
const lower = value.toLowerCase();
|
|
124
|
+
if (!NEUTRAL.has(lower)) {
|
|
125
|
+
return 'brand';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return 'monochrome';
|
|
129
|
+
}
|
|
130
|
+
function mergeViewBox(aliasLevel, iconLevel, packLevel) {
|
|
131
|
+
return {
|
|
132
|
+
width: aliasLevel.width ?? iconLevel.width ?? packLevel.width ?? DEFAULT_WIDTH,
|
|
133
|
+
height: aliasLevel.height ?? iconLevel.height ?? packLevel.height ?? DEFAULT_HEIGHT,
|
|
134
|
+
left: aliasLevel.left ?? iconLevel.left ?? packLevel.left ?? DEFAULT_LEFT,
|
|
135
|
+
top: aliasLevel.top ?? iconLevel.top ?? packLevel.top ?? DEFAULT_TOP,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// ─── Internal: transform composition ─────────────────────────────────────────
|
|
139
|
+
function composeTransforms(icon, alias) {
|
|
140
|
+
const iconRotate = icon.rotate ?? 0;
|
|
141
|
+
const iconHFlip = icon.hFlip ?? false;
|
|
142
|
+
const iconVFlip = icon.vFlip ?? false;
|
|
143
|
+
if (alias === null) {
|
|
144
|
+
return {
|
|
145
|
+
rotate: iconRotate,
|
|
146
|
+
hFlip: iconHFlip,
|
|
147
|
+
vFlip: iconVFlip,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const aliasRotate = alias.rotate ?? 0;
|
|
151
|
+
const aliasHFlip = alias.hFlip ?? false;
|
|
152
|
+
const aliasVFlip = alias.vFlip ?? false;
|
|
153
|
+
return {
|
|
154
|
+
rotate: ((iconRotate + aliasRotate) % 4),
|
|
155
|
+
hFlip: iconHFlip !== aliasHFlip, // XOR
|
|
156
|
+
vFlip: iconVFlip !== aliasVFlip, // XOR
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// ─── resolveIcon ─────────────────────────────────────────────────────────────
|
|
160
|
+
/**
|
|
161
|
+
* Resolve an IconRef against an IconPackMap to produce a ResolvedIcon.
|
|
162
|
+
*
|
|
163
|
+
* Resolution steps:
|
|
164
|
+
* 1. Look up the pack by ref.prefix. → ICON_NOT_FOUND if absent.
|
|
165
|
+
* 2. Look for ref.name in pack.icons. If found, use it directly.
|
|
166
|
+
* 3. Else look in pack.aliases. Follow the alias chain up to MAX_ALIAS_DEPTH.
|
|
167
|
+
* → ICON_NOT_FOUND if name not in icons or aliases, or chain too deep.
|
|
168
|
+
* 4. Merge viewBox dimensions: alias-level → icon-level → pack-level → defaults.
|
|
169
|
+
* 5. Compose transforms: alias-level on top of icon-level.
|
|
170
|
+
* 6. Detect colorMode from the resolved body.
|
|
171
|
+
*
|
|
172
|
+
* Pure — never throws, never touches the filesystem.
|
|
173
|
+
*/
|
|
174
|
+
export function resolveIcon(ref, packs) {
|
|
175
|
+
const pack = packs.get(ref.prefix);
|
|
176
|
+
if (pack === undefined) {
|
|
177
|
+
return err('ICON_NOT_FOUND', `Icon pack "${ref.prefix}" not loaded (looking up "${ref.prefix}:${ref.name}")`);
|
|
178
|
+
}
|
|
179
|
+
// Try direct icon lookup first
|
|
180
|
+
const directIcon = pack.icons[ref.name];
|
|
181
|
+
if (directIcon !== undefined) {
|
|
182
|
+
const viewBox = mergeViewBox({}, directIcon, pack);
|
|
183
|
+
const transforms = composeTransforms(directIcon, null);
|
|
184
|
+
return ok({
|
|
185
|
+
body: directIcon.body,
|
|
186
|
+
viewBox,
|
|
187
|
+
transforms,
|
|
188
|
+
colorMode: detectColorMode(directIcon.body),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
// Try alias lookup
|
|
192
|
+
const aliases = pack.aliases;
|
|
193
|
+
if (aliases === undefined || !(ref.name in aliases)) {
|
|
194
|
+
return err('ICON_NOT_FOUND', `Icon "${ref.name}" not found in pack "${ref.prefix}" (checked icons and aliases)`);
|
|
195
|
+
}
|
|
196
|
+
// Follow alias chain, accumulating the first alias's transform/dim overrides
|
|
197
|
+
let currentName = ref.name;
|
|
198
|
+
let currentAlias = aliases[ref.name] ?? null;
|
|
199
|
+
const topAlias = currentAlias; // preserve top-level alias for dim/transform composition
|
|
200
|
+
for (let depth = 0; depth < MAX_ALIAS_DEPTH; depth++) {
|
|
201
|
+
if (currentAlias === null)
|
|
202
|
+
break;
|
|
203
|
+
const parentName = currentAlias.parent;
|
|
204
|
+
const parentIcon = pack.icons[parentName];
|
|
205
|
+
if (parentIcon !== undefined) {
|
|
206
|
+
// Found the base icon — compose transforms and merge viewBox
|
|
207
|
+
const viewBox = mergeViewBox(topAlias ?? {}, parentIcon, pack);
|
|
208
|
+
const transforms = composeTransforms(parentIcon, topAlias);
|
|
209
|
+
return ok({
|
|
210
|
+
body: parentIcon.body,
|
|
211
|
+
viewBox,
|
|
212
|
+
transforms,
|
|
213
|
+
colorMode: detectColorMode(parentIcon.body),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
// Parent is itself an alias — follow one more level
|
|
217
|
+
const parentAlias = aliases[parentName];
|
|
218
|
+
if (parentAlias === undefined) {
|
|
219
|
+
return err('ICON_NOT_FOUND', `Alias "${currentName}" in pack "${ref.prefix}" points to parent "${parentName}" which does not exist`);
|
|
220
|
+
}
|
|
221
|
+
currentName = parentName;
|
|
222
|
+
currentAlias = parentAlias;
|
|
223
|
+
}
|
|
224
|
+
return err('ICON_NOT_FOUND', `Alias chain for "${ref.name}" in pack "${ref.prefix}" exceeds maximum depth of ${MAX_ALIAS_DEPTH}`);
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../../../src/icons/resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validateIconPack
|
|
3
|
+
*
|
|
4
|
+
* Pure validator for `.triton-icons.json` icon pack files. No file or network
|
|
5
|
+
* I/O — only validates an already-parsed JSON value against the IconifyJSON
|
|
6
|
+
* contract. Returns a Result so callers never need try/catch.
|
|
7
|
+
*
|
|
8
|
+
* Strictness policy:
|
|
9
|
+
* - Top-level Triton keys: strict (unknown keys are an error).
|
|
10
|
+
* - IconData and IconAlias entries: strict (unknown keys are an error).
|
|
11
|
+
* - All required fields must be present with the correct types.
|
|
12
|
+
* - Icon names and prefix format are validated against the token grammar.
|
|
13
|
+
*
|
|
14
|
+
* Token grammar (enforced here):
|
|
15
|
+
* prefix ::= [a-z][a-z0-9-]*
|
|
16
|
+
* name ::= [a-z0-9][a-z0-9-]*
|
|
17
|
+
*/
|
|
18
|
+
import type { IconifyJSON } from '../contracts/icons.js';
|
|
19
|
+
import { type Result } from '../contracts/result.js';
|
|
20
|
+
/**
|
|
21
|
+
* Validate an unknown value against the IconifyJSON contract.
|
|
22
|
+
*
|
|
23
|
+
* Pure and synchronous — never throws, never reads files.
|
|
24
|
+
* Returns ok(IconifyJSON) on success, err(ICON_VALIDATION_ERROR, ...) on any violation.
|
|
25
|
+
*
|
|
26
|
+
* Validates:
|
|
27
|
+
* - Required fields: prefix, icons
|
|
28
|
+
* - prefix format: [a-z][a-z0-9-]*
|
|
29
|
+
* - icons: at least one entry; each key matches [a-z0-9][a-z0-9-]*
|
|
30
|
+
* - Each IconData: required body, optional dims (positive), rotate (0–3), flips (boolean)
|
|
31
|
+
* - aliases: each alias key matches [a-z0-9][a-z0-9-]*; required parent
|
|
32
|
+
* - Pack-level dims: positive numbers if present
|
|
33
|
+
* - Unknown keys at any level: hard error
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateIconPack(json: unknown): Result<IconifyJSON>;
|
|
36
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/icons/validate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAwK9D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,CAsGnE"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* validateIconPack
|
|
3
|
+
*
|
|
4
|
+
* Pure validator for `.triton-icons.json` icon pack files. No file or network
|
|
5
|
+
* I/O — only validates an already-parsed JSON value against the IconifyJSON
|
|
6
|
+
* contract. Returns a Result so callers never need try/catch.
|
|
7
|
+
*
|
|
8
|
+
* Strictness policy:
|
|
9
|
+
* - Top-level Triton keys: strict (unknown keys are an error).
|
|
10
|
+
* - IconData and IconAlias entries: strict (unknown keys are an error).
|
|
11
|
+
* - All required fields must be present with the correct types.
|
|
12
|
+
* - Icon names and prefix format are validated against the token grammar.
|
|
13
|
+
*
|
|
14
|
+
* Token grammar (enforced here):
|
|
15
|
+
* prefix ::= [a-z][a-z0-9-]*
|
|
16
|
+
* name ::= [a-z0-9][a-z0-9-]*
|
|
17
|
+
*/
|
|
18
|
+
import { ok, err } from '../contracts/result.js';
|
|
19
|
+
// ─── Known key sets ───────────────────────────────────────────────────────────
|
|
20
|
+
const TOP_LEVEL_KEYS = new Set([
|
|
21
|
+
'prefix', 'icons', 'aliases', 'width', 'height', 'left', 'top',
|
|
22
|
+
]);
|
|
23
|
+
const ICON_DATA_KEYS = new Set([
|
|
24
|
+
'body', 'width', 'height', 'left', 'top', 'rotate', 'hFlip', 'vFlip',
|
|
25
|
+
]);
|
|
26
|
+
const ICON_ALIAS_KEYS = new Set([
|
|
27
|
+
'parent', 'rotate', 'hFlip', 'vFlip', 'width', 'height', 'left', 'top',
|
|
28
|
+
]);
|
|
29
|
+
// ─── Token grammar regexes ────────────────────────────────────────────────────
|
|
30
|
+
/** Pack prefix: starts with a lowercase letter, then lowercase alnum/hyphens. */
|
|
31
|
+
const PREFIX_RE = /^[a-z][a-z0-9-]*$/;
|
|
32
|
+
/** Icon/alias name: starts with lowercase alnum, then lowercase alnum/hyphens. */
|
|
33
|
+
const NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
34
|
+
const VALID_ROTATE = new Set([0, 1, 2, 3]);
|
|
35
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
36
|
+
function isPlainObject(v) {
|
|
37
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
38
|
+
}
|
|
39
|
+
function fail(message) {
|
|
40
|
+
return err('ICON_VALIDATION_ERROR', message);
|
|
41
|
+
}
|
|
42
|
+
// ─── IconData validator ───────────────────────────────────────────────────────
|
|
43
|
+
function validateIconData(iconName, obj) {
|
|
44
|
+
const ctx = `icons["${iconName}"]`;
|
|
45
|
+
if (!isPlainObject(obj)) {
|
|
46
|
+
return fail(`${ctx} must be a plain object`);
|
|
47
|
+
}
|
|
48
|
+
for (const key of Object.keys(obj)) {
|
|
49
|
+
if (!ICON_DATA_KEYS.has(key)) {
|
|
50
|
+
return fail(`Unknown key in ${ctx}: "${key}"`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// body — required, non-empty string
|
|
54
|
+
if (!('body' in obj)) {
|
|
55
|
+
return fail(`${ctx} is missing required field "body"`);
|
|
56
|
+
}
|
|
57
|
+
const body = obj['body'];
|
|
58
|
+
if (typeof body !== 'string' || body.length === 0) {
|
|
59
|
+
return fail(`${ctx}.body must be a non-empty string, got ${JSON.stringify(body)}`);
|
|
60
|
+
}
|
|
61
|
+
// width / height — optional positive numbers
|
|
62
|
+
for (const dim of ['width', 'height']) {
|
|
63
|
+
if (dim in obj) {
|
|
64
|
+
const val = obj[dim];
|
|
65
|
+
if (typeof val !== 'number' || val <= 0) {
|
|
66
|
+
return fail(`${ctx}.${dim} must be a positive number, got ${JSON.stringify(val)}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// left / top — optional numbers (may be zero or negative for unusual viewBoxes)
|
|
71
|
+
for (const origin of ['left', 'top']) {
|
|
72
|
+
if (origin in obj) {
|
|
73
|
+
const val = obj[origin];
|
|
74
|
+
if (typeof val !== 'number') {
|
|
75
|
+
return fail(`${ctx}.${origin} must be a number, got ${JSON.stringify(val)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// rotate — optional, must be 0 | 1 | 2 | 3
|
|
80
|
+
if ('rotate' in obj) {
|
|
81
|
+
const val = obj['rotate'];
|
|
82
|
+
if (!VALID_ROTATE.has(val)) {
|
|
83
|
+
return fail(`${ctx}.rotate must be 0, 1, 2, or 3, got ${JSON.stringify(val)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// hFlip / vFlip — optional booleans
|
|
87
|
+
for (const flip of ['hFlip', 'vFlip']) {
|
|
88
|
+
if (flip in obj) {
|
|
89
|
+
const val = obj[flip];
|
|
90
|
+
if (typeof val !== 'boolean') {
|
|
91
|
+
return fail(`${ctx}.${flip} must be a boolean, got ${JSON.stringify(val)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return ok(obj);
|
|
96
|
+
}
|
|
97
|
+
// ─── IconAlias validator ──────────────────────────────────────────────────────
|
|
98
|
+
function validateIconAlias(aliasName, obj) {
|
|
99
|
+
const ctx = `aliases["${aliasName}"]`;
|
|
100
|
+
if (!isPlainObject(obj)) {
|
|
101
|
+
return fail(`${ctx} must be a plain object`);
|
|
102
|
+
}
|
|
103
|
+
for (const key of Object.keys(obj)) {
|
|
104
|
+
if (!ICON_ALIAS_KEYS.has(key)) {
|
|
105
|
+
return fail(`Unknown key in ${ctx}: "${key}"`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// parent — required, non-empty string
|
|
109
|
+
if (!('parent' in obj)) {
|
|
110
|
+
return fail(`${ctx} is missing required field "parent"`);
|
|
111
|
+
}
|
|
112
|
+
const parent = obj['parent'];
|
|
113
|
+
if (typeof parent !== 'string' || parent.length === 0) {
|
|
114
|
+
return fail(`${ctx}.parent must be a non-empty string, got ${JSON.stringify(parent)}`);
|
|
115
|
+
}
|
|
116
|
+
// rotate — optional, 0 | 1 | 2 | 3
|
|
117
|
+
if ('rotate' in obj) {
|
|
118
|
+
const val = obj['rotate'];
|
|
119
|
+
if (!VALID_ROTATE.has(val)) {
|
|
120
|
+
return fail(`${ctx}.rotate must be 0, 1, 2, or 3, got ${JSON.stringify(val)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// hFlip / vFlip — optional booleans
|
|
124
|
+
for (const flip of ['hFlip', 'vFlip']) {
|
|
125
|
+
if (flip in obj) {
|
|
126
|
+
const val = obj[flip];
|
|
127
|
+
if (typeof val !== 'boolean') {
|
|
128
|
+
return fail(`${ctx}.${flip} must be a boolean, got ${JSON.stringify(val)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// width / height — optional positive numbers
|
|
133
|
+
for (const dim of ['width', 'height']) {
|
|
134
|
+
if (dim in obj) {
|
|
135
|
+
const val = obj[dim];
|
|
136
|
+
if (typeof val !== 'number' || val <= 0) {
|
|
137
|
+
return fail(`${ctx}.${dim} must be a positive number, got ${JSON.stringify(val)}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// left / top — optional numbers
|
|
142
|
+
for (const origin of ['left', 'top']) {
|
|
143
|
+
if (origin in obj) {
|
|
144
|
+
const val = obj[origin];
|
|
145
|
+
if (typeof val !== 'number') {
|
|
146
|
+
return fail(`${ctx}.${origin} must be a number, got ${JSON.stringify(val)}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return ok(obj);
|
|
151
|
+
}
|
|
152
|
+
// ─── Main validator ───────────────────────────────────────────────────────────
|
|
153
|
+
/**
|
|
154
|
+
* Validate an unknown value against the IconifyJSON contract.
|
|
155
|
+
*
|
|
156
|
+
* Pure and synchronous — never throws, never reads files.
|
|
157
|
+
* Returns ok(IconifyJSON) on success, err(ICON_VALIDATION_ERROR, ...) on any violation.
|
|
158
|
+
*
|
|
159
|
+
* Validates:
|
|
160
|
+
* - Required fields: prefix, icons
|
|
161
|
+
* - prefix format: [a-z][a-z0-9-]*
|
|
162
|
+
* - icons: at least one entry; each key matches [a-z0-9][a-z0-9-]*
|
|
163
|
+
* - Each IconData: required body, optional dims (positive), rotate (0–3), flips (boolean)
|
|
164
|
+
* - aliases: each alias key matches [a-z0-9][a-z0-9-]*; required parent
|
|
165
|
+
* - Pack-level dims: positive numbers if present
|
|
166
|
+
* - Unknown keys at any level: hard error
|
|
167
|
+
*/
|
|
168
|
+
export function validateIconPack(json) {
|
|
169
|
+
if (!isPlainObject(json)) {
|
|
170
|
+
return fail(`IconifyJSON must be a non-null plain object, got ${json === null ? 'null' : Array.isArray(json) ? 'array' : typeof json}`);
|
|
171
|
+
}
|
|
172
|
+
// Unknown top-level key check
|
|
173
|
+
for (const key of Object.keys(json)) {
|
|
174
|
+
if (!TOP_LEVEL_KEYS.has(key)) {
|
|
175
|
+
return fail(`Unknown top-level key: "${key}"`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// prefix — required string matching [a-z][a-z0-9-]*
|
|
179
|
+
if (!('prefix' in json)) {
|
|
180
|
+
return fail('Missing required field "prefix"');
|
|
181
|
+
}
|
|
182
|
+
const prefix = json['prefix'];
|
|
183
|
+
if (typeof prefix !== 'string') {
|
|
184
|
+
return fail(`"prefix" must be a string, got ${JSON.stringify(prefix)}`);
|
|
185
|
+
}
|
|
186
|
+
if (!PREFIX_RE.test(prefix)) {
|
|
187
|
+
return fail(`"prefix" must match ^[a-z][a-z0-9-]*$ (lowercase letter start, then lowercase alnum/hyphens), got ${JSON.stringify(prefix)}`);
|
|
188
|
+
}
|
|
189
|
+
// icons — required plain object with ≥1 entry
|
|
190
|
+
if (!('icons' in json)) {
|
|
191
|
+
return fail('Missing required field "icons"');
|
|
192
|
+
}
|
|
193
|
+
const iconsRaw = json['icons'];
|
|
194
|
+
if (!isPlainObject(iconsRaw)) {
|
|
195
|
+
return fail('"icons" must be a plain object');
|
|
196
|
+
}
|
|
197
|
+
const iconNames = Object.keys(iconsRaw);
|
|
198
|
+
if (iconNames.length === 0) {
|
|
199
|
+
return fail('"icons" must contain at least one icon entry');
|
|
200
|
+
}
|
|
201
|
+
const icons = {};
|
|
202
|
+
for (const name of iconNames) {
|
|
203
|
+
if (!NAME_RE.test(name)) {
|
|
204
|
+
return fail(`Icon name ${JSON.stringify(name)} must match ^[a-z0-9][a-z0-9-]*$ (lowercase alnum start, then lowercase alnum/hyphens)`);
|
|
205
|
+
}
|
|
206
|
+
const r = validateIconData(name, iconsRaw[name]);
|
|
207
|
+
if (!r.ok)
|
|
208
|
+
return r;
|
|
209
|
+
icons[name] = r.value;
|
|
210
|
+
}
|
|
211
|
+
// aliases — optional plain object
|
|
212
|
+
let aliases;
|
|
213
|
+
if ('aliases' in json) {
|
|
214
|
+
const aliasesRaw = json['aliases'];
|
|
215
|
+
if (!isPlainObject(aliasesRaw)) {
|
|
216
|
+
return fail('"aliases" must be a plain object');
|
|
217
|
+
}
|
|
218
|
+
aliases = {};
|
|
219
|
+
for (const aliasName of Object.keys(aliasesRaw)) {
|
|
220
|
+
if (!NAME_RE.test(aliasName)) {
|
|
221
|
+
return fail(`Alias name ${JSON.stringify(aliasName)} must match ^[a-z0-9][a-z0-9-]*$`);
|
|
222
|
+
}
|
|
223
|
+
const r = validateIconAlias(aliasName, aliasesRaw[aliasName]);
|
|
224
|
+
if (!r.ok)
|
|
225
|
+
return r;
|
|
226
|
+
aliases[aliasName] = r.value;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Pack-level dimension defaults — optional positive numbers (width/height) or numbers (left/top)
|
|
230
|
+
for (const dim of ['width', 'height']) {
|
|
231
|
+
if (dim in json) {
|
|
232
|
+
const val = json[dim];
|
|
233
|
+
if (typeof val !== 'number' || val <= 0) {
|
|
234
|
+
return fail(`"${dim}" must be a positive number, got ${JSON.stringify(val)}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
for (const origin of ['left', 'top']) {
|
|
239
|
+
if (origin in json) {
|
|
240
|
+
const val = json[origin];
|
|
241
|
+
if (typeof val !== 'number') {
|
|
242
|
+
return fail(`"${origin}" must be a number, got ${JSON.stringify(val)}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const result = {
|
|
247
|
+
prefix: prefix,
|
|
248
|
+
icons,
|
|
249
|
+
...(aliases !== undefined ? { aliases } : {}),
|
|
250
|
+
...('width' in json ? { width: json['width'] } : {}),
|
|
251
|
+
...('height' in json ? { height: json['height'] } : {}),
|
|
252
|
+
...('left' in json ? { left: json['left'] } : {}),
|
|
253
|
+
...('top' in json ? { top: json['top'] } : {}),
|
|
254
|
+
};
|
|
255
|
+
return ok(result);
|
|
256
|
+
}
|
|
257
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../src/icons/validate.ts"],"names":[],"mappings":"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"}
|