@tsofist/schema-forge 2.4.2 → 2.5.0

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.
@@ -2,6 +2,7 @@ import '../util/patch.extended-annotations-reader';
2
2
  import { SchemaObject } from 'ajv';
3
3
  import { ChainNodeParser, CompletedConfig, Context, SubNodeParser, TupleType } from 'ts-json-schema-generator';
4
4
  import { Node, TupleTypeNode } from 'typescript';
5
+ import { SchemaForgeOptions } from '../types';
5
6
  import { TypeExposeKind } from './types';
6
7
  interface Options {
7
8
  tsconfig: string;
@@ -14,6 +15,7 @@ interface Options {
14
15
  openapiCompatible?: boolean;
15
16
  sortObjectProperties?: boolean;
16
17
  allowUseFallbackDescription?: boolean;
18
+ shrinkDefinitionNames: SchemaForgeOptions['shrinkDefinitionNames'];
17
19
  }
18
20
  export declare function generateSchemaByDraftTypes(options: Options): Promise<SchemaObject>;
19
21
  export declare class TupleTypeParser implements SubNodeParser {
@@ -5,6 +5,7 @@ exports.generateSchemaByDraftTypes = generateSchemaByDraftTypes;
5
5
  require("../util/patch.extended-annotations-reader");
6
6
  const error_1 = require("@tsofist/stem/lib/error");
7
7
  const ajv_1 = require("ajv");
8
+ const jsonpath_plus_1 = require("jsonpath-plus");
8
9
  const ts_json_schema_generator_1 = require("ts-json-schema-generator");
9
10
  const typescript_1 = require("typescript");
10
11
  const sort_properties_1 = require("../util/sort-properties");
@@ -54,12 +55,43 @@ async function generateSchemaByDraftTypes(options) {
54
55
  const schema = generator.createSchema(definitionName);
55
56
  Object.assign(result.definitions, schema.definitions);
56
57
  }
58
+ if (options.shrinkDefinitionNames) {
59
+ const replacement = new Set();
60
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
61
+ for (const name of Object.keys(result.definitions)) {
62
+ console.log('DEF::::', name);
63
+ const r = options.shrinkDefinitionNames(name);
64
+ if (r) {
65
+ if (replacement.has(r) || r in result.definitions) {
66
+ (0, error_1.raise)(`Duplicate replacement definition name: ${r}`);
67
+ }
68
+ // rename property
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
70
+ result.definitions[r] = result.definitions[name];
71
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
72
+ delete result.definitions[name];
73
+ // rename references
74
+ const targets = (0, jsonpath_plus_1.JSONPath)({
75
+ path: `$..[?(@ && @.$ref == "#/definitions/${name}")]`,
76
+ json: result,
77
+ eval: 'safe',
78
+ });
79
+ targets.forEach((item) => {
80
+ item.$ref = item.$ref.replace(`#/definitions/${name}`, `#/definitions/${r}`);
81
+ });
82
+ }
83
+ }
84
+ }
57
85
  result.definitions = Object.fromEntries(Object.entries((result.definitions || {})).sort());
58
86
  if (options.sortObjectProperties)
59
87
  (0, sort_properties_1.sortProperties)(result.definitions);
60
88
  await new ajv_1.default({
61
89
  strict: true,
62
90
  allErrors: true,
91
+ strictSchema: true,
92
+ strictTypes: false,
93
+ strictTuples: false,
94
+ allowUnionTypes: true,
63
95
  }).validateSchema(result, true);
64
96
  return result;
65
97
  }
@@ -29,7 +29,7 @@ export interface SchemaForgeBaseOptions {
29
29
  * Filter for definitions
30
30
  * Important: dependencies will not be filtered
31
31
  */
32
- definitionsFilter?: (name: string) => boolean;
32
+ readonly definitionsFilter?: (name: string) => boolean;
33
33
  /**
34
34
  * Create shared $ref definitions for all types
35
35
  *
package/lib/generator.js CHANGED
@@ -3,10 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.forgeSchema = forgeSchema;
4
4
  exports.loadJSONSchema = loadJSONSchema;
5
5
  exports.loadJSONSchemaSync = loadJSONSchemaSync;
6
- const fs_1 = require("fs");
7
- const promises_1 = require("fs/promises");
8
6
  const node_crypto_1 = require("node:crypto");
9
- const promises_2 = require("node:fs/promises");
7
+ const node_fs_1 = require("node:fs");
8
+ const promises_1 = require("node:fs/promises");
10
9
  const as_array_1 = require("@tsofist/stem/lib/as-array");
11
10
  const error_1 = require("@tsofist/stem/lib/error");
12
11
  const noop_1 = require("@tsofist/stem/lib/noop");
@@ -53,6 +52,7 @@ async function forgeSchema(options) {
53
52
  openapiCompatible: options.openapiCompatible,
54
53
  sortObjectProperties: options.sortObjectProperties,
55
54
  allowUseFallbackDescription: options.allowUseFallbackDescription,
55
+ shrinkDefinitionNames: options.shrinkDefinitionNames,
56
56
  })),
57
57
  ...(options.schemaMetadata || {}),
58
58
  };
@@ -106,7 +106,7 @@ async function forgeSchema(options) {
106
106
  }
107
107
  finally {
108
108
  if (!KEEP_ARTEFACTS) {
109
- await Promise.all(files.map((fileName) => (0, promises_2.unlink)(fileName).catch(noop_1.noop)));
109
+ await Promise.all(files.map((fileName) => (0, promises_1.unlink)(fileName).catch(noop_1.noop)));
110
110
  }
111
111
  }
112
112
  return {
@@ -118,7 +118,7 @@ async function forgeSchema(options) {
118
118
  }
119
119
  finally {
120
120
  if (tsconfig && tsconfigGenerated) {
121
- await (0, promises_2.unlink)(tsconfig).catch(noop_1.noop);
121
+ await (0, promises_1.unlink)(tsconfig).catch(noop_1.noop);
122
122
  }
123
123
  }
124
124
  }
@@ -127,7 +127,7 @@ async function loadJSONSchema(files) {
127
127
  }
128
128
  function loadJSONSchemaSync(files) {
129
129
  return files.map((fn) => {
130
- const content = (0, fs_1.readFileSync)(fn, { encoding: 'utf8' });
130
+ const content = (0, node_fs_1.readFileSync)(fn, { encoding: 'utf8' });
131
131
  return JSON.parse(content);
132
132
  });
133
133
  }
@@ -176,6 +176,11 @@ describe('generator for a5', () => {
176
176
  outputSchemaMetadataFile,
177
177
  expose: 'all',
178
178
  explicitPublic: true,
179
+ shrinkDefinitionNames: (definitionName) => {
180
+ if (definitionName === 'NamesType')
181
+ return 'NT';
182
+ return undefined;
183
+ },
179
184
  });
180
185
  validator = (0, validator_1.createSchemaForgeValidator)({}, true);
181
186
  const schema = await (0, generator_1.loadJSONSchema)([outputSchemaFile]);
@@ -195,7 +200,7 @@ describe('generator for a5', () => {
195
200
  'DomainNum',
196
201
  'DomainValue',
197
202
  'DomainValuesType',
198
- 'NamesType',
203
+ 'NT', // 'NamesType',
199
204
  'NamesTypeAbnormal',
200
205
  'NumN',
201
206
  'Nums',
@@ -205,7 +210,7 @@ describe('generator for a5', () => {
205
210
  'VariadicList',
206
211
  'VariadicList1',
207
212
  ]);
208
- expect(validator.getValidator('test#/definitions/NamesType').schema).toStrictEqual({
213
+ expect(validator.getValidator('test#/definitions/NT').schema).toStrictEqual({
209
214
  type: 'string',
210
215
  enum: ['v:name1', 'v:name2'],
211
216
  });
@@ -217,7 +222,7 @@ describe('generator for a5', () => {
217
222
  $ref: '#/definitions/DomainValuesType',
218
223
  },
219
224
  name0: {
220
- $ref: '#/definitions/NamesType',
225
+ $ref: '#/definitions/NT',
221
226
  },
222
227
  name1: {
223
228
  type: 'string',
@@ -51,6 +51,7 @@ export type DBEntityOptions = {
51
51
  * Use string literal to set index name.
52
52
  */
53
53
  indexes?: {
54
- [column: string]: DBIndexOptionsDef<true>;
54
+ [field: string]: DBIndexOptionsDef<true>;
55
55
  };
56
56
  };
57
+ export type DBEntityOptionsDef = DBEntityOptions | string;
package/lib/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Nullable, PRec } from '@tsofist/stem';
1
+ import { NonEmptyString, Nullable, PRec } from '@tsofist/stem';
2
2
  import { ErrorCode } from '@tsofist/stem/lib/error';
