@twin.org/ts-to-schema 0.0.1-next.25 → 0.0.1-next.27

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.
@@ -10,6 +10,7 @@ var tsJsonSchemaGenerator = require('ts-json-schema-generator');
10
10
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
11
  // Copyright 2024 IOTA Stiftung.
12
12
  // SPDX-License-Identifier: Apache-2.0.
13
+ const SCHEMA_VERSION = "https://json-schema.org/draft/2020-12/schema";
13
14
  /**
14
15
  * Build the root command to be consumed by the CLI.
15
16
  * @param program The command to build on.
@@ -81,10 +82,10 @@ async function tsToSchema(config, outputFolder, workingDirectory) {
81
82
  for (const typeSource of config.types) {
82
83
  const typeSourceParts = typeSource.split("/");
83
84
  const type = core.StringHelper.pascalCase(typeSourceParts[typeSourceParts.length - 1].replace(/(\.d)?\.ts$/, ""), false);
84
- let content;
85
+ let schemaObject;
85
86
  if (core.Is.object(config.overrides?.[type])) {
86
87
  cliCore.CLIDisplay.task(core.I18n.formatMessage("commands.ts-to-schema.progress.overridingSchema"));
87
- content = JSON.stringify(config.overrides?.[type], undefined, "\t");
88
+ schemaObject = config.overrides?.[type];
88
89
  }
89
90
  else {
90
91
  cliCore.CLIDisplay.task(core.I18n.formatMessage("commands.ts-to-schema.progress.generatingSchema"));
@@ -92,17 +93,19 @@ async function tsToSchema(config, outputFolder, workingDirectory) {
92
93
  if (core.Is.empty(schemas[type])) {
93
94
  throw new core.GeneralError("commands", "commands.ts-to-schema.schemaNotFound", { type });
94
95
  }
95
- content = JSON.stringify(schemas[type], undefined, "\t");
96
- if (core.Is.objectValue(config.externalReferences)) {
97
- for (const external in config.externalReferences) {
98
- content = content.replace(new RegExp(`#/definitions/${external}`, "g"), config.externalReferences[external]);
99
- }
96
+ schemaObject = schemas[type];
97
+ }
98
+ schemaObject = finaliseSchema(schemaObject, config.baseUrl, type);
99
+ let content = JSON.stringify(schemaObject, undefined, "\t");
100
+ if (core.Is.objectValue(config.externalReferences)) {
101
+ for (const external in config.externalReferences) {
102
+ content = content.replace(new RegExp(`#/definitions/${external}`, "g"), config.externalReferences[external]);
100
103
  }
101
- // First replace all types that start with II to a single I with the new base url
102
- content = content.replace(/#\/definitions\/II(.*)/g, `${config.baseUrl}I$1`);
103
- // Then other types starting with capitals (optionally interfaces starting with I)
104
- content = content.replace(/#\/definitions\/I?([A-Z].*)/g, `${config.baseUrl}$1`);
105
104
  }
105
+ // First replace all types that start with II to a single I with the new base url
106
+ content = content.replace(/#\/definitions\/II(.*)/g, `${config.baseUrl}I$1`);
107
+ // Then other types starting with capitals (optionally interfaces starting with I)
108
+ content = content.replace(/#\/definitions\/I?([A-Z].*)/g, `${config.baseUrl}$1`);
106
109
  const filename = path.join(outputFolder, `${core.StringHelper.stripPrefix(type)}.json`);
107
110
  cliCore.CLIDisplay.value(core.I18n.formatMessage("commands.ts-to-schema.progress.writingSchema"), filename, 1);
108
111
  await promises.writeFile(filename, `${content}\n`);
@@ -208,6 +211,76 @@ function extractTypesFromSchema(allTypes, schema, output) {
208
211
  extractTypes(allTypes, additionalTypes, output);
209
212
  }
210
213
  }
214
+ /**
215
+ * Process the schema object to ensure it has the correct properties.
216
+ * @param schemaObject The schema object to process.
217
+ * @param baseUrl The base URL for the schema references.
218
+ * @param type The type of the schema object.
219
+ * @returns The finalised schema object.
220
+ */
221
+ function finaliseSchema(schemaObject, baseUrl, type) {
222
+ processArrays(schemaObject);
223
+ const { description, ...rest } = schemaObject;
224
+ return {
225
+ $schema: SCHEMA_VERSION,
226
+ $id: `${baseUrl}${core.StringHelper.stripPrefix(type)}`,
227
+ description,
228
+ ...rest
229
+ };
230
+ }
231
+ /**
232
+ * Process arrays in the schema object.
233
+ * @param schemaObject The schema object to process.
234
+ */
235
+ function processArrays(schemaObject) {
236
+ if (core.Is.object(schemaObject)) {
237
+ // latest specs have singular items in `items` property
238
+ // and multiple items in prefixItems, so update the schema accordingly
239
+ // https://www.learnjsonschema.com/2020-12/applicator/items/
240
+ // https://www.learnjsonschema.com/2020-12/applicator/prefixitems/
241
+ const schemaItems = schemaObject.items;
242
+ if (core.Is.array(schemaItems) || core.Is.object(schemaItems)) {
243
+ schemaObject.prefixItems = core.ArrayHelper.fromObjectOrArray(schemaItems);
244
+ schemaObject.items = false;
245
+ }
246
+ const additionalItems = schemaObject.additionalItems;
247
+ if (core.Is.array(additionalItems) || core.Is.object(additionalItems)) {
248
+ schemaObject.items = core.ArrayHelper.fromObjectOrArray(additionalItems)[0];
249
+ delete schemaObject.additionalItems;
250
+ }
251
+ processSchemaDictionary(schemaObject.properties);
252
+ processArrays(schemaObject.additionalProperties);
253
+ processSchemaArray(schemaObject.allOf);
254
+ processSchemaArray(schemaObject.anyOf);
255
+ processSchemaArray(schemaObject.oneOf);
256
+ }
257
+ }
258
+ /**
259
+ * Process arrays in the schema object.
260
+ * @param schemaDictionary The schema object to process.
261
+ */
262
+ function processSchemaDictionary(schemaDictionary) {
263
+ if (core.Is.object(schemaDictionary)) {
264
+ for (const item of Object.values(schemaDictionary)) {
265
+ if (core.Is.object(item)) {
266
+ processArrays(item);
267
+ }
268
+ }
269
+ }
270
+ }
271
+ /**
272
+ * Process arrays in the schema object.
273
+ * @param schemaArray The schema object to process.
274
+ */
275
+ function processSchemaArray(schemaArray) {
276
+ if (core.Is.arrayValue(schemaArray)) {
277
+ for (const item of schemaArray) {
278
+ if (core.Is.object(item)) {
279
+ processArrays(item);
280
+ }
281
+ }
282
+ }
283
+ }
211
284
 
