@unispechq/unispec-core 0.2.4 → 0.2.5
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/validator/index.js +61 -35
- package/dist/validator/index.d.ts +1 -0
- package/dist/validator/index.js +61 -35
- package/package.json +1 -1
|
@@ -9,13 +9,29 @@ const _2020_js_1 = __importDefault(require("ajv/dist/2020.js"));
|
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
const module_1 = require("module");
|
|
12
|
+
const url_1 = require("url");
|
|
12
13
|
const unispec_schema_1 = require("@unispechq/unispec-schema");
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
function getThisModuleUrl() {
|
|
15
|
+
if (typeof __filename === "string" && __filename.length > 0) {
|
|
16
|
+
return (0, url_1.pathToFileURL)(__filename).href;
|
|
17
|
+
}
|
|
18
|
+
const stack = new Error().stack ?? "";
|
|
19
|
+
const fileUrlMatch = stack.match(/file:\/\/\/[^\s)]+/);
|
|
20
|
+
if (fileUrlMatch?.[0]) {
|
|
21
|
+
return fileUrlMatch[0];
|
|
22
|
+
}
|
|
23
|
+
const winPathMatch = stack.match(/[A-Za-z]:\\[^\s)]+/);
|
|
24
|
+
if (winPathMatch?.[0]) {
|
|
25
|
+
return (0, url_1.pathToFileURL)(winPathMatch[0]).href;
|
|
26
|
+
}
|
|
27
|
+
throw new Error("Cannot determine current module URL for createRequire()");
|
|
28
|
+
}
|
|
29
|
+
function getLocalRequire() {
|
|
30
|
+
if (typeof require !== "undefined") {
|
|
31
|
+
return require;
|
|
32
|
+
}
|
|
33
|
+
return (0, module_1.createRequire)(getThisModuleUrl());
|
|
34
|
+
}
|
|
19
35
|
function findPackageRoot(startFilePath) {
|
|
20
36
|
let dir = path_1.default.dirname(startFilePath);
|
|
21
37
|
for (let i = 0; i < 50; i++) {
|
|
@@ -31,8 +47,12 @@ function findPackageRoot(startFilePath) {
|
|
|
31
47
|
}
|
|
32
48
|
throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
|
|
33
49
|
}
|
|
34
|
-
function getUniSpecSchemaDir() {
|
|
35
|
-
const
|
|
50
|
+
function getUniSpecSchemaDir(options = {}) {
|
|
51
|
+
const override = options.schemaDir ?? process.env.UNISPEC_SCHEMA_DIR;
|
|
52
|
+
if (override) {
|
|
53
|
+
return override;
|
|
54
|
+
}
|
|
55
|
+
const localRequire = getLocalRequire();
|
|
36
56
|
try {
|
|
37
57
|
const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
|
|
38
58
|
return path_1.default.join(path_1.default.dirname(pkgJsonPath), "schema");
|
|
@@ -43,33 +63,43 @@ function getUniSpecSchemaDir() {
|
|
|
43
63
|
return path_1.default.join(pkgRoot, "schema");
|
|
44
64
|
}
|
|
45
65
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const schemaDir = getUniSpecSchemaDir();
|
|
66
|
+
const validatorCache = new Map();
|
|
67
|
+
function getCompiledValidator(options = {}) {
|
|
68
|
+
const schemaDir = getUniSpecSchemaDir(options);
|
|
69
|
+
const cached = validatorCache.get(schemaDir);
|
|
70
|
+
if (cached) {
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
const ajv = new _2020_js_1.default({
|
|
74
|
+
allErrors: true,
|
|
75
|
+
strict: true,
|
|
76
|
+
});
|
|
77
|
+
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
78
|
+
ajv.addFormat("uri", true);
|
|
79
|
+
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
49
80
|
const types = unispec_schema_1.manifest?.types ?? {};
|
|
50
81
|
const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
|
|
51
82
|
for (const relPath of typeSchemaPaths) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
const schema = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
58
|
-
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
59
|
-
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
60
|
-
ajv.addSchema(schema, fallbackId);
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
// Ignore individual schema registration failures to keep the validator usable.
|
|
83
|
+
const filePath = path_1.default.join(schemaDir, relPath);
|
|
84
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
85
|
+
continue;
|
|
64
86
|
}
|
|
87
|
+
const schema = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
88
|
+
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
89
|
+
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
90
|
+
ajv.addSchema(schema, fallbackId);
|
|
65
91
|
}
|
|
92
|
+
const validateFn = ajv.compile(unispec_schema_1.unispec);
|
|
93
|
+
const testsSchemaPath = path_1.default.join(schemaDir, "unispec-tests.schema.json");
|
|
94
|
+
const testsSchema = JSON.parse(fs_1.default.readFileSync(testsSchemaPath, "utf8"));
|
|
95
|
+
const validateTestsFn = ajv.compile(testsSchema);
|
|
96
|
+
const compiled = {
|
|
97
|
+
validateFn,
|
|
98
|
+
validateTestsFn,
|
|
99
|
+
};
|
|
100
|
+
validatorCache.set(schemaDir, compiled);
|
|
101
|
+
return compiled;
|
|
66
102
|
}
|
|
67
|
-
catch {
|
|
68
|
-
// If subschemas cannot be loaded for some reason, validation will still work for
|
|
69
|
-
// parts of the schema that do not rely on those $ref references.
|
|
70
|
-
}
|
|
71
|
-
const validateFn = ajv.compile(unispec_schema_1.unispec);
|
|
72
|
-
let validateTestsFn;
|
|
73
103
|
function mapAjvErrors(errors) {
|
|
74
104
|
if (!errors)
|
|
75
105
|
return [];
|
|
@@ -83,6 +113,7 @@ function mapAjvErrors(errors) {
|
|
|
83
113
|
* Validate a UniSpec document against the UniSpec JSON Schema.
|
|
84
114
|
*/
|
|
85
115
|
async function validateUniSpec(doc, _options = {}) {
|
|
116
|
+
const { validateFn } = getCompiledValidator(_options);
|
|
86
117
|
const docForValidation = {
|
|
87
118
|
unispecVersion: "0.0.0",
|
|
88
119
|
service: {
|
|
@@ -110,12 +141,7 @@ async function validateUniSpec(doc, _options = {}) {
|
|
|
110
141
|
* Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
|
|
111
142
|
*/
|
|
112
143
|
async function validateUniSpecTests(doc, _options = {}) {
|
|
113
|
-
|
|
114
|
-
const schemaDir = getUniSpecSchemaDir();
|
|
115
|
-
const testsSchemaPath = path_1.default.join(schemaDir, "unispec-tests.schema.json");
|
|
116
|
-
const testsSchema = JSON.parse(fs_1.default.readFileSync(testsSchemaPath, "utf8"));
|
|
117
|
-
validateTestsFn = ajv.compile(testsSchema);
|
|
118
|
-
}
|
|
144
|
+
const { validateTestsFn } = getCompiledValidator(_options);
|
|
119
145
|
const valid = validateTestsFn(doc);
|
|
120
146
|
if (valid) {
|
|
121
147
|
return {
|
package/dist/validator/index.js
CHANGED
|
@@ -2,13 +2,29 @@ import Ajv2020 from "ajv/dist/2020.js";
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
+
import { pathToFileURL } from "url";
|
|
5
6
|
import { unispec as unispecSchema, manifest as unispecManifest } from "@unispechq/unispec-schema";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
function getThisModuleUrl() {
|
|
8
|
+
if (typeof __filename === "string" && __filename.length > 0) {
|
|
9
|
+
return pathToFileURL(__filename).href;
|
|
10
|
+
}
|
|
11
|
+
const stack = new Error().stack ?? "";
|
|
12
|
+
const fileUrlMatch = stack.match(/file:\/\/\/[^\s)]+/);
|
|
13
|
+
if (fileUrlMatch?.[0]) {
|
|
14
|
+
return fileUrlMatch[0];
|
|
15
|
+
}
|
|
16
|
+
const winPathMatch = stack.match(/[A-Za-z]:\\[^\s)]+/);
|
|
17
|
+
if (winPathMatch?.[0]) {
|
|
18
|
+
return pathToFileURL(winPathMatch[0]).href;
|
|
19
|
+
}
|
|
20
|
+
throw new Error("Cannot determine current module URL for createRequire()");
|
|
21
|
+
}
|
|
22
|
+
function getLocalRequire() {
|
|
23
|
+
if (typeof require !== "undefined") {
|
|
24
|
+
return require;
|
|
25
|
+
}
|
|
26
|
+
return createRequire(getThisModuleUrl());
|
|
27
|
+
}
|
|
12
28
|
function findPackageRoot(startFilePath) {
|
|
13
29
|
let dir = path.dirname(startFilePath);
|
|
14
30
|
for (let i = 0; i < 50; i++) {
|
|
@@ -24,8 +40,12 @@ function findPackageRoot(startFilePath) {
|
|
|
24
40
|
}
|
|
25
41
|
throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
|
|
26
42
|
}
|
|
27
|
-
function getUniSpecSchemaDir() {
|
|
28
|
-
const
|
|
43
|
+
function getUniSpecSchemaDir(options = {}) {
|
|
44
|
+
const override = options.schemaDir ?? process.env.UNISPEC_SCHEMA_DIR;
|
|
45
|
+
if (override) {
|
|
46
|
+
return override;
|
|
47
|
+
}
|
|
48
|
+
const localRequire = getLocalRequire();
|
|
29
49
|
try {
|
|
30
50
|
const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
|
|
31
51
|
return path.join(path.dirname(pkgJsonPath), "schema");
|
|
@@ -36,33 +56,43 @@ function getUniSpecSchemaDir() {
|
|
|
36
56
|
return path.join(pkgRoot, "schema");
|
|
37
57
|
}
|
|
38
58
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const schemaDir = getUniSpecSchemaDir();
|
|
59
|
+
const validatorCache = new Map();
|
|
60
|
+
function getCompiledValidator(options = {}) {
|
|
61
|
+
const schemaDir = getUniSpecSchemaDir(options);
|
|
62
|
+
const cached = validatorCache.get(schemaDir);
|
|
63
|
+
if (cached) {
|
|
64
|
+
return cached;
|
|
65
|
+
}
|
|
66
|
+
const ajv = new Ajv2020({
|
|
67
|
+
allErrors: true,
|
|
68
|
+
strict: true,
|
|
69
|
+
});
|
|
70
|
+
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
71
|
+
ajv.addFormat("uri", true);
|
|
72
|
+
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
42
73
|
const types = unispecManifest?.types ?? {};
|
|
43
74
|
const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
|
|
44
75
|
for (const relPath of typeSchemaPaths) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const schema = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
51
|
-
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
52
|
-
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
53
|
-
ajv.addSchema(schema, fallbackId);
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
// Ignore individual schema registration failures to keep the validator usable.
|
|
76
|
+
const filePath = path.join(schemaDir, relPath);
|
|
77
|
+
if (!fs.existsSync(filePath)) {
|
|
78
|
+
continue;
|
|
57
79
|
}
|
|
80
|
+
const schema = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
81
|
+
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
82
|
+
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
83
|
+
ajv.addSchema(schema, fallbackId);
|
|
58
84
|
}
|
|
85
|
+
const validateFn = ajv.compile(unispecSchema);
|
|
86
|
+
const testsSchemaPath = path.join(schemaDir, "unispec-tests.schema.json");
|
|
87
|
+
const testsSchema = JSON.parse(fs.readFileSync(testsSchemaPath, "utf8"));
|
|
88
|
+
const validateTestsFn = ajv.compile(testsSchema);
|
|
89
|
+
const compiled = {
|
|
90
|
+
validateFn,
|
|
91
|
+
validateTestsFn,
|
|
92
|
+
};
|
|
93
|
+
validatorCache.set(schemaDir, compiled);
|
|
94
|
+
return compiled;
|
|
59
95
|
}
|
|
60
|
-
catch {
|
|
61
|
-
// If subschemas cannot be loaded for some reason, validation will still work for
|
|
62
|
-
// parts of the schema that do not rely on those $ref references.
|
|
63
|
-
}
|
|
64
|
-
const validateFn = ajv.compile(unispecSchema);
|
|
65
|
-
let validateTestsFn;
|
|
66
96
|
function mapAjvErrors(errors) {
|
|
67
97
|
if (!errors)
|
|
68
98
|
return [];
|
|
@@ -76,6 +106,7 @@ function mapAjvErrors(errors) {
|
|
|
76
106
|
* Validate a UniSpec document against the UniSpec JSON Schema.
|
|
77
107
|
*/
|
|
78
108
|
export async function validateUniSpec(doc, _options = {}) {
|
|
109
|
+
const { validateFn } = getCompiledValidator(_options);
|
|
79
110
|
const docForValidation = {
|
|
80
111
|
unispecVersion: "0.0.0",
|
|
81
112
|
service: {
|
|
@@ -103,12 +134,7 @@ export async function validateUniSpec(doc, _options = {}) {
|
|
|
103
134
|
* Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
|
|
104
135
|
*/
|
|
105
136
|
export async function validateUniSpecTests(doc, _options = {}) {
|
|
106
|
-
|
|
107
|
-
const schemaDir = getUniSpecSchemaDir();
|
|
108
|
-
const testsSchemaPath = path.join(schemaDir, "unispec-tests.schema.json");
|
|
109
|
-
const testsSchema = JSON.parse(fs.readFileSync(testsSchemaPath, "utf8"));
|
|
110
|
-
validateTestsFn = ajv.compile(testsSchema);
|
|
111
|
-
}
|
|
137
|
+
const { validateTestsFn } = getCompiledValidator(_options);
|
|
112
138
|
const valid = validateTestsFn(doc);
|
|
113
139
|
if (valid) {
|
|
114
140
|
return {
|
package/package.json
CHANGED