@invisra/printspec 0.1.2 → 0.1.3
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/browser.d.ts +7 -0
- package/dist/browser.js +7 -0
- package/dist/bundle.browser.d.ts +3 -0
- package/dist/bundle.browser.js +5 -0
- package/dist/bundle.core.d.ts +27 -0
- package/dist/bundle.core.js +81 -0
- package/dist/bundle.d.ts +2 -25
- package/dist/bundle.js +3 -80
- package/dist/forms.browser.d.ts +37 -0
- package/dist/forms.browser.js +68 -0
- package/dist/generated/schemas.generated.d.ts +2428 -0
- package/dist/generated/schemas.generated.js +3055 -0
- package/dist/schemas.browser.d.ts +3 -0
- package/dist/schemas.browser.js +5 -0
- package/dist/schemas.d.ts +1 -6
- package/dist/schemas.js +1 -54
- package/dist/schemas.node.d.ts +5 -0
- package/dist/schemas.node.js +29 -0
- package/dist/schemas.shared.d.ts +3 -0
- package/dist/schemas.shared.js +34 -0
- package/dist/validate.browser.d.ts +9 -0
- package/dist/validate.browser.js +36 -0
- package/dist/validate.js +1 -10
- package/package.json +6 -2
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const schemas: Record<string, any>;
|
|
2
|
+
export declare const schemaFiles: ("rounded-rectangular-plate.schema.json" | "spacer-block.schema.json" | "round-spacer.schema.json" | "electronics-standoff.schema.json" | "l-bracket.schema.json" | "cable-comb.schema.json" | "cable-clip.schema.json" | "drill-guide.schema.json" | "simple-box.schema.json" | "simple-lid.schema.json" | "part-family.schema.json" | "composable-part.schema.json" | "project.schema.json" | "printspec.schema.json" | "common.schema.json")[];
|
|
3
|
+
export declare function createAjv(): import("ajv/dist/2020.js").Ajv2020;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { bundledSchemaFiles, bundledSchemas } from './generated/schemas.generated.js';
|
|
2
|
+
import { createAjvFromSchemas } from './schemas.shared.js';
|
|
3
|
+
export const schemas = bundledSchemas;
|
|
4
|
+
export const schemaFiles = [...bundledSchemaFiles];
|
|
5
|
+
export function createAjv() { return createAjvFromSchemas(schemas); }
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1,6 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const schemaDir: string;
|
|
3
|
-
export declare const schemaFiles: any;
|
|
4
|
-
export declare function loadSchemas(): Record<string, any>;
|
|
5
|
-
export declare const schemas: Record<string, any>;
|
|
6
|
-
export declare function createAjv(): Ajv2020;
|
|
1
|
+
export * from './schemas.node.js';
|
package/dist/schemas.js
CHANGED
|
@@ -1,54 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
5
|
-
import addFormats from 'ajv-formats';
|
|
6
|
-
const schemaBaseUri = 'https://schemas.invisra.ai/printspec/0.1.0/';
|
|
7
|
-
function isDirectory(candidate) {
|
|
8
|
-
return fs.existsSync(candidate) && fs.statSync(candidate).isDirectory();
|
|
9
|
-
}
|
|
10
|
-
function findSchemaDir() {
|
|
11
|
-
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
const packageLocalCandidate = path.resolve(moduleDir, '..', 'schemas');
|
|
13
|
-
if (isDirectory(packageLocalCandidate))
|
|
14
|
-
return packageLocalCandidate;
|
|
15
|
-
// Source checkout fallback: walk upward to the repository-level schemas
|
|
16
|
-
// directory so development builds can still validate fully offline.
|
|
17
|
-
for (let dir = moduleDir;; dir = path.dirname(dir)) {
|
|
18
|
-
const candidate = path.join(dir, 'schemas');
|
|
19
|
-
if (isDirectory(candidate))
|
|
20
|
-
return candidate;
|
|
21
|
-
const parent = path.dirname(dir);
|
|
22
|
-
if (parent === dir)
|
|
23
|
-
break;
|
|
24
|
-
}
|
|
25
|
-
throw new Error('Unable to locate bundled printspec schemas. Run npm run sync:schemas before building, or reinstall the package.');
|
|
26
|
-
}
|
|
27
|
-
export const schemaDir = findSchemaDir();
|
|
28
|
-
export const schemaFiles = fs.readdirSync(schemaDir).filter((f) => f.endsWith('.schema.json')).sort();
|
|
29
|
-
export function loadSchemas() {
|
|
30
|
-
const files = fs.readdirSync(schemaDir).filter((f) => f.endsWith('.schema.json')).sort();
|
|
31
|
-
return Object.fromEntries(files.map((file) => [file, JSON.parse(fs.readFileSync(path.join(schemaDir, file), 'utf8'))]));
|
|
32
|
-
}
|
|
33
|
-
export const schemas = loadSchemas();
|
|
34
|
-
export function createAjv() {
|
|
35
|
-
const ajv = new Ajv2020({ allErrors: true, strict: false, loadSchema: undefined });
|
|
36
|
-
addFormats(ajv);
|
|
37
|
-
const registered = new Set();
|
|
38
|
-
for (const [filename, schema] of Object.entries(schemas)) {
|
|
39
|
-
const primaryId = schema.$id ?? `${schemaBaseUri}${filename}`;
|
|
40
|
-
ajv.addSchema(schema, primaryId);
|
|
41
|
-
registered.add(primaryId);
|
|
42
|
-
}
|
|
43
|
-
for (const [filename, schema] of Object.entries(schemas)) {
|
|
44
|
-
const aliasSchema = { ...schema };
|
|
45
|
-
delete aliasSchema.$id;
|
|
46
|
-
for (const alias of [filename, `${schemaBaseUri}${filename}`]) {
|
|
47
|
-
if (!registered.has(alias)) {
|
|
48
|
-
ajv.addSchema(aliasSchema, alias);
|
|
49
|
-
registered.add(alias);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return ajv;
|
|
54
|
-
}
|
|
1
|
+
export * from './schemas.node.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { createAjvFromSchemas } from './schemas.shared.js';
|
|
5
|
+
function isDirectory(candidate) {
|
|
6
|
+
return fs.existsSync(candidate) && fs.statSync(candidate).isDirectory();
|
|
7
|
+
}
|
|
8
|
+
function findSchemaDir() {
|
|
9
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const packageLocalCandidate = path.resolve(moduleDir, '..', 'schemas');
|
|
11
|
+
if (isDirectory(packageLocalCandidate))
|
|
12
|
+
return packageLocalCandidate;
|
|
13
|
+
for (let dir = moduleDir;; dir = path.dirname(dir)) {
|
|
14
|
+
const candidate = path.join(dir, 'schemas');
|
|
15
|
+
if (isDirectory(candidate))
|
|
16
|
+
return candidate;
|
|
17
|
+
const parent = path.dirname(dir);
|
|
18
|
+
if (parent === dir)
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
throw new Error('Unable to locate bundled printspec schemas. Run npm run sync:schemas before building, or reinstall the package.');
|
|
22
|
+
}
|
|
23
|
+
export const schemaDir = findSchemaDir();
|
|
24
|
+
export const schemaFiles = fs.readdirSync(schemaDir).filter((f) => f.endsWith('.schema.json')).sort();
|
|
25
|
+
export function loadSchemas() {
|
|
26
|
+
return Object.fromEntries(schemaFiles.map((file) => [file, JSON.parse(fs.readFileSync(path.join(schemaDir, file), 'utf8'))]));
|
|
27
|
+
}
|
|
28
|
+
export const schemas = loadSchemas();
|
|
29
|
+
export function createAjv() { return createAjvFromSchemas(schemas); }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
2
|
+
import addFormats from 'ajv-formats';
|
|
3
|
+
const schemaBaseUri = 'https://schemas.invisra.ai/printspec/0.1.0/';
|
|
4
|
+
export function createAjvFromSchemas(schemas) {
|
|
5
|
+
const ajv = new Ajv2020({ allErrors: true, strict: false, loadSchema: undefined });
|
|
6
|
+
addFormats(ajv);
|
|
7
|
+
const registered = new Set();
|
|
8
|
+
for (const [filename, schema] of Object.entries(schemas)) {
|
|
9
|
+
const primaryId = schema.$id ?? `${schemaBaseUri}${filename}`;
|
|
10
|
+
ajv.addSchema(schema, primaryId);
|
|
11
|
+
registered.add(primaryId);
|
|
12
|
+
}
|
|
13
|
+
for (const [filename, schema] of Object.entries(schemas)) {
|
|
14
|
+
const aliasSchema = { ...schema };
|
|
15
|
+
delete aliasSchema.$id;
|
|
16
|
+
for (const alias of [filename, `${schemaBaseUri}${filename}`]) {
|
|
17
|
+
if (!registered.has(alias)) {
|
|
18
|
+
ajv.addSchema(aliasSchema, alias);
|
|
19
|
+
registered.add(alias);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return ajv;
|
|
24
|
+
}
|
|
25
|
+
function formatPath(instancePath) {
|
|
26
|
+
return instancePath && instancePath.length > 0 ? instancePath : '/';
|
|
27
|
+
}
|
|
28
|
+
export function formatAjvErrors(validate) {
|
|
29
|
+
return (validate.errors ?? []).map((error) => {
|
|
30
|
+
const keyword = error.keyword ? ` [${error.keyword}]` : '';
|
|
31
|
+
const message = error.message ?? 'failed schema validation';
|
|
32
|
+
return `${formatPath(error.instancePath)}: ${message}${keyword}`;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ValidationResult } from './types.js';
|
|
2
|
+
type ValidationOptions = {
|
|
3
|
+
semantic?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare function validatePartFamilySpec(part: unknown, _options?: ValidationOptions): ValidationResult;
|
|
6
|
+
export declare function validateComposablePartSpec(part: unknown, _options?: ValidationOptions): ValidationResult;
|
|
7
|
+
export declare function validateProjectSpec(project: unknown, _options?: ValidationOptions): ValidationResult;
|
|
8
|
+
export declare function validatePrintSpec(spec: unknown, options?: ValidationOptions): ValidationResult;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { validateSemantic } from './semantic.js';
|
|
2
|
+
import { createAjv, schemas } from './schemas.browser.js';
|
|
3
|
+
import { formatAjvErrors } from './schemas.shared.js';
|
|
4
|
+
const ajv = createAjv();
|
|
5
|
+
const validators = new Map();
|
|
6
|
+
function validatorFor(schemaName) {
|
|
7
|
+
const existing = validators.get(schemaName);
|
|
8
|
+
if (existing)
|
|
9
|
+
return existing;
|
|
10
|
+
const schema = schemas[schemaName];
|
|
11
|
+
if (!schema)
|
|
12
|
+
throw new Error(`Missing local schema: ${schemaName}`);
|
|
13
|
+
const compiled = ajv.compile(schema);
|
|
14
|
+
validators.set(schemaName, compiled);
|
|
15
|
+
return compiled;
|
|
16
|
+
}
|
|
17
|
+
function validateWithSchema(schemaName, value, semantic = false) {
|
|
18
|
+
const validate = validatorFor(schemaName);
|
|
19
|
+
const ok = validate(value);
|
|
20
|
+
const errors = ok ? [] : formatAjvErrors(validate);
|
|
21
|
+
if (errors.length === 0 && semantic)
|
|
22
|
+
errors.push(...validateSemantic(value));
|
|
23
|
+
return { valid: errors.length === 0, errors };
|
|
24
|
+
}
|
|
25
|
+
export function validatePartFamilySpec(part, _options = {}) {
|
|
26
|
+
return validateWithSchema('part-family.schema.json', part, false);
|
|
27
|
+
}
|
|
28
|
+
export function validateComposablePartSpec(part, _options = {}) {
|
|
29
|
+
return validateWithSchema('composable-part.schema.json', part, false);
|
|
30
|
+
}
|
|
31
|
+
export function validateProjectSpec(project, _options = {}) {
|
|
32
|
+
return validateWithSchema('project.schema.json', project, false);
|
|
33
|
+
}
|
|
34
|
+
export function validatePrintSpec(spec, options = {}) {
|
|
35
|
+
return validateWithSchema('printspec.schema.json', spec, options.semantic !== false);
|
|
36
|
+
}
|
package/dist/validate.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { validateSemantic } from './semantic.js';
|
|
2
2
|
import { createAjv, schemas } from './schemas.js';
|
|
3
|
+
import { formatAjvErrors } from './schemas.shared.js';
|
|
3
4
|
const ajv = createAjv();
|
|
4
5
|
const validators = new Map();
|
|
5
6
|
function validatorFor(schemaName) {
|
|
@@ -13,16 +14,6 @@ function validatorFor(schemaName) {
|
|
|
13
14
|
validators.set(schemaName, compiled);
|
|
14
15
|
return compiled;
|
|
15
16
|
}
|
|
16
|
-
function formatPath(instancePath) {
|
|
17
|
-
return instancePath && instancePath.length > 0 ? instancePath : '/';
|
|
18
|
-
}
|
|
19
|
-
function formatAjvErrors(validate) {
|
|
20
|
-
return (validate.errors ?? []).map((error) => {
|
|
21
|
-
const keyword = error.keyword ? ` [${error.keyword}]` : '';
|
|
22
|
-
const message = error.message ?? 'failed schema validation';
|
|
23
|
-
return `${formatPath(error.instancePath)}: ${message}${keyword}`;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
17
|
function validateWithSchema(schemaName, value, semantic = false) {
|
|
27
18
|
const validate = validatorFor(schemaName);
|
|
28
19
|
const ok = validate(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@invisra/printspec",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "JSON schemas, validators, BOM helpers, CLI commands, and starter generators for practical parametric 3D-printable parts.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Invisra",
|
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
"types": "./dist/index.d.ts",
|
|
35
35
|
"import": "./dist/index.js"
|
|
36
36
|
},
|
|
37
|
+
"./browser": {
|
|
38
|
+
"types": "./dist/browser.d.ts",
|
|
39
|
+
"import": "./dist/browser.js"
|
|
40
|
+
},
|
|
37
41
|
"./schemas/*": "./schemas/*",
|
|
38
42
|
"./package.json": "./package.json"
|
|
39
43
|
},
|
|
@@ -47,7 +51,7 @@
|
|
|
47
51
|
"test": "npm run build && node --test ../../tests/typescript/*.test.js",
|
|
48
52
|
"clean": "rm -rf dist",
|
|
49
53
|
"prepack": "npm run build",
|
|
50
|
-
"prepublishOnly": "npm run build && test -f dist/index.js && test -f dist/index.d.ts && test -f dist/cli.js"
|
|
54
|
+
"prepublishOnly": "npm run build && test -f dist/index.js && test -f dist/index.d.ts && test -f dist/browser.js && test -f dist/browser.d.ts && test -f dist/cli.js"
|
|
51
55
|
},
|
|
52
56
|
"dependencies": {
|
|
53
57
|
"ajv": "^8.17.1",
|