zenko 0.1.6 → 0.1.7
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/cli.cjs +430 -189
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +430 -189
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +426 -188
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -10
- package/dist/index.d.ts +7 -10
- package/dist/index.mjs +426 -188
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -158,6 +158,14 @@ function formatPropertyName(name) {
|
|
|
158
158
|
return isValidJSIdentifier(name) ? name : `"${name}"`;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
// src/utils/string-utils.ts
|
|
162
|
+
function toCamelCase(str) {
|
|
163
|
+
return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
|
|
164
|
+
}
|
|
165
|
+
function capitalize(str) {
|
|
166
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
167
|
+
}
|
|
168
|
+
|
|
161
169
|
// src/utils/http-status.ts
|
|
162
170
|
var statusNameMap = {
|
|
163
171
|
"400": "badRequest",
|
|
@@ -217,14 +225,6 @@ function mapStatusToIdentifier(status) {
|
|
|
217
225
|
if (!candidate) return "unknownError";
|
|
218
226
|
return /^[a-zA-Z_$]/.test(candidate) ? candidate : `status${candidate.charAt(0).toUpperCase()}${candidate.slice(1)}`;
|
|
219
227
|
}
|
|
220
|
-
function getStatusCategory(status) {
|
|
221
|
-
if (status === "default") return "default";
|
|
222
|
-
const code = Number(status);
|
|
223
|
-
if (!Number.isInteger(code)) return "unknown";
|
|
224
|
-
if (code >= 400 && code <= 499) return "client";
|
|
225
|
-
if (code >= 500 && code <= 599) return "server";
|
|
226
|
-
return "unknown";
|
|
227
|
-
}
|
|
228
228
|
function isErrorStatus(status) {
|
|
229
229
|
if (status === "default") return true;
|
|
230
230
|
const code = Number(status);
|
|
@@ -232,6 +232,169 @@ function isErrorStatus(status) {
|
|
|
232
232
|
return code >= 400;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
// src/utils/tree-shaking.ts
|
|
236
|
+
function analyzeZenkoUsage(operations) {
|
|
237
|
+
const usage = {
|
|
238
|
+
usesHeaderFn: false,
|
|
239
|
+
usesOperationDefinition: false,
|
|
240
|
+
usesOperationErrors: false
|
|
241
|
+
};
|
|
242
|
+
if (operations.length > 0) {
|
|
243
|
+
usage.usesOperationDefinition = true;
|
|
244
|
+
}
|
|
245
|
+
for (const op of operations) {
|
|
246
|
+
if (op.requestHeaders && op.requestHeaders.length > 0) {
|
|
247
|
+
usage.usesHeaderFn = true;
|
|
248
|
+
}
|
|
249
|
+
if (op.errors && hasAnyErrors(op.errors)) {
|
|
250
|
+
usage.usesOperationErrors = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (operations.length > 0 && !usage.usesOperationErrors) {
|
|
254
|
+
const hasDefaultErrors = operations.some(
|
|
255
|
+
(op) => !op.errors || !hasAnyErrors(op.errors)
|
|
256
|
+
);
|
|
257
|
+
if (hasDefaultErrors) {
|
|
258
|
+
usage.usesOperationErrors = true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return usage;
|
|
262
|
+
}
|
|
263
|
+
function generateZenkoImport(usage, mode, helpersOutput) {
|
|
264
|
+
const types = [];
|
|
265
|
+
if (usage.usesHeaderFn) types.push("HeaderFn");
|
|
266
|
+
if (usage.usesOperationDefinition) types.push("OperationDefinition");
|
|
267
|
+
if (usage.usesOperationErrors) types.push("OperationErrors");
|
|
268
|
+
if (types.length === 0) {
|
|
269
|
+
return "";
|
|
270
|
+
}
|
|
271
|
+
const importSource = mode === "package" ? '"zenko"' : `"${helpersOutput}"`;
|
|
272
|
+
return `import type { ${types.join(", ")} } from ${importSource};`;
|
|
273
|
+
}
|
|
274
|
+
function hasAnyErrors(errors) {
|
|
275
|
+
return Boolean(errors && Object.keys(errors).length > 0);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/utils/collect-inline-types.ts
|
|
279
|
+
function collectInlineRequestTypes(operations, spec) {
|
|
280
|
+
const requestTypesToGenerate = /* @__PURE__ */ new Map();
|
|
281
|
+
const operationLookup = /* @__PURE__ */ new Map();
|
|
282
|
+
for (const [, pathItem] of Object.entries(spec.paths || {})) {
|
|
283
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
284
|
+
const op = operation;
|
|
285
|
+
if (op.operationId) {
|
|
286
|
+
operationLookup.set(op.operationId, op);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
|
|
291
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
292
|
+
const op = operation;
|
|
293
|
+
if (op.operationId) {
|
|
294
|
+
operationLookup.set(op.operationId, op);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
for (const op of operations) {
|
|
299
|
+
const operation = operationLookup.get(op.operationId);
|
|
300
|
+
if (!operation) continue;
|
|
301
|
+
const requestBody = operation.requestBody;
|
|
302
|
+
if (requestBody && requestBody.content) {
|
|
303
|
+
const content = requestBody.content;
|
|
304
|
+
const jsonContent = content["application/json"];
|
|
305
|
+
if (jsonContent && jsonContent.schema) {
|
|
306
|
+
const schema = jsonContent.schema;
|
|
307
|
+
const typeName = `${capitalize(toCamelCase(op.operationId))}Request`;
|
|
308
|
+
if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
309
|
+
requestTypesToGenerate.set(typeName, schema);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return requestTypesToGenerate;
|
|
315
|
+
}
|
|
316
|
+
function collectInlineResponseTypes(operations, spec) {
|
|
317
|
+
const responseTypesToGenerate = /* @__PURE__ */ new Map();
|
|
318
|
+
const operationLookup = /* @__PURE__ */ new Map();
|
|
319
|
+
for (const [, pathItem] of Object.entries(spec.paths || {})) {
|
|
320
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
321
|
+
const op = operation;
|
|
322
|
+
if (op.operationId) {
|
|
323
|
+
operationLookup.set(op.operationId, op);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
|
|
328
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
329
|
+
const op = operation;
|
|
330
|
+
if (op.operationId) {
|
|
331
|
+
operationLookup.set(op.operationId, op);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
for (const op of operations) {
|
|
336
|
+
const operation = operationLookup.get(op.operationId);
|
|
337
|
+
if (!operation) continue;
|
|
338
|
+
const responses = operation.responses || {};
|
|
339
|
+
for (const [statusCode, response] of Object.entries(responses)) {
|
|
340
|
+
if (/^2\d\d$/.test(statusCode) && response.content) {
|
|
341
|
+
const content = response.content;
|
|
342
|
+
const jsonContent = content["application/json"];
|
|
343
|
+
if (jsonContent && jsonContent.schema) {
|
|
344
|
+
const schema = jsonContent.schema;
|
|
345
|
+
const typeName = `${capitalize(toCamelCase(op.operationId))}Response`;
|
|
346
|
+
if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
347
|
+
responseTypesToGenerate.set(typeName, schema);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return responseTypesToGenerate;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// src/utils/generate-helper-file.ts
|
|
357
|
+
function generateHelperFile() {
|
|
358
|
+
const output = [];
|
|
359
|
+
output.push("// Generated helper types for Zenko");
|
|
360
|
+
output.push(
|
|
361
|
+
"// This file provides type definitions for operation objects and path functions"
|
|
362
|
+
);
|
|
363
|
+
output.push("");
|
|
364
|
+
output.push(
|
|
365
|
+
"export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
|
|
366
|
+
);
|
|
367
|
+
output.push("");
|
|
368
|
+
output.push(
|
|
369
|
+
'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
|
|
370
|
+
);
|
|
371
|
+
output.push("");
|
|
372
|
+
output.push(
|
|
373
|
+
"export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
|
|
374
|
+
);
|
|
375
|
+
output.push("");
|
|
376
|
+
output.push(
|
|
377
|
+
"export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
|
|
378
|
+
);
|
|
379
|
+
output.push("");
|
|
380
|
+
output.push(
|
|
381
|
+
"export type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
|
|
382
|
+
);
|
|
383
|
+
output.push("");
|
|
384
|
+
output.push(
|
|
385
|
+
"export type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
|
|
386
|
+
);
|
|
387
|
+
output.push(" method: TMethod");
|
|
388
|
+
output.push(" path: TPath");
|
|
389
|
+
output.push(" request?: TRequest");
|
|
390
|
+
output.push(" response?: TResponse");
|
|
391
|
+
output.push(" headers?: THeaders");
|
|
392
|
+
output.push(" errors?: TErrors");
|
|
393
|
+
output.push("}");
|
|
394
|
+
output.push("");
|
|
395
|
+
return output.join("\n");
|
|
396
|
+
}
|
|
397
|
+
|
|
235
398
|
// src/zenko.ts
|
|
236
399
|
function generateWithMetadata(spec, options = {}) {
|
|
237
400
|
const output = [];
|
|
@@ -243,7 +406,14 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
243
406
|
strictNumeric
|
|
244
407
|
};
|
|
245
408
|
output.push('import { z } from "zod";');
|
|
246
|
-
|
|
409
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
410
|
+
if (spec.components?.schemas) {
|
|
411
|
+
for (const name of Object.keys(spec.components.schemas)) {
|
|
412
|
+
nameMap.set(name, toCamelCase(name));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
const operations = parseOperations(spec, nameMap);
|
|
416
|
+
appendHelperTypesImport(output, typesConfig, operations);
|
|
247
417
|
output.push("");
|
|
248
418
|
if (spec.components?.schemas) {
|
|
249
419
|
output.push("// Generated Zod Schemas");
|
|
@@ -251,15 +421,23 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
251
421
|
const sortedSchemas = topologicalSort(spec.components.schemas);
|
|
252
422
|
for (const name of sortedSchemas) {
|
|
253
423
|
const schema = spec.components.schemas[name];
|
|
424
|
+
const sanitizedName = nameMap.get(name);
|
|
254
425
|
output.push(
|
|
255
|
-
generateZodSchema(
|
|
426
|
+
generateZodSchema(
|
|
427
|
+
sanitizedName,
|
|
428
|
+
schema,
|
|
429
|
+
generatedTypes,
|
|
430
|
+
schemaOptions,
|
|
431
|
+
nameMap
|
|
432
|
+
)
|
|
256
433
|
);
|
|
257
434
|
output.push("");
|
|
258
|
-
output.push(
|
|
435
|
+
output.push(
|
|
436
|
+
`export type ${sanitizedName} = z.infer<typeof ${sanitizedName}>;`
|
|
437
|
+
);
|
|
259
438
|
output.push("");
|
|
260
439
|
}
|
|
261
440
|
}
|
|
262
|
-
const operations = parseOperations(spec);
|
|
263
441
|
output.push("// Path Functions");
|
|
264
442
|
output.push("export const paths = {");
|
|
265
443
|
for (const op of operations) {
|
|
@@ -273,24 +451,37 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
273
451
|
);
|
|
274
452
|
continue;
|
|
275
453
|
}
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
454
|
+
const alias = (n) => {
|
|
455
|
+
if (isValidJSIdentifier(n)) return n;
|
|
456
|
+
let aliased = toCamelCase(n);
|
|
457
|
+
if (!isValidJSIdentifier(aliased)) {
|
|
458
|
+
aliased = `_${aliased}`;
|
|
459
|
+
}
|
|
460
|
+
return aliased;
|
|
461
|
+
};
|
|
462
|
+
const destructPieces = [];
|
|
463
|
+
const typePieces = [];
|
|
281
464
|
for (const param of op.pathParams) {
|
|
282
|
-
|
|
465
|
+
destructPieces.push(
|
|
466
|
+
isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
|
|
467
|
+
);
|
|
468
|
+
typePieces.push(`${formatPropertyName(param.name)}: string`);
|
|
283
469
|
}
|
|
284
470
|
for (const param of op.queryParams) {
|
|
285
|
-
|
|
286
|
-
|
|
471
|
+
destructPieces.push(
|
|
472
|
+
isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
|
|
473
|
+
);
|
|
474
|
+
typePieces.push(
|
|
475
|
+
`${formatPropertyName(param.name)}${param.required ? "" : "?"}: ${mapQueryType(param)}`
|
|
287
476
|
);
|
|
288
477
|
}
|
|
289
|
-
const signatureParams = signaturePieces.join(", ");
|
|
290
478
|
const needsDefaultObject = !hasPathParams && hasQueryParams && op.queryParams.every((param) => !param.required);
|
|
291
|
-
const signatureArgs =
|
|
292
|
-
const signature = `${signatureArgs}: { ${
|
|
293
|
-
const pathWithParams = op.path.replace(
|
|
479
|
+
const signatureArgs = destructPieces.length ? `{ ${destructPieces.join(", ")} }` : "{}";
|
|
480
|
+
const signature = `${signatureArgs}: { ${typePieces.join(", ")} }${needsDefaultObject ? " = {}" : ""}`;
|
|
481
|
+
const pathWithParams = op.path.replace(
|
|
482
|
+
/{([^}]+)}/g,
|
|
483
|
+
(_m, n) => `\${${alias(n)}}`
|
|
484
|
+
);
|
|
294
485
|
if (!hasQueryParams) {
|
|
295
486
|
output.push(
|
|
296
487
|
` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => \`${pathWithParams}\`,`
|
|
@@ -302,8 +493,7 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
302
493
|
);
|
|
303
494
|
output.push(" const params = new URLSearchParams()");
|
|
304
495
|
for (const param of op.queryParams) {
|
|
305
|
-
const
|
|
306
|
-
const accessor = isValidJSIdentifier(param.name) ? param.name : propertyKey;
|
|
496
|
+
const accessor = isValidJSIdentifier(param.name) ? param.name : alias(toCamelCase(param.name));
|
|
307
497
|
const schema = param.schema ?? {};
|
|
308
498
|
if (schema?.type === "array") {
|
|
309
499
|
const itemValueExpression = convertQueryParamValue(
|
|
@@ -385,6 +575,8 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
385
575
|
}
|
|
386
576
|
output.push("} as const;");
|
|
387
577
|
output.push("");
|
|
578
|
+
generateRequestTypes(output, operations, spec, nameMap, schemaOptions);
|
|
579
|
+
generateResponseTypes(output, operations, spec, nameMap, schemaOptions);
|
|
388
580
|
generateOperationTypes(output, operations, typesConfig);
|
|
389
581
|
output.push("// Operation Objects");
|
|
390
582
|
for (const op of operations) {
|
|
@@ -398,13 +590,8 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
398
590
|
if (op.requestHeaders && op.requestHeaders.length > 0) {
|
|
399
591
|
output.push(` headers: headers.${camelCaseOperationId},`);
|
|
400
592
|
}
|
|
401
|
-
if (op.errors &&
|
|
402
|
-
output
|
|
403
|
-
appendErrorGroup(output, "clientErrors", op.errors.clientErrors);
|
|
404
|
-
appendErrorGroup(output, "serverErrors", op.errors.serverErrors);
|
|
405
|
-
appendErrorGroup(output, "defaultErrors", op.errors.defaultErrors);
|
|
406
|
-
appendErrorGroup(output, "otherErrors", op.errors.otherErrors);
|
|
407
|
-
output.push(" },");
|
|
593
|
+
if (op.errors && hasAnyErrors2(op.errors)) {
|
|
594
|
+
appendErrorGroup(output, "errors", op.errors);
|
|
408
595
|
}
|
|
409
596
|
output.push("} as const;");
|
|
410
597
|
output.push("");
|
|
@@ -420,6 +607,46 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
420
607
|
}
|
|
421
608
|
return result;
|
|
422
609
|
}
|
|
610
|
+
function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
611
|
+
const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
|
|
612
|
+
if (requestTypesToGenerate.size > 0) {
|
|
613
|
+
output.push("// Generated Request Types");
|
|
614
|
+
output.push("");
|
|
615
|
+
for (const [typeName, schema] of requestTypesToGenerate) {
|
|
616
|
+
const generatedSchema = generateZodSchema(
|
|
617
|
+
typeName,
|
|
618
|
+
schema,
|
|
619
|
+
/* @__PURE__ */ new Set(),
|
|
620
|
+
schemaOptions,
|
|
621
|
+
nameMap
|
|
622
|
+
);
|
|
623
|
+
output.push(generatedSchema);
|
|
624
|
+
output.push("");
|
|
625
|
+
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
626
|
+
output.push("");
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
631
|
+
const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
|
|
632
|
+
if (responseTypesToGenerate.size > 0) {
|
|
633
|
+
output.push("// Generated Response Types");
|
|
634
|
+
output.push("");
|
|
635
|
+
for (const [typeName, schema] of responseTypesToGenerate) {
|
|
636
|
+
const generatedSchema = generateZodSchema(
|
|
637
|
+
typeName,
|
|
638
|
+
schema,
|
|
639
|
+
/* @__PURE__ */ new Set(),
|
|
640
|
+
schemaOptions,
|
|
641
|
+
nameMap
|
|
642
|
+
);
|
|
643
|
+
output.push(generatedSchema);
|
|
644
|
+
output.push("");
|
|
645
|
+
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
646
|
+
output.push("");
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
423
650
|
function appendOperationField(buffer, key, value) {
|
|
424
651
|
if (!value) return;
|
|
425
652
|
buffer.push(` ${key}: ${value},`);
|
|
@@ -432,13 +659,8 @@ function appendErrorGroup(buffer, label, errors) {
|
|
|
432
659
|
}
|
|
433
660
|
buffer.push(" },");
|
|
434
661
|
}
|
|
435
|
-
function
|
|
436
|
-
return
|
|
437
|
-
group.clientErrors,
|
|
438
|
-
group.serverErrors,
|
|
439
|
-
group.defaultErrors,
|
|
440
|
-
group.otherErrors
|
|
441
|
-
].some((bucket) => bucket && Object.keys(bucket).length > 0);
|
|
662
|
+
function hasAnyErrors2(group) {
|
|
663
|
+
return Boolean(group && Object.keys(group).length > 0);
|
|
442
664
|
}
|
|
443
665
|
function isRequestMethod(method) {
|
|
444
666
|
switch (method) {
|
|
@@ -485,33 +707,70 @@ function inferResponseType(contentType, statusCode) {
|
|
|
485
707
|
}
|
|
486
708
|
return "unknown";
|
|
487
709
|
}
|
|
488
|
-
function parseOperations(spec) {
|
|
710
|
+
function parseOperations(spec, nameMap) {
|
|
489
711
|
const operations = [];
|
|
490
|
-
|
|
491
|
-
for (const [
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
712
|
+
if (spec.paths) {
|
|
713
|
+
for (const [path2, pathItem] of Object.entries(spec.paths)) {
|
|
714
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
715
|
+
const normalizedMethod = method.toLowerCase();
|
|
716
|
+
if (!isRequestMethod(normalizedMethod)) continue;
|
|
717
|
+
if (!operation.operationId) continue;
|
|
718
|
+
const pathParams = extractPathParams(path2);
|
|
719
|
+
const requestType = getRequestType(operation);
|
|
720
|
+
const { successResponse, errors } = getResponseTypes(
|
|
721
|
+
operation,
|
|
722
|
+
operation.operationId,
|
|
723
|
+
nameMap
|
|
724
|
+
);
|
|
725
|
+
const resolvedParameters = collectParameters(pathItem, operation, spec);
|
|
726
|
+
const requestHeaders = getRequestHeaders(resolvedParameters);
|
|
727
|
+
const queryParams = getQueryParams(resolvedParameters);
|
|
728
|
+
operations.push({
|
|
729
|
+
operationId: operation.operationId,
|
|
730
|
+
path: path2,
|
|
731
|
+
method: normalizedMethod,
|
|
732
|
+
pathParams,
|
|
733
|
+
queryParams,
|
|
734
|
+
requestType,
|
|
735
|
+
responseType: successResponse,
|
|
736
|
+
requestHeaders,
|
|
737
|
+
errors
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
if (spec.webhooks) {
|
|
743
|
+
for (const [webhookName, webhookItem] of Object.entries(spec.webhooks)) {
|
|
744
|
+
for (const [method, operation] of Object.entries(webhookItem)) {
|
|
745
|
+
const normalizedMethod = method.toLowerCase();
|
|
746
|
+
if (!isRequestMethod(normalizedMethod)) continue;
|
|
747
|
+
if (!operation.operationId) continue;
|
|
748
|
+
const path2 = webhookName;
|
|
749
|
+
const pathParams = extractPathParams(path2);
|
|
750
|
+
const requestType = getRequestType(operation);
|
|
751
|
+
const { successResponse, errors } = getResponseTypes(
|
|
752
|
+
operation,
|
|
753
|
+
operation.operationId
|
|
754
|
+
);
|
|
755
|
+
const resolvedParameters = collectParameters(
|
|
756
|
+
webhookItem,
|
|
757
|
+
operation,
|
|
758
|
+
spec
|
|
759
|
+
);
|
|
760
|
+
const requestHeaders = getRequestHeaders(resolvedParameters);
|
|
761
|
+
const queryParams = getQueryParams(resolvedParameters);
|
|
762
|
+
operations.push({
|
|
763
|
+
operationId: operation.operationId,
|
|
764
|
+
path: path2,
|
|
765
|
+
method: normalizedMethod,
|
|
766
|
+
pathParams,
|
|
767
|
+
queryParams,
|
|
768
|
+
requestType,
|
|
769
|
+
responseType: successResponse,
|
|
770
|
+
requestHeaders,
|
|
771
|
+
errors
|
|
772
|
+
});
|
|
773
|
+
}
|
|
515
774
|
}
|
|
516
775
|
}
|
|
517
776
|
return operations;
|
|
@@ -520,21 +779,42 @@ function normalizeTypesConfig(config) {
|
|
|
520
779
|
return {
|
|
521
780
|
emit: config?.emit ?? true,
|
|
522
781
|
helpers: config?.helpers ?? "package",
|
|
523
|
-
helpersOutput: config?.helpersOutput ?? "./zenko-types"
|
|
782
|
+
helpersOutput: config?.helpersOutput ?? "./zenko-types",
|
|
783
|
+
treeShake: config?.treeShake ?? true
|
|
524
784
|
};
|
|
525
785
|
}
|
|
526
|
-
function appendHelperTypesImport(buffer, config) {
|
|
786
|
+
function appendHelperTypesImport(buffer, config, operations) {
|
|
527
787
|
if (!config.emit) return;
|
|
528
788
|
switch (config.helpers) {
|
|
529
789
|
case "package":
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
790
|
+
if (config.treeShake) {
|
|
791
|
+
const usage = analyzeZenkoUsage(operations);
|
|
792
|
+
const importStatement = generateZenkoImport(usage, "package");
|
|
793
|
+
if (importStatement) {
|
|
794
|
+
buffer.push(importStatement);
|
|
795
|
+
}
|
|
796
|
+
} else {
|
|
797
|
+
buffer.push(
|
|
798
|
+
'import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "zenko";'
|
|
799
|
+
);
|
|
800
|
+
}
|
|
533
801
|
return;
|
|
534
802
|
case "file":
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
803
|
+
if (config.treeShake) {
|
|
804
|
+
const usage = analyzeZenkoUsage(operations);
|
|
805
|
+
const importStatement = generateZenkoImport(
|
|
806
|
+
usage,
|
|
807
|
+
"file",
|
|
808
|
+
config.helpersOutput
|
|
809
|
+
);
|
|
810
|
+
if (importStatement) {
|
|
811
|
+
buffer.push(importStatement);
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
buffer.push(
|
|
815
|
+
`import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "${config.helpersOutput}";`
|
|
816
|
+
);
|
|
817
|
+
}
|
|
538
818
|
return;
|
|
539
819
|
case "inline":
|
|
540
820
|
buffer.push(
|
|
@@ -550,24 +830,19 @@ function appendHelperTypesImport(buffer, config) {
|
|
|
550
830
|
"type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown);"
|
|
551
831
|
);
|
|
552
832
|
buffer.push(
|
|
553
|
-
"type OperationErrors<
|
|
833
|
+
"type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
|
|
554
834
|
);
|
|
555
|
-
buffer.push(" clientErrors?: TClient;");
|
|
556
|
-
buffer.push(" serverErrors?: TServer;");
|
|
557
|
-
buffer.push(" defaultErrors?: TDefault;");
|
|
558
|
-
buffer.push(" otherErrors?: TOther;");
|
|
559
|
-
buffer.push("};");
|
|
560
835
|
buffer.push(
|
|
561
836
|
"type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
|
|
562
837
|
);
|
|
563
|
-
buffer.push(" method: TMethod
|
|
564
|
-
buffer.push(" path: TPath
|
|
565
|
-
buffer.push(" request?: TRequest
|
|
566
|
-
buffer.push(" response?: TResponse
|
|
567
|
-
buffer.push(" headers?: THeaders
|
|
568
|
-
buffer.push(" errors?: TErrors
|
|
569
|
-
buffer.push("}
|
|
570
|
-
|
|
838
|
+
buffer.push(" method: TMethod");
|
|
839
|
+
buffer.push(" path: TPath");
|
|
840
|
+
buffer.push(" request?: TRequest");
|
|
841
|
+
buffer.push(" response?: TResponse");
|
|
842
|
+
buffer.push(" headers?: THeaders");
|
|
843
|
+
buffer.push(" errors?: TErrors");
|
|
844
|
+
buffer.push("}");
|
|
845
|
+
buffer.push("");
|
|
571
846
|
}
|
|
572
847
|
}
|
|
573
848
|
function generateOperationTypes(buffer, operations, config) {
|
|
@@ -595,14 +870,11 @@ function generateOperationTypes(buffer, operations, config) {
|
|
|
595
870
|
}
|
|
596
871
|
}
|
|
597
872
|
function buildOperationErrorsType(errors) {
|
|
598
|
-
if (!errors || !
|
|
873
|
+
if (!errors || !hasAnyErrors2(errors)) {
|
|
599
874
|
return "OperationErrors";
|
|
600
875
|
}
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
const fallback = buildErrorBucket(errors.defaultErrors);
|
|
604
|
-
const other = buildErrorBucket(errors.otherErrors);
|
|
605
|
-
return `OperationErrors<${client}, ${server}, ${fallback}, ${other}>`;
|
|
876
|
+
const errorBucket = buildErrorBucket(errors);
|
|
877
|
+
return `OperationErrors<${errorBucket}>`;
|
|
606
878
|
}
|
|
607
879
|
function buildErrorBucket(bucket) {
|
|
608
880
|
if (!bucket || Object.keys(bucket).length === 0) {
|
|
@@ -709,10 +981,10 @@ function getRequestType(operation) {
|
|
|
709
981
|
if (requestBody.$ref) {
|
|
710
982
|
return extractRefName(requestBody.$ref);
|
|
711
983
|
}
|
|
712
|
-
const typeName = `${capitalize(operation.operationId)}Request`;
|
|
984
|
+
const typeName = `${capitalize(toCamelCase(operation.operationId))}Request`;
|
|
713
985
|
return typeName;
|
|
714
986
|
}
|
|
715
|
-
function getResponseTypes(operation, operationId) {
|
|
987
|
+
function getResponseTypes(operation, operationId, nameMap) {
|
|
716
988
|
const responses = operation.responses ?? {};
|
|
717
989
|
const successCodes = /* @__PURE__ */ new Map();
|
|
718
990
|
const errorEntries = [];
|
|
@@ -753,11 +1025,15 @@ function getResponseTypes(operation, operationId) {
|
|
|
753
1025
|
successCodes.set(statusCode, resolvedSchema);
|
|
754
1026
|
}
|
|
755
1027
|
}
|
|
756
|
-
const successResponse = selectSuccessResponse(
|
|
757
|
-
|
|
1028
|
+
const successResponse = selectSuccessResponse(
|
|
1029
|
+
successCodes,
|
|
1030
|
+
operationId,
|
|
1031
|
+
nameMap
|
|
1032
|
+
);
|
|
1033
|
+
const errors = buildErrorGroups(errorEntries, operationId, nameMap);
|
|
758
1034
|
return { successResponse, errors };
|
|
759
1035
|
}
|
|
760
|
-
function selectSuccessResponse(responses, operationId) {
|
|
1036
|
+
function selectSuccessResponse(responses, operationId, nameMap) {
|
|
761
1037
|
if (responses.size === 0) return void 0;
|
|
762
1038
|
const preferredOrder = ["200", "201", "204"];
|
|
763
1039
|
for (const code of preferredOrder) {
|
|
@@ -768,61 +1044,51 @@ function selectSuccessResponse(responses, operationId) {
|
|
|
768
1044
|
}
|
|
769
1045
|
return resolveResponseType(
|
|
770
1046
|
schema,
|
|
771
|
-
`${capitalize(operationId)}Response
|
|
1047
|
+
`${capitalize(toCamelCase(operationId))}Response`,
|
|
1048
|
+
nameMap
|
|
772
1049
|
);
|
|
773
1050
|
}
|
|
774
1051
|
}
|
|
775
|
-
const [
|
|
1052
|
+
const [, firstSchema] = responses.entries().next().value ?? [];
|
|
776
1053
|
if (!firstSchema) return void 0;
|
|
777
1054
|
if (typeof firstSchema === "string") {
|
|
778
1055
|
return firstSchema;
|
|
779
1056
|
}
|
|
780
1057
|
return resolveResponseType(
|
|
781
1058
|
firstSchema,
|
|
782
|
-
`${capitalize(operationId)}Response
|
|
1059
|
+
`${capitalize(toCamelCase(operationId))}Response`,
|
|
1060
|
+
nameMap
|
|
783
1061
|
);
|
|
784
1062
|
}
|
|
785
|
-
function buildErrorGroups(errors = [], operationId) {
|
|
1063
|
+
function buildErrorGroups(errors = [], operationId, nameMap) {
|
|
786
1064
|
if (!errors.length) return void 0;
|
|
787
1065
|
const group = {};
|
|
788
1066
|
for (const { code, schema } of errors) {
|
|
789
|
-
const category = getStatusCategory(code);
|
|
790
1067
|
const identifier = mapStatusToIdentifier(code);
|
|
791
1068
|
const typeName = resolveResponseType(
|
|
792
1069
|
schema,
|
|
793
|
-
`${capitalize(operationId)}${capitalize(identifier)}
|
|
1070
|
+
`${capitalize(toCamelCase(operationId))}${capitalize(identifier)}`,
|
|
1071
|
+
nameMap
|
|
794
1072
|
);
|
|
795
|
-
|
|
796
|
-
case "client":
|
|
797
|
-
group.clientErrors ??= {};
|
|
798
|
-
group.clientErrors[identifier] = typeName;
|
|
799
|
-
break;
|
|
800
|
-
case "server":
|
|
801
|
-
group.serverErrors ??= {};
|
|
802
|
-
group.serverErrors[identifier] = typeName;
|
|
803
|
-
break;
|
|
804
|
-
case "default":
|
|
805
|
-
group.defaultErrors ??= {};
|
|
806
|
-
group.defaultErrors[identifier] = typeName;
|
|
807
|
-
break;
|
|
808
|
-
default:
|
|
809
|
-
group.otherErrors ??= {};
|
|
810
|
-
group.otherErrors[identifier] = typeName;
|
|
811
|
-
break;
|
|
812
|
-
}
|
|
1073
|
+
group[identifier] = typeName;
|
|
813
1074
|
}
|
|
814
1075
|
return group;
|
|
815
1076
|
}
|
|
816
|
-
function resolveResponseType(schema, fallbackName) {
|
|
1077
|
+
function resolveResponseType(schema, fallbackName, nameMap) {
|
|
817
1078
|
if (typeof schema === "string") {
|
|
818
1079
|
return schema;
|
|
819
1080
|
}
|
|
820
1081
|
if (schema.$ref) {
|
|
821
|
-
|
|
1082
|
+
const refName = extractRefName(schema.$ref);
|
|
1083
|
+
return nameMap?.get(refName) || refName;
|
|
822
1084
|
}
|
|
823
1085
|
if (schema.type === "array" && schema.items?.$ref) {
|
|
824
1086
|
const itemRef = extractRefName(schema.items.$ref);
|
|
825
|
-
|
|
1087
|
+
const sanitizedItemRef = nameMap?.get(itemRef) || itemRef;
|
|
1088
|
+
return `z.array(${sanitizedItemRef})`;
|
|
1089
|
+
}
|
|
1090
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1091
|
+
return fallbackName;
|
|
826
1092
|
}
|
|
827
1093
|
return fallbackName;
|
|
828
1094
|
}
|
|
@@ -905,19 +1171,30 @@ function convertQueryParamValue(schema, accessor) {
|
|
|
905
1171
|
return `String(${accessor})`;
|
|
906
1172
|
}
|
|
907
1173
|
}
|
|
908
|
-
function generateZodSchema(name, schema, generatedTypes, options) {
|
|
1174
|
+
function generateZodSchema(name, schema, generatedTypes, options, nameMap) {
|
|
909
1175
|
if (generatedTypes.has(name)) return "";
|
|
910
1176
|
generatedTypes.add(name);
|
|
911
1177
|
if (schema.enum) {
|
|
912
1178
|
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
913
1179
|
return `export const ${name} = z.enum([${enumValues}]);`;
|
|
914
1180
|
}
|
|
1181
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1182
|
+
const allOfParts = schema.allOf.map(
|
|
1183
|
+
(part) => getZodTypeFromSchema(part, options, nameMap)
|
|
1184
|
+
);
|
|
1185
|
+
if (allOfParts.length === 0) return `export const ${name} = z.object({});`;
|
|
1186
|
+
if (allOfParts.length === 1)
|
|
1187
|
+
return `export const ${name} = ${allOfParts[0]};`;
|
|
1188
|
+
const first = allOfParts[0];
|
|
1189
|
+
const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
|
|
1190
|
+
return `export const ${name} = ${first}${rest};`;
|
|
1191
|
+
}
|
|
915
1192
|
if (schema.type === "object" || schema.properties) {
|
|
916
|
-
return `export const ${name} = ${buildZodObject(schema, options)};`;
|
|
1193
|
+
return `export const ${name} = ${buildZodObject(schema, options, nameMap)};`;
|
|
917
1194
|
}
|
|
918
1195
|
if (schema.type === "array") {
|
|
919
1196
|
const itemSchema = schema.items ?? { type: "unknown" };
|
|
920
|
-
const itemType = getZodTypeFromSchema(itemSchema, options);
|
|
1197
|
+
const itemType = getZodTypeFromSchema(itemSchema, options, nameMap);
|
|
921
1198
|
const builder = applyStrictArrayBounds(
|
|
922
1199
|
schema,
|
|
923
1200
|
`z.array(${itemType})`,
|
|
@@ -926,18 +1203,29 @@ function generateZodSchema(name, schema, generatedTypes, options) {
|
|
|
926
1203
|
);
|
|
927
1204
|
return `export const ${name} = ${builder};`;
|
|
928
1205
|
}
|
|
929
|
-
return `export const ${name} = ${getZodTypeFromSchema(schema, options)};`;
|
|
1206
|
+
return `export const ${name} = ${getZodTypeFromSchema(schema, options, nameMap)};`;
|
|
930
1207
|
}
|
|
931
|
-
function getZodTypeFromSchema(schema, options) {
|
|
1208
|
+
function getZodTypeFromSchema(schema, options, nameMap) {
|
|
932
1209
|
if (schema.$ref) {
|
|
933
|
-
|
|
1210
|
+
const refName = extractRefName(schema.$ref);
|
|
1211
|
+
return nameMap?.get(refName) || refName;
|
|
934
1212
|
}
|
|
935
1213
|
if (schema.enum) {
|
|
936
1214
|
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
937
1215
|
return `z.enum([${enumValues}])`;
|
|
938
1216
|
}
|
|
939
|
-
if (schema.
|
|
940
|
-
|
|
1217
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1218
|
+
const allOfParts = schema.allOf.map(
|
|
1219
|
+
(part) => getZodTypeFromSchema(part, options, nameMap)
|
|
1220
|
+
);
|
|
1221
|
+
if (allOfParts.length === 0) return "z.object({})";
|
|
1222
|
+
if (allOfParts.length === 1) return allOfParts[0];
|
|
1223
|
+
const first = allOfParts[0];
|
|
1224
|
+
const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
|
|
1225
|
+
return `${first}${rest}`;
|
|
1226
|
+
}
|
|
1227
|
+
if (schema.type === "object" || schema.properties || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
1228
|
+
return buildZodObject(schema, options, nameMap);
|
|
941
1229
|
}
|
|
942
1230
|
switch (schema.type) {
|
|
943
1231
|
case "string":
|
|
@@ -947,7 +1235,8 @@ function getZodTypeFromSchema(schema, options) {
|
|
|
947
1235
|
case "array":
|
|
948
1236
|
return `z.array(${getZodTypeFromSchema(
|
|
949
1237
|
schema.items ?? { type: "unknown" },
|
|
950
|
-
options
|
|
1238
|
+
options,
|
|
1239
|
+
nameMap
|
|
951
1240
|
)})`;
|
|
952
1241
|
case "null":
|
|
953
1242
|
return "z.null()";
|
|
@@ -959,13 +1248,13 @@ function getZodTypeFromSchema(schema, options) {
|
|
|
959
1248
|
return "z.unknown()";
|
|
960
1249
|
}
|
|
961
1250
|
}
|
|
962
|
-
function buildZodObject(schema, options) {
|
|
1251
|
+
function buildZodObject(schema, options, nameMap) {
|
|
963
1252
|
const properties = [];
|
|
964
1253
|
for (const [propName, propSchema] of Object.entries(
|
|
965
1254
|
schema.properties || {}
|
|
966
1255
|
)) {
|
|
967
1256
|
const isRequired = schema.required?.includes(propName) ?? false;
|
|
968
|
-
const zodType = getZodTypeFromSchema(propSchema, options);
|
|
1257
|
+
const zodType = getZodTypeFromSchema(propSchema, options, nameMap);
|
|
969
1258
|
const finalType = isRequired ? zodType : `${zodType}.optional()`;
|
|
970
1259
|
properties.push(` ${formatPropertyName(propName)}: ${finalType},`);
|
|
971
1260
|
}
|
|
@@ -1073,57 +1362,6 @@ function applyNumericBounds(schema, builder) {
|
|
|
1073
1362
|
}
|
|
1074
1363
|
return builder;
|
|
1075
1364
|
}
|
|
1076
|
-
function generateHelperFile() {
|
|
1077
|
-
const output = [];
|
|
1078
|
-
output.push("// Generated helper types for Zenko");
|
|
1079
|
-
output.push(
|
|
1080
|
-
"// This file provides type definitions for operation objects and path functions"
|
|
1081
|
-
);
|
|
1082
|
-
output.push("");
|
|
1083
|
-
output.push(
|
|
1084
|
-
"export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
|
|
1085
|
-
);
|
|
1086
|
-
output.push("");
|
|
1087
|
-
output.push(
|
|
1088
|
-
'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
|
|
1089
|
-
);
|
|
1090
|
-
output.push("");
|
|
1091
|
-
output.push(
|
|
1092
|
-
"export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
|
|
1093
|
-
);
|
|
1094
|
-
output.push("");
|
|
1095
|
-
output.push(
|
|
1096
|
-
"export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
|
|
1097
|
-
);
|
|
1098
|
-
output.push("");
|
|
1099
|
-
output.push(
|
|
1100
|
-
"export type OperationErrors<TClient = unknown, TServer = unknown, TDefault = unknown, TOther = unknown> = {"
|
|
1101
|
-
);
|
|
1102
|
-
output.push(" clientErrors?: TClient");
|
|
1103
|
-
output.push(" serverErrors?: TServer");
|
|
1104
|
-
output.push(" defaultErrors?: TDefault");
|
|
1105
|
-
output.push(" otherErrors?: TOther");
|
|
1106
|
-
output.push("}");
|
|
1107
|
-
output.push("");
|
|
1108
|
-
output.push(
|
|
1109
|
-
"export type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
|
|
1110
|
-
);
|
|
1111
|
-
output.push(" method: TMethod");
|
|
1112
|
-
output.push(" path: TPath");
|
|
1113
|
-
output.push(" request?: TRequest");
|
|
1114
|
-
output.push(" response?: TResponse");
|
|
1115
|
-
output.push(" headers?: THeaders");
|
|
1116
|
-
output.push(" errors?: TErrors");
|
|
1117
|
-
output.push("}");
|
|
1118
|
-
output.push("");
|
|
1119
|
-
return output.join("\n");
|
|
1120
|
-
}
|
|
1121
|
-
function toCamelCase(str) {
|
|
1122
|
-
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1123
|
-
}
|
|
1124
|
-
function capitalize(str) {
|
|
1125
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1126
|
-
}
|
|
1127
1365
|
|
|
1128
1366
|
// src/cli.ts
|
|
1129
1367
|
async function main() {
|
|
@@ -1290,7 +1528,10 @@ async function generateSingle(options) {
|
|
|
1290
1528
|
fs.mkdirSync(path.dirname(resolvedOutput), { recursive: true });
|
|
1291
1529
|
fs.writeFileSync(resolvedOutput, result.output);
|
|
1292
1530
|
console.log(`\u2705 Generated TypeScript types in ${resolvedOutput}`);
|
|
1293
|
-
console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths).length} paths`);
|
|
1531
|
+
console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths || {}).length} paths`);
|
|
1532
|
+
if (spec.webhooks) {
|
|
1533
|
+
console.log(`\u{1FA9D} Processed ${Object.keys(spec.webhooks).length} webhooks`);
|
|
1534
|
+
}
|
|
1294
1535
|
if (result.helperFile) {
|
|
1295
1536
|
const helperPath = path.isAbsolute(result.helperFile.path) ? result.helperFile.path : path.resolve(path.dirname(resolvedOutput), result.helperFile.path);
|
|
1296
1537
|
const absoluteResolvedOutput = path.resolve(resolvedOutput);
|