From 27e0b506f5ca486df33f8100d5e98f86b6494356 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Wed, 8 Oct 2025 17:22:04 +0300 Subject: [PATCH 1/4] update: add generateSchemaMixin + node22 build fix --- dist/js/generateSchemaMixin.d.ts | 24 ++ dist/js/generateSchemaMixin.js | 236 +++++++++++ package-lock.json | 559 ++++++-------------------- package.json | 2 +- src/js/generateSchemaMixin.ts | 289 +++++++++++++ tests/js/enums.ts | 3 +- tests/js/generateSchemaMixin.tests.ts | 161 ++++++++ tests/js/utils.ts | 2 +- 8 files changed, 837 insertions(+), 439 deletions(-) create mode 100644 dist/js/generateSchemaMixin.d.ts create mode 100644 dist/js/generateSchemaMixin.js create mode 100644 src/js/generateSchemaMixin.ts create mode 100644 tests/js/generateSchemaMixin.tests.ts diff --git a/dist/js/generateSchemaMixin.d.ts b/dist/js/generateSchemaMixin.d.ts new file mode 100644 index 00000000..05d2d47e --- /dev/null +++ b/dist/js/generateSchemaMixin.d.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * Generates mixins for multiple schemas + * @param outputPaths - Object mapping schema IDs to output file paths + * @param skipFields - Array of field names to skip during generation + * @returns - Object with success and error counts + */ +declare function generateShemaMixin(outputPaths: Record, skipFields?: string[]): { + successCount: number; + errorCount: number; +}; +/** + * @example + * ```ts + * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * + * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * + * if (result.errorCount > 0) { + * process.exit(1); + * } + * ``` + */ +export default generateShemaMixin; diff --git a/dist/js/generateSchemaMixin.js b/dist/js/generateSchemaMixin.js new file mode 100644 index 00000000..a00648a3 --- /dev/null +++ b/dist/js/generateSchemaMixin.js @@ -0,0 +1,236 @@ +#!/usr/bin/env node +"use strict"; +/* eslint-disable no-restricted-syntax */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Script to generate mixin properties from JSON schema + * + * This script generates mixin functions for property/holder, property/meta_holder, + * and property/proto_holder schemas automatically. + * + * Usage: + * node scripts/generate-mixin-properties.js + */ +const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); +const schemas_json_1 = __importDefault(require("@mat3ra/esse/dist/js/schemas.json")); +const child_process_1 = require("child_process"); +const fs_1 = __importDefault(require("fs")); +/** + * Determines if a property should use requiredProp() or prop() + * @param propertyName - Name of the property + * @param requiredProperties - Array of required property names + * @returns - True if property is required + */ +function isRequiredProperty(propertyName, requiredProperties) { + return requiredProperties.includes(propertyName); +} +/** + * Generates TypeScript type annotation for a property + * @param propertyName - The property name + * @param schemaName - Name of the schema (for type reference) + * @returns - TypeScript type annotation + */ +function generateTypeAnnotation(propertyName, schemaName) { + return `${schemaName}["${propertyName}"]`; +} +/** + * Extracts properties from a schema, handling allOf if present + * @param schema - The JSON schema + * @returns - Object with properties and required fields + */ +function extractSchemaProperties(schema) { + let properties = {}; + let required = []; + // Handle allOf by merging properties from all schemas + if (schema.allOf && Array.isArray(schema.allOf)) { + for (const subSchema of schema.allOf) { + const extracted = extractSchemaProperties(subSchema); + properties = { ...properties, ...extracted.properties }; + required = [...required, ...extracted.required]; + } + } + // Add properties from current schema + if (schema.properties) { + properties = { ...properties, ...schema.properties }; + } + if (schema.required) { + required = [...required, ...schema.required]; + } + return { properties, required }; +} +/** + * Generates the complete mixin function + * @param schema - The JSON schema + * @param schemaName - Name of the schema + * @param mixinTypeName - Name of the mixin type + * @param entityTypeName - Name of the entity type + * @param skipFields - Array of field names to skip + * @returns - Generated TypeScript code + */ +function generateMixinFunction(schema, schemaName, mixinTypeName, entityTypeName, skipFields = []) { + // Convert mixin type name to camelCase for function name + const functionName = mixinTypeName.charAt(0).toLowerCase() + mixinTypeName.slice(1); + // Extract properties, handling allOf if present + const { properties, required } = extractSchemaProperties(schema); + if (Object.keys(properties).length === 0) { + throw new Error("No properties found in schema"); + } + // Filter out skip fields + const propertyEntries = Object.entries(properties).filter(([propertyName]) => !skipFields.includes(propertyName)); + let code = `import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity";\n`; + code += `import type { ${schemaName} } from "@mat3ra/esse/dist/js/types";\n\n`; + // Generate the mixin type using Omit utility + const skipFieldNames = skipFields.map((field) => `"${field}"`).join(" | "); + code += `export type ${mixinTypeName} = Omit<${schemaName}, ${skipFieldNames}>;\n\n`; + // Generate the entity type + code += `export type ${entityTypeName} = InMemoryEntity & ${mixinTypeName};\n\n`; + code += `export function ${functionName}(item: InMemoryEntity) {\n`; + code += ` // @ts-expect-error\n`; + code += ` const properties: InMemoryEntity & ${mixinTypeName} = {\n`; + for (let i = 0; i < propertyEntries.length; i++) { + const [propertyName] = propertyEntries[i]; + const isRequired = isRequiredProperty(propertyName, required); + const methodName = isRequired ? "requiredProp" : "prop"; + const typeAnnotation = generateTypeAnnotation(propertyName, schemaName); + code += `get ${propertyName}() {\n`; + code += `return this.${methodName}<${typeAnnotation}>("${propertyName}");\n`; + code += `}`; + // Add comma for all properties except the last one + if (i < propertyEntries.length - 1) { + code += `,\n`; + } + else { + code += `,\n`; + } + } + code += ` };\n\n`; + code += ` Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));\n`; + code += `}\n`; + return code; +} +/** + * Generates mixin function for a given schema ID + * @param schemaId - The schema ID (e.g., "property/holder") + * @param outputPath - The output file path + * @param skipFields - Array of field names to skip + * @returns - Generated TypeScript code + */ +function generateMixinFromSchemaId(schemaId, outputPath, skipFields = []) { + var _a, _b; + // Get the resolved schema by ID + const schema = JSONSchemasInterface_1.default.getSchemaById(schemaId); + if (!schema) { + throw new Error(`Schema not found with ID: ${schemaId}`); + } + // Extract schema name from title for import + let schemaName; + if (schema.title) { + // Convert title to proper schema name + schemaName = schema.title + .split(/\s+/) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(""); + } + else { + // Convert schema ID to proper schema name + schemaName = + schemaId + .split(/[/-]/) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join("") + "Schema"; + } + // Extract type names from output file path + const fileName = (_b = (_a = outputPath.split("/").pop()) === null || _a === void 0 ? void 0 : _a.replace(".ts", "")) !== null && _b !== void 0 ? _b : ""; + if (!fileName) { + throw new Error(`Invalid output path: ${outputPath}`); + } + const mixinTypeName = fileName; + const entityTypeName = fileName.replace("SchemaMixin", "InMemoryEntity"); + // Generate the complete mixin function + return generateMixinFunction(schema, schemaName, mixinTypeName, entityTypeName, skipFields); +} +/** + * Runs ESLint autofix on generated files + * @param filePaths - Array of file paths to fix + */ +function runESLintAutofix(filePaths) { + if (filePaths.length === 0) + return; + try { + console.log("Running ESLint autofix on generated files..."); + const filesToFix = filePaths.join(" "); + (0, child_process_1.execSync)(`npx eslint --fix ${filesToFix}`, { stdio: "inherit" }); + console.log("✓ ESLint autofix completed successfully"); + } + catch (error) { + console.warn("⚠ ESLint autofix failed:", error instanceof Error ? error.message : String(error)); + // Don't fail the entire process if ESLint autofix fails + } +} +/** + * Generates mixins for multiple schemas + * @param outputPaths - Object mapping schema IDs to output file paths + * @param skipFields - Array of field names to skip during generation + * @returns - Object with success and error counts + */ +function generateShemaMixin(outputPaths, skipFields = []) { + // Setup schemas + JSONSchemasInterface_1.default.setSchemas(schemas_json_1.default); + console.log("Generating mixin properties for all schemas..."); + const schemaIds = Object.keys(outputPaths); + let successCount = 0; + let errorCount = 0; + const generatedFiles = []; + for (const schemaId of schemaIds) { + try { + console.log(`\nProcessing schema: ${schemaId}`); + const outputPath = outputPaths[schemaId]; + if (!outputPath) { + throw new Error(`No output path defined for schema: ${schemaId}`); + } + const generatedCode = generateMixinFromSchemaId(schemaId, outputPath, skipFields); + // Ensure the directory exists + const dir = outputPath.substring(0, outputPath.lastIndexOf("/")); + if (!fs_1.default.existsSync(dir)) { + fs_1.default.mkdirSync(dir, { recursive: true }); + } + fs_1.default.writeFileSync(outputPath, generatedCode); + console.log(`✓ Generated mixin written to: ${outputPath}`); + generatedFiles.push(outputPath); + successCount += 1; + } + catch (error) { + console.error(`✗ Error processing schema ${schemaId}: ${error instanceof Error ? error.message : String(error)}`); + errorCount += 1; + } + } + // Run ESLint autofix on generated files + if (generatedFiles.length > 0) { + runESLintAutofix(generatedFiles); + } + console.log(`\n=== Summary ===`); + console.log(`Successfully generated: ${successCount} mixins`); + if (errorCount > 0) { + console.log(`Errors: ${errorCount} schemas failed`); + } + else { + console.log("All mixins generated successfully!"); + } + return { successCount, errorCount }; +} +/** + * @example + * ```ts + * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * + * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * + * if (result.errorCount > 0) { + * process.exit(1); + * } + * ``` + */ +exports.default = generateShemaMixin; diff --git a/package-lock.json b/package-lock.json index ab51fc26..d85277df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,6 @@ "mathjs": "^5.10.3", "mixwith": "^0.1.1", "nunjucks": "^3.2.4", - "react-jsonschema-form": "^1.8.1", "semver": "^7.6.3", "underscore": "^1.13.7", "underscore.string": "^3.3.6", @@ -34,7 +33,7 @@ "@babel/register": "^7.25.7", "@babel/runtime-corejs3": "^7.25.7", "@exabyte-io/eslint-config": "^2025.1.15-0", - "@mat3ra/esse": "2025.4.22-0", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", "@mat3ra/tsconfig": "2024.6.3-0", "@types/chai": "^4.3.20", "@types/crypto-js": "^4.2.2", @@ -42,7 +41,6 @@ "@types/json-schema": "^7.0.15", "@types/mocha": "^10.0.8", "@types/node": "^20.16.10", - "@types/react-jsonschema-form": "^1.7.13", "@types/underscore": "^1.11.15", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", @@ -86,6 +84,24 @@ "node": ">=6.0.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "version": "11.9.3", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz", + "integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.15", + "js-yaml": "^4.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/philsturgeon" + } + }, "node_modules/@babel/cli": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.27.0.tgz", @@ -1858,18 +1874,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs2": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.25.7.tgz", - "integrity": "sha512-xdsLBlDCJIZzwH1fBJ7GJu+bRFO0Sqv10WotmwMu83Joep1erPcWbTr84rZD42kPzSjtmrFgshdWHKfQTWOsng==", - "dependencies": { - "core-js": "^2.6.12", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/runtime-corejs3": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.27.0.tgz", @@ -1932,24 +1936,6 @@ "node": ">=6.9.0" } }, - "node_modules/@bcherny/json-schema-ref-parser": { - "version": "10.0.5-fork", - "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-10.0.5-fork.tgz", - "integrity": "sha512-E/jKbPoca1tfUPj3iSbitDZTGnq6FUFjkH6L8U2oDwSuwK1WhnnVtCG7oFOTg/DDnyoXbQYUiUiGOibHqaGVnw==", - "dev": true, - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/philsturgeon" - } - }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -2319,13 +2305,15 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@mat3ra/esse": { - "version": "2025.4.22-0", - "resolved": "https://registry.npmjs.org/@mat3ra/esse/-/esse-2025.4.22-0.tgz", - "integrity": "sha512-bhpMHMuf6JTDXN2Pae8L+Zsn/JWBVZCqtLo1LgkvKK9QkjuUcjT8ixSGPYOjYEKe6wak+AUI0CqqgUBcVCS1KQ==", + "version": "0.0.0", + "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", + "integrity": "sha512-odpa1r5U4RtVX7nen9FOiDzY/mZqd9P0TzoePOLViZUXqjXyqKMWb0k7AO5uXT4iA3yk7uFghxuk0QXiMVvDXg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@babel/cli": "^7.27.0", "@babel/core": "^7.26.10", @@ -2346,7 +2334,7 @@ "json-schema": "^0.4.0", "json-schema-deref-sync": "0.14.0", "json-schema-merge-allof": "^0.8.1", - "json-schema-to-typescript": "^13.1.2", + "json-schema-to-typescript": "^15.0.4", "lodash": "4.17.21" }, "engines": { @@ -2490,16 +2478,6 @@ "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==", "dev": true }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, "node_modules/@types/js-yaml": { "version": "4.0.9", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", @@ -2528,10 +2506,11 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.17.9", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.9.tgz", - "integrity": "sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==", - "dev": true + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/mathjs": { "version": "5.0.1", @@ -2541,12 +2520,6 @@ "decimal.js": "^10.0.0" } }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "dev": true - }, "node_modules/@types/mocha": { "version": "10.0.10", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", @@ -2563,38 +2536,6 @@ "undici-types": "~6.19.2" } }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.3.11", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.11.tgz", - "integrity": "sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-jsonschema-form": { - "version": "1.7.13", - "resolved": "https://registry.npmjs.org/@types/react-jsonschema-form/-/react-jsonschema-form-1.7.13.tgz", - "integrity": "sha512-C2jgO7/ow76oCSfUK++jKKox17R0A7ryMYNE5hJ2dR1Ske9jhuvjIlurvzMePh+Xjk8wey0nzB2C7HFKe2pRdg==", - "dev": true, - "dependencies": { - "@types/json-schema": "*", - "@types/react": "*" - } - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -2874,6 +2815,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2981,12 +2923,6 @@ "node": ">=4" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -3461,12 +3397,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", - "dev": true - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3595,22 +3525,6 @@ "node": ">=6" } }, - "node_modules/cli-color": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", - "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.64", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.15", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -3857,13 +3771,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true - }, "node_modules/core-js-compat": { "version": "3.41.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", @@ -3923,25 +3830,6 @@ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/d": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", - "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.64", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/dag-map": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", @@ -4397,64 +4285,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", - "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", - "dev": true, - "dependencies": { - "d": "^1.0.2", - "ext": "^1.7.0" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5179,21 +5015,6 @@ "node": ">=8" } }, - "node_modules/esniff": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", - "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", - "dev": true, - "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -5290,16 +5111,6 @@ "node": ">=0.10.0" } }, - "node_modules/event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -5323,19 +5134,11 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/ext": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", - "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", - "dev": true, - "dependencies": { - "type": "^2.7.2" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-diff": { "version": "1.3.0", @@ -5362,7 +5165,8 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -5637,18 +5441,6 @@ "node": ">=8.0.0" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -5711,25 +5503,6 @@ "node": ">= 6" } }, - "node_modules/glob-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-4.2.2.tgz", - "integrity": "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==", - "dev": true, - "dependencies": { - "@types/glob": "^7.1.3" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/ahmadnassri" - }, - "peerDependencies": { - "glob": "^7.1.6" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -6336,12 +6109,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -6714,7 +6481,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", @@ -6803,37 +6571,50 @@ } }, "node_modules/json-schema-to-typescript": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-13.1.2.tgz", - "integrity": "sha512-17G+mjx4nunvOpkPvcz7fdwUwYCEwyH8vR3Ym3rFiQ8uzAL3go+c1306Kk7iGRk8HuXBXqy+JJJmpYl0cvOllw==", + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz", + "integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==", "dev": true, + "license": "MIT", "dependencies": { - "@bcherny/json-schema-ref-parser": "10.0.5-fork", - "@types/json-schema": "^7.0.11", - "@types/lodash": "^4.14.182", - "@types/prettier": "^2.6.1", - "cli-color": "^2.0.2", - "get-stdin": "^8.0.0", - "glob": "^7.1.6", - "glob-promise": "^4.2.2", + "@apidevtools/json-schema-ref-parser": "^11.5.5", + "@types/json-schema": "^7.0.15", + "@types/lodash": "^4.17.7", "is-glob": "^4.0.3", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", - "minimist": "^1.2.6", - "mkdirp": "^1.0.4", - "mz": "^2.7.0", - "prettier": "^2.6.2" + "minimist": "^1.2.8", + "prettier": "^3.2.5", + "tinyglobby": "^0.2.9" }, "bin": { "json2ts": "dist/src/cli.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/json-schema-to-typescript/node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -7265,6 +7046,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -7290,15 +7072,6 @@ "yallist": "^3.0.2" } }, - "node_modules/lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", - "dev": true, - "dependencies": { - "es5-ext": "~0.10.2" - } - }, "node_modules/make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -7364,25 +7137,6 @@ "is-buffer": "~1.1.1" } }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" - }, - "engines": { - "node": ">=0.12" - } - }, "node_modules/memory-cache": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/memory-cache/-/memory-cache-0.2.0.tgz", @@ -7452,18 +7206,6 @@ "resolved": "https://registry.npmjs.org/mixwith/-/mixwith-0.1.1.tgz", "integrity": "sha512-DQsf/liljH/9e+94jR+xfK8vlKceeKdOM9H9UEXLwGuvEEpO6debNtJ9yt1ZKzPKPrwqGxzMdu0BR1fnQb6i4A==" }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mocha": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", @@ -7652,22 +7394,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7680,12 +7406,6 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -8038,6 +7758,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -8474,6 +8195,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -8484,6 +8206,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } @@ -8517,48 +8240,11 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", - "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-jsonschema-form": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/react-jsonschema-form/-/react-jsonschema-form-1.8.1.tgz", - "integrity": "sha512-aaDloxNAcGXOOOcdKOxxqEEn5oDlPUZgWcs8unXXB9vjBRgCF8rCm/wVSv1u2G5ih0j/BX6Ewd/WjI2g00lPdg==", - "deprecated": "react-jsonschema-form has been moved to @rjsf/core", - "dependencies": { - "@babel/runtime-corejs2": "^7.4.5", - "ajv": "^6.7.0", - "core-js": "^2.5.7", - "lodash": "^4.17.15", - "prop-types": "^15.5.8", - "react-is": "^16.8.4", - "react-lifecycles-compat": "^3.0.4", - "shortid": "^2.2.14" - }, - "engines": { - "node": ">=6", - "npm": ">=2.14.7" - }, - "peerDependencies": { - "react": ">=15" - } - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true }, "node_modules/readdirp": { "version": "3.6.0", @@ -8616,7 +8302,8 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -9010,15 +8697,6 @@ "node": ">=8" } }, - "node_modules/shortid": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", - "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dependencies": { - "nanoid": "^2.1.0" - } - }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -9477,50 +9155,64 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "node_modules/timers-ext": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", - "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, + "license": "MIT", "dependencies": { - "es5-ext": "^0.10.64", - "next-tick": "^1.1.0" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=0.12" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -9660,12 +9352,6 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/type": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", - "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", - "dev": true - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9939,6 +9625,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "dependencies": { "punycode": "^2.1.0" } diff --git a/package.json b/package.json index 548b7f20..f0a91591 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@babel/register": "^7.25.7", "@babel/runtime-corejs3": "^7.25.7", "@exabyte-io/eslint-config": "^2025.1.15-0", - "@mat3ra/esse": "2025.4.22-0", + "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", "@mat3ra/tsconfig": "2024.6.3-0", "@types/chai": "^4.3.20", "@types/crypto-js": "^4.2.2", diff --git a/src/js/generateSchemaMixin.ts b/src/js/generateSchemaMixin.ts new file mode 100644 index 00000000..a387d70a --- /dev/null +++ b/src/js/generateSchemaMixin.ts @@ -0,0 +1,289 @@ +#!/usr/bin/env node +/* eslint-disable no-restricted-syntax */ + +/** + * Script to generate mixin properties from JSON schema + * + * This script generates mixin functions for property/holder, property/meta_holder, + * and property/proto_holder schemas automatically. + * + * Usage: + * node scripts/generate-mixin-properties.js + */ + +import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; +import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; +import { execSync } from "child_process"; +import fs from "fs"; +import type { JSONSchema7 } from "json-schema"; + +/** + * Determines if a property should use requiredProp() or prop() + * @param propertyName - Name of the property + * @param requiredProperties - Array of required property names + * @returns - True if property is required + */ +function isRequiredProperty(propertyName: string, requiredProperties: string[]): boolean { + return requiredProperties.includes(propertyName); +} + +/** + * Generates TypeScript type annotation for a property + * @param propertyName - The property name + * @param schemaName - Name of the schema (for type reference) + * @returns - TypeScript type annotation + */ +function generateTypeAnnotation(propertyName: string, schemaName: string): string { + return `${schemaName}["${propertyName}"]`; +} + +/** + * Extracts properties from a schema, handling allOf if present + * @param schema - The JSON schema + * @returns - Object with properties and required fields + */ +function extractSchemaProperties(schema: JSONSchema7): { + properties: Record; + required: string[]; +} { + let properties: Record = {}; + let required: string[] = []; + + // Handle allOf by merging properties from all schemas + if (schema.allOf && Array.isArray(schema.allOf)) { + for (const subSchema of schema.allOf) { + const extracted = extractSchemaProperties(subSchema as JSONSchema7); + properties = { ...properties, ...extracted.properties }; + required = [...required, ...extracted.required]; + } + } + + // Add properties from current schema + if (schema.properties) { + properties = { ...properties, ...schema.properties }; + } + if (schema.required) { + required = [...required, ...schema.required]; + } + + return { properties, required }; +} + +/** + * Generates the complete mixin function + * @param schema - The JSON schema + * @param schemaName - Name of the schema + * @param mixinTypeName - Name of the mixin type + * @param entityTypeName - Name of the entity type + * @param skipFields - Array of field names to skip + * @returns - Generated TypeScript code + */ +function generateMixinFunction( + schema: JSONSchema7, + schemaName: string, + mixinTypeName: string, + entityTypeName: string, + skipFields: string[] = [], +): string { + // Convert mixin type name to camelCase for function name + const functionName = mixinTypeName.charAt(0).toLowerCase() + mixinTypeName.slice(1); + + // Extract properties, handling allOf if present + const { properties, required } = extractSchemaProperties(schema); + + if (Object.keys(properties).length === 0) { + throw new Error("No properties found in schema"); + } + + // Filter out skip fields + const propertyEntries = Object.entries(properties).filter( + ([propertyName]) => !skipFields.includes(propertyName), + ); + + let code = `import type { InMemoryEntity } from "@mat3ra/code/dist/js/entity";\n`; + code += `import type { ${schemaName} } from "@mat3ra/esse/dist/js/types";\n\n`; + + // Generate the mixin type using Omit utility + const skipFieldNames = skipFields.map((field) => `"${field}"`).join(" | "); + code += `export type ${mixinTypeName} = Omit<${schemaName}, ${skipFieldNames}>;\n\n`; + + // Generate the entity type + code += `export type ${entityTypeName} = InMemoryEntity & ${mixinTypeName};\n\n`; + + code += `export function ${functionName}(item: InMemoryEntity) {\n`; + code += ` // @ts-expect-error\n`; + code += ` const properties: InMemoryEntity & ${mixinTypeName} = {\n`; + + for (let i = 0; i < propertyEntries.length; i++) { + const [propertyName] = propertyEntries[i]; + const isRequired = isRequiredProperty(propertyName, required); + const methodName = isRequired ? "requiredProp" : "prop"; + const typeAnnotation = generateTypeAnnotation(propertyName, schemaName); + + code += `get ${propertyName}() {\n`; + code += `return this.${methodName}<${typeAnnotation}>("${propertyName}");\n`; + code += `}`; + + // Add comma for all properties except the last one + if (i < propertyEntries.length - 1) { + code += `,\n`; + } else { + code += `,\n`; + } + } + + code += ` };\n\n`; + code += ` Object.defineProperties(item, Object.getOwnPropertyDescriptors(properties));\n`; + code += `}\n`; + + return code; +} + +/** + * Generates mixin function for a given schema ID + * @param schemaId - The schema ID (e.g., "property/holder") + * @param outputPath - The output file path + * @param skipFields - Array of field names to skip + * @returns - Generated TypeScript code + */ +function generateMixinFromSchemaId( + schemaId: string, + outputPath: string, + skipFields: string[] = [], +): string { + // Get the resolved schema by ID + const schema = JSONSchemasInterface.getSchemaById(schemaId); + + if (!schema) { + throw new Error(`Schema not found with ID: ${schemaId}`); + } + + // Extract schema name from title for import + let schemaName; + if (schema.title) { + // Convert title to proper schema name + schemaName = schema.title + .split(/\s+/) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(""); + } else { + // Convert schema ID to proper schema name + schemaName = + schemaId + .split(/[/-]/) + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join("") + "Schema"; + } + + // Extract type names from output file path + const fileName = outputPath.split("/").pop()?.replace(".ts", "") ?? ""; + if (!fileName) { + throw new Error(`Invalid output path: ${outputPath}`); + } + + const mixinTypeName = fileName; + const entityTypeName = fileName.replace("SchemaMixin", "InMemoryEntity"); + + // Generate the complete mixin function + return generateMixinFunction(schema, schemaName, mixinTypeName, entityTypeName, skipFields); +} + +/** + * Runs ESLint autofix on generated files + * @param filePaths - Array of file paths to fix + */ +function runESLintAutofix(filePaths: string[]): void { + if (filePaths.length === 0) return; + + try { + console.log("Running ESLint autofix on generated files..."); + const filesToFix = filePaths.join(" "); + execSync(`npx eslint --fix ${filesToFix}`, { stdio: "inherit" }); + console.log("✓ ESLint autofix completed successfully"); + } catch (error) { + console.warn( + "⚠ ESLint autofix failed:", + error instanceof Error ? error.message : String(error), + ); + // Don't fail the entire process if ESLint autofix fails + } +} + +/** + * Generates mixins for multiple schemas + * @param outputPaths - Object mapping schema IDs to output file paths + * @param skipFields - Array of field names to skip during generation + * @returns - Object with success and error counts + */ +function generateShemaMixin(outputPaths: Record, skipFields: string[] = []) { + // Setup schemas + JSONSchemasInterface.setSchemas(allSchemas as JSONSchema7[]); + + console.log("Generating mixin properties for all schemas..."); + + const schemaIds = Object.keys(outputPaths); + let successCount = 0; + let errorCount = 0; + const generatedFiles = []; + + for (const schemaId of schemaIds) { + try { + console.log(`\nProcessing schema: ${schemaId}`); + + const outputPath = outputPaths[schemaId]; + if (!outputPath) { + throw new Error(`No output path defined for schema: ${schemaId}`); + } + + const generatedCode = generateMixinFromSchemaId(schemaId, outputPath, skipFields); + + // Ensure the directory exists + const dir = outputPath.substring(0, outputPath.lastIndexOf("/")); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + fs.writeFileSync(outputPath, generatedCode); + console.log(`✓ Generated mixin written to: ${outputPath}`); + generatedFiles.push(outputPath); + successCount += 1; + } catch (error) { + console.error( + `✗ Error processing schema ${schemaId}: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + errorCount += 1; + } + } + + // Run ESLint autofix on generated files + if (generatedFiles.length > 0) { + runESLintAutofix(generatedFiles); + } + + console.log(`\n=== Summary ===`); + console.log(`Successfully generated: ${successCount} mixins`); + if (errorCount > 0) { + console.log(`Errors: ${errorCount} schemas failed`); + } else { + console.log("All mixins generated successfully!"); + } + + return { successCount, errorCount }; +} + +/** + * @example + * ```ts + * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * + * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * + * if (result.errorCount > 0) { + * process.exit(1); + * } + * ``` + */ + +export default generateShemaMixin; diff --git a/tests/js/enums.ts b/tests/js/enums.ts index 32a43749..9140375b 100644 --- a/tests/js/enums.ts +++ b/tests/js/enums.ts @@ -1,6 +1,7 @@ import * as path from "path"; -export const FIXTURES_DIR = path.resolve(__dirname, "./fixtures"); +// Use relative path from the test directory - this will be resolved at runtime +export const FIXTURES_DIR = path.resolve(process.cwd(), "tests/js/fixtures"); export const YAML_COMBINE_FILE = path.resolve(FIXTURES_DIR, "yaml_combine_tag.yml"); export const YAML_LIST_TO_STRING_FILE = path.resolve(FIXTURES_DIR, "yaml_listToString_tag.yml"); export const YAML_PARAMETER_FILE = path.resolve(FIXTURES_DIR, "yaml_parameter_tag.yml"); diff --git a/tests/js/generateSchemaMixin.tests.ts b/tests/js/generateSchemaMixin.tests.ts new file mode 100644 index 00000000..4d1aad41 --- /dev/null +++ b/tests/js/generateSchemaMixin.tests.ts @@ -0,0 +1,161 @@ +/* eslint-disable no-unused-expressions */ +import { expect } from "chai"; +import fs from "fs"; +import path from "path"; + +import generateShemaMixin from "../../src/js/generateSchemaMixin"; + +describe("generateSchemaMixin Tests", () => { + const tempDir = path.join(__dirname, "temp_test_output"); + + beforeEach(() => { + // Create a temporary directory for test files + if (!fs.existsSync(tempDir)) { + fs.mkdirSync(tempDir, { recursive: true }); + } + }); + + afterEach(() => { + // Clean up temporary files and directories + if (fs.existsSync(tempDir)) { + const removeRecursive = (dirPath: string) => { + if (fs.existsSync(dirPath)) { + const files = fs.readdirSync(dirPath); + files.forEach((file) => { + const filePath = path.join(dirPath, file); + const stat = fs.statSync(filePath); + if (stat.isDirectory()) { + removeRecursive(filePath); + } else { + fs.unlinkSync(filePath); + } + }); + fs.rmdirSync(dirPath); + } + }; + removeRecursive(tempDir); + } + }); + + describe("generateShemaMixin - Basic Functionality", () => { + it("should handle empty output paths object", () => { + const outputPaths = {}; + + const result = generateShemaMixin(outputPaths); + + expect(result.successCount).to.equal(0); + expect(result.errorCount).to.equal(0); + }); + + it("should create directories if they don't exist", () => { + const nestedDir = path.join(tempDir, "nested", "directory"); + const outputPaths = { + "property/holder": path.join(nestedDir, "PropertyHolderSchemaMixin.ts"), + }; + + generateShemaMixin(outputPaths); + + // The function should attempt to create the directory + expect(fs.existsSync(nestedDir)).to.be.true; + }); + + it("should handle skip fields parameter", () => { + const outputPaths = { + "property/holder": path.join(tempDir, "PropertyHolderSchemaMixin.ts"), + }; + const skipFields = ["metadata"]; + + // This should not throw an error even if the schema doesn't exist + expect(() => { + generateShemaMixin(outputPaths, skipFields); + }).to.not.throw(); + }); + }); + + describe("generateShemaMixin - Error Handling", () => { + it("should handle non-existent schema IDs gracefully", () => { + const outputPaths = { + "non/existent": path.join(tempDir, "NonExistentSchemaMixin.ts"), + }; + + const result = generateShemaMixin(outputPaths); + + expect(result.successCount).to.equal(0); + expect(result.errorCount).to.equal(1); + }); + + it("should handle missing output paths", () => { + const outputPaths = { + "property/holder": undefined as unknown as string, + }; + + const result = generateShemaMixin(outputPaths); + + expect(result.successCount).to.equal(0); + expect(result.errorCount).to.equal(1); + }); + + it("should handle invalid output paths", () => { + const outputPaths = { + "property/holder": "", + }; + + const result = generateShemaMixin(outputPaths); + + expect(result.successCount).to.equal(0); + expect(result.errorCount).to.equal(1); + }); + }); + + describe("generateShemaMixin - Return Value", () => { + it("should return an object with successCount and errorCount", () => { + const outputPaths = {}; + + const result = generateShemaMixin(outputPaths); + + expect(result).to.have.property("successCount"); + expect(result).to.have.property("errorCount"); + expect(typeof result.successCount).to.equal("number"); + expect(typeof result.errorCount).to.equal("number"); + }); + + it("should return correct counts for mixed results", () => { + const outputPaths = { + "non/existent": path.join(tempDir, "NonExistentSchemaMixin.ts"), + "another/non/existent": path.join(tempDir, "AnotherNonExistentSchemaMixin.ts"), + }; + + const result = generateShemaMixin(outputPaths); + + expect(result.successCount).to.equal(0); + expect(result.errorCount).to.equal(2); + }); + }); + + describe("generateShemaMixin - Function Interface", () => { + it("should accept outputPaths as first parameter", () => { + const outputPaths = {}; + + expect(() => { + generateShemaMixin(outputPaths); + }).to.not.throw(); + }); + + it("should accept skipFields as optional second parameter", () => { + const outputPaths = {}; + const skipFields = ["field1", "field2"]; + + expect(() => { + generateShemaMixin(outputPaths, skipFields); + }).to.not.throw(); + }); + + it("should work without skipFields parameter", () => { + const outputPaths = {}; + + expect(() => { + generateShemaMixin(outputPaths); + }).to.not.throw(); + }); + }); +}); diff --git a/tests/js/utils.ts b/tests/js/utils.ts index e8207b9b..f0069b02 100644 --- a/tests/js/utils.ts +++ b/tests/js/utils.ts @@ -1,4 +1,4 @@ -import { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; +import type { AnyObject } from "@mat3ra/esse/dist/js/esse/types"; import { expect } from "chai"; export function assertObject(prop: unknown): prop is AnyObject { From cf60cc2d92499bc81aefa885145ba66eca0f7ef2 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Wed, 8 Oct 2025 17:38:57 +0300 Subject: [PATCH 2/4] update: add generateSchemaMixin + node22 build fix --- dist/js/generateSchemaMixin.d.ts | 7 +++- dist/js/generateSchemaMixin.js | 9 +++-- src/js/generateSchemaMixin.ts | 13 +++++-- tests/js/generateSchemaMixin.tests.ts | 55 ++++++++++++++++++++------- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/dist/js/generateSchemaMixin.d.ts b/dist/js/generateSchemaMixin.d.ts index 05d2d47e..93c64524 100644 --- a/dist/js/generateSchemaMixin.d.ts +++ b/dist/js/generateSchemaMixin.d.ts @@ -1,11 +1,13 @@ #!/usr/bin/env node +import type { JSONSchema7 } from "json-schema"; /** * Generates mixins for multiple schemas + * @param schemas - Array of JSON schemas to use for generation * @param outputPaths - Object mapping schema IDs to output file paths * @param skipFields - Array of field names to skip during generation * @returns - Object with success and error counts */ -declare function generateShemaMixin(outputPaths: Record, skipFields?: string[]): { +declare function generateShemaMixin(schemas: JSONSchema7[], outputPaths: Record, skipFields?: string[]): { successCount: number; errorCount: number; }; @@ -13,8 +15,9 @@ declare function generateShemaMixin(outputPaths: Record, skipFie * @example * ```ts * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; * - * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * const result = generateShemaMixin(allSchemas, OUTPUT_PATHS, SKIP_FIELDS); * * if (result.errorCount > 0) { * process.exit(1); diff --git a/dist/js/generateSchemaMixin.js b/dist/js/generateSchemaMixin.js index a00648a3..1781ecd2 100644 --- a/dist/js/generateSchemaMixin.js +++ b/dist/js/generateSchemaMixin.js @@ -15,7 +15,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); * node scripts/generate-mixin-properties.js */ const JSONSchemasInterface_1 = __importDefault(require("@mat3ra/esse/dist/js/esse/JSONSchemasInterface")); -const schemas_json_1 = __importDefault(require("@mat3ra/esse/dist/js/schemas.json")); const child_process_1 = require("child_process"); const fs_1 = __importDefault(require("fs")); /** @@ -172,13 +171,14 @@ function runESLintAutofix(filePaths) { } /** * Generates mixins for multiple schemas + * @param schemas - Array of JSON schemas to use for generation * @param outputPaths - Object mapping schema IDs to output file paths * @param skipFields - Array of field names to skip during generation * @returns - Object with success and error counts */ -function generateShemaMixin(outputPaths, skipFields = []) { +function generateShemaMixin(schemas, outputPaths, skipFields = []) { // Setup schemas - JSONSchemasInterface_1.default.setSchemas(schemas_json_1.default); + JSONSchemasInterface_1.default.setSchemas(schemas); console.log("Generating mixin properties for all schemas..."); const schemaIds = Object.keys(outputPaths); let successCount = 0; @@ -225,8 +225,9 @@ function generateShemaMixin(outputPaths, skipFields = []) { * @example * ```ts * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; * - * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * const result = generateShemaMixin(allSchemas, OUTPUT_PATHS, SKIP_FIELDS); * * if (result.errorCount > 0) { * process.exit(1); diff --git a/src/js/generateSchemaMixin.ts b/src/js/generateSchemaMixin.ts index a387d70a..0ef4726b 100644 --- a/src/js/generateSchemaMixin.ts +++ b/src/js/generateSchemaMixin.ts @@ -12,7 +12,6 @@ */ import JSONSchemasInterface from "@mat3ra/esse/dist/js/esse/JSONSchemasInterface"; -import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; import { execSync } from "child_process"; import fs from "fs"; import type { JSONSchema7 } from "json-schema"; @@ -211,13 +210,18 @@ function runESLintAutofix(filePaths: string[]): void { /** * Generates mixins for multiple schemas + * @param schemas - Array of JSON schemas to use for generation * @param outputPaths - Object mapping schema IDs to output file paths * @param skipFields - Array of field names to skip during generation * @returns - Object with success and error counts */ -function generateShemaMixin(outputPaths: Record, skipFields: string[] = []) { +function generateShemaMixin( + schemas: JSONSchema7[], + outputPaths: Record, + skipFields: string[] = [], +) { // Setup schemas - JSONSchemasInterface.setSchemas(allSchemas as JSONSchema7[]); + JSONSchemasInterface.setSchemas(schemas); console.log("Generating mixin properties for all schemas..."); @@ -277,8 +281,9 @@ function generateShemaMixin(outputPaths: Record, skipFields: str * @example * ```ts * import generateShemaMixin from "@mat3ra/code/dist/js/generateSchemaMixin"; + * import allSchemas from "@mat3ra/esse/dist/js/schemas.json"; * - * const result = generateShemaMixin(OUTPUT_PATHS, SKIP_FIELDS); + * const result = generateShemaMixin(allSchemas, OUTPUT_PATHS, SKIP_FIELDS); * * if (result.errorCount > 0) { * process.exit(1); diff --git a/tests/js/generateSchemaMixin.tests.ts b/tests/js/generateSchemaMixin.tests.ts index 4d1aad41..1ecb9251 100644 --- a/tests/js/generateSchemaMixin.tests.ts +++ b/tests/js/generateSchemaMixin.tests.ts @@ -1,6 +1,7 @@ /* eslint-disable no-unused-expressions */ import { expect } from "chai"; import fs from "fs"; +import type { JSONSchema7 } from "json-schema"; import path from "path"; import generateShemaMixin from "../../src/js/generateSchemaMixin"; @@ -8,7 +9,25 @@ import generateShemaMixin from "../../src/js/generateSchemaMixin"; describe("generateSchemaMixin Tests", () => { const tempDir = path.join(__dirname, "temp_test_output"); - beforeEach(() => { + // Mock schemas for testing + const mockSchemas: JSONSchema7[] = [ + { + $id: "property/holder", + title: "Property Holder", + type: "object", + properties: { + metadata: { type: "object" }, + name: { type: "string" }, + description: { type: "string" }, + }, + required: ["name"], + }, + ]; + + beforeEach(function setupTests() { + // Increase timeout to 10 seconds because generateShemaMixin runs ESLint autofix + // which can take several seconds to complete, especially on first run + this.timeout(10000); // Create a temporary directory for test files if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); @@ -41,7 +60,7 @@ describe("generateSchemaMixin Tests", () => { it("should handle empty output paths object", () => { const outputPaths = {}; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result.successCount).to.equal(0); expect(result.errorCount).to.equal(0); @@ -53,7 +72,7 @@ describe("generateSchemaMixin Tests", () => { "property/holder": path.join(nestedDir, "PropertyHolderSchemaMixin.ts"), }; - generateShemaMixin(outputPaths); + generateShemaMixin(mockSchemas, outputPaths); // The function should attempt to create the directory expect(fs.existsSync(nestedDir)).to.be.true; @@ -67,7 +86,7 @@ describe("generateSchemaMixin Tests", () => { // This should not throw an error even if the schema doesn't exist expect(() => { - generateShemaMixin(outputPaths, skipFields); + generateShemaMixin(mockSchemas, outputPaths, skipFields); }).to.not.throw(); }); }); @@ -78,7 +97,7 @@ describe("generateSchemaMixin Tests", () => { "non/existent": path.join(tempDir, "NonExistentSchemaMixin.ts"), }; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result.successCount).to.equal(0); expect(result.errorCount).to.equal(1); @@ -89,7 +108,7 @@ describe("generateSchemaMixin Tests", () => { "property/holder": undefined as unknown as string, }; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result.successCount).to.equal(0); expect(result.errorCount).to.equal(1); @@ -100,7 +119,7 @@ describe("generateSchemaMixin Tests", () => { "property/holder": "", }; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result.successCount).to.equal(0); expect(result.errorCount).to.equal(1); @@ -111,7 +130,7 @@ describe("generateSchemaMixin Tests", () => { it("should return an object with successCount and errorCount", () => { const outputPaths = {}; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result).to.have.property("successCount"); expect(result).to.have.property("errorCount"); @@ -125,7 +144,7 @@ describe("generateSchemaMixin Tests", () => { "another/non/existent": path.join(tempDir, "AnotherNonExistentSchemaMixin.ts"), }; - const result = generateShemaMixin(outputPaths); + const result = generateShemaMixin(mockSchemas, outputPaths); expect(result.successCount).to.equal(0); expect(result.errorCount).to.equal(2); @@ -133,20 +152,28 @@ describe("generateSchemaMixin Tests", () => { }); describe("generateShemaMixin - Function Interface", () => { - it("should accept outputPaths as first parameter", () => { + it("should accept schemas as first parameter", () => { const outputPaths = {}; expect(() => { - generateShemaMixin(outputPaths); + generateShemaMixin(mockSchemas, outputPaths); }).to.not.throw(); }); - it("should accept skipFields as optional second parameter", () => { + it("should accept outputPaths as second parameter", () => { + const outputPaths = {}; + + expect(() => { + generateShemaMixin(mockSchemas, outputPaths); + }).to.not.throw(); + }); + + it("should accept skipFields as optional third parameter", () => { const outputPaths = {}; const skipFields = ["field1", "field2"]; expect(() => { - generateShemaMixin(outputPaths, skipFields); + generateShemaMixin(mockSchemas, outputPaths, skipFields); }).to.not.throw(); }); @@ -154,7 +181,7 @@ describe("generateSchemaMixin Tests", () => { const outputPaths = {}; expect(() => { - generateShemaMixin(outputPaths); + generateShemaMixin(mockSchemas, outputPaths); }).to.not.throw(); }); }); From 56dc03665fc304f283aa14c59152703c5a05b786 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Wed, 8 Oct 2025 17:58:21 +0300 Subject: [PATCH 3/4] update: add generateSchemaMixin + node22 build fix --- tests/js/generateSchemaMixin.tests.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/js/generateSchemaMixin.tests.ts b/tests/js/generateSchemaMixin.tests.ts index 1ecb9251..7800d988 100644 --- a/tests/js/generateSchemaMixin.tests.ts +++ b/tests/js/generateSchemaMixin.tests.ts @@ -6,7 +6,10 @@ import path from "path"; import generateShemaMixin from "../../src/js/generateSchemaMixin"; -describe("generateSchemaMixin Tests", () => { +describe("generateSchemaMixin Tests", function () { + // Increase timeout to 10 seconds because generateShemaMixin runs ESLint autofix + // which can take several seconds to complete, especially on first run + this.timeout(10000); const tempDir = path.join(__dirname, "temp_test_output"); // Mock schemas for testing @@ -24,10 +27,7 @@ describe("generateSchemaMixin Tests", () => { }, ]; - beforeEach(function setupTests() { - // Increase timeout to 10 seconds because generateShemaMixin runs ESLint autofix - // which can take several seconds to complete, especially on first run - this.timeout(10000); + beforeEach(() => { // Create a temporary directory for test files if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); From 65068c200cc29806d83ea0001bf0c37acb1a4e64 Mon Sep 17 00:00:00 2001 From: Kostiantyn Dvornik Date: Wed, 8 Oct 2025 22:11:19 +0300 Subject: [PATCH 4/4] chore: esse --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index d85277df..90876478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "@babel/register": "^7.25.7", "@babel/runtime-corejs3": "^7.25.7", "@exabyte-io/eslint-config": "^2025.1.15-0", - "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", + "@mat3ra/esse": "2025.10.8-0", "@mat3ra/tsconfig": "2024.6.3-0", "@types/chai": "^4.3.20", "@types/crypto-js": "^4.2.2", @@ -2309,9 +2309,9 @@ "license": "MIT" }, "node_modules/@mat3ra/esse": { - "version": "0.0.0", - "resolved": "git+ssh://git@github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", - "integrity": "sha512-odpa1r5U4RtVX7nen9FOiDzY/mZqd9P0TzoePOLViZUXqjXyqKMWb0k7AO5uXT4iA3yk7uFghxuk0QXiMVvDXg==", + "version": "2025.10.8-0", + "resolved": "https://registry.npmjs.org/@mat3ra/esse/-/esse-2025.10.8-0.tgz", + "integrity": "sha512-JwHWF0nXdcv9pceYePNpAixnjIkQLPtlB2fm4MatRXiH9CqrPrHBRH+t/0v5O1Em2uM5jsnqA+EYB0toOMHOVw==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index f0a91591..b8022f83 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@babel/register": "^7.25.7", "@babel/runtime-corejs3": "^7.25.7", "@exabyte-io/eslint-config": "^2025.1.15-0", - "@mat3ra/esse": "git+https://github.com/Exabyte-io/esse.git#07e8bec495a6658031ed4af3a90f004c818b705a", + "@mat3ra/esse": "2025.10.8-0", "@mat3ra/tsconfig": "2024.6.3-0", "@types/chai": "^4.3.20", "@types/crypto-js": "^4.2.2",