diff --git a/packages/parser/json-schema-pointer/.eslintignore b/packages/parser/json-schema-pointer/.eslintignore new file mode 100644 index 0000000..e8e7770 --- /dev/null +++ b/packages/parser/json-schema-pointer/.eslintignore @@ -0,0 +1,2 @@ +**/*.js +**/*.mjs diff --git a/packages/parser/json-schema-pointer/.eslintrc.js b/packages/parser/json-schema-pointer/.eslintrc.js new file mode 100644 index 0000000..8f4a2ee --- /dev/null +++ b/packages/parser/json-schema-pointer/.eslintrc.js @@ -0,0 +1,8 @@ +/** @type { import("eslint").ESLint.ConfigData } */ +module.exports = { + extends: '@cuaklabs/eslint-config', + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, +}; diff --git a/packages/parser/json-schema-pointer/.gitignore b/packages/parser/json-schema-pointer/.gitignore new file mode 100644 index 0000000..c33861a --- /dev/null +++ b/packages/parser/json-schema-pointer/.gitignore @@ -0,0 +1,11 @@ +# node modules +/node_modules/ + +# Test coverage report +/coverage + +# Compiled files +/lib/ + +# Turborepo files +.turbo/ diff --git a/packages/parser/json-schema-pointer/.lintstagedrc.json b/packages/parser/json-schema-pointer/.lintstagedrc.json new file mode 100644 index 0000000..0061dfc --- /dev/null +++ b/packages/parser/json-schema-pointer/.lintstagedrc.json @@ -0,0 +1,9 @@ +{ + "*.js": [ + "prettier --write" + ], + "*.ts": [ + "prettier --write", + "eslint" + ] +} diff --git a/packages/parser/json-schema-pointer/CHANGELOG.md b/packages/parser/json-schema-pointer/CHANGELOG.md new file mode 100644 index 0000000..d62dd54 --- /dev/null +++ b/packages/parser/json-schema-pointer/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + + + + + diff --git a/packages/parser/json-schema-pointer/LICENSE b/packages/parser/json-schema-pointer/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/packages/parser/json-schema-pointer/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/packages/parser/json-schema-pointer/jest.config.mjs b/packages/parser/json-schema-pointer/jest.config.mjs new file mode 100644 index 0000000..7de2952 --- /dev/null +++ b/packages/parser/json-schema-pointer/jest.config.mjs @@ -0,0 +1,3 @@ +import { tsGlobalConfig } from '@cuaklabs/jest-config'; + +export default tsGlobalConfig; diff --git a/packages/parser/json-schema-pointer/jest.js.config.mjs b/packages/parser/json-schema-pointer/jest.js.config.mjs new file mode 100644 index 0000000..2496a9d --- /dev/null +++ b/packages/parser/json-schema-pointer/jest.js.config.mjs @@ -0,0 +1,3 @@ +import { jsGlobalConfig } from '@cuaklabs/jest-config'; + +export default jsGlobalConfig; diff --git a/packages/parser/json-schema-pointer/package.json b/packages/parser/json-schema-pointer/package.json new file mode 100644 index 0000000..ad332cc --- /dev/null +++ b/packages/parser/json-schema-pointer/package.json @@ -0,0 +1,53 @@ +{ + "author": "Roberto Pintos López (https://github.com/notaphplover)", + "description": "JSON Schema parser", + "devDependencies": { + "@cuaklabs/json-schema-types": "workspace:*", + "@jest/globals": "29.6.4", + "@types/glob": "8.1.0", + "@types/node": "18.17.14", + "@typescript-eslint/eslint-plugin": "6.6.0", + "@typescript-eslint/parser": "6.6.0", + "eslint": "8.48.0", + "eslint-import-resolver-typescript": "3.6.0", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jest": "27.2.3", + "eslint-plugin-prettier": "5.0.0", + "jest": "29.6.4", + "jest-mock": "29.6.3", + "prettier": "3.0.3", + "rimraf": "5.0.1", + "ts-jest": "29.1.1", + "ts-node": "10.9.1", + "typescript": "5.2.2" + }, + "bugs": { + "url": "https://github.com/cuaklabs/ajstt/issues" + }, + "homepage": "https://github.com/cuaklabs/ajstt#readme", + "license": "See license in \"LICENSE\" file", + "exports": "./lib/index.js", + "main": "lib/index.js", + "name": "@cuaklabs/json-schema-pointer", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/cuaklabs/ajstt.git" + }, + "scripts": { + "build": "tsc --build tsconfig.json", + "build:clean": "rimraf lib", + "format": "prettier --write ./src/**/*.ts", + "lint": "eslint --ext ts --ignore-path .gitignore ./src", + "prebuild": "pnpm run build:clean", + "test:ts": "jest --config=jest.config.mjs --runInBand", + "test:integration": "pnpm run test --selectProjects Integration", + "test": "jest --config=jest.js.config.mjs --runInBand", + "test:coverage": "pnpm run test --coverage", + "test:uncommitted": "pnpm run test:ts --changedSince=HEAD", + "test:unit": "pnpm run test --selectProjects Unit" + }, + "version": "0.1.0" +} diff --git a/packages/parser/json-schema-pointer/prettier.config.mjs b/packages/parser/json-schema-pointer/prettier.config.mjs new file mode 100644 index 0000000..6b34292 --- /dev/null +++ b/packages/parser/json-schema-pointer/prettier.config.mjs @@ -0,0 +1,3 @@ +import config from '@cuaklabs/prettier-config'; + +export default config; diff --git a/packages/parser/json-schema-pointer/src/index.ts b/packages/parser/json-schema-pointer/src/index.ts new file mode 100644 index 0000000..3778cd2 --- /dev/null +++ b/packages/parser/json-schema-pointer/src/index.ts @@ -0,0 +1,3 @@ +import { resolveJsonPointer } from './resolveJsonPointer'; + +export { resolveJsonPointer }; diff --git a/packages/parser/json-schema-pointer/src/resolveJsonPointer.spec.ts b/packages/parser/json-schema-pointer/src/resolveJsonPointer.spec.ts new file mode 100644 index 0000000..9ffbaa4 --- /dev/null +++ b/packages/parser/json-schema-pointer/src/resolveJsonPointer.spec.ts @@ -0,0 +1,232 @@ +import { beforeAll, describe, expect, it } from '@jest/globals'; + +import { JsonValue } from '@cuaklabs/json-schema-types'; + +import { resolveJsonPointer } from './resolveJsonPointer'; + +describe(resolveJsonPointer.name, () => { + describe.each<[string, JsonValue, JsonValue | undefined]>([ + [ + '', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + ], + [ + '/foo', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + ['bar', 'baz'], + ], + [ + '/foo/0', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 'bar', + ], + [ + '/', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 0, + ], + [ + '/a~1b', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 1, + ], + [ + '/c%d', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 2, + ], + [ + '/e^f', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 3, + ], + [ + '/g|h', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 4, + ], + [ + '/i\\j', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 5, + ], + [ + '/k"l', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 6, + ], + [ + '/ ', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 7, + ], + [ + '/m~0n', + { + '': 0, + ' ': 7, + 'a/b': 1, + 'c%d': 2, + 'e^f': 3, + foo: ['bar', 'baz'], + 'g|h': 4, + 'i\\j': 5, + 'k"l': 6, + 'm~n': 8, + }, + 8, + ], + ])( + 'having a "%s" pointer', + ( + pointer: string, + json: JsonValue, + expectedResult: JsonValue | undefined, + ) => { + describe('when called', () => { + let result: unknown; + + beforeAll(() => { + result = resolveJsonPointer(json, pointer); + }); + + it('should return the expected result', () => { + expect(result).toStrictEqual(expectedResult); + }); + }); + }, + ); +}); diff --git a/packages/parser/json-schema-pointer/src/resolveJsonPointer.ts b/packages/parser/json-schema-pointer/src/resolveJsonPointer.ts new file mode 100644 index 0000000..85c1d24 --- /dev/null +++ b/packages/parser/json-schema-pointer/src/resolveJsonPointer.ts @@ -0,0 +1,49 @@ +import { JsonValue } from '@cuaklabs/json-schema-types'; + +const SEPARATOR: string = '/'; +const SEPARATOR_ENCODED: string = '~1'; +const ENCODER: string = '~'; +const ENCODER_ENCODED: string = '~0'; + +export function resolveJsonPointer( + json: JsonValue, + pointer: string, +): JsonValue | undefined { + const pointerSegments: string[] = pointer + .split(SEPARATOR) + .map((segment: string) => + segment + .replaceAll(SEPARATOR_ENCODED, SEPARATOR) + .replaceAll(ENCODER_ENCODED, ENCODER), + ); + + if (pointerSegments[0] === undefined || pointerSegments[0] !== '') { + throw new Error('Invalid JSON pointer!'); + } + + let result: JsonValue | undefined = json; + + for (let i: number = 1; i < pointerSegments.length; ++i) { + const pointerSegment: string = pointerSegments[i] as string; + + if (result == null || typeof result !== 'object') { + result = undefined; + break; + } + + if (Array.isArray(result)) { + const pointerIndex: number = parseInt(pointerSegment); + + if (Number.isNaN(pointerIndex)) { + result = undefined; + break; + } + + result = result[pointerIndex]; + } else { + result = result[pointerSegment]; + } + } + + return result; +} diff --git a/packages/parser/json-schema-pointer/tsconfig.json b/packages/parser/json-schema-pointer/tsconfig.json new file mode 100644 index 0000000..4c1edb9 --- /dev/null +++ b/packages/parser/json-schema-pointer/tsconfig.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "@cuaklabs/typescript-config/tsconfig.base.node.cjs.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src" + }, + "include": ["src"] +} diff --git a/packages/transformers/ajsttil/src/index.ts b/packages/transformers/ajsttil/src/index.ts index aa5fda1..f5db5e0 100644 --- a/packages/transformers/ajsttil/src/index.ts +++ b/packages/transformers/ajsttil/src/index.ts @@ -5,11 +5,10 @@ export enum TypeMetadataKind { anyType, arrayType, booleanType, + floatType, integerType, literalType, noneType, - nullType, - numberType, or, propertyType, stringType, @@ -39,6 +38,7 @@ export type ArrayTypeMetadata = OneChildTypeMetadata; export type BooleanTypeMetadata = BaseTypeMetadata; +export type FloatTypeMetadata = BaseTypeMetadata; export type IntegerTypeMetadata = BaseTypeMetadata; export interface LiteralTypeMetadata @@ -46,8 +46,6 @@ export interface LiteralTypeMetadata literal: JsonValue; } export type NoneTypeMetadata = BaseTypeMetadata; -export type NullTypeMetadata = BaseTypeMetadata; -export type NumberTypeMetadata = BaseTypeMetadata; export type OrTypeMetadata = ManyChildrenTypeMetadata; export interface PropertyTypeMetadata extends OneChildTypeMetadata { @@ -61,11 +59,10 @@ export type TypeMedatata = | AnyTypeMetadata | ArrayTypeMetadata | BooleanTypeMetadata + | FloatTypeMetadata | IntegerTypeMetadata | LiteralTypeMetadata | NoneTypeMetadata - | NullTypeMetadata - | NumberTypeMetadata | OrTypeMetadata | PropertyTypeMetadata | StringTypeMetadata