@goast/core 0.0.4 → 0.0.6

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.
@@ -7,6 +7,7 @@ const fs_extra_1 = require("fs-extra");
7
7
  const config_1 = require("./config");
8
8
  const parser_1 = require("../parse/parser");
9
9
  const action_provider_1 = require("../utils/action-provider");
10
+ const file_system_utils_1 = require("../utils/file-system.utils");
10
11
  class _OpenApiGenerator {
11
12
  constructor(config, providers, parser) {
12
13
  this._providers = providers;
@@ -56,6 +57,12 @@ class _OpenApiGenerator {
56
57
  return yield this.generate(data);
57
58
  });
58
59
  }
60
+ parseAndGenerateFromDir(dir, options) {
61
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
62
+ const filter = (file) => { var _a, _b; return (file.endsWith('.yml') || file.endsWith('.yaml') || file.endsWith('.json')) && ((_b = (_a = options === null || options === void 0 ? void 0 : options.filter) === null || _a === void 0 ? void 0 : _a.call(options, file)) !== null && _b !== void 0 ? _b : true); };
63
+ return this.parseAndGenerate(...(yield (0, file_system_utils_1.getFiles)(dir, Object.assign(Object.assign({}, options), { filter }))));
64
+ });
65
+ }
59
66
  }
60
67
  class OpenApiGenerator extends _OpenApiGenerator {
61
68
  constructor(config) {
@@ -93,7 +100,7 @@ class OpenApiGenerationProviderBase {
93
100
  return this.onGenerate(ctx);
94
101
  }
95
102
  getProviderContext(context, config, defaultConfig) {
96
- const c = Object.assign(Object.assign(Object.assign({}, defaultConfig), context.config), config);
103
+ const c = Object.assign(Object.assign(Object.assign({}, context.config), defaultConfig), config);
97
104
  return Object.assign(context, {
98
105
  config: c,
99
106
  });
@@ -56,6 +56,7 @@ function collectPathItem(data, pathItems, path) {
56
56
  }
57
57
  function collectSchema(data, schemas) {
58
58
  (0, helpers_1.collect)(data, schemas, (data, schema) => {
59
+ var _a;
59
60
  const key = `${schema.$src.file}#${schema.$src.path}`;
60
61
  if (data.schemas.has(key))
61
62
  return;
@@ -75,6 +76,9 @@ function collectSchema(data, schemas) {
75
76
  if (typeof schema.additionalItems === 'object') {
76
77
  collectSchema(data, schema.additionalItems);
77
78
  }
79
+ if (typeof schema.discriminator === 'object') {
80
+ (0, helpers_1.collectRecord)(data, (_a = schema.discriminator) === null || _a === void 0 ? void 0 : _a.mapping, collectSchema);
81
+ }
78
82
  });
79
83
  }
80
84
  function collectParameter(data, parameters) {
@@ -9,10 +9,14 @@ function collect(data, obj, func) {
9
9
  for (const o of obj) {
10
10
  if (!o)
11
11
  continue;
12
+ if (o['x-ignore'])
13
+ continue;
12
14
  func(data, o);
13
15
  }
14
16
  }
15
17
  else {
18
+ if (obj['x-ignore'])
19
+ return;
16
20
  func(data, obj);
17
21
  }
18
22
  }
@@ -26,6 +30,8 @@ function collectRecord(data, obj, func) {
26
30
  const value = obj[key];
27
31
  if (!value)
28
32
  continue;
33
+ if (value['x-ignore'])
34
+ continue;
29
35
  func(data, value, key);
30
36
  }
31
37
  }
@@ -11,6 +11,7 @@ const yaml_1 = tslib_1.__importDefault(require("yaml"));
11
11
  const deref_proxy_1 = require("./deref-proxy");
12
12
  const collector_1 = require("../collect/collector");
13
13
  const transformer_1 = require("../transform/transformer");
14
+ const utils_1 = require("../utils");
14
15
  class OpenApiParser {
15
16
  constructor() {
16
17
  this._loadedDocuments = new Map();
@@ -61,7 +62,9 @@ class OpenApiParser {
61
62
  if (key === '$ref')
62
63
  continue;
63
64
  const v = value[key];
64
- if (v && typeof v === 'object') {
65
+ if ((0, utils_1.isNullish)(v))
66
+ continue;
67
+ if (typeof v === 'object') {
65
68
  if (Array.isArray(v)) {
66
69
  result[key] = yield Promise.all(v.map((v, index) => tslib_1.__awaiter(this, void 0, void 0, function* () {
67
70
  if (v && typeof v === 'object') {
@@ -76,6 +79,9 @@ class OpenApiParser {
76
79
  result[key] = yield this.dereference(file, `${path}/${String(key)}`, v);
77
80
  }
78
81
  }
82
+ if (typeof v === 'string' && path.endsWith('/discriminator/mapping')) {
83
+ result[key] = yield this.resolveReference(file, { $ref: v });
84
+ }
79
85
  }
80
86
  return result;
81
87
  });
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformSchema = void 0;
4
4
  const helpers_1 = require("./helpers");
5
5
  const utils_1 = require("../utils");
6
- function transformSchema(context, schema, isReference = false) {
6
+ function transformSchema(context, schema) {
7
7
  var _a, _b;
8
8
  if (!schema) {
9
9
  throw new Error('Schema is required.');
@@ -33,12 +33,11 @@ function transformSchema(context, schema, isReference = false) {
33
33
  kind = (0, helpers_1.determineSchemaKind)(schema);
34
34
  }
35
35
  }
36
- const ref = schema.$ref ? transformSchema(context, schema.$ref, true) : undefined;
37
36
  const id = context.idGenerator.generateId('schema');
38
37
  const nameInfo = (0, helpers_1.determineSchemaName)(schema, id);
39
- const result = {
38
+ const incompleteSchema = {
40
39
  $src: Object.assign(Object.assign({}, schema.$src), { component: schema }),
41
- $ref: ref,
40
+ $ref: undefined,
42
41
  id,
43
42
  name: nameInfo.name,
44
43
  isNameGenerated: nameInfo.isGenerated,
@@ -54,16 +53,25 @@ function transformSchema(context, schema, isReference = false) {
54
53
  custom: (0, helpers_1.getCustomFields)(schema),
55
54
  not: schema.not ? transformSchema(context, schema.not) : undefined,
56
55
  const: schema.const,
56
+ discriminator: schema.discriminator
57
+ ? {
58
+ propertyName: typeof schema.discriminator === 'string' ? schema.discriminator : schema.discriminator.propertyName,
59
+ mapping: {},
60
+ }
61
+ : undefined,
62
+ inheritedSchemas: [],
57
63
  };
58
- context.incompleteSchemas.set(schemaSource, result);
64
+ context.incompleteSchemas.set(schemaSource, incompleteSchema);
65
+ if (schema.$ref) {
66
+ incompleteSchema.$ref = transformSchema(context, schema.$ref);
67
+ }
59
68
  const extensions = schemaTransformers[kind](schema, context);
60
- Object.assign(result, extensions);
69
+ const completeSchema = Object.assign(incompleteSchema, extensions);
70
+ resolveDescriminatorMapping(context, completeSchema);
61
71
  context.incompleteSchemas.delete(schemaSource);
62
- context.transformed.schemas.set(openApiObjectId, result);
63
- if (!isReference) {
64
- context.schemas.set(schemaSource, result);
65
- }
66
- return result;
72
+ context.transformed.schemas.set(openApiObjectId, completeSchema);
73
+ context.schemas.set(schemaSource, completeSchema);
74
+ return completeSchema;
67
75
  }
68
76
  exports.transformSchema = transformSchema;
69
77
  const schemaTransformers = {
@@ -139,3 +147,14 @@ const schemaTransformers = {
139
147
  null: () => ({ type: 'null' }),
140
148
  unknown: () => ({}),
141
149
  };
150
+ function resolveDescriminatorMapping(context, schema) {
151
+ const discriminator = schema.$src.component.discriminator;
152
+ if (!discriminator || typeof discriminator === 'string' || !discriminator.mapping)
153
+ return;
154
+ for (const key of Object.keys(discriminator.mapping)) {
155
+ const mappedSchemaRef = discriminator.mapping[key];
156
+ const mappedSchema = transformSchema(context, mappedSchemaRef);
157
+ schema.discriminator.mapping[key] = mappedSchema;
158
+ mappedSchema.inheritedSchemas.push(schema);
159
+ }
160
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFiles = exports.defaultDirectoryScanOptions = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path_1 = require("path");
6
+ const fs_extra_1 = require("fs-extra");
7
+ exports.defaultDirectoryScanOptions = {
8
+ recursive: false,
9
+ maxDepth: 5,
10
+ };
11
+ function getFiles(dir, options) {
12
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
13
+ const opts = Object.assign(Object.assign({}, exports.defaultDirectoryScanOptions), options);
14
+ const files = [];
15
+ yield getFilesImpl(dir, opts, files, 0);
16
+ return files;
17
+ });
18
+ }
19
+ exports.getFiles = getFiles;
20
+ function getFilesImpl(dir, options, files, currentDepth) {
21
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
22
+ const dirFiles = yield (0, fs_extra_1.readdir)(dir);
23
+ for (const file of dirFiles) {
24
+ const filePath = (0, path_1.resolve)(dir, file);
25
+ const stat = yield (0, fs_extra_1.lstat)(filePath);
26
+ if (stat.isDirectory()) {
27
+ if (options.recursive) {
28
+ if (options.maxDepth && options.maxDepth > currentDepth) {
29
+ getFilesImpl(filePath, options, files, currentDepth + 1);
30
+ }
31
+ }
32
+ }
33
+ else {
34
+ if (!options.filter || options.filter(file)) {
35
+ files.push(filePath);
36
+ }
37
+ }
38
+ }
39
+ });
40
+ }
@@ -242,17 +242,22 @@ class SourceBuilder extends string_utils_1.StringBuilder {
242
242
  }
243
243
  /**
244
244
  * Adds one indentation level. If the current line already contains characters, only subsequent lines are affected.
245
- * @param builderFn The function to add indented content.
245
+ * @param builderFn The function to add indented content or the content itself.
246
246
  * @param condition The condition to check before adding indentation.
247
247
  * @returns A reference to this instance.
248
248
  */
249
- indent(builderFn, condition = true) {
249
+ indent(builderFnOrString, condition = true) {
250
250
  const shouldIndent = (0, condition_1.evalCondition)(condition);
251
251
  if (shouldIndent) {
252
252
  this.currentIndentLevel++;
253
253
  }
254
254
  try {
255
- builderFn(this);
255
+ if (typeof builderFnOrString === 'string') {
256
+ this.append(builderFnOrString);
257
+ }
258
+ else {
259
+ builderFnOrString(this);
260
+ }
256
261
  }
257
262
  finally {
258
263
  if (shouldIndent) {
@@ -264,14 +269,29 @@ class SourceBuilder extends string_utils_1.StringBuilder {
264
269
  /**
265
270
  * Adds parentheses around the specified content and adds one indentation level.
266
271
  * @param brackets The brackets to use.
267
- * @param builderFn The function to add content inside parentheses.
272
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
268
273
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
269
274
  * @returns A reference to this instance.
270
275
  */
271
- parenthesize(brackets, builderFn, indent = true) {
276
+ parenthesize(brackets, builderFnOrString, indent = true) {
272
277
  var _a, _b;
273
278
  this.append((_a = brackets[0]) !== null && _a !== void 0 ? _a : '');
274
- this.indent(builderFn, indent);
279
+ this.indent(builderFnOrString, indent);
280
+ this.append((_b = brackets[1]) !== null && _b !== void 0 ? _b : '');
281
+ return this;
282
+ }
283
+ /**
284
+ * Adds parentheses around the specified content and adds one indentation level. Line breaks are added after start and before end of the parentheses.
285
+ * @param brackets The brackets to use.
286
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
287
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
288
+ * @returns A reference to this instance.
289
+ */
290
+ parenthesizeMultiline(brackets, builderFnOrString, indent = true) {
291
+ var _a, _b;
292
+ this.appendLine((_a = brackets[0]) !== null && _a !== void 0 ? _a : '');
293
+ this.indent(builderFnOrString, indent);
294
+ this.ensureCurrentLineEmpty();
275
295
  this.append((_b = brackets[1]) !== null && _b !== void 0 ? _b : '');
276
296
  return this;
277
297
  }
@@ -279,16 +299,33 @@ class SourceBuilder extends string_utils_1.StringBuilder {
279
299
  * Adds parentheses around the specified content if the specified condition is true.
280
300
  * @param condition The condition to check before adding parentheses.
281
301
  * @param brackets The brackets to use.
282
- * @param builderFn The function to add content inside parentheses.
302
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
303
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
304
+ * @returns A reference to this instance.
305
+ */
306
+ parenthesizeIf(condition, brackets, builderFnOrString, indent) {
307
+ if ((0, condition_1.evalCondition)(condition)) {
308
+ this.parenthesize(brackets, builderFnOrString, indent !== null && indent !== void 0 ? indent : true);
309
+ }
310
+ else {
311
+ this.indent(builderFnOrString, indent !== null && indent !== void 0 ? indent : false);
312
+ }
313
+ return this;
314
+ }
315
+ /**
316
+ * Adds parentheses around the specified content if the specified condition is true. Line breaks are added after start and before end of the parentheses.
317
+ * @param condition The condition to check before adding parentheses.
318
+ * @param brackets The brackets to use.
319
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
283
320
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
284
321
  * @returns A reference to this instance.
285
322
  */
286
- parenthesizeIf(condition, brackets, builderFn, indent) {
323
+ parenthesizeMultilineIf(condition, brackets, builderFnOrString, indent) {
287
324
  if ((0, condition_1.evalCondition)(condition)) {
288
- this.parenthesize(brackets, builderFn, indent !== null && indent !== void 0 ? indent : true);
325
+ this.parenthesizeMultiline(brackets, builderFnOrString, indent !== null && indent !== void 0 ? indent : true);
289
326
  }
290
327
  else {
291
- this.indent(builderFn, indent !== null && indent !== void 0 ? indent : false);
328
+ this.indent(builderFnOrString, indent !== null && indent !== void 0 ? indent : false);
292
329
  }
293
330
  return this;
294
331
  }
@@ -4,6 +4,7 @@ import { emptyDir, ensureDir } from 'fs-extra';
4
4
  import { defaultOpenApiGeneratorConfig } from './config';
5
5
  import { OpenApiParser } from '../parse/parser';
6
6
  import { ActionProvider } from '../utils/action-provider';
7
+ import { getFiles } from '../utils/file-system.utils';
7
8
  class _OpenApiGenerator {
8
9
  constructor(config, providers, parser) {
9
10
  this._providers = providers;
@@ -53,6 +54,12 @@ class _OpenApiGenerator {
53
54
  return yield this.generate(data);
54
55
  });
55
56
  }
57
+ parseAndGenerateFromDir(dir, options) {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ const filter = (file) => { var _a, _b; return (file.endsWith('.yml') || file.endsWith('.yaml') || file.endsWith('.json')) && ((_b = (_a = options === null || options === void 0 ? void 0 : options.filter) === null || _a === void 0 ? void 0 : _a.call(options, file)) !== null && _b !== void 0 ? _b : true); };
60
+ return this.parseAndGenerate(...(yield getFiles(dir, Object.assign(Object.assign({}, options), { filter }))));
61
+ });
62
+ }
56
63
  }
57
64
  export class OpenApiGenerator extends _OpenApiGenerator {
58
65
  constructor(config) {
@@ -89,7 +96,7 @@ export class OpenApiGenerationProviderBase {
89
96
  return this.onGenerate(ctx);
90
97
  }
91
98
  getProviderContext(context, config, defaultConfig) {
92
- const c = Object.assign(Object.assign(Object.assign({}, defaultConfig), context.config), config);
99
+ const c = Object.assign(Object.assign(Object.assign({}, context.config), defaultConfig), config);
93
100
  return Object.assign(context, {
94
101
  config: c,
95
102
  });
@@ -52,6 +52,7 @@ function collectPathItem(data, pathItems, path) {
52
52
  }
53
53
  function collectSchema(data, schemas) {
54
54
  collect(data, schemas, (data, schema) => {
55
+ var _a;
55
56
  const key = `${schema.$src.file}#${schema.$src.path}`;
56
57
  if (data.schemas.has(key))
57
58
  return;
@@ -71,6 +72,9 @@ function collectSchema(data, schemas) {
71
72
  if (typeof schema.additionalItems === 'object') {
72
73
  collectSchema(data, schema.additionalItems);
73
74
  }
75
+ if (typeof schema.discriminator === 'object') {
76
+ collectRecord(data, (_a = schema.discriminator) === null || _a === void 0 ? void 0 : _a.mapping, collectSchema);
77
+ }
74
78
  });
75
79
  }
76
80
  function collectParameter(data, parameters) {
@@ -6,10 +6,14 @@ export function collect(data, obj, func) {
6
6
  for (const o of obj) {
7
7
  if (!o)
8
8
  continue;
9
+ if (o['x-ignore'])
10
+ continue;
9
11
  func(data, o);
10
12
  }
11
13
  }
12
14
  else {
15
+ if (obj['x-ignore'])
16
+ return;
13
17
  func(data, obj);
14
18
  }
15
19
  }
@@ -22,6 +26,8 @@ export function collectRecord(data, obj, func) {
22
26
  const value = obj[key];
23
27
  if (!value)
24
28
  continue;
29
+ if (value['x-ignore'])
30
+ continue;
25
31
  func(data, value, key);
26
32
  }
27
33
  }
@@ -8,6 +8,7 @@ import YAML from 'yaml';
8
8
  import { createDerefProxy } from './deref-proxy';
9
9
  import { collectOpenApi } from '../collect/collector';
10
10
  import { transformOpenApi } from '../transform/transformer';
11
+ import { isNullish } from '../utils';
11
12
  export class OpenApiParser {
12
13
  constructor() {
13
14
  this._loadedDocuments = new Map();
@@ -58,7 +59,9 @@ export class OpenApiParser {
58
59
  if (key === '$ref')
59
60
  continue;
60
61
  const v = value[key];
61
- if (v && typeof v === 'object') {
62
+ if (isNullish(v))
63
+ continue;
64
+ if (typeof v === 'object') {
62
65
  if (Array.isArray(v)) {
63
66
  result[key] = yield Promise.all(v.map((v, index) => __awaiter(this, void 0, void 0, function* () {
64
67
  if (v && typeof v === 'object') {
@@ -73,6 +76,9 @@ export class OpenApiParser {
73
76
  result[key] = yield this.dereference(file, `${path}/${String(key)}`, v);
74
77
  }
75
78
  }
79
+ if (typeof v === 'string' && path.endsWith('/discriminator/mapping')) {
80
+ result[key] = yield this.resolveReference(file, { $ref: v });
81
+ }
76
82
  }
77
83
  return result;
78
84
  });
@@ -1,6 +1,6 @@
1
1
  import { determineSchemaAccessibility, determineSchemaKind, determineSchemaName, getCustomFields, getOpenApiObjectIdentifier, transformAdditionalProperties, transformSchemaProperties, } from './helpers';
2
2
  import { createOverwriteProxy } from '../utils';
3
- export function transformSchema(context, schema, isReference = false) {
3
+ export function transformSchema(context, schema) {
4
4
  var _a, _b;
5
5
  if (!schema) {
6
6
  throw new Error('Schema is required.');
@@ -30,12 +30,11 @@ export function transformSchema(context, schema, isReference = false) {
30
30
  kind = determineSchemaKind(schema);
31
31
  }
32
32
  }
33
- const ref = schema.$ref ? transformSchema(context, schema.$ref, true) : undefined;
34
33
  const id = context.idGenerator.generateId('schema');
35
34
  const nameInfo = determineSchemaName(schema, id);
36
- const result = {
35
+ const incompleteSchema = {
37
36
  $src: Object.assign(Object.assign({}, schema.$src), { component: schema }),
38
- $ref: ref,
37
+ $ref: undefined,
39
38
  id,
40
39
  name: nameInfo.name,
41
40
  isNameGenerated: nameInfo.isGenerated,
@@ -51,16 +50,25 @@ export function transformSchema(context, schema, isReference = false) {
51
50
  custom: getCustomFields(schema),
52
51
  not: schema.not ? transformSchema(context, schema.not) : undefined,
53
52
  const: schema.const,
53
+ discriminator: schema.discriminator
54
+ ? {
55
+ propertyName: typeof schema.discriminator === 'string' ? schema.discriminator : schema.discriminator.propertyName,
56
+ mapping: {},
57
+ }
58
+ : undefined,
59
+ inheritedSchemas: [],
54
60
  };
55
- context.incompleteSchemas.set(schemaSource, result);
61
+ context.incompleteSchemas.set(schemaSource, incompleteSchema);
62
+ if (schema.$ref) {
63
+ incompleteSchema.$ref = transformSchema(context, schema.$ref);
64
+ }
56
65
  const extensions = schemaTransformers[kind](schema, context);
57
- Object.assign(result, extensions);
66
+ const completeSchema = Object.assign(incompleteSchema, extensions);
67
+ resolveDescriminatorMapping(context, completeSchema);
58
68
  context.incompleteSchemas.delete(schemaSource);
59
- context.transformed.schemas.set(openApiObjectId, result);
60
- if (!isReference) {
61
- context.schemas.set(schemaSource, result);
62
- }
63
- return result;
69
+ context.transformed.schemas.set(openApiObjectId, completeSchema);
70
+ context.schemas.set(schemaSource, completeSchema);
71
+ return completeSchema;
64
72
  }
65
73
  const schemaTransformers = {
66
74
  oneOf: (schema, context) => {
@@ -135,3 +143,14 @@ const schemaTransformers = {
135
143
  null: () => ({ type: 'null' }),
136
144
  unknown: () => ({}),
137
145
  };
146
+ function resolveDescriminatorMapping(context, schema) {
147
+ const discriminator = schema.$src.component.discriminator;
148
+ if (!discriminator || typeof discriminator === 'string' || !discriminator.mapping)
149
+ return;
150
+ for (const key of Object.keys(discriminator.mapping)) {
151
+ const mappedSchemaRef = discriminator.mapping[key];
152
+ const mappedSchema = transformSchema(context, mappedSchemaRef);
153
+ schema.discriminator.mapping[key] = mappedSchema;
154
+ mappedSchema.inheritedSchemas.push(schema);
155
+ }
156
+ }
@@ -0,0 +1,36 @@
1
+ import { __awaiter } from "tslib";
2
+ import { resolve } from 'path';
3
+ import { lstat, readdir } from 'fs-extra';
4
+ export const defaultDirectoryScanOptions = {
5
+ recursive: false,
6
+ maxDepth: 5,
7
+ };
8
+ export function getFiles(dir, options) {
9
+ return __awaiter(this, void 0, void 0, function* () {
10
+ const opts = Object.assign(Object.assign({}, defaultDirectoryScanOptions), options);
11
+ const files = [];
12
+ yield getFilesImpl(dir, opts, files, 0);
13
+ return files;
14
+ });
15
+ }
16
+ function getFilesImpl(dir, options, files, currentDepth) {
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ const dirFiles = yield readdir(dir);
19
+ for (const file of dirFiles) {
20
+ const filePath = resolve(dir, file);
21
+ const stat = yield lstat(filePath);
22
+ if (stat.isDirectory()) {
23
+ if (options.recursive) {
24
+ if (options.maxDepth && options.maxDepth > currentDepth) {
25
+ getFilesImpl(filePath, options, files, currentDepth + 1);
26
+ }
27
+ }
28
+ }
29
+ else {
30
+ if (!options.filter || options.filter(file)) {
31
+ files.push(filePath);
32
+ }
33
+ }
34
+ }
35
+ });
36
+ }
@@ -239,17 +239,22 @@ export class SourceBuilder extends StringBuilder {
239
239
  }
240
240
  /**
241
241
  * Adds one indentation level. If the current line already contains characters, only subsequent lines are affected.
242
- * @param builderFn The function to add indented content.
242
+ * @param builderFn The function to add indented content or the content itself.
243
243
  * @param condition The condition to check before adding indentation.
244
244
  * @returns A reference to this instance.
245
245
  */
246
- indent(builderFn, condition = true) {
246
+ indent(builderFnOrString, condition = true) {
247
247
  const shouldIndent = evalCondition(condition);
248
248
  if (shouldIndent) {
249
249
  this.currentIndentLevel++;
250
250
  }
251
251
  try {
252
- builderFn(this);
252
+ if (typeof builderFnOrString === 'string') {
253
+ this.append(builderFnOrString);
254
+ }
255
+ else {
256
+ builderFnOrString(this);
257
+ }
253
258
  }
254
259
  finally {
255
260
  if (shouldIndent) {
@@ -261,14 +266,29 @@ export class SourceBuilder extends StringBuilder {
261
266
  /**
262
267
  * Adds parentheses around the specified content and adds one indentation level.
263
268
  * @param brackets The brackets to use.
264
- * @param builderFn The function to add content inside parentheses.
269
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
265
270
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
266
271
  * @returns A reference to this instance.
267
272
  */
268
- parenthesize(brackets, builderFn, indent = true) {
273
+ parenthesize(brackets, builderFnOrString, indent = true) {
269
274
  var _a, _b;
270
275
  this.append((_a = brackets[0]) !== null && _a !== void 0 ? _a : '');
271
- this.indent(builderFn, indent);
276
+ this.indent(builderFnOrString, indent);
277
+ this.append((_b = brackets[1]) !== null && _b !== void 0 ? _b : '');
278
+ return this;
279
+ }
280
+ /**
281
+ * Adds parentheses around the specified content and adds one indentation level. Line breaks are added after start and before end of the parentheses.
282
+ * @param brackets The brackets to use.
283
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
284
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
285
+ * @returns A reference to this instance.
286
+ */
287
+ parenthesizeMultiline(brackets, builderFnOrString, indent = true) {
288
+ var _a, _b;
289
+ this.appendLine((_a = brackets[0]) !== null && _a !== void 0 ? _a : '');
290
+ this.indent(builderFnOrString, indent);
291
+ this.ensureCurrentLineEmpty();
272
292
  this.append((_b = brackets[1]) !== null && _b !== void 0 ? _b : '');
273
293
  return this;
274
294
  }
@@ -276,16 +296,33 @@ export class SourceBuilder extends StringBuilder {
276
296
  * Adds parentheses around the specified content if the specified condition is true.
277
297
  * @param condition The condition to check before adding parentheses.
278
298
  * @param brackets The brackets to use.
279
- * @param builderFn The function to add content inside parentheses.
299
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
300
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
301
+ * @returns A reference to this instance.
302
+ */
303
+ parenthesizeIf(condition, brackets, builderFnOrString, indent) {
304
+ if (evalCondition(condition)) {
305
+ this.parenthesize(brackets, builderFnOrString, indent !== null && indent !== void 0 ? indent : true);
306
+ }
307
+ else {
308
+ this.indent(builderFnOrString, indent !== null && indent !== void 0 ? indent : false);
309
+ }
310
+ return this;
311
+ }
312
+ /**
313
+ * Adds parentheses around the specified content if the specified condition is true. Line breaks are added after start and before end of the parentheses.
314
+ * @param condition The condition to check before adding parentheses.
315
+ * @param brackets The brackets to use.
316
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
280
317
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
281
318
  * @returns A reference to this instance.
282
319
  */
283
- parenthesizeIf(condition, brackets, builderFn, indent) {
320
+ parenthesizeMultilineIf(condition, brackets, builderFnOrString, indent) {
284
321
  if (evalCondition(condition)) {
285
- this.parenthesize(brackets, builderFn, indent !== null && indent !== void 0 ? indent : true);
322
+ this.parenthesizeMultiline(brackets, builderFnOrString, indent !== null && indent !== void 0 ? indent : true);
286
323
  }
287
324
  else {
288
- this.indent(builderFn, indent !== null && indent !== void 0 ? indent : false);
325
+ this.indent(builderFnOrString, indent !== null && indent !== void 0 ? indent : false);
289
326
  }
290
327
  return this;
291
328
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goast/core",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "repository": "https://github.com/MaSch0212/goast.git",
5
5
  "author": {
6
6
  "name": "Marc Schmidt (MaSch0212)",
@@ -3,6 +3,7 @@ import { AnyConfig, OpenApiGenerationProvider, OpenApiGenerationProviderContext,
3
3
  import { OpenApiParser } from '../parse/parser';
4
4
  import { ApiData } from '../transform';
5
5
  import { ActionProvider } from '../utils/action-provider';
6
+ import { DirectoryScanOptions } from '../utils/file-system.utils';
6
7
  import { EmptyConstructor, Merge } from '../utils/type.utils';
7
8
  type OpenApiGenerationProviders = {
8
9
  provider: ActionProvider<OpenApiGenerationProviderFn>;
@@ -22,6 +23,7 @@ declare class _OpenApiGenerator<TOutput extends OpenApiGeneratorInput> {
22
23
  useValue<PInput extends TOutput, POutput extends OpenApiGeneratorOutput, PConfig extends AnyConfig>(value: OpenApiGenerationProvider<VInput<PInput, TOutput>, POutput, PConfig>, config?: Partial<PConfig>): _OpenApiGenerator<Merge<[TOutput, POutput]>>;
23
24
  generate<T extends ApiData>(data: T): Promise<TOutput>;
24
25
  parseAndGenerate(...fileNames: (string | string[])[]): Promise<TOutput>;
26
+ parseAndGenerateFromDir(dir: string, options?: Partial<DirectoryScanOptions>): Promise<TOutput>;
25
27
  }
26
28
  export declare class OpenApiGenerator extends _OpenApiGenerator<{}> {
27
29
  constructor(config?: Partial<OpenApiGeneratorConfig>);
@@ -1,3 +1,4 @@
1
1
  import { OpenApiCollectorData } from './types';
2
- export declare function collect<T>(data: OpenApiCollectorData, obj: T | T[] | undefined, func: (data: OpenApiCollectorData, obj: NonNullable<T>) => void): void;
3
- export declare function collectRecord<T>(data: OpenApiCollectorData, obj: Record<string, T> | undefined, func: (data: OpenApiCollectorData, obj: NonNullable<T>, key: string) => void): void;
2
+ import { Nullable } from '../utils';
3
+ export declare function collect<T extends Record<`x-${string}`, unknown>>(data: OpenApiCollectorData, obj: Nullable<T | Nullable<T>[]>, func: (data: OpenApiCollectorData, obj: NonNullable<T>) => void): void;
4
+ export declare function collectRecord<T extends Record<`x-${string}`, unknown>>(data: OpenApiCollectorData, obj: Nullable<Record<string, Nullable<T>>>, func: (data: OpenApiCollectorData, obj: NonNullable<T>, key: string) => void): void;
@@ -1,11 +1,14 @@
1
- import { OpenApiDocument, OpenApiReference } from './openapi-types';
1
+ import { OpenApiDiscriminator, OpenApiDocument, OpenApiReference, OpenApiSchema } from './openapi-types';
2
2
  export type DerefSource<T> = {
3
3
  file: string;
4
4
  path: string;
5
5
  document: Deref<OpenApiDocument>;
6
6
  originalComponent: T;
7
7
  };
8
- type _Deref<T> = {
8
+ type _DerefDiscriminator = Omit<OpenApiDiscriminator, 'mapping'> & {
9
+ mapping?: Record<string, Deref<OpenApiSchema>>;
10
+ };
11
+ type _Deref<T extends object> = T extends OpenApiDiscriminator ? _DerefDiscriminator : {
9
12
  [K in keyof T as K extends keyof OpenApiReference ? never : K]: Deref<T[K]>;
10
13
  } & {
11
14
  $src: DerefSource<T>;
@@ -88,6 +88,10 @@ export type ApiSchemaProperty = {
88
88
  name: string;
89
89
  schema: ApiSchema;
90
90
  };
91
+ export type ApiSchemaDiscriminator = {
92
+ propertyName: string;
93
+ mapping: Record<string, ApiSchema>;
94
+ };
91
95
  export type ApiSchemaComponent = ApiComponent<OpenApiSchema>;
92
96
  export type ApiSchemaBase = ApiSchemaComponent & {
93
97
  name: string;
@@ -103,6 +107,8 @@ export type ApiSchemaBase = ApiSchemaComponent & {
103
107
  required: Set<string>;
104
108
  custom: Record<string, unknown>;
105
109
  not: ApiSchema | undefined;
110
+ discriminator: ApiSchemaDiscriminator | undefined;
111
+ inheritedSchemas: ApiSchema[];
106
112
  };
107
113
  export type ApiSchema<T extends ApiSchemaKind = ApiSchemaKind> = ApiSchemaBase & ApiSchemaExtensions<T>;
108
114
  type AdditionalCombinedSchemaProperties = {
@@ -1,4 +1,4 @@
1
1
  import { ApiSchema } from './api-types';
2
2
  import { OpenApiTransformerContext } from './types';
3
3
  import { Deref, OpenApiSchema } from '../parse';
4
- export declare function transformSchema<T extends Deref<OpenApiSchema>>(context: OpenApiTransformerContext, schema: T, isReference?: boolean): ApiSchema;
4
+ export declare function transformSchema<T extends Deref<OpenApiSchema>>(context: OpenApiTransformerContext, schema: T): ApiSchema;
@@ -0,0 +1,8 @@
1
+ import { Nullable } from './type.utils';
2
+ export type DirectoryScanOptions = {
3
+ recursive: boolean;
4
+ maxDepth: Nullable<number>;
5
+ filter?: (file: string) => boolean;
6
+ };
7
+ export declare const defaultDirectoryScanOptions: DirectoryScanOptions;
8
+ export declare function getFiles(dir: string, options?: Partial<DirectoryScanOptions>): Promise<string[]>;
@@ -148,28 +148,45 @@ export declare class SourceBuilder extends StringBuilder {
148
148
  applyIfElse(condition: Condition, builderFn: (builder: this) => void, elseBuilderFn: (builder: this) => void): this;
149
149
  /**
150
150
  * Adds one indentation level. If the current line already contains characters, only subsequent lines are affected.
151
- * @param builderFn The function to add indented content.
151
+ * @param builderFn The function to add indented content or the content itself.
152
152
  * @param condition The condition to check before adding indentation.
153
153
  * @returns A reference to this instance.
154
154
  */
155
- indent(builderFn: (builder: this) => void, condition?: Condition): this;
155
+ indent(builderFnOrString: ((builder: this) => void) | string, condition?: Condition): this;
156
156
  /**
157
157
  * Adds parentheses around the specified content and adds one indentation level.
158
158
  * @param brackets The brackets to use.
159
- * @param builderFn The function to add content inside parentheses.
159
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
160
160
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
161
161
  * @returns A reference to this instance.
162
162
  */
163
- parenthesize(brackets: Paratheses, builderFn: (builder: this) => void, indent?: boolean): this;
163
+ parenthesize(brackets: Paratheses, builderFnOrString: ((builder: this) => void) | string, indent?: boolean): this;
164
+ /**
165
+ * Adds parentheses around the specified content and adds one indentation level. Line breaks are added after start and before end of the parentheses.
166
+ * @param brackets The brackets to use.
167
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
168
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
169
+ * @returns A reference to this instance.
170
+ */
171
+ parenthesizeMultiline(brackets: Paratheses, builderFnOrString: ((builder: this) => void) | string, indent?: boolean): this;
164
172
  /**
165
173
  * Adds parentheses around the specified content if the specified condition is true.
166
174
  * @param condition The condition to check before adding parentheses.
167
175
  * @param brackets The brackets to use.
168
- * @param builderFn The function to add content inside parentheses.
176
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
177
+ * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
178
+ * @returns A reference to this instance.
179
+ */
180
+ parenthesizeIf(condition: Condition, brackets: Paratheses, builderFnOrString: ((builder: this) => void) | string, indent?: boolean): this;
181
+ /**
182
+ * Adds parentheses around the specified content if the specified condition is true. Line breaks are added after start and before end of the parentheses.
183
+ * @param condition The condition to check before adding parentheses.
184
+ * @param brackets The brackets to use.
185
+ * @param builderFnOrString The function to add content inside parentheses or one string that should be parenthesized.
169
186
  * @param indent Whether to indent the content inside parentheses. Defaults to `true`.
170
187
  * @returns A reference to this instance.
171
188
  */
172
- parenthesizeIf(condition: Condition, brackets: Paratheses, builderFn: (builder: this) => void, indent?: boolean): this;
189
+ parenthesizeMultilineIf(condition: Condition, brackets: Paratheses, builderFnOrString: ((builder: this) => void) | string, indent?: boolean): this;
173
190
  /**
174
191
  * Adds content for each item in the specified array.
175
192
  * @param items The items to add content for.