From 6cac9dd2ddef99853d5f4bbd5bc2c48c929144bd Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 25 Nov 2025 14:42:02 -0400 Subject: [PATCH] Improve NPM interface Signed-off-by: Juan Cruz Viotti --- npm/cjs.test.js | 33 +++++++++++++++++++++++++++++++++ npm/esm.test.mjs | 30 +++++++++++++++++++++++++++++- npm/main.js | 42 ++++++++++++++++++++++++++++++++++++++++++ npm/main.mjs | 27 ++++----------------------- 4 files changed, 108 insertions(+), 24 deletions(-) diff --git a/npm/cjs.test.js b/npm/cjs.test.js index 04bde41..5b7a878 100644 --- a/npm/cjs.test.js +++ b/npm/cjs.test.js @@ -36,3 +36,36 @@ test('loads schema from nested path', () => { assert.strictEqual(typeof schema, 'object'); assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); }); + +test('lazy loads schema via schemas object', () => { + const { schemas } = require('..'); + const schema = schemas['2020-12'].misc['schema-like']; + assert.strictEqual(typeof schema, 'object'); + assert.strictEqual(schema.title, 'JSON Schema Document'); +}); + +test('caches loaded schemas', () => { + const { schemas } = require('..'); + const schema1 = schemas['2020-12'].misc['schema-like']; + const schema2 = schemas['2020-12'].misc['schema-like']; + assert.strictEqual(schema1, schema2); +}); + +test('handles deeply nested paths', () => { + const { schemas } = require('..'); + const schema = schemas['2020-12'].w3c.xmlschema['2001']['hex-binary']; + assert.strictEqual(typeof schema, 'object'); + assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); +}); + +test('returns undefined for non-existent directories', () => { + const { schemas } = require('..'); + const result = schemas['2020-12'].nonexistent; + assert.strictEqual(result, undefined); +}); + +test('returns undefined for non-existent files', () => { + const { schemas } = require('..'); + const result = schemas['2020-12'].misc['nonexistent-file']; + assert.strictEqual(result, undefined); +}); diff --git a/npm/esm.test.mjs b/npm/esm.test.mjs index 26e8756..0b2cf20 100644 --- a/npm/esm.test.mjs +++ b/npm/esm.test.mjs @@ -1,6 +1,6 @@ import test from 'node:test'; import assert from 'node:assert'; -import getSchema from '@sourcemeta/std'; +import getSchema, { schemas } from '@sourcemeta/std'; test('loads a valid schema', () => { const schema = getSchema('2020-12/misc/schema-like'); @@ -36,3 +36,31 @@ test('loads schema from nested path', () => { assert.strictEqual(typeof schema, 'object'); assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); }); + +test('lazy loads schema via schemas object', () => { + const schema = schemas['2020-12'].misc['schema-like']; + assert.strictEqual(typeof schema, 'object'); + assert.strictEqual(schema.title, 'JSON Schema Document'); +}); + +test('caches loaded schemas', () => { + const schema1 = schemas['2020-12'].misc['schema-like']; + const schema2 = schemas['2020-12'].misc['schema-like']; + assert.strictEqual(schema1, schema2); +}); + +test('handles deeply nested paths', () => { + const schema = schemas['2020-12'].w3c.xmlschema['2001']['hex-binary']; + assert.strictEqual(typeof schema, 'object'); + assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); +}); + +test('returns undefined for non-existent directories', () => { + const result = schemas['2020-12'].nonexistent; + assert.strictEqual(result, undefined); +}); + +test('returns undefined for non-existent files', () => { + const result = schemas['2020-12'].misc['nonexistent-file']; + assert.strictEqual(result, undefined); +}); diff --git a/npm/main.js b/npm/main.js index e3fa04a..f8bca95 100644 --- a/npm/main.js +++ b/npm/main.js @@ -20,4 +20,46 @@ function getSchema(schemaPath) { } } +const cache = new Map(); + +function createSchemaProxy(currentPath = '') { + return new Proxy({}, { + get(target, property) { + if (typeof property !== 'string') { + return undefined; + } + + const newPath = currentPath ? `${currentPath}/${property}` : property; + + if (cache.has(newPath)) { + return cache.get(newPath); + } + + const schemaBasePath = path.join(__dirname, '..', 'schemas'); + const fullPath = path.join(schemaBasePath, newPath); + + const jsonPath = `${fullPath}.json`; + if (fs.existsSync(jsonPath)) { + try { + const content = fs.readFileSync(jsonPath, 'utf8'); + const schema = JSON.parse(content); + cache.set(newPath, schema); + return schema; + } catch (error) { + return undefined; + } + } + + if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) { + const proxy = createSchemaProxy(newPath); + cache.set(newPath, proxy); + return proxy; + } + + return undefined; + } + }); +} + module.exports = getSchema; +module.exports.schemas = createSchemaProxy(); diff --git a/npm/main.mjs b/npm/main.mjs index 913db74..93be0bf 100644 --- a/npm/main.mjs +++ b/npm/main.mjs @@ -1,26 +1,7 @@ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; +import { createRequire } from 'node:module'; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -function getSchema(schemaPath) { - if (!schemaPath || typeof schemaPath !== 'string') { - return null; - } - - if (schemaPath.includes('..')) { - return null; - } - - const absolutePath = path.join(__dirname, '..', 'schemas', `${schemaPath}.json`); - - try { - const content = fs.readFileSync(absolutePath, 'utf8'); - return JSON.parse(content); - } catch (error) { - return null; - } -} +const require = createRequire(import.meta.url); +const getSchema = require('./main.js'); +export const schemas = getSchema.schemas; export default getSchema;