@unispechq/unispec-core 0.2.5 → 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.
@@ -8,98 +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
- 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
- }
35
- function findPackageRoot(startFilePath) {
36
- let dir = path_1.default.dirname(startFilePath);
37
- for (let i = 0; i < 50; i++) {
38
- const pkgJsonPath = path_1.default.join(dir, "package.json");
39
- if (fs_1.default.existsSync(pkgJsonPath)) {
40
- return dir;
41
- }
42
- const parent = path_1.default.dirname(dir);
43
- if (parent === dir) {
44
- break;
45
- }
46
- dir = parent;
47
- }
48
- throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
49
- }
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();
56
- try {
57
- const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
58
- return path_1.default.join(path_1.default.dirname(pkgJsonPath), "schema");
59
- }
60
- catch {
61
- const entryPath = localRequire.resolve("@unispechq/unispec-schema");
62
- const pkgRoot = findPackageRoot(entryPath);
63
- return path_1.default.join(pkgRoot, "schema");
64
- }
65
- }
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
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");
80
21
  const types = unispec_schema_1.manifest?.types ?? {};
81
22
  const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
82
- for (const relPath of typeSchemaPaths) {
83
- const filePath = path_1.default.join(schemaDir, relPath);
84
- if (!fs_1.default.existsSync(filePath)) {
85
- continue;
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);
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;
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);
102
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;
103
35
  function mapAjvErrors(errors) {
104
36
  if (!errors)
105
37
  return [];
@@ -113,7 +45,6 @@ function mapAjvErrors(errors) {
113
45
  * Validate a UniSpec document against the UniSpec JSON Schema.
114
46
  */
115
47
  async function validateUniSpec(doc, _options = {}) {
116
- const { validateFn } = getCompiledValidator(_options);
117
48
  const docForValidation = {
118
49
  unispecVersion: "0.0.0",
119
50
  service: {
@@ -141,7 +72,12 @@ async function validateUniSpec(doc, _options = {}) {
141
72
  * Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
142
73
  */
143
74
  async function validateUniSpecTests(doc, _options = {}) {
144
- const { validateTestsFn } = getCompiledValidator(_options);
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
+ }
145
81
  const valid = validateTestsFn(doc);
146
82
  if (valid) {
147
83
  return {
@@ -1,6 +1,5 @@
1
1
  import { UniSpecDocument, UniSpecTestsDocument, ValidationResult } from "../types";
2
2
  export interface ValidateOptions {
3
- schemaDir?: string;
4
3
  }
5
4
  /**
6
5
  * Validate a UniSpec document against the UniSpec JSON Schema.
@@ -1,98 +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
- 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
- }
28
- function findPackageRoot(startFilePath) {
29
- let dir = path.dirname(startFilePath);
30
- for (let i = 0; i < 50; i++) {
31
- const pkgJsonPath = path.join(dir, "package.json");
32
- if (fs.existsSync(pkgJsonPath)) {
33
- return dir;
34
- }
35
- const parent = path.dirname(dir);
36
- if (parent === dir) {
37
- break;
38
- }
39
- dir = parent;
40
- }
41
- throw new Error(`Cannot locate package.json for resolved path: ${startFilePath}`);
42
- }
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();
49
- try {
50
- const pkgJsonPath = localRequire.resolve("@unispechq/unispec-schema/package.json");
51
- return path.join(path.dirname(pkgJsonPath), "schema");
52
- }
53
- catch {
54
- const entryPath = localRequire.resolve("@unispechq/unispec-schema");
55
- const pkgRoot = findPackageRoot(entryPath);
56
- return path.join(pkgRoot, "schema");
57
- }
58
- }
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
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");
73
14
  const types = unispecManifest?.types ?? {};
74
15
  const typeSchemaPaths = Object.values(types).map((rel) => String(rel));
75
- for (const relPath of typeSchemaPaths) {
76
- const filePath = path.join(schemaDir, relPath);
77
- if (!fs.existsSync(filePath)) {
78
- continue;
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);
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;
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);
95
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;
96
28
  function mapAjvErrors(errors) {
97
29
  if (!errors)
98
30
  return [];
@@ -106,7 +38,6 @@ function mapAjvErrors(errors) {
106
38
  * Validate a UniSpec document against the UniSpec JSON Schema.
107
39
  */
108
40
  export async function validateUniSpec(doc, _options = {}) {
109
- const { validateFn } = getCompiledValidator(_options);
110
41
  const docForValidation = {
111
42
  unispecVersion: "0.0.0",
112
43
  service: {
@@ -134,7 +65,12 @@ export async function validateUniSpec(doc, _options = {}) {
134
65
  * Validate a UniSpec Tests document against the UniSpec Tests JSON Schema.
135
66
  */
136
67
  export async function validateUniSpecTests(doc, _options = {}) {
137
- const { validateTestsFn } = getCompiledValidator(_options);
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
+ }
138
74
  const valid = validateTestsFn(doc);
139
75
  if (valid) {
140
76
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unispechq/unispec-core",
3
- "version": "0.2.5",
3
+ "version": "0.2.8",
4
4
  "description": "Central UniSpec Core Engine providing parsing, validation, normalization, diffing, and conversion of UniSpec specs.",
5
5
  "license": "MIT",
6
6
  "repository": {