@astryxdesign/cli 0.6.3-canary.98a2e4e → 0.6.3-canary.9e4c545
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/api/docs/_adapter.d.mts +30 -27
- package/api/docs/_adapter.mjs +154 -124
- package/api/docs/compiled-topics.test.mjs +78 -0
- package/api/docs/detail/detail.d.mts +0 -15
- package/api/docs/detail/detail.mjs +14 -78
- package/api/docs/detail/section/section.mjs +22 -18
- package/api/docs/detail/section/section.test.mjs +4 -3
- package/api/docs/index/index.mjs +6 -5
- package/api/doctor/doctor.mjs +3 -7
- package/api/search/search.mjs +5 -5
- package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
- package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
- package/authoring/_shared/contract.ts +22 -0
- package/authoring/codemod/codemod.doc.mjs +6 -1
- package/authoring/codemod/parse.d.mts +8 -8
- package/authoring/codemod/parse.mjs +8 -6
- 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 +4 -4
- package/authoring/debug/parse.mjs +3 -3
- package/authoring/doctypes/_schema.d.mts +121 -11
- package/authoring/doctypes/_schema.mjs +144 -13
- package/authoring/doctypes/base/graph-fields.doc.mjs +11 -4
- package/authoring/doctypes/base/type.ts +8 -4
- package/authoring/doctypes/command/command.doc.mjs +3 -2
- package/authoring/doctypes/command/parse.d.mts +2 -2
- package/authoring/doctypes/command/parse.mjs +1 -1
- package/authoring/doctypes/command/type.ts +2 -2
- package/authoring/doctypes/component/component.doc.mjs +5 -2
- package/authoring/doctypes/component/parse.d.mts +2 -2
- package/authoring/doctypes/component/parse.mjs +1 -1
- package/authoring/doctypes/component/type.ts +1 -1
- package/authoring/doctypes/enum/parse.d.mts +2 -2
- package/authoring/doctypes/enum/parse.mjs +1 -1
- package/authoring/doctypes/enum/type.ts +1 -1
- package/authoring/doctypes/function/function.doc.mjs +4 -0
- package/authoring/doctypes/function/parse.d.mts +2 -2
- package/authoring/doctypes/function/parse.mjs +1 -1
- package/authoring/doctypes/function/type.ts +1 -1
- package/authoring/doctypes/hook/hook.doc.mjs +4 -0
- package/authoring/doctypes/hook/parse.d.mts +2 -2
- package/authoring/doctypes/hook/parse.mjs +1 -1
- package/authoring/doctypes/hook/type.ts +1 -1
- package/authoring/doctypes/legacy.d.mts +6 -6
- package/authoring/doctypes/legacy.mjs +3 -3
- package/authoring/doctypes/load-contract.test.mjs +207 -0
- package/authoring/doctypes/namespace/namespace.doc.mjs +7 -3
- package/authoring/doctypes/namespace/parse.d.mts +2 -2
- package/authoring/doctypes/namespace/parse.mjs +1 -1
- package/authoring/doctypes/namespace/type.ts +2 -2
- package/authoring/doctypes/parse.d.mts +18 -18
- package/authoring/doctypes/parse.mjs +9 -9
- package/authoring/doctypes/reference/parse.d.mts +2 -2
- package/authoring/doctypes/reference/parse.mjs +1 -1
- package/authoring/doctypes/reference/reference.doc.mjs +6 -2
- package/authoring/doctypes/reference/type.ts +1 -1
- package/authoring/doctypes/schema/parse.d.mts +2 -2
- package/authoring/doctypes/schema/parse.mjs +1 -1
- package/authoring/doctypes/schema/type.ts +2 -2
- package/authoring/doctypes/template/parse.d.mts +92 -1
- package/authoring/doctypes/template/parse.mjs +33 -1
- package/authoring/doctypes/template/template.doc.mjs +4 -0
- package/authoring/doctypes/template/type.ts +4 -1
- package/authoring/doctypes/types.ts +10 -10
- package/authoring/gap-report/parse.d.mts +9 -9
- package/authoring/gap-report/parse.mjs +6 -6
- package/authoring/gap-report/type.ts +1 -1
- package/authoring/identity/identity.doc.mjs +3 -2
- package/authoring/identity/type.ts +10 -10
- package/authoring/index.d.ts +19 -19
- package/authoring/integration/parse.d.mts +2 -2
- package/authoring/integration/parse.mjs +1 -1
- package/authoring/integration/schema.d.mts +4 -4
- package/authoring/integration/schema.mjs +3 -3
- package/authoring/integration/type.ts +1 -1
- package/foundation/discovery/authoring-self-docs.test.mjs +71 -12
- package/foundation/discovery/docs-discovery.d.mts +4 -0
- package/foundation/discovery/docs-discovery.mjs +16 -2
- package/foundation/discovery/docs-discovery.test.mjs +47 -11
- package/foundation/doc-compiler/compile.d.mts +162 -0
- package/foundation/doc-compiler/compile.mjs +262 -0
- package/foundation/doc-compiler/doc-compiler.test.mjs +687 -0
- package/foundation/doc-compiler/ir.d.mts +9 -0
- package/foundation/doc-compiler/ir.mjs +287 -0
- package/foundation/doc-compiler/lenses.d.mts +33 -0
- package/foundation/doc-compiler/lenses.mjs +127 -0
- package/package.json +9 -9
|
@@ -4,14 +4,15 @@
|
|
|
4
4
|
* @file docs.detail.section leaf — load a single section of a topic.
|
|
5
5
|
*
|
|
6
6
|
* @input A topic name, a section query, and optional {lang, zh, dense}. Resolves
|
|
7
|
-
*
|
|
8
|
-
* stable key, then by exact title, then by a title that contains
|
|
7
|
+
* the topic via the shared adapter, finds the section in its lowered compiled
|
|
8
|
+
* node by its stable key, then by exact title, then by a title that contains
|
|
9
|
+
* the query, and links only that section.
|
|
9
10
|
* @output { type: 'docs.detail.section', data: ReferenceSection } with any
|
|
10
11
|
* token-ref blocks inlined — matching `astryx --json docs <topic> <section>`.
|
|
11
12
|
* Throws ERR_UNKNOWN_SECTION when nothing matches, or when the query matches
|
|
12
13
|
* more than one section (the candidates come back as suggestions).
|
|
13
|
-
* @position Leaf nested under api/docs/detail. Shares
|
|
14
|
-
*
|
|
14
|
+
* @position Leaf nested under api/docs/detail. Shares topic resolution with the
|
|
15
|
+
* detail leaf via _adapter.mjs and reads through the compiler's lenses.
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
18
|
import {AstryxError} from '../../../error.mjs';
|
|
@@ -20,8 +21,12 @@ import {
|
|
|
20
21
|
findDocSection,
|
|
21
22
|
sectionKey,
|
|
22
23
|
} from '../../../../foundation/discovery/docs-section-key.mjs';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
24
|
+
import {linkReferenceSection} from '../../../../foundation/doc-compiler/compile.mjs';
|
|
25
|
+
import {
|
|
26
|
+
readerSections,
|
|
27
|
+
sectionView,
|
|
28
|
+
} from '../../../../foundation/doc-compiler/lenses.mjs';
|
|
29
|
+
import {referenceTargets, resolveTopicDocs} from '../../_adapter.mjs';
|
|
25
30
|
|
|
26
31
|
/**
|
|
27
32
|
* @param {string} topic
|
|
@@ -44,31 +49,30 @@ export async function section(topic, sectionName, options = {}) {
|
|
|
44
49
|
ERROR_CODES.ERR_UNKNOWN_SECTION,
|
|
45
50
|
);
|
|
46
51
|
}
|
|
47
|
-
const {catalog, docsData, lang} = await resolveTopicDocs(topic, options);
|
|
48
52
|
|
|
49
|
-
const {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
+
const {catalog, node, lang} = await resolveTopicDocs(topic, options);
|
|
54
|
+
const sections = readerSections(node);
|
|
55
|
+
const {section: match, candidates} = findDocSection(sections, sectionName);
|
|
53
56
|
if (!match) {
|
|
54
57
|
const ambiguous = candidates.length > 1;
|
|
55
58
|
throw new AstryxError(
|
|
56
59
|
ambiguous
|
|
57
60
|
? `Section "${sectionName}" matches ${candidates.length} sections in "${topic}". Read one by its key.`
|
|
58
61
|
: `Section "${sectionName}" not found in "${topic}"`,
|
|
59
|
-
(ambiguous ? candidates :
|
|
62
|
+
(ambiguous ? candidates : sections).map(s => ({
|
|
60
63
|
name: sectionKey(s),
|
|
61
64
|
reason: s.title,
|
|
62
65
|
})),
|
|
63
66
|
ERROR_CODES.ERR_UNKNOWN_SECTION,
|
|
64
67
|
);
|
|
65
68
|
}
|
|
69
|
+
|
|
66
70
|
// A section read on its own inlines its token refs, as the whole topic does;
|
|
67
|
-
// otherwise a section that is only a token-ref prints blank.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
// otherwise a section that is only a token-ref prints blank. Only this
|
|
72
|
+
// section is linked, so a broken reference elsewhere cannot fail the read.
|
|
73
|
+
const linked = await linkReferenceSection(
|
|
74
|
+
match,
|
|
75
|
+
referenceTargets(catalog, lang),
|
|
72
76
|
);
|
|
73
|
-
return {type: 'docs.detail.section', data:
|
|
77
|
+
return {type: 'docs.detail.section', data: sectionView(node, linked)};
|
|
74
78
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import {describe, it, expect} from 'vitest';
|
|
11
11
|
import {section} from './section.mjs';
|
|
12
12
|
import {AstryxError} from '../../../error.mjs';
|
|
13
|
-
import {loadDocsCatalog,
|
|
13
|
+
import {loadDocsCatalog, lowerTopic} from '../../_adapter.mjs';
|
|
14
14
|
|
|
15
15
|
const SLOW = 30_000;
|
|
16
16
|
|
|
@@ -42,7 +42,8 @@ describe('docs.detail.section leaf', () => {
|
|
|
42
42
|
}, SLOW);
|
|
43
43
|
|
|
44
44
|
it('reads a section by its stable key', async () => {
|
|
45
|
-
const
|
|
45
|
+
const catalog = await loadDocsCatalog();
|
|
46
|
+
const {doc} = await lowerTopic(catalog, catalog.resolve('theme'));
|
|
46
47
|
const target = doc.sections[doc.sections.length - 1];
|
|
47
48
|
const res = await section('theme', target.id);
|
|
48
49
|
expect(res.data.title).toBe(target.title);
|
|
@@ -63,7 +64,7 @@ describe('docs.detail.section leaf', () => {
|
|
|
63
64
|
const catalog = await loadDocsCatalog();
|
|
64
65
|
let checked = 0;
|
|
65
66
|
for (const entry of catalog.entries()) {
|
|
66
|
-
const doc = await
|
|
67
|
+
const {doc} = await lowerTopic(catalog, entry);
|
|
67
68
|
for (const own of doc.sections) {
|
|
68
69
|
if (!own.content.some(block => block.type === 'token-ref')) continue;
|
|
69
70
|
const res = await section(entry.name, own.id, lang ? {lang} : {});
|
package/api/docs/index/index.mjs
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file docs.index leaf — the section index of one topic.
|
|
5
5
|
*
|
|
6
|
-
* @input A topic name plus optional {lang, zh, dense, cwd}. Resolves
|
|
7
|
-
*
|
|
6
|
+
* @input A topic name plus optional {lang, zh, dense, cwd}. Resolves the topic
|
|
7
|
+
* via the shared adapter and reads its lowered compiled node; nothing is
|
|
8
|
+
* linked, since the index never inlines a token reference.
|
|
8
9
|
* @output { type: 'docs.index', data: DocsIndex } — the topic's name, title and
|
|
9
10
|
* description and, for each section, the key it is read by, its title, and a
|
|
10
11
|
* one-line summary. Matches `astryx --json docs <topic> --index`.
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
* read, is the detail leaf.
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
|
-
import {
|
|
17
|
+
import {indexView} from '../../../foundation/doc-compiler/lenses.mjs';
|
|
17
18
|
import {resolveTopicDocs} from '../_adapter.mjs';
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -26,6 +27,6 @@ import {resolveTopicDocs} from '../_adapter.mjs';
|
|
|
26
27
|
* @returns {Promise<import('../docs.type.mjs').DocsIndexResponse>}
|
|
27
28
|
*/
|
|
28
29
|
export async function index(topic, options = {}) {
|
|
29
|
-
const {
|
|
30
|
-
return {type: 'docs.index', data:
|
|
30
|
+
const {node} = await resolveTopicDocs(topic, options);
|
|
31
|
+
return {type: 'docs.index', data: indexView(node)};
|
|
31
32
|
}
|
package/api/doctor/doctor.mjs
CHANGED
|
@@ -34,8 +34,8 @@ import {
|
|
|
34
34
|
docsIndexBytes,
|
|
35
35
|
oversizedDocSections,
|
|
36
36
|
} from '../../foundation/discovery/docs-output-budget.mjs';
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
37
|
+
import {compileTopic, overlayLanguages} from '../docs/_adapter.mjs';
|
|
38
|
+
import {detailView} from '../../foundation/doc-compiler/lenses.mjs';
|
|
39
39
|
import {semverCompare, isValidSemver, satisfiesRange} from '../../foundation/env/semver.mjs';
|
|
40
40
|
|
|
41
41
|
/**
|
|
@@ -798,11 +798,7 @@ export async function checkDocsProgressiveDisclosure(ctx) {
|
|
|
798
798
|
for (const lang of [null, ...overlayLanguages(entry)]) {
|
|
799
799
|
const where = lang ? `${entry.name} [${lang}]` : entry.name;
|
|
800
800
|
try {
|
|
801
|
-
const doc = await
|
|
802
|
-
await loadTopicDoc(entry, {lang}),
|
|
803
|
-
catalog,
|
|
804
|
-
{lang},
|
|
805
|
-
);
|
|
801
|
+
const doc = detailView(await compileTopic(catalog, entry, lang));
|
|
806
802
|
if (lang == null) topics += 1;
|
|
807
803
|
const indexBytes = docsIndexBytes(buildDocsIndexData(doc));
|
|
808
804
|
if (indexBytes > DOC_OUTPUT_BUDGET_BYTES) {
|
package/api/search/search.mjs
CHANGED
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
import {loadIntegrationsSafely} from '../component/_adapter.mjs';
|
|
67
67
|
import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
|
|
68
68
|
import {discoverTemplates, extractComponents} from '../template/template.mjs';
|
|
69
|
-
import {loadDocsCatalog,
|
|
69
|
+
import {loadDocsCatalog, lowerTopic} from '../docs/_adapter.mjs';
|
|
70
70
|
import {AstryxError} from '../error.mjs';
|
|
71
71
|
import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
|
|
72
72
|
import {setResultCoverage} from './coverage.mjs';
|
|
@@ -732,16 +732,16 @@ async function gatherHooks(coreDir) {
|
|
|
732
732
|
async function gatherDocs(cwd) {
|
|
733
733
|
/** @type {Candidate[]} */
|
|
734
734
|
const candidates = [];
|
|
735
|
-
let
|
|
735
|
+
let catalog;
|
|
736
736
|
try {
|
|
737
|
-
|
|
737
|
+
catalog = await loadDocsCatalog(cwd);
|
|
738
738
|
} catch {
|
|
739
739
|
return candidates;
|
|
740
740
|
}
|
|
741
|
-
for (const entry of entries) {
|
|
741
|
+
for (const entry of catalog.entries()) {
|
|
742
742
|
let doc = null;
|
|
743
743
|
try {
|
|
744
|
-
doc = await
|
|
744
|
+
doc = (await lowerTopic(catalog, entry)).doc;
|
|
745
745
|
} catch {
|
|
746
746
|
// A topic that cannot be loaded is reported by the commands that own
|
|
747
747
|
// integration issues; search just cannot index it.
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import {describe, it, expect} from 'vitest';
|
|
4
4
|
|
|
5
5
|
async function applyTransform(source, path = 'test.ts') {
|
|
6
|
-
const {default: transform} =
|
|
6
|
+
const {default: transform} =
|
|
7
|
+
await import('../unwrap-authoring-factories.mjs');
|
|
7
8
|
const jscodeshift = (await import('jscodeshift')).default;
|
|
8
9
|
const j = jscodeshift.withParser('tsx');
|
|
9
10
|
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
@@ -18,7 +19,7 @@ export default createConfig({integrations: ['@acme/widgets']});
|
|
|
18
19
|
`;
|
|
19
20
|
const output = await applyTransform(input);
|
|
20
21
|
expect(output).not.toContain('createConfig');
|
|
21
|
-
expect(output).toContain(
|
|
22
|
+
expect(output).toContain('export default {');
|
|
22
23
|
expect(output).toContain("integrations: ['@acme/widgets']");
|
|
23
24
|
expect(output).not.toContain('type:');
|
|
24
25
|
});
|
|
@@ -132,13 +133,34 @@ export default createComponentDoc();
|
|
|
132
133
|
expect(output).toContain("type: 'component'");
|
|
133
134
|
});
|
|
134
135
|
|
|
136
|
+
it('leaves same-named factories from unrelated packages unchanged', async () => {
|
|
137
|
+
const input = `import {createConfig} from '@acme/eslint';
|
|
138
|
+
export default createConfig({strict: true});
|
|
139
|
+
`;
|
|
140
|
+
expect(await applyTransform(input)).toBe(input);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('keeps an unrelated same-named import when another factory is migrated', async () => {
|
|
144
|
+
const input = `import {createConfig as createLintConfig} from '@acme/eslint';
|
|
145
|
+
import {createDoc} from '@astryxdesign/cli/doc';
|
|
146
|
+
export const lintConfig = createLintConfig({strict: true});
|
|
147
|
+
export const doc = createDoc({name: 'Theming', description: 'How theming works.'});
|
|
148
|
+
`;
|
|
149
|
+
const output = await applyTransform(input);
|
|
150
|
+
expect(output).toContain(
|
|
151
|
+
"import {createConfig as createLintConfig} from '@acme/eslint'",
|
|
152
|
+
);
|
|
153
|
+
expect(output).toContain('createLintConfig({strict: true})');
|
|
154
|
+
expect(output).not.toContain('createDoc');
|
|
155
|
+
expect(output).toContain("type: 'generic'");
|
|
156
|
+
});
|
|
157
|
+
|
|
135
158
|
it('is a no-op when no authoring factory is imported', async () => {
|
|
136
159
|
const input = `import {Button} from '@astryxdesign/core';
|
|
137
160
|
export default Button;
|
|
138
161
|
`;
|
|
139
|
-
const {default: transform} =
|
|
140
|
-
'../unwrap-authoring-factories.mjs'
|
|
141
|
-
);
|
|
162
|
+
const {default: transform} =
|
|
163
|
+
await import('../unwrap-authoring-factories.mjs');
|
|
142
164
|
const jscodeshift = (await import('jscodeshift')).default;
|
|
143
165
|
const j = jscodeshift.withParser('tsx');
|
|
144
166
|
const api = {jscodeshift: j, stats: () => {}, report: () => {}};
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* v0.3.0 removes the authoring factories. Authoring is now types + parsers: an
|
|
7
7
|
* author writes a plain object and stamps its `type` directly. This transform
|
|
8
|
-
* rewrites
|
|
9
|
-
* then drops the now-dead
|
|
8
|
+
* rewrites factory calls imported from the retired Astryx authoring entrypoints
|
|
9
|
+
* to the plain object the factory used to return, then drops the now-dead
|
|
10
|
+
* factory imports:
|
|
10
11
|
*
|
|
11
12
|
* createConfig(o) / createIntegration(o) -> o (no discriminant)
|
|
12
13
|
* createComponentDoc(o) -> { ...o, type: 'component' }
|
|
@@ -25,8 +26,9 @@
|
|
|
25
26
|
*
|
|
26
27
|
* Import aliases are followed (`import {createDoc as mk}` → calls to `mk`), and
|
|
27
28
|
* the factory specifiers are removed afterward (the whole import statement goes
|
|
28
|
-
* if nothing else was imported from it).
|
|
29
|
-
* `migrate-authoring-imports`, which repoints
|
|
29
|
+
* if nothing else was imported from it). Same-named imports from other packages
|
|
30
|
+
* remain untouched. Run this BEFORE `migrate-authoring-imports`, which repoints
|
|
31
|
+
* the surviving type imports.
|
|
30
32
|
*/
|
|
31
33
|
|
|
32
34
|
export const meta = {
|
|
@@ -35,13 +37,24 @@ export const meta = {
|
|
|
35
37
|
'Rewrites createConfig/createIntegration/createComponentDoc/' +
|
|
36
38
|
'createFunctionDoc/createDoc/createPageTemplate/createBlockTemplate/' +
|
|
37
39
|
'createCodemod/createConfigCodemod calls to the plain object they returned ' +
|
|
38
|
-
|
|
40
|
+
'(stamping the doc/template/codemod `type` discriminant), and removes the ' +
|
|
39
41
|
'now-dead factory imports. Authoring is types + parsers in v0.3.0 — there ' +
|
|
40
42
|
'are no factories.',
|
|
41
43
|
pr: '#4612',
|
|
42
44
|
fileExtensions: ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs'],
|
|
43
45
|
};
|
|
44
46
|
|
|
47
|
+
/** Legacy Astryx authoring entrypoints that exported the removed factories. */
|
|
48
|
+
const AUTHORING_SOURCES = new Set([
|
|
49
|
+
'@astryxdesign/cli/config',
|
|
50
|
+
'@astryxdesign/cli/doc',
|
|
51
|
+
'@astryxdesign/cli/integration',
|
|
52
|
+
'@astryxdesign/cli/template',
|
|
53
|
+
'@astryxdesign/cli/codemod',
|
|
54
|
+
'@astryxdesign/core/authoring',
|
|
55
|
+
'@astryxdesign/core/config',
|
|
56
|
+
]);
|
|
57
|
+
|
|
45
58
|
/**
|
|
46
59
|
* Factory name → the `type` discriminant it stamped, or `null` for the config /
|
|
47
60
|
* integration factories, which were pure typed-identity (no discriminant).
|
|
@@ -108,6 +121,7 @@ export default function transformer(file, api) {
|
|
|
108
121
|
/** @type {Map<string, string>} */
|
|
109
122
|
const localToFactory = new Map();
|
|
110
123
|
root.find(j.ImportDeclaration).forEach((/** @type {any} */ path) => {
|
|
124
|
+
if (!AUTHORING_SOURCES.has(path.node.source.value)) return;
|
|
111
125
|
for (const spec of path.node.specifiers ?? []) {
|
|
112
126
|
if (spec.type !== 'ImportSpecifier') continue;
|
|
113
127
|
const importedName = spec.imported?.name;
|
|
@@ -163,6 +177,7 @@ export default function transformer(file, api) {
|
|
|
163
177
|
// Drop the now-dead factory import specifiers; remove any import statement
|
|
164
178
|
// left empty.
|
|
165
179
|
root.find(j.ImportDeclaration).forEach((/** @type {any} */ path) => {
|
|
180
|
+
if (!AUTHORING_SOURCES.has(path.node.source.value)) return;
|
|
166
181
|
const specs = path.node.specifiers ?? [];
|
|
167
182
|
const kept = specs.filter(
|
|
168
183
|
(/** @type {any} */ spec) =>
|
|
@@ -28,5 +28,27 @@ export type MutuallyAssignable<A, B> = [A] extends [B]
|
|
|
28
28
|
: false
|
|
29
29
|
: false;
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* `T` without string or number index signatures, at every depth. A
|
|
33
|
+
* `.passthrough()` schema infers one and a hand-written interface never has
|
|
34
|
+
* one, so a lock drops them before comparing named fields. Recursive fields
|
|
35
|
+
* that a schema casts to their public type compare equal by construction.
|
|
36
|
+
*/
|
|
37
|
+
export type NamedFields<T> = T extends readonly (infer U)[]
|
|
38
|
+
? NamedFields<U>[]
|
|
39
|
+
: T extends (...args: never[]) => unknown
|
|
40
|
+
? T
|
|
41
|
+
: T extends object
|
|
42
|
+
? {
|
|
43
|
+
[
|
|
44
|
+
K in keyof T as string extends K
|
|
45
|
+
? never
|
|
46
|
+
: number extends K
|
|
47
|
+
? never
|
|
48
|
+
: K
|
|
49
|
+
]: NamedFields<T[K]>;
|
|
50
|
+
}
|
|
51
|
+
: T;
|
|
52
|
+
|
|
31
53
|
/** Compiles only when `T` is exactly `true`; otherwise a type error. */
|
|
32
54
|
export type Expect<T extends true> = T;
|
|
@@ -63,11 +63,13 @@ export const doc = {
|
|
|
63
63
|
name: 'file.path',
|
|
64
64
|
type: 'string',
|
|
65
65
|
description: 'Absolute path to the file being transformed.',
|
|
66
|
+
required: true,
|
|
66
67
|
},
|
|
67
68
|
{
|
|
68
69
|
name: 'file.source',
|
|
69
70
|
type: 'string',
|
|
70
71
|
description: 'The current source contents of the file.',
|
|
72
|
+
required: true,
|
|
71
73
|
},
|
|
72
74
|
],
|
|
73
75
|
},
|
|
@@ -81,18 +83,21 @@ export const doc = {
|
|
|
81
83
|
type: 'unknown',
|
|
82
84
|
description:
|
|
83
85
|
'A jscodeshift instance configured with a parser for the file.',
|
|
86
|
+
required: true,
|
|
84
87
|
},
|
|
85
88
|
{
|
|
86
89
|
name: 'api.stats',
|
|
87
90
|
type: '(...args: unknown[]) => void',
|
|
88
91
|
description:
|
|
89
92
|
'Report a statistic (no-op-friendly; provided for jscodeshift parity).',
|
|
93
|
+
required: true,
|
|
90
94
|
},
|
|
91
95
|
{
|
|
92
96
|
name: 'api.report',
|
|
93
97
|
type: '(...args: unknown[]) => void',
|
|
94
98
|
description:
|
|
95
99
|
'Report progress (no-op-friendly; provided for jscodeshift parity).',
|
|
100
|
+
required: true,
|
|
96
101
|
},
|
|
97
102
|
],
|
|
98
103
|
},
|
|
@@ -100,7 +105,7 @@ export const doc = {
|
|
|
100
105
|
},
|
|
101
106
|
{
|
|
102
107
|
name: 'type',
|
|
103
|
-
type: "'code'",
|
|
108
|
+
type: "'code' | 'config'",
|
|
104
109
|
description:
|
|
105
110
|
"Discriminant for the file-transforming variant. Use 'config' for a " +
|
|
106
111
|
'codemod that rewrites astryx.config.* instead (see notes).',
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Compile-time drift-lock: sealed envelope must infer exactly the public
|
|
6
6
|
* stamped-codemod union.
|
|
7
7
|
*
|
|
8
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
9
|
-
* import('../_shared/contract').Equal<
|
|
8
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
9
|
+
* import('../_shared/contract.js').Equal<
|
|
10
10
|
* z.infer<typeof codemodEnvelopeSchema>,
|
|
11
11
|
* AstryxCodemod | AstryxConfigCodemod
|
|
12
12
|
* >
|
|
@@ -24,10 +24,10 @@ export function parseCodemod(input: unknown, label?: string): AstryxCodemod | As
|
|
|
24
24
|
* Compile-time drift-lock: sealed envelope must infer exactly the public
|
|
25
25
|
* stamped-codemod union.
|
|
26
26
|
*/
|
|
27
|
-
export type _CodemodDriftLock = import("../_shared/contract").Expect<import("../_shared/contract").Equal<z.infer<typeof codemodEnvelopeSchema>, AstryxCodemod | AstryxConfigCodemod>>;
|
|
28
|
-
export type AstryxCodemod = import("./type").AstryxCodemod;
|
|
29
|
-
export type AstryxConfigCodemod = import("./type").AstryxConfigCodemod;
|
|
30
|
-
export type AstryxCodemodTransform = import("./type").AstryxCodemodTransform;
|
|
27
|
+
export type _CodemodDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").Equal<z.infer<typeof codemodEnvelopeSchema>, AstryxCodemod | AstryxConfigCodemod>>;
|
|
28
|
+
export type AstryxCodemod = import("./type.js").AstryxCodemod;
|
|
29
|
+
export type AstryxConfigCodemod = import("./type.js").AstryxConfigCodemod;
|
|
30
|
+
export type AstryxCodemodTransform = import("./type.js").AstryxCodemodTransform;
|
|
31
31
|
import { z } from 'zod';
|
|
32
32
|
/**
|
|
33
33
|
* The load-boundary contract: a stamped codemod default export, discriminated
|
|
@@ -38,13 +38,13 @@ declare const codemodEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
38
38
|
description: z.ZodOptional<z.ZodString>;
|
|
39
39
|
isOptional: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
40
40
|
fileExtensions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
41
|
-
transform: z.ZodType<import("./type").AstryxCodemodTransform, any, z.core.$ZodTypeInternals<import("./type").AstryxCodemodTransform, any>>;
|
|
41
|
+
transform: z.ZodType<import("./type.js").AstryxCodemodTransform, any, z.core.$ZodTypeInternals<import("./type.js").AstryxCodemodTransform, any>>;
|
|
42
42
|
type: z.ZodLiteral<"code">;
|
|
43
43
|
}, z.core.$strict>, z.ZodObject<{
|
|
44
44
|
title: z.ZodString;
|
|
45
45
|
description: z.ZodOptional<z.ZodString>;
|
|
46
46
|
isOptional: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
47
|
-
transform: z.ZodType<import("./type").AstryxCodemodTransform, any, z.core.$ZodTypeInternals<import("./type").AstryxCodemodTransform, any>>;
|
|
47
|
+
transform: z.ZodType<import("./type.js").AstryxCodemodTransform, any, z.core.$ZodTypeInternals<import("./type.js").AstryxCodemodTransform, any>>;
|
|
48
48
|
type: z.ZodLiteral<"config">;
|
|
49
49
|
}, z.core.$strict>], "type">;
|
|
50
50
|
export {};
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
import {z} from 'zod';
|
|
11
11
|
import {formatZodError} from '../_shared/errors.mjs';
|
|
12
12
|
|
|
13
|
-
/** @typedef {import('./type').AstryxCodemod} AstryxCodemod */
|
|
14
|
-
/** @typedef {import('./type').AstryxConfigCodemod} AstryxConfigCodemod */
|
|
15
|
-
/** @typedef {import('./type').AstryxCodemodTransform} AstryxCodemodTransform */
|
|
13
|
+
/** @typedef {import('./type.js').AstryxCodemod} AstryxCodemod */
|
|
14
|
+
/** @typedef {import('./type.js').AstryxConfigCodemod} AstryxConfigCodemod */
|
|
15
|
+
/** @typedef {import('./type.js').AstryxCodemodTransform} AstryxCodemodTransform */
|
|
16
16
|
|
|
17
17
|
const transform = /** @type {z.ZodType<AstryxCodemodTransform>} */ (
|
|
18
|
-
z.custom(value => typeof value === 'function', {
|
|
18
|
+
z.custom(value => typeof value === 'function', {
|
|
19
|
+
message: 'Expected a function',
|
|
20
|
+
})
|
|
19
21
|
);
|
|
20
22
|
|
|
21
23
|
const codeCodemodSchema = z
|
|
@@ -52,8 +54,8 @@ const codemodEnvelopeSchema = z.discriminatedUnion('type', [
|
|
|
52
54
|
* Compile-time drift-lock: sealed envelope must infer exactly the public
|
|
53
55
|
* stamped-codemod union.
|
|
54
56
|
*
|
|
55
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
56
|
-
* import('../_shared/contract').Equal<
|
|
57
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
58
|
+
* import('../_shared/contract.js').Equal<
|
|
57
59
|
* z.infer<typeof codemodEnvelopeSchema>,
|
|
58
60
|
* AstryxCodemod | AstryxConfigCodemod
|
|
59
61
|
* >
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* {@link AstryxConfig} type. If they drift, `Equal` becomes `false` and
|
|
7
7
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck.
|
|
8
8
|
*
|
|
9
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
10
|
-
* import('../_shared/contract').MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>
|
|
9
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
10
|
+
* import('../_shared/contract.js').MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>
|
|
11
11
|
* >} _ConfigDriftLock
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
@@ -23,13 +23,13 @@ export function parseConfig(input: unknown, label?: string): AstryxConfig;
|
|
|
23
23
|
* {@link AstryxConfig} type. If they drift, `Equal` becomes `false` and
|
|
24
24
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck.
|
|
25
25
|
*/
|
|
26
|
-
export type _ConfigDriftLock = import("../_shared/contract").Expect<import("../_shared/contract").MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>>;
|
|
27
|
-
export type AstryxConfig = import("./type").AstryxConfig;
|
|
28
|
-
export type PostCodemodHook = import("./type").PostCodemodHook;
|
|
29
|
-
export type XleComponent = import("./type").XleComponent;
|
|
30
|
-
export type DebugConfig = import("./type").DebugConfig;
|
|
31
|
-
export type DebugEventHandler = import("../debug/type").DebugEventHandler;
|
|
32
|
-
export type GapReportHandler = import("../gap-report/type").GapReportHandler;
|
|
26
|
+
export type _ConfigDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>>;
|
|
27
|
+
export type AstryxConfig = import("./type.js").AstryxConfig;
|
|
28
|
+
export type PostCodemodHook = import("./type.js").PostCodemodHook;
|
|
29
|
+
export type XleComponent = import("./type.js").XleComponent;
|
|
30
|
+
export type DebugConfig = import("./type.js").DebugConfig;
|
|
31
|
+
export type DebugEventHandler = import("../debug/type.js").DebugEventHandler;
|
|
32
|
+
export type GapReportHandler = import("../gap-report/type.js").GapReportHandler;
|
|
33
33
|
import { z } from 'zod';
|
|
34
34
|
declare const configSchema: z.ZodObject<{
|
|
35
35
|
integrations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -40,14 +40,14 @@ declare const configSchema: z.ZodObject<{
|
|
|
40
40
|
buildCommand: z.ZodType<(ctx: {
|
|
41
41
|
packageDir: string;
|
|
42
42
|
files: string[];
|
|
43
|
-
}) => import("./type").PostCodemodCommand | null | undefined | Promise<import("./type").PostCodemodCommand | null | undefined>, any, z.core.$ZodTypeInternals<(ctx: {
|
|
43
|
+
}) => import("./type.js").PostCodemodCommand | null | undefined | Promise<import("./type.js").PostCodemodCommand | null | undefined>, any, z.core.$ZodTypeInternals<(ctx: {
|
|
44
44
|
packageDir: string;
|
|
45
45
|
files: string[];
|
|
46
|
-
}) => import("./type").PostCodemodCommand | null | undefined | Promise<import("./type").PostCodemodCommand | null | undefined>, any>>;
|
|
46
|
+
}) => import("./type.js").PostCodemodCommand | null | undefined | Promise<import("./type.js").PostCodemodCommand | null | undefined>, any>>;
|
|
47
47
|
}, z.core.$strict>>>;
|
|
48
48
|
}, z.core.$strict>>;
|
|
49
|
-
debug: z.ZodOptional<z.ZodType<import("../debug/type").DebugEventHandler, any, z.core.$ZodTypeInternals<import("../debug/type").DebugEventHandler, any>>>;
|
|
50
|
-
gapReport: z.ZodOptional<z.ZodType<import("../gap-report/type").GapReportHandler, any, z.core.$ZodTypeInternals<import("../gap-report/type").GapReportHandler, any>>>;
|
|
49
|
+
debug: z.ZodOptional<z.ZodType<import("../debug/type.js").DebugEventHandler, any, z.core.$ZodTypeInternals<import("../debug/type.js").DebugEventHandler, any>>>;
|
|
50
|
+
gapReport: z.ZodOptional<z.ZodType<import("../gap-report/type.js").GapReportHandler, any, z.core.$ZodTypeInternals<import("../gap-report/type.js").GapReportHandler, any>>>;
|
|
51
51
|
experimental: z.ZodOptional<z.ZodObject<{
|
|
52
52
|
xle: z.ZodOptional<z.ZodObject<{
|
|
53
53
|
components: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
@@ -13,12 +13,12 @@ import {z} from 'zod';
|
|
|
13
13
|
import {formatZodError} from '../_shared/errors.mjs';
|
|
14
14
|
import {parseGapReportHandler} from '../gap-report/parse.mjs';
|
|
15
15
|
|
|
16
|
-
/** @typedef {import('./type').AstryxConfig} AstryxConfig */
|
|
17
|
-
/** @typedef {import('./type').PostCodemodHook} PostCodemodHook */
|
|
18
|
-
/** @typedef {import('./type').XleComponent} XleComponent */
|
|
19
|
-
/** @typedef {import('./type').DebugConfig} DebugConfig */
|
|
20
|
-
/** @typedef {import('../debug/type').DebugEventHandler} DebugEventHandler */
|
|
21
|
-
/** @typedef {import('../gap-report/type').GapReportHandler} GapReportHandler */
|
|
16
|
+
/** @typedef {import('./type.js').AstryxConfig} AstryxConfig */
|
|
17
|
+
/** @typedef {import('./type.js').PostCodemodHook} PostCodemodHook */
|
|
18
|
+
/** @typedef {import('./type.js').XleComponent} XleComponent */
|
|
19
|
+
/** @typedef {import('./type.js').DebugConfig} DebugConfig */
|
|
20
|
+
/** @typedef {import('../debug/type.js').DebugEventHandler} DebugEventHandler */
|
|
21
|
+
/** @typedef {import('../gap-report/type.js').GapReportHandler} GapReportHandler */
|
|
22
22
|
|
|
23
23
|
// Typed `z.custom` so `z.infer` reproduces the real function type (not `unknown`).
|
|
24
24
|
const buildCommand = /** @type {z.ZodType<PostCodemodHook['buildCommand']>} */ (
|
|
@@ -95,8 +95,8 @@ const configSchema = z
|
|
|
95
95
|
* {@link AstryxConfig} type. If they drift, `Equal` becomes `false` and
|
|
96
96
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck.
|
|
97
97
|
*
|
|
98
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
99
|
-
* import('../_shared/contract').MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>
|
|
98
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
99
|
+
* import('../_shared/contract.js').MutuallyAssignable<z.infer<typeof configSchema>, AstryxConfig>
|
|
100
100
|
* >} _ConfigDriftLock
|
|
101
101
|
*/
|
|
102
102
|
|
package/authoring/config/type.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* boundary; there is no factory to call.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type {DebugEventHandler} from '../debug/type';
|
|
13
|
-
import type {GapReportHandler} from '../gap-report/type';
|
|
12
|
+
import type {DebugEventHandler} from '../debug/type.js';
|
|
13
|
+
import type {GapReportHandler} from '../gap-report/type.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* A command to run as part of a post-codemod hook. Returned by a hook's
|
|
@@ -21,7 +21,7 @@ export interface PostCodemodCommand {
|
|
|
21
21
|
args?: string[];
|
|
22
22
|
options?: {
|
|
23
23
|
cwd?: string;
|
|
24
|
-
env?:
|
|
24
|
+
env?: Record<string, string | undefined>;
|
|
25
25
|
timeout?: number;
|
|
26
26
|
};
|
|
27
27
|
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck —
|
|
8
8
|
* so a field added to the recorder without being published here breaks CI.
|
|
9
9
|
*
|
|
10
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
11
|
-
* import('../_shared/contract').MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>
|
|
10
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
11
|
+
* import('../_shared/contract.js').MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>
|
|
12
12
|
* >} _DebugEventDriftLock
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
@@ -29,8 +29,8 @@ export function parseDebugEvent(input: unknown, label?: string): DebugEvent;
|
|
|
29
29
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck —
|
|
30
30
|
* so a field added to the recorder without being published here breaks CI.
|
|
31
31
|
*/
|
|
32
|
-
export type _DebugEventDriftLock = import("../_shared/contract").Expect<import("../_shared/contract").MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>>;
|
|
33
|
-
export type DebugEvent = import("./type").DebugEvent;
|
|
32
|
+
export type _DebugEventDriftLock = import("../_shared/contract.js").Expect<import("../_shared/contract.js").MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>>;
|
|
33
|
+
export type DebugEvent = import("./type.js").DebugEvent;
|
|
34
34
|
import { z } from 'zod';
|
|
35
35
|
declare const eventSchema: z.ZodObject<{
|
|
36
36
|
schemaVersion: z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import {z} from 'zod';
|
|
23
23
|
import {formatZodError} from '../_shared/errors.mjs';
|
|
24
24
|
|
|
25
|
-
/** @typedef {import('./type').DebugEvent} DebugEvent */
|
|
25
|
+
/** @typedef {import('./type.js').DebugEvent} DebugEvent */
|
|
26
26
|
|
|
27
27
|
const outcomeSchema = z.enum([
|
|
28
28
|
'ok',
|
|
@@ -169,8 +169,8 @@ const eventSchema = z
|
|
|
169
169
|
* `Expect<false>` fails the `tsconfig.authoring-contract.json` typecheck —
|
|
170
170
|
* so a field added to the recorder without being published here breaks CI.
|
|
171
171
|
*
|
|
172
|
-
* @typedef {import('../_shared/contract').Expect<
|
|
173
|
-
* import('../_shared/contract').MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>
|
|
172
|
+
* @typedef {import('../_shared/contract.js').Expect<
|
|
173
|
+
* import('../_shared/contract.js').MutuallyAssignable<z.infer<typeof eventSchema>, DebugEvent>
|
|
174
174
|
* >} _DebugEventDriftLock
|
|
175
175
|
*/
|
|
176
176
|
|