@unispechq/unispec-core 0.2.10 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/converters/index.js +20 -13
- package/dist/cjs/diff/index.js +18 -5
- package/dist/cjs/loader/index.js +61 -6
- package/dist/cjs/normalizer/index.js +22 -8
- package/dist/cjs/schemas/index.js +13 -10
- package/dist/cjs/validator/generated-schemas.js +827 -0
- package/dist/cjs/validator/index.js +8 -90
- package/dist/converters/index.d.ts +1 -0
- package/dist/converters/index.js +20 -13
- package/dist/diff/index.d.ts +18 -5
- package/dist/diff/index.js +18 -5
- package/dist/loader/index.d.ts +3 -4
- package/dist/loader/index.js +28 -6
- package/dist/normalizer/index.d.ts +16 -2
- package/dist/normalizer/index.js +22 -8
- package/dist/schemas/index.js +13 -10
- package/dist/types/index.d.ts +7 -1
- package/dist/validator/generated-schemas.d.ts +842 -0
- package/dist/validator/generated-schemas.js +824 -0
- package/dist/validator/index.js +8 -57
- package/package.json +8 -3
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -39,58 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
6
|
exports.validateUniSpec = validateUniSpec;
|
|
40
7
|
exports.validateUniSpecTests = validateUniSpecTests;
|
|
41
8
|
const _2020_js_1 = __importDefault(require("ajv/dist/2020.js"));
|
|
9
|
+
const generated_schemas_js_1 = require("./generated-schemas.js");
|
|
42
10
|
let cached = null;
|
|
43
|
-
async function tryCreateNodeSchemaProvider() {
|
|
44
|
-
try {
|
|
45
|
-
const fs = await Promise.resolve().then(() => __importStar(require("node:fs/promises")));
|
|
46
|
-
const path = await Promise.resolve().then(() => __importStar(require("node:path")));
|
|
47
|
-
const module = await Promise.resolve().then(() => __importStar(require("node:module")));
|
|
48
|
-
const requireBasePath = typeof __filename === "string" && __filename.length > 0
|
|
49
|
-
? __filename
|
|
50
|
-
: path.join(process.cwd(), "__unispec_core_require__.js");
|
|
51
|
-
const require = module.createRequire(requireBasePath);
|
|
52
|
-
const schemaIndexPath = require.resolve("@unispechq/unispec-schema/schema");
|
|
53
|
-
const schemaRoot = path.dirname(schemaIndexPath);
|
|
54
|
-
return {
|
|
55
|
-
getSchema: async (schemaPath) => {
|
|
56
|
-
const fullPath = path.join(schemaRoot, schemaPath);
|
|
57
|
-
const json = await fs.readFile(fullPath, "utf8");
|
|
58
|
-
return JSON.parse(json);
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
11
|
async function loadDefaultSchemas() {
|
|
67
|
-
|
|
68
|
-
if (!schemaProvider) {
|
|
69
|
-
throw new Error("UniSpec validator: default schema loading is not available in this environment. " +
|
|
70
|
-
"Provide ValidateOptions.schemas (recommended for browsers/edge runtimes) or ValidateOptions.schemaProvider.");
|
|
71
|
-
}
|
|
72
|
-
const { manifest, unispec } = (await Promise.resolve().then(() => __importStar(require("@unispechq/unispec-schema"))));
|
|
73
|
-
const types = manifest?.types ?? {};
|
|
74
|
-
const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
|
|
75
|
-
const subschemas = await Promise.all(typeSchemaPaths.map(async (relPath) => {
|
|
76
|
-
try {
|
|
77
|
-
return await schemaProvider.getSchema(relPath);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
}));
|
|
83
|
-
let unispecTests;
|
|
84
|
-
try {
|
|
85
|
-
unispecTests = await schemaProvider.getSchema("unispec-tests.schema.json");
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
unispecTests = undefined;
|
|
89
|
-
}
|
|
12
|
+
// Always use generated schemas - they work in all environments
|
|
90
13
|
return {
|
|
91
|
-
unispec: unispec,
|
|
92
|
-
unispecTests,
|
|
93
|
-
subschemas: subschemas
|
|
14
|
+
unispec: generated_schemas_js_1.GENERATED_SCHEMAS.unispec,
|
|
15
|
+
unispecTests: generated_schemas_js_1.GENERATED_SCHEMAS.unispecTests,
|
|
16
|
+
subschemas: generated_schemas_js_1.GENERATED_SCHEMAS.subschemas,
|
|
94
17
|
};
|
|
95
18
|
}
|
|
96
19
|
function createAjv(options) {
|
|
@@ -138,15 +61,10 @@ function mapAjvErrors(errors) {
|
|
|
138
61
|
*/
|
|
139
62
|
async function validateUniSpec(doc, options = {}) {
|
|
140
63
|
const { validateUniSpecFn } = await getValidator(options);
|
|
64
|
+
// Ensure the document has required fields for validation
|
|
141
65
|
const docForValidation = {
|
|
142
|
-
unispecVersion: "
|
|
143
|
-
service:
|
|
144
|
-
name: doc.name,
|
|
145
|
-
description: doc.description,
|
|
146
|
-
version: doc.version,
|
|
147
|
-
protocols: doc.protocols,
|
|
148
|
-
schemas: doc.schemas,
|
|
149
|
-
},
|
|
66
|
+
unispecVersion: doc.unispecVersion || "1.0.0",
|
|
67
|
+
service: doc.service,
|
|
150
68
|
extensions: doc.extensions,
|
|
151
69
|
};
|
|
152
70
|
const valid = validateUniSpecFn(docForValidation);
|
package/dist/converters/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export function toOpenAPI(doc) {
|
|
2
|
-
const rest = (doc.protocols?.rest ?? {});
|
|
2
|
+
const rest = (doc.service?.protocols?.rest ?? {});
|
|
3
3
|
const info = {
|
|
4
|
-
title: doc.name,
|
|
5
|
-
description: doc.description,
|
|
4
|
+
title: doc.service.name,
|
|
5
|
+
description: doc.service.description,
|
|
6
6
|
};
|
|
7
7
|
const servers = [];
|
|
8
8
|
const paths = {};
|
|
9
9
|
const components = {};
|
|
10
|
-
// Map doc.schemas into OpenAPI components.schemas
|
|
11
|
-
const schemas = (doc.schemas ?? {});
|
|
10
|
+
// Map doc.service.schemas into OpenAPI components.schemas
|
|
11
|
+
const schemas = (doc.service?.schemas ?? {});
|
|
12
12
|
const componentsSchemas = {};
|
|
13
13
|
for (const [name, def] of Object.entries(schemas)) {
|
|
14
14
|
componentsSchemas[name] = def.jsonSchema;
|
|
@@ -133,13 +133,16 @@ export function toGraphQLSDL(doc) {
|
|
|
133
133
|
// via a Query field. This does not attempt to interpret the full GraphQL
|
|
134
134
|
// protocol structure yet, but provides a stable, deterministic SDL shape
|
|
135
135
|
// based on top-level UniSpec document fields.
|
|
136
|
-
const graphql = doc.protocols?.graphql;
|
|
136
|
+
const graphql = doc.service?.protocols?.graphql;
|
|
137
137
|
const customSDL = graphql?.schema;
|
|
138
138
|
if (typeof customSDL === "string" && customSDL.trim()) {
|
|
139
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
sdl: customSDL,
|
|
141
|
+
url: graphql?.url
|
|
142
|
+
};
|
|
140
143
|
}
|
|
141
|
-
const title = doc.name;
|
|
142
|
-
const description = doc.description ?? "";
|
|
144
|
+
const title = doc.service.name;
|
|
145
|
+
const description = doc.service.description ?? "";
|
|
143
146
|
const lines = [];
|
|
144
147
|
if (title || description) {
|
|
145
148
|
lines.push("\"\"");
|
|
@@ -160,14 +163,17 @@ export function toGraphQLSDL(doc) {
|
|
|
160
163
|
lines.push(" _serviceInfo: String!\n");
|
|
161
164
|
lines.push("}");
|
|
162
165
|
const sdl = lines.join("\n");
|
|
163
|
-
return {
|
|
166
|
+
return {
|
|
167
|
+
sdl,
|
|
168
|
+
url: graphql?.url
|
|
169
|
+
};
|
|
164
170
|
}
|
|
165
171
|
export function toWebSocketModel(doc) {
|
|
166
172
|
// Base WebSocket model intended for a modern, dashboard-oriented UI.
|
|
167
173
|
// It exposes service metadata, a normalized list of channels and the raw
|
|
168
174
|
// websocket protocol object, while also embedding the original UniSpec
|
|
169
175
|
// document under a technical key for debugging and introspection.
|
|
170
|
-
const websocket = (doc.protocols?.websocket ?? {});
|
|
176
|
+
const websocket = (doc.service?.protocols?.websocket ?? {});
|
|
171
177
|
const channelsArray = Array.isArray(websocket.channels) ? websocket.channels : [];
|
|
172
178
|
const channels = [...channelsArray]
|
|
173
179
|
.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""))
|
|
@@ -181,10 +187,11 @@ export function toWebSocketModel(doc) {
|
|
|
181
187
|
}));
|
|
182
188
|
return {
|
|
183
189
|
service: {
|
|
184
|
-
name: doc.name,
|
|
190
|
+
name: doc.service.name,
|
|
185
191
|
title: undefined,
|
|
186
|
-
description: doc.description,
|
|
192
|
+
description: doc.service.description,
|
|
187
193
|
},
|
|
194
|
+
url: websocket.url,
|
|
188
195
|
channels,
|
|
189
196
|
rawProtocol: websocket,
|
|
190
197
|
"x-unispec-ws": doc,
|
package/dist/diff/index.d.ts
CHANGED
|
@@ -11,11 +11,24 @@ export interface DiffResult {
|
|
|
11
11
|
changes: UniSpecChange[];
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Compare two UniSpec documents and return detected changes.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* -
|
|
19
|
-
* -
|
|
16
|
+
* This function performs a deep comparison between two UniSpec documents
|
|
17
|
+
* and categorizes changes by severity and protocol. Useful for:
|
|
18
|
+
* - API change detection in CI/CD pipelines
|
|
19
|
+
* - Breaking change analysis
|
|
20
|
+
* - Version compatibility checks
|
|
21
|
+
* - Audit trails for API evolution
|
|
22
|
+
*
|
|
23
|
+
* Features:
|
|
24
|
+
* - Detects added/removed fields at any depth
|
|
25
|
+
* - Special handling for named collections (routes, operations, channels)
|
|
26
|
+
* - Severity classification: "breaking" | "non-breaking" | "unknown"
|
|
27
|
+
* - Protocol categorization: "rest" | "graphql" | "websocket"
|
|
28
|
+
* - Detailed change descriptions with JSON paths
|
|
29
|
+
*
|
|
30
|
+
* @param oldDoc - The previous version of the UniSpec document
|
|
31
|
+
* @param newDoc - The current version of the UniSpec document
|
|
32
|
+
* @returns Object containing all detected changes
|
|
20
33
|
*/
|
|
21
34
|
export declare function diffUniSpec(oldDoc: UniSpecDocument, newDoc: UniSpecDocument): DiffResult;
|
package/dist/diff/index.js
CHANGED
|
@@ -218,12 +218,25 @@ function annotateGraphQLChange(change) {
|
|
|
218
218
|
return annotated;
|
|
219
219
|
}
|
|
220
220
|
/**
|
|
221
|
-
*
|
|
221
|
+
* Compare two UniSpec documents and return detected changes.
|
|
222
222
|
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
* -
|
|
226
|
-
* -
|
|
223
|
+
* This function performs a deep comparison between two UniSpec documents
|
|
224
|
+
* and categorizes changes by severity and protocol. Useful for:
|
|
225
|
+
* - API change detection in CI/CD pipelines
|
|
226
|
+
* - Breaking change analysis
|
|
227
|
+
* - Version compatibility checks
|
|
228
|
+
* - Audit trails for API evolution
|
|
229
|
+
*
|
|
230
|
+
* Features:
|
|
231
|
+
* - Detects added/removed fields at any depth
|
|
232
|
+
* - Special handling for named collections (routes, operations, channels)
|
|
233
|
+
* - Severity classification: "breaking" | "non-breaking" | "unknown"
|
|
234
|
+
* - Protocol categorization: "rest" | "graphql" | "websocket"
|
|
235
|
+
* - Detailed change descriptions with JSON paths
|
|
236
|
+
*
|
|
237
|
+
* @param oldDoc - The previous version of the UniSpec document
|
|
238
|
+
* @param newDoc - The current version of the UniSpec document
|
|
239
|
+
* @returns Object containing all detected changes
|
|
227
240
|
*/
|
|
228
241
|
export function diffUniSpec(oldDoc, newDoc) {
|
|
229
242
|
const changes = [];
|
package/dist/loader/index.d.ts
CHANGED
|
@@ -4,10 +4,9 @@ export interface LoadOptions {
|
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
6
|
* Load a UniSpec document from a raw input value.
|
|
7
|
-
*
|
|
7
|
+
* Supports:
|
|
8
8
|
* - JavaScript objects (treated as already parsed UniSpec)
|
|
9
9
|
* - JSON strings
|
|
10
|
-
*
|
|
11
|
-
* YAML and filesystem helpers will be added later, keeping this API stable.
|
|
10
|
+
* - YAML strings
|
|
12
11
|
*/
|
|
13
|
-
export declare function loadUniSpec(input: string | object,
|
|
12
|
+
export declare function loadUniSpec(input: string | object, options?: LoadOptions): Promise<UniSpecDocument>;
|
package/dist/loader/index.js
CHANGED
|
@@ -1,19 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Load a UniSpec document from a raw input value.
|
|
3
|
-
*
|
|
3
|
+
* Supports:
|
|
4
4
|
* - JavaScript objects (treated as already parsed UniSpec)
|
|
5
5
|
* - JSON strings
|
|
6
|
-
*
|
|
7
|
-
* YAML and filesystem helpers will be added later, keeping this API stable.
|
|
6
|
+
* - YAML strings
|
|
8
7
|
*/
|
|
9
|
-
export async function loadUniSpec(input,
|
|
8
|
+
export async function loadUniSpec(input, options = {}) {
|
|
10
9
|
if (typeof input === "string") {
|
|
11
10
|
const trimmed = input.trim();
|
|
12
11
|
if (!trimmed) {
|
|
13
12
|
throw new Error("Cannot load UniSpec: input string is empty");
|
|
14
13
|
}
|
|
15
|
-
//
|
|
16
|
-
|
|
14
|
+
// Try JSON first (faster and more common)
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(trimmed);
|
|
17
|
+
}
|
|
18
|
+
catch (jsonError) {
|
|
19
|
+
// If JSON fails, try YAML
|
|
20
|
+
try {
|
|
21
|
+
// Dynamic import to avoid bundling yaml parser if not needed
|
|
22
|
+
const yamlModule = await import("js-yaml");
|
|
23
|
+
if (!yamlModule.load) {
|
|
24
|
+
throw new Error("js-yaml module not available");
|
|
25
|
+
}
|
|
26
|
+
const doc = yamlModule.load(trimmed, {
|
|
27
|
+
filename: options.filename,
|
|
28
|
+
// Basic security options
|
|
29
|
+
schema: yamlModule.FAILSAFE_SCHEMA
|
|
30
|
+
});
|
|
31
|
+
return doc;
|
|
32
|
+
}
|
|
33
|
+
catch (yamlError) {
|
|
34
|
+
const jsonMsg = jsonError instanceof Error ? jsonError.message : String(jsonError);
|
|
35
|
+
const yamlMsg = yamlError instanceof Error ? yamlError.message : String(yamlError);
|
|
36
|
+
throw new Error(`Failed to parse input as JSON or YAML. JSON error: ${jsonMsg}. YAML error: ${yamlMsg}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
17
39
|
}
|
|
18
40
|
return input;
|
|
19
41
|
}
|
|
@@ -4,8 +4,22 @@ export interface NormalizeOptions {
|
|
|
4
4
|
/**
|
|
5
5
|
* Normalize a UniSpec document into a canonical, deterministic form.
|
|
6
6
|
*
|
|
7
|
+
* This function ensures consistent representation of UniSpec documents
|
|
8
|
+
* by sorting object keys and protocol-specific structures in a predictable order.
|
|
9
|
+
* Useful for:
|
|
10
|
+
* - Generating stable diffs between documents
|
|
11
|
+
* - Creating consistent output for caching
|
|
12
|
+
* - Ensuring reproducible builds
|
|
13
|
+
*
|
|
7
14
|
* Current behavior:
|
|
8
|
-
* - Recursively sorts object keys lexicographically
|
|
9
|
-
* -
|
|
15
|
+
* - Recursively sorts object keys lexicographically
|
|
16
|
+
* - Sorts REST routes by name or path+method
|
|
17
|
+
* - Sorts GraphQL operations by name within each operation type
|
|
18
|
+
* - Sorts WebSocket channels and messages by name
|
|
19
|
+
* - Preserves all values as-is
|
|
20
|
+
*
|
|
21
|
+
* @param doc - The UniSpec document to normalize
|
|
22
|
+
* @param options - Normalization options (currently unused, reserved for future)
|
|
23
|
+
* @returns The normalized UniSpec document
|
|
10
24
|
*/
|
|
11
25
|
export declare function normalizeUniSpec(doc: UniSpecDocument, _options?: NormalizeOptions): UniSpecDocument;
|
package/dist/normalizer/index.js
CHANGED
|
@@ -16,10 +16,10 @@ function normalizeValue(value) {
|
|
|
16
16
|
return value;
|
|
17
17
|
}
|
|
18
18
|
function normalizeRestRoutes(doc) {
|
|
19
|
-
if (!doc || !doc.protocols) {
|
|
19
|
+
if (!doc || !doc.service?.protocols) {
|
|
20
20
|
return doc;
|
|
21
21
|
}
|
|
22
|
-
const protocols = doc.protocols;
|
|
22
|
+
const protocols = doc.service.protocols;
|
|
23
23
|
const rest = protocols.rest;
|
|
24
24
|
if (!rest || !Array.isArray(rest.routes)) {
|
|
25
25
|
return doc;
|
|
@@ -34,10 +34,10 @@ function normalizeRestRoutes(doc) {
|
|
|
34
34
|
return doc;
|
|
35
35
|
}
|
|
36
36
|
function normalizeWebSocket(doc) {
|
|
37
|
-
if (!doc || !doc.protocols) {
|
|
37
|
+
if (!doc || !doc.service?.protocols) {
|
|
38
38
|
return doc;
|
|
39
39
|
}
|
|
40
|
-
const protocols = doc.protocols;
|
|
40
|
+
const protocols = doc.service.protocols;
|
|
41
41
|
const websocket = protocols.websocket;
|
|
42
42
|
if (!websocket || !Array.isArray(websocket.channels)) {
|
|
43
43
|
return doc;
|
|
@@ -65,10 +65,10 @@ function normalizeWebSocket(doc) {
|
|
|
65
65
|
return doc;
|
|
66
66
|
}
|
|
67
67
|
function normalizeGraphqlOperations(doc) {
|
|
68
|
-
if (!doc || !doc.protocols) {
|
|
68
|
+
if (!doc || !doc.service?.protocols) {
|
|
69
69
|
return doc;
|
|
70
70
|
}
|
|
71
|
-
const protocols = doc.protocols;
|
|
71
|
+
const protocols = doc.service.protocols;
|
|
72
72
|
const graphql = protocols.graphql;
|
|
73
73
|
if (!graphql) {
|
|
74
74
|
return doc;
|
|
@@ -94,9 +94,23 @@ function normalizeGraphqlOperations(doc) {
|
|
|
94
94
|
/**
|
|
95
95
|
* Normalize a UniSpec document into a canonical, deterministic form.
|
|
96
96
|
*
|
|
97
|
+
* This function ensures consistent representation of UniSpec documents
|
|
98
|
+
* by sorting object keys and protocol-specific structures in a predictable order.
|
|
99
|
+
* Useful for:
|
|
100
|
+
* - Generating stable diffs between documents
|
|
101
|
+
* - Creating consistent output for caching
|
|
102
|
+
* - Ensuring reproducible builds
|
|
103
|
+
*
|
|
97
104
|
* Current behavior:
|
|
98
|
-
* - Recursively sorts object keys lexicographically
|
|
99
|
-
* -
|
|
105
|
+
* - Recursively sorts object keys lexicographically
|
|
106
|
+
* - Sorts REST routes by name or path+method
|
|
107
|
+
* - Sorts GraphQL operations by name within each operation type
|
|
108
|
+
* - Sorts WebSocket channels and messages by name
|
|
109
|
+
* - Preserves all values as-is
|
|
110
|
+
*
|
|
111
|
+
* @param doc - The UniSpec document to normalize
|
|
112
|
+
* @param options - Normalization options (currently unused, reserved for future)
|
|
113
|
+
* @returns The normalized UniSpec document
|
|
100
114
|
*/
|
|
101
115
|
export function normalizeUniSpec(doc, _options = {}) {
|
|
102
116
|
const normalized = normalizeValue(doc);
|
package/dist/schemas/index.js
CHANGED
|
@@ -27,21 +27,24 @@ export function resolveSchemaRef(doc, ref) {
|
|
|
27
27
|
const name = normalizeSchemaRef(ref);
|
|
28
28
|
if (!name)
|
|
29
29
|
return undefined;
|
|
30
|
-
return doc.schemas?.[name];
|
|
30
|
+
return doc.service?.schemas?.[name];
|
|
31
31
|
}
|
|
32
32
|
export function registerSchema(doc, name, jsonSchema) {
|
|
33
|
-
if (!doc.
|
|
34
|
-
doc.
|
|
33
|
+
if (!doc.service) {
|
|
34
|
+
doc.service = { name: "" };
|
|
35
|
+
}
|
|
36
|
+
if (!doc.service.schemas) {
|
|
37
|
+
doc.service.schemas = {};
|
|
35
38
|
}
|
|
36
39
|
const definition = {
|
|
37
40
|
jsonSchema,
|
|
38
41
|
};
|
|
39
|
-
doc.schemas[name] = definition;
|
|
42
|
+
doc.service.schemas[name] = definition;
|
|
40
43
|
return definition;
|
|
41
44
|
}
|
|
42
45
|
function updateSchemaRefs(doc, mapping) {
|
|
43
|
-
const rest = doc.protocols?.rest;
|
|
44
|
-
const websocket = doc.protocols?.websocket;
|
|
46
|
+
const rest = doc.service?.protocols?.rest;
|
|
47
|
+
const websocket = doc.service?.protocols?.websocket;
|
|
45
48
|
if (rest?.routes) {
|
|
46
49
|
for (const route of rest.routes) {
|
|
47
50
|
for (const params of [route.pathParams, route.queryParams, route.headers]) {
|
|
@@ -101,13 +104,13 @@ function updateSchemaRefs(doc, mapping) {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
export function dedupeSchemas(doc) {
|
|
104
|
-
if (!doc.schemas)
|
|
107
|
+
if (!doc.service?.schemas)
|
|
105
108
|
return;
|
|
106
|
-
const names = Object.keys(doc.schemas);
|
|
109
|
+
const names = Object.keys(doc.service.schemas);
|
|
107
110
|
const hashToName = new Map();
|
|
108
111
|
const renameMap = {};
|
|
109
112
|
for (const name of names) {
|
|
110
|
-
const schema = doc.schemas[name];
|
|
113
|
+
const schema = doc.service.schemas[name];
|
|
111
114
|
const hash = stableStringify(schema?.jsonSchema ?? null);
|
|
112
115
|
const existing = hashToName.get(hash);
|
|
113
116
|
if (!existing) {
|
|
@@ -121,6 +124,6 @@ export function dedupeSchemas(doc) {
|
|
|
121
124
|
return;
|
|
122
125
|
updateSchemaRefs(doc, renameMap);
|
|
123
126
|
for (const dup of duplicates) {
|
|
124
|
-
delete doc.schemas[dup];
|
|
127
|
+
delete doc.service.schemas[dup];
|
|
125
128
|
}
|
|
126
129
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface UniSpecGraphQLOperation {
|
|
|
5
5
|
deprecationReason?: string;
|
|
6
6
|
}
|
|
7
7
|
export interface UniSpecGraphQLProtocol {
|
|
8
|
+
url?: string;
|
|
8
9
|
schema?: string;
|
|
9
10
|
queries?: UniSpecGraphQLOperation[];
|
|
10
11
|
mutations?: UniSpecGraphQLOperation[];
|
|
@@ -26,6 +27,7 @@ export interface UniSpecWebSocketChannel {
|
|
|
26
27
|
extensions?: Record<string, unknown>;
|
|
27
28
|
}
|
|
28
29
|
export interface UniSpecWebSocketProtocol {
|
|
30
|
+
url?: string;
|
|
29
31
|
channels?: UniSpecWebSocketChannel[];
|
|
30
32
|
securitySchemes?: Record<string, Record<string, unknown>>;
|
|
31
33
|
}
|
|
@@ -86,12 +88,16 @@ export interface UniSpecServiceProtocols {
|
|
|
86
88
|
websocket?: UniSpecWebSocketProtocol;
|
|
87
89
|
}
|
|
88
90
|
export interface UniSpecDocument {
|
|
91
|
+
unispecVersion: string;
|
|
92
|
+
service: UniSpecService;
|
|
93
|
+
extensions?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
export interface UniSpecService {
|
|
89
96
|
name: string;
|
|
90
97
|
description?: string;
|
|
91
98
|
version?: string;
|
|
92
99
|
protocols?: UniSpecServiceProtocols;
|
|
93
100
|
schemas?: UniSpecSchemas;
|
|
94
|
-
extensions?: Record<string, unknown>;
|
|
95
101
|
}
|
|
96
102
|
export interface ValidationError {
|
|
97
103
|
message: string;
|