@astryxdesign/cli 0.4.5 → 0.4.6-canary.cea9ecd

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/api/component/_adapter.d.mts +22 -5
  3. package/api/component/_adapter.mjs +51 -3
  4. package/api/docs/_adapter.d.mts +37 -8
  5. package/api/docs/_adapter.mjs +70 -41
  6. package/api/docs/detail/detail.d.mts +2 -0
  7. package/api/docs/detail/detail.mjs +12 -10
  8. package/api/docs/detail/section/section.d.mts +2 -0
  9. package/api/docs/detail/section/section.mjs +1 -0
  10. package/api/docs/docs.d.mts +2 -0
  11. package/api/docs/docs.doc.mjs +11 -2
  12. package/api/docs/docs.mjs +2 -1
  13. package/api/docs/docs.type.d.mts +15 -0
  14. package/api/docs/docs.type.mjs +6 -0
  15. package/api/docs/integrationDocs.test.mjs +208 -0
  16. package/api/docs/list/list.d.mts +5 -1
  17. package/api/docs/list/list.mjs +30 -14
  18. package/api/init/run/run.mjs +9 -4
  19. package/api/integration/validate-integration.mjs +2 -1
  20. package/api/integration/validate-integration.type.d.mts +1 -0
  21. package/api/integration/validate-integration.type.mjs +1 -0
  22. package/api/search/search.mjs +26 -15
  23. package/api/upgrade/_adapter.d.mts +2 -2
  24. package/api/upgrade/_adapter.mjs +7 -3
  25. package/api/upgrade/run/run.mjs +1 -1
  26. package/assets/codemods/transforms/v0.1.0/__tests__/drop-xds-prefix-imports.test.mjs +245 -0
  27. package/assets/codemods/transforms/v0.1.0/drop-xds-prefix-imports.mjs +139 -13
  28. package/assets/docs/cli-integrations.doc.mjs +41 -3
  29. package/assets/docs/layout.doc.dense.mjs +275 -30
  30. package/assets/docs/layout.doc.mjs +412 -78
  31. package/assets/docs/theme.doc.mjs +3 -3
  32. package/assets/templates/blocks/components/AvatarGroup/AvatarGroupInteractive.doc.mjs +15 -0
  33. package/assets/templates/blocks/components/AvatarGroup/AvatarGroupInteractive.tsx +47 -0
  34. package/assets/templates/blocks/components/AvatarGroup/AvatarGroupShowcase.doc.mjs +1 -1
  35. package/assets/templates/blocks/components/Breadcrumbs/BreadcrumbsCustomSeparator.tsx +18 -5
  36. package/assets/templates/blocks/components/Selector/SelectorOptionDescriptions.doc.mjs +14 -0
  37. package/assets/templates/blocks/components/Selector/SelectorOptionDescriptions.tsx +76 -0
  38. package/assets/templates/pages/dashboard-cohort-funnel/page.tsx +914 -0
  39. package/assets/templates/pages/dashboard-cohort-funnel/template.doc.mjs +12 -0
  40. package/assets/templates/pages/dashboard-data/page.tsx +894 -0
  41. package/assets/templates/pages/dashboard-data/template.doc.mjs +13 -0
  42. package/assets/templates/pages/dashboard-executive-summary/page.tsx +874 -0
  43. package/assets/templates/pages/dashboard-executive-summary/template.doc.mjs +13 -0
  44. package/assets/templates/pages/dashboard-project-status/page.tsx +1139 -0
  45. package/assets/templates/pages/dashboard-project-status/template.doc.mjs +13 -0
  46. package/assets/templates/pages/dashboard-service-monitoring/page.tsx +1590 -0
  47. package/assets/templates/pages/dashboard-service-monitoring/template.doc.mjs +12 -0
  48. package/authoring/doctypes/_schema.d.mts +2 -0
  49. package/authoring/doctypes/_schema.mjs +5 -0
  50. package/authoring/doctypes/reference/reference.doc.mjs +14 -0
  51. package/authoring/doctypes/reference/type.ts +12 -0
  52. package/authoring/doctypes/template/type.ts +2 -0
  53. package/authoring/integration/integration.doc.mjs +10 -1
  54. package/authoring/integration/parse.d.mts +1 -0
  55. package/authoring/integration/parse.mjs +1 -0
  56. package/authoring/integration/parse.test.mjs +1 -0
  57. package/authoring/integration/type.ts +5 -0
  58. package/clients/cli/commands/component-ownership.test.mjs +63 -3
  59. package/clients/cli/commands/theme-build.doc.mjs +1 -1
  60. package/foundation/agent-docs/agent-docs.d.mts +19 -3
  61. package/foundation/agent-docs/agent-docs.mjs +30 -11
  62. package/foundation/agent-docs/agent-docs.test.mjs +38 -0
  63. package/foundation/config/project.d.mts +16 -0
  64. package/foundation/config/project.mjs +65 -4
  65. package/foundation/config/project.test.mjs +66 -0
  66. package/foundation/discovery/docs-discovery.d.mts +185 -0
  67. package/foundation/discovery/docs-discovery.mjs +544 -0
  68. package/foundation/discovery/docs-discovery.test.mjs +341 -0
  69. package/foundation/integrations/integrations.d.mts +8 -6
  70. package/foundation/integrations/integrations.mjs +6 -4
  71. package/foundation/integrations/validate-contributions.mjs +30 -2
  72. package/package.json +9 -9
