@forgeax/engine-pack 0.1.28 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/dist/build.mjs +34 -51
- package/dist/build.mjs.map +1 -1
- package/dist/cli-asset.mjs +21 -12
- package/dist/cli-asset.mjs.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/inventory/declaration.d.ts +1 -1
- package/dist/inventory/declaration.d.ts.map +1 -1
- package/dist/inventory/sync.d.ts.map +1 -1
- package/dist/native-cooker-registry.d.ts +1 -0
- package/dist/native-cooker-registry.d.ts.map +1 -1
- package/dist/native-cooker.mjs.map +1 -1
- package/dist/pack-authoring-node.mjs +21 -12
- package/dist/pack-authoring-node.mjs.map +1 -1
- package/dist/runtime.mjs.map +1 -1
- package/dist/scanner.mjs +21 -12
- package/dist/scanner.mjs.map +1 -1
- package/dist/schema-compiled.d.ts.map +1 -1
- package/dist/schema.mjs +40 -62
- package/dist/schema.mjs.map +1 -1
- package/dist/scriptable-pack-node.d.ts.map +1 -1
- package/dist/scriptable-pack-node.mjs +11 -3
- package/dist/scriptable-pack-node.mjs.map +1 -1
- package/dist/scriptable-pack-worker.mjs +5 -1
- package/dist/scriptable-pack-worker.mjs.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/inventory-schema.test.ts +10 -10
- package/src/__tests__/pack-authoring.unit.test.ts +2 -4
- package/src/__tests__/pack.unit.test.ts +86 -124
- package/src/__tests__/scanner-instance-cycle.test.ts +92 -0
- package/src/__tests__/scanner-inventory.contract.test.ts +2 -2
- package/src/__tests__/scriptable-pack-diagnostic.integration.test.ts +45 -0
- package/src/inventory/binding.ts +3 -3
- package/src/inventory/declaration.ts +10 -48
- package/src/inventory/sync.ts +3 -2
- package/src/native-cooker-registry.ts +1 -0
- package/src/scanner.ts +28 -28
- package/src/schema-compiled.ts +40 -79
- package/src/scriptable-pack-node.ts +11 -3
- package/src/scriptable-pack-worker.ts +8 -1
- package/src/__tests__/scanner-mount-cycle.test.ts +0 -232
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { expect, it } from 'vitest';
|
|
5
|
+
import { loadScriptablePack } from '../scriptable-pack-node.js';
|
|
6
|
+
|
|
7
|
+
it('keeps the source line and column for a malformed author module', async () => {
|
|
8
|
+
const root = await mkdtemp(join(tmpdir(), 'pack-source-diagnostic-'));
|
|
9
|
+
const source = join(root, 'broken.pack.ts');
|
|
10
|
+
try {
|
|
11
|
+
await writeFile(source, 'export default {\n build: () => { const = 1; }\n};\n');
|
|
12
|
+
const loaded = await loadScriptablePack(source);
|
|
13
|
+
expect(loaded.ok).toBe(false);
|
|
14
|
+
if (loaded.ok) return;
|
|
15
|
+
expect(JSON.stringify(loaded.error)).toContain(`${source}:2:`);
|
|
16
|
+
} finally {
|
|
17
|
+
await rm(root, { recursive: true, force: true });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it.each([
|
|
22
|
+
0, 17,
|
|
23
|
+
])('propagates worker exit %i during a build instead of waiting for timeout', async (code) => {
|
|
24
|
+
const root = await mkdtemp(join(tmpdir(), 'pack-worker-exit-'));
|
|
25
|
+
const source = join(root, 'exit.pack.ts');
|
|
26
|
+
try {
|
|
27
|
+
await writeFile(
|
|
28
|
+
source,
|
|
29
|
+
`export default { schemaVersion: '2.0.0', packageId: new Uint8Array([121,171,30,178,252,222,65,195,145,119,233,61,213,193,142,245]), build() { process.exit(${code}); } };`,
|
|
30
|
+
);
|
|
31
|
+
const loaded = await loadScriptablePack(source, { buildTimeoutMs: 1000 });
|
|
32
|
+
expect(loaded.ok).toBe(true);
|
|
33
|
+
if (!loaded.ok) return;
|
|
34
|
+
await expect(
|
|
35
|
+
loaded.value.build({
|
|
36
|
+
packageId: loaded.value.packageId,
|
|
37
|
+
readByGuid: async () => {
|
|
38
|
+
throw new Error('unexpected read');
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
).rejects.toThrow(`worker exited with code ${code}`);
|
|
42
|
+
} finally {
|
|
43
|
+
await rm(root, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
});
|
package/src/inventory/binding.ts
CHANGED
|
@@ -15,11 +15,11 @@ export function projectAssetRefs(inventory: AuthorInventory): readonly AssetRef[
|
|
|
15
15
|
/** Derive instance-relative scene refs from the same validated author rows. */
|
|
16
16
|
export function projectSceneEntityRefs(inventory: AuthorInventory): readonly SceneEntityRef[] {
|
|
17
17
|
return inventory.declarations.flatMap((row) =>
|
|
18
|
-
row.
|
|
18
|
+
row.sceneEntityKeys === undefined
|
|
19
19
|
? []
|
|
20
|
-
: row.
|
|
20
|
+
: row.sceneEntityKeys.map((address) => ({
|
|
21
21
|
sceneSourceKey: row.sourceKey,
|
|
22
|
-
|
|
22
|
+
address,
|
|
23
23
|
})),
|
|
24
24
|
);
|
|
25
25
|
}
|
|
@@ -6,7 +6,7 @@ export interface AuthorInventoryRow {
|
|
|
6
6
|
readonly kind: string;
|
|
7
7
|
readonly payload: Readonly<Record<string, unknown>>;
|
|
8
8
|
readonly refs: readonly string[];
|
|
9
|
-
readonly
|
|
9
|
+
readonly sceneEntityKeys?: readonly string[];
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface AuthorInventory {
|
|
@@ -102,54 +102,16 @@ export function validateAuthorInventory(value: unknown): Result<AuthorInventory,
|
|
|
102
102
|
{ guid, sourceKey },
|
|
103
103
|
);
|
|
104
104
|
}
|
|
105
|
-
if (row.kind === 'scene') {
|
|
106
|
-
const payload = row.payload;
|
|
107
|
-
const payloadRecord =
|
|
108
|
-
typeof payload === 'object' && payload !== null
|
|
109
|
-
? (payload as Record<string, unknown>)
|
|
110
|
-
: undefined;
|
|
111
|
-
const entities =
|
|
112
|
-
payloadRecord !== undefined && Array.isArray(payloadRecord.entities)
|
|
113
|
-
? payloadRecord.entities
|
|
114
|
-
: [];
|
|
115
|
-
const bindings = new Set<string>();
|
|
116
|
-
for (const entity of entities) {
|
|
117
|
-
const bindingKey =
|
|
118
|
-
typeof entity === 'object' && entity !== null && typeof entity.bindingKey === 'string'
|
|
119
|
-
? entity.bindingKey
|
|
120
|
-
: undefined;
|
|
121
|
-
if (bindingKey !== undefined && bindingKey.length === 0) {
|
|
122
|
-
return failure(
|
|
123
|
-
'inventory-scene-binding-missing',
|
|
124
|
-
'each declared scene bindingKey is non-empty',
|
|
125
|
-
'remove the empty bindingKey or declare a stable key in the scene producer',
|
|
126
|
-
{ sourceKey },
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
if (bindingKey === undefined) continue;
|
|
130
|
-
if (bindings.has(bindingKey)) {
|
|
131
|
-
return failure(
|
|
132
|
-
'inventory-scene-binding-duplicate',
|
|
133
|
-
'bindingKey values are unique within one scene',
|
|
134
|
-
'rename the duplicate bindingKey in the scene producer',
|
|
135
|
-
{ sourceKey },
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
bindings.add(bindingKey);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
105
|
guids.add(normalizedGuid);
|
|
142
106
|
sourceKeys.add(sourceKey);
|
|
143
|
-
const
|
|
144
|
-
row.kind
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
)
|
|
152
|
-
: undefined;
|
|
107
|
+
const sceneEntityKeys = (() => {
|
|
108
|
+
if (row.kind !== 'scene' || typeof row.payload !== 'object' || row.payload === null)
|
|
109
|
+
return undefined;
|
|
110
|
+
const entities = (row.payload as { readonly entities?: unknown }).entities;
|
|
111
|
+
if (entities === null || typeof entities !== 'object' || Array.isArray(entities))
|
|
112
|
+
return undefined;
|
|
113
|
+
return Object.keys(entities);
|
|
114
|
+
})();
|
|
153
115
|
declarations.push({
|
|
154
116
|
guid,
|
|
155
117
|
sourceKey,
|
|
@@ -161,7 +123,7 @@ export function validateAuthorInventory(value: unknown): Result<AuthorInventory,
|
|
|
161
123
|
refs: Array.isArray(row.refs)
|
|
162
124
|
? row.refs.filter((ref): ref is string => typeof ref === 'string')
|
|
163
125
|
: [],
|
|
164
|
-
...(
|
|
126
|
+
...(sceneEntityKeys === undefined ? {} : { sceneEntityKeys }),
|
|
165
127
|
});
|
|
166
128
|
}
|
|
167
129
|
return ok({ declarations });
|
package/src/inventory/sync.ts
CHANGED
|
@@ -5,7 +5,8 @@ export type InventoryDigest = string;
|
|
|
5
5
|
export function inventoryDigest(inventory: AuthorInventory): InventoryDigest {
|
|
6
6
|
return inventory.declarations
|
|
7
7
|
.map(
|
|
8
|
-
(row) =>
|
|
8
|
+
(row) =>
|
|
9
|
+
`${row.guid}\0${row.sourceKey}\0${row.kind}\0${row.sceneEntityKeys?.join('\0') ?? ''}`,
|
|
9
10
|
)
|
|
10
11
|
.sort()
|
|
11
12
|
.join('\n');
|
|
@@ -16,7 +17,7 @@ export function syncAuthorInventory(inventory: AuthorInventory): AuthorInventory
|
|
|
16
17
|
declarations: inventory.declarations.map((row) => ({
|
|
17
18
|
...row,
|
|
18
19
|
refs: [...row.refs],
|
|
19
|
-
...(row.
|
|
20
|
+
...(row.sceneEntityKeys === undefined ? {} : { sceneEntityKeys: [...row.sceneEntityKeys] }),
|
|
20
21
|
})),
|
|
21
22
|
};
|
|
22
23
|
}
|
|
@@ -20,6 +20,7 @@ export interface NativeCookDraft<P = unknown> {
|
|
|
20
20
|
readonly refs: readonly string[];
|
|
21
21
|
readonly artifacts: Readonly<Record<string, NativeCookArtifact>>;
|
|
22
22
|
readonly inputFingerprint: string;
|
|
23
|
+
readonly sourceDependencies?: readonly string[];
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export interface NativeCooker<P = unknown, I = unknown> {
|
package/src/scanner.ts
CHANGED
|
@@ -254,27 +254,35 @@ function makePackError(
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
/**
|
|
257
|
-
* For scene assets
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* mounts with malformed `source` (out-of-range integer / non-integer) —
|
|
261
|
-
* those are caught by ajv schema validation upstream. The yielded GUIDs
|
|
262
|
-
* feed scanner step-6's mount-asset cycle DFS (D-1, R10).
|
|
257
|
+
* For keyed scene assets, return the lowercased GUID each nested instance
|
|
258
|
+
* source resolves to via `asset.refs[]` (or directly carries). The yielded GUIDs feed
|
|
259
|
+
* scanner step-6's scene dependency cycle DFS.
|
|
263
260
|
*/
|
|
264
|
-
function*
|
|
261
|
+
function* extractInstanceSourceGuids(asset: {
|
|
265
262
|
kind?: unknown;
|
|
266
263
|
payload?: unknown;
|
|
267
264
|
refs: readonly string[];
|
|
268
265
|
}): Generator<string> {
|
|
269
266
|
if (asset.kind !== 'scene') return;
|
|
270
|
-
const payload = asset.payload as {
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
267
|
+
const payload = asset.payload as { entities?: unknown } | undefined;
|
|
268
|
+
if (
|
|
269
|
+
!payload ||
|
|
270
|
+
payload.entities === null ||
|
|
271
|
+
typeof payload.entities !== 'object' ||
|
|
272
|
+
Array.isArray(payload.entities)
|
|
273
|
+
)
|
|
274
|
+
return;
|
|
275
|
+
for (const rawEntity of Object.values(payload.entities as Record<string, unknown>)) {
|
|
276
|
+
if (rawEntity === null || typeof rawEntity !== 'object' || Array.isArray(rawEntity)) continue;
|
|
277
|
+
const instance = (rawEntity as { instance?: unknown }).instance;
|
|
278
|
+
if (instance === null || typeof instance !== 'object' || Array.isArray(instance)) continue;
|
|
279
|
+
const source = (instance as { source?: unknown }).source;
|
|
280
|
+
const resolved =
|
|
281
|
+
typeof source === 'number' && Number.isInteger(source)
|
|
282
|
+
? asset.refs[source]
|
|
283
|
+
: typeof source === 'string'
|
|
284
|
+
? source
|
|
285
|
+
: undefined;
|
|
278
286
|
if (typeof resolved !== 'string') continue;
|
|
279
287
|
yield resolved.toLowerCase();
|
|
280
288
|
}
|
|
@@ -450,7 +458,7 @@ async function scanValidated(
|
|
|
450
458
|
guidToPath.set(normalizedGuid, packPath);
|
|
451
459
|
packRefs.set(normalizedGuid, [
|
|
452
460
|
...asset.refs.map((ref) => ref.toLowerCase()),
|
|
453
|
-
...
|
|
461
|
+
...extractInstanceSourceGuids(asset),
|
|
454
462
|
]);
|
|
455
463
|
}
|
|
456
464
|
}
|
|
@@ -563,20 +571,12 @@ async function scanValidated(
|
|
|
563
571
|
}
|
|
564
572
|
guidToPath.set(normalizedGuid, packPath);
|
|
565
573
|
|
|
566
|
-
//
|
|
567
|
-
//
|
|
568
|
-
//
|
|
569
|
-
// asset.refs[]. By the .pack.json convention mount.source is an
|
|
570
|
-
// integer index into the same asset.refs[], so the resolved GUID is
|
|
571
|
-
// already present in `existingRefs`; this defensive pass guarantees
|
|
572
|
-
// that any author-supplied mounts[] references participate in the
|
|
573
|
-
// cycle DFS even if the schema-emitter forgot to mirror them into
|
|
574
|
-
// refs[]. The `kind: 'mount-asset'` tag on the resulting
|
|
575
|
-
// pack-cyclic-reference detail is set by the cycle producer below
|
|
576
|
-
// (R10).
|
|
574
|
+
// Keyed scene instances are explicit dependency edges. Keep the
|
|
575
|
+
// producer source in the cycle graph alongside ordinary asset refs so
|
|
576
|
+
// recursive SceneAsset declarations fail before publication.
|
|
577
577
|
packRefs.set(normalizedGuid, [
|
|
578
578
|
...asset.refs.map((ref) => ref.toLowerCase()),
|
|
579
|
-
...
|
|
579
|
+
...extractInstanceSourceGuids(asset),
|
|
580
580
|
]);
|
|
581
581
|
}
|
|
582
582
|
capture?.declarations.set(packPath, {
|
package/src/schema-compiled.ts
CHANGED
|
@@ -75,108 +75,69 @@ export function buildSceneAssetValidator(
|
|
|
75
75
|
componentsProperties[name] = sub;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
// feat-20260713-mount-override-component-add-and-shared-ref-round M1 / w3;
|
|
80
|
-
// requirements §S-10 / AC-03): validates each entry in mounts[].overrides[].
|
|
81
|
-
// `field` is optional — it is a component-granular add-or-patch discriminant
|
|
82
|
-
// (present -> patch one field with `value`; absent -> add/upsert the whole
|
|
83
|
-
// `comp` with `value` as its per-field map). `localId` / `comp` / `value`
|
|
84
|
-
// stay required; `additionalProperties: false` rejects any `op`-tag
|
|
85
|
-
// discriminant so downstream consumers never branch on it. Field-level type
|
|
86
|
-
// validation (matching the schema vocab) is enforced at runtime via
|
|
87
|
-
// setSceneOverride (D-9 / EcsErrorCode 'scene-override-type-mismatch').
|
|
88
|
-
const mountOverrideSchema = {
|
|
78
|
+
const componentsSchema = {
|
|
89
79
|
type: 'object',
|
|
90
80
|
additionalProperties: false,
|
|
91
|
-
|
|
92
|
-
properties: {
|
|
93
|
-
localId: { type: 'integer', minimum: 0 },
|
|
94
|
-
comp: { type: 'string', minLength: 1 },
|
|
95
|
-
field: { type: 'string', minLength: 1 },
|
|
96
|
-
value: {},
|
|
97
|
-
},
|
|
81
|
+
properties: componentsProperties,
|
|
98
82
|
};
|
|
99
|
-
|
|
100
|
-
// SceneInstanceMount schema (feat-20260608-scene-nesting-ecs-fication
|
|
101
|
-
// M1 / w11; requirements §S-10): validates each mounts[] entry. parent /
|
|
102
|
-
// components / overrides are optional; cross-mount window collision and
|
|
103
|
-
// mount.source / mount.memberCount agreement with referenced child
|
|
104
|
-
// SceneAsset are checked at the build-time scanner (D-1, w14), not here.
|
|
105
|
-
const mountSchema = {
|
|
83
|
+
const instanceSchema = {
|
|
106
84
|
type: 'object',
|
|
107
85
|
additionalProperties: false,
|
|
108
|
-
required: ['
|
|
86
|
+
required: ['source'],
|
|
109
87
|
properties: {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
additionalProperties: false,
|
|
118
|
-
properties: componentsProperties,
|
|
88
|
+
// Authored scenes use a GUID string. Pack output may carry a refs[]
|
|
89
|
+
// index, which is resolved by the Scene decoder before instantiation.
|
|
90
|
+
source: {
|
|
91
|
+
oneOf: [
|
|
92
|
+
{ type: 'string', minLength: 1 },
|
|
93
|
+
{ type: 'integer', minimum: 0 },
|
|
94
|
+
],
|
|
119
95
|
},
|
|
120
96
|
overrides: {
|
|
121
97
|
type: 'array',
|
|
122
|
-
items:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
'sourceRevision',
|
|
131
|
-
'publicationGeneration',
|
|
132
|
-
'outputDigest',
|
|
133
|
-
'outputSetDigest',
|
|
134
|
-
'receiptIdentity',
|
|
135
|
-
],
|
|
136
|
-
properties: {
|
|
137
|
-
schemaVersion: { type: 'string', const: 'scene-publication-fence/1' },
|
|
138
|
-
sourcePath: { type: 'string', minLength: 1 },
|
|
139
|
-
sourceRevision: { type: 'string', minLength: 1 },
|
|
140
|
-
publicationGeneration: { type: 'integer', minimum: 1 },
|
|
141
|
-
outputDigest: { type: 'string', minLength: 1 },
|
|
142
|
-
outputSetDigest: { type: 'string', minLength: 1 },
|
|
143
|
-
receiptIdentity: { type: 'string', minLength: 1 },
|
|
98
|
+
items: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
additionalProperties: false,
|
|
101
|
+
required: ['target', 'components'],
|
|
102
|
+
properties: {
|
|
103
|
+
target: { type: 'array', minItems: 1, items: { type: 'string', minLength: 1 } },
|
|
104
|
+
components: componentsSchema,
|
|
105
|
+
},
|
|
144
106
|
},
|
|
145
107
|
},
|
|
146
108
|
},
|
|
147
109
|
};
|
|
148
|
-
|
|
110
|
+
const entitySchema = {
|
|
111
|
+
type: 'object',
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
required: ['components'],
|
|
114
|
+
properties: {
|
|
115
|
+
components: componentsSchema,
|
|
116
|
+
instance: instanceSchema,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
149
119
|
const sceneSchema = {
|
|
150
120
|
type: 'object',
|
|
151
121
|
additionalProperties: false,
|
|
152
122
|
required: ['kind', 'entities'],
|
|
153
123
|
properties: {
|
|
154
124
|
kind: { type: 'string', const: 'scene' },
|
|
155
|
-
|
|
156
|
-
|
|
125
|
+
// Skin assets are explicit scene dependencies so async catalog loading
|
|
126
|
+
// can finish the joint-wiring path before the Scene is instantiated.
|
|
127
|
+
// Authored producers use GUID strings; Pack output may use refs[] indices.
|
|
128
|
+
skinGuids: {
|
|
157
129
|
type: 'array',
|
|
158
130
|
items: {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
localId: { type: 'integer', minimum: 0 },
|
|
164
|
-
bindingKey: { type: 'string', minLength: 1 },
|
|
165
|
-
components: {
|
|
166
|
-
type: 'object',
|
|
167
|
-
additionalProperties: false,
|
|
168
|
-
properties: componentsProperties,
|
|
169
|
-
},
|
|
170
|
-
},
|
|
131
|
+
oneOf: [
|
|
132
|
+
{ type: 'string', minLength: 1 },
|
|
133
|
+
{ type: 'integer', minimum: 0 },
|
|
134
|
+
],
|
|
171
135
|
},
|
|
172
136
|
},
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
mounts: {
|
|
178
|
-
type: 'array',
|
|
179
|
-
items: mountSchema,
|
|
137
|
+
entities: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
propertyNames: { type: 'string', minLength: 1 },
|
|
140
|
+
additionalProperties: entitySchema,
|
|
180
141
|
},
|
|
181
142
|
},
|
|
182
143
|
};
|
|
@@ -266,9 +266,17 @@ class WorkerScriptablePackExecutor
|
|
|
266
266
|
}
|
|
267
267
|
};
|
|
268
268
|
worker.on('message', onMessage);
|
|
269
|
-
|
|
269
|
+
const fail = (error: Error): void => {
|
|
270
|
+
rejectLoad(error);
|
|
271
|
+
const active = this.build;
|
|
272
|
+
this.build = undefined;
|
|
273
|
+
active?.reject(error);
|
|
274
|
+
void this.dispose('failure');
|
|
275
|
+
};
|
|
276
|
+
worker.once('error', fail);
|
|
270
277
|
worker.once('exit', (code) => {
|
|
271
|
-
if (
|
|
278
|
+
if (this.disposal !== undefined) return;
|
|
279
|
+
fail(new Error(`ScriptablePack worker exited with code ${code}`));
|
|
272
280
|
});
|
|
273
281
|
});
|
|
274
282
|
}
|
|
@@ -393,7 +401,7 @@ class ReusableWorkerScriptablePackExecutor
|
|
|
393
401
|
void this.dispose('failure');
|
|
394
402
|
});
|
|
395
403
|
this.worker.on('exit', (code) => {
|
|
396
|
-
if (
|
|
404
|
+
if (this.disposal !== undefined) return;
|
|
397
405
|
this.failed = true;
|
|
398
406
|
this.rejectActive(new Error(`ScriptablePack worker exited with code ${code}`));
|
|
399
407
|
void this.dispose('failure');
|
|
@@ -215,7 +215,14 @@ function compileModuleClosure(entryPath: string, outputRoot: string, loadId?: nu
|
|
|
215
215
|
if (errors.length > 0) {
|
|
216
216
|
throw new Error(
|
|
217
217
|
`ScriptablePack TypeScript transpile failed for ${path}: ${errors
|
|
218
|
-
.map((diagnostic) =>
|
|
218
|
+
.map((diagnostic) => {
|
|
219
|
+
const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
|
|
220
|
+
const location =
|
|
221
|
+
position === undefined
|
|
222
|
+
? path
|
|
223
|
+
: `${path}:${position.line + 1}:${position.character + 1}`;
|
|
224
|
+
return `${location}: ${ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`;
|
|
225
|
+
})
|
|
219
226
|
.join('; ')}`,
|
|
220
227
|
);
|
|
221
228
|
}
|