@unispechq/unispec-core 0.2.6 → 0.2.8
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 +26 -106
- package/dist/validator/index.d.ts +0 -1
- package/dist/validator/index.js +26 -106
- package/package.json +1 -1
|
@@ -8,114 +8,30 @@ exports.validateUniSpecTests = validateUniSpecTests;
|
|
|
8
8
|
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
|
-
const module_1 = require("module");
|
|
12
|
-
const url_1 = require("url");
|
|
13
11
|
const unispec_schema_1 = require("@unispechq/unispec-schema");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
return (0, module_1.createRequire)(getThisModuleUrl());
|
|
31
|
-
}
|
|
32
|
-
function assertValidSchemaDir(schemaDir) {
|
|
33
|
-
const requiredFiles = [
|
|
34
|
-
path_1.default.join(schemaDir, "types", "service.schema.json"),
|
|
35
|
-
path_1.default.join(schemaDir, "unispec-tests.schema.json"),
|
|
36
|
-
];
|
|
37
|
-
const missing = requiredFiles.filter((p) => !fs_1.default.existsSync(p));
|
|
38
|
-
if (missing.length === 0) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const hints = [
|
|
42
|
-
`UniSpec schema directory is invalid or incomplete: ${schemaDir}`,
|
|
43
|
-
`Missing schema files:`,
|
|
44
|
-
...missing.map((p) => `- ${p}`),
|
|
45
|
-
`You can override the schema directory via ValidateOptions.schemaDir or UNISPEC_SCHEMA_DIR env var.`,
|
|
46
|
-
`In bundled environments (e.g. Next.js), module resolution can be altered; make sure @unispechq/unispec-schema is installed and accessible at runtime.`,
|
|
47
|
-
];
|
|
48
|
-
throw new Error(hints.join("\n"));
|
|
49
|
-
}
|
|
50
|
-
function findPackageRoot(startFilePath) {
|
|
51
|
-
let dir = path_1.default.dirname(startFilePath);
|
|
52
|
-
for (let i = 0; i < 50; i++) {
|
|
53
|
-
const pkgJsonPath = path_1.default.join(dir, "package.json");
|
|
54
|
-
if (fs_1.default.existsSync(pkgJsonPath)) {
|
|
55
|
-
return dir;
|
|
56
|
-
}
|
|
57
|
-
const parent = path_1.default.dirname(dir);
|
|
58
|
-
if (parent === dir) {
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
dir = parent;
|
|
62
|
-
}
|
|
63
|
-
throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
|
|
64
|
-
}
|
|
65
|
-
function getUniSpecSchemaDir(options = {}) {
|
|
66
|
-
const override = options.schemaDir ?? process.env.UNISPEC_SCHEMA_DIR;
|
|
67
|
-
if (override) {
|
|
68
|
-
return override;
|
|
69
|
-
}
|
|
70
|
-
const localRequire = getLocalRequire();
|
|
71
|
-
try {
|
|
72
|
-
const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
|
|
73
|
-
return path_1.default.join(path_1.default.dirname(pkgJsonPath), "schema");
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
const entryPath = localRequire.resolve("@unispechq/unispec-schema");
|
|
77
|
-
const pkgRoot = findPackageRoot(entryPath);
|
|
78
|
-
return path_1.default.join(pkgRoot, "schema");
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
const validatorCache = new Map();
|
|
82
|
-
function getCompiledValidator(options = {}) {
|
|
83
|
-
const schemaDir = getUniSpecSchemaDir(options);
|
|
84
|
-
assertValidSchemaDir(schemaDir);
|
|
85
|
-
const cached = validatorCache.get(schemaDir);
|
|
86
|
-
if (cached) {
|
|
87
|
-
return cached;
|
|
88
|
-
}
|
|
89
|
-
const ajv = new _2020_js_1.default({
|
|
90
|
-
allErrors: true,
|
|
91
|
-
strict: true,
|
|
92
|
-
});
|
|
93
|
-
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
94
|
-
ajv.addFormat("uri", true);
|
|
95
|
-
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
12
|
+
const ajv = new _2020_js_1.default({
|
|
13
|
+
allErrors: true,
|
|
14
|
+
strict: true,
|
|
15
|
+
});
|
|
16
|
+
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
17
|
+
ajv.addFormat("uri", true);
|
|
18
|
+
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
19
|
+
try {
|
|
20
|
+
const schemaDir = path_1.default.join(process.cwd(), "node_modules", "@unispechq", "unispec-schema", "schema");
|
|
96
21
|
const types = unispec_schema_1.manifest?.types ?? {};
|
|
97
22
|
const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const schema = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
104
|
-
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
105
|
-
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
106
|
-
ajv.addSchema(schema, fallbackId);
|
|
107
|
-
}
|
|
108
|
-
const validateFn = ajv.compile(unispec_schema_1.unispec);
|
|
109
|
-
const testsSchemaPath = path_1.default.join(schemaDir, "unispec-tests.schema.json");
|
|
110
|
-
const testsSchema = JSON.parse(fs_1.default.readFileSync(testsSchemaPath, "utf8"));
|
|
111
|
-
const validateTestsFn = ajv.compile(testsSchema);
|
|
112
|
-
const compiled = {
|
|
113
|
-
validateFn,
|
|
114
|
-
validateTestsFn,
|
|
115
|
-
};
|
|
116
|
-
validatorCache.set(schemaDir, compiled);
|
|
117
|
-
return compiled;
|
|
23
|
+
const loadedTypeSchemas = typeSchemaPaths
|
|
24
|
+
.map((relPath) => path_1.default.join(schemaDir, relPath))
|
|
25
|
+
.filter((filePath) => fs_1.default.existsSync(filePath))
|
|
26
|
+
.map((filePath) => JSON.parse(fs_1.default.readFileSync(filePath, "utf8")));
|
|
27
|
+
ajv.addSchema(loadedTypeSchemas);
|
|
118
28
|
}
|
|
29
|
+
catch {
|
|
30
|
+
// If subschemas cannot be loaded for some reason, validation will still work for
|
|
31
|
+
// parts of the schema that do not rely on those $ref references.
|
|
32
|
+
}
|
|
33
|
+
const validateFn = ajv.compile(unispec_schema_1.unispec);
|
|
34
|
+
let validateTestsFn;
|
|
119
35
|
function mapAjvErrors(errors) {
|
|
120
36
|
if (!errors)
|
|
121
37
|
return [];
|
|
@@ -129,7 +45,6 @@ function mapAjvErrors(errors) {
|
|
|
129
45
|
* Validate a UniSpec document against the UniSpec JSON Schema.
|
|
130
46
|
*/
|
|
131
47
|
async function validateUniSpec(doc, _options = {}) {
|
|
132
|
-
const { validateFn } = getCompiledValidator(_options);
|
|
133
48
|
const docForValidation = {
|
|
134
49
|
unispecVersion: "0.0.0",
|
|
135
50
|
service: {
|
|
@@ -157,7 +72,12 @@ async function validateUniSpec(doc, _options = {}) {
|
|
|
157
72
|
* Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
|
|
158
73
|
*/
|
|
159
74
|
async function validateUniSpecTests(doc, _options = {}) {
|
|
160
|
-
|
|
75
|
+
if (!validateTestsFn) {
|
|
76
|
+
const schemaDir = path_1.default.join(process.cwd(), "node_modules", "@unispechq", "unispec-schema", "schema");
|
|
77
|
+
const testsSchemaPath = path_1.default.join(schemaDir, "unispec-tests.schema.json");
|
|
78
|
+
const testsSchema = JSON.parse(fs_1.default.readFileSync(testsSchemaPath, "utf8"));
|
|
79
|
+
validateTestsFn = ajv.compile(testsSchema);
|
|
80
|
+
}
|
|
161
81
|
const valid = validateTestsFn(doc);
|
|
162
82
|
if (valid) {
|
|
163
83
|
return {
|
package/dist/validator/index.js
CHANGED
|
@@ -1,114 +1,30 @@
|
|
|
1
1
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { createRequire } from "module";
|
|
5
|
-
import { pathToFileURL } from "url";
|
|
6
4
|
import { unispec as unispecSchema, manifest as unispecManifest } from "@unispechq/unispec-schema";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
return createRequire(getThisModuleUrl());
|
|
24
|
-
}
|
|
25
|
-
function assertValidSchemaDir(schemaDir) {
|
|
26
|
-
const requiredFiles = [
|
|
27
|
-
path.join(schemaDir, "types", "service.schema.json"),
|
|
28
|
-
path.join(schemaDir, "unispec-tests.schema.json"),
|
|
29
|
-
];
|
|
30
|
-
const missing = requiredFiles.filter((p) => !fs.existsSync(p));
|
|
31
|
-
if (missing.length === 0) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const hints = [
|
|
35
|
-
`UniSpec schema directory is invalid or incomplete: ${schemaDir}`,
|
|
36
|
-
`Missing schema files:`,
|
|
37
|
-
...missing.map((p) => `- ${p}`),
|
|
38
|
-
`You can override the schema directory via ValidateOptions.schemaDir or UNISPEC_SCHEMA_DIR env var.`,
|
|
39
|
-
`In bundled environments (e.g. Next.js), module resolution can be altered; make sure @unispechq/unispec-schema is installed and accessible at runtime.`,
|
|
40
|
-
];
|
|
41
|
-
throw new Error(hints.join("\n"));
|
|
42
|
-
}
|
|
43
|
-
function findPackageRoot(startFilePath) {
|
|
44
|
-
let dir = path.dirname(startFilePath);
|
|
45
|
-
for (let i = 0; i < 50; i++) {
|
|
46
|
-
const pkgJsonPath = path.join(dir, "package.json");
|
|
47
|
-
if (fs.existsSync(pkgJsonPath)) {
|
|
48
|
-
return dir;
|
|
49
|
-
}
|
|
50
|
-
const parent = path.dirname(dir);
|
|
51
|
-
if (parent === dir) {
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
dir = parent;
|
|
55
|
-
}
|
|
56
|
-
throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
|
|
57
|
-
}
|
|
58
|
-
function getUniSpecSchemaDir(options = {}) {
|
|
59
|
-
const override = options.schemaDir ?? process.env.UNISPEC_SCHEMA_DIR;
|
|
60
|
-
if (override) {
|
|
61
|
-
return override;
|
|
62
|
-
}
|
|
63
|
-
const localRequire = getLocalRequire();
|
|
64
|
-
try {
|
|
65
|
-
const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
|
|
66
|
-
return path.join(path.dirname(pkgJsonPath), "schema");
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
const entryPath = localRequire.resolve("@unispechq/unispec-schema");
|
|
70
|
-
const pkgRoot = findPackageRoot(entryPath);
|
|
71
|
-
return path.join(pkgRoot, "schema");
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const validatorCache = new Map();
|
|
75
|
-
function getCompiledValidator(options = {}) {
|
|
76
|
-
const schemaDir = getUniSpecSchemaDir(options);
|
|
77
|
-
assertValidSchemaDir(schemaDir);
|
|
78
|
-
const cached = validatorCache.get(schemaDir);
|
|
79
|
-
if (cached) {
|
|
80
|
-
return cached;
|
|
81
|
-
}
|
|
82
|
-
const ajv = new Ajv2020({
|
|
83
|
-
allErrors: true,
|
|
84
|
-
strict: true,
|
|
85
|
-
});
|
|
86
|
-
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
87
|
-
ajv.addFormat("uri", true);
|
|
88
|
-
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
5
|
+
const ajv = new Ajv2020({
|
|
6
|
+
allErrors: true,
|
|
7
|
+
strict: true,
|
|
8
|
+
});
|
|
9
|
+
// Register minimal URI format to satisfy UniSpec schemas (service.environments[*].baseUrl)
|
|
10
|
+
ajv.addFormat("uri", true);
|
|
11
|
+
// Register all UniSpec subschemas so that Ajv can resolve internal $ref links
|
|
12
|
+
try {
|
|
13
|
+
const schemaDir = path.join(process.cwd(), "node_modules", "@unispechq", "unispec-schema", "schema");
|
|
89
14
|
const types = unispecManifest?.types ?? {};
|
|
90
15
|
const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const schema = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
97
|
-
const normalizedRelPath = String(relPath).replace(/^\.\//, "");
|
|
98
|
-
const fallbackId = `https://unispec.dev/schema/${normalizedRelPath}`;
|
|
99
|
-
ajv.addSchema(schema, fallbackId);
|
|
100
|
-
}
|
|
101
|
-
const validateFn = ajv.compile(unispecSchema);
|
|
102
|
-
const testsSchemaPath = path.join(schemaDir, "unispec-tests.schema.json");
|
|
103
|
-
const testsSchema = JSON.parse(fs.readFileSync(testsSchemaPath, "utf8"));
|
|
104
|
-
const validateTestsFn = ajv.compile(testsSchema);
|
|
105
|
-
const compiled = {
|
|
106
|
-
validateFn,
|
|
107
|
-
validateTestsFn,
|
|
108
|
-
};
|
|
109
|
-
validatorCache.set(schemaDir, compiled);
|
|
110
|
-
return compiled;
|
|
16
|
+
const loadedTypeSchemas = typeSchemaPaths
|
|
17
|
+
.map((relPath) => path.join(schemaDir, relPath))
|
|
18
|
+
.filter((filePath) => fs.existsSync(filePath))
|
|
19
|
+
.map((filePath) => JSON.parse(fs.readFileSync(filePath, "utf8")));
|
|
20
|
+
ajv.addSchema(loadedTypeSchemas);
|
|
111
21
|
}
|
|
22
|
+
catch {
|
|
23
|
+
// If subschemas cannot be loaded for some reason, validation will still work for
|
|
24
|
+
// parts of the schema that do not rely on those $ref references.
|
|
25
|
+
}
|
|
26
|
+
const validateFn = ajv.compile(unispecSchema);
|
|
27
|
+
let validateTestsFn;
|
|
112
28
|
function mapAjvErrors(errors) {
|
|
113
29
|
if (!errors)
|
|
114
30
|
return [];
|
|
@@ -122,7 +38,6 @@ function mapAjvErrors(errors) {
|
|
|
122
38
|
* Validate a UniSpec document against the UniSpec JSON Schema.
|
|
123
39
|
*/
|
|
124
40
|
export async function validateUniSpec(doc, _options = {}) {
|
|
125
|
-
const { validateFn } = getCompiledValidator(_options);
|
|
126
41
|
const docForValidation = {
|
|
127
42
|
unispecVersion: "0.0.0",
|
|
128
43
|
service: {
|
|
@@ -150,7 +65,12 @@ export async function validateUniSpec(doc, _options = {}) {
|
|
|
150
65
|
* Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
|
|
151
66
|
*/
|
|
152
67
|
export async function validateUniSpecTests(doc, _options = {}) {
|
|
153
|
-
|
|
68
|
+
if (!validateTestsFn) {
|
|
69
|
+
const schemaDir = path.join(process.cwd(), "node_modules", "@unispechq", "unispec-schema", "schema");
|
|
70
|
+
const testsSchemaPath = path.join(schemaDir, "unispec-tests.schema.json");
|
|
71
|
+
const testsSchema = JSON.parse(fs.readFileSync(testsSchemaPath, "utf8"));
|
|
72
|
+
validateTestsFn = ajv.compile(testsSchema);
|
|
73
|
+
}
|
|
154
74
|
const valid = validateTestsFn(doc);
|
|
155
75
|
if (valid) {
|
|
156
76
|
return {
|
package/package.json
CHANGED