212
285
  // Copyright 2024 IOTA Stiftung.
213
286
  // SPDX-License-Identifier: Apache-2.0.
@@ -227,7 +300,7 @@ class CLI extends cliCore.CLIBase {
227
300
  return this.execute({
228
301
  title: "TWIN TypeScript To Schema",
229
302
  appName: "ts-to-schema",
230
- version: "0.0.1-next.25", // x-release-please-version
303
+ version: "0.0.1-next.27", // x-release-please-version
231
304
  icon: "⚙️ ",
232
305
  supportsEnvFiles: false,
233
306
  overrideOutputWidth: options?.overrideOutputWidth
@@ -2,11 +2,12 @@ import path from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import { CLIDisplay, CLIUtils, CLIBase } from '@twin.org/cli-core';
4
4
  import { mkdir, rm, writeFile } from 'node:fs/promises';
5
- import { I18n, GeneralError, Is, StringHelper } from '@twin.org/core';
5
+ import { I18n, GeneralError, Is, StringHelper, ArrayHelper } from '@twin.org/core';
6
6
  import { createGenerator } from 'ts-json-schema-generator';
7
7
 
8
8
  // Copyright 2024 IOTA Stiftung.
9
9
  // SPDX-License-Identifier: Apache-2.0.
10
+ const SCHEMA_VERSION = "https://json-schema.org/draft/2020-12/schema";
10
11
  /**
11
12
  * Build the root command to be consumed by the CLI.
12
13
  * @param program The command to build on.
@@ -78,10 +79,10 @@ async function tsToSchema(config, outputFolder, workingDirectory) {
78
79
  for (const typeSource of config.types) {
79
80
  const typeSourceParts = typeSource.split("/");
80
81
  const type = StringHelper.pascalCase(typeSourceParts[typeSourceParts.length - 1].replace(/(\.d)?\.ts$/, ""), false);
81
- let content;
82
+ let schemaObject;
82
83
  if (Is.object(config.overrides?.[type])) {
83
84
  CLIDisplay.task(I18n.formatMessage("commands.ts-to-schema.progress.overridingSchema"));
84
- content = JSON.stringify(config.overrides?.[type], undefined, "\t");
85
+ schemaObject = config.overrides?.[type];
85
86
  }
86
87
  else {
87
88
  CLIDisplay.task(I18n.formatMessage("commands.ts-to-schema.progress.generatingSchema"));
@@ -89,17 +90,19 @@ async function tsToSchema(config, outputFolder, workingDirectory) {
89
90
  if (Is.empty(schemas[type])) {
90
91
  throw new GeneralError("commands", "commands.ts-to-schema.schemaNotFound", { type });
91
92
  }
92
- content = JSON.stringify(schemas[type], undefined, "\t");
93
- if (Is.objectValue(config.externalReferences)) {
94
- for (const external in config.externalReferences) {
95
- content = content.replace(new RegExp(`#/definitions/${external}`, "g"), config.externalReferences[external]);
96
- }
93
+ schemaObject = schemas[type];
94
+ }
95
+ schemaObject = finaliseSchema(schemaObject, config.baseUrl, type);
96
+ let content = JSON.stringify(schemaObject, undefined, "\t");
97
+ if (Is.objectValue(config.externalReferences)) {
98
+ for (const external in config.externalReferences) {
99
+ content = content.replace(new RegExp(`#/definitions/${external}`, "g"), config.externalReferences[external]);
97
100
  }
98
- // First replace all types that start with II to a single I with the new base url
99
- content = content.replace(/#\/definitions\/II(.*)/g, `${config.baseUrl}I$1`);
100
- // Then other types starting with capitals (optionally interfaces starting with I)
101
- content = content.replace(/#\/definitions\/I?([A-Z].*)/g, `${config.baseUrl}$1`);
102
101
  }
102
+ // First replace all types that start with II to a single I with the new base url
103
+ content = content.replace(/#\/definitions\/II(.*)/g, `${config.baseUrl}I$1`);
104
+ // Then other types starting with capitals (optionally interfaces starting with I)
105
+ content = content.replace(/#\/definitions\/I?([A-Z].*)/g, `${config.baseUrl}$1`);
103
106
  const filename = path.join(outputFolder, `${StringHelper.stripPrefix(type)}.json`);
104
107
  CLIDisplay.value(I18n.formatMessage("commands.ts-to-schema.progress.writingSchema"), filename, 1);
105
108
  await writeFile(filename, `${content}\n`);
@@ -205,6 +208,76 @@ function extractTypesFromSchema(allTypes, schema, output) {
205
208
  extractTypes(allTypes, additionalTypes, output);
206
209
  }
207
210
  }
211
+ /**
212
+ * Process the schema object to ensure it has the correct properties.
213
+ * @param schemaObject The schema object to process.
214
+ * @param baseUrl The base URL for the schema references.
215
+ * @param type The type of the schema object.
216
+ * @returns The finalised schema object.
217
+ */
218
+ function finaliseSchema(schemaObject, baseUrl, type) {
219
+ processArrays(schemaObject);
220
+ const { description, ...rest } = schemaObject;
221
+ return {
222
+ $schema: SCHEMA_VERSION,
223
+ $id: `${baseUrl}${StringHelper.stripPrefix(type)}`,
224
+ description,
225
+ ...rest
226
+ };
227
+ }
228
+ /**
229
+ * Process arrays in the schema object.
230
+ * @param schemaObject The schema object to process.
231
+ */
232
+ function processArrays(schemaObject) {
233
+ if (Is.object(schemaObject)) {
234
+ // latest specs have singular items in `items` property
235
+ // and multiple items in prefixItems, so update the schema accordingly
236
+ // https://www.learnjsonschema.com/2020-12/applicator/items/
237
+ // https://www.learnjsonschema.com/2020-12/applicator/prefixitems/
238
+ const schemaItems = schemaObject.items;
239
+ if (Is.array(schemaItems) || Is.object(schemaItems)) {
240
+ schemaObject.prefixItems = ArrayHelper.fromObjectOrArray(schemaItems);
241
+ schemaObject.items = false;
242
+ }
243
+ const additionalItems = schemaObject.additionalItems;
244
+ if (Is.array(additionalItems) || Is.object(additionalItems)) {
245
+ schemaObject.items = ArrayHelper.fromObjectOrArray(additionalItems)[0];
246
+ delete schemaObject.additionalItems;
247
+ }
248
+ processSchemaDictionary(schemaObject.properties);
249
+ processArrays(schemaObject.additionalProperties);
250
+ processSchemaArray(schemaObject.allOf);
251
+ processSchemaArray(schemaObject.anyOf);
252
+ processSchemaArray(schemaObject.oneOf);
253
+ }
254
+ }
255
+ /**
256
+ * Process arrays in the schema object.
257
+ * @param schemaDictionary The schema object to process.
258
+ */
259
+ function processSchemaDictionary(schemaDictionary) {
260
+ if (Is.object(schemaDictionary)) {
261
+ for (const item of Object.values(schemaDictionary)) {
262
+ if (Is.object(item)) {
263
+ processArrays(item);
264
+ }
265
+ }
266
+ }
267
+ }
268
+ /**
269
+ * Process arrays in the schema object.
270
+ * @param schemaArray The schema object to process.
271
+ */
272
+ function processSchemaArray(schemaArray) {
273
+ if (Is.arrayValue(schemaArray)) {
274
+ for (const item of schemaArray) {
275
+ if (Is.object(item)) {
276
+ processArrays(item);
277
+ }
278
+ }
279
+ }
280
+ }
208
281
 
209
282
  // Copyright 2024 IOTA Stiftung.
210
283
  // SPDX-License-Identifier: Apache-2.0.
@@ -224,7 +297,7 @@ class CLI extends CLIBase {
224
297
  return this.execute({
225
298
  title: "TWIN TypeScript To Schema",
226
299
  appName: "ts-to-schema",
227
- version: "0.0.1-next.25", // x-release-please-version
300
+ version: "0.0.1-next.27", // x-release-please-version
228
301
  icon: "⚙️ ",
229
302
  supportsEnvFiles: false,
230
303
  overrideOutputWidth: options?.overrideOutputWidth
@@ -1,5 +1,5 @@
1
- import type { JsonSchemaDraft202012Object } from "@hyperjump/json-schema/draft-2020-12";
1
+ import type { AnySchemaObject } from "ajv/dist/2020.js";
2
2
  /**
3
3
  * Default schema type.
4
4
  */
5
- export type IJsonSchema = JsonSchemaDraft202012Object;
5
+ export type IJsonSchema = AnySchemaObject;
package/docs/changelog.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @twin.org/ts-to-schema - Changelog
2
2
 
3
+ ## [0.0.1-next.27](https://github.com/twinfoundation/tools/compare/ts-to-schema-v0.0.1-next.26...ts-to-schema-v0.0.1-next.27) (2025-06-17)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **ts-to-schema:** Synchronize repo versions
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/nameof bumped from 0.0.1-next.26 to 0.0.1-next.27
16
+ * devDependencies
17
+ * @twin.org/merge-locales bumped from 0.0.1-next.26 to 0.0.1-next.27
18
+ * @twin.org/nameof-transformer bumped from 0.0.1-next.26 to 0.0.1-next.27
19
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.1-next.26 to 0.0.1-next.27
20
+
21
+ ## [0.0.1-next.26](https://github.com/twinfoundation/tools/compare/ts-to-schema-v0.0.1-next.25...ts-to-schema-v0.0.1-next.26) (2025-06-11)
22
+
23
+
24
+ ### Features
25
+
26
+ * use most recent JSON schema specs ([4598cbf](https://github.com/twinfoundation/tools/commit/4598cbf29f7b82dba4a9f3b19f81dfe66f5a6060))
27
+
28
+
29
+ ### Dependencies
30
+
31
+ * The following workspace dependencies were updated
32
+ * dependencies
33
+ * @twin.org/nameof bumped from 0.0.1-next.25 to 0.0.1-next.26
34
+ * devDependencies
35
+ * @twin.org/merge-locales bumped from 0.0.1-next.25 to 0.0.1-next.26
36
+ * @twin.org/nameof-transformer bumped from 0.0.1-next.25 to 0.0.1-next.26
37
+ * @twin.org/nameof-vitest-plugin bumped from 0.0.1-next.25 to 0.0.1-next.26
38
+
3
39
  ## [0.0.1-next.25](https://github.com/twinfoundation/tools/compare/ts-to-schema-v0.0.1-next.24...ts-to-schema-v0.0.1-next.25) (2025-06-10)
4
40
 
5
41
 
@@ -40,4 +40,4 @@ Override for specific types, to be used when the type cannot be generated automa
40
40
 
41
41
  #### Index Signature
42
42
 
43
- \[`id`: `string`\]: `JsonSchemaDraft202012Object`
43
+ \[`id`: `string`\]: `AnySchemaObject`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twin.org/ts-to-schema",
3
- "version": "0.0.1-next.25",
3
+ "version": "0.0.1-next.27",
4
4
  "description": "Tool to convert TypeScript definitions to JSON schemas",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,11 +14,10 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@hyperjump/json-pointer": "1.1.1",
18
- "@hyperjump/json-schema": "1.14.1",
19
17
  "@twin.org/cli-core": "next",
20
18
  "@twin.org/core": "next",
21
- "@twin.org/nameof": "0.0.1-next.25",
19
+ "@twin.org/nameof": "0.0.1-next.27",
20
+ "ajv": "8.17.1",
22
21
  "commander": "14.0.0",
23
22
  "glob": "11.0.2",
24
23
  "ts-json-schema-generator": "2.4.0"