ajsc 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # ajsc - Another JSON Schema Parser
2
+
3
+ **ajsc** is an npm package that transforms JSON Schema definitions into an intermediate representation (IR) called `IRNode`. This intermediate form is designed to be consumed by language-specific converters—such as the built-in [TypeScript converter](#typescriptconverter)—or by any custom converter you create for languages like Kotlin or Swift. This library streamlines the process of converting API JSON Schema definitions into strong-typed code representations, ensuring consistency between your API contracts and client implementations.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **Comprehensive Schema Parsing:**
10
+ Convert JSON Schema types including strings, numbers, booleans, nulls, literals, enums, unions, intersections, arrays, and objects into a unified IR.
11
+
12
+ - **Intermediate Representation (`IRNode`):**
13
+ The `IRNode` provides a standard structure that captures type, constraints, and path information. This representation is ideal for further transformation into various target languages.
14
+
15
+ - **Plugin-Based Architecture:**
16
+ Use the provided language plugin (currently, a [TypeScript converter](#typescriptconverter)) or write your own converter to support additional languages such as Kotlin or Swift.
17
+
18
+ - **$defs and References Handling:**
19
+ Resolve JSON Schema definitions (`$defs`) and references (`$ref`) seamlessly, ensuring reusable schema components are properly processed.
20
+
21
+ - **Unique Signature Tracking:**
22
+ For objects and arrays, the library tracks unique signatures to avoid duplicate type definitions when converting to code.
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ Install **ajsc** via npm:
29
+
30
+ ```bash
31
+ npm install ajsc
32
+ ```
33
+
34
+ ## Usage
35
+ ### Basic Conversion to IRNode
36
+ The primary function of ajsc is to convert a JSON Schema into an IRNode. Here’s an example of converting a simple JSON Schema that defines a string type:
37
+
38
+ ```javascript
39
+ import { JSONSchemaConverter } from "ajsc";
40
+
41
+ const schema = { type: "string" };
42
+ const converter = new JSONSchemaConverter(schema);
43
+
44
+ console.log(converter.irNode);
45
+ // Output:
46
+ // {
47
+ // type: "string",
48
+ // constraints: {},
49
+ // path: "",
50
+ // }
51
+ Converting Complex Schemas
52
+ You can also convert more complex schemas including objects, arrays, unions, intersections, and even schemas with $defs:
53
+
54
+ javascript
55
+ Copy
56
+ import { JSONSchemaConverter } from "ajsc";
57
+
58
+ const complexSchema = {
59
+ $defs: {
60
+ Person: {
61
+ type: "object",
62
+ properties: {
63
+ name: { type: "string" },
64
+ age: { type: "number" },
65
+ },
66
+ required: ["name"],
67
+ },
68
+ },
69
+ type: "object",
70
+ properties: {
71
+ person: { $ref: "#/$defs/Person" },
72
+ },
73
+ };
74
+
75
+ const converter = new JSONSchemaConverter(complexSchema);
76
+ console.log(converter.irNode);
77
+ ```
78
+
79
+ ## API Reference
80
+ ### JSONSchemaConverter
81
+ - Constructor:
82
+ `new JSONSchemaConverter(schema: object)`
83
+ - Properties:
84
+ - irNode: The resulting intermediate representation of the JSON Schema.
85
+ - Supported Schema Types:
86
+ - Primitive Types: string, number, boolean, null
87
+ - Literals: Using the const keyword.
88
+ - Enums: Using the enum property.
89
+ - Unions: When type is an array (e.g., ["string", "number"]).
90
+ - Intersections: Using allOf to combine multiple schemas.
91
+ - Arrays: With type: "array" and an items schema.
92
+ - Objects: With type: "object" and a properties definition.
93
+ - $defs and $ref: For defining and referencing reusable schema parts.
94
+
95
+ ### TypescriptConverter
96
+
97
+ The package includes a TypeScript language plugin that converts the IRNode into TypeScript type definitions.
98
+
99
+ - Constructor:
100
+ `new TypescriptConverter(schema: object, options?: { inlineTypes?: boolean })`
101
+ - Properties:
102
+ - code: A string containing the generated TypeScript code.
103
+
104
+ Usage Example:
105
+
106
+ ```javascript
107
+ import { TypescriptConverter } from "ajsc";
108
+
109
+ const schema = {
110
+ type: "object",
111
+ properties: {
112
+ name: { type: "string" },
113
+ age: { type: "number" },
114
+ contacts: {
115
+ type: "array",
116
+ items: {
117
+ type: "object",
118
+ properties: {
119
+ email: { type: "string" },
120
+ },
121
+ required: ["email"],
122
+ },
123
+ },
124
+ profile: {
125
+ type: "object",
126
+ properties: {
127
+ email: { type: "string" },
128
+ },
129
+ required: ["email"],
130
+ },
131
+ },
132
+ required: ["name", "age"],
133
+ };
134
+
135
+ const tsConverter = new TypescriptConverter(schema, { inlineTypes: true });
136
+ console.log(tsConverter.code);
137
+
138
+ // Expected output (formatted):
139
+ // {
140
+ // name: string;
141
+ // age: number;
142
+ // contacts?: Array<{ email: string; }>;
143
+ // profile?: { email: string; };
144
+ // }
145
+ ```
@@ -0,0 +1,65 @@
1
+ import { JSONSchema7Definition } from "json-schema";
2
+ import { ConverterOptions, IRNode, SignatureOccurrences } from "./types.js";
3
+ /**
4
+ * JSONSchemaConverter converts a JSON Schema (Draft‑07) into an
5
+ * intermediate representation (IR) that can later be transformed
6
+ * into target language code via a language plugin.
7
+ *
8
+ * This implementation now supports internal definitions via both
9
+ * "$defs" and "definitions", and resolves local "$ref" pointers.
10
+ */
11
+ export declare class JSONSchemaConverter {
12
+ private opts?;
13
+ private ir;
14
+ private rootSchema;
15
+ private signatureOccurrences;
16
+ get irNode(): IRNode;
17
+ get signatureOccurrencesMap(): SignatureOccurrences;
18
+ constructor(schema: JSONSchema7Definition, opts?: ConverterOptions | undefined);
19
+ private calcObjSignatureOccurrences;
20
+ /**
21
+ * Recursively converts a JSON Schema definition into an IRNode.
22
+ *
23
+ * This method now handles $ref resolution (using the root schema),
24
+ * combinators (oneOf, anyOf, allOf), as well as enums, const, objects,
25
+ * arrays, and primitives.
26
+ */
27
+ private convertSchema;
28
+ /**
29
+ * Converts a JSON Schema definition to target code using the provided language plugin.
30
+ */
31
+ convertToIRSchema(schema: JSONSchema7Definition): IRNode;
32
+ private validateSchema;
33
+ /**
34
+ * A placeholder for reference resolution. In a more advanced implementation,
35
+ * this method might inline external references or perform more complex processing.
36
+ * ie: fetching a remote/url $def
37
+ */
38
+ private resolveReferences;
39
+ private convertToIR;
40
+ private getNameFromPath;
41
+ private getNextObjectSequence;
42
+ private getParentNameFromPath;
43
+ /**
44
+ * Generates a unique signature for a schema.
45
+ * Uses a stable JSON.stringify that sorts keys to ensure that
46
+ * semantically equivalent schemas produce the same string.
47
+ */
48
+ private getSchemaSignature;
49
+ private getTypeName;
50
+ /**
51
+ * Resolves a local $ref using the stored root schema.
52
+ *
53
+ * This method expects local references (starting with "#/") and uses a simple
54
+ * JSON Pointer resolution algorithm.
55
+ */
56
+ private resolveRef;
57
+ /**
58
+ * Resolves a JSON Pointer (RFC 6901) within the given document.
59
+ *
60
+ * @param pointer A JSON Pointer string (e.g., "#/definitions/Foo" or "#/$defs/Bar")
61
+ * @param document The root document object.
62
+ */
63
+ private resolvePointer;
64
+ private simpleHash;
65
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,56 @@
1
+ import { IRNode, SignatureOccurrenceValue } from "./types.js";
2
+ export type RefTypeName = string;
3
+ export type RefTypes = [
4
+ SignatureOccurrenceValue["signature"],
5
+ RefTypeName,
6
+ {
7
+ code: string;
8
+ }
9
+ ][];
10
+ export declare class TypescriptBaseConverter {
11
+ /**
12
+ * Recursively generates a TypeScript type string for the given IR node.
13
+ *
14
+ * @param ir - The IR node to convert.
15
+ * @returns A string representing the TypeScript type.
16
+ */
17
+ protected generateType(ir: IRNode, utils: {
18
+ getReferencedType(ir: IRNode): string | undefined;
19
+ }): string;
20
+ /**
21
+ * Generates a TypeScript object type (as an inline type literal) from the given IR node.
22
+ *
23
+ * @param ir - The IR node of type "object".
24
+ * @returns A string representing the object type.
25
+ */
26
+ protected generateObjectType(ir: IRNode, utils: {
27
+ getReferencedType(ir: IRNode): string | undefined;
28
+ }): string;
29
+ protected isValidIdentifier(name: string): boolean;
30
+ /**
31
+ * Parses a list of dot-separated paths into an array of string arrays.
32
+ * Removes any "0" character segments.
33
+ *
34
+ * @param list
35
+ * @protected
36
+ */
37
+ protected parsePaths(list: string[]): string[][];
38
+ /**
39
+ * Returns the longest common prefix (sequence) among an array of string arrays.
40
+ * @param paths - An array of string arrays.
41
+ * @returns An array representing the common sequence.
42
+ *
43
+ * @example
44
+ * const arrays = [
45
+ * ["organizations", "migration", "step", "create_regions"],
46
+ * ["organizations", "migration", "step", "create_location_groups"],
47
+ * ["organizations", "migration", "step", "create_locations"],
48
+ * ["organizations", "migration", "step", "create_locations_bolos"],
49
+ * ];
50
+ *
51
+ * console.log(commonSequence(arrays)); // Output: ["organizations", "migration", "step"]
52
+ *
53
+ */
54
+ protected commonSequence(paths: string[][]): string[];
55
+ protected makeTypeReferenceName(signatureOccurrences: SignatureOccurrenceValue["occurrences"]): string;
56
+ }
@@ -0,0 +1,21 @@
1
+ import { IRNode, LanguagePlugin } from "./types.js";
2
+ import { TypescriptBaseConverter } from "./TypescriptBaseConverter.js";
3
+ import { JSONSchema7Definition } from "json-schema";
4
+ /**
5
+ * A TypeScript language converter plugin.
6
+ */
7
+ export declare class TypescriptConverter extends TypescriptBaseConverter implements LanguagePlugin {
8
+ readonly language = "typescript";
9
+ private ir;
10
+ private refTypes;
11
+ readonly code: string;
12
+ constructor(schema: JSONSchema7Definition, opts?: {
13
+ /**
14
+ * If true, referenced types will not be created for objects and instead
15
+ * the object type will be inlined.
16
+ */
17
+ inlineTypes?: boolean;
18
+ });
19
+ private getUniqueRefTypeName;
20
+ protected getReferencedType(ir: IRNode): string | undefined;
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { IRNode } from "./types.js";
2
+ import { JSONSchema7Definition } from "json-schema";
3
+ import { TypescriptBaseConverter } from "./TypescriptBaseConverter.js";
4
+ /**
5
+ * A TypeScript language converter plugin that implements namespace scoping.
6
+ *
7
+ * Referenced/Shared typings are moved to the top level of the namespace scope
8
+ * that is created for each IR node.
9
+ */
10
+ export declare class TypescriptProcedureConverter extends TypescriptBaseConverter {
11
+ private ir;
12
+ private refTypes;
13
+ readonly code: string;
14
+ constructor(scopeName: string, rpcJsonSchemas: {
15
+ args: JSONSchema7Definition;
16
+ data: JSONSchema7Definition;
17
+ });
18
+ private getUniqueRefTypeName;
19
+ protected getReferencedType(ir: IRNode): string | undefined;
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ export * from './JSONSchemaConverter.js';
2
+ export * from './TypescriptBaseConverter.js';
3
+ export * from './TypescriptConverter.js';
4
+ export * from './TypescriptProcedureConverter.js';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './JSONSchemaConverter.js';
2
+ export * from './TypescriptBaseConverter.js';
3
+ export * from './TypescriptConverter.js';
4
+ export * from './TypescriptProcedureConverter.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,0BAA0B,CAAC;AACzC,cAAc,mCAAmC,CAAC"}
@@ -0,0 +1,77 @@
1
+ export type IRType = "string" | "number" | "integer" | "boolean" | "object" | "array" | "null" | "enum" | "union" | "intersection" | "literal";
2
+ export interface IRNode {
3
+ signature?: string;
4
+ /**
5
+ * The base type of the IR node.
6
+ */
7
+ type: IRType;
8
+ /**
9
+ * Optional name for the node (useful for objects, enums, etc.).
10
+ */
11
+ name?: string;
12
+ /**
13
+ * Dot notation path to the node in a runtime object.
14
+ * For example, "user.profile.name".
15
+ */
16
+ path: string;
17
+ /**
18
+ * Indicates whether this property/node is required.
19
+ * For object properties, this can be derived from the JSON Schema 'required' array.
20
+ */
21
+ required?: boolean;
22
+ /**
23
+ * For object types: a mapping of property names to their IR node definitions.
24
+ */
25
+ properties?: {
26
+ [key: string]: IRNode;
27
+ };
28
+ /**
29
+ * For array types: the IR node representing the type of items in the array.
30
+ */
31
+ items?: IRNode;
32
+ /**
33
+ * For enum types: a list of allowed literal values.
34
+ */
35
+ values?: any[];
36
+ /**
37
+ * For union or intersection types: an array of candidate IR nodes.
38
+ * Note: This is used regardless of whether the union originated from a 'oneOf' or an 'anyOf'.
39
+ */
40
+ options?: IRNode[];
41
+ /**
42
+ * Additional constraints such as minimum, maximum, pattern, etc.
43
+ */
44
+ constraints?: {
45
+ [key: string]: any;
46
+ combinator?: "oneOf" | "anyOf";
47
+ maxLength?: number;
48
+ minLength?: number;
49
+ pattern?: string;
50
+ maximum?: number;
51
+ minimum?: number;
52
+ value?: any;
53
+ };
54
+ }
55
+ export type SignatureOccurrenceValue = {
56
+ occurrences: {
57
+ node: IRNode;
58
+ nodePath: string;
59
+ count: number;
60
+ }[];
61
+ signature: string;
62
+ total: number;
63
+ };
64
+ export type SignatureOccurrences = Map<string, SignatureOccurrenceValue>;
65
+ export interface Context {
66
+ signatureOccurrences: SignatureOccurrences;
67
+ }
68
+ export interface LanguagePlugin {
69
+ /**
70
+ * The name of the language this plugin converts to (e.g., "typescript", "java", "python").
71
+ */
72
+ language: string;
73
+ }
74
+ export interface ConverterOptions {
75
+ validateSchema?: boolean;
76
+ transform?: (ir: IRNode) => IRNode;
77
+ }
@@ -0,0 +1,26 @@
1
+ export declare const PathUtils: {
2
+ /**
3
+ * Parses a list of dot-separated paths into an array of string arrays.
4
+ * Removes any "0" character segments.
5
+ *
6
+ * @param list
7
+ * @protected
8
+ */
9
+ parsePaths: (list: string[]) => string[][];
10
+ parsePath: (path: string) => string[];
11
+ /**
12
+ * Returns the last `count` common elements (shared path) among all given path arrays,
13
+ * comparing from the end (i.e. common suffix).
14
+ *
15
+ * @param paths - An array of string arrays (paths) to compare.
16
+ * @param count - The number of common elements (starting from the end) to return.
17
+ * @returns An array containing the shared path elements in original order.
18
+ */
19
+ commonSequenceReversed: (paths: string[][], count?: number) => string[];
20
+ /**
21
+ * Returns the longest common prefix (sequence) among an array of string arrays.
22
+ * @param paths - An array of string arrays.
23
+ * @returns An array representing the common sequence.
24
+ */
25
+ commonSequence: (paths: string[][]) => string[];
26
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Converts a string to PascalCase.
3
+ * Splits on whitespace, hyphens, or underscores.
4
+ */
5
+ export declare function toPascalCase(str: string): string;
package/package.json CHANGED
@@ -1,26 +1,15 @@
1
1
  {
2
2
  "name": "ajsc",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Another Json-Schema Converter",
5
5
  "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
6
9
  "scripts": {
7
10
  "build": "tsc",
8
11
  "test": "vitest --run"
9
12
  },
10
- "exports": {
11
- "./JSONSchemaConverter": {
12
- "types": "./dist/JSONSchemaConverter.d.ts",
13
- "default": "./dist/JSONSchemaConverter.js"
14
- },
15
- "./TypescriptConverter": {
16
- "types": "./dist/TypescriptConverter.d.ts",
17
- "default": "./dist/TypescriptConverter.js"
18
- },
19
- "./TypescriptProcedureConverter": {
20
- "types": "./dist/TypescriptProcedureConverter.d.ts",
21
- "default": "./dist/TypescriptProcedureConverter.js"
22
- }
23
- },
24
13
  "keywords": [
25
14
  "json-schema",
26
15
  "converter",
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './JSONSchemaConverter.js';
2
+ export * from './TypescriptBaseConverter.js';
3
+ export * from './TypescriptConverter.js';
4
+ export * from './TypescriptProcedureConverter.js';