@puzzle-ui/seo 0.0.0-stage → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +755 -2
- package/dist/LICENSE +21 -0
- package/dist/context/config.cjs +82 -0
- package/dist/context/config.cjs.map +1 -0
- package/dist/context/config.d.cts +6 -0
- package/dist/context/config.d.ts +6 -0
- package/dist/context/config.js +80 -0
- package/dist/context/config.js.map +1 -0
- package/dist/context/index.cjs +6 -0
- package/dist/context/index.d.cts +4 -0
- package/dist/context/index.d.ts +4 -0
- package/dist/context/index.js +3 -0
- package/dist/context/types.d.cts +46 -0
- package/dist/context/types.d.ts +46 -0
- package/dist/core/graph.cjs +464 -0
- package/dist/core/graph.cjs.map +1 -0
- package/dist/core/graph.d.cts +62 -0
- package/dist/core/graph.d.ts +62 -0
- package/dist/core/graph.js +456 -0
- package/dist/core/graph.js.map +1 -0
- package/dist/core/index.cjs +11 -0
- package/dist/core/index.d.cts +3 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +1 -0
- package/dist/core/types.d.cts +92 -0
- package/dist/core/types.d.ts +92 -0
- package/dist/index.cjs +96 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +48 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata/index.cjs +4 -0
- package/dist/metadata/index.d.cts +3 -0
- package/dist/metadata/index.d.ts +3 -0
- package/dist/metadata/index.js +1 -0
- package/dist/metadata/resolve.cjs +122 -0
- package/dist/metadata/resolve.cjs.map +1 -0
- package/dist/metadata/resolve.d.cts +4 -0
- package/dist/metadata/resolve.d.ts +4 -0
- package/dist/metadata/resolve.js +121 -0
- package/dist/metadata/resolve.js.map +1 -0
- package/dist/metadata/types.d.cts +82 -0
- package/dist/metadata/types.d.ts +82 -0
- package/dist/next/index.cjs +13 -0
- package/dist/next/index.cjs.map +1 -0
- package/dist/next/index.d.cts +15 -0
- package/dist/next/index.d.ts +14 -0
- package/dist/next/index.js +12 -0
- package/dist/next/index.js.map +1 -0
- package/dist/react/context.cjs +30 -0
- package/dist/react/context.cjs.map +1 -0
- package/dist/react/context.d.cts +14 -0
- package/dist/react/context.d.ts +14 -0
- package/dist/react/context.js +27 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/index.cjs +48 -0
- package/dist/react/index.d.cts +6 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.js +5 -0
- package/dist/react/metadata.cjs +100 -0
- package/dist/react/metadata.cjs.map +1 -0
- package/dist/react/metadata.d.cts +18 -0
- package/dist/react/metadata.d.ts +18 -0
- package/dist/react/metadata.js +99 -0
- package/dist/react/metadata.js.map +1 -0
- package/dist/react/provider.cjs +42 -0
- package/dist/react/provider.cjs.map +1 -0
- package/dist/react/provider.d.cts +3 -0
- package/dist/react/provider.d.ts +3 -0
- package/dist/react/provider.js +42 -0
- package/dist/react/provider.js.map +1 -0
- package/dist/react/schema-components.cjs +294 -0
- package/dist/react/schema-components.cjs.map +1 -0
- package/dist/react/schema-components.d.cts +84 -0
- package/dist/react/schema-components.d.ts +80 -0
- package/dist/react/schema-components.js +254 -0
- package/dist/react/schema-components.js.map +1 -0
- package/dist/react/types.d.cts +81 -0
- package/dist/react/types.d.ts +80 -0
- package/dist/react-router/index.cjs +13 -0
- package/dist/react-router/index.cjs.map +1 -0
- package/dist/react-router/index.d.cts +21 -0
- package/dist/react-router/index.d.ts +20 -0
- package/dist/react-router/index.js +12 -0
- package/dist/react-router/index.js.map +1 -0
- package/dist/robots/generate.cjs +88 -0
- package/dist/robots/generate.cjs.map +1 -0
- package/dist/robots/generate.d.cts +4 -0
- package/dist/robots/generate.d.ts +4 -0
- package/dist/robots/generate.js +86 -0
- package/dist/robots/generate.js.map +1 -0
- package/dist/robots/index.cjs +5 -0
- package/dist/robots/index.d.cts +3 -0
- package/dist/robots/index.d.ts +3 -0
- package/dist/robots/index.js +1 -0
- package/dist/robots/types.d.cts +27 -0
- package/dist/robots/types.d.ts +27 -0
- package/dist/schema/create-registry.cjs +12 -0
- package/dist/schema/create-registry.cjs.map +1 -0
- package/dist/schema/create-registry.d.cts +2 -0
- package/dist/schema/create-registry.d.ts +2 -0
- package/dist/schema/create-registry.js +12 -0
- package/dist/schema/create-registry.js.map +1 -0
- package/dist/schema/generated/index.d.cts +2 -0
- package/dist/schema/generated/schemaorg.cjs +36386 -0
- package/dist/schema/generated/schemaorg.cjs.map +1 -0
- package/dist/schema/generated/schemaorg.d.cts +945 -0
- package/dist/schema/generated/schemaorg.d.ts +945 -0
- package/dist/schema/generated/schemaorg.js +36384 -0
- package/dist/schema/generated/schemaorg.js.map +1 -0
- package/dist/schema/index.cjs +11 -0
- package/dist/schema/index.d.cts +7 -0
- package/dist/schema/index.d.ts +6 -0
- package/dist/schema/index.js +5 -0
- package/dist/schema/registry.cjs +194 -0
- package/dist/schema/registry.cjs.map +1 -0
- package/dist/schema/registry.d.cts +2 -0
- package/dist/schema/registry.d.ts +2 -0
- package/dist/schema/registry.js +194 -0
- package/dist/schema/registry.js.map +1 -0
- package/dist/schema/types.d.cts +79 -0
- package/dist/schema/types.d.ts +79 -0
- package/dist/schema/validate.cjs +131 -0
- package/dist/schema/validate.cjs.map +1 -0
- package/dist/schema/validate.d.cts +16 -0
- package/dist/schema/validate.d.ts +16 -0
- package/dist/schema/validate.js +131 -0
- package/dist/schema/validate.js.map +1 -0
- package/dist/server/handlers.cjs +96 -0
- package/dist/server/handlers.cjs.map +1 -0
- package/dist/server/handlers.d.cts +3 -0
- package/dist/server/handlers.d.ts +3 -0
- package/dist/server/handlers.js +95 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/index.cjs +6 -0
- package/dist/server/index.d.cts +4 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +3 -0
- package/dist/server/routes.cjs +17 -0
- package/dist/server/routes.cjs.map +1 -0
- package/dist/server/routes.d.cts +2 -0
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.js +17 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/types.d.cts +61 -0
- package/dist/server/types.d.ts +61 -0
- package/dist/sitemap/generate.cjs +147 -0
- package/dist/sitemap/generate.cjs.map +1 -0
- package/dist/sitemap/generate.d.cts +3 -0
- package/dist/sitemap/generate.d.ts +3 -0
- package/dist/sitemap/generate.js +146 -0
- package/dist/sitemap/generate.js.map +1 -0
- package/dist/sitemap/index.cjs +11 -0
- package/dist/sitemap/index.d.cts +4 -0
- package/dist/sitemap/index.d.ts +4 -0
- package/dist/sitemap/index.js +3 -0
- package/dist/sitemap/types.d.cts +82 -0
- package/dist/sitemap/types.d.ts +82 -0
- package/dist/sitemap/xml.cjs +215 -0
- package/dist/sitemap/xml.cjs.map +1 -0
- package/dist/sitemap/xml.d.cts +16 -0
- package/dist/sitemap/xml.d.ts +16 -0
- package/dist/sitemap/xml.js +210 -0
- package/dist/sitemap/xml.js.map +1 -0
- package/dist/tanstack/index.cjs +13 -0
- package/dist/tanstack/index.cjs.map +1 -0
- package/dist/tanstack/index.d.cts +19 -0
- package/dist/tanstack/index.d.ts +18 -0
- package/dist/tanstack/index.js +12 -0
- package/dist/tanstack/index.js.map +1 -0
- package/dist/testing/diagnostics.cjs +27 -0
- package/dist/testing/diagnostics.cjs.map +1 -0
- package/dist/testing/diagnostics.d.cts +3 -0
- package/dist/testing/diagnostics.d.ts +3 -0
- package/dist/testing/diagnostics.js +27 -0
- package/dist/testing/diagnostics.js.map +1 -0
- package/dist/testing/fixture.cjs +80 -0
- package/dist/testing/fixture.cjs.map +1 -0
- package/dist/testing/fixture.d.cts +4 -0
- package/dist/testing/fixture.d.ts +4 -0
- package/dist/testing/fixture.js +78 -0
- package/dist/testing/fixture.js.map +1 -0
- package/dist/testing/index.cjs +9 -0
- package/dist/testing/index.d.cts +5 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.js +4 -0
- package/dist/testing/inspect.cjs +63 -0
- package/dist/testing/inspect.cjs.map +1 -0
- package/dist/testing/inspect.d.cts +5 -0
- package/dist/testing/inspect.d.ts +5 -0
- package/dist/testing/inspect.js +63 -0
- package/dist/testing/inspect.js.map +1 -0
- package/dist/testing/types.d.cts +40 -0
- package/dist/testing/types.d.ts +40 -0
- package/dist/urls/index.cjs +8 -0
- package/dist/urls/index.d.cts +3 -0
- package/dist/urls/index.d.ts +3 -0
- package/dist/urls/index.js +1 -0
- package/dist/urls/normalize.cjs +65 -0
- package/dist/urls/normalize.cjs.map +1 -0
- package/dist/urls/normalize.d.cts +14 -0
- package/dist/urls/normalize.d.ts +14 -0
- package/dist/urls/normalize.js +60 -0
- package/dist/urls/normalize.js.map +1 -0
- package/dist/urls/types.d.cts +22 -0
- package/dist/urls/types.d.ts +22 -0
- package/dist/validation/index.cjs +5 -0
- package/dist/validation/index.d.cts +3 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +1 -0
- package/dist/validation/types.d.cts +75 -0
- package/dist/validation/types.d.ts +75 -0
- package/dist/validation/validate.cjs +452 -0
- package/dist/validation/validate.cjs.map +1 -0
- package/dist/validation/validate.d.cts +7 -0
- package/dist/validation/validate.d.ts +6 -0
- package/dist/validation/validate.js +450 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +203 -4
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_registry = require("./registry.cjs");
|
|
3
|
+
const require_create_registry = require("./create-registry.cjs");
|
|
4
|
+
const require_validate = require("./validate.cjs");
|
|
5
|
+
const require_schemaorg = require("./generated/schemaorg.cjs");
|
|
6
|
+
exports.SCHEMAORG_SOURCE_HASH = require_schemaorg.SCHEMAORG_SOURCE_HASH;
|
|
7
|
+
exports.SCHEMAORG_VERSION = require_schemaorg.SCHEMAORG_VERSION;
|
|
8
|
+
exports.createDefaultSchemaRegistry = require_create_registry.createDefaultSchemaRegistry;
|
|
9
|
+
exports.createSchemaRegistry = require_registry.createSchemaRegistry;
|
|
10
|
+
exports.generatedSchemaDefinitions = require_schemaorg.generatedSchemaDefinitions;
|
|
11
|
+
exports.validateSchemaNode = require_validate.validateSchemaNode;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SchemaDefinition, SchemaDefinitionCollection, SchemaDefinitionSource, SchemaEnumerationValue, SchemaExtension, SchemaPropertyDefinition, SchemaPropertyType, SchemaReference, SchemaRegistry, SchemaRegistryConflict, SchemaRegistryOptions, SchemaRegistryProvider, SchemaValidationOptions } from "./types.cjs";
|
|
2
|
+
import { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, generatedSchemaDefinitions } from "./generated/schemaorg.cjs";
|
|
3
|
+
import { createSchemaRegistry } from "./registry.cjs";
|
|
4
|
+
import { createDefaultSchemaRegistry } from "./create-registry.cjs";
|
|
5
|
+
import { validateSchemaNode } from "./validate.cjs";
|
|
6
|
+
import "./generated/index.cjs";
|
|
7
|
+
export { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, type SchemaDefinition, type SchemaDefinitionCollection, type SchemaDefinitionSource, type SchemaEnumerationValue, type SchemaExtension, type SchemaPropertyDefinition, type SchemaPropertyType, type SchemaReference, type SchemaRegistry, type SchemaRegistryConflict, type SchemaRegistryOptions, type SchemaRegistryProvider, type SchemaValidationOptions, createDefaultSchemaRegistry, createSchemaRegistry, generatedSchemaDefinitions, validateSchemaNode };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SchemaDefinition, SchemaDefinitionCollection, SchemaDefinitionSource, SchemaEnumerationValue, SchemaExtension, SchemaPropertyDefinition, SchemaPropertyType, SchemaReference, SchemaRegistry, SchemaRegistryConflict, SchemaRegistryOptions, SchemaRegistryProvider, SchemaValidationOptions } from "./types.js";
|
|
2
|
+
import { createSchemaRegistry } from "./registry.js";
|
|
3
|
+
import { createDefaultSchemaRegistry } from "./create-registry.js";
|
|
4
|
+
import { validateSchemaNode } from "./validate.js";
|
|
5
|
+
import { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, generatedSchemaDefinitions } from "./generated/schemaorg.js";
|
|
6
|
+
export { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, type SchemaDefinition, type SchemaDefinitionCollection, type SchemaDefinitionSource, type SchemaEnumerationValue, type SchemaExtension, type SchemaPropertyDefinition, type SchemaPropertyType, type SchemaReference, type SchemaRegistry, type SchemaRegistryConflict, type SchemaRegistryOptions, type SchemaRegistryProvider, type SchemaValidationOptions, createDefaultSchemaRegistry, createSchemaRegistry, generatedSchemaDefinitions, validateSchemaNode };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createSchemaRegistry } from "./registry.js";
|
|
2
|
+
import { createDefaultSchemaRegistry } from "./create-registry.js";
|
|
3
|
+
import { validateSchemaNode } from "./validate.js";
|
|
4
|
+
import { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, generatedSchemaDefinitions } from "./generated/schemaorg.js";
|
|
5
|
+
export { SCHEMAORG_SOURCE_HASH, SCHEMAORG_VERSION, createDefaultSchemaRegistry, createSchemaRegistry, generatedSchemaDefinitions, validateSchemaNode };
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// src/schema/registry.ts
|
|
2
|
+
const normalizeType = (type) => {
|
|
3
|
+
const value = type.trim();
|
|
4
|
+
if (!value) throw new Error("Schema type cannot be empty.");
|
|
5
|
+
return /^[A-Za-z][A-Za-z0-9]*$/.test(value) ? `https://schema.org/${value}` : value.replace(/^http:\/\/schema\.org\//, "https://schema.org/");
|
|
6
|
+
};
|
|
7
|
+
const isRdfVocabularyType = (type) => /^https?:\/\/www\.w3\.org\/(1999\/02\/22-rdf-syntax-ns|2000\/01\/rdf-schema)#/.test(type);
|
|
8
|
+
/**
|
|
9
|
+
* Recursively freezes registry-owned objects and arrays.
|
|
10
|
+
*
|
|
11
|
+
* Definitions are normalized into new objects before reaching this function,
|
|
12
|
+
* so freezing them never mutates the caller's original input objects.
|
|
13
|
+
*/
|
|
14
|
+
const deepFreeze = (value) => {
|
|
15
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
16
|
+
Object.freeze(value);
|
|
17
|
+
for (const nestedValue of Object.values(value)) deepFreeze(nestedValue);
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
const normalizeEnumerationValue = (value) => ({
|
|
21
|
+
...value,
|
|
22
|
+
type: normalizeType(value.type)
|
|
23
|
+
});
|
|
24
|
+
const normalizeProperty = (property) => ({
|
|
25
|
+
...property,
|
|
26
|
+
expectedTypes: property.expectedTypes?.map(normalizeType),
|
|
27
|
+
rangeTypes: property.rangeTypes?.map(normalizeType),
|
|
28
|
+
domainTypes: property.domainTypes?.map(normalizeType),
|
|
29
|
+
inverseOf: property.inverseOf ? normalizeType(property.inverseOf) : void 0,
|
|
30
|
+
supersededBy: property.supersededBy ? normalizeType(property.supersededBy) : void 0,
|
|
31
|
+
type: Array.isArray(property.type) ? property.type.map(normalizeType) : normalizeType(property.type)
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Normalizes a definition and assigns its authoritative source.
|
|
35
|
+
*
|
|
36
|
+
* The source is determined by the collection the definition came from,
|
|
37
|
+
* never by the caller-provided source property.
|
|
38
|
+
*/
|
|
39
|
+
const normalizeDefinition = (definition, source) => ({
|
|
40
|
+
...definition,
|
|
41
|
+
type: normalizeType(definition.type),
|
|
42
|
+
source,
|
|
43
|
+
parentTypes: definition.parentTypes?.map(normalizeType),
|
|
44
|
+
enumerationValues: definition.enumerationValues?.map(normalizeEnumerationValue),
|
|
45
|
+
properties: definition.properties?.map(normalizeProperty)
|
|
46
|
+
});
|
|
47
|
+
const deduplicateProperties = (definitions, conflicts) => {
|
|
48
|
+
for (const definition of definitions) {
|
|
49
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50
|
+
definition.properties = definition.properties?.filter((property) => {
|
|
51
|
+
if (seen.has(property.name)) {
|
|
52
|
+
conflicts.push({
|
|
53
|
+
type: definition.type,
|
|
54
|
+
property: property.name,
|
|
55
|
+
code: "duplicate-property",
|
|
56
|
+
message: `Duplicate property ${property.name} on ${definition.type}.`
|
|
57
|
+
});
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
seen.add(property.name);
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const createSchemaRegistry = (options = {}) => {
|
|
66
|
+
const generated = (options.generated ?? []).map((definition) => normalizeDefinition(definition, "generated"));
|
|
67
|
+
const custom = (options.custom ?? []).map((definition) => normalizeDefinition(definition, "custom"));
|
|
68
|
+
const conflicts = [];
|
|
69
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const definition of generated) {
|
|
71
|
+
if (definitions.has(definition.type)) {
|
|
72
|
+
conflicts.push({
|
|
73
|
+
type: definition.type,
|
|
74
|
+
code: "duplicate-type",
|
|
75
|
+
message: `Duplicate generated schema type: ${definition.type}`
|
|
76
|
+
});
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
definitions.set(definition.type, definition);
|
|
80
|
+
}
|
|
81
|
+
for (const definition of custom) {
|
|
82
|
+
const existing = definitions.get(definition.type);
|
|
83
|
+
if (existing) {
|
|
84
|
+
if (!(options.allowGeneratedOverrides === true && existing.source === "generated")) {
|
|
85
|
+
conflicts.push({
|
|
86
|
+
type: definition.type,
|
|
87
|
+
code: "duplicate-type",
|
|
88
|
+
message: existing.source === "generated" ? `Custom schema type conflicts with generated type: ${definition.type}` : `Duplicate custom schema type: ${definition.type}`
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
definitions.set(definition.type, definition);
|
|
94
|
+
}
|
|
95
|
+
deduplicateProperties(definitions.values(), conflicts);
|
|
96
|
+
for (const extension of options.extensions ?? []) {
|
|
97
|
+
const type = normalizeType(extension.type);
|
|
98
|
+
const existing = definitions.get(type);
|
|
99
|
+
if (!existing) {
|
|
100
|
+
conflicts.push({
|
|
101
|
+
type,
|
|
102
|
+
code: "unknown-parent",
|
|
103
|
+
message: `Cannot extend unknown schema type: ${type}`
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (extension.namespace && existing.namespace && extension.namespace !== existing.namespace) {
|
|
108
|
+
conflicts.push({
|
|
109
|
+
type,
|
|
110
|
+
code: "namespace-mismatch",
|
|
111
|
+
message: `Extension namespace does not match ${type}.`
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const properties = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const property of existing.properties ?? []) properties.set(property.name, property);
|
|
117
|
+
const extensionPropertyNames = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const property of extension.properties) {
|
|
119
|
+
if (properties.has(property.name) || extensionPropertyNames.has(property.name)) {
|
|
120
|
+
conflicts.push({
|
|
121
|
+
type,
|
|
122
|
+
property: property.name,
|
|
123
|
+
code: "duplicate-property",
|
|
124
|
+
message: `Property ${property.name} already exists on ${type}.`
|
|
125
|
+
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
extensionPropertyNames.add(property.name);
|
|
129
|
+
properties.set(property.name, normalizeProperty(property));
|
|
130
|
+
}
|
|
131
|
+
definitions.set(type, {
|
|
132
|
+
...existing,
|
|
133
|
+
properties: [...properties.values()]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
for (const definition of definitions.values()) for (const parentType of definition.parentTypes ?? []) {
|
|
137
|
+
if (definitions.has(parentType) || isRdfVocabularyType(parentType)) continue;
|
|
138
|
+
conflicts.push({
|
|
139
|
+
type: definition.type,
|
|
140
|
+
code: "unknown-parent",
|
|
141
|
+
message: `Unknown parent type ${parentType} referenced by ${definition.type}.`
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (const definition of definitions.values()) deepFreeze(definition);
|
|
145
|
+
const frozenGenerated = deepFreeze(generated);
|
|
146
|
+
const frozenCustom = deepFreeze(custom);
|
|
147
|
+
const collection = deepFreeze({
|
|
148
|
+
generated: frozenGenerated,
|
|
149
|
+
custom: frozenCustom
|
|
150
|
+
});
|
|
151
|
+
const frozenConflicts = deepFreeze(conflicts);
|
|
152
|
+
const get = (type) => definitions.get(normalizeType(type));
|
|
153
|
+
const getAncestors = (type, visited = /* @__PURE__ */ new Set()) => {
|
|
154
|
+
const definition = get(type);
|
|
155
|
+
if (!definition) return [];
|
|
156
|
+
const result = [];
|
|
157
|
+
for (const parentType of definition.parentTypes ?? []) {
|
|
158
|
+
if (visited.has(parentType)) continue;
|
|
159
|
+
visited.add(parentType);
|
|
160
|
+
const parent = get(parentType);
|
|
161
|
+
if (!parent) continue;
|
|
162
|
+
result.push(parent);
|
|
163
|
+
result.push(...getAncestors(parentType, visited));
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
};
|
|
167
|
+
const getProperties = (type, inherited = true) => {
|
|
168
|
+
const definition = get(type);
|
|
169
|
+
if (!definition) return [];
|
|
170
|
+
const properties = /* @__PURE__ */ new Map();
|
|
171
|
+
if (inherited) for (const ancestor of [...getAncestors(type)].reverse()) for (const property of ancestor.properties ?? []) properties.set(property.name, property);
|
|
172
|
+
for (const property of definition.properties ?? []) properties.set(property.name, property);
|
|
173
|
+
return [...properties.values()];
|
|
174
|
+
};
|
|
175
|
+
const isTypeOf = (type, expectedType) => {
|
|
176
|
+
const normalizedType = normalizeType(type);
|
|
177
|
+
const normalizedExpected = normalizeType(expectedType);
|
|
178
|
+
return normalizedType === normalizedExpected || getAncestors(normalizedType).some((ancestor) => ancestor.type === normalizedExpected);
|
|
179
|
+
};
|
|
180
|
+
return Object.freeze({
|
|
181
|
+
get,
|
|
182
|
+
has: (type) => Boolean(get(type)),
|
|
183
|
+
getAll: () => [...definitions.values()],
|
|
184
|
+
getProperty: (type, property) => getProperties(type).find((item) => item.name === property),
|
|
185
|
+
getProperties: (type, options) => getProperties(type, options?.inherited ?? true),
|
|
186
|
+
getAncestors,
|
|
187
|
+
isTypeOf,
|
|
188
|
+
getCollection: () => collection,
|
|
189
|
+
getConflicts: () => frozenConflicts
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
exports.createSchemaRegistry = createSchemaRegistry;
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=registry.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.cjs","names":[],"sources":["../../src/schema/registry.ts"],"sourcesContent":["import type {\n SchemaDefinition,\n SchemaEnumerationValue,\n SchemaPropertyDefinition,\n SchemaRegistry,\n SchemaRegistryConflict,\n SchemaRegistryOptions,\n} from \"./types\";\n\nconst normalizeType = (type: string): string => {\n const value = type.trim();\n\n if (!value) {\n throw new Error(\"Schema type cannot be empty.\");\n }\n\n return /^[A-Za-z][A-Za-z0-9]*$/.test(value)\n ? `https://schema.org/${value}`\n : value.replace(/^http:\\/\\/schema\\.org\\//, \"https://schema.org/\");\n};\n\nconst isRdfVocabularyType = (type: string): boolean =>\n /^https?:\\/\\/www\\.w3\\.org\\/(1999\\/02\\/22-rdf-syntax-ns|2000\\/01\\/rdf-schema)#/.test(\n type,\n );\n\n/**\n * Recursively freezes registry-owned objects and arrays.\n *\n * Definitions are normalized into new objects before reaching this function,\n * so freezing them never mutates the caller's original input objects.\n */\nconst deepFreeze = <T>(value: T): T => {\n if (value === null || typeof value !== \"object\" || Object.isFrozen(value)) {\n return value;\n }\n\n Object.freeze(value);\n\n for (const nestedValue of Object.values(value)) {\n deepFreeze(nestedValue);\n }\n\n return value;\n};\n\nconst normalizeEnumerationValue = (\n value: SchemaEnumerationValue,\n): SchemaEnumerationValue => ({\n ...value,\n type: normalizeType(value.type),\n});\n\nconst normalizeProperty = (\n property: SchemaPropertyDefinition,\n): SchemaPropertyDefinition => ({\n ...property,\n expectedTypes: property.expectedTypes?.map(normalizeType),\n rangeTypes: property.rangeTypes?.map(normalizeType),\n domainTypes: property.domainTypes?.map(normalizeType),\n inverseOf: property.inverseOf ? normalizeType(property.inverseOf) : undefined,\n supersededBy: property.supersededBy\n ? normalizeType(property.supersededBy)\n : undefined,\n type: Array.isArray(property.type)\n ? property.type.map(normalizeType)\n : normalizeType(property.type),\n});\n\n/**\n * Normalizes a definition and assigns its authoritative source.\n *\n * The source is determined by the collection the definition came from,\n * never by the caller-provided source property.\n */\nconst normalizeDefinition = (\n definition: SchemaDefinition,\n source: SchemaDefinition[\"source\"],\n): SchemaDefinition => ({\n ...definition,\n type: normalizeType(definition.type),\n source,\n parentTypes: definition.parentTypes?.map(normalizeType),\n enumerationValues: definition.enumerationValues?.map(\n normalizeEnumerationValue,\n ),\n properties: definition.properties?.map(normalizeProperty),\n});\n\nconst deduplicateProperties = (\n definitions: Iterable<SchemaDefinition>,\n conflicts: SchemaRegistryConflict[],\n): void => {\n for (const definition of definitions) {\n const seen = new Set<string>();\n\n definition.properties = definition.properties?.filter((property) => {\n if (seen.has(property.name)) {\n conflicts.push({\n type: definition.type,\n property: property.name,\n code: \"duplicate-property\",\n message: `Duplicate property ${property.name} on ${definition.type}.`,\n });\n\n return false;\n }\n\n seen.add(property.name);\n return true;\n });\n }\n};\n\nexport const createSchemaRegistry = (\n options: SchemaRegistryOptions = {},\n): SchemaRegistry => {\n // Collection membership is the source of truth. Ignore any source value\n // supplied by callers to prevent custom definitions impersonating generated\n // definitions (or vice versa).\n const generated = (options.generated ?? []).map((definition) =>\n normalizeDefinition(definition, \"generated\"),\n );\n\n const custom = (options.custom ?? []).map((definition) =>\n normalizeDefinition(definition, \"custom\"),\n );\n\n const conflicts: SchemaRegistryConflict[] = [];\n\n const definitions = new Map<string, SchemaDefinition>();\n\n for (const definition of generated) {\n if (definitions.has(definition.type)) {\n conflicts.push({\n type: definition.type,\n code: \"duplicate-type\",\n message: `Duplicate generated schema type: ${definition.type}`,\n });\n\n continue;\n }\n\n definitions.set(definition.type, definition);\n }\n\n // Only generated definitions may be overridden, and only when explicitly\n // enabled. A custom definition can never silently replace another custom\n // definition, even when allowGeneratedOverrides is true.\n for (const definition of custom) {\n const existing = definitions.get(definition.type);\n\n if (existing) {\n const canOverrideGenerated =\n options.allowGeneratedOverrides === true &&\n existing.source === \"generated\";\n\n if (!canOverrideGenerated) {\n conflicts.push({\n type: definition.type,\n code: \"duplicate-type\",\n message:\n existing.source === \"generated\"\n ? `Custom schema type conflicts with generated type: ${definition.type}`\n : `Duplicate custom schema type: ${definition.type}`,\n });\n\n continue;\n }\n }\n\n definitions.set(definition.type, definition);\n }\n\n // Validate the effective definitions before applying extensions. This also\n // catches duplicates in definitions that would otherwise be collapsed by\n // the extension merge operation.\n deduplicateProperties(definitions.values(), conflicts);\n\n for (const extension of options.extensions ?? []) {\n const type = normalizeType(extension.type);\n const existing = definitions.get(type);\n\n if (!existing) {\n conflicts.push({\n type,\n code: \"unknown-parent\",\n message: `Cannot extend unknown schema type: ${type}`,\n });\n\n continue;\n }\n\n if (\n extension.namespace &&\n existing.namespace &&\n extension.namespace !== existing.namespace\n ) {\n conflicts.push({\n type,\n code: \"namespace-mismatch\",\n message: `Extension namespace does not match ${type}.`,\n });\n\n continue;\n }\n\n const properties = new Map<string, SchemaPropertyDefinition>();\n\n for (const property of existing.properties ?? []) {\n properties.set(property.name, property);\n }\n\n const extensionPropertyNames = new Set<string>();\n\n for (const property of extension.properties) {\n if (\n properties.has(property.name) ||\n extensionPropertyNames.has(property.name)\n ) {\n conflicts.push({\n type,\n property: property.name,\n code: \"duplicate-property\",\n message: `Property ${property.name} already exists on ${type}.`,\n });\n\n continue;\n }\n\n extensionPropertyNames.add(property.name);\n properties.set(property.name, normalizeProperty(property));\n }\n\n definitions.set(type, {\n ...existing,\n properties: [...properties.values()],\n });\n }\n\n // Report parent references that cannot be resolved by this registry.\n // RDF/RDFS meta-classes (e.g. DataType → rdfs:Class) are vocabulary\n // structure, not Schema.org types, so they are never registered.\n for (const definition of definitions.values()) {\n for (const parentType of definition.parentTypes ?? []) {\n if (definitions.has(parentType) || isRdfVocabularyType(parentType)) {\n continue;\n }\n\n conflicts.push({\n type: definition.type,\n code: \"unknown-parent\",\n message: `Unknown parent type ${parentType} referenced by ${definition.type}.`,\n });\n }\n }\n\n // Freeze every effective definition after all extensions have been applied.\n // This includes nested property metadata, enumeration values and arrays.\n for (const definition of definitions.values()) {\n deepFreeze(definition);\n }\n\n // Keep the generated/custom collections immutable as well. They contain\n // normalized copies, not references to the caller's original definitions.\n const frozenGenerated = deepFreeze(generated);\n const frozenCustom = deepFreeze(custom);\n\n const collection = deepFreeze({\n generated: frozenGenerated,\n custom: frozenCustom,\n });\n\n const frozenConflicts = deepFreeze(conflicts);\n\n const get = (type: string) => definitions.get(normalizeType(type));\n\n const getAncestors = (\n type: string,\n visited = new Set<string>(),\n ): SchemaDefinition[] => {\n const definition = get(type);\n\n if (!definition) {\n return [];\n }\n\n const result: SchemaDefinition[] = [];\n\n for (const parentType of definition.parentTypes ?? []) {\n if (visited.has(parentType)) {\n continue;\n }\n\n visited.add(parentType);\n\n const parent = get(parentType);\n\n if (!parent) {\n continue;\n }\n\n result.push(parent);\n result.push(...getAncestors(parentType, visited));\n }\n\n return result;\n };\n\n const getProperties = (\n type: string,\n inherited = true,\n ): readonly SchemaPropertyDefinition[] => {\n const definition = get(type);\n\n if (!definition) {\n return [];\n }\n\n const properties = new Map<string, SchemaPropertyDefinition>();\n\n if (inherited) {\n for (const ancestor of [...getAncestors(type)].reverse()) {\n for (const property of ancestor.properties ?? []) {\n properties.set(property.name, property);\n }\n }\n }\n\n for (const property of definition.properties ?? []) {\n properties.set(property.name, property);\n }\n\n return [...properties.values()];\n };\n\n const isTypeOf = (type: string, expectedType: string): boolean => {\n const normalizedType = normalizeType(type);\n const normalizedExpected = normalizeType(expectedType);\n\n return (\n normalizedType === normalizedExpected ||\n getAncestors(normalizedType).some(\n (ancestor) => ancestor.type === normalizedExpected,\n )\n );\n };\n\n return Object.freeze({\n get,\n has: (type: string) => Boolean(get(type)),\n getAll: () => [...definitions.values()],\n\n getProperty: (type: string, property: string) =>\n getProperties(type).find((item) => item.name === property),\n\n getProperties: (type: string, options?: { inherited?: boolean }) =>\n getProperties(type, options?.inherited ?? true),\n\n getAncestors,\n\n isTypeOf,\n\n getCollection: () => collection,\n\n getConflicts: () => frozenConflicts,\n });\n};\n"],"mappings":";AASA,MAAM,iBAAiB,SAAyB;CAC9C,MAAM,QAAQ,KAAK,KAAK;CAExB,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,8BAA8B;CAGhD,OAAO,yBAAyB,KAAK,KAAK,IACtC,sBAAsB,UACtB,MAAM,QAAQ,2BAA2B,qBAAqB;AACpE;AAEA,MAAM,uBAAuB,SAC3B,+EAA+E,KAC7E,IACF;;;;;;;AAQF,MAAM,cAAiB,UAAgB;CACrC,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GACtE,OAAO;CAGT,OAAO,OAAO,KAAK;CAEnB,KAAK,MAAM,eAAe,OAAO,OAAO,KAAK,GAC3C,WAAW,WAAW;CAGxB,OAAO;AACT;AAEA,MAAM,6BACJ,WAC4B;CAC5B,GAAG;CACH,MAAM,cAAc,MAAM,IAAI;AAChC;AAEA,MAAM,qBACJ,cAC8B;CAC9B,GAAG;CACH,eAAe,SAAS,eAAe,IAAI,aAAa;CACxD,YAAY,SAAS,YAAY,IAAI,aAAa;CAClD,aAAa,SAAS,aAAa,IAAI,aAAa;CACpD,WAAW,SAAS,YAAY,cAAc,SAAS,SAAS,IAAI,KAAA;CACpE,cAAc,SAAS,eACnB,cAAc,SAAS,YAAY,IACnC,KAAA;CACJ,MAAM,MAAM,QAAQ,SAAS,IAAI,IAC7B,SAAS,KAAK,IAAI,aAAa,IAC/B,cAAc,SAAS,IAAI;AACjC;;;;;;;AAQA,MAAM,uBACJ,YACA,YACsB;CACtB,GAAG;CACH,MAAM,cAAc,WAAW,IAAI;CACnC;CACA,aAAa,WAAW,aAAa,IAAI,aAAa;CACtD,mBAAmB,WAAW,mBAAmB,IAC/C,yBACF;CACA,YAAY,WAAW,YAAY,IAAI,iBAAiB;AAC1D;AAEA,MAAM,yBACJ,aACA,cACS;CACT,KAAK,MAAM,cAAc,aAAa;EACpC,MAAM,uBAAO,IAAI,IAAY;EAE7B,WAAW,aAAa,WAAW,YAAY,QAAQ,aAAa;GAClE,IAAI,KAAK,IAAI,SAAS,IAAI,GAAG;IAC3B,UAAU,KAAK;KACb,MAAM,WAAW;KACjB,UAAU,SAAS;KACnB,MAAM;KACN,SAAS,sBAAsB,SAAS,KAAK,MAAM,WAAW,KAAK;IACrE,CAAC;IAED,OAAO;GACT;GAEA,KAAK,IAAI,SAAS,IAAI;GACtB,OAAO;EACT,CAAC;CACH;AACF;AAEA,MAAa,wBACX,UAAiC,CAAC,MACf;CAInB,MAAM,aAAa,QAAQ,aAAa,CAAC,EAAA,CAAG,KAAK,eAC/C,oBAAoB,YAAY,WAAW,CAC7C;CAEA,MAAM,UAAU,QAAQ,UAAU,CAAC,EAAA,CAAG,KAAK,eACzC,oBAAoB,YAAY,QAAQ,CAC1C;CAEA,MAAM,YAAsC,CAAC;CAE7C,MAAM,8BAAc,IAAI,IAA8B;CAEtD,KAAK,MAAM,cAAc,WAAW;EAClC,IAAI,YAAY,IAAI,WAAW,IAAI,GAAG;GACpC,UAAU,KAAK;IACb,MAAM,WAAW;IACjB,MAAM;IACN,SAAS,oCAAoC,WAAW;GAC1D,CAAC;GAED;EACF;EAEA,YAAY,IAAI,WAAW,MAAM,UAAU;CAC7C;CAKA,KAAK,MAAM,cAAc,QAAQ;EAC/B,MAAM,WAAW,YAAY,IAAI,WAAW,IAAI;EAEhD,IAAI,UAKE;OAAA,EAHF,QAAQ,4BAA4B,QACpC,SAAS,WAAW,cAEK;IACzB,UAAU,KAAK;KACb,MAAM,WAAW;KACjB,MAAM;KACN,SACE,SAAS,WAAW,cAChB,qDAAqD,WAAW,SAChE,iCAAiC,WAAW;IACpD,CAAC;IAED;GACF;;EAGF,YAAY,IAAI,WAAW,MAAM,UAAU;CAC7C;CAKA,sBAAsB,YAAY,OAAO,GAAG,SAAS;CAErD,KAAK,MAAM,aAAa,QAAQ,cAAc,CAAC,GAAG;EAChD,MAAM,OAAO,cAAc,UAAU,IAAI;EACzC,MAAM,WAAW,YAAY,IAAI,IAAI;EAErC,IAAI,CAAC,UAAU;GACb,UAAU,KAAK;IACb;IACA,MAAM;IACN,SAAS,sCAAsC;GACjD,CAAC;GAED;EACF;EAEA,IACE,UAAU,aACV,SAAS,aACT,UAAU,cAAc,SAAS,WACjC;GACA,UAAU,KAAK;IACb;IACA,MAAM;IACN,SAAS,sCAAsC,KAAK;GACtD,CAAC;GAED;EACF;EAEA,MAAM,6BAAa,IAAI,IAAsC;EAE7D,KAAK,MAAM,YAAY,SAAS,cAAc,CAAC,GAC7C,WAAW,IAAI,SAAS,MAAM,QAAQ;EAGxC,MAAM,yCAAyB,IAAI,IAAY;EAE/C,KAAK,MAAM,YAAY,UAAU,YAAY;GAC3C,IACE,WAAW,IAAI,SAAS,IAAI,KAC5B,uBAAuB,IAAI,SAAS,IAAI,GACxC;IACA,UAAU,KAAK;KACb;KACA,UAAU,SAAS;KACnB,MAAM;KACN,SAAS,YAAY,SAAS,KAAK,qBAAqB,KAAK;IAC/D,CAAC;IAED;GACF;GAEA,uBAAuB,IAAI,SAAS,IAAI;GACxC,WAAW,IAAI,SAAS,MAAM,kBAAkB,QAAQ,CAAC;EAC3D;EAEA,YAAY,IAAI,MAAM;GACpB,GAAG;GACH,YAAY,CAAC,GAAG,WAAW,OAAO,CAAC;EACrC,CAAC;CACH;CAKA,KAAK,MAAM,cAAc,YAAY,OAAO,GAC1C,KAAK,MAAM,cAAc,WAAW,eAAe,CAAC,GAAG;EACrD,IAAI,YAAY,IAAI,UAAU,KAAK,oBAAoB,UAAU,GAC/D;EAGF,UAAU,KAAK;GACb,MAAM,WAAW;GACjB,MAAM;GACN,SAAS,uBAAuB,WAAW,iBAAiB,WAAW,KAAK;EAC9E,CAAC;CACH;CAKF,KAAK,MAAM,cAAc,YAAY,OAAO,GAC1C,WAAW,UAAU;CAKvB,MAAM,kBAAkB,WAAW,SAAS;CAC5C,MAAM,eAAe,WAAW,MAAM;CAEtC,MAAM,aAAa,WAAW;EAC5B,WAAW;EACX,QAAQ;CACV,CAAC;CAED,MAAM,kBAAkB,WAAW,SAAS;CAE5C,MAAM,OAAO,SAAiB,YAAY,IAAI,cAAc,IAAI,CAAC;CAEjE,MAAM,gBACJ,MACA,0BAAU,IAAI,IAAY,MACH;EACvB,MAAM,aAAa,IAAI,IAAI;EAE3B,IAAI,CAAC,YACH,OAAO,CAAC;EAGV,MAAM,SAA6B,CAAC;EAEpC,KAAK,MAAM,cAAc,WAAW,eAAe,CAAC,GAAG;GACrD,IAAI,QAAQ,IAAI,UAAU,GACxB;GAGF,QAAQ,IAAI,UAAU;GAEtB,MAAM,SAAS,IAAI,UAAU;GAE7B,IAAI,CAAC,QACH;GAGF,OAAO,KAAK,MAAM;GAClB,OAAO,KAAK,GAAG,aAAa,YAAY,OAAO,CAAC;EAClD;EAEA,OAAO;CACT;CAEA,MAAM,iBACJ,MACA,YAAY,SAC4B;EACxC,MAAM,aAAa,IAAI,IAAI;EAE3B,IAAI,CAAC,YACH,OAAO,CAAC;EAGV,MAAM,6BAAa,IAAI,IAAsC;EAE7D,IAAI,WACF,KAAK,MAAM,YAAY,CAAC,GAAG,aAAa,IAAI,CAAC,CAAC,CAAC,QAAQ,GACrD,KAAK,MAAM,YAAY,SAAS,cAAc,CAAC,GAC7C,WAAW,IAAI,SAAS,MAAM,QAAQ;EAK5C,KAAK,MAAM,YAAY,WAAW,cAAc,CAAC,GAC/C,WAAW,IAAI,SAAS,MAAM,QAAQ;EAGxC,OAAO,CAAC,GAAG,WAAW,OAAO,CAAC;CAChC;CAEA,MAAM,YAAY,MAAc,iBAAkC;EAChE,MAAM,iBAAiB,cAAc,IAAI;EACzC,MAAM,qBAAqB,cAAc,YAAY;EAErD,OACE,mBAAmB,sBACnB,aAAa,cAAc,CAAC,CAAC,MAC1B,aAAa,SAAS,SAAS,kBAClC;CAEJ;CAEA,OAAO,OAAO,OAAO;EACnB;EACA,MAAM,SAAiB,QAAQ,IAAI,IAAI,CAAC;EACxC,cAAc,CAAC,GAAG,YAAY,OAAO,CAAC;EAEtC,cAAc,MAAc,aAC1B,cAAc,IAAI,CAAC,CAAC,MAAM,SAAS,KAAK,SAAS,QAAQ;EAE3D,gBAAgB,MAAc,YAC5B,cAAc,MAAM,SAAS,aAAa,IAAI;EAEhD;EAEA;EAEA,qBAAqB;EAErB,oBAAoB;CACtB,CAAC;AACH"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// src/schema/registry.ts
|
|
2
|
+
const normalizeType = (type) => {
|
|
3
|
+
const value = type.trim();
|
|
4
|
+
if (!value) throw new Error("Schema type cannot be empty.");
|
|
5
|
+
return /^[A-Za-z][A-Za-z0-9]*$/.test(value) ? `https://schema.org/${value}` : value.replace(/^http:\/\/schema\.org\//, "https://schema.org/");
|
|
6
|
+
};
|
|
7
|
+
const isRdfVocabularyType = (type) => /^https?:\/\/www\.w3\.org\/(1999\/02\/22-rdf-syntax-ns|2000\/01\/rdf-schema)#/.test(type);
|
|
8
|
+
/**
|
|
9
|
+
* Recursively freezes registry-owned objects and arrays.
|
|
10
|
+
*
|
|
11
|
+
* Definitions are normalized into new objects before reaching this function,
|
|
12
|
+
* so freezing them never mutates the caller's original input objects.
|
|
13
|
+
*/
|
|
14
|
+
const deepFreeze = (value) => {
|
|
15
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
16
|
+
Object.freeze(value);
|
|
17
|
+
for (const nestedValue of Object.values(value)) deepFreeze(nestedValue);
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
const normalizeEnumerationValue = (value) => ({
|
|
21
|
+
...value,
|
|
22
|
+
type: normalizeType(value.type)
|
|
23
|
+
});
|
|
24
|
+
const normalizeProperty = (property) => ({
|
|
25
|
+
...property,
|
|
26
|
+
expectedTypes: property.expectedTypes?.map(normalizeType),
|
|
27
|
+
rangeTypes: property.rangeTypes?.map(normalizeType),
|
|
28
|
+
domainTypes: property.domainTypes?.map(normalizeType),
|
|
29
|
+
inverseOf: property.inverseOf ? normalizeType(property.inverseOf) : void 0,
|
|
30
|
+
supersededBy: property.supersededBy ? normalizeType(property.supersededBy) : void 0,
|
|
31
|
+
type: Array.isArray(property.type) ? property.type.map(normalizeType) : normalizeType(property.type)
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Normalizes a definition and assigns its authoritative source.
|
|
35
|
+
*
|
|
36
|
+
* The source is determined by the collection the definition came from,
|
|
37
|
+
* never by the caller-provided source property.
|
|
38
|
+
*/
|
|
39
|
+
const normalizeDefinition = (definition, source) => ({
|
|
40
|
+
...definition,
|
|
41
|
+
type: normalizeType(definition.type),
|
|
42
|
+
source,
|
|
43
|
+
parentTypes: definition.parentTypes?.map(normalizeType),
|
|
44
|
+
enumerationValues: definition.enumerationValues?.map(normalizeEnumerationValue),
|
|
45
|
+
properties: definition.properties?.map(normalizeProperty)
|
|
46
|
+
});
|
|
47
|
+
const deduplicateProperties = (definitions, conflicts) => {
|
|
48
|
+
for (const definition of definitions) {
|
|
49
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50
|
+
definition.properties = definition.properties?.filter((property) => {
|
|
51
|
+
if (seen.has(property.name)) {
|
|
52
|
+
conflicts.push({
|
|
53
|
+
type: definition.type,
|
|
54
|
+
property: property.name,
|
|
55
|
+
code: "duplicate-property",
|
|
56
|
+
message: `Duplicate property ${property.name} on ${definition.type}.`
|
|
57
|
+
});
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
seen.add(property.name);
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const createSchemaRegistry = (options = {}) => {
|
|
66
|
+
const generated = (options.generated ?? []).map((definition) => normalizeDefinition(definition, "generated"));
|
|
67
|
+
const custom = (options.custom ?? []).map((definition) => normalizeDefinition(definition, "custom"));
|
|
68
|
+
const conflicts = [];
|
|
69
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
70
|
+
for (const definition of generated) {
|
|
71
|
+
if (definitions.has(definition.type)) {
|
|
72
|
+
conflicts.push({
|
|
73
|
+
type: definition.type,
|
|
74
|
+
code: "duplicate-type",
|
|
75
|
+
message: `Duplicate generated schema type: ${definition.type}`
|
|
76
|
+
});
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
definitions.set(definition.type, definition);
|
|
80
|
+
}
|
|
81
|
+
for (const definition of custom) {
|
|
82
|
+
const existing = definitions.get(definition.type);
|
|
83
|
+
if (existing) {
|
|
84
|
+
if (!(options.allowGeneratedOverrides === true && existing.source === "generated")) {
|
|
85
|
+
conflicts.push({
|
|
86
|
+
type: definition.type,
|
|
87
|
+
code: "duplicate-type",
|
|
88
|
+
message: existing.source === "generated" ? `Custom schema type conflicts with generated type: ${definition.type}` : `Duplicate custom schema type: ${definition.type}`
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
definitions.set(definition.type, definition);
|
|
94
|
+
}
|
|
95
|
+
deduplicateProperties(definitions.values(), conflicts);
|
|
96
|
+
for (const extension of options.extensions ?? []) {
|
|
97
|
+
const type = normalizeType(extension.type);
|
|
98
|
+
const existing = definitions.get(type);
|
|
99
|
+
if (!existing) {
|
|
100
|
+
conflicts.push({
|
|
101
|
+
type,
|
|
102
|
+
code: "unknown-parent",
|
|
103
|
+
message: `Cannot extend unknown schema type: ${type}`
|
|
104
|
+
});
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (extension.namespace && existing.namespace && extension.namespace !== existing.namespace) {
|
|
108
|
+
conflicts.push({
|
|
109
|
+
type,
|
|
110
|
+
code: "namespace-mismatch",
|
|
111
|
+
message: `Extension namespace does not match ${type}.`
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const properties = /* @__PURE__ */ new Map();
|
|
116
|
+
for (const property of existing.properties ?? []) properties.set(property.name, property);
|
|
117
|
+
const extensionPropertyNames = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const property of extension.properties) {
|
|
119
|
+
if (properties.has(property.name) || extensionPropertyNames.has(property.name)) {
|
|
120
|
+
conflicts.push({
|
|
121
|
+
type,
|
|
122
|
+
property: property.name,
|
|
123
|
+
code: "duplicate-property",
|
|
124
|
+
message: `Property ${property.name} already exists on ${type}.`
|
|
125
|
+
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
extensionPropertyNames.add(property.name);
|
|
129
|
+
properties.set(property.name, normalizeProperty(property));
|
|
130
|
+
}
|
|
131
|
+
definitions.set(type, {
|
|
132
|
+
...existing,
|
|
133
|
+
properties: [...properties.values()]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
for (const definition of definitions.values()) for (const parentType of definition.parentTypes ?? []) {
|
|
137
|
+
if (definitions.has(parentType) || isRdfVocabularyType(parentType)) continue;
|
|
138
|
+
conflicts.push({
|
|
139
|
+
type: definition.type,
|
|
140
|
+
code: "unknown-parent",
|
|
141
|
+
message: `Unknown parent type ${parentType} referenced by ${definition.type}.`
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (const definition of definitions.values()) deepFreeze(definition);
|
|
145
|
+
const frozenGenerated = deepFreeze(generated);
|
|
146
|
+
const frozenCustom = deepFreeze(custom);
|
|
147
|
+
const collection = deepFreeze({
|
|
148
|
+
generated: frozenGenerated,
|
|
149
|
+
custom: frozenCustom
|
|
150
|
+
});
|
|
151
|
+
const frozenConflicts = deepFreeze(conflicts);
|
|
152
|
+
const get = (type) => definitions.get(normalizeType(type));
|
|
153
|
+
const getAncestors = (type, visited = /* @__PURE__ */ new Set()) => {
|
|
154
|
+
const definition = get(type);
|
|
155
|
+
if (!definition) return [];
|
|
156
|
+
const result = [];
|
|
157
|
+
for (const parentType of definition.parentTypes ?? []) {
|
|
158
|
+
if (visited.has(parentType)) continue;
|
|
159
|
+
visited.add(parentType);
|
|
160
|
+
const parent = get(parentType);
|
|
161
|
+
if (!parent) continue;
|
|
162
|
+
result.push(parent);
|
|
163
|
+
result.push(...getAncestors(parentType, visited));
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
};
|
|
167
|
+
const getProperties = (type, inherited = true) => {
|
|
168
|
+
const definition = get(type);
|
|
169
|
+
if (!definition) return [];
|
|
170
|
+
const properties = /* @__PURE__ */ new Map();
|
|
171
|
+
if (inherited) for (const ancestor of [...getAncestors(type)].reverse()) for (const property of ancestor.properties ?? []) properties.set(property.name, property);
|
|
172
|
+
for (const property of definition.properties ?? []) properties.set(property.name, property);
|
|
173
|
+
return [...properties.values()];
|
|
174
|
+
};
|
|
175
|
+
const isTypeOf = (type, expectedType) => {
|
|
176
|
+
const normalizedType = normalizeType(type);
|
|
177
|
+
const normalizedExpected = normalizeType(expectedType);
|
|
178
|
+
return normalizedType === normalizedExpected || getAncestors(normalizedType).some((ancestor) => ancestor.type === normalizedExpected);
|
|
179
|
+
};
|
|
180
|
+
return Object.freeze({
|
|
181
|
+
get,
|
|
182
|
+
has: (type) => Boolean(get(type)),
|
|
183
|
+
getAll: () => [...definitions.values()],
|
|
184
|
+
getProperty: (type, property) => getProperties(type).find((item) => item.name === property),
|
|
185
|
+
getProperties: (type, options) => getProperties(type, options?.inherited ?? true),
|
|
186
|
+
getAncestors,
|
|
187
|
+
isTypeOf,
|
|
188
|
+
getCollection: () => collection,
|
|
189
|
+
getConflicts: () => frozenConflicts
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
export { createSchemaRegistry };
|
|
193
|
+
|
|
194
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/schema/registry.ts"],"sourcesContent":["import type {\n SchemaDefinition,\n SchemaEnumerationValue,\n SchemaPropertyDefinition,\n SchemaRegistry,\n SchemaRegistryConflict,\n SchemaRegistryOptions,\n} from \"./types\";\n\nconst normalizeType = (type: string): string => {\n const value = type.trim();\n\n if (!value) {\n throw new Error(\"Schema type cannot be empty.\");\n }\n\n return /^[A-Za-z][A-Za-z0-9]*$/.test(value)\n ? `https://schema.org/${value}`\n : value.replace(/^http:\\/\\/schema\\.org\\//, \"https://schema.org/\");\n};\n\nconst isRdfVocabularyType = (type: string): boolean =>\n /^https?:\\/\\/www\\.w3\\.org\\/(1999\\/02\\/22-rdf-syntax-ns|2000\\/01\\/rdf-schema)#/.test(\n type,\n );\n\n/**\n * Recursively freezes registry-owned objects and arrays.\n *\n * Definitions are normalized into new objects before reaching this function,\n * so freezing them never mutates the caller's original input objects.\n */\nconst deepFreeze = <T>(value: T): T => {\n if (value === null || typeof value !== \"object\" || Object.isFrozen(value)) {\n return value;\n }\n\n Object.freeze(value);\n\n for (const nestedValue of Object.values(value)) {\n deepFreeze(nestedValue);\n }\n\n return value;\n};\n\nconst normalizeEnumerationValue = (\n value: SchemaEnumerationValue,\n): SchemaEnumerationValue => ({\n ...value,\n type: normalizeType(value.type),\n});\n\nconst normalizeProperty = (\n property: SchemaPropertyDefinition,\n): SchemaPropertyDefinition => ({\n ...property,\n expectedTypes: property.expectedTypes?.map(normalizeType),\n rangeTypes: property.rangeTypes?.map(normalizeType),\n domainTypes: property.domainTypes?.map(normalizeType),\n inverseOf: property.inverseOf ? normalizeType(property.inverseOf) : undefined,\n supersededBy: property.supersededBy\n ? normalizeType(property.supersededBy)\n : undefined,\n type: Array.isArray(property.type)\n ? property.type.map(normalizeType)\n : normalizeType(property.type),\n});\n\n/**\n * Normalizes a definition and assigns its authoritative source.\n *\n * The source is determined by the collection the definition came from,\n * never by the caller-provided source property.\n */\nconst normalizeDefinition = (\n definition: SchemaDefinition,\n source: SchemaDefinition[\"source\"],\n): SchemaDefinition => ({\n ...definition,\n type: normalizeType(definition.type),\n source,\n parentTypes: definition.parentTypes?.map(normalizeType),\n enumerationValues: definition.enumerationValues?.map(\n normalizeEnumerationValue,\n ),\n properties: definition.properties?.map(normalizeProperty),\n});\n\nconst deduplicateProperties = (\n definitions: Iterable<SchemaDefinition>,\n conflicts: SchemaRegistryConflict[],\n): void => {\n for (const definition of definitions) {\n const seen = new Set<string>();\n\n definition.properties = definition.properties?.filter((property) => {\n if (seen.has(property.name)) {\n conflicts.push({\n type: definition.type,\n property: property.name,\n code: \"duplicate-property\",\n message: `Duplicate property ${property.name} on ${definition.type}.`,\n });\n\n return false;\n }\n\n seen.add(property.name);\n return true;\n });\n }\n};\n\nexport const createSchemaRegistry = (\n options: SchemaRegistryOptions = {},\n): SchemaRegistry => {\n // Collection membership is the source of truth. Ignore any source value\n // supplied by callers to prevent custom definitions impersonating generated\n // definitions (or vice versa).\n const generated = (options.generated ?? []).map((definition) =>\n normalizeDefinition(definition, \"generated\"),\n );\n\n const custom = (options.custom ?? []).map((definition) =>\n normalizeDefinition(definition, \"custom\"),\n );\n\n const conflicts: SchemaRegistryConflict[] = [];\n\n const definitions = new Map<string, SchemaDefinition>();\n\n for (const definition of generated) {\n if (definitions.has(definition.type)) {\n conflicts.push({\n type: definition.type,\n code: \"duplicate-type\",\n message: `Duplicate generated schema type: ${definition.type}`,\n });\n\n continue;\n }\n\n definitions.set(definition.type, definition);\n }\n\n // Only generated definitions may be overridden, and only when explicitly\n // enabled. A custom definition can never silently replace another custom\n // definition, even when allowGeneratedOverrides is true.\n for (const definition of custom) {\n const existing = definitions.get(definition.type);\n\n if (existing) {\n const canOverrideGenerated =\n options.allowGeneratedOverrides === true &&\n existing.source === \"generated\";\n\n if (!canOverrideGenerated) {\n conflicts.push({\n type: definition.type,\n code: \"duplicate-type\",\n message:\n existing.source === \"generated\"\n ? `Custom schema type conflicts with generated type: ${definition.type}`\n : `Duplicate custom schema type: ${definition.type}`,\n });\n\n continue;\n }\n }\n\n definitions.set(definition.type, definition);\n }\n\n // Validate the effective definitions before applying extensions. This also\n // catches duplicates in definitions that would otherwise be collapsed by\n // the extension merge operation.\n deduplicateProperties(definitions.values(), conflicts);\n\n for (const extension of options.extensions ?? []) {\n const type = normalizeType(extension.type);\n const existing = definitions.get(type);\n\n if (!existing) {\n conflicts.push({\n type,\n code: \"unknown-parent\",\n message: `Cannot extend unknown schema type: ${type}`,\n });\n\n continue;\n }\n\n if (\n extension.namespace &&\n existing.namespace &&\n extension.namespace !== existing.namespace\n ) {\n conflicts.push({\n type,\n code: \"namespace-mismatch\",\n message: `Extension namespace does not match ${type}.`,\n });\n\n continue;\n }\n\n const properties = new Map<string, SchemaPropertyDefinition>();\n\n for (const property of existing.properties ?? []) {\n properties.set(property.name, property);\n }\n\n const extensionPropertyNames = new Set<string>();\n\n for (const property of extension.properties) {\n if (\n properties.has(property.name) ||\n extensionPropertyNames.has(property.name)\n ) {\n conflicts.push({\n type,\n property: property.name,\n code: \"duplicate-property\",\n message: `Property ${property.name} already exists on ${type}.`,\n });\n\n continue;\n }\n\n extensionPropertyNames.add(property.name);\n properties.set(property.name, normalizeProperty(property));\n }\n\n definitions.set(type, {\n ...existing,\n properties: [...properties.values()],\n });\n }\n\n // Report parent references that cannot be resolved by this registry.\n // RDF/RDFS meta-classes (e.g. DataType → rdfs:Class) are vocabulary\n // structure, not Schema.org types, so they are never registered.\n for (const definition of definitions.values()) {\n for (const parentType of definition.parentTypes ?? []) {\n if (definitions.has(parentType) || isRdfVocabularyType(parentType)) {\n continue;\n }\n\n conflicts.push({\n type: definition.type,\n code: \"unknown-parent\",\n message: `Unknown parent type ${parentType} referenced by ${definition.type}.`,\n });\n }\n }\n\n // Freeze every effective definition after all extensions have been applied.\n // This includes nested property metadata, enumeration values and arrays.\n for (const definition of definitions.values()) {\n deepFreeze(definition);\n }\n\n // Keep the generated/custom collections immutable as well. They contain\n // normalized copies, not references to the caller's original definitions.\n const frozenGenerated = deepFreeze(generated);\n const frozenCustom = deepFreeze(custom);\n\n const collection = deepFreeze({\n generated: frozenGenerated,\n custom: frozenCustom,\n });\n\n const frozenConflicts = deepFreeze(conflicts);\n\n const get = (type: string) => definitions.get(normalizeType(type));\n\n const getAncestors = (\n type: string,\n visited = new Set<string>(),\n ): SchemaDefinition[] => {\n const definition = get(type);\n\n if (!definition) {\n return [];\n }\n\n const result: SchemaDefinition[] = [];\n\n for (const parentType of definition.parentTypes ?? []) {\n if (visited.has(parentType)) {\n continue;\n }\n\n visited.add(parentType);\n\n const parent = get(parentType);\n\n if (!parent) {\n continue;\n }\n\n result.push(parent);\n result.push(...getAncestors(parentType, visited));\n }\n\n return result;\n };\n\n const getProperties = (\n type: string,\n inherited = true,\n ): readonly SchemaPropertyDefinition[] => {\n const definition = get(type);\n\n if (!definition) {\n return [];\n }\n\n const properties = new Map<string, SchemaPropertyDefinition>();\n\n if (inherited) {\n for (const ancestor of [...getAncestors(type)].reverse()) {\n for (const property of ancestor.properties ?? []) {\n properties.set(property.name, property);\n }\n }\n }\n\n for (const property of definition.properties ?? []) {\n properties.set(property.name, property);\n }\n\n return [...properties.values()];\n };\n\n const isTypeOf = (type: string, expectedType: string): boolean => {\n const normalizedType = normalizeType(type);\n const normalizedExpected = normalizeType(expectedType);\n\n return (\n normalizedType === normalizedExpected ||\n getAncestors(normalizedType).some(\n (ancestor) => ancestor.type === normalizedExpected,\n )\n );\n };\n\n return Object.freeze({\n get,\n has: (type: string) => Boolean(get(type)),\n getAll: () => [...definitions.values()],\n\n getProperty: (type: string, property: string) =>\n getProperties(type).find((item) => item.name === property),\n\n getProperties: (type: string, options?: { inherited?: boolean }) =>\n getProperties(type, options?.inherited ?? true),\n\n getAncestors,\n\n isTypeOf,\n\n getCollection: () => collection,\n\n getConflicts: () => frozenConflicts,\n });\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { JsonObject, SeoNode, SeoNodeId } from "../core/types.cjs";
|
|
2
|
+
export type SchemaDefinitionSource = "generated" | "custom";
|
|
3
|
+
export type SchemaPropertyType = string | string[];
|
|
4
|
+
export interface SchemaEnumerationValue {
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SchemaPropertyDefinition {
|
|
10
|
+
name: string;
|
|
11
|
+
type: SchemaPropertyType;
|
|
12
|
+
required?: boolean;
|
|
13
|
+
multiple?: boolean;
|
|
14
|
+
description?: string;
|
|
15
|
+
expectedTypes?: string[];
|
|
16
|
+
domainTypes?: string[];
|
|
17
|
+
rangeTypes?: string[];
|
|
18
|
+
inverseOf?: string;
|
|
19
|
+
supersededBy?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SchemaDefinition<T extends SeoNode = SeoNode> {
|
|
22
|
+
name: string;
|
|
23
|
+
type: string;
|
|
24
|
+
source: SchemaDefinitionSource;
|
|
25
|
+
description?: string;
|
|
26
|
+
properties?: readonly SchemaPropertyDefinition[];
|
|
27
|
+
parentTypes?: readonly string[];
|
|
28
|
+
enumerationValues?: readonly SchemaEnumerationValue[];
|
|
29
|
+
nodeType?: string;
|
|
30
|
+
namespace?: string;
|
|
31
|
+
create?: (input: JsonObject) => T;
|
|
32
|
+
}
|
|
33
|
+
export interface SchemaExtension {
|
|
34
|
+
type: string;
|
|
35
|
+
namespace?: string;
|
|
36
|
+
properties: readonly SchemaPropertyDefinition[];
|
|
37
|
+
description?: string;
|
|
38
|
+
parentTypes?: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export interface SchemaReference {
|
|
41
|
+
id: SeoNodeId | string;
|
|
42
|
+
type?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface SchemaRegistryProvider {
|
|
45
|
+
get(type: string): SchemaDefinition | undefined;
|
|
46
|
+
has(type: string): boolean;
|
|
47
|
+
getAll(): readonly SchemaDefinition[];
|
|
48
|
+
}
|
|
49
|
+
export interface SchemaValidationOptions {
|
|
50
|
+
strict?: boolean;
|
|
51
|
+
allowUnknownProperties?: boolean;
|
|
52
|
+
validateRequiredProperties?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface SchemaDefinitionCollection {
|
|
55
|
+
generated: readonly SchemaDefinition[];
|
|
56
|
+
custom: readonly SchemaDefinition[];
|
|
57
|
+
}
|
|
58
|
+
export interface SchemaRegistryConflict {
|
|
59
|
+
type: string;
|
|
60
|
+
property?: string;
|
|
61
|
+
code: "duplicate-type" | "duplicate-property" | "unknown-parent" | "namespace-mismatch";
|
|
62
|
+
message: string;
|
|
63
|
+
}
|
|
64
|
+
export interface SchemaRegistryOptions {
|
|
65
|
+
generated?: readonly SchemaDefinition[];
|
|
66
|
+
custom?: readonly SchemaDefinition[];
|
|
67
|
+
extensions?: readonly SchemaExtension[];
|
|
68
|
+
allowGeneratedOverrides?: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface SchemaRegistry extends SchemaRegistryProvider {
|
|
71
|
+
getProperty(type: string, property: string): SchemaPropertyDefinition | undefined;
|
|
72
|
+
getProperties(type: string, options?: {
|
|
73
|
+
inherited?: boolean;
|
|
74
|
+
}): readonly SchemaPropertyDefinition[];
|
|
75
|
+
getAncestors(type: string): readonly SchemaDefinition[];
|
|
76
|
+
isTypeOf(type: string, expectedType: string): boolean;
|
|
77
|
+
getCollection(): SchemaDefinitionCollection;
|
|
78
|
+
getConflicts(): readonly SchemaRegistryConflict[];
|
|
79
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { JsonObject, SeoNode, SeoNodeId } from "../core/types.js";
|
|
2
|
+
export type SchemaDefinitionSource = "generated" | "custom";
|
|
3
|
+
export type SchemaPropertyType = string | string[];
|
|
4
|
+
export interface SchemaEnumerationValue {
|
|
5
|
+
name: string;
|
|
6
|
+
type: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SchemaPropertyDefinition {
|
|
10
|
+
name: string;
|
|
11
|
+
type: SchemaPropertyType;
|
|
12
|
+
required?: boolean;
|
|
13
|
+
multiple?: boolean;
|
|
14
|
+
description?: string;
|
|
15
|
+
expectedTypes?: string[];
|
|
16
|
+
domainTypes?: string[];
|
|
17
|
+
rangeTypes?: string[];
|
|
18
|
+
inverseOf?: string;
|
|
19
|
+
supersededBy?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SchemaDefinition<T extends SeoNode = SeoNode> {
|
|
22
|
+
name: string;
|
|
23
|
+
type: string;
|
|
24
|
+
source: SchemaDefinitionSource;
|
|
25
|
+
description?: string;
|
|
26
|
+
properties?: readonly SchemaPropertyDefinition[];
|
|
27
|
+
parentTypes?: readonly string[];
|
|
28
|
+
enumerationValues?: readonly SchemaEnumerationValue[];
|
|
29
|
+
nodeType?: string;
|
|
30
|
+
namespace?: string;
|
|
31
|
+
create?: (input: JsonObject) => T;
|
|
32
|
+
}
|
|
33
|
+
export interface SchemaExtension {
|
|
34
|
+
type: string;
|
|
35
|
+
namespace?: string;
|
|
36
|
+
properties: readonly SchemaPropertyDefinition[];
|
|
37
|
+
description?: string;
|
|
38
|
+
parentTypes?: readonly string[];
|
|
39
|
+
}
|
|
40
|
+
export interface SchemaReference {
|
|
41
|
+
id: SeoNodeId | string;
|
|
42
|
+
type?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface SchemaRegistryProvider {
|
|
45
|
+
get(type: string): SchemaDefinition | undefined;
|
|
46
|
+
has(type: string): boolean;
|
|
47
|
+
getAll(): readonly SchemaDefinition[];
|
|
48
|
+
}
|
|
49
|
+
export interface SchemaValidationOptions {
|
|
50
|
+
strict?: boolean;
|
|
51
|
+
allowUnknownProperties?: boolean;
|
|
52
|
+
validateRequiredProperties?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface SchemaDefinitionCollection {
|
|
55
|
+
generated: readonly SchemaDefinition[];
|
|
56
|
+
custom: readonly SchemaDefinition[];
|
|
57
|
+
}
|
|
58
|
+
export interface SchemaRegistryConflict {
|
|
59
|
+
type: string;
|
|
60
|
+
property?: string;
|
|
61
|
+
code: "duplicate-type" | "duplicate-property" | "unknown-parent" | "namespace-mismatch";
|
|
62
|
+
message: string;
|
|
63
|
+
}
|
|
64
|
+
export interface SchemaRegistryOptions {
|
|
65
|
+
generated?: readonly SchemaDefinition[];
|
|
66
|
+
custom?: readonly SchemaDefinition[];
|
|
67
|
+
extensions?: readonly SchemaExtension[];
|
|
68
|
+
allowGeneratedOverrides?: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface SchemaRegistry extends SchemaRegistryProvider {
|
|
71
|
+
getProperty(type: string, property: string): SchemaPropertyDefinition | undefined;
|
|
72
|
+
getProperties(type: string, options?: {
|
|
73
|
+
inherited?: boolean;
|
|
74
|
+
}): readonly SchemaPropertyDefinition[];
|
|
75
|
+
getAncestors(type: string): readonly SchemaDefinition[];
|
|
76
|
+
isTypeOf(type: string, expectedType: string): boolean;
|
|
77
|
+
getCollection(): SchemaDefinitionCollection;
|
|
78
|
+
getConflicts(): readonly SchemaRegistryConflict[];
|
|
79
|
+
}
|