3
3
  import { ErrorObject, ErrorsTextOptions, SchemaObject, ValidateFunction } from 'ajv';
4
4
  import { SchemaForgeBaseOptions } from './generator/types';
@@ -73,6 +73,12 @@ export interface SchemaForgeOptions extends SchemaForgeBaseOptions {
73
73
  * @default false
74
74
  */
75
75
  readonly sortObjectProperties?: boolean;
76
+ /**
77
+ * If you want to shrink the schema definition names, you have to provide a replacement function.
78
+ *
79
+ * WARN: this functionality is not compatible (yet) with `encodeRefs=true` option.
80
+ */
81
+ readonly shrinkDefinitionNames?: (definitionName: string) => undefined | NonEmptyString;
76
82
  }
77
83
  export interface SchemaForgeMetadata {
78
84
  $id: string;
package/lib/validator.js CHANGED
@@ -249,6 +249,7 @@ function createSchemaForgeValidator(engineOptions, useAdditionalFormats = false)
249
249
  function addJSDocKeywords(engine) {
250
250
  const InterfaceNamePattern = '^[A-Z][a-zA-Z0-9]+$';
251
251
  const PropertyNamePattern = '^[a-z][a-zA-Z0-9]+$';
252
+ const NestedPropertyNamePattern = '^[a-z][a-zA-Z0-9.-]+$';
252
253
  const MethodNamePattern = PropertyNamePattern;
253
254
  const MemberNamePattern = `${InterfaceNamePattern.substring(0, InterfaceNamePattern.length - 1)}#${PropertyNamePattern.substring(1)}`;
254
255
  const IXNamePattern = '^ix_[a-z][a-zA-Z0-9_]+$';
@@ -369,7 +370,7 @@ function addJSDocKeywords(engine) {
369
370
  type: 'object',
370
371
  additionalProperties: DBIndexSchema,
371
372
  propertyNames: {
372
- pattern: PropertyNamePattern,
373
+ pattern: NestedPropertyNamePattern,
373
374
  },
374
375
  },
375
376
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsofist/schema-forge",
3
- "version": "2.4.2",
3
+ "version": "2.5.0",
4
4
  "description": "Generate JSON schema from TypeScript types",
5
5
  "author": "Andrew Berdnikov <tsofistgudmen@gmail.com>",
6
6
  "license": "LGPL-3.0",
@@ -25,6 +25,7 @@
25
25
  "ajv": "^8.17.1",
26
26
  "ajv-formats": "^3.0.1",
27
27
  "json-schema-faker": "^0.5.8",
28
+ "jsonpath-plus": "^10.3.0",
28
29
  "ts-json-schema-generator": "~2.3.0",
29
30
  "tslib": "^2.8.1"
30
31
  },