@astryxdesign/cli 0.6.3-canary.f22695a → 0.6.3
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 +1 -2
- package/api/build/build.type.d.mts +2 -2
- package/api/build/build.type.mjs +2 -2
- package/api/component/component.type.d.mts +6 -6
- package/api/component/component.type.mjs +19 -19
- package/api/discover/discover.type.d.mts +4 -4
- package/api/discover/discover.type.mjs +10 -10
- package/api/docs/_adapter.d.mts +24 -37
- package/api/docs/_adapter.mjs +83 -169
- package/api/docs/detail/detail.mjs +63 -14
- package/api/docs/detail/section/section.d.mts +1 -1
- package/api/docs/detail/section/section.mjs +20 -44
- package/api/docs/detail/section/section.test.mjs +0 -41
- package/api/docs/docs.d.mts +2 -7
- package/api/docs/docs.doc.mjs +10 -27
- package/api/docs/docs.mjs +9 -16
- package/api/docs/docs.test.mjs +0 -6
- package/api/docs/docs.type.d.mts +3 -40
- package/api/docs/docs.type.mjs +8 -36
- package/api/docs/integrationDocs.test.mjs +0 -106
- package/api/doctor/doctor.d.mts +0 -48
- package/api/doctor/doctor.mjs +0 -232
- package/api/doctor/doctor.test.mjs +0 -196
- package/api/hook/hook.type.d.mts +3 -3
- package/api/hook/hook.type.mjs +11 -11
- package/api/hook/list/list.d.mts +1 -1
- package/api/integration/add-contribution.mjs +3 -5
- package/api/integration/add-contribution.test.mjs +4 -4
- package/api/integration/integration-authoring.type.d.mts +1 -1
- package/api/integration/pack-check.mjs +7 -49
- package/api/integration/pack-check.test.mjs +0 -249
- package/api/search/search.d.mts +1 -1
- package/api/search/search.mjs +5 -5
- package/api/search/search.type.d.mts +2 -2
- package/api/search/search.type.mjs +1 -1
- package/api/swizzle/swizzle.type.d.mts +2 -2
- package/api/swizzle/swizzle.type.mjs +2 -2
- package/api/template/template.d.mts +1 -1
- package/api/template/template.type.d.mts +6 -6
- package/api/template/template.type.mjs +12 -12
- package/api/theme/build/build.mjs +6 -20
- package/api/theme/build/build.test.mjs +0 -127
- package/api/theme/palette/generate/generate.mjs +1 -1
- package/api/theme/palette/generate/generator.d.mts +13 -10
- package/api/theme/palette/generate/generator.mjs +3 -7
- package/api/theme/theme.type.d.mts +11 -170
- package/api/theme/theme.type.mjs +27 -94
- package/api/upgrade/_adapter.mjs +5 -71
- package/api/upgrade/upgrade.doc.mjs +3 -4
- package/api/upgrade/upgrade.type.d.mts +5 -5
- package/api/upgrade/upgrade.type.mjs +11 -11
- package/assets/codemods/integration-discovery.mjs +2 -40
- package/assets/codemods/integration-discovery.test.mjs +0 -58
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
- package/assets/docs/README.md +0 -9
- package/assets/docs/cli-integrations.doc.mjs +15 -86
- package/assets/docs/styling-libraries.doc.mjs +1 -1
- package/assets/docs/working-with-ai.doc.mjs +1 -1
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
- package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
- package/authoring/_shared/contract.ts +0 -22
- package/authoring/codemod/codemod.doc.mjs +1 -6
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +6 -8
- package/authoring/config/parse.d.mts +13 -13
- package/authoring/config/parse.mjs +8 -8
- package/authoring/config/type.ts +3 -3
- package/authoring/debug/parse.d.mts +5 -5
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/doctypes/_schema.d.mts +23 -788
- package/authoring/doctypes/_schema.mjs +39 -492
- package/authoring/doctypes/base/type.ts +0 -40
- package/authoring/doctypes/command/command.doc.mjs +2 -3
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +2 -3
- package/authoring/doctypes/component/component.doc.mjs +3 -6
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +3 -4
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -3
- package/authoring/doctypes/function/function.doc.mjs +0 -4
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +2 -6
- package/authoring/doctypes/hook/hook.doc.mjs +0 -4
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +2 -3
- package/authoring/doctypes/legacy.d.mts +6 -8
- package/authoring/doctypes/legacy.mjs +4 -5
- package/authoring/doctypes/parse.d.mts +18 -20
- package/authoring/doctypes/parse.mjs +10 -16
- package/authoring/doctypes/parse.test.mjs +3 -77
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +5 -8
- package/authoring/doctypes/reference/reference.doc.mjs +4 -17
- package/authoring/doctypes/reference/type.ts +5 -51
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +2 -3
- package/authoring/doctypes/template/parse.d.mts +1 -92
- package/authoring/doctypes/template/parse.mjs +2 -36
- package/authoring/doctypes/template/parse.test.mjs +2 -8
- package/authoring/doctypes/template/template.doc.mjs +0 -4
- package/authoring/doctypes/template/type.ts +2 -5
- package/authoring/doctypes/types.ts +9 -10
- package/authoring/gap-report/parse.d.mts +10 -10
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/index.d.mts +0 -1
- package/authoring/index.d.ts +17 -49
- package/authoring/index.mjs +0 -1
- package/authoring/integration/integration.doc.mjs +6 -13
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/parse.test.mjs +1 -10
- package/authoring/integration/schema.d.mts +4 -6
- package/authoring/integration/schema.mjs +3 -9
- package/authoring/integration/type.ts +6 -23
- package/authoring/shadcn/receipt.d.mts +6 -6
- package/clients/cli/commands/docs.doc.mjs +3 -13
- package/clients/cli/commands/docs.mjs +21 -121
- package/clients/cli/commands/docs.test.mjs +0 -88
- package/clients/cli/commands/integration-authoring.test.mjs +9 -13
- package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
- package/clients/cli/commands/upgrade.doc.mjs +2 -2
- package/clients/cli/formatters/index.mjs +1 -162
- package/clients/cli/formatters/index.test.mjs +0 -91
- package/clients/cli/lib/manifest.mjs +2 -7
- package/foundation/config/project.mjs +6 -21
- package/foundation/discovery/component-discovery.d.mts +1 -1
- package/foundation/discovery/component-discovery.mjs +1 -2
- package/foundation/discovery/docs-discovery.d.mts +4 -11
- package/foundation/discovery/docs-discovery.mjs +88 -208
- package/foundation/discovery/docs-discovery.test.mjs +13 -279
- package/foundation/discovery/template-adapter.mjs +1 -2
- package/foundation/integrations/autolink.mjs +5 -12
- package/foundation/integrations/integration-warnings.mjs +0 -6
- package/foundation/integrations/integrations.d.mts +2 -46
- package/foundation/integrations/integrations.mjs +8 -167
- package/foundation/integrations/integrations.test.mjs +1 -384
- package/foundation/integrations/validate-contributions.d.mts +0 -2
- package/foundation/integrations/validate-contributions.mjs +0 -10
- package/foundation/response/json-contract.test.mjs +17 -46
- package/foundation/response/response-types.doc.mjs +1 -6
- package/package.json +11 -9
- package/api/docs/compiled-topics.test.mjs +0 -78
- package/api/docs/index/index.d.mts +0 -18
- package/api/docs/index/index.mjs +0 -32
- package/api/docs/index/index.test.mjs +0 -62
- package/api/upgrade/project-context.test.mjs +0 -272
- package/assets/docs/authoring.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
- package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
- package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
- package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
- package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
- package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
- package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
- package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
- package/authoring/doctypes/load-contract.test.mjs +0 -207
- package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
- package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
- package/authoring/doctypes/namespace/parse.d.mts +0 -12
- package/authoring/doctypes/namespace/parse.mjs +0 -25
- package/authoring/doctypes/namespace/parse.test.mjs +0 -165
- package/authoring/doctypes/namespace/type.ts +0 -71
- package/authoring/identity/identity.doc.d.mts +0 -9
- package/authoring/identity/identity.doc.mjs +0 -61
- package/authoring/identity/type.ts +0 -132
- package/foundation/discovery/authoring-self-docs.d.mts +0 -69
- package/foundation/discovery/authoring-self-docs.mjs +0 -214
- package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
- package/foundation/discovery/docs-output-budget.d.mts +0 -28
- package/foundation/discovery/docs-output-budget.mjs +0 -50
- package/foundation/discovery/docs-section-key.d.mts +0 -98
- package/foundation/discovery/docs-section-key.mjs +0 -221
- package/foundation/discovery/docs-section-key.test.mjs +0 -224
- package/foundation/doc-compiler/compile.d.mts +0 -162
- package/foundation/doc-compiler/compile.mjs +0 -262
- package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
- package/foundation/doc-compiler/ir.d.mts +0 -9
- package/foundation/doc-compiler/ir.mjs +0 -287
- package/foundation/doc-compiler/lenses.d.mts +0 -33
- package/foundation/doc-compiler/lenses.mjs +0 -127
- package/foundation/identity/provider-identity.d.mts +0 -90
- package/foundation/identity/provider-identity.mjs +0 -320
- package/foundation/identity/provider-identity.test.mjs +0 -254
- package/foundation/identity/providers.d.mts +0 -7
- package/foundation/identity/providers.mjs +0 -16
- package/foundation/integrations/provider-conflicts.test.mjs +0 -125
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Stable section keys, section lookup, and the topic index.
|
|
5
|
-
*
|
|
6
|
-
* @input Reference-doc sections, each with an optional authored `id`.
|
|
7
|
-
* @output The key a section is addressed by (its `id`, else a kebab-case key
|
|
8
|
-
* derived from its authored title), lookup by key or title, and the compact
|
|
9
|
-
* index a topic-only docs read returns.
|
|
10
|
-
* @position Shared by docs discovery (which rejects colliding keys before a
|
|
11
|
-
* reader sees them), the docs leaves (index, section, detail), and Doctor
|
|
12
|
-
* (output budgets). Imports nothing from discovery, so both can use it.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/** A stable key: lowercase letters and digits, joined by single hyphens. */
|
|
16
|
-
export const SECTION_KEY_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
17
|
-
|
|
18
|
-
/** The longest summary an index entry carries, in characters. */
|
|
19
|
-
export const SECTION_SUMMARY_MAX = 240;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* A section's authored title. A `--zh`/`--dense` overlay replaces the visible
|
|
23
|
-
* title, but extensions are written against the authored one and keys derive
|
|
24
|
-
* from it, so both stay the same in every language.
|
|
25
|
-
*/
|
|
26
|
-
const SOURCE_TITLE = Symbol('astryx.docs.sourceTitle');
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Record the authored title of a section whose visible title a translation
|
|
30
|
-
* overlay replaces.
|
|
31
|
-
* @template {object} T
|
|
32
|
-
* @param {T} section
|
|
33
|
-
* @param {string} title
|
|
34
|
-
* @returns {T}
|
|
35
|
-
*/
|
|
36
|
-
export function withSourceTitle(section, title) {
|
|
37
|
-
Object.defineProperty(section, SOURCE_TITLE, {value: title, configurable: true});
|
|
38
|
-
return section;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @param {any} section
|
|
43
|
-
* @returns {string}
|
|
44
|
-
*/
|
|
45
|
-
export function sourceTitle(section) {
|
|
46
|
-
return section?.[SOURCE_TITLE] ?? section?.title;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* The key a title derives: accents folded, `&` spelled out, and every other
|
|
51
|
-
* run of non-alphanumerics collapsed to one hyphen. Empty when the title has
|
|
52
|
-
* no Latin letters or digits to derive from.
|
|
53
|
-
* @param {unknown} title
|
|
54
|
-
* @returns {string}
|
|
55
|
-
*/
|
|
56
|
-
export function sectionTitleKey(title) {
|
|
57
|
-
if (typeof title !== 'string') return '';
|
|
58
|
-
return title
|
|
59
|
-
.normalize('NFKD')
|
|
60
|
-
.replace(/[\u0300-\u036f]/g, '')
|
|
61
|
-
.toLowerCase()
|
|
62
|
-
.replace(/&/g, ' and ')
|
|
63
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
64
|
-
.replace(/^-+|-+$/g, '');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* The key a section is addressed by: its authored `id`, else the key its
|
|
69
|
-
* authored title derives.
|
|
70
|
-
* @param {any} section
|
|
71
|
-
* @returns {string}
|
|
72
|
-
*/
|
|
73
|
-
export function sectionKey(section) {
|
|
74
|
-
return typeof section?.id === 'string'
|
|
75
|
-
? section.id
|
|
76
|
-
: sectionTitleKey(sourceTitle(section));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Problems with the keys of a topic's sections: an authored id that is not a
|
|
81
|
-
* stable key, a title no key derives from, and two sections sharing a key.
|
|
82
|
-
* Keys are never suffixed to make them unique, because readers link to them.
|
|
83
|
-
* @param {any[]} sections
|
|
84
|
-
* @returns {string[]}
|
|
85
|
-
*/
|
|
86
|
-
export function sectionKeyProblems(sections) {
|
|
87
|
-
/** @type {string[]} */
|
|
88
|
-
const problems = [];
|
|
89
|
-
/** @type {Map<string, number>} */
|
|
90
|
-
const seen = new Map();
|
|
91
|
-
sections.forEach((section, s) => {
|
|
92
|
-
const at = `sections[${s}]`;
|
|
93
|
-
// A missing title is reported where titles are checked; no key to judge.
|
|
94
|
-
if (
|
|
95
|
-
section?.id == null &&
|
|
96
|
-
(typeof section?.title !== 'string' || section.title === '')
|
|
97
|
-
) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (
|
|
101
|
-
section?.id != null &&
|
|
102
|
-
(typeof section.id !== 'string' || !SECTION_KEY_RE.test(section.id))
|
|
103
|
-
) {
|
|
104
|
-
problems.push(
|
|
105
|
-
`${at}.id: ${JSON.stringify(section.id)} is not a stable key. Use lowercase letters and digits joined by single hyphens.`,
|
|
106
|
-
);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const key = sectionKey(section);
|
|
110
|
-
if (key === '') {
|
|
111
|
-
problems.push(
|
|
112
|
-
`${at}: no key derives from the title ${JSON.stringify(section?.title)}. Give the section an id.`,
|
|
113
|
-
);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
const first = seen.get(key);
|
|
117
|
-
if (first != null) {
|
|
118
|
-
problems.push(
|
|
119
|
-
`${at}: the key "${key}" is already used by sections[${first}]. Give one of them a distinct id or title.`,
|
|
120
|
-
);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
seen.set(key, s);
|
|
124
|
-
});
|
|
125
|
-
return problems;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Stamp every section with the key it is addressed by. Runs only after
|
|
130
|
-
* extensions merge: a derived key must never take part in merge matching.
|
|
131
|
-
* @template {{sections: any[]}} T
|
|
132
|
-
* @param {T} doc
|
|
133
|
-
* @returns {T}
|
|
134
|
-
*/
|
|
135
|
-
export function withSectionKeys(doc) {
|
|
136
|
-
return {
|
|
137
|
-
...doc,
|
|
138
|
-
sections: doc.sections.map(section =>
|
|
139
|
-
section.id != null
|
|
140
|
-
? section
|
|
141
|
-
: withSourceTitle(
|
|
142
|
-
{...section, id: sectionKey(section)},
|
|
143
|
-
sourceTitle(section),
|
|
144
|
-
),
|
|
145
|
-
),
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Find the section a reader asked for: by key, then by exact title (or the
|
|
151
|
-
* key the query derives), then by a title that contains the query. More than
|
|
152
|
-
* one match is refused rather than guessed.
|
|
153
|
-
* @param {any[]} sections
|
|
154
|
-
* @param {string} query
|
|
155
|
-
* @returns {{section: any | null, candidates: any[]}} `candidates` lists the
|
|
156
|
-
* matches when the query is ambiguous, and is empty when nothing matches
|
|
157
|
-
*/
|
|
158
|
-
export function findDocSection(sections, query) {
|
|
159
|
-
const wanted = query.trim();
|
|
160
|
-
const byKey = sections.find(section => sectionKey(section) === wanted);
|
|
161
|
-
if (byKey) return {section: byKey, candidates: []};
|
|
162
|
-
|
|
163
|
-
const lower = wanted.toLowerCase();
|
|
164
|
-
const derived = sectionTitleKey(wanted);
|
|
165
|
-
const exact = sections.filter(
|
|
166
|
-
section =>
|
|
167
|
-
section.title.toLowerCase() === lower ||
|
|
168
|
-
(derived !== '' && sectionTitleKey(sourceTitle(section)) === derived),
|
|
169
|
-
);
|
|
170
|
-
if (exact.length === 1) return {section: exact[0], candidates: []};
|
|
171
|
-
if (exact.length > 1) return {section: null, candidates: exact};
|
|
172
|
-
|
|
173
|
-
const partial = sections.filter(section =>
|
|
174
|
-
section.title.toLowerCase().includes(lower),
|
|
175
|
-
);
|
|
176
|
-
if (partial.length === 1) return {section: partial[0], candidates: []};
|
|
177
|
-
return {section: null, candidates: partial};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* One line that says what a section holds: its first prose or list text,
|
|
182
|
-
* whitespace collapsed, cut at a word boundary.
|
|
183
|
-
* @param {any} section
|
|
184
|
-
* @param {number} [max]
|
|
185
|
-
* @returns {string}
|
|
186
|
-
*/
|
|
187
|
-
export function sectionSummary(section, max = SECTION_SUMMARY_MAX) {
|
|
188
|
-
const first = (section?.content ?? []).find(
|
|
189
|
-
(/** @type {any} */ block) =>
|
|
190
|
-
(block?.type === 'prose' && typeof block.text === 'string') ||
|
|
191
|
-
(block?.type === 'list' && Array.isArray(block.items)),
|
|
192
|
-
);
|
|
193
|
-
const raw =
|
|
194
|
-
first == null ? '' : first.type === 'prose' ? first.text : first.items[0];
|
|
195
|
-
const text = String(raw ?? '')
|
|
196
|
-
.replace(/\s+/g, ' ')
|
|
197
|
-
.trim();
|
|
198
|
-
if (text.length <= max) return text;
|
|
199
|
-
const cut = text.slice(0, max - 1);
|
|
200
|
-
const space = cut.lastIndexOf(' ');
|
|
201
|
-
return `${(space > max / 2 ? cut.slice(0, space) : cut).trimEnd()}…`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* The index a topic-only read returns: what the topic is, and one entry per
|
|
206
|
-
* section with the key to read it by.
|
|
207
|
-
* @param {{name: string, title: string, description: string, sections: any[]}} doc
|
|
208
|
-
* @returns {import('../../api/docs/docs.type.mjs').DocsIndex}
|
|
209
|
-
*/
|
|
210
|
-
export function buildDocsIndexData(doc) {
|
|
211
|
-
return {
|
|
212
|
-
name: doc.name,
|
|
213
|
-
title: doc.title,
|
|
214
|
-
description: doc.description,
|
|
215
|
-
sections: doc.sections.map(section => ({
|
|
216
|
-
id: sectionKey(section),
|
|
217
|
-
title: section.title,
|
|
218
|
-
summary: sectionSummary(section),
|
|
219
|
-
})),
|
|
220
|
-
};
|
|
221
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
import {describe, expect, it} from 'vitest';
|
|
4
|
-
import {
|
|
5
|
-
SECTION_KEY_RE,
|
|
6
|
-
SECTION_SUMMARY_MAX,
|
|
7
|
-
buildDocsIndexData,
|
|
8
|
-
findDocSection,
|
|
9
|
-
sectionKey,
|
|
10
|
-
sectionKeyProblems,
|
|
11
|
-
sectionSummary,
|
|
12
|
-
sectionTitleKey,
|
|
13
|
-
sourceTitle,
|
|
14
|
-
withSectionKeys,
|
|
15
|
-
withSourceTitle,
|
|
16
|
-
} from './docs-section-key.mjs';
|
|
17
|
-
|
|
18
|
-
/** @param {string} title @param {object} [fields] */
|
|
19
|
-
const section = (title, fields = {}) => ({title, content: [], ...fields});
|
|
20
|
-
|
|
21
|
-
describe('sectionTitleKey', () => {
|
|
22
|
-
it.each([
|
|
23
|
-
['Quick Start', 'quick-start'],
|
|
24
|
-
['Light/Dark Mode', 'light-dark-mode'],
|
|
25
|
-
["Do & Don't", 'do-and-don-t'],
|
|
26
|
-
[' Café Crème ', 'cafe-creme'],
|
|
27
|
-
['useTheme()', 'usetheme'],
|
|
28
|
-
['--- Tokens ---', 'tokens'],
|
|
29
|
-
['亮/暗模式', ''],
|
|
30
|
-
['', ''],
|
|
31
|
-
])('%j derives %j', (title, key) => {
|
|
32
|
-
expect(sectionTitleKey(title)).toBe(key);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('derives only stable keys', () => {
|
|
36
|
-
for (const title of ['A B', 'x__y', 'Élan 2.0', 'a-b-', '-a']) {
|
|
37
|
-
expect(sectionTitleKey(title)).toMatch(SECTION_KEY_RE);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('derives nothing from a non-string', () => {
|
|
42
|
-
expect(sectionTitleKey(undefined)).toBe('');
|
|
43
|
-
expect(sectionTitleKey(42)).toBe('');
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('sectionKey', () => {
|
|
48
|
-
it('prefers the authored id', () => {
|
|
49
|
-
expect(sectionKey(section('Quick Start', {id: 'start'}))).toBe('start');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('derives from the authored title, not a translated one', () => {
|
|
53
|
-
const translated = withSourceTitle(section('快速开始'), 'Quick Start');
|
|
54
|
-
expect(sectionKey(translated)).toBe('quick-start');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('sectionKeyProblems', () => {
|
|
59
|
-
it('accepts distinct keys', () => {
|
|
60
|
-
expect(
|
|
61
|
-
sectionKeyProblems([section('Install'), section('Usage', {id: 'use'})]),
|
|
62
|
-
).toEqual([]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('rejects two sections that share a key', () => {
|
|
66
|
-
const problems = sectionKeyProblems([
|
|
67
|
-
section('Quick Start'),
|
|
68
|
-
section('Quick-start'),
|
|
69
|
-
]);
|
|
70
|
-
expect(problems).toHaveLength(1);
|
|
71
|
-
expect(problems[0]).toContain('"quick-start" is already used by sections[0]');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('rejects an authored id that collides with a derived key', () => {
|
|
75
|
-
expect(
|
|
76
|
-
sectionKeyProblems([section('Install'), section('Setup', {id: 'install'})]),
|
|
77
|
-
).toHaveLength(1);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('rejects an unsafe id and never suffixes one', () => {
|
|
81
|
-
for (const id of ['Quick Start', 'a_b', 'a--b', '-a', '', 7]) {
|
|
82
|
-
expect(sectionKeyProblems([section('Install', {id})])[0]).toContain(
|
|
83
|
-
'is not a stable key',
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('rejects a title no key derives from', () => {
|
|
89
|
-
expect(sectionKeyProblems([section('亮/暗模式')])[0]).toContain(
|
|
90
|
-
'Give the section an id',
|
|
91
|
-
);
|
|
92
|
-
expect(sectionKeyProblems([section('亮/暗模式', {id: 'light-dark'})])).toEqual(
|
|
93
|
-
[],
|
|
94
|
-
);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('leaves a missing title to the title check', () => {
|
|
98
|
-
expect(sectionKeyProblems([{content: []}, section('')])).toEqual([]);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('withSectionKeys', () => {
|
|
103
|
-
it('stamps derived keys and keeps authored ones', () => {
|
|
104
|
-
const doc = withSectionKeys({
|
|
105
|
-
sections: [section('Quick Start'), section('Usage', {id: 'use'})],
|
|
106
|
-
});
|
|
107
|
-
expect(doc.sections.map(s => s.id)).toEqual(['quick-start', 'use']);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('keeps the authored title of a translated section', () => {
|
|
111
|
-
const doc = withSectionKeys({
|
|
112
|
-
sections: [withSourceTitle(section('快速开始'), 'Quick Start')],
|
|
113
|
-
});
|
|
114
|
-
expect(doc.sections[0].id).toBe('quick-start');
|
|
115
|
-
expect(sourceTitle(doc.sections[0])).toBe('Quick Start');
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe('findDocSection', () => {
|
|
120
|
-
const sections = withSectionKeys({
|
|
121
|
-
sections: [
|
|
122
|
-
section('Quick Start'),
|
|
123
|
-
section('Theme Props'),
|
|
124
|
-
section('Theme Tokens', {id: 'tokens'}),
|
|
125
|
-
section('Overview', {id: 'overview-a'}),
|
|
126
|
-
section('Overview', {id: 'overview-b'}),
|
|
127
|
-
],
|
|
128
|
-
}).sections;
|
|
129
|
-
|
|
130
|
-
it('finds a section by key first', () => {
|
|
131
|
-
expect(findDocSection(sections, 'tokens').section.title).toBe(
|
|
132
|
-
'Theme Tokens',
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('finds a section by exact title, case-insensitively', () => {
|
|
137
|
-
expect(findDocSection(sections, 'quick start').section.id).toBe(
|
|
138
|
-
'quick-start',
|
|
139
|
-
);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('finds a section by the key its query derives', () => {
|
|
143
|
-
expect(findDocSection(sections, 'Quick-Start!').section.id).toBe(
|
|
144
|
-
'quick-start',
|
|
145
|
-
);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('finds a section by a unique part of its title', () => {
|
|
149
|
-
expect(findDocSection(sections, 'props').section.id).toBe('theme-props');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('refuses an ambiguous exact title and lists the candidates', () => {
|
|
153
|
-
const {section: match, candidates} = findDocSection(sections, 'Overview');
|
|
154
|
-
expect(match).toBeNull();
|
|
155
|
-
expect(candidates.map(s => s.id)).toEqual(['overview-a', 'overview-b']);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('refuses an ambiguous partial title', () => {
|
|
159
|
-
const {section: match, candidates} = findDocSection(sections, 'theme');
|
|
160
|
-
expect(match).toBeNull();
|
|
161
|
-
expect(candidates.map(s => s.id)).toEqual(['theme-props', 'tokens']);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('returns nothing for no match', () => {
|
|
165
|
-
expect(findDocSection(sections, 'zzz')).toEqual({
|
|
166
|
-
section: null,
|
|
167
|
-
candidates: [],
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe('sectionSummary', () => {
|
|
173
|
-
it('uses the first prose or list text, whitespace collapsed', () => {
|
|
174
|
-
expect(
|
|
175
|
-
sectionSummary({
|
|
176
|
-
content: [
|
|
177
|
-
{type: 'code', lang: 'ts', code: 'x'},
|
|
178
|
-
{type: 'prose', text: 'Line one.\n\n Line two.'},
|
|
179
|
-
],
|
|
180
|
-
}),
|
|
181
|
-
).toBe('Line one. Line two.');
|
|
182
|
-
expect(
|
|
183
|
-
sectionSummary({content: [{type: 'list', items: ['First', 'Second']}]}),
|
|
184
|
-
).toBe('First');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('is empty when the section has no text', () => {
|
|
188
|
-
expect(sectionSummary({content: [{type: 'table', headers: [], rows: []}]})).toBe(
|
|
189
|
-
'',
|
|
190
|
-
);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('cuts a long summary at a word boundary', () => {
|
|
194
|
-
const summary = sectionSummary({
|
|
195
|
-
content: [{type: 'prose', text: 'word '.repeat(200)}],
|
|
196
|
-
});
|
|
197
|
-
expect(summary.length).toBeLessThanOrEqual(SECTION_SUMMARY_MAX);
|
|
198
|
-
expect(summary.endsWith('word…')).toBe(true);
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
describe('buildDocsIndexData', () => {
|
|
203
|
-
it('lists each section by key, title, and summary', () => {
|
|
204
|
-
expect(
|
|
205
|
-
buildDocsIndexData({
|
|
206
|
-
name: 'theme',
|
|
207
|
-
title: 'Theme',
|
|
208
|
-
description: 'Theming.',
|
|
209
|
-
sections: [
|
|
210
|
-
section('Quick Start', {content: [{type: 'prose', text: 'Start.'}]}),
|
|
211
|
-
section('Usage', {id: 'use'}),
|
|
212
|
-
],
|
|
213
|
-
}),
|
|
214
|
-
).toEqual({
|
|
215
|
-
name: 'theme',
|
|
216
|
-
title: 'Theme',
|
|
217
|
-
description: 'Theming.',
|
|
218
|
-
sections: [
|
|
219
|
-
{id: 'quick-start', title: 'Quick Start', summary: 'Start.'},
|
|
220
|
-
{id: 'use', title: 'Usage', summary: ''},
|
|
221
|
-
],
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
|
|
2
|
-
// DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* One authored file, as discovery loaded it.
|
|
6
|
-
* @typedef {object} AuthoredFile
|
|
7
|
-
* @property {string} file the file's name, for messages only
|
|
8
|
-
* @property {any} [doc] the parsed doc, when it loaded
|
|
9
|
-
* @property {unknown} [error] why it did not load or parse
|
|
10
|
-
* @property {any} [overlay] the language overlay's export, when one applies
|
|
11
|
-
* @property {unknown} [overlayError] why the overlay did not load
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {object} ReferenceTopicInput
|
|
15
|
-
* @property {string} id the topic's name in the catalog
|
|
16
|
-
* @property {string} provider the package that owns the topic
|
|
17
|
-
* @property {string | null} replaces the topic it took the place of
|
|
18
|
-
* @property {string | null} lang the overlay language, or null for authored text
|
|
19
|
-
* @property {AuthoredFile} base
|
|
20
|
-
* @property {Array<AuthoredFile & {provider: string}>} extensions in merge order
|
|
21
|
-
*/
|
|
22
|
-
/**
|
|
23
|
-
* A token reference after linking: the target section's content, or why it
|
|
24
|
-
* has none.
|
|
25
|
-
* @typedef {{status: 'resolved', topic: string, section: string, previewType?: string, content: any[]}
|
|
26
|
-
* | {status: 'unknown-topic'}
|
|
27
|
-
* | {status: 'unknown-section'}} TokenRefResolution
|
|
28
|
-
*/
|
|
29
|
-
/**
|
|
30
|
-
* @typedef {object} CompiledReferenceNode
|
|
31
|
-
* @property {number} schemaVersion
|
|
32
|
-
* @property {'reference'} kind
|
|
33
|
-
* @property {'lowered' | 'linked'} stage `linked` once every token reference
|
|
34
|
-
* carries its resolution; a lowered node carries none
|
|
35
|
-
* @property {string} id the topic's name in the catalog
|
|
36
|
-
* @property {string | null} lang
|
|
37
|
-
* @property {{provider: string, replaces: string | null, extensions: string[]}} provenance
|
|
38
|
-
* @property {Record<string, string>} sourceTitles section key -> authored title
|
|
39
|
-
* @property {any} doc the topic: authored fields in authored order, every
|
|
40
|
-
* section keyed; a linked node's token references carry `resolved`
|
|
41
|
-
*/
|
|
42
|
-
/**
|
|
43
|
-
* Lower one topic: overlay each file, merge the extensions in order, and stamp
|
|
44
|
-
* every section with its key.
|
|
45
|
-
* @param {ReferenceTopicInput} input
|
|
46
|
-
* @returns {CompiledReferenceNode}
|
|
47
|
-
*/
|
|
48
|
-
export function lowerReferenceTopic(input: ReferenceTopicInput): CompiledReferenceNode;
|
|
49
|
-
/**
|
|
50
|
-
* Link every section of a lowered node.
|
|
51
|
-
* @param {CompiledReferenceNode} node
|
|
52
|
-
* @param {(topic: string) => Promise<CompiledReferenceNode | null>} lowerTarget
|
|
53
|
-
* the lowered node a reference names, or null when no topic has that name
|
|
54
|
-
* @returns {Promise<CompiledReferenceNode>}
|
|
55
|
-
*/
|
|
56
|
-
export function linkReferenceTopic(node: CompiledReferenceNode, lowerTarget: (topic: string) => Promise<CompiledReferenceNode | null>): Promise<CompiledReferenceNode>;
|
|
57
|
-
/**
|
|
58
|
-
* Resolve the token references in one section. A section with none comes back
|
|
59
|
-
* as it went in.
|
|
60
|
-
* @template {{content: any[]}} S
|
|
61
|
-
* @param {S} section
|
|
62
|
-
* @param {(topic: string) => Promise<CompiledReferenceNode | null>} lowerTarget
|
|
63
|
-
* @returns {Promise<S>}
|
|
64
|
-
*/
|
|
65
|
-
export function linkReferenceSection<S extends {
|
|
66
|
-
content: any[];
|
|
67
|
-
}>(section: S, lowerTarget: (topic: string) => Promise<CompiledReferenceNode | null>): Promise<S>;
|
|
68
|
-
/** Bumped whenever the shape of a compiled node changes. */
|
|
69
|
-
export const COMPILED_DOC_SCHEMA_VERSION: 1;
|
|
70
|
-
/**
|
|
71
|
-
* One authored file, as discovery loaded it.
|
|
72
|
-
*/
|
|
73
|
-
export type AuthoredFile = {
|
|
74
|
-
/**
|
|
75
|
-
* the file's name, for messages only
|
|
76
|
-
*/
|
|
77
|
-
file: string;
|
|
78
|
-
/**
|
|
79
|
-
* the parsed doc, when it loaded
|
|
80
|
-
*/
|
|
81
|
-
doc?: any;
|
|
82
|
-
/**
|
|
83
|
-
* why it did not load or parse
|
|
84
|
-
*/
|
|
85
|
-
error?: unknown;
|
|
86
|
-
/**
|
|
87
|
-
* the language overlay's export, when one applies
|
|
88
|
-
*/
|
|
89
|
-
overlay?: any;
|
|
90
|
-
/**
|
|
91
|
-
* why the overlay did not load
|
|
92
|
-
*/
|
|
93
|
-
overlayError?: unknown;
|
|
94
|
-
};
|
|
95
|
-
export type ReferenceTopicInput = {
|
|
96
|
-
/**
|
|
97
|
-
* the topic's name in the catalog
|
|
98
|
-
*/
|
|
99
|
-
id: string;
|
|
100
|
-
/**
|
|
101
|
-
* the package that owns the topic
|
|
102
|
-
*/
|
|
103
|
-
provider: string;
|
|
104
|
-
/**
|
|
105
|
-
* the topic it took the place of
|
|
106
|
-
*/
|
|
107
|
-
replaces: string | null;
|
|
108
|
-
/**
|
|
109
|
-
* the overlay language, or null for authored text
|
|
110
|
-
*/
|
|
111
|
-
lang: string | null;
|
|
112
|
-
base: AuthoredFile;
|
|
113
|
-
/**
|
|
114
|
-
* in merge order
|
|
115
|
-
*/
|
|
116
|
-
extensions: Array<AuthoredFile & {
|
|
117
|
-
provider: string;
|
|
118
|
-
}>;
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* A token reference after linking: the target section's content, or why it
|
|
122
|
-
* has none.
|
|
123
|
-
*/
|
|
124
|
-
export type TokenRefResolution = {
|
|
125
|
-
status: "resolved";
|
|
126
|
-
topic: string;
|
|
127
|
-
section: string;
|
|
128
|
-
previewType?: string;
|
|
129
|
-
content: any[];
|
|
130
|
-
} | {
|
|
131
|
-
status: "unknown-topic";
|
|
132
|
-
} | {
|
|
133
|
-
status: "unknown-section";
|
|
134
|
-
};
|
|
135
|
-
export type CompiledReferenceNode = {
|
|
136
|
-
schemaVersion: number;
|
|
137
|
-
kind: "reference";
|
|
138
|
-
/**
|
|
139
|
-
* `linked` once every token reference
|
|
140
|
-
* carries its resolution; a lowered node carries none
|
|
141
|
-
*/
|
|
142
|
-
stage: "lowered" | "linked";
|
|
143
|
-
/**
|
|
144
|
-
* the topic's name in the catalog
|
|
145
|
-
*/
|
|
146
|
-
id: string;
|
|
147
|
-
lang: string | null;
|
|
148
|
-
provenance: {
|
|
149
|
-
provider: string;
|
|
150
|
-
replaces: string | null;
|
|
151
|
-
extensions: string[];
|
|
152
|
-
};
|
|
153
|
-
/**
|
|
154
|
-
* section key -> authored title
|
|
155
|
-
*/
|
|
156
|
-
sourceTitles: Record<string, string>;
|
|
157
|
-
/**
|
|
158
|
-
* the topic: authored fields in authored order, every
|
|
159
|
-
* section keyed; a linked node's token references carry `resolved`
|
|
160
|
-
*/
|
|
161
|
-
doc: any;
|
|
162
|
-
};
|