@krapwoo/ds-viewer 0.14.2 → 0.15.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/README.md +224 -2
- package/dist/cli/doctor.js +306 -17
- package/dist/cli/explain.js +26 -0
- package/dist/cli/staticPage.js +90 -6
- package/dist/cli/tokenDefinition.js +125 -0
- package/dist/native/catalog/catalogNavigation.js +27 -11
- package/dist/native/catalog/pageApi.js +557 -26
- package/dist/native/catalog/tokenDefinition.js +205 -0
- package/native/catalog/CatalogSearchInput.tsx +18 -3
- package/native/catalog/CatalogShell.tsx +318 -46
- package/native/catalog/CatalogSidebar.tsx +37 -1
- package/native/catalog/FamilyPage.tsx +567 -137
- package/native/catalog/GroupPage.tsx +230 -0
- package/native/catalog/JumpRow.tsx +81 -0
- package/native/catalog/ReferenceDetails.tsx +144 -16
- package/native/catalog/SectionBlock.tsx +49 -5
- package/native/catalog/SourceReferencePicker.tsx +180 -0
- package/native/catalog/StructuredTokenPage.tsx +592 -0
- package/native/catalog/Swatch.tsx +29 -2
- package/native/catalog/TokenLayouts.tsx +30 -9
- package/native/catalog/catalogNavigation.ts +30 -10
- package/native/catalog/catalogReferences.ts +212 -0
- package/native/catalog/familyModel.ts +10 -4
- package/native/catalog/index.ts +22 -0
- package/native/catalog/pageApi.ts +595 -23
- package/native/catalog/tokenDefinition.ts +430 -0
- package/native/catalog/types.ts +77 -5
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static, literal-only reader for `CatalogPageInput.tokenDefinition` — the same posture
|
|
3
|
+
* `cli/staticPage.ts`'s own `readStaticPage` already uses for every other field: no module
|
|
4
|
+
* resolution, no execution, a same-file `const` chase only (`resolve`, reused from
|
|
5
|
+
* `cli/staticPage.ts`). Reads structural metadata only (`kind`, section `id`/`title`/`desc`/`wide`,
|
|
6
|
+
* and each entry's own literal `id`, for duplicate detection) — never an entry's real value, which
|
|
7
|
+
* stays an opaque runtime import (design R4).
|
|
8
|
+
*/
|
|
9
|
+
import * as ts from 'typescript';
|
|
10
|
+
import { findProp, propertyStringLiteral, readStringLiteralArray, resolve } from "./staticPage.js";
|
|
11
|
+
import { canonicalTokenTitle, isTokenKind } from "../native/catalog/tokenDefinition.js";
|
|
12
|
+
/** Reads `node` (a `tokenDefinition:` property initializer) down to `kind` and each section's
|
|
13
|
+
* `id`/`title`/`desc`/`wide`/entry-ids. Returns `undefined` — never a partial read — when `kind`
|
|
14
|
+
* isn't a literal, `sections` isn't a literal array, or any one section isn't a literal object
|
|
15
|
+
* with a literal `id` and `title`: the same "never a partial read" contract every other array
|
|
16
|
+
* reader in `cli/staticPage.ts` already follows (`readComposedOf`, `readSections`, …). An entry
|
|
17
|
+
* whose own `id` isn't literal is simply omitted from `entryIds` — informational leniency, since
|
|
18
|
+
* only the *structural* shape (kind/sections/ids) needs to be checkable, never an entry's real
|
|
19
|
+
* value (design R4: "no blanket uncheckability of otherwise literal page geometry"). */
|
|
20
|
+
export function readStaticTokenDefinition(node, consts) {
|
|
21
|
+
const resolved = resolve(node, consts, new Set());
|
|
22
|
+
if (!ts.isObjectLiteralExpression(resolved))
|
|
23
|
+
return undefined;
|
|
24
|
+
const kind = propertyStringLiteral(resolved, 'kind', consts);
|
|
25
|
+
if (kind === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
const sectionsProp = findProp(resolved, 'sections');
|
|
28
|
+
if (!sectionsProp)
|
|
29
|
+
return undefined;
|
|
30
|
+
const sectionsResolved = resolve(sectionsProp.initializer, consts, new Set());
|
|
31
|
+
if (!ts.isArrayLiteralExpression(sectionsResolved))
|
|
32
|
+
return undefined;
|
|
33
|
+
const sections = [];
|
|
34
|
+
for (const element of sectionsResolved.elements) {
|
|
35
|
+
const sectionResolved = resolve(element, consts, new Set());
|
|
36
|
+
if (!ts.isObjectLiteralExpression(sectionResolved))
|
|
37
|
+
return undefined;
|
|
38
|
+
const id = propertyStringLiteral(sectionResolved, 'id', consts);
|
|
39
|
+
const title = propertyStringLiteral(sectionResolved, 'title', consts);
|
|
40
|
+
if (id === undefined || title === undefined)
|
|
41
|
+
return undefined;
|
|
42
|
+
const desc = propertyStringLiteral(sectionResolved, 'desc', consts);
|
|
43
|
+
const wideProp = findProp(sectionResolved, 'wide');
|
|
44
|
+
const wide = wideProp ? resolve(wideProp.initializer, consts, new Set()).kind === ts.SyntaxKind.TrueKeyword : false;
|
|
45
|
+
const entryIds = [];
|
|
46
|
+
let entriesOpaque = false;
|
|
47
|
+
const entriesProp = findProp(sectionResolved, 'entries');
|
|
48
|
+
if (entriesProp) {
|
|
49
|
+
const entriesResolved = resolve(entriesProp.initializer, consts, new Set());
|
|
50
|
+
if (ts.isArrayLiteralExpression(entriesResolved)) {
|
|
51
|
+
for (const entryElement of entriesResolved.elements) {
|
|
52
|
+
const entryResolved = resolve(entryElement, consts, new Set());
|
|
53
|
+
if (!ts.isObjectLiteralExpression(entryResolved)) {
|
|
54
|
+
entriesOpaque = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const entryId = propertyStringLiteral(entryResolved, 'id', consts);
|
|
58
|
+
if (entryId !== undefined)
|
|
59
|
+
entryIds.push(entryId);
|
|
60
|
+
else
|
|
61
|
+
entriesOpaque = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
entriesOpaque = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// #64 B1: this section's own sub-groups, read the same lenient way as its own entries above.
|
|
69
|
+
const groups = [];
|
|
70
|
+
let groupsOpaque = false;
|
|
71
|
+
const groupsProp = findProp(sectionResolved, 'groups');
|
|
72
|
+
if (groupsProp) {
|
|
73
|
+
const groupsResolved = resolve(groupsProp.initializer, consts, new Set());
|
|
74
|
+
if (ts.isArrayLiteralExpression(groupsResolved)) {
|
|
75
|
+
for (const groupElement of groupsResolved.elements) {
|
|
76
|
+
const groupResolved = resolve(groupElement, consts, new Set());
|
|
77
|
+
if (!ts.isObjectLiteralExpression(groupResolved)) {
|
|
78
|
+
groupsOpaque = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const groupId = propertyStringLiteral(groupResolved, 'id', consts);
|
|
82
|
+
const groupTitle = propertyStringLiteral(groupResolved, 'title', consts);
|
|
83
|
+
if (groupId === undefined || groupTitle === undefined) {
|
|
84
|
+
groupsOpaque = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const groupEntryIds = [];
|
|
88
|
+
let groupEntriesOpaque = false;
|
|
89
|
+
const groupEntriesProp = findProp(groupResolved, 'entries');
|
|
90
|
+
if (groupEntriesProp) {
|
|
91
|
+
const groupEntriesResolved = resolve(groupEntriesProp.initializer, consts, new Set());
|
|
92
|
+
if (ts.isArrayLiteralExpression(groupEntriesResolved)) {
|
|
93
|
+
for (const entryElement of groupEntriesResolved.elements) {
|
|
94
|
+
const entryResolved = resolve(entryElement, consts, new Set());
|
|
95
|
+
if (!ts.isObjectLiteralExpression(entryResolved)) {
|
|
96
|
+
groupEntriesOpaque = true;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const entryId = propertyStringLiteral(entryResolved, 'id', consts);
|
|
100
|
+
if (entryId !== undefined)
|
|
101
|
+
groupEntryIds.push(entryId);
|
|
102
|
+
else
|
|
103
|
+
groupEntriesOpaque = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
groupEntriesOpaque = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
groups.push({ id: groupId, title: groupTitle, entryIds: groupEntryIds, entriesOpaque: groupEntriesOpaque });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
groupsOpaque = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// #64 B5: this section's own literal `aliases`, when every element resolves as a literal
|
|
118
|
+
// string — omitted (never a penalty) otherwise.
|
|
119
|
+
const aliasesProp = findProp(sectionResolved, 'aliases');
|
|
120
|
+
const aliases = aliasesProp ? readStringLiteralArray(aliasesProp.initializer, consts) : undefined;
|
|
121
|
+
sections.push({ id, title, desc, wide, entryIds, entriesOpaque, groups, groupsOpaque, ...(aliases !== undefined ? { aliases } : null) });
|
|
122
|
+
}
|
|
123
|
+
return { kind, sections };
|
|
124
|
+
}
|
|
125
|
+
export { canonicalTokenTitle, isTokenKind };
|
|
@@ -132,23 +132,37 @@ export function resolveActiveFromHash(hash, order) {
|
|
|
132
132
|
return idFromHash(hash, order);
|
|
133
133
|
}
|
|
134
134
|
/** Every member id other than the whole, every member alias, and every family page's own
|
|
135
|
-
* (page-level) alias, mapped to where it resolves (spec §5.3 "Old addresses").
|
|
136
|
-
* `
|
|
135
|
+
* (page-level) alias, mapped to where it resolves (spec §5.3 "Old addresses"). #64 B5: also, a
|
|
136
|
+
* tokenDefinition page's own page-level aliases (`tokenDefinitionAliases`) and each of its
|
|
137
|
+
* sections' own `aliases` — the same routing a family page's aliases already get, extended to
|
|
138
|
+
* tokenDefinition pages. A page with neither contributes nothing. */
|
|
137
139
|
export function aliasTargets(sections) {
|
|
138
140
|
const targets = new Map();
|
|
139
141
|
for (const section of sections) {
|
|
140
142
|
const family = section.family;
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
if (family) {
|
|
144
|
+
for (const member of family.members) {
|
|
145
|
+
if (member.id === family.whole) {
|
|
146
|
+
// C3: the whole's own id already resolves via `order` (it equals the page's own id), but
|
|
147
|
+
// its own aliases were never registered anywhere — routing one to the page, with no member
|
|
148
|
+
// focus (unlike a non-whole member's alias, which focuses that member).
|
|
149
|
+
for (const alias of member.aliases ?? [])
|
|
150
|
+
targets.set(alias, { pageId: section.id });
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
targets.set(member.id, { pageId: section.id, memberId: member.id });
|
|
154
|
+
for (const alias of member.aliases ?? [])
|
|
155
|
+
targets.set(alias, { pageId: section.id, memberId: member.id });
|
|
156
|
+
}
|
|
157
|
+
for (const alias of family.aliases ?? [])
|
|
158
|
+
targets.set(alias, { pageId: section.id });
|
|
149
159
|
}
|
|
150
|
-
for (const alias of
|
|
160
|
+
for (const alias of section.tokenDefinitionAliases ?? [])
|
|
151
161
|
targets.set(alias, { pageId: section.id });
|
|
162
|
+
for (const tdSection of section.tokenDefinition?.sections ?? []) {
|
|
163
|
+
for (const alias of tdSection.aliases ?? [])
|
|
164
|
+
targets.set(alias, { pageId: section.id, sectionId: tdSection.id });
|
|
165
|
+
}
|
|
152
166
|
}
|
|
153
167
|
return targets;
|
|
154
168
|
}
|
|
@@ -171,6 +185,8 @@ export function resolveRoute(hash, order, aliases) {
|
|
|
171
185
|
if (target) {
|
|
172
186
|
if (target.memberId !== undefined)
|
|
173
187
|
return { kind: 'member', pageId: target.pageId, memberId: target.memberId };
|
|
188
|
+
if (target.sectionId !== undefined)
|
|
189
|
+
return { kind: 'page', id: target.pageId, sectionId: target.sectionId };
|
|
174
190
|
return { kind: 'page', id: target.pageId };
|
|
175
191
|
}
|
|
176
192
|
return { kind: 'notFound', raw: decoded };
|