@checkdigit/eslint-plugin 7.18.0-PR.143-b064 → 7.18.0-PR.143-b6d4
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/dist-mjs/athena/athena.mjs +82 -36
- package/dist-mjs/athena/visitor.mjs +27 -1
- package/dist-mjs/openapi/service-schema-generator.mjs +26 -64
- package/dist-types/athena/visitor.d.ts +4 -0
- package/package.json +1 -1
- package/src/athena/athena.ts +93 -43
- package/src/athena/visitor.ts +28 -0
- package/src/openapi/service-schema-generator.ts +26 -74
- package/src/services/interchange/v1/swagger.schema.deref.json +16 -15
- package/src/services/ledger/v1/swagger.schema.deref.json +81 -81
- package/src/services/ledger/v2/swagger.schema.deref.json +4119 -0
- package/src/services/link/v1/swagger.schema.deref.json +13 -12
- package/src/services/link/{v1/swagger.schema.json → v2/swagger.schema.deref.json} +98 -28
- package/src/services/message/v1/swagger.schema.deref.json +731 -731
- package/src/services/message/v2/swagger.schema.deref.json +1017 -1017
- package/src/services/paymentCard/v1/swagger.schema.deref.json +248 -238
- package/src/services/paymentCard/v2/swagger.schema.deref.json +257 -274
- package/src/services/paymentCard/v3/swagger.schema.deref.json +2843 -0
- package/src/services/person/v1/swagger.schema.deref.json +111 -96
- package/src/services/person/v2/swagger.schema.deref.json +4931 -0
- package/src/services/teampayApproval/v1/swagger.schema.deref.json +2 -165
- package/src/services/teampayCardManagement/v1/swagger.schema.deref.json +220 -1768
- package/src/services/teampayClientManagement/v1/swagger.schema.deref.json +217 -217
- package/src/services/interchange/v1/swagger.schema.json +0 -423
- package/src/services/interchange/v1/swagger.yml +0 -414
- package/src/services/ledger/v1/swagger.schema.json +0 -1048
- package/src/services/ledger/v1/swagger.yml +0 -1094
- package/src/services/link/v1/swagger.yml +0 -343
- package/src/services/message/v1/swagger.schema.json +0 -2944
- package/src/services/message/v1/swagger.yml +0 -2798
- package/src/services/message/v2/swagger.schema.json +0 -3040
- package/src/services/message/v2/swagger.yml +0 -3009
- package/src/services/paymentCard/v1/swagger.schema.json +0 -1687
- package/src/services/paymentCard/v1/swagger.yml +0 -1161
- package/src/services/paymentCard/v2/swagger.schema.json +0 -1649
- package/src/services/paymentCard/v2/swagger.yml +0 -1149
- package/src/services/person/v1/swagger.schema.json +0 -979
- package/src/services/person/v1/swagger.yml +0 -1157
- package/src/services/teampayClientManagement/v1/swagger.schema.json +0 -1598
- package/src/services/teampayClientManagement/v1/swagger.yml +0 -1376
package/src/athena/athena.ts
CHANGED
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
} from './context.ts';
|
|
29
29
|
import { buildServiceTables } from './service-table.ts';
|
|
30
30
|
import {
|
|
31
|
+
containsCastToArray,
|
|
32
|
+
containsCastToMap,
|
|
31
33
|
containsLambda,
|
|
32
34
|
extractBracketAccessorPath,
|
|
33
35
|
extractColumnRefs,
|
|
@@ -228,7 +230,7 @@ function resolveFromClause(select: Select, ctx: VisitContext): void {
|
|
|
228
230
|
|
|
229
231
|
interface UnnestMapping {
|
|
230
232
|
fromColumn: string;
|
|
231
|
-
|
|
233
|
+
toColumns: string[]; // 1 item for array UNNEST, 2 items for map UNNEST (key, value)
|
|
232
234
|
ast: object;
|
|
233
235
|
}
|
|
234
236
|
|
|
@@ -243,15 +245,17 @@ function extractUnnestMappings(select: Select): UnnestMapping[] {
|
|
|
243
245
|
const fromColumn = typeof item.expr.column === 'string' ? item.expr.column : undefined;
|
|
244
246
|
assert.ok(fromColumn !== undefined, 'UNNEST expr must be a column_ref with a string column name');
|
|
245
247
|
|
|
246
|
-
// The alias is stored as a func_call node: UNNEST(col) AS t(
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
:
|
|
252
|
-
|
|
248
|
+
// The alias is stored as a func_call node: UNNEST(col) AS t(alias1[, alias2])
|
|
249
|
+
const aliasArgs = item.as?.args.value ?? [];
|
|
250
|
+
const toColumns: string[] = [];
|
|
251
|
+
for (const col of aliasArgs) {
|
|
252
|
+
if (typeof (col as { column?: unknown }).column === 'string') {
|
|
253
|
+
toColumns.push((col as { column: string }).column);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
assert.ok(toColumns.length > 0, 'UNNEST alias must have at least one column name');
|
|
253
257
|
|
|
254
|
-
mappings.push({ fromColumn,
|
|
258
|
+
mappings.push({ fromColumn, toColumns, ast: item.expr });
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
return mappings;
|
|
@@ -260,45 +264,93 @@ function extractUnnestMappings(select: Select): UnnestMapping[] {
|
|
|
260
264
|
function applyUnnestPre(mappings: UnnestMapping[], ctx: VisitContext): UnnestMapping[] {
|
|
261
265
|
const deferred: UnnestMapping[] = [];
|
|
262
266
|
|
|
263
|
-
for (const { fromColumn,
|
|
267
|
+
for (const { fromColumn, toColumns, ast } of mappings) {
|
|
264
268
|
// Find the table that owns the source column
|
|
265
269
|
const ownerTable = [...ctx.tables.values()].flat().find((table) => table.columns.has(fromColumn));
|
|
266
270
|
|
|
267
271
|
if (ownerTable === undefined) {
|
|
268
|
-
deferred.push({ fromColumn,
|
|
272
|
+
deferred.push({ fromColumn, toColumns, ast });
|
|
269
273
|
continue;
|
|
270
274
|
}
|
|
271
275
|
|
|
272
276
|
const sourceColumns = ownerTable.columns.get(fromColumn) ?? [];
|
|
273
277
|
const sourceSchema = sourceColumns[0]?.schema;
|
|
274
|
-
if (sourceSchema?.type !== 'array') {
|
|
275
|
-
throw new AthenaError(ATHENA_ERROR, `UNNEST source column '${fromColumn}' must resolve to an array schema`, ast);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
278
|
const unnestTableName = `${ownerTable.name ?? '<anonymous>'}:<unnested>`;
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
279
|
+
const apiOperation = ownerTable.apiOperation !== undefined ? { apiOperation: ownerTable.apiOperation } : {};
|
|
280
|
+
|
|
281
|
+
if (sourceSchema?.type === 'array') {
|
|
282
|
+
const [toColumn] = toColumns;
|
|
283
|
+
assert.ok(toColumn !== undefined);
|
|
284
|
+
ctx.tables.set(unnestTableName, [
|
|
285
|
+
{
|
|
286
|
+
name: unnestTableName,
|
|
287
|
+
...apiOperation,
|
|
288
|
+
columns: new Map([[toColumn, [resolvedCol(toColumn, sourceSchema.items, sourceColumns[0]?.ast)]]]),
|
|
289
|
+
},
|
|
290
|
+
]);
|
|
291
|
+
} else if (sourceSchema?.type === 'object') {
|
|
292
|
+
// MAP UNNEST: UNNEST(map_col) AS t(key_col, value_col)
|
|
293
|
+
const [keyColumn, valueColumn] = toColumns;
|
|
294
|
+
assert.ok(
|
|
295
|
+
keyColumn !== undefined && valueColumn !== undefined,
|
|
296
|
+
`UNNEST of map column '${fromColumn}' requires exactly two alias columns (key, value)`,
|
|
297
|
+
);
|
|
298
|
+
const addlProps = (sourceSchema as SchemaObject)['additionalProperties'] as unknown;
|
|
299
|
+
const valueSchema: SchemaObject =
|
|
300
|
+
typeof addlProps === 'object' && addlProps !== null ? addlProps : { type: 'string' };
|
|
301
|
+
ctx.tables.set(unnestTableName, [
|
|
302
|
+
{
|
|
303
|
+
name: unnestTableName,
|
|
304
|
+
...apiOperation,
|
|
305
|
+
columns: new Map([
|
|
306
|
+
[keyColumn, [resolvedCol(keyColumn, { type: 'string' }, sourceColumns[0]?.ast)]],
|
|
307
|
+
[valueColumn, [resolvedCol(valueColumn, valueSchema, sourceColumns[0]?.ast)]],
|
|
308
|
+
]),
|
|
309
|
+
},
|
|
310
|
+
]);
|
|
311
|
+
} else {
|
|
312
|
+
throw new AthenaError(
|
|
313
|
+
ATHENA_ERROR,
|
|
314
|
+
`UNNEST source column '${fromColumn}' must resolve to an array or map schema`,
|
|
315
|
+
ast,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
286
318
|
}
|
|
287
319
|
|
|
288
320
|
return deferred;
|
|
289
321
|
}
|
|
290
322
|
|
|
291
323
|
function applyUnnestPost(mappings: UnnestMapping[], columns: Map<string, ResolvedColumn[]>): void {
|
|
292
|
-
for (const { fromColumn,
|
|
324
|
+
for (const { fromColumn, toColumns, ast } of mappings) {
|
|
293
325
|
const sourceColumns = columns.get(fromColumn);
|
|
294
326
|
if (sourceColumns === undefined) {
|
|
295
327
|
throw new AthenaError(ATHENA_ERROR, `UNNEST source column '${fromColumn}' not found in SELECT`, ast);
|
|
296
328
|
}
|
|
297
329
|
const sourceSchema = sourceColumns[0]?.schema;
|
|
298
|
-
|
|
299
|
-
|
|
330
|
+
|
|
331
|
+
if (sourceSchema?.type === 'array') {
|
|
332
|
+
const [toColumn] = toColumns;
|
|
333
|
+
assert.ok(toColumn !== undefined);
|
|
334
|
+
columns.set(toColumn, [resolvedCol(toColumn, sourceSchema.items, sourceColumns[0]?.ast)]);
|
|
335
|
+
} else if (sourceSchema?.type === 'object') {
|
|
336
|
+
// MAP UNNEST: produces key column and value column
|
|
337
|
+
const [keyColumn, valueColumn] = toColumns;
|
|
338
|
+
assert.ok(
|
|
339
|
+
keyColumn !== undefined && valueColumn !== undefined,
|
|
340
|
+
`UNNEST of map column '${fromColumn}' requires exactly two alias columns (key, value)`,
|
|
341
|
+
);
|
|
342
|
+
const addlProps = (sourceSchema as SchemaObject)['additionalProperties'] as unknown;
|
|
343
|
+
const valueSchema: SchemaObject =
|
|
344
|
+
typeof addlProps === 'object' && addlProps !== null ? addlProps : { type: 'string' };
|
|
345
|
+
columns.set(keyColumn, [resolvedCol(keyColumn, { type: 'string' }, sourceColumns[0]?.ast)]);
|
|
346
|
+
columns.set(valueColumn, [resolvedCol(valueColumn, valueSchema, sourceColumns[0]?.ast)]);
|
|
347
|
+
} else {
|
|
348
|
+
throw new AthenaError(
|
|
349
|
+
ATHENA_ERROR,
|
|
350
|
+
`UNNEST source column '${fromColumn}' must resolve to an array or map schema`,
|
|
351
|
+
ast,
|
|
352
|
+
);
|
|
300
353
|
}
|
|
301
|
-
columns.set(toColumn, [resolvedCol(toColumn, sourceSchema.items, sourceColumns[0]?.ast)]);
|
|
302
354
|
}
|
|
303
355
|
}
|
|
304
356
|
|
|
@@ -502,22 +554,6 @@ function resolveSingleColumnRef(
|
|
|
502
554
|
);
|
|
503
555
|
}
|
|
504
556
|
|
|
505
|
-
/** Return true when the column expression is a CAST / TRY_CAST to ARRAY<…>. */
|
|
506
|
-
function isCastToArray(node: unknown): boolean {
|
|
507
|
-
if (typeof node !== 'object' || node === null) {
|
|
508
|
-
return false;
|
|
509
|
-
}
|
|
510
|
-
const typed = node as Record<string, unknown>;
|
|
511
|
-
if (typed['type'] === 'cast') {
|
|
512
|
-
const target = (typed['target'] as { dataType?: string }[] | undefined)?.[0];
|
|
513
|
-
return target?.dataType === 'ARRAY';
|
|
514
|
-
}
|
|
515
|
-
if (typed['type'] === 'expr') {
|
|
516
|
-
return isCastToArray(typed['expr']);
|
|
517
|
-
}
|
|
518
|
-
return false;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
557
|
function resolveSelectColumns(select: Select, ctx: VisitContext): Map<string, ResolvedColumn[]> {
|
|
522
558
|
const allTables = [...ctx.tables.values()].flat();
|
|
523
559
|
const columns = new Map<string, ResolvedColumn[]>();
|
|
@@ -544,7 +580,7 @@ function resolveSelectColumns(select: Select, ctx: VisitContext): Map<string, Re
|
|
|
544
580
|
// the inner expression (e.g. json_parse) has no schema-aware path to navigate.
|
|
545
581
|
// Skip when the inner expression already resolved to an array (e.g. json_extract on an
|
|
546
582
|
// array-typed property): overriding would strip the items schema and break UNNEST typing.
|
|
547
|
-
if (
|
|
583
|
+
if (containsCastToArray(columnAST)) {
|
|
548
584
|
const colName = columnAlias ?? indexedName;
|
|
549
585
|
const existing = columns.get(colName);
|
|
550
586
|
if (existing !== undefined && existing[0]?.schema.type !== 'array') {
|
|
@@ -554,6 +590,20 @@ function resolveSelectColumns(select: Select, ctx: VisitContext): Map<string, Re
|
|
|
554
590
|
);
|
|
555
591
|
}
|
|
556
592
|
}
|
|
593
|
+
|
|
594
|
+
// Same for CAST/TRY_CAST to MAP<…>: honour the declared map type when the inner
|
|
595
|
+
// expression (e.g. split_to_map) has no schema-aware navigation available.
|
|
596
|
+
// Skip when the schema is already an object to preserve additionalProperties.
|
|
597
|
+
if (containsCastToMap(columnAST)) {
|
|
598
|
+
const colName = columnAlias ?? indexedName;
|
|
599
|
+
const existing = columns.get(colName);
|
|
600
|
+
if (existing !== undefined && existing[0]?.schema.type !== 'object') {
|
|
601
|
+
columns.set(
|
|
602
|
+
colName,
|
|
603
|
+
existing.map((col) => resolvedCol(col.name, { type: 'object' }, col.ast)),
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
557
607
|
}
|
|
558
608
|
|
|
559
609
|
return columns;
|
package/src/athena/visitor.ts
CHANGED
|
@@ -382,3 +382,31 @@ export function hasFunctionCalls(expr: unknown): boolean {
|
|
|
382
382
|
});
|
|
383
383
|
return found;
|
|
384
384
|
}
|
|
385
|
+
|
|
386
|
+
/** Return true when the expression tree contains any CAST / TRY_CAST to ARRAY<…>. */
|
|
387
|
+
export function containsCastToArray(expr: unknown): boolean {
|
|
388
|
+
let found = false;
|
|
389
|
+
walkExpr(expr, {
|
|
390
|
+
visitCast(node) {
|
|
391
|
+
const target = (node as unknown as { target?: { dataType?: string }[] }).target?.[0];
|
|
392
|
+
if (target?.dataType === 'ARRAY') {
|
|
393
|
+
found = true;
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
return found;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Return true when the expression tree contains any CAST / TRY_CAST to MAP<…>. */
|
|
401
|
+
export function containsCastToMap(expr: unknown): boolean {
|
|
402
|
+
let found = false;
|
|
403
|
+
walkExpr(expr, {
|
|
404
|
+
visitCast(node) {
|
|
405
|
+
const target = (node as unknown as { target?: { dataType?: string }[] }).target?.[0];
|
|
406
|
+
if (target?.dataType === 'MAP') {
|
|
407
|
+
found = true;
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
return found;
|
|
412
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// openapi/service-schema-generator.ts
|
|
2
2
|
|
|
3
|
-
import { execFileSync } from 'node:child_process';
|
|
4
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
4
|
|
|
6
5
|
import debug from 'debug';
|
|
@@ -53,18 +52,6 @@ function derefApiSchemas(schemas: ApiSchemas): ApiSchemas {
|
|
|
53
52
|
return { apis: resolvedApis };
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
function fetchUrlSync(url: string): string | null {
|
|
57
|
-
try {
|
|
58
|
-
return execFileSync(process.execPath, ['--input-type=module'], {
|
|
59
|
-
input: `const r=await fetch(${JSON.stringify(url)});if(!r.ok)process.exit(1);process.stdout.write(await r.text());`,
|
|
60
|
-
encoding: 'utf-8',
|
|
61
|
-
timeout: 15_000,
|
|
62
|
-
});
|
|
63
|
-
} catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
55
|
function readServiceConfig(
|
|
69
56
|
packageJsonContent: string,
|
|
70
57
|
org: string,
|
|
@@ -105,73 +92,33 @@ function findServiceLocally(serviceFolder: string, org: string, serviceName: str
|
|
|
105
92
|
}
|
|
106
93
|
|
|
107
94
|
function findServiceInProject(serviceName: string): ServiceSource | null {
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
if (org === undefined) {
|
|
95
|
+
const packageJson = JSON.parse(readFileSync('./package.json', 'utf-8')) as { name?: string };
|
|
96
|
+
const [org, projectName] = (packageJson.name ?? '').slice(1).split('/');
|
|
97
|
+
if (org === undefined || projectName !== serviceName) {
|
|
112
98
|
return null;
|
|
113
99
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
log('service is the current project, looking for API schemas locally', serviceName);
|
|
117
|
-
const serviceSource = findServiceLocally('.', org, serviceName);
|
|
118
|
-
if (serviceSource !== null) {
|
|
119
|
-
return serviceSource;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return null;
|
|
100
|
+
log(`[schema-generator] '${serviceName}' is the current project, reading local swagger files`);
|
|
101
|
+
return findServiceLocally('.', org, serviceName);
|
|
124
102
|
}
|
|
125
103
|
|
|
126
104
|
function findServiceInNodeModules(serviceName: string): ServiceSource | null {
|
|
127
105
|
for (const org of GITHUB_ORGANIZATIONS) {
|
|
128
106
|
const serviceFolder = `node_modules/@${org}/${serviceName}`;
|
|
129
107
|
if (!existsSync(serviceFolder)) {
|
|
108
|
+
log(`[schema-generator] not found in node_modules: @${org}/${serviceName}`);
|
|
130
109
|
continue;
|
|
131
110
|
}
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
const serviceSource = findServiceLocally(serviceFolder, org, serviceName);
|
|
135
|
-
if (serviceSource !== null) {
|
|
136
|
-
return serviceSource;
|
|
137
|
-
}
|
|
138
|
-
} catch {
|
|
139
|
-
// continue to next org
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function findServiceOnGitHub(serviceName: string): ServiceSource | null {
|
|
146
|
-
for (const org of GITHUB_ORGANIZATIONS) {
|
|
147
|
-
const pkgUrl = `https://raw.githubusercontent.com/${org}/${serviceName}/main/package.json`;
|
|
148
|
-
log(`fetching package.json from ${pkgUrl}`);
|
|
149
|
-
const pkgContent = fetchUrlSync(pkgUrl);
|
|
150
|
-
if (pkgContent === null) {
|
|
151
|
-
continue;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
111
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const endpoints: ServiceEndpoint[] = [];
|
|
161
|
-
for (const endpoint of config.endpoints) {
|
|
162
|
-
const swaggerUrl = `https://raw.githubusercontent.com/${org}/${serviceName}/main/${config.apiRoot}/${endpoint}/swagger.yml`;
|
|
163
|
-
log(`fetching swagger.yml from ${swaggerUrl}`);
|
|
164
|
-
const yamlContent = fetchUrlSync(swaggerUrl);
|
|
165
|
-
if (yamlContent !== null) {
|
|
166
|
-
endpoints.push({ path: endpoint, yamlContent });
|
|
167
|
-
}
|
|
112
|
+
log(`[schema-generator] found in node_modules: @${org}/${serviceName}, reading swagger files`);
|
|
113
|
+
const source = findServiceLocally(serviceFolder, org, serviceName);
|
|
114
|
+
if (source !== null) {
|
|
115
|
+
return source;
|
|
168
116
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// continue to next org
|
|
117
|
+
log(`[schema-generator] no swagger schema inside node_modules/@${org}/${serviceName}`);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
log(
|
|
120
|
+
`[schema-generator] error reading node_modules/@${org}/${serviceName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
121
|
+
);
|
|
175
122
|
}
|
|
176
123
|
}
|
|
177
124
|
return null;
|
|
@@ -181,15 +128,18 @@ export function generateSchemasForService(
|
|
|
181
128
|
serviceName: string,
|
|
182
129
|
outputDir?: string,
|
|
183
130
|
): { schema: ApiSchemas; endpoint: string }[] {
|
|
184
|
-
log(
|
|
131
|
+
log(`[schema-generator] locating service '${serviceName}'`);
|
|
185
132
|
|
|
186
|
-
const source =
|
|
187
|
-
findServiceInProject(serviceName) ?? findServiceInNodeModules(serviceName) ?? findServiceOnGitHub(serviceName);
|
|
133
|
+
const source = findServiceInProject(serviceName) ?? findServiceInNodeModules(serviceName);
|
|
188
134
|
if (source === null) {
|
|
189
|
-
log(
|
|
135
|
+
log(
|
|
136
|
+
`[schema-generator] '${serviceName}' not found — ensure it is listed as a devDependency or the repo is accessible via git`,
|
|
137
|
+
);
|
|
190
138
|
return [];
|
|
191
139
|
}
|
|
192
140
|
|
|
141
|
+
log(`[schema-generator] found '${serviceName}' (${source.endpoints.length.toString()} endpoint(s))`);
|
|
142
|
+
|
|
193
143
|
const results: { schema: ApiSchemas; endpoint: string }[] = [];
|
|
194
144
|
for (const { path: endpoint, yamlContent } of source.endpoints) {
|
|
195
145
|
try {
|
|
@@ -205,10 +155,12 @@ export function generateSchemasForService(
|
|
|
205
155
|
const dir = `${outputDir}/${versionFolder}`;
|
|
206
156
|
mkdirSync(dir, { recursive: true });
|
|
207
157
|
writeFileSync(`${dir}/${SWAGGER_SCHEMA_DEREF_FILENAME}`, JSON.stringify(schema, undefined, 2));
|
|
208
|
-
log(`cached schema to ${dir}/${SWAGGER_SCHEMA_DEREF_FILENAME}`);
|
|
158
|
+
log(`[schema-generator] cached schema to ${dir}/${SWAGGER_SCHEMA_DEREF_FILENAME}`);
|
|
209
159
|
}
|
|
210
160
|
} catch (error) {
|
|
211
|
-
log(
|
|
161
|
+
log(
|
|
162
|
+
`[schema-generator] error processing endpoint ${endpoint}: ${error instanceof Error ? error.message : String(error)}`,
|
|
163
|
+
);
|
|
212
164
|
}
|
|
213
165
|
}
|
|
214
166
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"put": {
|
|
6
6
|
"request": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
8
|
-
"$id": "https://
|
|
8
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/api/InterchangePutRequestContext",
|
|
9
9
|
"type": "object",
|
|
10
10
|
"properties": {
|
|
11
11
|
"params": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"body": {
|
|
33
33
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
34
|
-
"$id": "https://
|
|
34
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Interchange",
|
|
35
35
|
"type": "object",
|
|
36
36
|
"additionalProperties": false,
|
|
37
37
|
"description": "Data that describes an interchange record.",
|
|
@@ -281,7 +281,7 @@
|
|
|
281
281
|
"allOf": [
|
|
282
282
|
{
|
|
283
283
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
284
|
-
"$id": "https://
|
|
284
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Amount",
|
|
285
285
|
"type": "object",
|
|
286
286
|
"additionalProperties": false,
|
|
287
287
|
"required": ["amount", "currency"],
|
|
@@ -308,7 +308,7 @@
|
|
|
308
308
|
"allOf": [
|
|
309
309
|
{
|
|
310
310
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
311
|
-
"$id": "https://
|
|
311
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Amount",
|
|
312
312
|
"type": "object",
|
|
313
313
|
"additionalProperties": false,
|
|
314
314
|
"required": ["amount", "currency"],
|
|
@@ -354,7 +354,7 @@
|
|
|
354
354
|
"responses": {
|
|
355
355
|
"204": {
|
|
356
356
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
357
|
-
"$id": "https://
|
|
357
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/api/InterchangePutResponseNoContent",
|
|
358
358
|
"type": "object",
|
|
359
359
|
"properties": {
|
|
360
360
|
"headers": {
|
|
@@ -368,15 +368,16 @@
|
|
|
368
368
|
"type": "string",
|
|
369
369
|
"format": "date-time"
|
|
370
370
|
}
|
|
371
|
-
}
|
|
371
|
+
},
|
|
372
|
+
"required": ["created-on", "updated-on"]
|
|
372
373
|
}
|
|
373
374
|
},
|
|
374
|
-
"required": [],
|
|
375
|
+
"required": ["headers"],
|
|
375
376
|
"additionalProperties": false
|
|
376
377
|
},
|
|
377
378
|
"default": {
|
|
378
379
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
379
|
-
"$id": "https://
|
|
380
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/api/InterchangePutResponseDefault",
|
|
380
381
|
"type": "object",
|
|
381
382
|
"properties": {
|
|
382
383
|
"headers": {
|
|
@@ -385,7 +386,7 @@
|
|
|
385
386
|
},
|
|
386
387
|
"body": {
|
|
387
388
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
388
|
-
"$id": "https://
|
|
389
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Error",
|
|
389
390
|
"type": "object",
|
|
390
391
|
"additionalProperties": false,
|
|
391
392
|
"properties": {
|
|
@@ -410,7 +411,7 @@
|
|
|
410
411
|
"definitions": {
|
|
411
412
|
"Ping": {
|
|
412
413
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
413
|
-
"$id": "https://
|
|
414
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Ping",
|
|
414
415
|
"type": "object",
|
|
415
416
|
"additionalProperties": false,
|
|
416
417
|
"required": ["serverTime"],
|
|
@@ -424,7 +425,7 @@
|
|
|
424
425
|
},
|
|
425
426
|
"Error": {
|
|
426
427
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
427
|
-
"$id": "https://
|
|
428
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Error",
|
|
428
429
|
"type": "object",
|
|
429
430
|
"additionalProperties": false,
|
|
430
431
|
"properties": {
|
|
@@ -440,7 +441,7 @@
|
|
|
440
441
|
},
|
|
441
442
|
"Interchange": {
|
|
442
443
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
443
|
-
"$id": "https://
|
|
444
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Interchange",
|
|
444
445
|
"type": "object",
|
|
445
446
|
"additionalProperties": false,
|
|
446
447
|
"description": "Data that describes an interchange record.",
|
|
@@ -690,7 +691,7 @@
|
|
|
690
691
|
"allOf": [
|
|
691
692
|
{
|
|
692
693
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
693
|
-
"$id": "https://
|
|
694
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Amount",
|
|
694
695
|
"type": "object",
|
|
695
696
|
"additionalProperties": false,
|
|
696
697
|
"required": ["amount", "currency"],
|
|
@@ -717,7 +718,7 @@
|
|
|
717
718
|
"allOf": [
|
|
718
719
|
{
|
|
719
720
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
720
|
-
"$id": "https://
|
|
721
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Amount",
|
|
721
722
|
"type": "object",
|
|
722
723
|
"additionalProperties": false,
|
|
723
724
|
"required": ["amount", "currency"],
|
|
@@ -758,7 +759,7 @@
|
|
|
758
759
|
},
|
|
759
760
|
"Amount": {
|
|
760
761
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
761
|
-
"$id": "https://
|
|
762
|
+
"$id": "https://interchange.checkdigit/interchange/v1/schemas/definitions/Amount",
|
|
762
763
|
"type": "object",
|
|
763
764
|
"additionalProperties": false,
|
|
764
765
|
"required": ["amount", "currency"],
|