@astrale-os/sdk 0.5.0-beta.138 → 0.5.0-beta.139
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tooling/packaging/declarations/normalize.js +3 -38
- package/dist/tooling/packaging/declarations/paths.d.ts +5 -0
- package/dist/tooling/packaging/declarations/paths.js +38 -0
- package/dist/tooling/packaging/finalize.d.ts +13 -0
- package/dist/tooling/packaging/finalize.js +62 -0
- package/dist/tooling/packaging/index.d.ts +2 -0
- package/dist/tooling/packaging/index.js +1 -0
- package/dist/tooling/packaging/javascript.d.ts +3 -0
- package/dist/tooling/packaging/javascript.js +45 -2
- package/dist/tooling/packaging/packaging.d.ts +2 -5
- package/dist/tooling/packaging/packaging.js +6 -30
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync,
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
3
|
import { admitPackageImports, resolvePackageImport } from './imports.js';
|
|
4
|
+
import { confined, resolveImportTarget, resolveLocal, runtimeSpecifier } from './paths.js';
|
|
4
5
|
import { declarationReferences } from './references.js';
|
|
5
6
|
import { declarationEdits, declarationFacade } from './transform.js';
|
|
6
7
|
/** Normalize emitted declarations without re-emitting or re-typechecking their source program. */
|
|
@@ -87,42 +88,6 @@ export function reachableDeclarations(root, requested, imports = {}) {
|
|
|
87
88
|
}
|
|
88
89
|
return [...seen].sort();
|
|
89
90
|
}
|
|
90
|
-
function resolveImportTarget(root, target) {
|
|
91
|
-
return resolveLocal(join(root, 'entry.d.ts'), `./${target.slice('./dist/'.length)}`);
|
|
92
|
-
}
|
|
93
|
-
function resolveLocal(containing, specifier) {
|
|
94
|
-
const base = resolve(dirname(containing), specifier);
|
|
95
|
-
const candidates = [
|
|
96
|
-
base.endsWith('.mjs') ? base.replace(/\.mjs$/u, '.d.mts') : '',
|
|
97
|
-
base.endsWith('.cjs') ? base.replace(/\.cjs$/u, '.d.cts') : '',
|
|
98
|
-
base.endsWith('.js') ? base.replace(/\.js$/u, '.d.ts') : '',
|
|
99
|
-
/\.d\.(?:ts|mts|cts)$/u.test(base) ? base : '',
|
|
100
|
-
`${base}.d.ts`,
|
|
101
|
-
join(base, 'index.d.ts'),
|
|
102
|
-
];
|
|
103
|
-
const file = candidates.find((candidate) => candidate && existsSync(candidate));
|
|
104
|
-
if (!file)
|
|
105
|
-
throw new TypeError(`Cannot resolve declaration reference ${specifier} from ${containing}.`);
|
|
106
|
-
return file;
|
|
107
|
-
}
|
|
108
|
-
/** Point a local declaration reference at the emitted ESM module that owns it. */
|
|
109
|
-
function runtimeSpecifier(containing, declaration) {
|
|
110
|
-
const runtime = declaration
|
|
111
|
-
.replace(/\.d\.mts$/u, '.mjs')
|
|
112
|
-
.replace(/\.d\.cts$/u, '.cjs')
|
|
113
|
-
.replace(/\.d\.ts$/u, '.js');
|
|
114
|
-
const path = relative(dirname(containing), runtime).replaceAll('\\', '/');
|
|
115
|
-
return path.startsWith('./') || path.startsWith('../') ? path : `./${path}`;
|
|
116
|
-
}
|
|
117
|
-
function confined(root, file) {
|
|
118
|
-
const path = relative(realpathSync(root), realpathSync(file));
|
|
119
|
-
if (path === '..' ||
|
|
120
|
-
path.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
|
|
121
|
-
isAbsolute(path)) {
|
|
122
|
-
throw new TypeError(`Declaration reference escapes package root: ${file}.`);
|
|
123
|
-
}
|
|
124
|
-
return file;
|
|
125
|
-
}
|
|
126
91
|
function apply(source, edits) {
|
|
127
92
|
let result = source;
|
|
128
93
|
for (const edit of [...edits].sort((left, right) => right.start - left.start)) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function resolveImportTarget(root: string, target: string): string;
|
|
2
|
+
export declare function resolveLocal(containing: string, specifier: string): string;
|
|
3
|
+
/** Point a local declaration reference at the emitted ESM module that owns it. */
|
|
4
|
+
export declare function runtimeSpecifier(containing: string, declaration: string): string;
|
|
5
|
+
export declare function confined(root: string, file: string): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
3
|
+
export function resolveImportTarget(root, target) {
|
|
4
|
+
return resolveLocal(join(root, 'entry.d.ts'), `./${target.slice('./dist/'.length)}`);
|
|
5
|
+
}
|
|
6
|
+
export function resolveLocal(containing, specifier) {
|
|
7
|
+
const base = resolve(dirname(containing), specifier);
|
|
8
|
+
const candidates = [
|
|
9
|
+
base.endsWith('.mjs') ? base.replace(/\.mjs$/u, '.d.mts') : '',
|
|
10
|
+
base.endsWith('.cjs') ? base.replace(/\.cjs$/u, '.d.cts') : '',
|
|
11
|
+
base.endsWith('.js') ? base.replace(/\.js$/u, '.d.ts') : '',
|
|
12
|
+
/\.d\.(?:ts|mts|cts)$/u.test(base) ? base : '',
|
|
13
|
+
`${base}.d.ts`,
|
|
14
|
+
join(base, 'index.d.ts'),
|
|
15
|
+
];
|
|
16
|
+
const file = candidates.find((candidate) => candidate && existsSync(candidate));
|
|
17
|
+
if (!file)
|
|
18
|
+
throw new TypeError(`Cannot resolve declaration reference ${specifier} from ${containing}.`);
|
|
19
|
+
return file;
|
|
20
|
+
}
|
|
21
|
+
/** Point a local declaration reference at the emitted ESM module that owns it. */
|
|
22
|
+
export function runtimeSpecifier(containing, declaration) {
|
|
23
|
+
const runtime = declaration
|
|
24
|
+
.replace(/\.d\.mts$/u, '.mjs')
|
|
25
|
+
.replace(/\.d\.cts$/u, '.cjs')
|
|
26
|
+
.replace(/\.d\.ts$/u, '.js');
|
|
27
|
+
const path = relative(dirname(containing), runtime).replaceAll('\\', '/');
|
|
28
|
+
return path.startsWith('./') || path.startsWith('../') ? path : `./${path}`;
|
|
29
|
+
}
|
|
30
|
+
export function confined(root, file) {
|
|
31
|
+
const path = relative(realpathSync(root), realpathSync(file));
|
|
32
|
+
if (path === '..' ||
|
|
33
|
+
path.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
|
|
34
|
+
isAbsolute(path)) {
|
|
35
|
+
throw new TypeError(`Declaration reference escapes package root: ${file}.`);
|
|
36
|
+
}
|
|
37
|
+
return file;
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PackageImports } from './declarations/imports.js';
|
|
2
|
+
export interface FinalizeDomainPackageInput {
|
|
3
|
+
readonly projectDir: string;
|
|
4
|
+
/** Additional emitted type-closure mappings supplied by the SDK compiler. */
|
|
5
|
+
readonly imports?: PackageImports;
|
|
6
|
+
}
|
|
7
|
+
export interface FinalizeDomainPackageResult {
|
|
8
|
+
readonly declarations: number;
|
|
9
|
+
readonly replacements: number;
|
|
10
|
+
readonly packages: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
/** Finalize already-compiled Schema, Runtime, and Application exports through one SDK boundary. */
|
|
13
|
+
export declare function finalizeDomainPackage(input: FinalizeDomainPackageInput): Promise<FinalizeDomainPackageResult>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { normalizeDeclarations, verifyDeclarationPackage } from './declarations/index.js';
|
|
4
|
+
import { verifyPublishedJavaScript } from './exports.js';
|
|
5
|
+
import { normalizeJavaScript, verifyContractJavaScript } from './javascript.js';
|
|
6
|
+
import { admitSelfPackage } from './self.js';
|
|
7
|
+
/** Finalize already-compiled Schema, Runtime, and Application exports through one SDK boundary. */
|
|
8
|
+
export async function finalizeDomainPackage(input) {
|
|
9
|
+
const projectDir = resolve(input.projectDir);
|
|
10
|
+
const root = resolve(projectDir, 'dist');
|
|
11
|
+
try {
|
|
12
|
+
const manifest = JSON.parse(readFileSync(resolve(projectDir, 'package.json'), 'utf8'));
|
|
13
|
+
const published = manifest.publishConfig ?? manifest;
|
|
14
|
+
const exports = published.exports ?? manifest.exports ?? {};
|
|
15
|
+
const targets = new Set();
|
|
16
|
+
const collect = (value, types = false) => {
|
|
17
|
+
if (typeof value === 'string') {
|
|
18
|
+
if (types)
|
|
19
|
+
targets.add(value);
|
|
20
|
+
}
|
|
21
|
+
else if (value !== null && typeof value === 'object') {
|
|
22
|
+
for (const [condition, nested] of Object.entries(value))
|
|
23
|
+
collect(nested, types || condition === 'types');
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
collect(published.types, true);
|
|
27
|
+
collect(exports);
|
|
28
|
+
if (targets.size === 0)
|
|
29
|
+
throw new TypeError('Published Domain package declares no type export.');
|
|
30
|
+
const entrypoints = [...targets].sort().map((target) => {
|
|
31
|
+
if (!target.startsWith('./dist/') || !/\.d\.(?:ts|mts|cts)$/u.test(target)) {
|
|
32
|
+
throw new TypeError(`Published Domain type export must target a declaration under ./dist: ${target}.`);
|
|
33
|
+
}
|
|
34
|
+
return target.slice('./dist/'.length);
|
|
35
|
+
});
|
|
36
|
+
const imports = { ...manifest.publishConfig?.imports, ...input.imports };
|
|
37
|
+
const self = admitSelfPackage(manifest.name, Object.keys(exports).filter((key) => key !== './package.json'));
|
|
38
|
+
verifyPublishedJavaScript(projectDir, manifest);
|
|
39
|
+
const javascriptReplacements = normalizeJavaScript(root, imports);
|
|
40
|
+
const javascriptPackages = verifyContractJavaScript(root, self);
|
|
41
|
+
const normalized = await normalizeDeclarations({ root, entrypoints, imports });
|
|
42
|
+
const verified = await verifyDeclarationPackage({ root, packageRoot: projectDir, entrypoints });
|
|
43
|
+
const packages = [...new Set([...javascriptPackages, ...verified.packages])].sort();
|
|
44
|
+
const declared = new Set([
|
|
45
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
46
|
+
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
47
|
+
...Object.keys(manifest.peerDependencies ?? {}),
|
|
48
|
+
]);
|
|
49
|
+
const missing = packages.filter((name) => !declared.has(name));
|
|
50
|
+
if (missing.length > 0)
|
|
51
|
+
throw new TypeError(`Published Domain contract references undeclared packages: ${missing.join(', ')}.`);
|
|
52
|
+
return Object.freeze({
|
|
53
|
+
declarations: verified.files.length,
|
|
54
|
+
replacements: javascriptReplacements + normalized.replacements,
|
|
55
|
+
packages: Object.freeze(packages),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (cause) {
|
|
59
|
+
rmSync(root, { recursive: true, force: true });
|
|
60
|
+
throw cause;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export type { PackageDomainInput, PackageDomainResult } from './packaging.js';
|
|
2
2
|
export { packageDomain } from './packaging.js';
|
|
3
|
+
export type { FinalizeDomainPackageInput, FinalizeDomainPackageResult } from './finalize.js';
|
|
4
|
+
export { finalizeDomainPackage } from './finalize.js';
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type PackageImports } from './declarations/imports.js';
|
|
1
2
|
import { type SelfPackage } from './self.js';
|
|
2
3
|
/** Verify emitted Schema JavaScript and return its complete external package set. */
|
|
3
4
|
export declare function verifyContractJavaScript(root: string, self?: SelfPackage): readonly string[];
|
|
5
|
+
/** Normalize local runtime imports with the same package mappings as declarations. */
|
|
6
|
+
export declare function normalizeJavaScript(root: string, imports: PackageImports): number;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
1
|
+
import { readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { extname, join } from 'node:path';
|
|
3
3
|
import ts from 'typescript';
|
|
4
|
+
import { admitPackageImports, resolvePackageImport, } from './declarations/imports.js';
|
|
5
|
+
import { confined, resolveImportTarget, resolveLocal, runtimeSpecifier, } from './declarations/paths.js';
|
|
4
6
|
import { isSelfPackageReference, packageName } from './self.js';
|
|
5
7
|
/** Verify emitted Schema JavaScript and return its complete external package set. */
|
|
6
8
|
export function verifyContractJavaScript(root, self) {
|
|
@@ -69,3 +71,44 @@ function moduleSpecifier(node) {
|
|
|
69
71
|
? argument.text
|
|
70
72
|
: undefined;
|
|
71
73
|
}
|
|
74
|
+
/** Normalize local runtime imports with the same package mappings as declarations. */
|
|
75
|
+
export function normalizeJavaScript(root, imports) {
|
|
76
|
+
const mappings = admitPackageImports(imports);
|
|
77
|
+
const output = new Map();
|
|
78
|
+
let replacements = 0;
|
|
79
|
+
for (const file of javascriptFiles(root)) {
|
|
80
|
+
const source = readFileSync(file, 'utf8');
|
|
81
|
+
const document = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true);
|
|
82
|
+
const edits = [];
|
|
83
|
+
const visit = (node) => {
|
|
84
|
+
const specifier = moduleSpecifier(node);
|
|
85
|
+
if (specifier !== undefined &&
|
|
86
|
+
(specifier.startsWith('#') || (specifier.startsWith('.') && extname(specifier) === ''))) {
|
|
87
|
+
const target = specifier.startsWith('#')
|
|
88
|
+
? resolveImportTarget(root, resolvePackageImport(specifier, mappings))
|
|
89
|
+
: resolveLocal(file, specifier);
|
|
90
|
+
confined(root, target);
|
|
91
|
+
const literal = ts.isImportDeclaration(node) || ts.isExportDeclaration(node)
|
|
92
|
+
? node.moduleSpecifier
|
|
93
|
+
: node.arguments[0];
|
|
94
|
+
edits.push({
|
|
95
|
+
start: literal.getStart(document) + 1,
|
|
96
|
+
end: literal.getEnd() - 1,
|
|
97
|
+
replacement: runtimeSpecifier(file, target),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
ts.forEachChild(node, visit);
|
|
101
|
+
};
|
|
102
|
+
visit(document);
|
|
103
|
+
let normalized = source;
|
|
104
|
+
for (const edit of edits.sort((left, right) => right.start - left.start)) {
|
|
105
|
+
normalized = `${normalized.slice(0, edit.start)}${edit.replacement}${normalized.slice(edit.end)}`;
|
|
106
|
+
}
|
|
107
|
+
if (edits.length > 0)
|
|
108
|
+
output.set(file, normalized);
|
|
109
|
+
replacements += edits.length;
|
|
110
|
+
}
|
|
111
|
+
for (const [file, source] of output)
|
|
112
|
+
writeFileSync(file, source);
|
|
113
|
+
return replacements;
|
|
114
|
+
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import { type FinalizeDomainPackageResult } from './finalize.js';
|
|
1
2
|
export interface PackageDomainInput {
|
|
2
3
|
readonly projectDir: string;
|
|
3
4
|
}
|
|
4
|
-
export
|
|
5
|
-
readonly declarations: number;
|
|
6
|
-
readonly replacements: number;
|
|
7
|
-
readonly packages: readonly string[];
|
|
8
|
-
}
|
|
5
|
+
export type PackageDomainResult = FinalizeDomainPackageResult;
|
|
9
6
|
/** Compile, normalize, and verify every public Schema contract in one Domain package. */
|
|
10
7
|
export declare function packageDomain(input: PackageDomainInput): Promise<PackageDomainResult>;
|
|
@@ -3,10 +3,7 @@ import { rm } from 'node:fs/promises';
|
|
|
3
3
|
import { posix, resolve } from 'node:path';
|
|
4
4
|
import { admitDomainPackage } from './admission.js';
|
|
5
5
|
import { compileDomainPackage } from './compile.js';
|
|
6
|
-
import {
|
|
7
|
-
import { verifyPublishedJavaScript } from './exports.js';
|
|
8
|
-
import { verifyContractJavaScript } from './javascript.js';
|
|
9
|
-
import { admitSelfPackage } from './self.js';
|
|
6
|
+
import { finalizeDomainPackage } from './finalize.js';
|
|
10
7
|
/** Compile, normalize, and verify every public Schema contract in one Domain package. */
|
|
11
8
|
export async function packageDomain(input) {
|
|
12
9
|
const projectDir = resolve(input.projectDir);
|
|
@@ -16,29 +13,13 @@ export async function packageDomain(input) {
|
|
|
16
13
|
const manifest = JSON.parse(await readFile(resolve(projectDir, 'package.json'), 'utf8'));
|
|
17
14
|
admitDomainPackage(projectDir, manifest);
|
|
18
15
|
const contracts = admitContractManifest(manifest);
|
|
19
|
-
const self = admitSelfPackage(manifest.name, contracts.map(({ subpath }) => subpath));
|
|
20
16
|
const { typeClosure } = compileDomainPackage(projectDir, contracts.map(({ source }) => source));
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
verifyPublishedJavaScript(projectDir, manifest);
|
|
24
|
-
const javascriptPackages = verifyContractJavaScript(root, self);
|
|
25
|
-
const normalized = await normalizeDeclarations({
|
|
26
|
-
root,
|
|
17
|
+
const result = await finalizeDomainPackage({
|
|
18
|
+
projectDir,
|
|
27
19
|
imports: declarationImports(manifest, typeClosure),
|
|
28
|
-
entrypoints: declarationEntrypoints,
|
|
29
|
-
});
|
|
30
|
-
const verified = await verifyDeclarationPackage({
|
|
31
|
-
root,
|
|
32
|
-
packageRoot: projectDir,
|
|
33
|
-
entrypoints: declarationEntrypoints,
|
|
34
|
-
});
|
|
35
|
-
const packages = Object.freeze([...new Set([...javascriptPackages, ...verified.packages])].sort());
|
|
36
|
-
verifyDependencies(manifest, packages);
|
|
37
|
-
return Object.freeze({
|
|
38
|
-
declarations: verified.files.length,
|
|
39
|
-
replacements: normalized.replacements,
|
|
40
|
-
packages,
|
|
41
20
|
});
|
|
21
|
+
verifyUsedDependencies(manifest, result.packages);
|
|
22
|
+
return result;
|
|
42
23
|
}
|
|
43
24
|
catch (cause) {
|
|
44
25
|
await rm(root, { recursive: true, force: true });
|
|
@@ -98,7 +79,6 @@ function admitContractManifest(manifest) {
|
|
|
98
79
|
return Object.freeze({
|
|
99
80
|
subpath,
|
|
100
81
|
source: source.types.slice(2),
|
|
101
|
-
declaration: expected.types.slice('./dist/'.length),
|
|
102
82
|
});
|
|
103
83
|
});
|
|
104
84
|
if (new Set(contracts.map(({ source }) => source)).size !== contracts.length) {
|
|
@@ -177,17 +157,13 @@ function publishedTargets(source) {
|
|
|
177
157
|
import: `./dist/${stem}.js`,
|
|
178
158
|
});
|
|
179
159
|
}
|
|
180
|
-
function
|
|
160
|
+
function verifyUsedDependencies(manifest, packages) {
|
|
181
161
|
const declared = new Set([
|
|
182
162
|
...Object.keys(manifest.dependencies ?? {}),
|
|
183
163
|
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
184
164
|
...Object.keys(manifest.peerDependencies ?? {}),
|
|
185
165
|
]);
|
|
186
166
|
const used = new Set(packages);
|
|
187
|
-
const missing = packages.filter((name) => !declared.has(name));
|
|
188
|
-
if (missing.length > 0) {
|
|
189
|
-
throw new TypeError(`Published Domain contract references undeclared packages: ${missing.join(', ')}.`);
|
|
190
|
-
}
|
|
191
167
|
const unused = [...declared].filter((name) => !used.has(name)).sort();
|
|
192
168
|
if (unused.length > 0) {
|
|
193
169
|
throw new TypeError(`Domain contract declares unused production packages: ${unused.join(', ')}.`);
|