@ankhorage/zora 26.1.6 → 27.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -13
- package/dist/capabilities/index.d.ts.map +1 -1
- package/dist/capabilities/index.js +2 -63
- package/dist/capabilities/index.js.map +3 -3
- package/package.json +4 -102
- package/src/capabilities/index.test.ts +4 -7
- package/src/capabilities/index.ts +1 -62
- package/src/invertedThemeAcceptance.test.tsx +1 -1
- package/src/packedWebConsumerAcceptance.test.ts +20 -0
- package/src/structureOwnership.test.ts +1 -1
- package/src/webPackageExports.test.ts +1 -0
- package/dist/cli/commands/create.d.ts +0 -14
- package/dist/cli/commands/create.d.ts.map +0 -1
- package/dist/cli/commands/create.js +0 -22
- package/dist/cli/commands/create.js.map +0 -1
- package/dist/cli/commands/sync.d.ts +0 -14
- package/dist/cli/commands/sync.d.ts.map +0 -1
- package/dist/cli/commands/sync.js +0 -18
- package/dist/cli/commands/sync.js.map +0 -1
- package/dist/cli/index.d.ts +0 -27
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -44
- package/dist/cli/index.js.map +0 -1
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.d.ts +0 -4
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.d.ts.map +0 -1
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.js +0 -88
- package/dist/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.js.map +0 -1
- package/dist/features/web-component-artifact/adapters/outbound/node/readWebDesiredStateWithNodeAsync.d.ts +0 -5
- package/dist/features/web-component-artifact/adapters/outbound/node/readWebDesiredStateWithNodeAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/adapters/outbound/node/readWebDesiredStateWithNodeAsync.js +0 -24
- package/dist/features/web-component-artifact/adapters/outbound/node/readWebDesiredStateWithNodeAsync.js.map +0 -1
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.d.ts +0 -10
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.d.ts.map +0 -1
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.js +0 -2
- package/dist/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.js.map +0 -1
- package/dist/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.d.ts +0 -15
- package/dist/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.js +0 -76
- package/dist/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.js.map +0 -1
- package/dist/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.d.ts +0 -6
- package/dist/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.js +0 -61
- package/dist/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.js.map +0 -1
- package/dist/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.d.ts +0 -8
- package/dist/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.js +0 -10
- package/dist/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.js.map +0 -1
- package/dist/features/web-component-artifact/composition/synchronizeDeclaredWebComponentsWithNodeAsync.d.ts +0 -3
- package/dist/features/web-component-artifact/composition/synchronizeDeclaredWebComponentsWithNodeAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/composition/synchronizeDeclaredWebComponentsWithNodeAsync.js +0 -16
- package/dist/features/web-component-artifact/composition/synchronizeDeclaredWebComponentsWithNodeAsync.js.map +0 -1
- package/dist/features/web-component-artifact/composition/synchronizeWebComponentArtifactsWithNodeAsync.d.ts +0 -4
- package/dist/features/web-component-artifact/composition/synchronizeWebComponentArtifactsWithNodeAsync.d.ts.map +0 -1
- package/dist/features/web-component-artifact/composition/synchronizeWebComponentArtifactsWithNodeAsync.js +0 -7
- package/dist/features/web-component-artifact/composition/synchronizeWebComponentArtifactsWithNodeAsync.js.map +0 -1
- package/src/cli/commands/create.ts +0 -37
- package/src/cli/commands/sync.ts +0 -35
- package/src/cli/index.test.ts +0 -35
- package/src/cli/index.ts +0 -57
- package/src/features/web-component-artifact/adapters/outbound/node/createNodeWebComponentArtifactFileSystem.ts +0 -109
- package/src/features/web-component-artifact/adapters/outbound/node/readWebDesiredStateWithNodeAsync.ts +0 -29
- package/src/features/web-component-artifact/application/ports/outbound/WebComponentArtifactFileSystemPort.ts +0 -9
- package/src/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.test.ts +0 -128
- package/src/features/web-component-artifact/application/use-cases/synchronizeWebComponentArtifactsAsync.ts +0 -133
- package/src/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.ts +0 -60
- package/src/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.ts +0 -18
- package/src/features/web-component-artifact/composition/synchronizeDeclaredWebComponentsWithNodeAsync.ts +0 -17
- package/src/features/web-component-artifact/composition/synchronizeWebComponentArtifactsWithNodeAsync.ts +0 -16
- package/src/webArtifactRuntime.test.ts +0 -14
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { mkdir, mkdtemp, readdir, readFile, readlink, rm, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { tmpdir } from 'node:os';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
import { expect, test } from 'bun:test';
|
|
6
|
-
|
|
7
|
-
import { createNodeWebComponentArtifactFileSystem } from '../../adapters/outbound/node/createNodeWebComponentArtifactFileSystem';
|
|
8
|
-
import { synchronizeWebComponentArtifactsAsync } from './synchronizeWebComponentArtifactsAsync';
|
|
9
|
-
|
|
10
|
-
test('syncs one shared provider graph, prunes removed components, and preserves output on failure', async () => {
|
|
11
|
-
const sandbox = await mkdtemp(join(tmpdir(), 'zora-web-sync-'));
|
|
12
|
-
const packageRoot = join(sandbox, 'owner');
|
|
13
|
-
const outputDirectory = join(sandbox, 'project', '.ankh', 'zora', 'web');
|
|
14
|
-
const entries = {
|
|
15
|
-
'runtime/ZoraProvider.js': "export { runtime } from '../chunks/shared.js';\n",
|
|
16
|
-
'runtime/ZoraProvider.d.ts': 'export declare const ZoraProvider: unknown;\n',
|
|
17
|
-
'components/select/Select.js': "export { select } from '../../chunks/shared.js';\n",
|
|
18
|
-
'components/select/Select.d.ts': 'export declare const Select: unknown;\n',
|
|
19
|
-
'components/button/Button.js': "export { button } from '../../chunks/shared.js';\n",
|
|
20
|
-
'components/button/Button.d.ts': 'export declare const Button: unknown;\n',
|
|
21
|
-
'chunks/shared.js': 'export const runtime = 1, select = 2, button = 3;\n',
|
|
22
|
-
} as const;
|
|
23
|
-
try {
|
|
24
|
-
await Promise.all(
|
|
25
|
-
Object.entries(entries).map(async ([file, source]) => {
|
|
26
|
-
const path = join(packageRoot, 'web-dist', file);
|
|
27
|
-
await mkdir(dirname(path), { recursive: true });
|
|
28
|
-
await writeFile(path, source);
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
31
|
-
await writeFile(
|
|
32
|
-
join(packageRoot, 'web-dist', 'manifest.json'),
|
|
33
|
-
JSON.stringify({
|
|
34
|
-
schemaVersion: 2,
|
|
35
|
-
runtime: {
|
|
36
|
-
entry: 'runtime/ZoraProvider.js',
|
|
37
|
-
files: ['runtime/ZoraProvider.js', 'runtime/ZoraProvider.d.ts', 'chunks/shared.js'],
|
|
38
|
-
},
|
|
39
|
-
artifacts: [
|
|
40
|
-
{
|
|
41
|
-
component: 'select',
|
|
42
|
-
files: [
|
|
43
|
-
'components/select/Select.js',
|
|
44
|
-
'components/select/Select.d.ts',
|
|
45
|
-
'chunks/shared.js',
|
|
46
|
-
],
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
component: 'button',
|
|
50
|
-
files: [
|
|
51
|
-
'components/button/Button.js',
|
|
52
|
-
'components/button/Button.d.ts',
|
|
53
|
-
'chunks/shared.js',
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
59
|
-
const fileSystem = createNodeWebComponentArtifactFileSystem();
|
|
60
|
-
const base = { outputDirectory, packageRoot, packageVersion: '1.2.3' };
|
|
61
|
-
const first = await synchronizeWebComponentArtifactsAsync(
|
|
62
|
-
{ ...base, components: ['select', 'button'] },
|
|
63
|
-
fileSystem,
|
|
64
|
-
);
|
|
65
|
-
const evidence = JSON.parse(
|
|
66
|
-
await readFile(join(outputDirectory, 'materialization.json'), 'utf8'),
|
|
67
|
-
) as { readonly components: readonly string[]; readonly files: readonly string[] };
|
|
68
|
-
expect(evidence.components).toEqual(['button', 'select']);
|
|
69
|
-
expect(evidence.files.filter((file) => file === 'chunks/shared.js')).toHaveLength(1);
|
|
70
|
-
expect(first.files).toEqual(evidence.files);
|
|
71
|
-
|
|
72
|
-
const firstGeneration = await readlink(outputDirectory);
|
|
73
|
-
const second = await synchronizeWebComponentArtifactsAsync(
|
|
74
|
-
{ ...base, components: ['button'] },
|
|
75
|
-
fileSystem,
|
|
76
|
-
);
|
|
77
|
-
expect(second.files).not.toContain('components/select/Select.js');
|
|
78
|
-
expect(await readlink(outputDirectory)).not.toBe(firstGeneration);
|
|
79
|
-
expect(await readdir(join(outputDirectory, 'components'))).toEqual(['button']);
|
|
80
|
-
expect(await readdir(dirname(outputDirectory))).toHaveLength(2);
|
|
81
|
-
|
|
82
|
-
await synchronizeWebComponentArtifactsAsync(
|
|
83
|
-
{ ...base, packageVersion: '1.2.4', components: ['button'] },
|
|
84
|
-
fileSystem,
|
|
85
|
-
);
|
|
86
|
-
expect(await readFile(join(outputDirectory, 'runtime/ZoraProvider.js'), 'utf8')).toContain(
|
|
87
|
-
'Generated by @ankhorage/zora v1.2.4',
|
|
88
|
-
);
|
|
89
|
-
expect(await readFile(join(outputDirectory, 'components/button/Button.js'), 'utf8')).toContain(
|
|
90
|
-
'Generated by @ankhorage/zora v1.2.4',
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
await rm(join(packageRoot, 'web-dist', 'components/button/Button.js'));
|
|
94
|
-
const validGeneration = await readlink(outputDirectory);
|
|
95
|
-
const failed = await synchronizeWebComponentArtifactsAsync(
|
|
96
|
-
{ ...base, components: ['button'] },
|
|
97
|
-
fileSystem,
|
|
98
|
-
).then(
|
|
99
|
-
() => false,
|
|
100
|
-
() => true,
|
|
101
|
-
);
|
|
102
|
-
expect(failed).toBe(true);
|
|
103
|
-
expect(await readlink(outputDirectory)).toBe(validGeneration);
|
|
104
|
-
expect(await readFile(join(outputDirectory, 'components/button/Button.js'), 'utf8')).toContain(
|
|
105
|
-
'Generated by @ankhorage/zora v1.2.4',
|
|
106
|
-
);
|
|
107
|
-
} finally {
|
|
108
|
-
await rm(sandbox, { force: true, recursive: true });
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
test('swaps Windows-style junction generations without leaving stale output', async () => {
|
|
113
|
-
const sandbox = await mkdtemp(join(tmpdir(), 'zora-web-windows-swap-'));
|
|
114
|
-
const outputDirectory = join(sandbox, 'web');
|
|
115
|
-
const fileSystem = createNodeWebComponentArtifactFileSystem('win32');
|
|
116
|
-
try {
|
|
117
|
-
const first = await fileSystem.createStageDirectoryAsync(outputDirectory);
|
|
118
|
-
await writeFile(join(first, 'version.txt'), 'first');
|
|
119
|
-
await fileSystem.commitStageDirectoryAsync(first, outputDirectory);
|
|
120
|
-
const second = await fileSystem.createStageDirectoryAsync(outputDirectory);
|
|
121
|
-
await writeFile(join(second, 'version.txt'), 'second');
|
|
122
|
-
await fileSystem.commitStageDirectoryAsync(second, outputDirectory);
|
|
123
|
-
expect(await readFile(join(outputDirectory, 'version.txt'), 'utf8')).toBe('second');
|
|
124
|
-
expect(await readdir(sandbox)).toHaveLength(2);
|
|
125
|
-
} finally {
|
|
126
|
-
await rm(sandbox, { force: true, recursive: true });
|
|
127
|
-
}
|
|
128
|
-
});
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { isRecord } from '@ankhorage/utility/object';
|
|
2
|
-
|
|
3
|
-
import type { WebComponentArtifactFileSystemPort } from '../ports/outbound/WebComponentArtifactFileSystemPort';
|
|
4
|
-
|
|
5
|
-
export interface SynchronizeWebComponentArtifactsInput {
|
|
6
|
-
readonly components: readonly string[];
|
|
7
|
-
readonly outputDirectory: string;
|
|
8
|
-
readonly packageRoot: string;
|
|
9
|
-
readonly packageVersion: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface SynchronizeWebComponentArtifactsResult {
|
|
13
|
-
readonly components: readonly string[];
|
|
14
|
-
readonly files: readonly string[];
|
|
15
|
-
readonly outputDirectory: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface ArtifactDefinition {
|
|
19
|
-
readonly component: string;
|
|
20
|
-
readonly files: readonly string[];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface WebArtifactCatalog {
|
|
24
|
-
readonly runtime: { readonly files: readonly string[] };
|
|
25
|
-
readonly artifacts: readonly ArtifactDefinition[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/*** Reconcile one desired web set from a single published ZORA generation. */
|
|
29
|
-
export async function synchronizeWebComponentArtifactsAsync(
|
|
30
|
-
input: SynchronizeWebComponentArtifactsInput,
|
|
31
|
-
fileSystem: WebComponentArtifactFileSystemPort,
|
|
32
|
-
): Promise<SynchronizeWebComponentArtifactsResult> {
|
|
33
|
-
const catalog = await readArtifactCatalogAsync(input.packageRoot, fileSystem);
|
|
34
|
-
const components = [...new Set(input.components)].sort();
|
|
35
|
-
const selected = components.map((component) => {
|
|
36
|
-
const artifact = catalog.artifacts.find((candidate) => candidate.component === component);
|
|
37
|
-
if (artifact === undefined) throw new Error(`Unsupported ZORA web component: ${component}`);
|
|
38
|
-
return artifact;
|
|
39
|
-
});
|
|
40
|
-
const files = [
|
|
41
|
-
...new Set([...catalog.runtime.files, ...selected.flatMap(({ files }) => files)]),
|
|
42
|
-
].sort();
|
|
43
|
-
const stage = await fileSystem.createStageDirectoryAsync(input.outputDirectory);
|
|
44
|
-
try {
|
|
45
|
-
await Promise.all(
|
|
46
|
-
files.map(async (file) => {
|
|
47
|
-
const source = await fileSystem.readTextFileAsync(
|
|
48
|
-
fileSystem.joinPath(input.packageRoot, 'web-dist', file),
|
|
49
|
-
);
|
|
50
|
-
const destination = fileSystem.joinPath(stage, file);
|
|
51
|
-
await fileSystem.ensureDirectoryAsync(fileSystem.joinPath(stage, parentDirectory(file)));
|
|
52
|
-
await fileSystem.writeTextFileAsync(
|
|
53
|
-
destination,
|
|
54
|
-
`// Generated by @ankhorage/zora v${input.packageVersion}. Do not edit manually.\n${source}`,
|
|
55
|
-
);
|
|
56
|
-
}),
|
|
57
|
-
);
|
|
58
|
-
await fileSystem.writeTextFileAsync(
|
|
59
|
-
fileSystem.joinPath(stage, 'materialization.json'),
|
|
60
|
-
`${JSON.stringify(
|
|
61
|
-
{
|
|
62
|
-
schemaVersion: 1,
|
|
63
|
-
owner: '@ankhorage/zora',
|
|
64
|
-
ownerVersion: input.packageVersion,
|
|
65
|
-
platform: 'web',
|
|
66
|
-
components,
|
|
67
|
-
files: [...files, 'materialization.json'].sort(),
|
|
68
|
-
},
|
|
69
|
-
null,
|
|
70
|
-
2,
|
|
71
|
-
)}\n`,
|
|
72
|
-
);
|
|
73
|
-
await fileSystem.commitStageDirectoryAsync(stage, input.outputDirectory);
|
|
74
|
-
} catch (error) {
|
|
75
|
-
await fileSystem.removeStageDirectoryAsync(stage);
|
|
76
|
-
throw error;
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
components,
|
|
80
|
-
files: [...files, 'materialization.json'].sort(),
|
|
81
|
-
outputDirectory: input.outputDirectory,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/*** Read and validate the packaged catalog before changing consumer output. */
|
|
86
|
-
async function readArtifactCatalogAsync(
|
|
87
|
-
packageRoot: string,
|
|
88
|
-
fileSystem: WebComponentArtifactFileSystemPort,
|
|
89
|
-
): Promise<WebArtifactCatalog> {
|
|
90
|
-
const source = await fileSystem.readTextFileAsync(
|
|
91
|
-
fileSystem.joinPath(packageRoot, 'web-dist', 'manifest.json'),
|
|
92
|
-
);
|
|
93
|
-
const parsed: unknown = JSON.parse(source);
|
|
94
|
-
if (
|
|
95
|
-
!isRecord(parsed) ||
|
|
96
|
-
parsed.schemaVersion !== 2 ||
|
|
97
|
-
!isRecord(parsed.runtime) ||
|
|
98
|
-
!isFileList(parsed.runtime.files) ||
|
|
99
|
-
!Array.isArray(parsed.artifacts)
|
|
100
|
-
) {
|
|
101
|
-
throw new Error('Invalid ZORA web artifact manifest.');
|
|
102
|
-
}
|
|
103
|
-
const artifacts = parsed.artifacts.map((artifact: unknown) => {
|
|
104
|
-
if (
|
|
105
|
-
!isRecord(artifact) ||
|
|
106
|
-
typeof artifact.component !== 'string' ||
|
|
107
|
-
!isFileList(artifact.files)
|
|
108
|
-
) {
|
|
109
|
-
throw new Error('Invalid ZORA web artifact manifest entry.');
|
|
110
|
-
}
|
|
111
|
-
return { component: artifact.component, files: artifact.files };
|
|
112
|
-
});
|
|
113
|
-
return { runtime: { files: parsed.runtime.files }, artifacts };
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/*** Accept only known, relative generated file paths. */
|
|
117
|
-
function isFileList(value: unknown): value is readonly string[] {
|
|
118
|
-
return (
|
|
119
|
-
Array.isArray(value) &&
|
|
120
|
-
value.length > 0 &&
|
|
121
|
-
value.every(
|
|
122
|
-
(entry) =>
|
|
123
|
-
typeof entry === 'string' &&
|
|
124
|
-
/^(?:runtime|components|chunks|assets)\/[A-Za-z0-9_./-]+$/u.test(entry) &&
|
|
125
|
-
!entry.split('/').includes('..'),
|
|
126
|
-
)
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/*** Resolve the parent path inside the generated directory. */
|
|
131
|
-
function parentDirectory(file: string): string {
|
|
132
|
-
return file.slice(0, file.lastIndexOf('/'));
|
|
133
|
-
}
|
package/src/features/web-component-artifact/composition/createWebDesiredStateWithNodeAsync.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { dirname, join, resolve } from 'node:path';
|
|
4
|
-
|
|
5
|
-
import { readWebDesiredStateWithNodeAsync } from '../adapters/outbound/node/readWebDesiredStateWithNodeAsync';
|
|
6
|
-
import { readWebComponentPackageMetadataAsync } from './readWebComponentPackageMetadataAsync';
|
|
7
|
-
import { synchronizeWebComponentArtifactsWithNodeAsync } from './synchronizeWebComponentArtifactsWithNodeAsync';
|
|
8
|
-
|
|
9
|
-
/*** Add one requested web component and regenerate the complete declared set. */
|
|
10
|
-
export async function createWebDesiredStateWithNodeAsync(input: {
|
|
11
|
-
readonly component: string;
|
|
12
|
-
readonly projectRoot: string;
|
|
13
|
-
}) {
|
|
14
|
-
const desired = await readWebDesiredStateWithNodeAsync(input.projectRoot, true);
|
|
15
|
-
const components = [...new Set([...desired.components, input.component])].sort();
|
|
16
|
-
const { packageRoot, packageVersion } = await readWebComponentPackageMetadataAsync();
|
|
17
|
-
const desiredPath = resolve(input.projectRoot, 'zora.web.json');
|
|
18
|
-
const previous = await readFile(desiredPath, 'utf8').catch((error: unknown) => {
|
|
19
|
-
if (isMissingFile(error)) return undefined;
|
|
20
|
-
throw error;
|
|
21
|
-
});
|
|
22
|
-
const next = `${JSON.stringify({ schemaVersion: 1, components }, null, 2)}\n`;
|
|
23
|
-
if (next !== previous) await replaceDesiredStateAsync(desiredPath, next);
|
|
24
|
-
try {
|
|
25
|
-
return await synchronizeWebComponentArtifactsWithNodeAsync({
|
|
26
|
-
components,
|
|
27
|
-
outputDirectory: resolve(input.projectRoot, '.ankh', 'zora', 'web'),
|
|
28
|
-
packageRoot,
|
|
29
|
-
packageVersion,
|
|
30
|
-
});
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (next !== previous) {
|
|
33
|
-
try {
|
|
34
|
-
if (previous === undefined) await rm(desiredPath);
|
|
35
|
-
else await replaceDesiredStateAsync(desiredPath, previous);
|
|
36
|
-
} catch (rollbackError) {
|
|
37
|
-
throw new AggregateError([error, rollbackError], 'ZORA create and rollback failed.', {
|
|
38
|
-
cause: rollbackError,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/*** Replace the authoritative project declaration only after its complete contents are staged. */
|
|
47
|
-
async function replaceDesiredStateAsync(path: string, content: string): Promise<void> {
|
|
48
|
-
const temporaryPath = join(dirname(path), `.zora-web-${randomUUID()}.tmp`);
|
|
49
|
-
try {
|
|
50
|
-
await writeFile(temporaryPath, content, 'utf8');
|
|
51
|
-
await rename(temporaryPath, path);
|
|
52
|
-
} finally {
|
|
53
|
-
await rm(temporaryPath, { force: true });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/*** Recognize only absent desired state, not unrelated filesystem failures. */
|
|
58
|
-
function isMissingFile(error: unknown): boolean {
|
|
59
|
-
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
60
|
-
}
|
package/src/features/web-component-artifact/composition/readWebComponentPackageMetadataAsync.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { dirname, resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
/*** Reads the active ZORA package location and version for generated web artifacts. */
|
|
6
|
-
export async function readWebComponentPackageMetadataAsync(): Promise<WebComponentPackageMetadata> {
|
|
7
|
-
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..');
|
|
8
|
-
const packageJson = JSON.parse(await readFile(resolve(packageRoot, 'package.json'), 'utf8')) as {
|
|
9
|
-
readonly version: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
return { packageRoot, packageVersion: packageJson.version };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface WebComponentPackageMetadata {
|
|
16
|
-
readonly packageRoot: string;
|
|
17
|
-
readonly packageVersion: string;
|
|
18
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
|
|
3
|
-
import { readWebDesiredStateWithNodeAsync } from '../adapters/outbound/node/readWebDesiredStateWithNodeAsync';
|
|
4
|
-
import { readWebComponentPackageMetadataAsync } from './readWebComponentPackageMetadataAsync';
|
|
5
|
-
import { synchronizeWebComponentArtifactsWithNodeAsync } from './synchronizeWebComponentArtifactsWithNodeAsync';
|
|
6
|
-
|
|
7
|
-
/*** Load project desired state and sync it from the active ZORA package release. */
|
|
8
|
-
export async function synchronizeDeclaredWebComponentsWithNodeAsync(projectRoot: string) {
|
|
9
|
-
const desired = await readWebDesiredStateWithNodeAsync(projectRoot, false);
|
|
10
|
-
const { packageRoot, packageVersion } = await readWebComponentPackageMetadataAsync();
|
|
11
|
-
return await synchronizeWebComponentArtifactsWithNodeAsync({
|
|
12
|
-
components: desired.components,
|
|
13
|
-
outputDirectory: resolve(projectRoot, '.ankh', 'zora', 'web'),
|
|
14
|
-
packageRoot,
|
|
15
|
-
packageVersion,
|
|
16
|
-
});
|
|
17
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { createNodeWebComponentArtifactFileSystem } from '../adapters/outbound/node/createNodeWebComponentArtifactFileSystem';
|
|
2
|
-
import {
|
|
3
|
-
synchronizeWebComponentArtifactsAsync,
|
|
4
|
-
type SynchronizeWebComponentArtifactsInput,
|
|
5
|
-
type SynchronizeWebComponentArtifactsResult,
|
|
6
|
-
} from '../application/use-cases/synchronizeWebComponentArtifactsAsync';
|
|
7
|
-
|
|
8
|
-
/*** Wire Node filesystem operations into shared ZORA web reconciliation. */
|
|
9
|
-
export async function synchronizeWebComponentArtifactsWithNodeAsync(
|
|
10
|
-
input: SynchronizeWebComponentArtifactsInput,
|
|
11
|
-
): Promise<SynchronizeWebComponentArtifactsResult> {
|
|
12
|
-
return await synchronizeWebComponentArtifactsAsync(
|
|
13
|
-
input,
|
|
14
|
-
createNodeWebComponentArtifactFileSystem(),
|
|
15
|
-
);
|
|
16
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { expect, test } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
test('materialized components share the generated provider through SSR and interaction', () => {
|
|
4
|
-
const subprocess = Bun.spawnSync({
|
|
5
|
-
cmd: [process.execPath, 'scripts/web-artifacts/verifyWebMaterialization.ts'],
|
|
6
|
-
stderr: 'pipe',
|
|
7
|
-
stdout: 'pipe',
|
|
8
|
-
});
|
|
9
|
-
const output = `${subprocess.stdout.toString()}\n${subprocess.stderr.toString()}`;
|
|
10
|
-
expect(subprocess.exitCode, output).toBe(0);
|
|
11
|
-
expect(output).toContain(
|
|
12
|
-
'Materialized ZORA provider, SSR hydration, and Select interaction passed.',
|
|
13
|
-
);
|
|
14
|
-
});
|