halfcode-compiler.xnl 0.1.1 → 0.2.1
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/application-assembly.js +1 -1
- package/dist/{index-DuRG4TQo.d.ts → index-DKwcVwK6.d.ts} +1 -1
- package/dist/{index-Ba5Gt9iW.d.ts → index-DqYap2u_.d.ts} +15 -1
- package/dist/{index-D-cBhQVw.d.ts → index-wU-iKJnW.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/kind-definition.d.ts +16 -4
- package/dist/kind-definition.js +33 -1
- package/dist/resource-core.d.ts +2 -2
- package/dist/resource-core.js +1 -1
- package/dist/resource-projection.d.ts +1 -1
- package/dist/skill-capsule.d.ts +1 -1
- package/dist/skill-capsule.js +1 -1
- package/dist/{src-Dv8bfFUo.js → src-4m42imop.js} +1 -1
- package/dist/{src-DEuFHizY.js → src-D8xlMdXx.js} +1 -1
- package/dist/{src-COEMEqZw.js → src-DKkIFGWH.js} +98 -22
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as assertObjectOperationCatalog, c as resolveApplicationAssembly, i as assertObjectOperationCall, l as resourceRefToFqn, n as applicationAssemblyPackage, o as assertObjectOperationDefinition, r as assertExecuteObjectOperationRequest, s as loadApplicationAssembly, t as ObjectOperationContractError } from "./src-
|
|
1
|
+
import { a as assertObjectOperationCatalog, c as resolveApplicationAssembly, i as assertObjectOperationCall, l as resourceRefToFqn, n as applicationAssemblyPackage, o as assertObjectOperationDefinition, r as assertExecuteObjectOperationRequest, s as loadApplicationAssembly, t as ObjectOperationContractError } from "./src-4m42imop.js";
|
|
2
2
|
export { ObjectOperationContractError, applicationAssemblyPackage, assertExecuteObjectOperationRequest, assertObjectOperationCall, assertObjectOperationCatalog, assertObjectOperationDefinition, loadApplicationAssembly, resolveApplicationAssembly, resourceRefToFqn };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as ResourceDescriptor } from "./index-DqYap2u_.js";
|
|
2
2
|
//#region ../resource-projection/src/index.d.ts
|
|
3
3
|
interface ResourceRegistry {
|
|
4
4
|
readonly byKind: ReadonlyMap<string, readonly ResourceDescriptor[]>;
|
|
@@ -35,8 +35,22 @@ interface ResourceRecord extends ResourceDescriptor {
|
|
|
35
35
|
format: "xnl";
|
|
36
36
|
node: ResourceNode;
|
|
37
37
|
}
|
|
38
|
+
interface ResourceKindContract {
|
|
39
|
+
resourceKind: string;
|
|
40
|
+
sourceShapes: readonly SourceShape[];
|
|
41
|
+
currentApiVersion: string;
|
|
42
|
+
supportedApiVersions: readonly string[];
|
|
43
|
+
documentCardinality?: "one" | "many";
|
|
44
|
+
}
|
|
45
|
+
interface RegisteredKindDefinition extends ResourceKindContract {
|
|
46
|
+
resourceId: string;
|
|
47
|
+
requiredFiles: readonly string[];
|
|
48
|
+
documentCardinality: "one" | "many";
|
|
49
|
+
documentUri: string;
|
|
50
|
+
}
|
|
38
51
|
interface ResourceRegistry {
|
|
39
52
|
readonly byKind: ReadonlyMap<string, readonly ResourceRecord[]>;
|
|
53
|
+
readonly kindDefinitions: ReadonlyMap<string, RegisteredKindDefinition>;
|
|
40
54
|
}
|
|
41
55
|
interface ResourceTree {
|
|
42
56
|
manifest: ResourceRecord;
|
|
@@ -64,4 +78,4 @@ declare class ResourceValidationError extends Error {
|
|
|
64
78
|
declare function loadResourceTree(options: LoadResourceTreeOptions): Promise<ResourceTree>;
|
|
65
79
|
declare function validateResourceTree(options: LoadResourceTreeOptions): Promise<ResourceDiagnostic[]>;
|
|
66
80
|
//#endregion
|
|
67
|
-
export {
|
|
81
|
+
export { ResourceValueMap as _, ResourceIdentity as a, validateResourceTree as b, ResourceNode as c, ResourceScalar as d, ResourceTree as f, ResourceValueList as g, ResourceValue as h, ResourceDiagnostic as i, ResourceRecord as l, ResourceValidationError as m, RegisteredKindDefinition as n, ResourceKindContract as o, ResourceTreeBuildResult as p, ResourceDescriptor as r, ResourceMetadata as s, LoadResourceTreeOptions as t, ResourceRegistry as u, SourceShape as v, loadResourceTree as y };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as ApplicationAssembly } from "./index-FdimP_SL.js";
|
|
2
|
-
import { t as ResourceRegistry } from "./index-
|
|
2
|
+
import { t as ResourceRegistry } from "./index-DKwcVwK6.js";
|
|
3
3
|
//#region ../compiler-skill/src/index.d.ts
|
|
4
4
|
interface SkillDescriptor {
|
|
5
5
|
name: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { A as ObjectTargets, B as assertExecuteObjectOperationRequest, C as ObjectOperationDefinition, D as ObjectOperationTargetDeclaration, E as ObjectOperationOwnerKind, F as ResourceSource, G as resolveApplicationAssembly, H as assertObjectOperationCatalog, I as SkillCapsuleResource, K as resourceRefToFqn, L as TextMaterial, M as ResolveApplicationAssemblyOptions, N as ResolvedAssemblyPortBinding, O as ObjectTargetKindDefinition, P as ResourceInclude, R as TextResource, S as ObjectOperationContractError, T as ObjectOperationHandler, U as assertObjectOperationDefinition, V as assertObjectOperationCall, W as loadApplicationAssembly, _ as ObjectInvocationMode, a as AssemblyResource, b as ObjectOperationCatalog, c as BusinessObjectSopResource, d as ExecuteObjectOperationRequest, f as JsonObject, g as ObjectInvocation, h as LoadApplicationAssemblyOptions, i as AssemblyPortBinding, j as PageObjectResource, k as ObjectTargetRef, l as CodeBinding, m as JsonValue, n as ApplicationScope, o as AuthoringModuleDescriptor, p as JsonPrimitive, r as AssemblyPort, s as BusinessObjectResource, t as ApplicationAssembly, u as ContractedCallableResource, v as ObjectOperationBehavior, w as ObjectOperationEffect, x as ObjectOperationConfig, y as ObjectOperationCall, z as applicationAssemblyPackage } from "./index-FdimP_SL.js";
|
|
2
|
-
import { a as SkillReference, c as compilerSkillPackage, i as SkillDescriptor, n as CompileSkillCapsuleInput, o as compileResourceSkillCapsule, r as SkillCapsulePlan, s as compileSkillCapsule, t as CompileResourceSkillCapsuleInput } from "./index-
|
|
2
|
+
import { a as SkillReference, c as compilerSkillPackage, i as SkillDescriptor, n as CompileSkillCapsuleInput, o as compileResourceSkillCapsule, r as SkillCapsulePlan, s as compileSkillCapsule, t as CompileResourceSkillCapsuleInput } from "./index-wU-iKJnW.js";
|
|
3
3
|
export { type ApplicationAssembly, type ApplicationScope, type AssemblyPort, type AssemblyPortBinding, type AssemblyResource, type AuthoringModuleDescriptor, type BusinessObjectResource, type BusinessObjectSopResource, type CodeBinding, CompileResourceSkillCapsuleInput, CompileSkillCapsuleInput, type ContractedCallableResource, type ExecuteObjectOperationRequest, type JsonObject, type JsonPrimitive, type JsonValue, type LoadApplicationAssemblyOptions, type ObjectInvocation, type ObjectInvocationMode, type ObjectOperationBehavior, type ObjectOperationCall, type ObjectOperationCatalog, type ObjectOperationConfig, ObjectOperationContractError, type ObjectOperationDefinition, type ObjectOperationEffect, type ObjectOperationHandler, type ObjectOperationOwnerKind, type ObjectOperationTargetDeclaration, type ObjectTargetKindDefinition, type ObjectTargetRef, type ObjectTargets, type PageObjectResource, type ResolveApplicationAssemblyOptions, type ResolvedAssemblyPortBinding, type ResourceInclude, type ResourceSource, SkillCapsulePlan, type SkillCapsuleResource, SkillDescriptor, SkillReference, type TextMaterial, type TextResource, applicationAssemblyPackage, assertExecuteObjectOperationRequest, assertObjectOperationCall, assertObjectOperationCatalog, assertObjectOperationDefinition, compileResourceSkillCapsule, compileSkillCapsule, compilerSkillPackage, loadApplicationAssembly, resolveApplicationAssembly, resourceRefToFqn };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as assertObjectOperationCatalog, c as resolveApplicationAssembly, i as assertObjectOperationCall, l as resourceRefToFqn, n as applicationAssemblyPackage, o as assertObjectOperationDefinition, r as assertExecuteObjectOperationRequest, s as loadApplicationAssembly, t as ObjectOperationContractError } from "./src-
|
|
1
|
+
import { a as assertObjectOperationCatalog, c as resolveApplicationAssembly, i as assertObjectOperationCall, l as resourceRefToFqn, n as applicationAssemblyPackage, o as assertObjectOperationDefinition, r as assertExecuteObjectOperationRequest, s as loadApplicationAssembly, t as ObjectOperationContractError } from "./src-4m42imop.js";
|
|
2
2
|
import "./application-assembly.js";
|
|
3
|
-
import { n as compileSkillCapsule, r as compilerSkillPackage, t as compileResourceSkillCapsule } from "./src-
|
|
3
|
+
import { n as compileSkillCapsule, r as compilerSkillPackage, t as compileResourceSkillCapsule } from "./src-D8xlMdXx.js";
|
|
4
4
|
export { ObjectOperationContractError, applicationAssemblyPackage, assertExecuteObjectOperationRequest, assertObjectOperationCall, assertObjectOperationCatalog, assertObjectOperationDefinition, compileResourceSkillCapsule, compileSkillCapsule, compilerSkillPackage, loadApplicationAssembly, resolveApplicationAssembly, resourceRefToFqn };
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as ResourceKindContract, r as ResourceDescriptor } from "./index-DqYap2u_.js";
|
|
2
2
|
//#region ../kind-definition/src/index.d.ts
|
|
3
|
-
interface KindDefinition extends ResourceDescriptor {
|
|
3
|
+
interface KindDefinition extends ResourceDescriptor, ResourceKindContract {
|
|
4
4
|
kind: "KindDefinition";
|
|
5
|
+
}
|
|
6
|
+
interface ResourceMigrationDefinition<T> {
|
|
7
|
+
id: string;
|
|
5
8
|
resourceKind: string;
|
|
6
|
-
|
|
9
|
+
fromApiVersion: string;
|
|
10
|
+
toApiVersion: string;
|
|
11
|
+
migrate: (resource: T) => T;
|
|
12
|
+
}
|
|
13
|
+
declare class ResourceMigrationRegistry<T> {
|
|
14
|
+
private readonly definitions;
|
|
15
|
+
private readonly ids;
|
|
16
|
+
register(definition: ResourceMigrationDefinition<T>): this;
|
|
17
|
+
plan(resourceKind: string, fromApiVersion: string, toApiVersion: string): readonly ResourceMigrationDefinition<T>[];
|
|
18
|
+
migrate(resourceKind: string, fromApiVersion: string, toApiVersion: string, resource: T): T;
|
|
7
19
|
}
|
|
8
20
|
declare const kindDefinitionPackage: {
|
|
9
21
|
readonly role: "framework";
|
|
@@ -11,4 +23,4 @@ declare const kindDefinitionPackage: {
|
|
|
11
23
|
readonly owns: "resource kind validation authority";
|
|
12
24
|
};
|
|
13
25
|
//#endregion
|
|
14
|
-
export { KindDefinition, kindDefinitionPackage };
|
|
26
|
+
export { KindDefinition, ResourceMigrationDefinition, ResourceMigrationRegistry, kindDefinitionPackage };
|
package/dist/kind-definition.js
CHANGED
|
@@ -1,8 +1,40 @@
|
|
|
1
1
|
//#region ../kind-definition/src/index.ts
|
|
2
|
+
var ResourceMigrationRegistry = class {
|
|
3
|
+
definitions = [];
|
|
4
|
+
ids = /* @__PURE__ */ new Set();
|
|
5
|
+
register(definition) {
|
|
6
|
+
if (this.ids.has(definition.id)) throw new Error(`Duplicate migration id '${definition.id}'`);
|
|
7
|
+
if (!definition.id || !definition.resourceKind || !definition.fromApiVersion || !definition.toApiVersion) throw new Error("Migration definitions require id, resourceKind, fromApiVersion, and toApiVersion");
|
|
8
|
+
if (definition.fromApiVersion === definition.toApiVersion) throw new Error(`Migration '${definition.id}' must change apiVersion`);
|
|
9
|
+
this.ids.add(definition.id);
|
|
10
|
+
this.definitions.push(Object.freeze({ ...definition }));
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
plan(resourceKind, fromApiVersion, toApiVersion) {
|
|
14
|
+
if (fromApiVersion === toApiVersion) return [];
|
|
15
|
+
const steps = [];
|
|
16
|
+
const visited = /* @__PURE__ */ new Set();
|
|
17
|
+
let current = fromApiVersion;
|
|
18
|
+
while (current !== toApiVersion) {
|
|
19
|
+
if (visited.has(current)) throw new Error(`Migration cycle detected for Kind '${resourceKind}' at '${current}'`);
|
|
20
|
+
visited.add(current);
|
|
21
|
+
const candidates = this.definitions.filter((definition) => definition.resourceKind === resourceKind && definition.fromApiVersion === current);
|
|
22
|
+
if (candidates.length === 0) throw new Error(`No migration for Kind '${resourceKind}' from '${current}' to '${toApiVersion}'`);
|
|
23
|
+
if (candidates.length > 1) throw new Error(`Ambiguous migration for Kind '${resourceKind}' from '${current}': ${candidates.map((candidate) => candidate.id).join(", ")}`);
|
|
24
|
+
const step = candidates[0];
|
|
25
|
+
steps.push(step);
|
|
26
|
+
current = step.toApiVersion;
|
|
27
|
+
}
|
|
28
|
+
return Object.freeze(steps);
|
|
29
|
+
}
|
|
30
|
+
migrate(resourceKind, fromApiVersion, toApiVersion, resource) {
|
|
31
|
+
return this.plan(resourceKind, fromApiVersion, toApiVersion).reduce((value, step) => step.migrate(value), resource);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
2
34
|
const kindDefinitionPackage = {
|
|
3
35
|
role: "framework",
|
|
4
36
|
area: "kind-definition",
|
|
5
37
|
owns: "resource kind validation authority"
|
|
6
38
|
};
|
|
7
39
|
//#endregion
|
|
8
|
-
export { kindDefinitionPackage };
|
|
40
|
+
export { ResourceMigrationRegistry, kindDefinitionPackage };
|
package/dist/resource-core.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { LoadResourceTreeOptions, ResourceDescriptor, ResourceDiagnostic, ResourceIdentity, ResourceMetadata, ResourceNode, ResourceRecord, ResourceRegistry, ResourceScalar, ResourceTree, ResourceTreeBuildResult, ResourceValidationError, ResourceValue, ResourceValueList, ResourceValueMap, SourceShape, loadResourceTree, validateResourceTree };
|
|
1
|
+
import { _ as ResourceValueMap, a as ResourceIdentity, b as validateResourceTree, c as ResourceNode, d as ResourceScalar, f as ResourceTree, g as ResourceValueList, h as ResourceValue, i as ResourceDiagnostic, l as ResourceRecord, m as ResourceValidationError, n as RegisteredKindDefinition, o as ResourceKindContract, p as ResourceTreeBuildResult, r as ResourceDescriptor, s as ResourceMetadata, t as LoadResourceTreeOptions, u as ResourceRegistry, v as SourceShape, y as loadResourceTree } from "./index-DqYap2u_.js";
|
|
2
|
+
export { LoadResourceTreeOptions, RegisteredKindDefinition, ResourceDescriptor, ResourceDiagnostic, ResourceIdentity, ResourceKindContract, ResourceMetadata, ResourceNode, ResourceRecord, ResourceRegistry, ResourceScalar, ResourceTree, ResourceTreeBuildResult, ResourceValidationError, ResourceValue, ResourceValueList, ResourceValueMap, SourceShape, loadResourceTree, validateResourceTree };
|
package/dist/resource-core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as loadResourceTree, r as validateResourceTree, t as ResourceValidationError } from "./src-
|
|
1
|
+
import { n as loadResourceTree, r as validateResourceTree, t as ResourceValidationError } from "./src-DKkIFGWH.js";
|
|
2
2
|
export { ResourceValidationError, loadResourceTree, validateResourceTree };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as resourceProjectionPackage, t as ResourceRegistry } from "./index-
|
|
1
|
+
import { n as resourceProjectionPackage, t as ResourceRegistry } from "./index-DKwcVwK6.js";
|
|
2
2
|
export { ResourceRegistry, resourceProjectionPackage };
|
package/dist/skill-capsule.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as SkillReference, c as compilerSkillPackage, i as SkillDescriptor, n as CompileSkillCapsuleInput, o as compileResourceSkillCapsule, r as SkillCapsulePlan, s as compileSkillCapsule, t as CompileResourceSkillCapsuleInput } from "./index-
|
|
1
|
+
import { a as SkillReference, c as compilerSkillPackage, i as SkillDescriptor, n as CompileSkillCapsuleInput, o as compileResourceSkillCapsule, r as SkillCapsulePlan, s as compileSkillCapsule, t as CompileResourceSkillCapsuleInput } from "./index-wU-iKJnW.js";
|
|
2
2
|
export { CompileResourceSkillCapsuleInput, CompileSkillCapsuleInput, SkillCapsulePlan, SkillDescriptor, SkillReference, compileResourceSkillCapsule, compileSkillCapsule, compilerSkillPackage };
|
package/dist/skill-capsule.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as compileSkillCapsule, r as compilerSkillPackage, t as compileResourceSkillCapsule } from "./src-
|
|
1
|
+
import { n as compileSkillCapsule, r as compilerSkillPackage, t as compileResourceSkillCapsule } from "./src-D8xlMdXx.js";
|
|
2
2
|
export { compileResourceSkillCapsule, compileSkillCapsule, compilerSkillPackage };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { l as resourceRefToFqn, u as resolveObjectOperationCompilation } from "./src-
|
|
1
|
+
import { l as resourceRefToFqn, u as resolveObjectOperationCompilation } from "./src-4m42imop.js";
|
|
2
2
|
import { n as parseResourceMappings, r as planResourceMappings, t as applyResourceMappingPlan } from "./src-BlKlpg0J.js";
|
|
3
3
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
@@ -3,8 +3,9 @@ import { readFile, readdir, realpath, stat } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
//#region ../resource-core/src/xnl-loader.ts
|
|
5
5
|
async function buildXnlResourceTree(options) {
|
|
6
|
+
const requestedRoot = resolve(options.rootDir);
|
|
6
7
|
const context = {
|
|
7
|
-
rootDir:
|
|
8
|
+
rootDir: await realpath(requestedRoot).catch(() => requestedRoot),
|
|
8
9
|
diagnostics: [],
|
|
9
10
|
kindDefinitions: /* @__PURE__ */ new Map(),
|
|
10
11
|
resources: [],
|
|
@@ -22,7 +23,10 @@ async function buildXnlResourceTree(options) {
|
|
|
22
23
|
diagnostics: [],
|
|
23
24
|
tree: {
|
|
24
25
|
manifest,
|
|
25
|
-
registry: {
|
|
26
|
+
registry: {
|
|
27
|
+
byKind,
|
|
28
|
+
kindDefinitions: context.kindDefinitions
|
|
29
|
+
},
|
|
26
30
|
diagnostics: []
|
|
27
31
|
}
|
|
28
32
|
};
|
|
@@ -88,6 +92,7 @@ async function loadCatalog(catalog, manifestDir, context) {
|
|
|
88
92
|
context.diagnostics.push(kindMismatch(record.kind, catalog.kind, record.documentUri));
|
|
89
93
|
continue;
|
|
90
94
|
}
|
|
95
|
+
validateResourceApiVersion(record, definition, context.diagnostics);
|
|
91
96
|
await validateRequiredFiles(dirname(file), record, definition, context.diagnostics);
|
|
92
97
|
validateIdentity(record, context);
|
|
93
98
|
context.resources.push(record);
|
|
@@ -95,15 +100,25 @@ async function loadCatalog(catalog, manifestDir, context) {
|
|
|
95
100
|
for (const nested of catalogs.filter((item) => item.kind !== "KindDefinition")) await loadCatalog(nested, dirname(file), context);
|
|
96
101
|
continue;
|
|
97
102
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
if (definition.documentCardinality === "many" && catalog.shape !== "single-file") {
|
|
104
|
+
context.diagnostics.push({
|
|
105
|
+
code: "RESOURCE_DOCUMENT_CARDINALITY_UNSUPPORTED",
|
|
106
|
+
location: catalog.location,
|
|
107
|
+
message: `Kind '${catalog.kind}' allows multiple document roots only in a single-file catalog.`
|
|
108
|
+
});
|
|
102
109
|
continue;
|
|
103
110
|
}
|
|
104
|
-
await
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
const records = await loadXnlRecords(file, catalog.shape, context, definition.documentCardinality);
|
|
112
|
+
for (const record of records) {
|
|
113
|
+
if (record.kind !== catalog.kind) {
|
|
114
|
+
context.diagnostics.push(kindMismatch(record.kind, catalog.kind, record.documentUri));
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
validateResourceApiVersion(record, definition, context.diagnostics);
|
|
118
|
+
await validateRequiredFiles(dirname(file), record, definition, context.diagnostics);
|
|
119
|
+
validateIdentity(record, context);
|
|
120
|
+
context.resources.push(record);
|
|
121
|
+
}
|
|
107
122
|
}
|
|
108
123
|
}
|
|
109
124
|
async function catalogFiles(catalog, manifestDir, context) {
|
|
@@ -118,7 +133,20 @@ async function catalogFiles(catalog, manifestDir, context) {
|
|
|
118
133
|
});
|
|
119
134
|
return [];
|
|
120
135
|
}
|
|
121
|
-
if (catalog.shape === "single-file")
|
|
136
|
+
if (catalog.shape === "single-file") {
|
|
137
|
+
if (catalog.entry) {
|
|
138
|
+
if (!isPlainEntry(catalog.entry) || !catalog.entry.toLowerCase().endsWith(".xnl")) {
|
|
139
|
+
context.diagnostics.push({
|
|
140
|
+
code: "RESOURCE_CATALOG_ENTRY_INVALID",
|
|
141
|
+
location: catalog.location,
|
|
142
|
+
message: "A single-file catalog entry must be a plain XNL filename."
|
|
143
|
+
});
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
return [join(root, catalog.entry)];
|
|
147
|
+
}
|
|
148
|
+
return entries.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".xnl")).sort((left, right) => left.name.localeCompare(right.name)).map((entry) => join(root, entry.name));
|
|
149
|
+
}
|
|
122
150
|
if (!catalog.entry || !isPlainEntry(catalog.entry)) {
|
|
123
151
|
context.diagnostics.push({
|
|
124
152
|
code: "RESOURCE_CATALOG_ENTRY_INVALID",
|
|
@@ -130,6 +158,9 @@ async function catalogFiles(catalog, manifestDir, context) {
|
|
|
130
158
|
return entries.filter((entry) => entry.isDirectory()).sort((left, right) => left.name.localeCompare(right.name)).map((entry) => join(root, entry.name, catalog.entry));
|
|
131
159
|
}
|
|
132
160
|
async function loadXnlRecord(filePath, sourceShape, context) {
|
|
161
|
+
return (await loadXnlRecords(filePath, sourceShape, context, "one"))[0];
|
|
162
|
+
}
|
|
163
|
+
async function loadXnlRecords(filePath, sourceShape, context, documentCardinality) {
|
|
133
164
|
const documentUri = documentUriFor(context.rootDir, filePath);
|
|
134
165
|
const source = await readFile(filePath, "utf8").catch(() => void 0);
|
|
135
166
|
if (source === void 0) {
|
|
@@ -138,9 +169,9 @@ async function loadXnlRecord(filePath, sourceShape, context) {
|
|
|
138
169
|
location: documentUri,
|
|
139
170
|
message: "Resource file does not exist."
|
|
140
171
|
});
|
|
141
|
-
return;
|
|
172
|
+
return [];
|
|
142
173
|
}
|
|
143
|
-
let
|
|
174
|
+
let roots;
|
|
144
175
|
try {
|
|
145
176
|
const parsed = parseXnl(source, { textBlockStyle: true });
|
|
146
177
|
if (parsed.warnings?.length) {
|
|
@@ -149,25 +180,32 @@ async function loadXnlRecord(filePath, sourceShape, context) {
|
|
|
149
180
|
location: documentUri,
|
|
150
181
|
message: parsed.warnings.map((warning) => warning.message).join("; ")
|
|
151
182
|
});
|
|
152
|
-
return;
|
|
183
|
+
return [];
|
|
153
184
|
}
|
|
154
|
-
if (parsed.nodes.length
|
|
185
|
+
if (parsed.nodes.length === 0 || parsed.nodes.some((node) => !isDataElement(node)) || documentCardinality === "one" && parsed.nodes.length !== 1) {
|
|
155
186
|
context.diagnostics.push({
|
|
156
187
|
code: "RESOURCE_XNL_ROOT_INVALID",
|
|
157
188
|
location: documentUri,
|
|
158
|
-
message: "XNL resource documents must contain exactly one data-element root."
|
|
189
|
+
message: documentCardinality === "one" ? "XNL resource documents must contain exactly one data-element root." : "XNL resource forests must contain one or more data-element roots."
|
|
159
190
|
});
|
|
160
|
-
return;
|
|
191
|
+
return [];
|
|
161
192
|
}
|
|
162
|
-
|
|
193
|
+
roots = parsed.nodes;
|
|
163
194
|
} catch (error) {
|
|
164
195
|
context.diagnostics.push({
|
|
165
196
|
code: "RESOURCE_XNL_SYNTAX",
|
|
166
197
|
location: documentUri,
|
|
167
198
|
message: `Invalid XNL resource document: ${error instanceof Error ? error.message : String(error)}`
|
|
168
199
|
});
|
|
169
|
-
return;
|
|
200
|
+
return [];
|
|
170
201
|
}
|
|
202
|
+
return roots.flatMap((root) => {
|
|
203
|
+
const record = resourceRecordFromRoot(root, filePath, sourceShape, context);
|
|
204
|
+
return record ? [record] : [];
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function resourceRecordFromRoot(root, filePath, sourceShape, context) {
|
|
208
|
+
const documentUri = documentUriFor(context.rootDir, filePath);
|
|
171
209
|
const node = normalizeNode(root);
|
|
172
210
|
const resourceId = node.resourceId;
|
|
173
211
|
const apiVersion = asString(node.metadata.apiVersion);
|
|
@@ -265,20 +303,55 @@ function normalizeKindDefinition(record, diagnostics) {
|
|
|
265
303
|
const resourceKind = asString(record.node.properties.resourceKind) ?? record.resourceId.split(".").at(-1);
|
|
266
304
|
const shapes = record.node.properties.sourceShapes;
|
|
267
305
|
const sourceShapes = Array.isArray(shapes) ? shapes.filter(isXnlShape) : [];
|
|
268
|
-
|
|
306
|
+
const currentApiVersion = asString(record.node.properties.currentApiVersion);
|
|
307
|
+
const versions = record.node.properties.supportedApiVersions;
|
|
308
|
+
const supportedApiVersions = Array.isArray(versions) ? versions.filter((value) => typeof value === "string" && Boolean(value.trim())) : [];
|
|
309
|
+
const cardinalityValue = asString(record.node.properties.documentCardinality) ?? "one";
|
|
310
|
+
if (!resourceKind || sourceShapes.length === 0 || !currentApiVersion || supportedApiVersions.length === 0 || !isDocumentCardinality(cardinalityValue)) {
|
|
269
311
|
diagnostics.push({
|
|
270
312
|
code: "KIND_DEFINITION_INVALID",
|
|
271
313
|
location: record.documentUri,
|
|
272
|
-
message: "KindDefinition requires resourceKind (or an id suffix) and
|
|
314
|
+
message: "KindDefinition requires resourceKind (or an id suffix), sourceShapes, currentApiVersion, and supportedApiVersions."
|
|
273
315
|
});
|
|
274
316
|
return;
|
|
275
317
|
}
|
|
318
|
+
if (!supportedApiVersions.includes(currentApiVersion)) {
|
|
319
|
+
diagnostics.push({
|
|
320
|
+
code: "KIND_DEFINITION_VERSION_INVALID",
|
|
321
|
+
location: record.documentUri,
|
|
322
|
+
message: `Kind '${resourceKind}' currentApiVersion '${currentApiVersion}' must be included in supportedApiVersions.`
|
|
323
|
+
});
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (cardinalityValue === "many" && sourceShapes.some((shape) => shape !== "single-file")) {
|
|
327
|
+
diagnostics.push({
|
|
328
|
+
code: "KIND_DEFINITION_CARDINALITY_INVALID",
|
|
329
|
+
location: record.documentUri,
|
|
330
|
+
message: `Kind '${resourceKind}' documentCardinality 'many' requires only the single-file source shape.`
|
|
331
|
+
});
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const requiredFiles = ((record.node.subdomains.DescriptorContract?.subdomains.RequiredFiles)?.body ?? []).filter(isResourceNode).filter((node) => node.tag === "File").map((node) => asString(node.properties.name)).filter((value) => Boolean(value));
|
|
276
335
|
return {
|
|
336
|
+
resourceId: record.resourceId,
|
|
277
337
|
resourceKind,
|
|
278
|
-
sourceShapes,
|
|
279
|
-
requiredFiles: (
|
|
338
|
+
sourceShapes: Object.freeze([...sourceShapes]),
|
|
339
|
+
requiredFiles: Object.freeze([...requiredFiles]),
|
|
340
|
+
currentApiVersion,
|
|
341
|
+
supportedApiVersions: Object.freeze([...new Set(supportedApiVersions)]),
|
|
342
|
+
documentCardinality: cardinalityValue,
|
|
343
|
+
documentUri: record.documentUri
|
|
280
344
|
};
|
|
281
345
|
}
|
|
346
|
+
function validateResourceApiVersion(record, definition, diagnostics) {
|
|
347
|
+
if (definition.supportedApiVersions.includes(record.metadata.apiVersion)) return;
|
|
348
|
+
diagnostics.push({
|
|
349
|
+
code: "RESOURCE_API_VERSION_UNSUPPORTED",
|
|
350
|
+
location: record.documentUri,
|
|
351
|
+
message: `Kind '${record.kind}' does not support apiVersion '${record.metadata.apiVersion}'.`,
|
|
352
|
+
hint: `Current apiVersion is '${definition.currentApiVersion}'.`
|
|
353
|
+
});
|
|
354
|
+
}
|
|
282
355
|
async function validateRequiredFiles(resourceDir, record, definition, diagnostics) {
|
|
283
356
|
for (const name of definition.requiredFiles) {
|
|
284
357
|
if (!isPlainEntry(name)) {
|
|
@@ -366,6 +439,9 @@ function kindMismatch(actual, expected, location) {
|
|
|
366
439
|
function isXnlShape(value) {
|
|
367
440
|
return value === "single-file" || value === "directory" || value === "manifest";
|
|
368
441
|
}
|
|
442
|
+
function isDocumentCardinality(value) {
|
|
443
|
+
return value === "one" || value === "many";
|
|
444
|
+
}
|
|
369
445
|
function isPlainEntry(value) {
|
|
370
446
|
return Boolean(value) && !value.includes("/") && !value.includes("\\") && !value.includes("..");
|
|
371
447
|
}
|