@aigne/afs 1.11.0-beta → 1.11.0-beta.10
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/LICENSE.md +17 -84
- package/README.md +4 -13
- package/dist/_virtual/rolldown_runtime.mjs +7 -0
- package/dist/afs.cjs +1330 -0
- package/dist/afs.d.cts +275 -0
- package/dist/afs.d.cts.map +1 -0
- package/dist/afs.d.mts +275 -0
- package/dist/afs.d.mts.map +1 -0
- package/dist/afs.mjs +1331 -0
- package/dist/afs.mjs.map +1 -0
- package/dist/capabilities/index.d.mts +2 -0
- package/dist/capabilities/types.d.cts +100 -0
- package/dist/capabilities/types.d.cts.map +1 -0
- package/dist/capabilities/types.d.mts +100 -0
- package/dist/capabilities/types.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.cjs +20 -0
- package/dist/capabilities/world-mapping.d.cts +139 -0
- package/dist/capabilities/world-mapping.d.cts.map +1 -0
- package/dist/capabilities/world-mapping.d.mts +139 -0
- package/dist/capabilities/world-mapping.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.mjs +20 -0
- package/dist/capabilities/world-mapping.mjs.map +1 -0
- package/dist/error.cjs +63 -0
- package/dist/error.d.cts +39 -0
- package/dist/error.d.cts.map +1 -0
- package/dist/error.d.mts +39 -0
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +59 -0
- package/dist/error.mjs.map +1 -0
- package/dist/index.cjs +72 -345
- package/dist/index.d.cts +18 -300
- package/dist/index.d.mts +20 -300
- package/dist/index.mjs +16 -342
- package/dist/loader/index.cjs +110 -0
- package/dist/loader/index.d.cts +48 -0
- package/dist/loader/index.d.cts.map +1 -0
- package/dist/loader/index.d.mts +48 -0
- package/dist/loader/index.d.mts.map +1 -0
- package/dist/loader/index.mjs +110 -0
- package/dist/loader/index.mjs.map +1 -0
- package/dist/meta/index.cjs +4 -0
- package/dist/meta/index.mjs +6 -0
- package/dist/meta/kind.cjs +161 -0
- package/dist/meta/kind.d.cts +134 -0
- package/dist/meta/kind.d.cts.map +1 -0
- package/dist/meta/kind.d.mts +134 -0
- package/dist/meta/kind.d.mts.map +1 -0
- package/dist/meta/kind.mjs +157 -0
- package/dist/meta/kind.mjs.map +1 -0
- package/dist/meta/path.cjs +116 -0
- package/dist/meta/path.d.cts +43 -0
- package/dist/meta/path.d.cts.map +1 -0
- package/dist/meta/path.d.mts +43 -0
- package/dist/meta/path.d.mts.map +1 -0
- package/dist/meta/path.mjs +112 -0
- package/dist/meta/path.mjs.map +1 -0
- package/dist/meta/type.d.cts +96 -0
- package/dist/meta/type.d.cts.map +1 -0
- package/dist/meta/type.d.mts +96 -0
- package/dist/meta/type.d.mts.map +1 -0
- package/dist/meta/validation.cjs +77 -0
- package/dist/meta/validation.d.cts +19 -0
- package/dist/meta/validation.d.cts.map +1 -0
- package/dist/meta/validation.d.mts +19 -0
- package/dist/meta/validation.d.mts.map +1 -0
- package/dist/meta/validation.mjs +77 -0
- package/dist/meta/validation.mjs.map +1 -0
- package/dist/meta/well-known-kinds.cjs +228 -0
- package/dist/meta/well-known-kinds.d.cts +52 -0
- package/dist/meta/well-known-kinds.d.cts.map +1 -0
- package/dist/meta/well-known-kinds.d.mts +52 -0
- package/dist/meta/well-known-kinds.d.mts.map +1 -0
- package/dist/meta/well-known-kinds.mjs +219 -0
- package/dist/meta/well-known-kinds.mjs.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts.map +1 -0
- package/dist/path.cjs +255 -0
- package/dist/path.d.cts +93 -0
- package/dist/path.d.cts.map +1 -0
- package/dist/path.d.mts +93 -0
- package/dist/path.d.mts.map +1 -0
- package/dist/path.mjs +249 -0
- package/dist/path.mjs.map +1 -0
- package/dist/provider/base.cjs +425 -0
- package/dist/provider/base.d.cts +175 -0
- package/dist/provider/base.d.cts.map +1 -0
- package/dist/provider/base.d.mts +175 -0
- package/dist/provider/base.d.mts.map +1 -0
- package/dist/provider/base.mjs +426 -0
- package/dist/provider/base.mjs.map +1 -0
- package/dist/provider/decorators.cjs +268 -0
- package/dist/provider/decorators.d.cts +244 -0
- package/dist/provider/decorators.d.cts.map +1 -0
- package/dist/provider/decorators.d.mts +244 -0
- package/dist/provider/decorators.d.mts.map +1 -0
- package/dist/provider/decorators.mjs +256 -0
- package/dist/provider/decorators.mjs.map +1 -0
- package/dist/provider/index.cjs +19 -0
- package/dist/provider/index.d.cts +5 -0
- package/dist/provider/index.d.mts +5 -0
- package/dist/provider/index.mjs +5 -0
- package/dist/provider/router.cjs +185 -0
- package/dist/provider/router.d.cts +50 -0
- package/dist/provider/router.d.cts.map +1 -0
- package/dist/provider/router.d.mts +50 -0
- package/dist/provider/router.d.mts.map +1 -0
- package/dist/provider/router.mjs +185 -0
- package/dist/provider/router.mjs.map +1 -0
- package/dist/provider/types.d.cts +113 -0
- package/dist/provider/types.d.cts.map +1 -0
- package/dist/provider/types.d.mts +113 -0
- package/dist/provider/types.d.mts.map +1 -0
- package/dist/registry.cjs +358 -0
- package/dist/registry.d.cts +96 -0
- package/dist/registry.d.cts.map +1 -0
- package/dist/registry.d.mts +96 -0
- package/dist/registry.d.mts.map +1 -0
- package/dist/registry.mjs +360 -0
- package/dist/registry.mjs.map +1 -0
- package/dist/type.cjs +34 -0
- package/dist/type.d.cts +420 -0
- package/dist/type.d.cts.map +1 -0
- package/dist/type.d.mts +420 -0
- package/dist/type.d.mts.map +1 -0
- package/dist/type.mjs +33 -0
- package/dist/type.mjs.map +1 -0
- package/dist/utils/camelize.d.cts.map +1 -1
- package/dist/utils/camelize.d.mts.map +1 -1
- package/dist/utils/schema.cjs +129 -0
- package/dist/utils/schema.d.cts +65 -0
- package/dist/utils/schema.d.cts.map +1 -0
- package/dist/utils/schema.d.mts +65 -0
- package/dist/utils/schema.d.mts.map +1 -0
- package/dist/utils/schema.mjs +124 -0
- package/dist/utils/schema.mjs.map +1 -0
- package/dist/utils/type-utils.d.cts.map +1 -1
- package/dist/utils/type-utils.d.mts.map +1 -1
- package/dist/utils/uri-template.cjs +123 -0
- package/dist/utils/uri-template.d.cts +48 -0
- package/dist/utils/uri-template.d.cts.map +1 -0
- package/dist/utils/uri-template.d.mts +48 -0
- package/dist/utils/uri-template.d.mts.map +1 -0
- package/dist/utils/uri-template.mjs +120 -0
- package/dist/utils/uri-template.mjs.map +1 -0
- package/dist/utils/uri.cjs +49 -0
- package/dist/utils/uri.d.cts +34 -0
- package/dist/utils/uri.d.cts.map +1 -0
- package/dist/utils/uri.d.mts +34 -0
- package/dist/utils/uri.d.mts.map +1 -0
- package/dist/utils/uri.mjs +49 -0
- package/dist/utils/uri.mjs.map +1 -0
- package/dist/utils/zod.cjs +6 -8
- package/dist/utils/zod.d.cts +2 -2
- package/dist/utils/zod.d.cts.map +1 -1
- package/dist/utils/zod.d.mts +2 -2
- package/dist/utils/zod.d.mts.map +1 -1
- package/dist/utils/zod.mjs +6 -8
- package/dist/utils/zod.mjs.map +1 -1
- package/package.json +27 -4
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/loader/index.ts"],"sourcesContent":["/**\n * AFS Provider Dynamic Loader\n *\n * Provides utilities for dynamically loading AFS providers at runtime.\n *\n * @example\n * ```typescript\n * import { loadProvider, getProviderSchema } from \"@aigne/afs/loader\";\n *\n * // Load a provider with configuration\n * const fs = await loadProvider(\"@aigne/afs-fs\", {\n * config: { localPath: \"./data\" },\n * basePath: \"/path/to/config/dir\"\n * });\n *\n * // Get provider schema for validation\n * const schema = await getProviderSchema(\"@aigne/afs-fs\");\n * ```\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ZodType } from \"zod\";\nimport type { AFSModule, AFSModuleLoadParams } from \"../type.js\";\n\n// Re-export types for convenience\nexport type { AFSModuleLoadParams } from \"../type.js\";\n\n/**\n * Resolve a package specifier to an importable path.\n * If the specifier is a directory path (e.g. from npm install),\n * read its package.json to find the ESM entry point.\n * We must use the ESM (.mjs) entry, not CJS (.cjs), because\n * importing CJS from ESM wraps module.exports in an extra default layer\n * which breaks the expected export shape.\n */\nfunction resolveImportPath(specifier: string): string {\n if (!specifier.startsWith(\"/\")) return specifier;\n\n const pkgJsonPath = join(specifier, \"package.json\");\n if (!existsSync(pkgJsonPath)) return specifier;\n\n try {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n // Prefer ESM entry: exports[\".\"].import > module > main\n const esmEntry = (typeof pkg.exports === \"object\" && pkg.exports[\".\"]?.import) || pkg.module;\n if (esmEntry) return join(specifier, esmEntry);\n // Fallback to main (may be CJS)\n if (pkg.main) return join(specifier, pkg.main);\n } catch {\n // Fall through to use original specifier\n }\n return specifier;\n}\n\n/**\n * Dynamically load an AFS Provider from a package.\n *\n * @param packageName - Package name or subpath (e.g., \"@aigne/afs-fs\" or \"@aigne/afs-cloud/s3\")\n * @param options - Load options (optional)\n * @returns Provider instance\n *\n * @throws Error if package doesn't exist or doesn't export a valid AFS Provider\n *\n * @example\n * ```typescript\n * const fs = await loadProvider(\"@aigne/afs-fs\", {\n * config: { localPath: \"./data\" },\n * basePath: \"/path/to/config/dir\"\n * });\n * ```\n */\nexport async function loadProvider<T extends AFSModule = AFSModule>(\n packageName: string,\n options?: AFSModuleLoadParams,\n): Promise<T> {\n // 1. Dynamic import the package\n const importPath = resolveImportPath(packageName);\n let module: Record<string, unknown>;\n try {\n module = (await import(importPath)) as Record<string, unknown>;\n } catch (error) {\n throw new Error(\n `Failed to import package \"${packageName}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n // 2. Get the default export\n const ProviderClass = module.default as {\n load?: (params: AFSModuleLoadParams) => Promise<T>;\n };\n\n if (!ProviderClass || typeof ProviderClass.load !== \"function\") {\n throw new Error(\n `Package \"${packageName}\" does not export a valid AFS Provider. ` +\n `Expected default export with static load() method.`,\n );\n }\n\n // 3. Call load() to create instance\n return ProviderClass.load(options ?? {});\n}\n\n/**\n * Get the configuration schema for an AFS Provider without creating an instance.\n *\n * Useful for:\n * - Configuration validation\n * - Documentation generation\n * - IDE integration\n *\n * @param packageName - Package name or subpath\n * @returns Zod schema for the provider's configuration\n *\n * @throws Error if package doesn't export schema() method\n *\n * @example\n * ```typescript\n * const schema = await getProviderSchema(\"@aigne/afs-fs\");\n * const result = schema.safeParse(config);\n * if (!result.success) {\n * console.error(result.error);\n * }\n * ```\n */\nexport async function getProviderSchema(packageName: string): Promise<ZodType<unknown>> {\n // Dynamic import the package\n const importPath = resolveImportPath(packageName);\n let module: Record<string, unknown>;\n try {\n module = (await import(importPath)) as Record<string, unknown>;\n } catch (error) {\n throw new Error(\n `Failed to import package \"${packageName}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n const ProviderClass = module.default as {\n schema?: () => ZodType<unknown>;\n };\n\n if (!ProviderClass || typeof ProviderClass.schema !== \"function\") {\n throw new Error(`Package \"${packageName}\" does not export schema() method.`);\n }\n\n return ProviderClass.schema();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAS,kBAAkB,WAA2B;AACpD,KAAI,CAAC,UAAU,WAAW,IAAI,CAAE,QAAO;CAEvC,MAAM,cAAc,KAAK,WAAW,eAAe;AACnD,KAAI,CAAC,WAAW,YAAY,CAAE,QAAO;AAErC,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,aAAa,QAAQ,CAAC;EAE1D,MAAM,WAAY,OAAO,IAAI,YAAY,YAAY,IAAI,QAAQ,MAAM,UAAW,IAAI;AACtF,MAAI,SAAU,QAAO,KAAK,WAAW,SAAS;AAE9C,MAAI,IAAI,KAAM,QAAO,KAAK,WAAW,IAAI,KAAK;SACxC;AAGR,QAAO;;;;;;;;;;;;;;;;;;;AAoBT,eAAsB,aACpB,aACA,SACY;CAEZ,MAAM,aAAa,kBAAkB,YAAY;CACjD,IAAI;AACJ,KAAI;AACF,WAAU,MAAM,OAAO;UAChB,OAAO;AACd,QAAM,IAAI,MACR,6BAA6B,YAAY,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACrG;;CAIH,MAAM,gBAAgB,OAAO;AAI7B,KAAI,CAAC,iBAAiB,OAAO,cAAc,SAAS,WAClD,OAAM,IAAI,MACR,YAAY,YAAY,4FAEzB;AAIH,QAAO,cAAc,KAAK,WAAW,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;AAyB1C,eAAsB,kBAAkB,aAAgD;CAEtF,MAAM,aAAa,kBAAkB,YAAY;CACjD,IAAI;AACJ,KAAI;AACF,WAAU,MAAM,OAAO;UAChB,OAAO;AACd,QAAM,IAAI,MACR,6BAA6B,YAAY,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,GACrG;;CAGH,MAAM,gBAAgB,OAAO;AAI7B,KAAI,CAAC,iBAAiB,OAAO,cAAc,WAAW,WACpD,OAAM,IAAI,MAAM,YAAY,YAAY,oCAAoC;AAG9E,QAAO,cAAc,QAAQ"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { combineValidationResults, validateNodes } from "./validation.mjs";
|
|
2
|
+
import { WELL_KNOWN_KINDS, WELL_KNOWN_KINDS_MAP, afsDocument, afsExecutable, afsImage, afsLink, afsNode, commonMetaSchema, getWellKnownKind, isWellKnownKind } from "./well-known-kinds.mjs";
|
|
3
|
+
import { KindError, createKindResolver, defaultKindResolver, defineKind, getInheritanceChain, resolveKindSchema } from "./kind.mjs";
|
|
4
|
+
import { KINDS_SEGMENT, META_SEGMENT, getNodePathFromMetaPath, isKindsPath, isMetaPath, parseMetaPath } from "./path.mjs";
|
|
5
|
+
|
|
6
|
+
export { };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const require_utils_zod = require('../utils/zod.cjs');
|
|
2
|
+
const require_validation = require('./validation.cjs');
|
|
3
|
+
const require_well_known_kinds = require('./well-known-kinds.cjs');
|
|
4
|
+
let zod_from_json_schema = require("zod-from-json-schema");
|
|
5
|
+
|
|
6
|
+
//#region src/meta/kind.ts
|
|
7
|
+
/**
|
|
8
|
+
* Default kind resolver that only knows about well-known kinds.
|
|
9
|
+
* Providers should supply their own resolver that includes their kinds.
|
|
10
|
+
*/
|
|
11
|
+
const defaultKindResolver = (name) => {
|
|
12
|
+
return require_well_known_kinds.WELL_KNOWN_KINDS_MAP.get(name);
|
|
13
|
+
};
|
|
14
|
+
const zodSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
/**
|
|
16
|
+
* Convert JSON Schema to Zod schema with caching.
|
|
17
|
+
*/
|
|
18
|
+
function getZodSchema(jsonSchema) {
|
|
19
|
+
let zodSchema = zodSchemaCache.get(jsonSchema);
|
|
20
|
+
if (!zodSchema) {
|
|
21
|
+
zodSchema = (0, zod_from_json_schema.convertJsonSchemaToZod)(jsonSchema);
|
|
22
|
+
zodSchemaCache.set(jsonSchema, zodSchema);
|
|
23
|
+
}
|
|
24
|
+
return zodSchema;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Define a new Kind with validation capabilities.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const projectKind = defineKind({
|
|
32
|
+
* name: "chamber:project",
|
|
33
|
+
* extends: "afs:node",
|
|
34
|
+
* description: "A project directory",
|
|
35
|
+
* meta: {
|
|
36
|
+
* type: "object",
|
|
37
|
+
* properties: {
|
|
38
|
+
* name: { type: "string" },
|
|
39
|
+
* status: { type: "string", enum: ["active", "archived"] },
|
|
40
|
+
* },
|
|
41
|
+
* required: ["name"],
|
|
42
|
+
* },
|
|
43
|
+
* nodes: {
|
|
44
|
+
* required: [{ path: "src" }],
|
|
45
|
+
* optional: [{ path: "*.md" }],
|
|
46
|
+
* },
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Validate meta (includes parent validation)
|
|
50
|
+
* const result = projectKind.validate({ name: "My Project", status: "active" });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function defineKind(definition) {
|
|
54
|
+
const schema = {
|
|
55
|
+
name: definition.name,
|
|
56
|
+
extends: definition.extends,
|
|
57
|
+
description: definition.description,
|
|
58
|
+
meta: definition.meta,
|
|
59
|
+
nodes: definition.nodes
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
schema,
|
|
63
|
+
name: definition.name,
|
|
64
|
+
extends: definition.extends,
|
|
65
|
+
validate(meta, resolver = defaultKindResolver) {
|
|
66
|
+
const chain = this.getInheritanceChain(resolver);
|
|
67
|
+
const errors = [];
|
|
68
|
+
for (const kindSchema of chain) if (kindSchema.meta) try {
|
|
69
|
+
require_utils_zod.zodParse(getZodSchema(kindSchema.meta), meta, { prefix: kindSchema.name });
|
|
70
|
+
} catch (err) {
|
|
71
|
+
errors.push({
|
|
72
|
+
path: "",
|
|
73
|
+
message: err instanceof Error ? err.message : String(err),
|
|
74
|
+
code: "VALIDATION_ERROR"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
valid: errors.length === 0,
|
|
79
|
+
errors
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
validateNodes(basePath, nodeNames) {
|
|
83
|
+
return require_validation.validateNodes(basePath, nodeNames, schema.nodes);
|
|
84
|
+
},
|
|
85
|
+
getInheritanceChain(resolver = defaultKindResolver) {
|
|
86
|
+
return getInheritanceChain(schema, resolver);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get the inheritance chain from root ancestor to the given kind.
|
|
92
|
+
*
|
|
93
|
+
* @param kind - The kind to get inheritance chain for
|
|
94
|
+
* @param resolver - Function to resolve kind by name
|
|
95
|
+
* @returns Array of KindSchema from root to leaf (inclusive)
|
|
96
|
+
* @throws Error if circular inheritance is detected or parent not found
|
|
97
|
+
*/
|
|
98
|
+
function getInheritanceChain(kind, resolver = defaultKindResolver) {
|
|
99
|
+
const chain = [];
|
|
100
|
+
const visited = /* @__PURE__ */ new Set();
|
|
101
|
+
let current = kind;
|
|
102
|
+
while (current) {
|
|
103
|
+
if (visited.has(current.name)) throw new Error(`Circular inheritance detected: ${current.name}`);
|
|
104
|
+
visited.add(current.name);
|
|
105
|
+
chain.unshift(current);
|
|
106
|
+
if (!current.extends) break;
|
|
107
|
+
current = resolver(current.extends);
|
|
108
|
+
if (!current) throw new Error(`Parent kind not found: "${kind.extends}" (extended by "${kind.name}")`);
|
|
109
|
+
}
|
|
110
|
+
return chain;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a kind resolver that includes provider kinds and well-known kinds.
|
|
114
|
+
*
|
|
115
|
+
* @param providerKinds - Kinds defined by the provider
|
|
116
|
+
* @returns A resolver function
|
|
117
|
+
*/
|
|
118
|
+
function createKindResolver(providerKinds) {
|
|
119
|
+
const providerMap = new Map(providerKinds.map((k) => [k.name, k]));
|
|
120
|
+
return (name) => {
|
|
121
|
+
const providerKind = providerMap.get(name);
|
|
122
|
+
if (providerKind) return providerKind;
|
|
123
|
+
return require_well_known_kinds.WELL_KNOWN_KINDS_MAP.get(name);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Error thrown when kind resolution fails.
|
|
128
|
+
*/
|
|
129
|
+
var KindError = class extends Error {
|
|
130
|
+
constructor(message, kindName) {
|
|
131
|
+
super(message);
|
|
132
|
+
this.kindName = kindName;
|
|
133
|
+
this.name = "KindError";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Resolve a kind name to its KindSchema.
|
|
138
|
+
*
|
|
139
|
+
* Looks up the kind in provider kinds first, then falls back to well-known kinds.
|
|
140
|
+
*
|
|
141
|
+
* @param kindName - The name of the kind to resolve (e.g., "afs:node", "chamber:project")
|
|
142
|
+
* @param providerKinds - Optional array of kinds defined by the provider
|
|
143
|
+
* @returns The resolved KindSchema, or undefined if not found
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const nodeKind = resolveKindSchema("afs:node");
|
|
148
|
+
* const projectKind = resolveKindSchema("chamber:project", providerKinds);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
function resolveKindSchema(kindName, providerKinds) {
|
|
152
|
+
return (providerKinds ? createKindResolver(providerKinds) : defaultKindResolver)(kindName);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
exports.KindError = KindError;
|
|
157
|
+
exports.createKindResolver = createKindResolver;
|
|
158
|
+
exports.defaultKindResolver = defaultKindResolver;
|
|
159
|
+
exports.defineKind = defineKind;
|
|
160
|
+
exports.getInheritanceChain = getInheritanceChain;
|
|
161
|
+
exports.resolveKindSchema = resolveKindSchema;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { JSONSchema7 } from "../node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.cjs";
|
|
2
|
+
import { KindSchema, NodesConstraints, ValidationResult } from "./type.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/meta/kind.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Input for defineKind function.
|
|
7
|
+
*/
|
|
8
|
+
interface KindDefinition {
|
|
9
|
+
/** Unique name in format "provider:kind" */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Parent kind name for inheritance */
|
|
12
|
+
extends?: string;
|
|
13
|
+
/** Human-readable description */
|
|
14
|
+
description?: string;
|
|
15
|
+
/** Meta schema in JSON Schema format */
|
|
16
|
+
meta?: JSONSchema7;
|
|
17
|
+
/** Child node structure constraints */
|
|
18
|
+
nodes?: NodesConstraints;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A defined Kind with validation capabilities.
|
|
22
|
+
*/
|
|
23
|
+
interface Kind {
|
|
24
|
+
/** The underlying schema */
|
|
25
|
+
readonly schema: KindSchema;
|
|
26
|
+
/** Kind name */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** Parent kind name */
|
|
29
|
+
readonly extends?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Validate meta data against this kind and all ancestors.
|
|
32
|
+
* Performs layer-by-layer validation from root to leaf.
|
|
33
|
+
*
|
|
34
|
+
* @param meta - Meta data to validate
|
|
35
|
+
* @param resolver - Function to resolve kind by name (for inheritance)
|
|
36
|
+
* @returns Validation result with all errors from all layers
|
|
37
|
+
*/
|
|
38
|
+
validate(meta: unknown, resolver?: KindResolver): ValidationResult;
|
|
39
|
+
/**
|
|
40
|
+
* Validate node structure against this kind's nodes constraints.
|
|
41
|
+
*
|
|
42
|
+
* @param basePath - Base path for error reporting (e.g., "/project")
|
|
43
|
+
* @param nodeNames - List of node names in the directory
|
|
44
|
+
* @returns Validation result
|
|
45
|
+
*/
|
|
46
|
+
validateNodes(basePath: string, nodeNames: string[]): ValidationResult;
|
|
47
|
+
/**
|
|
48
|
+
* Get the inheritance chain from root to this kind.
|
|
49
|
+
*
|
|
50
|
+
* @param resolver - Function to resolve kind by name
|
|
51
|
+
* @returns Array of KindSchema from root ancestor to this kind
|
|
52
|
+
*/
|
|
53
|
+
getInheritanceChain(resolver?: KindResolver): KindSchema[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Function type for resolving a kind by name.
|
|
57
|
+
* Used for looking up parent kinds during inheritance resolution.
|
|
58
|
+
*/
|
|
59
|
+
type KindResolver = (name: string) => KindSchema | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Default kind resolver that only knows about well-known kinds.
|
|
62
|
+
* Providers should supply their own resolver that includes their kinds.
|
|
63
|
+
*/
|
|
64
|
+
declare const defaultKindResolver: KindResolver;
|
|
65
|
+
/**
|
|
66
|
+
* Define a new Kind with validation capabilities.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const projectKind = defineKind({
|
|
71
|
+
* name: "chamber:project",
|
|
72
|
+
* extends: "afs:node",
|
|
73
|
+
* description: "A project directory",
|
|
74
|
+
* meta: {
|
|
75
|
+
* type: "object",
|
|
76
|
+
* properties: {
|
|
77
|
+
* name: { type: "string" },
|
|
78
|
+
* status: { type: "string", enum: ["active", "archived"] },
|
|
79
|
+
* },
|
|
80
|
+
* required: ["name"],
|
|
81
|
+
* },
|
|
82
|
+
* nodes: {
|
|
83
|
+
* required: [{ path: "src" }],
|
|
84
|
+
* optional: [{ path: "*.md" }],
|
|
85
|
+
* },
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* // Validate meta (includes parent validation)
|
|
89
|
+
* const result = projectKind.validate({ name: "My Project", status: "active" });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function defineKind(definition: KindDefinition): Kind;
|
|
93
|
+
/**
|
|
94
|
+
* Get the inheritance chain from root ancestor to the given kind.
|
|
95
|
+
*
|
|
96
|
+
* @param kind - The kind to get inheritance chain for
|
|
97
|
+
* @param resolver - Function to resolve kind by name
|
|
98
|
+
* @returns Array of KindSchema from root to leaf (inclusive)
|
|
99
|
+
* @throws Error if circular inheritance is detected or parent not found
|
|
100
|
+
*/
|
|
101
|
+
declare function getInheritanceChain(kind: KindSchema, resolver?: KindResolver): KindSchema[];
|
|
102
|
+
/**
|
|
103
|
+
* Create a kind resolver that includes provider kinds and well-known kinds.
|
|
104
|
+
*
|
|
105
|
+
* @param providerKinds - Kinds defined by the provider
|
|
106
|
+
* @returns A resolver function
|
|
107
|
+
*/
|
|
108
|
+
declare function createKindResolver(providerKinds: KindSchema[]): KindResolver;
|
|
109
|
+
/**
|
|
110
|
+
* Error thrown when kind resolution fails.
|
|
111
|
+
*/
|
|
112
|
+
declare class KindError extends Error {
|
|
113
|
+
readonly kindName: string;
|
|
114
|
+
constructor(message: string, kindName: string);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve a kind name to its KindSchema.
|
|
118
|
+
*
|
|
119
|
+
* Looks up the kind in provider kinds first, then falls back to well-known kinds.
|
|
120
|
+
*
|
|
121
|
+
* @param kindName - The name of the kind to resolve (e.g., "afs:node", "chamber:project")
|
|
122
|
+
* @param providerKinds - Optional array of kinds defined by the provider
|
|
123
|
+
* @returns The resolved KindSchema, or undefined if not found
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const nodeKind = resolveKindSchema("afs:node");
|
|
128
|
+
* const projectKind = resolveKindSchema("chamber:project", providerKinds);
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
declare function resolveKindSchema(kindName: string, providerKinds?: KindSchema[]): KindSchema | undefined;
|
|
132
|
+
//#endregion
|
|
133
|
+
export { Kind, KindDefinition, KindError, KindResolver, createKindResolver, defaultKindResolver, defineKind, getInheritanceChain, resolveKindSchema };
|
|
134
|
+
//# sourceMappingURL=kind.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind.d.cts","names":[],"sources":["../../src/meta/kind.ts"],"mappings":";;;;;;;UAyBiB,cAAA;EAUS;EARxB,IAAA;EAce;EAZf,OAAA;;EAEA,WAAA;EA4BmC;EA1BnC,IAAA,GAAO,WAAA;EAmC+C;EAjCtD,KAAA,GAAQ,gBAAA;AAAA;;;;UAMO,IAAA;EAKN;EAAA,SAHA,MAAA,EAAQ,UAAA;EAgBjB;EAAA,SAbS,IAAA;EAa0B;EAAA,SAV1B,OAAA;EAUyC;;;;;;;;EAAlD,QAAA,CAAS,IAAA,WAAe,QAAA,GAAW,YAAA,GAAe,gBAAA;EAiBM;;AAO1D;;;;;EAfE,aAAA,CAAc,QAAA,UAAkB,SAAA,aAAsB,gBAAA;EA2BvD;;;;AAmDD;;EAtEE,mBAAA,CAAoB,QAAA,GAAW,YAAA,GAAe,UAAA;AAAA;;;;;KAOpC,YAAA,IAAgB,IAAA,aAAiB,UAAA;AAyH7C;;;;AAAA,cA/Ga,mBAAA,EAAqB,YAAA;;;;;;;;;;;AAkJlC;;;;;;;;;AAqBA;;;;;;;;iBAlHgB,UAAA,CAAW,UAAA,EAAY,cAAA,GAAiB,IAAA;;;AA2IxD;;;;;;iBAjFgB,mBAAA,CACd,IAAA,EAAM,UAAA,EACN,QAAA,GAAU,YAAA,GACT,UAAA;;;;;;;iBAgCa,kBAAA,CAAmB,aAAA,EAAe,UAAA,KAAe,YAAA;;;;cAqBpD,SAAA,SAAkB,KAAA;EAAA,SAGX,QAAA;cADhB,OAAA,UACgB,QAAA;AAAA;;;;;;;;;;;;;;;;iBAsBJ,iBAAA,CACd,QAAA,UACA,aAAA,GAAgB,UAAA,KACf,UAAA"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { JSONSchema7 } from "../node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.mjs";
|
|
2
|
+
import { KindSchema, NodesConstraints, ValidationResult } from "./type.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/meta/kind.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Input for defineKind function.
|
|
7
|
+
*/
|
|
8
|
+
interface KindDefinition {
|
|
9
|
+
/** Unique name in format "provider:kind" */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Parent kind name for inheritance */
|
|
12
|
+
extends?: string;
|
|
13
|
+
/** Human-readable description */
|
|
14
|
+
description?: string;
|
|
15
|
+
/** Meta schema in JSON Schema format */
|
|
16
|
+
meta?: JSONSchema7;
|
|
17
|
+
/** Child node structure constraints */
|
|
18
|
+
nodes?: NodesConstraints;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A defined Kind with validation capabilities.
|
|
22
|
+
*/
|
|
23
|
+
interface Kind {
|
|
24
|
+
/** The underlying schema */
|
|
25
|
+
readonly schema: KindSchema;
|
|
26
|
+
/** Kind name */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** Parent kind name */
|
|
29
|
+
readonly extends?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Validate meta data against this kind and all ancestors.
|
|
32
|
+
* Performs layer-by-layer validation from root to leaf.
|
|
33
|
+
*
|
|
34
|
+
* @param meta - Meta data to validate
|
|
35
|
+
* @param resolver - Function to resolve kind by name (for inheritance)
|
|
36
|
+
* @returns Validation result with all errors from all layers
|
|
37
|
+
*/
|
|
38
|
+
validate(meta: unknown, resolver?: KindResolver): ValidationResult;
|
|
39
|
+
/**
|
|
40
|
+
* Validate node structure against this kind's nodes constraints.
|
|
41
|
+
*
|
|
42
|
+
* @param basePath - Base path for error reporting (e.g., "/project")
|
|
43
|
+
* @param nodeNames - List of node names in the directory
|
|
44
|
+
* @returns Validation result
|
|
45
|
+
*/
|
|
46
|
+
validateNodes(basePath: string, nodeNames: string[]): ValidationResult;
|
|
47
|
+
/**
|
|
48
|
+
* Get the inheritance chain from root to this kind.
|
|
49
|
+
*
|
|
50
|
+
* @param resolver - Function to resolve kind by name
|
|
51
|
+
* @returns Array of KindSchema from root ancestor to this kind
|
|
52
|
+
*/
|
|
53
|
+
getInheritanceChain(resolver?: KindResolver): KindSchema[];
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Function type for resolving a kind by name.
|
|
57
|
+
* Used for looking up parent kinds during inheritance resolution.
|
|
58
|
+
*/
|
|
59
|
+
type KindResolver = (name: string) => KindSchema | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Default kind resolver that only knows about well-known kinds.
|
|
62
|
+
* Providers should supply their own resolver that includes their kinds.
|
|
63
|
+
*/
|
|
64
|
+
declare const defaultKindResolver: KindResolver;
|
|
65
|
+
/**
|
|
66
|
+
* Define a new Kind with validation capabilities.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const projectKind = defineKind({
|
|
71
|
+
* name: "chamber:project",
|
|
72
|
+
* extends: "afs:node",
|
|
73
|
+
* description: "A project directory",
|
|
74
|
+
* meta: {
|
|
75
|
+
* type: "object",
|
|
76
|
+
* properties: {
|
|
77
|
+
* name: { type: "string" },
|
|
78
|
+
* status: { type: "string", enum: ["active", "archived"] },
|
|
79
|
+
* },
|
|
80
|
+
* required: ["name"],
|
|
81
|
+
* },
|
|
82
|
+
* nodes: {
|
|
83
|
+
* required: [{ path: "src" }],
|
|
84
|
+
* optional: [{ path: "*.md" }],
|
|
85
|
+
* },
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* // Validate meta (includes parent validation)
|
|
89
|
+
* const result = projectKind.validate({ name: "My Project", status: "active" });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function defineKind(definition: KindDefinition): Kind;
|
|
93
|
+
/**
|
|
94
|
+
* Get the inheritance chain from root ancestor to the given kind.
|
|
95
|
+
*
|
|
96
|
+
* @param kind - The kind to get inheritance chain for
|
|
97
|
+
* @param resolver - Function to resolve kind by name
|
|
98
|
+
* @returns Array of KindSchema from root to leaf (inclusive)
|
|
99
|
+
* @throws Error if circular inheritance is detected or parent not found
|
|
100
|
+
*/
|
|
101
|
+
declare function getInheritanceChain(kind: KindSchema, resolver?: KindResolver): KindSchema[];
|
|
102
|
+
/**
|
|
103
|
+
* Create a kind resolver that includes provider kinds and well-known kinds.
|
|
104
|
+
*
|
|
105
|
+
* @param providerKinds - Kinds defined by the provider
|
|
106
|
+
* @returns A resolver function
|
|
107
|
+
*/
|
|
108
|
+
declare function createKindResolver(providerKinds: KindSchema[]): KindResolver;
|
|
109
|
+
/**
|
|
110
|
+
* Error thrown when kind resolution fails.
|
|
111
|
+
*/
|
|
112
|
+
declare class KindError extends Error {
|
|
113
|
+
readonly kindName: string;
|
|
114
|
+
constructor(message: string, kindName: string);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve a kind name to its KindSchema.
|
|
118
|
+
*
|
|
119
|
+
* Looks up the kind in provider kinds first, then falls back to well-known kinds.
|
|
120
|
+
*
|
|
121
|
+
* @param kindName - The name of the kind to resolve (e.g., "afs:node", "chamber:project")
|
|
122
|
+
* @param providerKinds - Optional array of kinds defined by the provider
|
|
123
|
+
* @returns The resolved KindSchema, or undefined if not found
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const nodeKind = resolveKindSchema("afs:node");
|
|
128
|
+
* const projectKind = resolveKindSchema("chamber:project", providerKinds);
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
declare function resolveKindSchema(kindName: string, providerKinds?: KindSchema[]): KindSchema | undefined;
|
|
132
|
+
//#endregion
|
|
133
|
+
export { Kind, KindDefinition, KindError, KindResolver, createKindResolver, defaultKindResolver, defineKind, getInheritanceChain, resolveKindSchema };
|
|
134
|
+
//# sourceMappingURL=kind.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind.d.mts","names":[],"sources":["../../src/meta/kind.ts"],"mappings":";;;;;;;UAyBiB,cAAA;EAUS;EARxB,IAAA;EAce;EAZf,OAAA;;EAEA,WAAA;EA4BmC;EA1BnC,IAAA,GAAO,WAAA;EAmC+C;EAjCtD,KAAA,GAAQ,gBAAA;AAAA;;;;UAMO,IAAA;EAKN;EAAA,SAHA,MAAA,EAAQ,UAAA;EAgBjB;EAAA,SAbS,IAAA;EAa0B;EAAA,SAV1B,OAAA;EAUyC;;;;;;;;EAAlD,QAAA,CAAS,IAAA,WAAe,QAAA,GAAW,YAAA,GAAe,gBAAA;EAiBM;;AAO1D;;;;;EAfE,aAAA,CAAc,QAAA,UAAkB,SAAA,aAAsB,gBAAA;EA2BvD;;;;AAmDD;;EAtEE,mBAAA,CAAoB,QAAA,GAAW,YAAA,GAAe,UAAA;AAAA;;;;;KAOpC,YAAA,IAAgB,IAAA,aAAiB,UAAA;AAyH7C;;;;AAAA,cA/Ga,mBAAA,EAAqB,YAAA;;;;;;;;;;;AAkJlC;;;;;;;;;AAqBA;;;;;;;;iBAlHgB,UAAA,CAAW,UAAA,EAAY,cAAA,GAAiB,IAAA;;;AA2IxD;;;;;;iBAjFgB,mBAAA,CACd,IAAA,EAAM,UAAA,EACN,QAAA,GAAU,YAAA,GACT,UAAA;;;;;;;iBAgCa,kBAAA,CAAmB,aAAA,EAAe,UAAA,KAAe,YAAA;;;;cAqBpD,SAAA,SAAkB,KAAA;EAAA,SAGX,QAAA;cADhB,OAAA,UACgB,QAAA;AAAA;;;;;;;;;;;;;;;;iBAsBJ,iBAAA,CACd,QAAA,UACA,aAAA,GAAgB,UAAA,KACf,UAAA"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { zodParse } from "../utils/zod.mjs";
|
|
2
|
+
import { validateNodes } from "./validation.mjs";
|
|
3
|
+
import { WELL_KNOWN_KINDS_MAP } from "./well-known-kinds.mjs";
|
|
4
|
+
import { convertJsonSchemaToZod } from "zod-from-json-schema";
|
|
5
|
+
|
|
6
|
+
//#region src/meta/kind.ts
|
|
7
|
+
/**
|
|
8
|
+
* Default kind resolver that only knows about well-known kinds.
|
|
9
|
+
* Providers should supply their own resolver that includes their kinds.
|
|
10
|
+
*/
|
|
11
|
+
const defaultKindResolver = (name) => {
|
|
12
|
+
return WELL_KNOWN_KINDS_MAP.get(name);
|
|
13
|
+
};
|
|
14
|
+
const zodSchemaCache = /* @__PURE__ */ new WeakMap();
|
|
15
|
+
/**
|
|
16
|
+
* Convert JSON Schema to Zod schema with caching.
|
|
17
|
+
*/
|
|
18
|
+
function getZodSchema(jsonSchema) {
|
|
19
|
+
let zodSchema = zodSchemaCache.get(jsonSchema);
|
|
20
|
+
if (!zodSchema) {
|
|
21
|
+
zodSchema = convertJsonSchemaToZod(jsonSchema);
|
|
22
|
+
zodSchemaCache.set(jsonSchema, zodSchema);
|
|
23
|
+
}
|
|
24
|
+
return zodSchema;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Define a new Kind with validation capabilities.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const projectKind = defineKind({
|
|
32
|
+
* name: "chamber:project",
|
|
33
|
+
* extends: "afs:node",
|
|
34
|
+
* description: "A project directory",
|
|
35
|
+
* meta: {
|
|
36
|
+
* type: "object",
|
|
37
|
+
* properties: {
|
|
38
|
+
* name: { type: "string" },
|
|
39
|
+
* status: { type: "string", enum: ["active", "archived"] },
|
|
40
|
+
* },
|
|
41
|
+
* required: ["name"],
|
|
42
|
+
* },
|
|
43
|
+
* nodes: {
|
|
44
|
+
* required: [{ path: "src" }],
|
|
45
|
+
* optional: [{ path: "*.md" }],
|
|
46
|
+
* },
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // Validate meta (includes parent validation)
|
|
50
|
+
* const result = projectKind.validate({ name: "My Project", status: "active" });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
function defineKind(definition) {
|
|
54
|
+
const schema = {
|
|
55
|
+
name: definition.name,
|
|
56
|
+
extends: definition.extends,
|
|
57
|
+
description: definition.description,
|
|
58
|
+
meta: definition.meta,
|
|
59
|
+
nodes: definition.nodes
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
schema,
|
|
63
|
+
name: definition.name,
|
|
64
|
+
extends: definition.extends,
|
|
65
|
+
validate(meta, resolver = defaultKindResolver) {
|
|
66
|
+
const chain = this.getInheritanceChain(resolver);
|
|
67
|
+
const errors = [];
|
|
68
|
+
for (const kindSchema of chain) if (kindSchema.meta) try {
|
|
69
|
+
zodParse(getZodSchema(kindSchema.meta), meta, { prefix: kindSchema.name });
|
|
70
|
+
} catch (err) {
|
|
71
|
+
errors.push({
|
|
72
|
+
path: "",
|
|
73
|
+
message: err instanceof Error ? err.message : String(err),
|
|
74
|
+
code: "VALIDATION_ERROR"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
valid: errors.length === 0,
|
|
79
|
+
errors
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
validateNodes(basePath, nodeNames) {
|
|
83
|
+
return validateNodes(basePath, nodeNames, schema.nodes);
|
|
84
|
+
},
|
|
85
|
+
getInheritanceChain(resolver = defaultKindResolver) {
|
|
86
|
+
return getInheritanceChain(schema, resolver);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get the inheritance chain from root ancestor to the given kind.
|
|
92
|
+
*
|
|
93
|
+
* @param kind - The kind to get inheritance chain for
|
|
94
|
+
* @param resolver - Function to resolve kind by name
|
|
95
|
+
* @returns Array of KindSchema from root to leaf (inclusive)
|
|
96
|
+
* @throws Error if circular inheritance is detected or parent not found
|
|
97
|
+
*/
|
|
98
|
+
function getInheritanceChain(kind, resolver = defaultKindResolver) {
|
|
99
|
+
const chain = [];
|
|
100
|
+
const visited = /* @__PURE__ */ new Set();
|
|
101
|
+
let current = kind;
|
|
102
|
+
while (current) {
|
|
103
|
+
if (visited.has(current.name)) throw new Error(`Circular inheritance detected: ${current.name}`);
|
|
104
|
+
visited.add(current.name);
|
|
105
|
+
chain.unshift(current);
|
|
106
|
+
if (!current.extends) break;
|
|
107
|
+
current = resolver(current.extends);
|
|
108
|
+
if (!current) throw new Error(`Parent kind not found: "${kind.extends}" (extended by "${kind.name}")`);
|
|
109
|
+
}
|
|
110
|
+
return chain;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a kind resolver that includes provider kinds and well-known kinds.
|
|
114
|
+
*
|
|
115
|
+
* @param providerKinds - Kinds defined by the provider
|
|
116
|
+
* @returns A resolver function
|
|
117
|
+
*/
|
|
118
|
+
function createKindResolver(providerKinds) {
|
|
119
|
+
const providerMap = new Map(providerKinds.map((k) => [k.name, k]));
|
|
120
|
+
return (name) => {
|
|
121
|
+
const providerKind = providerMap.get(name);
|
|
122
|
+
if (providerKind) return providerKind;
|
|
123
|
+
return WELL_KNOWN_KINDS_MAP.get(name);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Error thrown when kind resolution fails.
|
|
128
|
+
*/
|
|
129
|
+
var KindError = class extends Error {
|
|
130
|
+
constructor(message, kindName) {
|
|
131
|
+
super(message);
|
|
132
|
+
this.kindName = kindName;
|
|
133
|
+
this.name = "KindError";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Resolve a kind name to its KindSchema.
|
|
138
|
+
*
|
|
139
|
+
* Looks up the kind in provider kinds first, then falls back to well-known kinds.
|
|
140
|
+
*
|
|
141
|
+
* @param kindName - The name of the kind to resolve (e.g., "afs:node", "chamber:project")
|
|
142
|
+
* @param providerKinds - Optional array of kinds defined by the provider
|
|
143
|
+
* @returns The resolved KindSchema, or undefined if not found
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const nodeKind = resolveKindSchema("afs:node");
|
|
148
|
+
* const projectKind = resolveKindSchema("chamber:project", providerKinds);
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
function resolveKindSchema(kindName, providerKinds) {
|
|
152
|
+
return (providerKinds ? createKindResolver(providerKinds) : defaultKindResolver)(kindName);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
export { KindError, createKindResolver, defaultKindResolver, defineKind, getInheritanceChain, resolveKindSchema };
|
|
157
|
+
//# sourceMappingURL=kind.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind.mjs","names":[],"sources":["../../src/meta/kind.ts"],"sourcesContent":["/**\n * Kind System - defineKind API with layer-by-layer validation\n *\n * Provides:\n * - defineKind() function for creating Kind definitions\n * - Layer-by-layer validation (validates each ancestor separately)\n * - Inheritance chain resolution\n *\n * Uses zod-from-json-schema for runtime JSON Schema to Zod conversion.\n */\n\nimport type { ZodType } from \"zod\";\nimport { convertJsonSchemaToZod } from \"zod-from-json-schema\";\nimport { zodParse } from \"../utils/zod.js\";\nimport type { JSONSchema7, KindSchema, NodesConstraints, ValidationResult } from \"./type.js\";\nimport { validateNodes } from \"./validation.js\";\nimport { WELL_KNOWN_KINDS_MAP } from \"./well-known-kinds.js\";\n\n// =============================================================================\n// Kind definition and instance types\n// =============================================================================\n\n/**\n * Input for defineKind function.\n */\nexport interface KindDefinition {\n /** Unique name in format \"provider:kind\" */\n name: string;\n /** Parent kind name for inheritance */\n extends?: string;\n /** Human-readable description */\n description?: string;\n /** Meta schema in JSON Schema format */\n meta?: JSONSchema7;\n /** Child node structure constraints */\n nodes?: NodesConstraints;\n}\n\n/**\n * A defined Kind with validation capabilities.\n */\nexport interface Kind {\n /** The underlying schema */\n readonly schema: KindSchema;\n\n /** Kind name */\n readonly name: string;\n\n /** Parent kind name */\n readonly extends?: string;\n\n /**\n * Validate meta data against this kind and all ancestors.\n * Performs layer-by-layer validation from root to leaf.\n *\n * @param meta - Meta data to validate\n * @param resolver - Function to resolve kind by name (for inheritance)\n * @returns Validation result with all errors from all layers\n */\n validate(meta: unknown, resolver?: KindResolver): ValidationResult;\n\n /**\n * Validate node structure against this kind's nodes constraints.\n *\n * @param basePath - Base path for error reporting (e.g., \"/project\")\n * @param nodeNames - List of node names in the directory\n * @returns Validation result\n */\n validateNodes(basePath: string, nodeNames: string[]): ValidationResult;\n\n /**\n * Get the inheritance chain from root to this kind.\n *\n * @param resolver - Function to resolve kind by name\n * @returns Array of KindSchema from root ancestor to this kind\n */\n getInheritanceChain(resolver?: KindResolver): KindSchema[];\n}\n\n/**\n * Function type for resolving a kind by name.\n * Used for looking up parent kinds during inheritance resolution.\n */\nexport type KindResolver = (name: string) => KindSchema | undefined;\n\n// =============================================================================\n// Default resolver (uses well-known kinds)\n// =============================================================================\n\n/**\n * Default kind resolver that only knows about well-known kinds.\n * Providers should supply their own resolver that includes their kinds.\n */\nexport const defaultKindResolver: KindResolver = (name: string) => {\n return WELL_KNOWN_KINDS_MAP.get(name);\n};\n\n// =============================================================================\n// Schema cache for performance\n// =============================================================================\n\nconst zodSchemaCache = new WeakMap<JSONSchema7, ZodType>();\n\n/**\n * Convert JSON Schema to Zod schema with caching.\n */\nfunction getZodSchema(jsonSchema: JSONSchema7): ZodType {\n let zodSchema = zodSchemaCache.get(jsonSchema);\n if (!zodSchema) {\n zodSchema = convertJsonSchemaToZod(jsonSchema as any);\n zodSchemaCache.set(jsonSchema, zodSchema);\n }\n return zodSchema;\n}\n\n// =============================================================================\n// defineKind implementation\n// =============================================================================\n\n/**\n * Define a new Kind with validation capabilities.\n *\n * @example\n * ```typescript\n * const projectKind = defineKind({\n * name: \"chamber:project\",\n * extends: \"afs:node\",\n * description: \"A project directory\",\n * meta: {\n * type: \"object\",\n * properties: {\n * name: { type: \"string\" },\n * status: { type: \"string\", enum: [\"active\", \"archived\"] },\n * },\n * required: [\"name\"],\n * },\n * nodes: {\n * required: [{ path: \"src\" }],\n * optional: [{ path: \"*.md\" }],\n * },\n * });\n *\n * // Validate meta (includes parent validation)\n * const result = projectKind.validate({ name: \"My Project\", status: \"active\" });\n * ```\n */\nexport function defineKind(definition: KindDefinition): Kind {\n const schema: KindSchema = {\n name: definition.name,\n extends: definition.extends,\n description: definition.description,\n meta: definition.meta,\n nodes: definition.nodes,\n };\n\n return {\n schema,\n name: definition.name,\n extends: definition.extends,\n\n validate(meta: unknown, resolver: KindResolver = defaultKindResolver): ValidationResult {\n const chain = this.getInheritanceChain(resolver);\n const errors: ValidationResult[\"errors\"] = [];\n\n // Validate each layer from root to leaf\n for (const kindSchema of chain) {\n if (kindSchema.meta) {\n try {\n zodParse(getZodSchema(kindSchema.meta), meta, { prefix: kindSchema.name });\n } catch (err) {\n errors.push({\n path: \"\",\n message: err instanceof Error ? err.message : String(err),\n code: \"VALIDATION_ERROR\",\n });\n }\n }\n }\n\n return { valid: errors.length === 0, errors };\n },\n\n validateNodes(basePath: string, nodeNames: string[]): ValidationResult {\n return validateNodes(basePath, nodeNames, schema.nodes);\n },\n\n getInheritanceChain(resolver: KindResolver = defaultKindResolver): KindSchema[] {\n return getInheritanceChain(schema, resolver);\n },\n };\n}\n\n// =============================================================================\n// Inheritance helpers\n// =============================================================================\n\n/**\n * Get the inheritance chain from root ancestor to the given kind.\n *\n * @param kind - The kind to get inheritance chain for\n * @param resolver - Function to resolve kind by name\n * @returns Array of KindSchema from root to leaf (inclusive)\n * @throws Error if circular inheritance is detected or parent not found\n */\nexport function getInheritanceChain(\n kind: KindSchema,\n resolver: KindResolver = defaultKindResolver,\n): KindSchema[] {\n const chain: KindSchema[] = [];\n const visited = new Set<string>();\n let current: KindSchema | undefined = kind;\n\n // Walk up the inheritance tree\n while (current) {\n if (visited.has(current.name)) {\n throw new Error(`Circular inheritance detected: ${current.name}`);\n }\n visited.add(current.name);\n chain.unshift(current); // Add to front (we're walking up)\n\n if (!current.extends) {\n break;\n }\n\n current = resolver(current.extends);\n if (!current) {\n throw new Error(`Parent kind not found: \"${kind.extends}\" (extended by \"${kind.name}\")`);\n }\n }\n\n return chain;\n}\n\n/**\n * Create a kind resolver that includes provider kinds and well-known kinds.\n *\n * @param providerKinds - Kinds defined by the provider\n * @returns A resolver function\n */\nexport function createKindResolver(providerKinds: KindSchema[]): KindResolver {\n const providerMap = new Map(providerKinds.map((k) => [k.name, k]));\n\n return (name: string) => {\n // Provider kinds take precedence\n const providerKind = providerMap.get(name);\n if (providerKind) {\n return providerKind;\n }\n // Fall back to well-known kinds\n return WELL_KNOWN_KINDS_MAP.get(name);\n };\n}\n\n// =============================================================================\n// Utility exports\n// =============================================================================\n\n/**\n * Error thrown when kind resolution fails.\n */\nexport class KindError extends Error {\n constructor(\n message: string,\n public readonly kindName: string,\n ) {\n super(message);\n this.name = \"KindError\";\n }\n}\n\n/**\n * Resolve a kind name to its KindSchema.\n *\n * Looks up the kind in provider kinds first, then falls back to well-known kinds.\n *\n * @param kindName - The name of the kind to resolve (e.g., \"afs:node\", \"chamber:project\")\n * @param providerKinds - Optional array of kinds defined by the provider\n * @returns The resolved KindSchema, or undefined if not found\n *\n * @example\n * ```typescript\n * const nodeKind = resolveKindSchema(\"afs:node\");\n * const projectKind = resolveKindSchema(\"chamber:project\", providerKinds);\n * ```\n */\nexport function resolveKindSchema(\n kindName: string,\n providerKinds?: KindSchema[],\n): KindSchema | undefined {\n const resolver = providerKinds ? createKindResolver(providerKinds) : defaultKindResolver;\n return resolver(kindName);\n}\n"],"mappings":";;;;;;;;;;AA6FA,MAAa,uBAAqC,SAAiB;AACjE,QAAO,qBAAqB,IAAI,KAAK;;AAOvC,MAAM,iCAAiB,IAAI,SAA+B;;;;AAK1D,SAAS,aAAa,YAAkC;CACtD,IAAI,YAAY,eAAe,IAAI,WAAW;AAC9C,KAAI,CAAC,WAAW;AACd,cAAY,uBAAuB,WAAkB;AACrD,iBAAe,IAAI,YAAY,UAAU;;AAE3C,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCT,SAAgB,WAAW,YAAkC;CAC3D,MAAM,SAAqB;EACzB,MAAM,WAAW;EACjB,SAAS,WAAW;EACpB,aAAa,WAAW;EACxB,MAAM,WAAW;EACjB,OAAO,WAAW;EACnB;AAED,QAAO;EACL;EACA,MAAM,WAAW;EACjB,SAAS,WAAW;EAEpB,SAAS,MAAe,WAAyB,qBAAuC;GACtF,MAAM,QAAQ,KAAK,oBAAoB,SAAS;GAChD,MAAM,SAAqC,EAAE;AAG7C,QAAK,MAAM,cAAc,MACvB,KAAI,WAAW,KACb,KAAI;AACF,aAAS,aAAa,WAAW,KAAK,EAAE,MAAM,EAAE,QAAQ,WAAW,MAAM,CAAC;YACnE,KAAK;AACZ,WAAO,KAAK;KACV,MAAM;KACN,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;KACzD,MAAM;KACP,CAAC;;AAKR,UAAO;IAAE,OAAO,OAAO,WAAW;IAAG;IAAQ;;EAG/C,cAAc,UAAkB,WAAuC;AACrE,UAAO,cAAc,UAAU,WAAW,OAAO,MAAM;;EAGzD,oBAAoB,WAAyB,qBAAmC;AAC9E,UAAO,oBAAoB,QAAQ,SAAS;;EAE/C;;;;;;;;;;AAeH,SAAgB,oBACd,MACA,WAAyB,qBACX;CACd,MAAM,QAAsB,EAAE;CAC9B,MAAM,0BAAU,IAAI,KAAa;CACjC,IAAI,UAAkC;AAGtC,QAAO,SAAS;AACd,MAAI,QAAQ,IAAI,QAAQ,KAAK,CAC3B,OAAM,IAAI,MAAM,kCAAkC,QAAQ,OAAO;AAEnE,UAAQ,IAAI,QAAQ,KAAK;AACzB,QAAM,QAAQ,QAAQ;AAEtB,MAAI,CAAC,QAAQ,QACX;AAGF,YAAU,SAAS,QAAQ,QAAQ;AACnC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,2BAA2B,KAAK,QAAQ,kBAAkB,KAAK,KAAK,IAAI;;AAI5F,QAAO;;;;;;;;AAST,SAAgB,mBAAmB,eAA2C;CAC5E,MAAM,cAAc,IAAI,IAAI,cAAc,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AAElE,SAAQ,SAAiB;EAEvB,MAAM,eAAe,YAAY,IAAI,KAAK;AAC1C,MAAI,aACF,QAAO;AAGT,SAAO,qBAAqB,IAAI,KAAK;;;;;;AAWzC,IAAa,YAAb,cAA+B,MAAM;CACnC,YACE,SACA,AAAgB,UAChB;AACA,QAAM,QAAQ;EAFE;AAGhB,OAAK,OAAO;;;;;;;;;;;;;;;;;;AAmBhB,SAAgB,kBACd,UACA,eACwB;AAExB,SADiB,gBAAgB,mBAAmB,cAAc,GAAG,qBACrD,SAAS"}
|