@@ -24,6 +24,7 @@ function scaffold({
24
24
  withCodemods = true,
25
25
  brokenComponent = false,
26
26
  brokenCodemod = false,
27
+ docs = null,
27
28
  integrationIssuesUrl = 'https://example.com/widgets/issues',
28
29
  } = {}) {
29
30
  fs.writeFileSync(
@@ -48,6 +49,7 @@ function scaffold({
48
49
  if (withComponents) manifest.components = './components';
49
50
  if (withTemplates) manifest.templates = './templates';
50
51
  if (withCodemods) manifest.codemods = './codemods';
52
+ if (docs) manifest.docs = './docs';
51
53
  if (integrationIssuesUrl) manifest.issuesUrl = integrationIssuesUrl;
52
54
  fs.writeFileSync(
53
55
  path.join(pkgDir, 'astryx.integration.mjs'),
@@ -99,9 +101,34 @@ function scaffold({
99
101
  }
100
102
  }
101
103
 
104
+ if (docs) {
105
+ const docsDir = path.join(pkgDir, 'docs');
106
+ fs.mkdirSync(docsDir, {recursive: true});
107
+ for (const [file, doc] of Object.entries(docs)) {
108
+ fs.writeFileSync(
109
+ path.join(docsDir, file),
110
+ typeof doc === 'string'
111
+ ? doc
112
+ : `export const docs = ${JSON.stringify(doc, null, 2)};\n`,
113
+ );
114
+ }
115
+ }
116
+
102
117
  return pkgDir;
103
118
  }
104
119
 
120
+ /** A minimal, valid topic for the docs-root fixtures. */
121
+ function topicDoc(fields) {
122
+ return {
123
+ type: 'generic',
124
+ name: 'deploying',
125
+ title: 'Deploying',
126
+ description: 'How to ship it.',
127
+ sections: [{title: 'Overview', content: [{type: 'prose', text: 'Ship it.'}]}],
128
+ ...fields,
129
+ };
130
+ }
131
+
105
132
  beforeEach(() => {
106
133
  originalCwd = process.cwd();
107
134
  tmpDir = fs.mkdtempSync(path.join(process.cwd(), '.astryx-project-test-'));
@@ -198,6 +225,45 @@ describe('Project discovery', () => {
198
225
  expect(integration[0].codemods[0].id).toBe('drop-foo');
199
226
  });
200
227
 
228
+ it('docs() adds an integration topic beside the built-in ones', async () => {
229
+ scaffold({docs: {'deploying.doc.mjs': topicDoc()}});
230
+ const project = await Project.load(tmpDir);
231
+ const catalog = await project.docs();
232
+ expect(catalog.resolve('deploying')).toMatchObject({
233
+ name: 'deploying',
234
+ package: '@acme/widgets',
235
+ });
236
+ // The CLI's own topics are still there.
237
+ expect(catalog.resolve('tokens').package).toBe('@astryxdesign/cli');
238
+ expect(await project.issues()).toEqual([]);
239
+ });
240
+
241
+ it('docs() lets an integration replace a built-in topic, aliasing the old name', async () => {
242
+ scaffold({
243
+ docs: {
244
+ 'setup.doc.mjs': topicDoc({name: 'setup', replaces: 'getting-started'}),
245
+ },
246
+ });
247
+ const project = await Project.load(tmpDir);
248
+ const catalog = await project.docs();
249
+ expect(catalog.resolve('setup').package).toBe('@acme/widgets');
250
+ expect(catalog.resolve('getting-started').name).toBe('setup');
251
+ });
252
+
253
+ it('docs() records an unusable topic as an issue and contributes none', async () => {
254
+ scaffold({
255
+ docs: {
256
+ 'ok.doc.mjs': topicDoc(),
257
+ 'broken.doc.mjs': topicDoc({name: 'broken', sections: []}),
258
+ },
259
+ });
260
+ const project = await Project.load(tmpDir);
261
+ const catalog = await project.docs();
262
+ expect(catalog.resolve('deploying')).toBeUndefined();
263
+ const issues = await project.issues();
264
+ expect(issues.some(i => i.code === 'invalid_doc' && i.severity === 'error')).toBe(true);
265
+ });
266
+
201
267
  it('memoizes components() — the second call does not re-walk', async () => {
202
268
  scaffold();
203
269
  const project = await Project.load(tmpDir);
@@ -0,0 +1,185 @@
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
+ * @typedef {object} DocsTopicRecord A doc file discovered under a docs root.
6
+ * @property {string} name
7
+ * @property {string} package owner package
8
+ * @property {string} path absolute path to the doc file
9
+ * @property {string} [title]
10
+ * @property {string} [description]
11
+ * @property {string|null} [category]
12
+ * @property {string} [replaces] topic this doc takes the place of
13
+ * @property {string} [extendsTopic] topic this doc merges onto (`extends`)
14
+ */
15
+ /**
16
+ * @typedef {object} DocsTopicEntry A resolved topic in the catalog.
17
+ * @property {string} name
18
+ * @property {string} package owner package
19
+ * @property {string} path absolute path to the doc file
20
+ * @property {string} [title]
21
+ * @property {string} [description]
22
+ * @property {string|null} [category]
23
+ * @property {string} [replaces] the topic this one took the place of
24
+ * @property {Array<{package: string, path: string}>} extensions overlays to
25
+ * merge onto the base doc, in the order their integrations were configured
26
+ */
27
+ /**
28
+ * Discover the CLI's own topics.
29
+ * @returns {Record<string, string>} topic name → absolute doc path
30
+ */
31
+ export function discoverBuiltinTopics(): Record<string, string>;
32
+ /**
33
+ * Load a topic doc from disk. A `.ts` doc is loaded through jiti, the rest
34
+ * natively; both the historical `export const docs` and the stamped
35
+ * `export default` forms are accepted, because core authors the first and the
36
+ * integration guide documents the second.
37
+ *
38
+ * @param {string} file absolute path to a doc file
39
+ * @returns {Promise<unknown>} the authored doc value
40
+ */
41
+ export function loadTopicModule(file: string): Promise<unknown>;
42
+ /**
43
+ * Check the fields the docs surfaces actually read. `parseDoc` is the outer
44
+ * gate, but the reference-doc schema is a passthrough over `{name, type}` —
45
+ * a doc with no `sections`, or a prose block whose `text` is misspelled,
46
+ * passes it and reaches a reader as a missing section or a blank gap. Those
47
+ * are hard to trace back from the rendered output, so they are caught here,
48
+ * where the file that needs fixing can be named.
49
+ *
50
+ * @param {any} doc a parsed doc
51
+ * @returns {string[]} problems, each already pointed at a place in the doc
52
+ */
53
+ export function problemsInTopic(doc: any): string[];
54
+ /**
55
+ * Discover the topics contributed by a single loaded integration. Mirrors
56
+ * `discoverIntegrationComponents`: walk the resolved root, take every
57
+ * conventional doc file, and record what it declares. Unlike component
58
+ * discovery this loads each doc, because a topic's name and its relationship
59
+ * to an existing topic are fields inside the file.
60
+ *
61
+ * Errors are returned, not thrown: one unusable doc is reported as an issue
62
+ * against its package while the rest of the CLI keeps working.
63
+ *
64
+ * @param {{name: string, docs?: string}} integration a loaded integration
65
+ * @returns {Promise<{records: DocsTopicRecord[], errors: Error[]}>}
66
+ */
67
+ export function discoverIntegrationDocs(integration: {
68
+ name: string;
69
+ docs?: string;
70
+ }): Promise<{
71
+ records: DocsTopicRecord[];
72
+ errors: Error[];
73
+ }>;
74
+ /**
75
+ * Merge an extension onto a base topic: a section whose title matches one in
76
+ * the base replaces it, a section the base does not have is appended, and the
77
+ * title/description are taken from the extension when it states them.
78
+ *
79
+ * Keyed by section TITLE rather than by position, the way the localization
80
+ * overlays are — position keying grafts an overlay onto whichever section
81
+ * happens to share its index, so a partial or reordered overlay corrupts
82
+ * everything after it (#2182).
83
+ *
84
+ * @param {any} base
85
+ * @param {any} overlay
86
+ * @returns {any} a new doc; neither input is mutated
87
+ */
88
+ export function mergeTopic(base: any, overlay: any): any;
89
+ /**
90
+ * Owner package recorded for the built-in topics. They ship inside the CLI
91
+ * (assets/docs), not in @astryxdesign/core, so this is the CLI's own name —
92
+ * unlike component discovery, whose built-ins belong to core.
93
+ */
94
+ export const BUILTIN_DOCS_PACKAGE: "@astryxdesign/cli";
95
+ /**
96
+ * Every topic a project can read, and the relationships between them.
97
+ *
98
+ * Insertion order is the read order: the built-in topics in discovery order,
99
+ * then whatever the configured integrations add, in the order they are
100
+ * configured. A replacement keeps the position of the topic it replaced, so
101
+ * "the first topic" stays stable for a reader that opens it by default.
102
+ */
103
+ export class DocsCatalog {
104
+ /**
105
+ * Seed a catalog with the CLI's own topics.
106
+ * @param {Record<string, string>} [builtins] topic name → absolute path
107
+ * @returns {DocsCatalog}
108
+ */
109
+ static fromBuiltins(builtins?: Record<string, string>): DocsCatalog;
110
+ /**
111
+ * Add one integration-contributed doc, honoring what it declares. Returns
112
+ * the issue it caused, or null when it applied cleanly — the caller owns
113
+ * routing (an `error` skips the contribution, a `warning` keeps it).
114
+ *
115
+ * @param {DocsTopicRecord} record
116
+ * @returns {import('../integrations/issue').AstryxIntegrationIssue | null}
117
+ */
118
+ add(record: DocsTopicRecord): import("../integrations/issue").AstryxIntegrationIssue | null;
119
+ /**
120
+ * Look a topic up by name, case-insensitively, following the alias a renamed
121
+ * replacement left behind.
122
+ * @param {unknown} name
123
+ * @returns {DocsTopicEntry | undefined}
124
+ */
125
+ resolve(name: unknown): DocsTopicEntry | undefined;
126
+ /** @returns {string[]} every topic name, in read order */
127
+ names(): string[];
128
+ /** @returns {DocsTopicEntry[]} every topic, in read order */
129
+ entries(): DocsTopicEntry[];
130
+ #private;
131
+ }
132
+ /**
133
+ * A doc file discovered under a docs root.
134
+ */
135
+ export type DocsTopicRecord = {
136
+ name: string;
137
+ /**
138
+ * owner package
139
+ */
140
+ package: string;
141
+ /**
142
+ * absolute path to the doc file
143
+ */
144
+ path: string;
145
+ title?: string | undefined;
146
+ description?: string | undefined;
147
+ category?: string | null | undefined;
148
+ /**
149
+ * topic this doc takes the place of
150
+ */
151
+ replaces?: string | undefined;
152
+ /**
153
+ * topic this doc merges onto (`extends`)
154
+ */
155
+ extendsTopic?: string | undefined;
156
+ };
157
+ /**
158
+ * A resolved topic in the catalog.
159
+ */
160
+ export type DocsTopicEntry = {
161
+ name: string;
162
+ /**
163
+ * owner package
164
+ */
165
+ package: string;
166
+ /**
167
+ * absolute path to the doc file
168
+ */
169
+ path: string;
170
+ title?: string | undefined;
171
+ description?: string | undefined;
172
+ category?: string | null | undefined;
173
+ /**
174
+ * the topic this one took the place of
175
+ */
176
+ replaces?: string | undefined;
177
+ /**
178
+ * overlays to
179
+ * merge onto the base doc, in the order their integrations were configured
180
+ */
181
+ extensions: Array<{
182
+ package: string;
183
+ path: string;
184
+ }>;
185
+ };