@pikku/cli 0.12.2 → 0.12.4
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/cli.schema.json +1 -1
- package/console-app/assets/index-AX4YS8AA.js +657 -0
- package/console-app/assets/{index-0Ui5UudO.css → index-DvrDbftC.css} +1 -1
- package/console-app/index.html +2 -2
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/agent/pikku-agent-wirings-meta.gen.js +1 -1
- package/dist/.pikku/agent/pikku-agent-wirings.gen.d.ts +1 -1
- package/dist/.pikku/agent/pikku-agent-wirings.gen.js +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/channel/pikku-channels-meta.gen.js +1 -1
- package/dist/.pikku/channel/pikku-channels.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channels.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.d.ts +13 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +17 -2
- package/dist/.pikku/cli/pikku-cli-client.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-client.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +12 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +30 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +17 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +88 -88
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-wirings-meta.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-wirings.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-wirings.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +3 -1
- package/dist/.pikku/pikku-services.gen.js +2 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/pikku-websocket.gen.d.ts +1 -1
- package/dist/.pikku/pikku-websocket.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-remote-rpc-workers.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/scheduler/pikku-schedulers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-schedulers-wirings.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +3 -3
- package/dist/.pikku/schemas/schemas/ConsoleCommandInput.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuNewAddonInput.schema.json +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/src/cli.wiring.js +9 -0
- package/dist/src/functions/commands/all.js +33 -11
- package/dist/src/functions/commands/console.d.ts +3 -0
- package/dist/src/functions/commands/console.js +8 -2
- package/dist/src/functions/commands/new-addon.d.ts +3 -0
- package/dist/src/functions/commands/new-addon.js +8 -6
- package/dist/src/functions/wirings/ai-agent/serialize-public-agent.js +19 -0
- package/dist/src/functions/wirings/channels/pikku-command-channels-map.js +1 -1
- package/dist/src/functions/wirings/channels/serialize-typed-channel-map.d.ts +1 -1
- package/dist/src/functions/wirings/channels/serialize-typed-channel-map.js +7 -6
- package/dist/src/functions/wirings/cli/pikku-command-cli-entry.js +9 -1
- package/dist/src/functions/wirings/cli/serialize-channel-cli.js +35 -12
- package/dist/src/functions/wirings/console/pikku-command-node-types.js +2 -2
- package/dist/src/functions/wirings/console/pikku-command-nodes-meta.js +20 -11
- package/dist/src/functions/wirings/console/serialize-console-functions.js +1 -1
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.js +1 -1
- package/dist/src/functions/wirings/functions/serialize-addon-types.js +23 -1
- package/dist/src/functions/wirings/functions/serialize-function-types.js +38 -0
- package/dist/src/services.js +1 -1
- package/dist/src/utils/file-import-path.js +5 -2
- package/dist/src/utils/openapi/codegen.d.ts +1 -0
- package/dist/src/utils/openapi/codegen.js +214 -46
- package/dist/src/utils/openapi/parse-openapi.d.ts +25 -0
- package/dist/src/utils/openapi/parse-openapi.js +119 -9
- package/dist/src/utils/openapi/zod-codegen.d.ts +1 -53
- package/dist/src/utils/openapi/zod-codegen.js +1 -251
- package/dist/src/utils/pikku-cli-config.js +2 -2
- package/dist/src/utils/strip-verbose-meta.d.ts +2 -0
- package/dist/src/utils/strip-verbose-meta.js +34 -0
- package/package.json +4 -3
- package/console-app/assets/index-DRJQtv3c.js +0 -676
|
@@ -16,6 +16,15 @@ export async function parseOpenAPISpec(filePath) {
|
|
|
16
16
|
else {
|
|
17
17
|
doc = parseYAML(content);
|
|
18
18
|
}
|
|
19
|
+
// Validate spec version
|
|
20
|
+
const specVersion = doc.openapi ?? doc.swagger;
|
|
21
|
+
if (!specVersion) {
|
|
22
|
+
throw new Error('Not a valid OpenAPI/Swagger spec: missing "openapi" or "swagger" version field.');
|
|
23
|
+
}
|
|
24
|
+
const major = String(specVersion).split('.')[0];
|
|
25
|
+
if (major !== '2' && major !== '3') {
|
|
26
|
+
throw new Error(`Unsupported spec version "${specVersion}". Only OpenAPI 3.x and Swagger 2.x are supported.`);
|
|
27
|
+
}
|
|
19
28
|
// Resolve all $ref pointers in-place
|
|
20
29
|
resolveRefs(doc, doc);
|
|
21
30
|
const info = {
|
|
@@ -23,8 +32,11 @@ export async function parseOpenAPISpec(filePath) {
|
|
|
23
32
|
version: doc.info?.version ?? '1.0.0',
|
|
24
33
|
description: doc.info?.description,
|
|
25
34
|
};
|
|
26
|
-
const
|
|
35
|
+
const serverUrls = extractServerUrls(doc);
|
|
36
|
+
const baseUrl = serverUrls[0] ?? '';
|
|
27
37
|
const authType = detectAuthType(doc);
|
|
38
|
+
const securitySchemes = extractSecuritySchemes(doc);
|
|
39
|
+
const tagDescriptions = extractTagDescriptions(doc);
|
|
28
40
|
// Extract component schemas
|
|
29
41
|
const componentSchemas = {};
|
|
30
42
|
if (doc.components?.schemas) {
|
|
@@ -32,7 +44,7 @@ export async function parseOpenAPISpec(filePath) {
|
|
|
32
44
|
componentSchemas[name] = schema;
|
|
33
45
|
}
|
|
34
46
|
}
|
|
35
|
-
// Extract operations
|
|
47
|
+
// Extract operations (skip deprecated)
|
|
36
48
|
const operations = [];
|
|
37
49
|
if (doc.paths) {
|
|
38
50
|
for (const [path, pathItem] of Object.entries(doc.paths)) {
|
|
@@ -42,7 +54,11 @@ export async function parseOpenAPISpec(filePath) {
|
|
|
42
54
|
const op = pathItem[method];
|
|
43
55
|
if (!op)
|
|
44
56
|
continue;
|
|
57
|
+
// Skip deprecated operations
|
|
58
|
+
if (op.deprecated === true)
|
|
59
|
+
continue;
|
|
45
60
|
const allParams = [...sharedParams, ...(op.parameters ?? [])];
|
|
61
|
+
const body = op.requestBody;
|
|
46
62
|
operations.push({
|
|
47
63
|
operationId: op.operationId,
|
|
48
64
|
method,
|
|
@@ -52,14 +68,28 @@ export async function parseOpenAPISpec(filePath) {
|
|
|
52
68
|
tags: op.tags ?? [],
|
|
53
69
|
pathParams: extractParams(allParams, 'path'),
|
|
54
70
|
queryParams: extractParams(allParams, 'query'),
|
|
71
|
+
headerParams: extractParams(allParams, 'header'),
|
|
55
72
|
requestBody: extractRequestBody(op),
|
|
73
|
+
requestBodyDescription: body?.description,
|
|
74
|
+
requestBodyRequired: body?.required,
|
|
56
75
|
responseSchema: extractResponseSchema(op),
|
|
57
76
|
responseDescription: extractResponseDescription(op),
|
|
77
|
+
errorResponses: extractErrorResponses(op),
|
|
78
|
+
deprecated: false,
|
|
58
79
|
});
|
|
59
80
|
}
|
|
60
81
|
}
|
|
61
82
|
}
|
|
62
|
-
return {
|
|
83
|
+
return {
|
|
84
|
+
info,
|
|
85
|
+
baseUrl,
|
|
86
|
+
serverUrls,
|
|
87
|
+
authType,
|
|
88
|
+
operations,
|
|
89
|
+
componentSchemas,
|
|
90
|
+
securitySchemes,
|
|
91
|
+
tagDescriptions,
|
|
92
|
+
};
|
|
63
93
|
}
|
|
64
94
|
/** Recursively resolve $ref pointers in-place */
|
|
65
95
|
function resolveRefs(node, root) {
|
|
@@ -100,18 +130,18 @@ function resolveRefPath(ref, root) {
|
|
|
100
130
|
}
|
|
101
131
|
return current;
|
|
102
132
|
}
|
|
103
|
-
function
|
|
133
|
+
function extractServerUrls(doc) {
|
|
104
134
|
// OpenAPI 3.x
|
|
105
135
|
if (doc.servers && doc.servers.length > 0) {
|
|
106
|
-
return doc.servers
|
|
136
|
+
return doc.servers.map((s) => s.url).filter((url) => !!url);
|
|
107
137
|
}
|
|
108
138
|
// Swagger 2.x
|
|
109
139
|
if (doc.host) {
|
|
110
|
-
const
|
|
140
|
+
const schemes = doc.schemes?.length ? doc.schemes : ['https'];
|
|
111
141
|
const basePath = doc.basePath ?? '';
|
|
112
|
-
return `${scheme}://${doc.host}${basePath}
|
|
142
|
+
return schemes.map((scheme) => `${scheme}://${doc.host}${basePath}`);
|
|
113
143
|
}
|
|
114
|
-
return
|
|
144
|
+
return [];
|
|
115
145
|
}
|
|
116
146
|
function detectAuthType(doc) {
|
|
117
147
|
const securitySchemes = doc.components?.securitySchemes ?? doc.securityDefinitions ?? {};
|
|
@@ -125,14 +155,31 @@ function detectAuthType(doc) {
|
|
|
125
155
|
}
|
|
126
156
|
return 'none';
|
|
127
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Build an OpenAPI schema object from v2-style parameter-level properties
|
|
160
|
+
* (type, enum, items, format, default) that aren't nested under `schema`.
|
|
161
|
+
*/
|
|
162
|
+
function paramToSchema(p) {
|
|
163
|
+
const schema = { type: p.type ?? 'string' };
|
|
164
|
+
if (p.enum)
|
|
165
|
+
schema.enum = p.enum;
|
|
166
|
+
if (p.items)
|
|
167
|
+
schema.items = p.items;
|
|
168
|
+
if (p.format)
|
|
169
|
+
schema.format = p.format;
|
|
170
|
+
if (p.default !== undefined)
|
|
171
|
+
schema.default = p.default;
|
|
172
|
+
return schema;
|
|
173
|
+
}
|
|
128
174
|
function extractParams(params, location) {
|
|
129
175
|
return params
|
|
130
176
|
.filter((p) => p.in === location)
|
|
131
177
|
.map((p) => ({
|
|
132
178
|
name: p.name,
|
|
133
179
|
required: p.required ?? location === 'path',
|
|
134
|
-
schema: (p.schema ??
|
|
180
|
+
schema: (p.schema ?? paramToSchema(p)),
|
|
135
181
|
description: p.description,
|
|
182
|
+
example: p.example,
|
|
136
183
|
}));
|
|
137
184
|
}
|
|
138
185
|
function extractRequestBody(op) {
|
|
@@ -194,3 +241,66 @@ function extractResponseSchema(op) {
|
|
|
194
241
|
}
|
|
195
242
|
return undefined;
|
|
196
243
|
}
|
|
244
|
+
function extractErrorResponses(op) {
|
|
245
|
+
const responses = op.responses;
|
|
246
|
+
if (!responses)
|
|
247
|
+
return [];
|
|
248
|
+
const errors = [];
|
|
249
|
+
for (const [code, resp] of Object.entries(responses)) {
|
|
250
|
+
const statusCode = parseInt(code, 10);
|
|
251
|
+
if (isNaN(statusCode))
|
|
252
|
+
continue;
|
|
253
|
+
if (statusCode >= 400) {
|
|
254
|
+
errors.push({
|
|
255
|
+
statusCode,
|
|
256
|
+
description: resp.description ?? `Error ${statusCode}`,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return errors;
|
|
261
|
+
}
|
|
262
|
+
function extractSecuritySchemes(doc) {
|
|
263
|
+
const raw = doc.components?.securitySchemes ?? doc.securityDefinitions ?? {};
|
|
264
|
+
const result = {};
|
|
265
|
+
for (const [name, scheme] of Object.entries(raw)) {
|
|
266
|
+
const info = {
|
|
267
|
+
type: scheme.type === 'http' ? 'http' : scheme.type,
|
|
268
|
+
};
|
|
269
|
+
if (scheme.type === 'http') {
|
|
270
|
+
info.scheme = scheme.scheme;
|
|
271
|
+
info.bearerFormat = scheme.bearerFormat;
|
|
272
|
+
}
|
|
273
|
+
if (scheme.type === 'apiKey') {
|
|
274
|
+
info.name = scheme.name;
|
|
275
|
+
info.in = scheme.in;
|
|
276
|
+
}
|
|
277
|
+
if (scheme.type === 'oauth2') {
|
|
278
|
+
// Extract flows — prefer authorizationCode, then implicit, then clientCredentials
|
|
279
|
+
const flows = scheme.flows ?? {};
|
|
280
|
+
const flow = flows.authorizationCode ??
|
|
281
|
+
flows.implicit ??
|
|
282
|
+
flows.clientCredentials ??
|
|
283
|
+
flows.password;
|
|
284
|
+
if (flow) {
|
|
285
|
+
info.flows = {
|
|
286
|
+
authorizationUrl: flow.authorizationUrl,
|
|
287
|
+
tokenUrl: flow.tokenUrl,
|
|
288
|
+
scopes: flow.scopes,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
result[name] = info;
|
|
293
|
+
}
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
function extractTagDescriptions(doc) {
|
|
297
|
+
const result = {};
|
|
298
|
+
if (Array.isArray(doc.tags)) {
|
|
299
|
+
for (const tag of doc.tags) {
|
|
300
|
+
if (tag.name && tag.description) {
|
|
301
|
+
result[tag.name] = tag.description;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
@@ -1,53 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Converts OpenAPI schemas into Zod code strings.
|
|
3
|
-
*
|
|
4
|
-
* Chaining order: base → refinements → .nullable() → .optional() → .default() → .describe()
|
|
5
|
-
*/
|
|
6
|
-
export interface OpenAPISchema {
|
|
7
|
-
type?: string;
|
|
8
|
-
format?: string;
|
|
9
|
-
description?: string;
|
|
10
|
-
enum?: unknown[];
|
|
11
|
-
items?: OpenAPISchema;
|
|
12
|
-
properties?: Record<string, OpenAPISchema>;
|
|
13
|
-
required?: string[];
|
|
14
|
-
nullable?: boolean;
|
|
15
|
-
default?: unknown;
|
|
16
|
-
minimum?: number;
|
|
17
|
-
maximum?: number;
|
|
18
|
-
exclusiveMinimum?: number;
|
|
19
|
-
exclusiveMaximum?: number;
|
|
20
|
-
minLength?: number;
|
|
21
|
-
maxLength?: number;
|
|
22
|
-
pattern?: string;
|
|
23
|
-
minItems?: number;
|
|
24
|
-
maxItems?: number;
|
|
25
|
-
oneOf?: OpenAPISchema[];
|
|
26
|
-
anyOf?: OpenAPISchema[];
|
|
27
|
-
allOf?: OpenAPISchema[];
|
|
28
|
-
additionalProperties?: boolean | OpenAPISchema;
|
|
29
|
-
$ref?: string;
|
|
30
|
-
readOnly?: boolean;
|
|
31
|
-
writeOnly?: boolean;
|
|
32
|
-
}
|
|
33
|
-
export interface ZodCodegenContext {
|
|
34
|
-
/** Map from component schema name to its Zod variable name */
|
|
35
|
-
schemaRefs: Map<string, string>;
|
|
36
|
-
/** Track which refs are actually used */
|
|
37
|
-
usedRefs: Set<string>;
|
|
38
|
-
/** Indent level for readability */
|
|
39
|
-
indent: number;
|
|
40
|
-
}
|
|
41
|
-
export declare function createContext(schemaRefs?: Map<string, string>): ZodCodegenContext;
|
|
42
|
-
/**
|
|
43
|
-
* Convert a single OpenAPI schema to a Zod expression string.
|
|
44
|
-
* Does NOT include .optional() — that's handled at the property level based on `required`.
|
|
45
|
-
*/
|
|
46
|
-
export declare function schemaToZod(schema: OpenAPISchema, ctx: ZodCodegenContext, opts?: {
|
|
47
|
-
optional?: boolean;
|
|
48
|
-
}): string;
|
|
49
|
-
/**
|
|
50
|
-
* Generate the Zod variable name for a component schema.
|
|
51
|
-
* e.g. "PaginatedResponse" → "PaginatedResponseSchema"
|
|
52
|
-
*/
|
|
53
|
-
export declare function schemaVarName(name: string): string;
|
|
1
|
+
export { type OpenAPISchema, type ZodCodegenContext, createContext, schemaToZod, schemaVarName, } from '@pikku/openapi-to-zod-schema';
|
|
@@ -1,251 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Converts OpenAPI schemas into Zod code strings.
|
|
3
|
-
*
|
|
4
|
-
* Chaining order: base → refinements → .nullable() → .optional() → .default() → .describe()
|
|
5
|
-
*/
|
|
6
|
-
export function createContext(schemaRefs) {
|
|
7
|
-
return {
|
|
8
|
-
schemaRefs: schemaRefs ?? new Map(),
|
|
9
|
-
usedRefs: new Set(),
|
|
10
|
-
indent: 0,
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Convert a single OpenAPI schema to a Zod expression string.
|
|
15
|
-
* Does NOT include .optional() — that's handled at the property level based on `required`.
|
|
16
|
-
*/
|
|
17
|
-
export function schemaToZod(schema, ctx, opts = {}) {
|
|
18
|
-
let code = schemaToZodBase(schema, ctx);
|
|
19
|
-
// Refinements
|
|
20
|
-
code = applyRefinements(code, schema);
|
|
21
|
-
// Nullable
|
|
22
|
-
if (schema.nullable) {
|
|
23
|
-
code += '.nullable()';
|
|
24
|
-
}
|
|
25
|
-
// Optional
|
|
26
|
-
if (opts.optional) {
|
|
27
|
-
code += '.optional()';
|
|
28
|
-
}
|
|
29
|
-
// Default
|
|
30
|
-
if (schema.default !== undefined) {
|
|
31
|
-
code += `.default(${JSON.stringify(schema.default)})`;
|
|
32
|
-
}
|
|
33
|
-
// Description
|
|
34
|
-
if (schema.description) {
|
|
35
|
-
code += `.describe(${JSON.stringify(schema.description)})`;
|
|
36
|
-
}
|
|
37
|
-
return code;
|
|
38
|
-
}
|
|
39
|
-
function schemaToZodBase(schema, ctx) {
|
|
40
|
-
// Handle $ref
|
|
41
|
-
if (schema.$ref) {
|
|
42
|
-
const refName = schema.$ref.split('/').pop();
|
|
43
|
-
const zodName = ctx.schemaRefs.get(refName);
|
|
44
|
-
if (zodName) {
|
|
45
|
-
ctx.usedRefs.add(refName);
|
|
46
|
-
return zodName;
|
|
47
|
-
}
|
|
48
|
-
// Unknown ref — fallback to z.unknown()
|
|
49
|
-
return 'z.unknown()';
|
|
50
|
-
}
|
|
51
|
-
// Handle allOf — merge into single object
|
|
52
|
-
if (schema.allOf && schema.allOf.length > 0) {
|
|
53
|
-
return handleAllOf(schema.allOf, ctx);
|
|
54
|
-
}
|
|
55
|
-
// Handle oneOf/anyOf — union
|
|
56
|
-
if (schema.oneOf && schema.oneOf.length > 0) {
|
|
57
|
-
return handleUnion(schema.oneOf, ctx);
|
|
58
|
-
}
|
|
59
|
-
if (schema.anyOf && schema.anyOf.length > 0) {
|
|
60
|
-
return handleUnion(schema.anyOf, ctx);
|
|
61
|
-
}
|
|
62
|
-
// Handle enum
|
|
63
|
-
if (schema.enum && schema.enum.length > 0) {
|
|
64
|
-
return handleEnum(schema.enum);
|
|
65
|
-
}
|
|
66
|
-
// Handle by type
|
|
67
|
-
switch (schema.type) {
|
|
68
|
-
case 'string':
|
|
69
|
-
return handleString(schema);
|
|
70
|
-
case 'integer':
|
|
71
|
-
return 'z.number().int()';
|
|
72
|
-
case 'number':
|
|
73
|
-
return 'z.number()';
|
|
74
|
-
case 'boolean':
|
|
75
|
-
return 'z.boolean()';
|
|
76
|
-
case 'array':
|
|
77
|
-
return handleArray(schema, ctx);
|
|
78
|
-
case 'object':
|
|
79
|
-
return handleObject(schema, ctx);
|
|
80
|
-
default:
|
|
81
|
-
// No type specified but has properties — treat as object
|
|
82
|
-
if (schema.properties) {
|
|
83
|
-
return handleObject(schema, ctx);
|
|
84
|
-
}
|
|
85
|
-
return 'z.unknown()';
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function handleString(schema) {
|
|
89
|
-
switch (schema.format) {
|
|
90
|
-
case 'uuid':
|
|
91
|
-
return 'z.string().uuid()';
|
|
92
|
-
case 'date-time':
|
|
93
|
-
return 'z.string().datetime()';
|
|
94
|
-
case 'date':
|
|
95
|
-
return 'z.string().date()';
|
|
96
|
-
case 'email':
|
|
97
|
-
return 'z.string().email()';
|
|
98
|
-
case 'uri':
|
|
99
|
-
case 'url':
|
|
100
|
-
return 'z.string().url()';
|
|
101
|
-
default:
|
|
102
|
-
return 'z.string()';
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
function handleEnum(values) {
|
|
106
|
-
// If all values are strings, use z.enum
|
|
107
|
-
if (values.every((v) => typeof v === 'string')) {
|
|
108
|
-
const enumValues = values.map((v) => JSON.stringify(v)).join(', ');
|
|
109
|
-
return `z.enum([${enumValues}])`;
|
|
110
|
-
}
|
|
111
|
-
// Mixed types — use z.union of z.literal
|
|
112
|
-
const literals = values.map((v) => `z.literal(${JSON.stringify(v)})`).join(', ');
|
|
113
|
-
return `z.union([${literals}])`;
|
|
114
|
-
}
|
|
115
|
-
function handleArray(schema, ctx) {
|
|
116
|
-
const itemsZod = schema.items
|
|
117
|
-
? schemaToZodBase(schema.items, ctx)
|
|
118
|
-
: 'z.unknown()';
|
|
119
|
-
return `z.array(${itemsZod})`;
|
|
120
|
-
}
|
|
121
|
-
function indent(ctx) {
|
|
122
|
-
return ' '.repeat(ctx.indent);
|
|
123
|
-
}
|
|
124
|
-
function handleObject(schema, ctx) {
|
|
125
|
-
if (!schema.properties || Object.keys(schema.properties).length === 0) {
|
|
126
|
-
// Object with no defined properties
|
|
127
|
-
if (schema.additionalProperties) {
|
|
128
|
-
const valueSchema = typeof schema.additionalProperties === 'object'
|
|
129
|
-
? schemaToZod(schema.additionalProperties, ctx)
|
|
130
|
-
: 'z.unknown()';
|
|
131
|
-
return `z.record(z.string(), ${valueSchema})`;
|
|
132
|
-
}
|
|
133
|
-
return 'z.record(z.string(), z.unknown())';
|
|
134
|
-
}
|
|
135
|
-
const inner = { ...ctx, indent: ctx.indent + 1 };
|
|
136
|
-
const pad = indent(inner);
|
|
137
|
-
const closePad = indent(ctx);
|
|
138
|
-
const requiredSet = new Set(schema.required ?? []);
|
|
139
|
-
const entries = [];
|
|
140
|
-
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
141
|
-
const isOptional = !requiredSet.has(key);
|
|
142
|
-
const propZod = schemaToZod(propSchema, inner, { optional: isOptional });
|
|
143
|
-
entries.push(`${pad}${safeKey(key)}: ${propZod},`);
|
|
144
|
-
}
|
|
145
|
-
return `z.object({\n${entries.join('\n')}\n${closePad}})`;
|
|
146
|
-
}
|
|
147
|
-
function handleAllOf(schemas, ctx) {
|
|
148
|
-
// Collect all properties from all schemas
|
|
149
|
-
const mergedProps = {};
|
|
150
|
-
const mergedRequired = [];
|
|
151
|
-
for (const sub of schemas) {
|
|
152
|
-
if (sub.$ref) {
|
|
153
|
-
const refName = sub.$ref.split('/').pop();
|
|
154
|
-
const zodName = ctx.schemaRefs.get(refName);
|
|
155
|
-
if (zodName) {
|
|
156
|
-
ctx.usedRefs.add(refName);
|
|
157
|
-
// If it's a pure ref in an allOf, we'd need to merge/extend
|
|
158
|
-
// For simplicity, if we have refs mixed with objects, use .merge()
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (sub.properties) {
|
|
162
|
-
Object.assign(mergedProps, sub.properties);
|
|
163
|
-
}
|
|
164
|
-
if (sub.required) {
|
|
165
|
-
mergedRequired.push(...sub.required);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
// If we have only refs, use .merge()
|
|
169
|
-
const refSchemas = schemas.filter((s) => s.$ref);
|
|
170
|
-
const objSchemas = schemas.filter((s) => !s.$ref && (s.properties || s.type === 'object'));
|
|
171
|
-
if (refSchemas.length > 0 && objSchemas.length === 0) {
|
|
172
|
-
const parts = refSchemas.map((s) => {
|
|
173
|
-
const refName = s.$ref.split('/').pop();
|
|
174
|
-
ctx.usedRefs.add(refName);
|
|
175
|
-
return ctx.schemaRefs.get(refName) || 'z.object({})';
|
|
176
|
-
});
|
|
177
|
-
if (parts.length === 1)
|
|
178
|
-
return parts[0];
|
|
179
|
-
return parts.reduce((acc, part) => `${acc}.merge(${part})`);
|
|
180
|
-
}
|
|
181
|
-
// Otherwise, merge into a single object
|
|
182
|
-
if (Object.keys(mergedProps).length > 0) {
|
|
183
|
-
return handleObject({
|
|
184
|
-
type: 'object',
|
|
185
|
-
properties: mergedProps,
|
|
186
|
-
required: [...new Set(mergedRequired)],
|
|
187
|
-
}, ctx);
|
|
188
|
-
}
|
|
189
|
-
// Fallback
|
|
190
|
-
return 'z.unknown()';
|
|
191
|
-
}
|
|
192
|
-
function handleUnion(schemas, ctx) {
|
|
193
|
-
const members = schemas.map((s) => schemaToZodBase(s, ctx));
|
|
194
|
-
if (members.length === 1)
|
|
195
|
-
return members[0];
|
|
196
|
-
return `z.union([${members.join(', ')}])`;
|
|
197
|
-
}
|
|
198
|
-
function applyRefinements(code, schema) {
|
|
199
|
-
let result = code;
|
|
200
|
-
// String refinements
|
|
201
|
-
if (schema.type === 'string' || (!schema.type && !schema.format)) {
|
|
202
|
-
if (schema.minLength !== undefined) {
|
|
203
|
-
result += `.min(${schema.minLength})`;
|
|
204
|
-
}
|
|
205
|
-
if (schema.maxLength !== undefined) {
|
|
206
|
-
result += `.max(${schema.maxLength})`;
|
|
207
|
-
}
|
|
208
|
-
if (schema.pattern) {
|
|
209
|
-
result += `.regex(new RegExp(${JSON.stringify(schema.pattern)}))`;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
// Number refinements
|
|
213
|
-
if (schema.type === 'number' || schema.type === 'integer') {
|
|
214
|
-
if (schema.minimum !== undefined) {
|
|
215
|
-
result += `.min(${schema.minimum})`;
|
|
216
|
-
}
|
|
217
|
-
if (schema.maximum !== undefined) {
|
|
218
|
-
result += `.max(${schema.maximum})`;
|
|
219
|
-
}
|
|
220
|
-
if (schema.exclusiveMinimum !== undefined) {
|
|
221
|
-
result += `.gt(${schema.exclusiveMinimum})`;
|
|
222
|
-
}
|
|
223
|
-
if (schema.exclusiveMaximum !== undefined) {
|
|
224
|
-
result += `.lt(${schema.exclusiveMaximum})`;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
// Array refinements
|
|
228
|
-
if (schema.type === 'array') {
|
|
229
|
-
if (schema.minItems !== undefined) {
|
|
230
|
-
result += `.min(${schema.minItems})`;
|
|
231
|
-
}
|
|
232
|
-
if (schema.maxItems !== undefined) {
|
|
233
|
-
result += `.max(${schema.maxItems})`;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return result;
|
|
237
|
-
}
|
|
238
|
-
/** Ensure property keys are safe identifiers, or quote them */
|
|
239
|
-
function safeKey(key) {
|
|
240
|
-
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
|
|
241
|
-
return key;
|
|
242
|
-
}
|
|
243
|
-
return JSON.stringify(key);
|
|
244
|
-
}
|
|
245
|
-
/**
|
|
246
|
-
* Generate the Zod variable name for a component schema.
|
|
247
|
-
* e.g. "PaginatedResponse" → "PaginatedResponseSchema"
|
|
248
|
-
*/
|
|
249
|
-
export function schemaVarName(name) {
|
|
250
|
-
return name.endsWith('Schema') ? name : `${name}Schema`;
|
|
251
|
-
}
|
|
1
|
+
export { createContext, schemaToZod, schemaVarName, } from '@pikku/openapi-to-zod-schema';
|
|
@@ -319,8 +319,8 @@ const _getPikkuCLIConfig = async (logger, configFile = undefined, requiredFields
|
|
|
319
319
|
result.cliTypesFile = join(cliDir, 'pikku-cli-types.gen.ts');
|
|
320
320
|
}
|
|
321
321
|
const consoleDir = join(result.outDir, 'console');
|
|
322
|
-
if (!result.
|
|
323
|
-
result.
|
|
322
|
+
if (!result.addonMetaJsonFile) {
|
|
323
|
+
result.addonMetaJsonFile = join(consoleDir, 'pikku-addon-meta.gen.json');
|
|
324
324
|
}
|
|
325
325
|
if (!result.nodeTypesFile) {
|
|
326
326
|
result.nodeTypesFile = join(consoleDir, 'pikku-node-types.gen.ts');
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
* 2. Record of meta entries: { "entryName": { pikkuFuncId, description, tags, ... } }
|
|
26
26
|
* -> Strips description, tags from each entry (one level deep only)
|
|
27
27
|
* 3. CLI meta and others with complex nesting: preserved as-is except for pikkuFuncId entries
|
|
28
|
+
*
|
|
29
|
+
* Also strips addon namespace prefixes from pikkuFuncId values where packageName is present.
|
|
28
30
|
*/
|
|
29
31
|
export declare function stripVerboseFields<T>(obj: T): T;
|
|
30
32
|
/**
|
|
@@ -75,6 +75,35 @@ function hasVerboseShallow(obj, additionalFields) {
|
|
|
75
75
|
}
|
|
76
76
|
return false;
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Recursively strip addon namespace prefixes from pikkuFuncId values.
|
|
80
|
+
* When an entry has both pikkuFuncId (e.g. "swaggerPetstore:addPet") and packageName,
|
|
81
|
+
* the namespace prefix is redundant — strip it so runtime gets bare function names.
|
|
82
|
+
*/
|
|
83
|
+
function stripAddonNamespacePrefixes(obj) {
|
|
84
|
+
if (obj === null || obj === undefined || typeof obj !== 'object')
|
|
85
|
+
return obj;
|
|
86
|
+
if (Array.isArray(obj))
|
|
87
|
+
return obj.map(stripAddonNamespacePrefixes);
|
|
88
|
+
const record = obj;
|
|
89
|
+
const result = {};
|
|
90
|
+
for (const [key, value] of Object.entries(record)) {
|
|
91
|
+
if (key === 'pikkuFuncId' &&
|
|
92
|
+
typeof value === 'string' &&
|
|
93
|
+
value.includes(':') &&
|
|
94
|
+
'packageName' in record &&
|
|
95
|
+
record.packageName) {
|
|
96
|
+
result[key] = value.substring(value.indexOf(':') + 1);
|
|
97
|
+
}
|
|
98
|
+
else if (typeof value === 'object' && value !== null) {
|
|
99
|
+
result[key] = stripAddonNamespacePrefixes(value);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
result[key] = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
78
107
|
/**
|
|
79
108
|
* Strip verbose fields from a meta object.
|
|
80
109
|
*
|
|
@@ -84,8 +113,13 @@ function hasVerboseShallow(obj, additionalFields) {
|
|
|
84
113
|
* 2. Record of meta entries: { "entryName": { pikkuFuncId, description, tags, ... } }
|
|
85
114
|
* -> Strips description, tags from each entry (one level deep only)
|
|
86
115
|
* 3. CLI meta and others with complex nesting: preserved as-is except for pikkuFuncId entries
|
|
116
|
+
*
|
|
117
|
+
* Also strips addon namespace prefixes from pikkuFuncId values where packageName is present.
|
|
87
118
|
*/
|
|
88
119
|
export function stripVerboseFields(obj) {
|
|
120
|
+
return stripAddonNamespacePrefixes(_stripVerboseFieldsInner(obj));
|
|
121
|
+
}
|
|
122
|
+
function _stripVerboseFieldsInner(obj) {
|
|
89
123
|
if (obj === null || obj === undefined || typeof obj !== 'object') {
|
|
90
124
|
return obj;
|
|
91
125
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.4",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"imports": {
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@openapi-contrib/json-schema-to-openapi-schema": "^4.3.1",
|
|
28
|
-
"@pikku/core": "^0.12.
|
|
29
|
-
"@pikku/inspector": "^0.12.
|
|
28
|
+
"@pikku/core": "^0.12.4",
|
|
29
|
+
"@pikku/inspector": "^0.12.3",
|
|
30
|
+
"@pikku/openapi-to-zod-schema": "^0.12.2",
|
|
30
31
|
"@types/cookie": "^1.0.0",
|
|
31
32
|
"@types/json-schema": "^7.0.15",
|
|
32
33
|
"chalk": "^5.6.2",
|