From 6f7f0b11c58889dfce3146726766ad1cc56bd4a5 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 29 Dec 2025 13:38:14 -0400 Subject: [PATCH 1/2] WIP Signed-off-by: Juan Cruz Viotti --- meta/schemas.json | 12 +- schemas/2020-12/misc/single-line-text.json | 15 - test/misc/single-line-text.test.json | 341 --------------------- 3 files changed, 9 insertions(+), 359 deletions(-) delete mode 100644 schemas/2020-12/misc/single-line-text.json delete mode 100644 test/misc/single-line-text.test.json diff --git a/meta/schemas.json b/meta/schemas.json index 0ddb9c44..417c2072 100644 --- a/meta/schemas.json +++ b/meta/schemas.json @@ -15,13 +15,19 @@ "properties": { "$id": false, "$comment": { - "$ref": "../schemas/2020-12/misc/single-line-text.json" + "$ref": "#/$defs/single-line-text" }, "title": { - "$ref": "../schemas/2020-12/misc/single-line-text.json" + "$ref": "#/$defs/single-line-text" }, "description": { - "$ref": "../schemas/2020-12/misc/single-line-text.json" + "$ref": "#/$defs/single-line-text" + } + }, + "$defs": { + "single-line-text": { + "type": "string", + "pattern": "^(?!.*\\.$)(?!.*(? Date: Mon, 29 Dec 2025 13:39:57 -0400 Subject: [PATCH 2/2] Simplify repository Signed-off-by: Juan Cruz Viotti --- .github/workflows/cd.yml | 5 - .github/workflows/ci.yml | 1 - .npmignore | 9 - Makefile | 19 - README.markdown | 1 - npm/cjs.test.js | 71 ---- npm/esm.test.mjs | 66 ---- npm/main.js | 65 ---- npm/main.mjs | 7 - package.json | 52 +-- schemas/2020-12/misc/schema-like.json | 17 - test/misc/schema-like.test.json | 495 -------------------------- vendorpull.mask | 2 - 13 files changed, 2 insertions(+), 808 deletions(-) delete mode 100644 .npmignore delete mode 100644 npm/cjs.test.js delete mode 100644 npm/esm.test.mjs delete mode 100644 npm/main.js delete mode 100644 npm/main.mjs delete mode 100644 schemas/2020-12/misc/schema-like.json delete mode 100644 test/misc/schema-like.test.json diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 0e3a68b8..e80e6900 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -21,7 +21,6 @@ jobs: - uses: actions/checkout@v4 - run: make lint - run: make test - - run: make dist - run: ./scripts/ci-quality-no-uncommitted-files.sh - run: gh config set prompt disabled @@ -31,10 +30,6 @@ jobs: - name: Perform Tag Release run: | gh release create ${{ github.ref_name }} --draft=false --title ${{ github.ref_name }} --target "$GITHUB_SHA" --generate-notes - gh release upload --clobber ${{ github.ref_name }} dist/*.zip dist/*.tar.gz if: github.ref_type == 'tag' env: GH_TOKEN: ${{ github.token }} - - - name: Publish to NPM - run: sudo npm install --global npm@latest && npm publish diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ff27840..e0e4191d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,5 +20,4 @@ jobs: - uses: actions/checkout@v4 - run: make lint - run: make test - - run: make dist - run: ./scripts/ci-quality-no-uncommitted-files.sh diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 4c27a088..00000000 --- a/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -* -!LICENSE -!README.markdown -!schemas -!schemas/** -!npm -!npm/** -npm/**/*.test.js -npm/**/*.test.mjs diff --git a/Makefile b/Makefile index e2c2717b..3b80b791 100644 --- a/Makefile +++ b/Makefile @@ -40,25 +40,6 @@ lint: common node_modules .PHONY: test test: node_modules $(TIME) $(NODE) $(JSONSCHEMA) test ./test - $(NODE) npm/cjs.test.js - $(NODE) npm/esm.test.mjs - -# TODO: Add a `jsonschema pkg` command instead -.PHONY: dist -VERSION = $(shell $(JQ) --raw-output '.["x-version"]' jsonschema.json) -dist: - $(RMRF) $@ - $(MKDIRP) $@ - cd schemas && $(ZIP) -r ../$@/sourcemeta-std-v$(VERSION).zip * -x '*.DS_Store' - $(ZIP) $@/sourcemeta-std-v$(VERSION).zip LICENSE - $(UNZIP) -l $@/sourcemeta-std-v$(VERSION).zip - cd schemas && $(TAR) -cf ../$@/sourcemeta-std-v$(VERSION).tar --exclude '.DS_Store' * - $(TAR) -rf $@/sourcemeta-std-v$(VERSION).tar LICENSE - $(GZIP) $@/sourcemeta-std-v$(VERSION).tar - $(TAR) -tzf $@/sourcemeta-std-v$(VERSION).tar.gz - $(MKDIRP) $@/npm - $(NPM) version --no-git-tag-version --allow-same-version "$(VERSION)" - $(NPM) pack --pack-destination $@/npm node_modules: package.json package-lock.json $(NPM) ci diff --git a/README.markdown b/README.markdown index 6c675801..6508cdfa 100644 --- a/README.markdown +++ b/README.markdown @@ -2,7 +2,6 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17526561.svg)](https://doi.org/10.5281/zenodo.17526561) [![GitHub Release](https://img.shields.io/github/v/release/sourcemeta/std)](https://github.com/sourcemeta/std/releases) -[![NPM Version](https://img.shields.io/npm/v/@sourcemeta/std)](https://www.npmjs.com/package/@sourcemeta/std) *** **Browse the schemas at [https://schemas.sourcemeta.com/sourcemeta/std](https://schemas.sourcemeta.com/sourcemeta/std)** diff --git a/npm/cjs.test.js b/npm/cjs.test.js deleted file mode 100644 index 5b7a8787..00000000 --- a/npm/cjs.test.js +++ /dev/null @@ -1,71 +0,0 @@ -const test = require('node:test'); -const assert = require('node:assert'); -const getSchema = require('..'); - -test('loads a valid schema', () => { - const schema = getSchema('2020-12/misc/schema-like'); - assert.strictEqual(typeof schema, 'object'); - assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); - assert.strictEqual(schema.title, 'JSON Schema Document'); -}); - -test('returns null for non-existent schema', () => { - const schema = getSchema('nonexistent/schema/path'); - assert.strictEqual(schema, null); -}); - -test('returns null for invalid input types', () => { - assert.strictEqual(getSchema(null), null); - assert.strictEqual(getSchema(undefined), null); - assert.strictEqual(getSchema(123), null); - assert.strictEqual(getSchema({}), null); -}); - -test('blocks directory traversal attempts', () => { - const schema = getSchema('../package'); - assert.strictEqual(schema, null); -}); - -test('blocks directory traversal with multiple levels', () => { - const schema = getSchema('../../etc/passwd'); - assert.strictEqual(schema, null); -}); - -test('loads schema from nested path', () => { - const schema = getSchema('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('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 deleted file mode 100644 index 0b2cf203..00000000 --- a/npm/esm.test.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import test from 'node:test'; -import assert from 'node:assert'; -import getSchema, { schemas } from '@sourcemeta/std'; - -test('loads a valid schema', () => { - const schema = getSchema('2020-12/misc/schema-like'); - assert.strictEqual(typeof schema, 'object'); - assert.strictEqual(schema.$schema, 'https://json-schema.org/draft/2020-12/schema'); - assert.strictEqual(schema.title, 'JSON Schema Document'); -}); - -test('returns null for non-existent schema', () => { - const schema = getSchema('nonexistent/schema/path'); - assert.strictEqual(schema, null); -}); - -test('returns null for invalid input types', () => { - assert.strictEqual(getSchema(null), null); - assert.strictEqual(getSchema(undefined), null); - assert.strictEqual(getSchema(123), null); - assert.strictEqual(getSchema({}), null); -}); - -test('blocks directory traversal attempts', () => { - const schema = getSchema('../package'); - assert.strictEqual(schema, null); -}); - -test('blocks directory traversal with multiple levels', () => { - const schema = getSchema('../../etc/passwd'); - assert.strictEqual(schema, null); -}); - -test('loads schema from nested path', () => { - const schema = getSchema('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('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 deleted file mode 100644 index f8bca959..00000000 --- a/npm/main.js +++ /dev/null @@ -1,65 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -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 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 deleted file mode 100644 index 93be0bf5..00000000 --- a/npm/main.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import { createRequire } from 'node:module'; - -const require = createRequire(import.meta.url); -const getSchema = require('./main.js'); - -export const schemas = getSchema.schemas; -export default getSchema; diff --git a/package.json b/package.json index df132a6f..5c98b957 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,7 @@ { "name": "@sourcemeta/std", - "version": "0.3.1", - "description": "A growing collection of hand-crafted high-quality schemas, From RFC-compliant Email Address schemas to ISO-compliant Currency Codes", - "main": "npm/main.js", - "module": "npm/main.mjs", - "exports": { - ".": { - "import": "./npm/main.mjs", - "require": "./npm/main.js" - } - }, - "license": "UNLICENSED", - "homepage": "https://github.com/sourcemeta/std", - "author": { - "email": "hello@sourcemeta.com", - "name": "Sourcemeta", - "url": "https://www.sourcemeta.com" - }, - "funding": "https://github.com/sponsors/sourcemeta", - "keywords": [ - "jsonschema", - "json", - "schema", - "json-schema", - "cli", - "$ref", - "dereference", - "reference", - "resolve", - "json-pointer", - "validator", - "validation", - "bundle", - "json-schema-validator", - "json-schema-validation", - "lint", - "format", - "draft", - "library" - ], - "bugs": { - "url": "https://github.com/sourcemeta/std/issues" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/sourcemeta/std.git" - }, - "publishConfig": { - "provenance": true, - "access": "public" - }, + "version": "0.0.0", + "private": true, "devDependencies": { "@sourcemeta/jsonschema": "^13.2.0" } diff --git a/schemas/2020-12/misc/schema-like.json b/schemas/2020-12/misc/schema-like.json deleted file mode 100644 index 7ca0507d..00000000 --- a/schemas/2020-12/misc/schema-like.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "JSON Schema Document", - "description": "A JSON document that is considered to be a potentially valid JSON Schema", - "examples": [ - true, - false, - { - "type": "string" - } - ], - "x-license": "https://github.com/sourcemeta/std/blob/main/LICENSE", - "x-links": [ - "https://json-schema.org/draft/2020-12/json-schema-core#name-json-schema-documents" - ], - "type": [ "object", "boolean" ] -} diff --git a/test/misc/schema-like.test.json b/test/misc/schema-like.test.json deleted file mode 100644 index 4545b41a..00000000 --- a/test/misc/schema-like.test.json +++ /dev/null @@ -1,495 +0,0 @@ -{ - "x-license": "https://github.com/sourcemeta/std/blob/main/LICENSE", - "target": "../../schemas/2020-12/misc/schema-like.json", - "tests": [ - { - "description": "Invalid type - string", - "data": "foo", - "valid": false - }, - { - "description": "Invalid type - number", - "data": 123, - "valid": false - }, - { - "description": "Invalid type - null", - "data": null, - "valid": false - }, - { - "description": "Invalid type - array", - "data": [], - "valid": false - }, - { - "description": "Invalid type - non-empty array", - "data": [ "type", "string" ], - "valid": false - }, - { - "description": "Valid - boolean true", - "data": true, - "valid": true - }, - { - "description": "Valid - boolean false", - "data": false, - "valid": true - }, - { - "description": "Valid - empty object", - "data": {}, - "valid": true - }, - { - "description": "Valid - simple type constraint", - "data": { - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - type with format", - "data": { - "type": "string", - "format": "email" - }, - "valid": true - }, - { - "description": "Valid - string with pattern", - "data": { - "type": "string", - "pattern": "^[a-z]+$" - }, - "valid": true - }, - { - "description": "Valid - number with minimum and maximum", - "data": { - "type": "number", - "maximum": 100, - "minimum": 0 - }, - "valid": true - }, - { - "description": "Valid - integer constraints", - "data": { - "type": "integer", - "exclusiveMaximum": 1000, - "exclusiveMinimum": 0, - "multipleOf": 5 - }, - "valid": true - }, - { - "description": "Valid - array with items", - "data": { - "type": "array", - "items": { - "type": "string" - } - }, - "valid": true - }, - { - "description": "Valid - array with prefixItems", - "data": { - "type": "array", - "prefixItems": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "valid": true - }, - { - "description": "Valid - array with contains", - "data": { - "type": "array", - "maxContains": 5, - "minContains": 1, - "contains": { - "type": "string" - } - }, - "valid": true - }, - { - "description": "Valid - array with minItems and maxItems", - "data": { - "type": "array", - "maxItems": 10, - "minItems": 1, - "uniqueItems": true - }, - "valid": true - }, - { - "description": "Valid - object with properties", - "data": { - "type": "object", - "properties": { - "age": { - "type": "integer" - }, - "name": { - "type": "string" - } - } - }, - "valid": true - }, - { - "description": "Valid - object with required", - "data": { - "type": "object", - "required": [ "name" ], - "properties": { - "name": { - "type": "string" - } - } - }, - "valid": true - }, - { - "description": "Valid - object with additionalProperties", - "data": { - "type": "object", - "additionalProperties": false - }, - "valid": true - }, - { - "description": "Valid - object with patternProperties", - "data": { - "type": "object", - "patternProperties": { - "^I_": { - "type": "integer" - }, - "^S_": { - "type": "string" - } - } - }, - "valid": true - }, - { - "description": "Valid - object with propertyNames", - "data": { - "type": "object", - "propertyNames": { - "pattern": "^[a-z]+$" - } - }, - "valid": true - }, - { - "description": "Valid - object with minProperties and maxProperties", - "data": { - "type": "object", - "maxProperties": 10, - "minProperties": 1 - }, - "valid": true - }, - { - "description": "Valid - object with dependentRequired", - "data": { - "type": "object", - "dependentRequired": { - "credit_card": [ "billing_address" ] - } - }, - "valid": true - }, - { - "description": "Valid - object with dependentSchemas", - "data": { - "type": "object", - "dependentSchemas": { - "credit_card": { - "required": [ "billing_address" ] - } - } - }, - "valid": true - }, - { - "description": "Valid - enum constraint", - "data": { - "enum": [ "red", "green", "blue" ] - }, - "valid": true - }, - { - "description": "Valid - const constraint", - "data": { - "const": "fixed-value" - }, - "valid": true - }, - { - "description": "Valid - allOf composition", - "data": { - "allOf": [ - { - "type": "string" - }, - { - "minLength": 5 - } - ] - }, - "valid": true - }, - { - "description": "Valid - anyOf composition", - "data": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - }, - "valid": true - }, - { - "description": "Valid - oneOf composition", - "data": { - "oneOf": [ - { - "type": "string", - "minLength": 5 - }, - { - "type": "number", - "minimum": 0 - } - ] - }, - "valid": true - }, - { - "description": "Valid - not composition", - "data": { - "not": { - "type": "null" - } - }, - "valid": true - }, - { - "description": "Valid - if-then-else", - "data": { - "if": { - "properties": { - "country": { - "const": "US" - } - } - }, - "then": { - "properties": { - "postal_code": { - "pattern": "[0-9]{5}" - } - } - }, - "else": { - "properties": { - "postal_code": { - "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" - } - } - } - }, - "valid": true - }, - { - "description": "Valid - with $defs", - "data": { - "type": "object", - "$defs": { - "address": { - "type": "object", - "properties": { - "city": { - "type": "string" - }, - "street": { - "type": "string" - } - } - } - } - }, - "valid": true - }, - { - "description": "Valid - with title and description", - "data": { - "title": "Person", - "description": "A person object", - "type": "object" - }, - "valid": true - }, - { - "description": "Valid - with examples", - "data": { - "examples": [ "foo", "bar", "baz" ], - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - with default", - "data": { - "default": "hello", - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - with deprecated", - "data": { - "deprecated": true, - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - with readOnly and writeOnly", - "data": { - "type": "object", - "properties": { - "id": { - "readOnly": true, - "type": "integer" - }, - "password": { - "writeOnly": true, - "type": "string" - } - } - }, - "valid": true - }, - { - "description": "Valid - with $comment", - "data": { - "$comment": "This is a comment about the schema", - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - multiple types", - "data": { - "type": [ "string", "number" ] - }, - "valid": true - }, - { - "description": "Valid - contentMediaType and contentEncoding", - "data": { - "type": "string", - "contentEncoding": "base64", - "contentMediaType": "application/json" - }, - "valid": true - }, - { - "description": "Valid - complex nested schema without meta keywords", - "data": { - "title": "Product", - "description": "A product from the catalog", - "type": "object", - "required": [ "productId", "productName", "price" ], - "properties": { - "price": { - "type": "number", - "exclusiveMinimum": true, - "minimum": 0 - }, - "productId": { - "description": "The unique identifier for a product", - "type": "integer" - }, - "productName": { - "description": "Name of the product", - "type": "string" - }, - "tags": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": "string" - } - } - } - }, - "valid": true - }, - { - "description": "Valid - object with custom keywords", - "data": { - "x-another": 123, - "x-custom": "value", - "type": "string" - }, - "valid": true - }, - { - "description": "Valid - unevaluatedProperties", - "data": { - "type": "object", - "unevaluatedProperties": false - }, - "valid": true - }, - { - "description": "Valid - unevaluatedItems", - "data": { - "type": "array", - "unevaluatedItems": false - }, - "valid": true - }, - { - "description": "Valid - with unknown/custom keywords", - "data": { - "type": "string", - "anotherUnknown": 123, - "customValidation": { - "nested": "object" - }, - "unknownKeyword": "value", - "yetAnother": [ "array", "values" ] - }, - "valid": true - }, - { - "description": "Valid - only unknown keywords", - "data": { - "anotherCustom": "bar", - "customKeyword": "foo", - "nonStandard": true - }, - "valid": true - } - ] -} diff --git a/vendorpull.mask b/vendorpull.mask index 4b06a573..0f004a17 100644 --- a/vendorpull.mask +++ b/vendorpull.mask @@ -15,7 +15,5 @@ templates DATA DEPENDENCIES generated.mk -npm package.json package-lock.json -.npmignore