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.mjs
CHANGED
|
@@ -135,6 +135,14 @@ function formatPropertyName(name) {
|
|
|
135
135
|
return isValidJSIdentifier(name) ? name : `"${name}"`;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
// src/utils/string-utils.ts
|
|
139
|
+
function toCamelCase(str) {
|
|
140
|
+
return str.replace(/-([a-zA-Z])/g, (_, letter) => letter.toUpperCase()).replace(/-+$/, "");
|
|
141
|
+
}
|
|
142
|
+
function capitalize(str) {
|
|
143
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
138
146
|
// src/utils/http-status.ts
|
|
139
147
|
var statusNameMap = {
|
|
140
148
|
"400": "badRequest",
|
|
@@ -194,14 +202,6 @@ function mapStatusToIdentifier(status) {
|
|
|
194
202
|
if (!candidate) return "unknownError";
|
|
195
203
|
return /^[a-zA-Z_$]/.test(candidate) ? candidate : `status${candidate.charAt(0).toUpperCase()}${candidate.slice(1)}`;
|
|
196
204
|
}
|
|
197
|
-
function getStatusCategory(status) {
|
|
198
|
-
if (status === "default") return "default";
|
|
199
|
-
const code = Number(status);
|
|
200
|
-
if (!Number.isInteger(code)) return "unknown";
|
|
201
|
-
if (code >= 400 && code <= 499) return "client";
|
|
202
|
-
if (code >= 500 && code <= 599) return "server";
|
|
203
|
-
return "unknown";
|
|
204
|
-
}
|
|
205
205
|
function isErrorStatus(status) {
|
|
206
206
|
if (status === "default") return true;
|
|
207
207
|
const code = Number(status);
|
|
@@ -209,6 +209,169 @@ function isErrorStatus(status) {
|
|
|
209
209
|
return code >= 400;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// src/utils/tree-shaking.ts
|
|
213
|
+
function analyzeZenkoUsage(operations) {
|
|
214
|
+
const usage = {
|
|
215
|
+
usesHeaderFn: false,
|
|
216
|
+
usesOperationDefinition: false,
|
|
217
|
+
usesOperationErrors: false
|
|
218
|
+
};
|
|
219
|
+
if (operations.length > 0) {
|
|
220
|
+
usage.usesOperationDefinition = true;
|
|
221
|
+
}
|
|
222
|
+
for (const op of operations) {
|
|
223
|
+
if (op.requestHeaders && op.requestHeaders.length > 0) {
|
|
224
|
+
usage.usesHeaderFn = true;
|
|
225
|
+
}
|
|
226
|
+
if (op.errors && hasAnyErrors(op.errors)) {
|
|
227
|
+
usage.usesOperationErrors = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (operations.length > 0 && !usage.usesOperationErrors) {
|
|
231
|
+
const hasDefaultErrors = operations.some(
|
|
232
|
+
(op) => !op.errors || !hasAnyErrors(op.errors)
|
|
233
|
+
);
|
|
234
|
+
if (hasDefaultErrors) {
|
|
235
|
+
usage.usesOperationErrors = true;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return usage;
|
|
239
|
+
}
|
|
240
|
+
function generateZenkoImport(usage, mode, helpersOutput) {
|
|
241
|
+
const types = [];
|
|
242
|
+
if (usage.usesHeaderFn) types.push("HeaderFn");
|
|
243
|
+
if (usage.usesOperationDefinition) types.push("OperationDefinition");
|
|
244
|
+
if (usage.usesOperationErrors) types.push("OperationErrors");
|
|
245
|
+
if (types.length === 0) {
|
|
246
|
+
return "";
|
|
247
|
+
}
|
|
248
|
+
const importSource = mode === "package" ? '"zenko"' : `"${helpersOutput}"`;
|
|
249
|
+
return `import type { ${types.join(", ")} } from ${importSource};`;
|
|
250
|
+
}
|
|
251
|
+
function hasAnyErrors(errors) {
|
|
252
|
+
return Boolean(errors && Object.keys(errors).length > 0);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/utils/collect-inline-types.ts
|
|
256
|
+
function collectInlineRequestTypes(operations, spec) {
|
|
257
|
+
const requestTypesToGenerate = /* @__PURE__ */ new Map();
|
|
258
|
+
const operationLookup = /* @__PURE__ */ new Map();
|
|
259
|
+
for (const [, pathItem] of Object.entries(spec.paths || {})) {
|
|
260
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
261
|
+
const op = operation;
|
|
262
|
+
if (op.operationId) {
|
|
263
|
+
operationLookup.set(op.operationId, op);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
|
|
268
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
269
|
+
const op = operation;
|
|
270
|
+
if (op.operationId) {
|
|
271
|
+
operationLookup.set(op.operationId, op);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
for (const op of operations) {
|
|
276
|
+
const operation = operationLookup.get(op.operationId);
|
|
277
|
+
if (!operation) continue;
|
|
278
|
+
const requestBody = operation.requestBody;
|
|
279
|
+
if (requestBody && requestBody.content) {
|
|
280
|
+
const content = requestBody.content;
|
|
281
|
+
const jsonContent = content["application/json"];
|
|
282
|
+
if (jsonContent && jsonContent.schema) {
|
|
283
|
+
const schema = jsonContent.schema;
|
|
284
|
+
const typeName = `${capitalize(toCamelCase(op.operationId))}Request`;
|
|
285
|
+
if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
286
|
+
requestTypesToGenerate.set(typeName, schema);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return requestTypesToGenerate;
|
|
292
|
+
}
|
|
293
|
+
function collectInlineResponseTypes(operations, spec) {
|
|
294
|
+
const responseTypesToGenerate = /* @__PURE__ */ new Map();
|
|
295
|
+
const operationLookup = /* @__PURE__ */ new Map();
|
|
296
|
+
for (const [, pathItem] of Object.entries(spec.paths || {})) {
|
|
297
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
298
|
+
const op = operation;
|
|
299
|
+
if (op.operationId) {
|
|
300
|
+
operationLookup.set(op.operationId, op);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
for (const [, pathItem] of Object.entries(spec.webhooks || {})) {
|
|
305
|
+
for (const [, operation] of Object.entries(pathItem)) {
|
|
306
|
+
const op = operation;
|
|
307
|
+
if (op.operationId) {
|
|
308
|
+
operationLookup.set(op.operationId, op);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const op of operations) {
|
|
313
|
+
const operation = operationLookup.get(op.operationId);
|
|
314
|
+
if (!operation) continue;
|
|
315
|
+
const responses = operation.responses || {};
|
|
316
|
+
for (const [statusCode, response] of Object.entries(responses)) {
|
|
317
|
+
if (/^2\d\d$/.test(statusCode) && response.content) {
|
|
318
|
+
const content = response.content;
|
|
319
|
+
const jsonContent = content["application/json"];
|
|
320
|
+
if (jsonContent && jsonContent.schema) {
|
|
321
|
+
const schema = jsonContent.schema;
|
|
322
|
+
const typeName = `${capitalize(toCamelCase(op.operationId))}Response`;
|
|
323
|
+
if (!schema.$ref || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
324
|
+
responseTypesToGenerate.set(typeName, schema);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return responseTypesToGenerate;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/utils/generate-helper-file.ts
|
|
334
|
+
function generateHelperFile() {
|
|
335
|
+
const output = [];
|
|
336
|
+
output.push("// Generated helper types for Zenko");
|
|
337
|
+
output.push(
|
|
338
|
+
"// This file provides type definitions for operation objects and path functions"
|
|
339
|
+
);
|
|
340
|
+
output.push("");
|
|
341
|
+
output.push(
|
|
342
|
+
"export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
|
|
343
|
+
);
|
|
344
|
+
output.push("");
|
|
345
|
+
output.push(
|
|
346
|
+
'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
|
|
347
|
+
);
|
|
348
|
+
output.push("");
|
|
349
|
+
output.push(
|
|
350
|
+
"export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
|
|
351
|
+
);
|
|
352
|
+
output.push("");
|
|
353
|
+
output.push(
|
|
354
|
+
"export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
|
|
355
|
+
);
|
|
356
|
+
output.push("");
|
|
357
|
+
output.push(
|
|
358
|
+
"export type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
|
|
359
|
+
);
|
|
360
|
+
output.push("");
|
|
361
|
+
output.push(
|
|
362
|
+
"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> = {"
|
|
363
|
+
);
|
|
364
|
+
output.push(" method: TMethod");
|
|
365
|
+
output.push(" path: TPath");
|
|
366
|
+
output.push(" request?: TRequest");
|
|
367
|
+
output.push(" response?: TResponse");
|
|
368
|
+
output.push(" headers?: THeaders");
|
|
369
|
+
output.push(" errors?: TErrors");
|
|
370
|
+
output.push("}");
|
|
371
|
+
output.push("");
|
|
372
|
+
return output.join("\n");
|
|
373
|
+
}
|
|
374
|
+
|
|
212
375
|
// src/zenko.ts
|
|
213
376
|
function generateWithMetadata(spec, options = {}) {
|
|
214
377
|
const output = [];
|
|
@@ -220,7 +383,14 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
220
383
|
strictNumeric
|
|
221
384
|
};
|
|
222
385
|
output.push('import { z } from "zod";');
|
|
223
|
-
|
|
386
|
+
const nameMap = /* @__PURE__ */ new Map();
|
|
387
|
+
if (spec.components?.schemas) {
|
|
388
|
+
for (const name of Object.keys(spec.components.schemas)) {
|
|
389
|
+
nameMap.set(name, toCamelCase(name));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const operations = parseOperations(spec, nameMap);
|
|
393
|
+
appendHelperTypesImport(output, typesConfig, operations);
|
|
224
394
|
output.push("");
|
|
225
395
|
if (spec.components?.schemas) {
|
|
226
396
|
output.push("// Generated Zod Schemas");
|
|
@@ -228,15 +398,23 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
228
398
|
const sortedSchemas = topologicalSort(spec.components.schemas);
|
|
229
399
|
for (const name of sortedSchemas) {
|
|
230
400
|
const schema = spec.components.schemas[name];
|
|
401
|
+
const sanitizedName = nameMap.get(name);
|
|
231
402
|
output.push(
|
|
232
|
-
generateZodSchema(
|
|
403
|
+
generateZodSchema(
|
|
404
|
+
sanitizedName,
|
|
405
|
+
schema,
|
|
406
|
+
generatedTypes,
|
|
407
|
+
schemaOptions,
|
|
408
|
+
nameMap
|
|
409
|
+
)
|
|
233
410
|
);
|
|
234
411
|
output.push("");
|
|
235
|
-
output.push(
|
|
412
|
+
output.push(
|
|
413
|
+
`export type ${sanitizedName} = z.infer<typeof ${sanitizedName}>;`
|
|
414
|
+
);
|
|
236
415
|
output.push("");
|
|
237
416
|
}
|
|
238
417
|
}
|
|
239
|
-
const operations = parseOperations(spec);
|
|
240
418
|
output.push("// Path Functions");
|
|
241
419
|
output.push("export const paths = {");
|
|
242
420
|
for (const op of operations) {
|
|
@@ -250,24 +428,37 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
250
428
|
);
|
|
251
429
|
continue;
|
|
252
430
|
}
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
431
|
+
const alias = (n) => {
|
|
432
|
+
if (isValidJSIdentifier(n)) return n;
|
|
433
|
+
let aliased = toCamelCase(n);
|
|
434
|
+
if (!isValidJSIdentifier(aliased)) {
|
|
435
|
+
aliased = `_${aliased}`;
|
|
436
|
+
}
|
|
437
|
+
return aliased;
|
|
438
|
+
};
|
|
439
|
+
const destructPieces = [];
|
|
440
|
+
const typePieces = [];
|
|
258
441
|
for (const param of op.pathParams) {
|
|
259
|
-
|
|
442
|
+
destructPieces.push(
|
|
443
|
+
isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
|
|
444
|
+
);
|
|
445
|
+
typePieces.push(`${formatPropertyName(param.name)}: string`);
|
|
260
446
|
}
|
|
261
447
|
for (const param of op.queryParams) {
|
|
262
|
-
|
|
263
|
-
|
|
448
|
+
destructPieces.push(
|
|
449
|
+
isValidJSIdentifier(param.name) ? param.name : `${formatPropertyName(param.name)}: ${alias(param.name)}`
|
|
450
|
+
);
|
|
451
|
+
typePieces.push(
|
|
452
|
+
`${formatPropertyName(param.name)}${param.required ? "" : "?"}: ${mapQueryType(param)}`
|
|
264
453
|
);
|
|
265
454
|
}
|
|
266
|
-
const signatureParams = signaturePieces.join(", ");
|
|
267
455
|
const needsDefaultObject = !hasPathParams && hasQueryParams && op.queryParams.every((param) => !param.required);
|
|
268
|
-
const signatureArgs =
|
|
269
|
-
const signature = `${signatureArgs}: { ${
|
|
270
|
-
const pathWithParams = op.path.replace(
|
|
456
|
+
const signatureArgs = destructPieces.length ? `{ ${destructPieces.join(", ")} }` : "{}";
|
|
457
|
+
const signature = `${signatureArgs}: { ${typePieces.join(", ")} }${needsDefaultObject ? " = {}" : ""}`;
|
|
458
|
+
const pathWithParams = op.path.replace(
|
|
459
|
+
/{([^}]+)}/g,
|
|
460
|
+
(_m, n) => `\${${alias(n)}}`
|
|
461
|
+
);
|
|
271
462
|
if (!hasQueryParams) {
|
|
272
463
|
output.push(
|
|
273
464
|
` ${formatPropertyName(camelCaseOperationId)}: (${signature}) => \`${pathWithParams}\`,`
|
|
@@ -279,8 +470,7 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
279
470
|
);
|
|
280
471
|
output.push(" const params = new URLSearchParams()");
|
|
281
472
|
for (const param of op.queryParams) {
|
|
282
|
-
const
|
|
283
|
-
const accessor = isValidJSIdentifier(param.name) ? param.name : propertyKey;
|
|
473
|
+
const accessor = isValidJSIdentifier(param.name) ? param.name : alias(toCamelCase(param.name));
|
|
284
474
|
const schema = param.schema ?? {};
|
|
285
475
|
if (schema?.type === "array") {
|
|
286
476
|
const itemValueExpression = convertQueryParamValue(
|
|
@@ -362,6 +552,8 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
362
552
|
}
|
|
363
553
|
output.push("} as const;");
|
|
364
554
|
output.push("");
|
|
555
|
+
generateRequestTypes(output, operations, spec, nameMap, schemaOptions);
|
|
556
|
+
generateResponseTypes(output, operations, spec, nameMap, schemaOptions);
|
|
365
557
|
generateOperationTypes(output, operations, typesConfig);
|
|
366
558
|
output.push("// Operation Objects");
|
|
367
559
|
for (const op of operations) {
|
|
@@ -375,13 +567,8 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
375
567
|
if (op.requestHeaders && op.requestHeaders.length > 0) {
|
|
376
568
|
output.push(` headers: headers.${camelCaseOperationId},`);
|
|
377
569
|
}
|
|
378
|
-
if (op.errors &&
|
|
379
|
-
output
|
|
380
|
-
appendErrorGroup(output, "clientErrors", op.errors.clientErrors);
|
|
381
|
-
appendErrorGroup(output, "serverErrors", op.errors.serverErrors);
|
|
382
|
-
appendErrorGroup(output, "defaultErrors", op.errors.defaultErrors);
|
|
383
|
-
appendErrorGroup(output, "otherErrors", op.errors.otherErrors);
|
|
384
|
-
output.push(" },");
|
|
570
|
+
if (op.errors && hasAnyErrors2(op.errors)) {
|
|
571
|
+
appendErrorGroup(output, "errors", op.errors);
|
|
385
572
|
}
|
|
386
573
|
output.push("} as const;");
|
|
387
574
|
output.push("");
|
|
@@ -397,6 +584,46 @@ function generateWithMetadata(spec, options = {}) {
|
|
|
397
584
|
}
|
|
398
585
|
return result;
|
|
399
586
|
}
|
|
587
|
+
function generateRequestTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
588
|
+
const requestTypesToGenerate = collectInlineRequestTypes(operations, spec);
|
|
589
|
+
if (requestTypesToGenerate.size > 0) {
|
|
590
|
+
output.push("// Generated Request Types");
|
|
591
|
+
output.push("");
|
|
592
|
+
for (const [typeName, schema] of requestTypesToGenerate) {
|
|
593
|
+
const generatedSchema = generateZodSchema(
|
|
594
|
+
typeName,
|
|
595
|
+
schema,
|
|
596
|
+
/* @__PURE__ */ new Set(),
|
|
597
|
+
schemaOptions,
|
|
598
|
+
nameMap
|
|
599
|
+
);
|
|
600
|
+
output.push(generatedSchema);
|
|
601
|
+
output.push("");
|
|
602
|
+
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
603
|
+
output.push("");
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function generateResponseTypes(output, operations, spec, nameMap, schemaOptions) {
|
|
608
|
+
const responseTypesToGenerate = collectInlineResponseTypes(operations, spec);
|
|
609
|
+
if (responseTypesToGenerate.size > 0) {
|
|
610
|
+
output.push("// Generated Response Types");
|
|
611
|
+
output.push("");
|
|
612
|
+
for (const [typeName, schema] of responseTypesToGenerate) {
|
|
613
|
+
const generatedSchema = generateZodSchema(
|
|
614
|
+
typeName,
|
|
615
|
+
schema,
|
|
616
|
+
/* @__PURE__ */ new Set(),
|
|
617
|
+
schemaOptions,
|
|
618
|
+
nameMap
|
|
619
|
+
);
|
|
620
|
+
output.push(generatedSchema);
|
|
621
|
+
output.push("");
|
|
622
|
+
output.push(`export type ${typeName} = z.infer<typeof ${typeName}>;`);
|
|
623
|
+
output.push("");
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
400
627
|
function appendOperationField(buffer, key, value) {
|
|
401
628
|
if (!value) return;
|
|
402
629
|
buffer.push(` ${key}: ${value},`);
|
|
@@ -409,13 +636,8 @@ function appendErrorGroup(buffer, label, errors) {
|
|
|
409
636
|
}
|
|
410
637
|
buffer.push(" },");
|
|
411
638
|
}
|
|
412
|
-
function
|
|
413
|
-
return
|
|
414
|
-
group.clientErrors,
|
|
415
|
-
group.serverErrors,
|
|
416
|
-
group.defaultErrors,
|
|
417
|
-
group.otherErrors
|
|
418
|
-
].some((bucket) => bucket && Object.keys(bucket).length > 0);
|
|
639
|
+
function hasAnyErrors2(group) {
|
|
640
|
+
return Boolean(group && Object.keys(group).length > 0);
|
|
419
641
|
}
|
|
420
642
|
function isRequestMethod(method) {
|
|
421
643
|
switch (method) {
|
|
@@ -462,33 +684,70 @@ function inferResponseType(contentType, statusCode) {
|
|
|
462
684
|
}
|
|
463
685
|
return "unknown";
|
|
464
686
|
}
|
|
465
|
-
function parseOperations(spec) {
|
|
687
|
+
function parseOperations(spec, nameMap) {
|
|
466
688
|
const operations = [];
|
|
467
|
-
|
|
468
|
-
for (const [
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
689
|
+
if (spec.paths) {
|
|
690
|
+
for (const [path2, pathItem] of Object.entries(spec.paths)) {
|
|
691
|
+
for (const [method, operation] of Object.entries(pathItem)) {
|
|
692
|
+
const normalizedMethod = method.toLowerCase();
|
|
693
|
+
if (!isRequestMethod(normalizedMethod)) continue;
|
|
694
|
+
if (!operation.operationId) continue;
|
|
695
|
+
const pathParams = extractPathParams(path2);
|
|
696
|
+
const requestType = getRequestType(operation);
|
|
697
|
+
const { successResponse, errors } = getResponseTypes(
|
|
698
|
+
operation,
|
|
699
|
+
operation.operationId,
|
|
700
|
+
nameMap
|
|
701
|
+
);
|
|
702
|
+
const resolvedParameters = collectParameters(pathItem, operation, spec);
|
|
703
|
+
const requestHeaders = getRequestHeaders(resolvedParameters);
|
|
704
|
+
const queryParams = getQueryParams(resolvedParameters);
|
|
705
|
+
operations.push({
|
|
706
|
+
operationId: operation.operationId,
|
|
707
|
+
path: path2,
|
|
708
|
+
method: normalizedMethod,
|
|
709
|
+
pathParams,
|
|
710
|
+
queryParams,
|
|
711
|
+
requestType,
|
|
712
|
+
responseType: successResponse,
|
|
713
|
+
requestHeaders,
|
|
714
|
+
errors
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
if (spec.webhooks) {
|
|
720
|
+
for (const [webhookName, webhookItem] of Object.entries(spec.webhooks)) {
|
|
721
|
+
for (const [method, operation] of Object.entries(webhookItem)) {
|
|
722
|
+
const normalizedMethod = method.toLowerCase();
|
|
723
|
+
if (!isRequestMethod(normalizedMethod)) continue;
|
|
724
|
+
if (!operation.operationId) continue;
|
|
725
|
+
const path2 = webhookName;
|
|
726
|
+
const pathParams = extractPathParams(path2);
|
|
727
|
+
const requestType = getRequestType(operation);
|
|
728
|
+
const { successResponse, errors } = getResponseTypes(
|
|
729
|
+
operation,
|
|
730
|
+
operation.operationId
|
|
731
|
+
);
|
|
732
|
+
const resolvedParameters = collectParameters(
|
|
733
|
+
webhookItem,
|
|
734
|
+
operation,
|
|
735
|
+
spec
|
|
736
|
+
);
|
|
737
|
+
const requestHeaders = getRequestHeaders(resolvedParameters);
|
|
738
|
+
const queryParams = getQueryParams(resolvedParameters);
|
|
739
|
+
operations.push({
|
|
740
|
+
operationId: operation.operationId,
|
|
741
|
+
path: path2,
|
|
742
|
+
method: normalizedMethod,
|
|
743
|
+
pathParams,
|
|
744
|
+
queryParams,
|
|
745
|
+
requestType,
|
|
746
|
+
responseType: successResponse,
|
|
747
|
+
requestHeaders,
|
|
748
|
+
errors
|
|
749
|
+
});
|
|
750
|
+
}
|
|
492
751
|
}
|
|
493
752
|
}
|
|
494
753
|
return operations;
|
|
@@ -497,21 +756,42 @@ function normalizeTypesConfig(config) {
|
|
|
497
756
|
return {
|
|
498
757
|
emit: config?.emit ?? true,
|
|
499
758
|
helpers: config?.helpers ?? "package",
|
|
500
|
-
helpersOutput: config?.helpersOutput ?? "./zenko-types"
|
|
759
|
+
helpersOutput: config?.helpersOutput ?? "./zenko-types",
|
|
760
|
+
treeShake: config?.treeShake ?? true
|
|
501
761
|
};
|
|
502
762
|
}
|
|
503
|
-
function appendHelperTypesImport(buffer, config) {
|
|
763
|
+
function appendHelperTypesImport(buffer, config, operations) {
|
|
504
764
|
if (!config.emit) return;
|
|
505
765
|
switch (config.helpers) {
|
|
506
766
|
case "package":
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
767
|
+
if (config.treeShake) {
|
|
768
|
+
const usage = analyzeZenkoUsage(operations);
|
|
769
|
+
const importStatement = generateZenkoImport(usage, "package");
|
|
770
|
+
if (importStatement) {
|
|
771
|
+
buffer.push(importStatement);
|
|
772
|
+
}
|
|
773
|
+
} else {
|
|
774
|
+
buffer.push(
|
|
775
|
+
'import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "zenko";'
|
|
776
|
+
);
|
|
777
|
+
}
|
|
510
778
|
return;
|
|
511
779
|
case "file":
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
780
|
+
if (config.treeShake) {
|
|
781
|
+
const usage = analyzeZenkoUsage(operations);
|
|
782
|
+
const importStatement = generateZenkoImport(
|
|
783
|
+
usage,
|
|
784
|
+
"file",
|
|
785
|
+
config.helpersOutput
|
|
786
|
+
);
|
|
787
|
+
if (importStatement) {
|
|
788
|
+
buffer.push(importStatement);
|
|
789
|
+
}
|
|
790
|
+
} else {
|
|
791
|
+
buffer.push(
|
|
792
|
+
`import type { PathFn, HeaderFn, OperationDefinition, OperationErrors } from "${config.helpersOutput}";`
|
|
793
|
+
);
|
|
794
|
+
}
|
|
515
795
|
return;
|
|
516
796
|
case "inline":
|
|
517
797
|
buffer.push(
|
|
@@ -527,24 +807,19 @@ function appendHelperTypesImport(buffer, config) {
|
|
|
527
807
|
"type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown);"
|
|
528
808
|
);
|
|
529
809
|
buffer.push(
|
|
530
|
-
"type OperationErrors<
|
|
810
|
+
"type OperationErrors<TError = unknown> = TError extends Record<string, unknown> ? TError : Record<string, TError>;"
|
|
531
811
|
);
|
|
532
|
-
buffer.push(" clientErrors?: TClient;");
|
|
533
|
-
buffer.push(" serverErrors?: TServer;");
|
|
534
|
-
buffer.push(" defaultErrors?: TDefault;");
|
|
535
|
-
buffer.push(" otherErrors?: TOther;");
|
|
536
|
-
buffer.push("};");
|
|
537
812
|
buffer.push(
|
|
538
813
|
"type OperationDefinition<TMethod extends RequestMethod, TPath extends (...args: any[]) => string, TRequest = undefined, TResponse = undefined, THeaders extends AnyHeaderFn | undefined = undefined, TErrors extends OperationErrors | undefined = undefined> = {"
|
|
539
814
|
);
|
|
540
|
-
buffer.push(" method: TMethod
|
|
541
|
-
buffer.push(" path: TPath
|
|
542
|
-
buffer.push(" request?: TRequest
|
|
543
|
-
buffer.push(" response?: TResponse
|
|
544
|
-
buffer.push(" headers?: THeaders
|
|
545
|
-
buffer.push(" errors?: TErrors
|
|
546
|
-
buffer.push("}
|
|
547
|
-
|
|
815
|
+
buffer.push(" method: TMethod");
|
|
816
|
+
buffer.push(" path: TPath");
|
|
817
|
+
buffer.push(" request?: TRequest");
|
|
818
|
+
buffer.push(" response?: TResponse");
|
|
819
|
+
buffer.push(" headers?: THeaders");
|
|
820
|
+
buffer.push(" errors?: TErrors");
|
|
821
|
+
buffer.push("}");
|
|
822
|
+
buffer.push("");
|
|
548
823
|
}
|
|
549
824
|
}
|
|
550
825
|
function generateOperationTypes(buffer, operations, config) {
|
|
@@ -572,14 +847,11 @@ function generateOperationTypes(buffer, operations, config) {
|
|
|
572
847
|
}
|
|
573
848
|
}
|
|
574
849
|
function buildOperationErrorsType(errors) {
|
|
575
|
-
if (!errors || !
|
|
850
|
+
if (!errors || !hasAnyErrors2(errors)) {
|
|
576
851
|
return "OperationErrors";
|
|
577
852
|
}
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
const fallback = buildErrorBucket(errors.defaultErrors);
|
|
581
|
-
const other = buildErrorBucket(errors.otherErrors);
|
|
582
|
-
return `OperationErrors<${client}, ${server}, ${fallback}, ${other}>`;
|
|
853
|
+
const errorBucket = buildErrorBucket(errors);
|
|
854
|
+
return `OperationErrors<${errorBucket}>`;
|
|
583
855
|
}
|
|
584
856
|
function buildErrorBucket(bucket) {
|
|
585
857
|
if (!bucket || Object.keys(bucket).length === 0) {
|
|
@@ -686,10 +958,10 @@ function getRequestType(operation) {
|
|
|
686
958
|
if (requestBody.$ref) {
|
|
687
959
|
return extractRefName(requestBody.$ref);
|
|
688
960
|
}
|
|
689
|
-
const typeName = `${capitalize(operation.operationId)}Request`;
|
|
961
|
+
const typeName = `${capitalize(toCamelCase(operation.operationId))}Request`;
|
|
690
962
|
return typeName;
|
|
691
963
|
}
|
|
692
|
-
function getResponseTypes(operation, operationId) {
|
|
964
|
+
function getResponseTypes(operation, operationId, nameMap) {
|
|
693
965
|
const responses = operation.responses ?? {};
|
|
694
966
|
const successCodes = /* @__PURE__ */ new Map();
|
|
695
967
|
const errorEntries = [];
|
|
@@ -730,11 +1002,15 @@ function getResponseTypes(operation, operationId) {
|
|
|
730
1002
|
successCodes.set(statusCode, resolvedSchema);
|
|
731
1003
|
}
|
|
732
1004
|
}
|
|
733
|
-
const successResponse = selectSuccessResponse(
|
|
734
|
-
|
|
1005
|
+
const successResponse = selectSuccessResponse(
|
|
1006
|
+
successCodes,
|
|
1007
|
+
operationId,
|
|
1008
|
+
nameMap
|
|
1009
|
+
);
|
|
1010
|
+
const errors = buildErrorGroups(errorEntries, operationId, nameMap);
|
|
735
1011
|
return { successResponse, errors };
|
|
736
1012
|
}
|
|
737
|
-
function selectSuccessResponse(responses, operationId) {
|
|
1013
|
+
function selectSuccessResponse(responses, operationId, nameMap) {
|
|
738
1014
|
if (responses.size === 0) return void 0;
|
|
739
1015
|
const preferredOrder = ["200", "201", "204"];
|
|
740
1016
|
for (const code of preferredOrder) {
|
|
@@ -745,61 +1021,51 @@ function selectSuccessResponse(responses, operationId) {
|
|
|
745
1021
|
}
|
|
746
1022
|
return resolveResponseType(
|
|
747
1023
|
schema,
|
|
748
|
-
`${capitalize(operationId)}Response
|
|
1024
|
+
`${capitalize(toCamelCase(operationId))}Response`,
|
|
1025
|
+
nameMap
|
|
749
1026
|
);
|
|
750
1027
|
}
|
|
751
1028
|
}
|
|
752
|
-
const [
|
|
1029
|
+
const [, firstSchema] = responses.entries().next().value ?? [];
|
|
753
1030
|
if (!firstSchema) return void 0;
|
|
754
1031
|
if (typeof firstSchema === "string") {
|
|
755
1032
|
return firstSchema;
|
|
756
1033
|
}
|
|
757
1034
|
return resolveResponseType(
|
|
758
1035
|
firstSchema,
|
|
759
|
-
`${capitalize(operationId)}Response
|
|
1036
|
+
`${capitalize(toCamelCase(operationId))}Response`,
|
|
1037
|
+
nameMap
|
|
760
1038
|
);
|
|
761
1039
|
}
|
|
762
|
-
function buildErrorGroups(errors = [], operationId) {
|
|
1040
|
+
function buildErrorGroups(errors = [], operationId, nameMap) {
|
|
763
1041
|
if (!errors.length) return void 0;
|
|
764
1042
|
const group = {};
|
|
765
1043
|
for (const { code, schema } of errors) {
|
|
766
|
-
const category = getStatusCategory(code);
|
|
767
1044
|
const identifier = mapStatusToIdentifier(code);
|
|
768
1045
|
const typeName = resolveResponseType(
|
|
769
1046
|
schema,
|
|
770
|
-
`${capitalize(operationId)}${capitalize(identifier)}
|
|
1047
|
+
`${capitalize(toCamelCase(operationId))}${capitalize(identifier)}`,
|
|
1048
|
+
nameMap
|
|
771
1049
|
);
|
|
772
|
-
|
|
773
|
-
case "client":
|
|
774
|
-
group.clientErrors ??= {};
|
|
775
|
-
group.clientErrors[identifier] = typeName;
|
|
776
|
-
break;
|
|
777
|
-
case "server":
|
|
778
|
-
group.serverErrors ??= {};
|
|
779
|
-
group.serverErrors[identifier] = typeName;
|
|
780
|
-
break;
|
|
781
|
-
case "default":
|
|
782
|
-
group.defaultErrors ??= {};
|
|
783
|
-
group.defaultErrors[identifier] = typeName;
|
|
784
|
-
break;
|
|
785
|
-
default:
|
|
786
|
-
group.otherErrors ??= {};
|
|
787
|
-
group.otherErrors[identifier] = typeName;
|
|
788
|
-
break;
|
|
789
|
-
}
|
|
1050
|
+
group[identifier] = typeName;
|
|
790
1051
|
}
|
|
791
1052
|
return group;
|
|
792
1053
|
}
|
|
793
|
-
function resolveResponseType(schema, fallbackName) {
|
|
1054
|
+
function resolveResponseType(schema, fallbackName, nameMap) {
|
|
794
1055
|
if (typeof schema === "string") {
|
|
795
1056
|
return schema;
|
|
796
1057
|
}
|
|
797
1058
|
if (schema.$ref) {
|
|
798
|
-
|
|
1059
|
+
const refName = extractRefName(schema.$ref);
|
|
1060
|
+
return nameMap?.get(refName) || refName;
|
|
799
1061
|
}
|
|
800
1062
|
if (schema.type === "array" && schema.items?.$ref) {
|
|
801
1063
|
const itemRef = extractRefName(schema.items.$ref);
|
|
802
|
-
|
|
1064
|
+
const sanitizedItemRef = nameMap?.get(itemRef) || itemRef;
|
|
1065
|
+
return `z.array(${sanitizedItemRef})`;
|
|
1066
|
+
}
|
|
1067
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1068
|
+
return fallbackName;
|
|
803
1069
|
}
|
|
804
1070
|
return fallbackName;
|
|
805
1071
|
}
|
|
@@ -882,19 +1148,30 @@ function convertQueryParamValue(schema, accessor) {
|
|
|
882
1148
|
return `String(${accessor})`;
|
|
883
1149
|
}
|
|
884
1150
|
}
|
|
885
|
-
function generateZodSchema(name, schema, generatedTypes, options) {
|
|
1151
|
+
function generateZodSchema(name, schema, generatedTypes, options, nameMap) {
|
|
886
1152
|
if (generatedTypes.has(name)) return "";
|
|
887
1153
|
generatedTypes.add(name);
|
|
888
1154
|
if (schema.enum) {
|
|
889
1155
|
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
890
1156
|
return `export const ${name} = z.enum([${enumValues}]);`;
|
|
891
1157
|
}
|
|
1158
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1159
|
+
const allOfParts = schema.allOf.map(
|
|
1160
|
+
(part) => getZodTypeFromSchema(part, options, nameMap)
|
|
1161
|
+
);
|
|
1162
|
+
if (allOfParts.length === 0) return `export const ${name} = z.object({});`;
|
|
1163
|
+
if (allOfParts.length === 1)
|
|
1164
|
+
return `export const ${name} = ${allOfParts[0]};`;
|
|
1165
|
+
const first = allOfParts[0];
|
|
1166
|
+
const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
|
|
1167
|
+
return `export const ${name} = ${first}${rest};`;
|
|
1168
|
+
}
|
|
892
1169
|
if (schema.type === "object" || schema.properties) {
|
|
893
|
-
return `export const ${name} = ${buildZodObject(schema, options)};`;
|
|
1170
|
+
return `export const ${name} = ${buildZodObject(schema, options, nameMap)};`;
|
|
894
1171
|
}
|
|
895
1172
|
if (schema.type === "array") {
|
|
896
1173
|
const itemSchema = schema.items ?? { type: "unknown" };
|
|
897
|
-
const itemType = getZodTypeFromSchema(itemSchema, options);
|
|
1174
|
+
const itemType = getZodTypeFromSchema(itemSchema, options, nameMap);
|
|
898
1175
|
const builder = applyStrictArrayBounds(
|
|
899
1176
|
schema,
|
|
900
1177
|
`z.array(${itemType})`,
|
|
@@ -903,18 +1180,29 @@ function generateZodSchema(name, schema, generatedTypes, options) {
|
|
|
903
1180
|
);
|
|
904
1181
|
return `export const ${name} = ${builder};`;
|
|
905
1182
|
}
|
|
906
|
-
return `export const ${name} = ${getZodTypeFromSchema(schema, options)};`;
|
|
1183
|
+
return `export const ${name} = ${getZodTypeFromSchema(schema, options, nameMap)};`;
|
|
907
1184
|
}
|
|
908
|
-
function getZodTypeFromSchema(schema, options) {
|
|
1185
|
+
function getZodTypeFromSchema(schema, options, nameMap) {
|
|
909
1186
|
if (schema.$ref) {
|
|
910
|
-
|
|
1187
|
+
const refName = extractRefName(schema.$ref);
|
|
1188
|
+
return nameMap?.get(refName) || refName;
|
|
911
1189
|
}
|
|
912
1190
|
if (schema.enum) {
|
|
913
1191
|
const enumValues = schema.enum.map((v) => `"${v}"`).join(", ");
|
|
914
1192
|
return `z.enum([${enumValues}])`;
|
|
915
1193
|
}
|
|
916
|
-
if (schema.
|
|
917
|
-
|
|
1194
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
1195
|
+
const allOfParts = schema.allOf.map(
|
|
1196
|
+
(part) => getZodTypeFromSchema(part, options, nameMap)
|
|
1197
|
+
);
|
|
1198
|
+
if (allOfParts.length === 0) return "z.object({})";
|
|
1199
|
+
if (allOfParts.length === 1) return allOfParts[0];
|
|
1200
|
+
const first = allOfParts[0];
|
|
1201
|
+
const rest = allOfParts.slice(1).map((part) => `.and(${part})`).join("");
|
|
1202
|
+
return `${first}${rest}`;
|
|
1203
|
+
}
|
|
1204
|
+
if (schema.type === "object" || schema.properties || schema.allOf || schema.oneOf || schema.anyOf) {
|
|
1205
|
+
return buildZodObject(schema, options, nameMap);
|
|
918
1206
|
}
|
|
919
1207
|
switch (schema.type) {
|
|
920
1208
|
case "string":
|
|
@@ -924,7 +1212,8 @@ function getZodTypeFromSchema(schema, options) {
|
|
|
924
1212
|
case "array":
|
|
925
1213
|
return `z.array(${getZodTypeFromSchema(
|
|
926
1214
|
schema.items ?? { type: "unknown" },
|
|
927
|
-
options
|
|
1215
|
+
options,
|
|
1216
|
+
nameMap
|
|
928
1217
|
)})`;
|
|
929
1218
|
case "null":
|
|
930
1219
|
return "z.null()";
|
|
@@ -936,13 +1225,13 @@ function getZodTypeFromSchema(schema, options) {
|
|
|
936
1225
|
return "z.unknown()";
|
|
937
1226
|
}
|
|
938
1227
|
}
|
|
939
|
-
function buildZodObject(schema, options) {
|
|
1228
|
+
function buildZodObject(schema, options, nameMap) {
|
|
940
1229
|
const properties = [];
|
|
941
1230
|
for (const [propName, propSchema] of Object.entries(
|
|
942
1231
|
schema.properties || {}
|
|
943
1232
|
)) {
|
|
944
1233
|
const isRequired = schema.required?.includes(propName) ?? false;
|
|
945
|
-
const zodType = getZodTypeFromSchema(propSchema, options);
|
|
1234
|
+
const zodType = getZodTypeFromSchema(propSchema, options, nameMap);
|
|
946
1235
|
const finalType = isRequired ? zodType : `${zodType}.optional()`;
|
|
947
1236
|
properties.push(` ${formatPropertyName(propName)}: ${finalType},`);
|
|
948
1237
|
}
|
|
@@ -1050,57 +1339,6 @@ function applyNumericBounds(schema, builder) {
|
|
|
1050
1339
|
}
|
|
1051
1340
|
return builder;
|
|
1052
1341
|
}
|
|
1053
|
-
function generateHelperFile() {
|
|
1054
|
-
const output = [];
|
|
1055
|
-
output.push("// Generated helper types for Zenko");
|
|
1056
|
-
output.push(
|
|
1057
|
-
"// This file provides type definitions for operation objects and path functions"
|
|
1058
|
-
);
|
|
1059
|
-
output.push("");
|
|
1060
|
-
output.push(
|
|
1061
|
-
"export type PathFn<TArgs extends unknown[] = []> = (...args: TArgs) => string"
|
|
1062
|
-
);
|
|
1063
|
-
output.push("");
|
|
1064
|
-
output.push(
|
|
1065
|
-
'export type RequestMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"'
|
|
1066
|
-
);
|
|
1067
|
-
output.push("");
|
|
1068
|
-
output.push(
|
|
1069
|
-
"export type HeaderFn<TArgs extends unknown[] = [], TResult = Record<string, unknown> | Record<string, never>> = (...args: TArgs) => TResult"
|
|
1070
|
-
);
|
|
1071
|
-
output.push("");
|
|
1072
|
-
output.push(
|
|
1073
|
-
"export type AnyHeaderFn = HeaderFn<any, unknown> | (() => unknown)"
|
|
1074
|
-
);
|
|
1075
|
-
output.push("");
|
|
1076
|
-
output.push(
|
|
1077
|
-
"export type OperationErrors<TClient = unknown, TServer = unknown, TDefault = unknown, TOther = unknown> = {"
|
|
1078
|
-
);
|
|
1079
|
-
output.push(" clientErrors?: TClient");
|
|
1080
|
-
output.push(" serverErrors?: TServer");
|
|
1081
|
-
output.push(" defaultErrors?: TDefault");
|
|
1082
|
-
output.push(" otherErrors?: TOther");
|
|
1083
|
-
output.push("}");
|
|
1084
|
-
output.push("");
|
|
1085
|
-
output.push(
|
|
1086
|
-
"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> = {"
|
|
1087
|
-
);
|
|
1088
|
-
output.push(" method: TMethod");
|
|
1089
|
-
output.push(" path: TPath");
|
|
1090
|
-
output.push(" request?: TRequest");
|
|
1091
|
-
output.push(" response?: TResponse");
|
|
1092
|
-
output.push(" headers?: THeaders");
|
|
1093
|
-
output.push(" errors?: TErrors");
|
|
1094
|
-
output.push("}");
|
|
1095
|
-
output.push("");
|
|
1096
|
-
return output.join("\n");
|
|
1097
|
-
}
|
|
1098
|
-
function toCamelCase(str) {
|
|
1099
|
-
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1100
|
-
}
|
|
1101
|
-
function capitalize(str) {
|
|
1102
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1103
|
-
}
|
|
1104
1342
|
|
|
1105
1343
|
// src/cli.ts
|
|
1106
1344
|
async function main() {
|
|
@@ -1267,7 +1505,10 @@ async function generateSingle(options) {
|
|
|
1267
1505
|
fs.mkdirSync(path.dirname(resolvedOutput), { recursive: true });
|
|
1268
1506
|
fs.writeFileSync(resolvedOutput, result.output);
|
|
1269
1507
|
console.log(`\u2705 Generated TypeScript types in ${resolvedOutput}`);
|
|
1270
|
-
console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths).length} paths`);
|
|
1508
|
+
console.log(`\u{1F4C4} Processed ${Object.keys(spec.paths || {}).length} paths`);
|
|
1509
|
+
if (spec.webhooks) {
|
|
1510
|
+
console.log(`\u{1FA9D} Processed ${Object.keys(spec.webhooks).length} webhooks`);
|
|
1511
|
+
}
|
|
1271
1512
|
if (result.helperFile) {
|
|
1272
1513
|
const helperPath = path.isAbsolute(result.helperFile.path) ? result.helperFile.path : path.resolve(path.dirname(resolvedOutput), result.helperFile.path);
|
|
1273
1514
|
const absoluteResolvedOutput = path.resolve(resolvedOutput);
|