@cosmneo/onion-lasagna 0.4.0 → 0.4.1
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/chunk-EJNADL7J.js +285 -0
- package/dist/chunk-EJNADL7J.js.map +1 -0
- package/dist/graphql/index.cjs +132 -39
- package/dist/graphql/index.cjs.map +1 -1
- package/dist/graphql/index.js +1 -1
- package/dist/graphql/sdl/index.cjs +132 -39
- package/dist/graphql/sdl/index.cjs.map +1 -1
- package/dist/graphql/sdl/index.d.cts +16 -0
- package/dist/graphql/sdl/index.d.ts +16 -0
- package/dist/graphql/sdl/index.js +1 -1
- package/dist/index.cjs +132 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -3
- package/dist/chunk-4RFWJ5XZ.js +0 -192
- package/dist/chunk-4RFWJ5XZ.js.map +0 -1
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectFields,
|
|
3
|
+
generateFieldId,
|
|
4
|
+
isSchemaDefinition
|
|
5
|
+
} from "./chunk-BG2FY27M.js";
|
|
6
|
+
|
|
7
|
+
// src/presentation/graphql/sdl/generate.ts
|
|
8
|
+
function generateGraphQLSDL(schema, config) {
|
|
9
|
+
const fields = isSchemaDefinition(schema) ? schema.fields : schema;
|
|
10
|
+
const collectedFields = collectFields(fields);
|
|
11
|
+
const includeDescriptions = config?.includeDescriptions ?? true;
|
|
12
|
+
const includeDeprecations = config?.includeDeprecations ?? true;
|
|
13
|
+
const queries = [];
|
|
14
|
+
const mutations = [];
|
|
15
|
+
const subscriptions = [];
|
|
16
|
+
for (const { key, field } of collectedFields) {
|
|
17
|
+
const fieldId = generateFieldId(key);
|
|
18
|
+
if (field.operation === "query") {
|
|
19
|
+
queries.push({ fieldId, field });
|
|
20
|
+
} else if (field.operation === "mutation") {
|
|
21
|
+
mutations.push({ fieldId, field });
|
|
22
|
+
} else if (field.operation === "subscription") {
|
|
23
|
+
subscriptions.push({ fieldId, field });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const namedTypes = /* @__PURE__ */ new Map();
|
|
27
|
+
const lines = [];
|
|
28
|
+
if (config?.preamble) {
|
|
29
|
+
lines.push(config.preamble);
|
|
30
|
+
lines.push("");
|
|
31
|
+
}
|
|
32
|
+
if (queries.length > 0) {
|
|
33
|
+
lines.push("type Query {");
|
|
34
|
+
for (const { fieldId, field } of queries) {
|
|
35
|
+
const fieldLine = buildFieldLine(
|
|
36
|
+
fieldId,
|
|
37
|
+
field,
|
|
38
|
+
namedTypes,
|
|
39
|
+
includeDescriptions,
|
|
40
|
+
includeDeprecations
|
|
41
|
+
);
|
|
42
|
+
lines.push(fieldLine);
|
|
43
|
+
}
|
|
44
|
+
lines.push("}");
|
|
45
|
+
lines.push("");
|
|
46
|
+
}
|
|
47
|
+
if (mutations.length > 0) {
|
|
48
|
+
lines.push("type Mutation {");
|
|
49
|
+
for (const { fieldId, field } of mutations) {
|
|
50
|
+
const fieldLine = buildFieldLine(
|
|
51
|
+
fieldId,
|
|
52
|
+
field,
|
|
53
|
+
namedTypes,
|
|
54
|
+
includeDescriptions,
|
|
55
|
+
includeDeprecations
|
|
56
|
+
);
|
|
57
|
+
lines.push(fieldLine);
|
|
58
|
+
}
|
|
59
|
+
lines.push("}");
|
|
60
|
+
lines.push("");
|
|
61
|
+
}
|
|
62
|
+
if (subscriptions.length > 0) {
|
|
63
|
+
lines.push("type Subscription {");
|
|
64
|
+
for (const { fieldId, field } of subscriptions) {
|
|
65
|
+
const fieldLine = buildFieldLine(
|
|
66
|
+
fieldId,
|
|
67
|
+
field,
|
|
68
|
+
namedTypes,
|
|
69
|
+
includeDescriptions,
|
|
70
|
+
includeDeprecations
|
|
71
|
+
);
|
|
72
|
+
lines.push(fieldLine);
|
|
73
|
+
}
|
|
74
|
+
lines.push("}");
|
|
75
|
+
lines.push("");
|
|
76
|
+
}
|
|
77
|
+
for (const [, typeBody] of namedTypes) {
|
|
78
|
+
lines.push(typeBody);
|
|
79
|
+
lines.push("");
|
|
80
|
+
}
|
|
81
|
+
return lines.join("\n").trimEnd() + "\n";
|
|
82
|
+
}
|
|
83
|
+
function buildFieldLine(fieldId, field, namedTypes, includeDescriptions, includeDeprecations) {
|
|
84
|
+
const parts = [];
|
|
85
|
+
if (includeDescriptions && field.docs.description) {
|
|
86
|
+
const escaped = field.docs.description.replace(/"""/g, '\\"""');
|
|
87
|
+
parts.push(` """${escaped}"""`);
|
|
88
|
+
}
|
|
89
|
+
const inputTypeName = field.input ? `${capitalize(fieldId)}Input` : void 0;
|
|
90
|
+
const outputRootName = field.output ? `${capitalize(fieldId)}Output` : void 0;
|
|
91
|
+
if (field.input && inputTypeName) {
|
|
92
|
+
const jsonSchema = field.input.toJsonSchema();
|
|
93
|
+
registerInputType(inputTypeName, jsonSchema, namedTypes);
|
|
94
|
+
}
|
|
95
|
+
let outputTypeName;
|
|
96
|
+
if (field.output && outputRootName) {
|
|
97
|
+
const jsonSchema = field.output.toJsonSchema();
|
|
98
|
+
outputTypeName = registerOutputType(outputRootName, jsonSchema, namedTypes);
|
|
99
|
+
}
|
|
100
|
+
let signature = ` ${fieldId}`;
|
|
101
|
+
if (inputTypeName) {
|
|
102
|
+
signature += `(input: ${inputTypeName}!)`;
|
|
103
|
+
}
|
|
104
|
+
signature += ": ";
|
|
105
|
+
signature += outputTypeName ?? "JSON";
|
|
106
|
+
if (includeDeprecations && field.docs.deprecated) {
|
|
107
|
+
const reason = field.docs.deprecationReason;
|
|
108
|
+
signature += reason ? ` @deprecated(reason: "${escapeSDLString(reason)}")` : " @deprecated";
|
|
109
|
+
}
|
|
110
|
+
if (parts.length > 0) {
|
|
111
|
+
return parts.join("\n") + "\n" + signature;
|
|
112
|
+
}
|
|
113
|
+
return signature;
|
|
114
|
+
}
|
|
115
|
+
function registerInputType(typeName, jsonSchema, namedTypes) {
|
|
116
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
117
|
+
namedTypes.set(typeName, "");
|
|
118
|
+
const properties = jsonSchema.properties ?? {};
|
|
119
|
+
const required = new Set(
|
|
120
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
121
|
+
);
|
|
122
|
+
const lines = [`input ${typeName} {`];
|
|
123
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
124
|
+
const graphqlType = jsonSchemaToGraphQLType(
|
|
125
|
+
propSchema,
|
|
126
|
+
`${typeName}_${capitalize(propName)}`,
|
|
127
|
+
namedTypes,
|
|
128
|
+
"input"
|
|
129
|
+
);
|
|
130
|
+
const isRequired = required.has(propName);
|
|
131
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
132
|
+
}
|
|
133
|
+
lines.push("}");
|
|
134
|
+
namedTypes.set(typeName, lines.join("\n"));
|
|
135
|
+
return typeName;
|
|
136
|
+
}
|
|
137
|
+
function registerOutputType(typeName, jsonSchema, namedTypes) {
|
|
138
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
139
|
+
if (jsonSchema.type === "array") {
|
|
140
|
+
const items = jsonSchema.items;
|
|
141
|
+
if (!items) return "[JSON]";
|
|
142
|
+
const itemTypeName = jsonSchemaToGraphQLType(items, `${typeName}_Item`, namedTypes, "output");
|
|
143
|
+
return `[${itemTypeName}]`;
|
|
144
|
+
}
|
|
145
|
+
const variants = pickVariants(jsonSchema);
|
|
146
|
+
if (variants) {
|
|
147
|
+
return registerUnionType(typeName, variants, namedTypes);
|
|
148
|
+
}
|
|
149
|
+
namedTypes.set(typeName, "");
|
|
150
|
+
const properties = jsonSchema.properties ?? {};
|
|
151
|
+
if (Object.keys(properties).length === 0) {
|
|
152
|
+
namedTypes.delete(typeName);
|
|
153
|
+
return "JSON";
|
|
154
|
+
}
|
|
155
|
+
const required = new Set(
|
|
156
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
157
|
+
);
|
|
158
|
+
const lines = [`type ${typeName} {`];
|
|
159
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
160
|
+
const graphqlType = jsonSchemaToGraphQLType(
|
|
161
|
+
propSchema,
|
|
162
|
+
`${typeName}_${capitalize(propName)}`,
|
|
163
|
+
namedTypes,
|
|
164
|
+
"output"
|
|
165
|
+
);
|
|
166
|
+
const isRequired = required.has(propName);
|
|
167
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
168
|
+
}
|
|
169
|
+
lines.push("}");
|
|
170
|
+
namedTypes.set(typeName, lines.join("\n"));
|
|
171
|
+
return typeName;
|
|
172
|
+
}
|
|
173
|
+
function registerUnionType(typeName, variants, namedTypes) {
|
|
174
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
175
|
+
namedTypes.set(typeName, "");
|
|
176
|
+
const memberNames = [];
|
|
177
|
+
const seen = /* @__PURE__ */ new Set();
|
|
178
|
+
for (let i = 0; i < variants.length; i++) {
|
|
179
|
+
const variant = variants[i];
|
|
180
|
+
if (!variant || !isObjectSchema(variant)) {
|
|
181
|
+
namedTypes.delete(typeName);
|
|
182
|
+
return "JSON";
|
|
183
|
+
}
|
|
184
|
+
const discriminator = pickDiscriminatorLabel(variant);
|
|
185
|
+
let memberName = discriminator ? `${typeName}_${pascalize(discriminator)}` : `${typeName}_Member${i + 1}`;
|
|
186
|
+
let suffix = 2;
|
|
187
|
+
while (seen.has(memberName)) {
|
|
188
|
+
memberName = `${typeName}_${pascalize(discriminator ?? "Member")}${suffix++}`;
|
|
189
|
+
}
|
|
190
|
+
seen.add(memberName);
|
|
191
|
+
registerOutputType(memberName, variant, namedTypes);
|
|
192
|
+
memberNames.push(memberName);
|
|
193
|
+
}
|
|
194
|
+
namedTypes.set(typeName, `union ${typeName} = ${memberNames.join(" | ")}`);
|
|
195
|
+
return typeName;
|
|
196
|
+
}
|
|
197
|
+
function pickVariants(schema) {
|
|
198
|
+
if (Array.isArray(schema.oneOf)) return schema.oneOf;
|
|
199
|
+
if (Array.isArray(schema.anyOf)) return schema.anyOf;
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
function isObjectSchema(schema) {
|
|
203
|
+
if (!schema || typeof schema !== "object") return false;
|
|
204
|
+
if (schema.type === "object") return true;
|
|
205
|
+
if (schema.properties && typeof schema.properties === "object") return true;
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
function pickDiscriminatorLabel(schema) {
|
|
209
|
+
const properties = schema.properties ?? {};
|
|
210
|
+
for (const propSchema of Object.values(properties)) {
|
|
211
|
+
if (!propSchema || typeof propSchema !== "object") continue;
|
|
212
|
+
const constValue = propSchema.const;
|
|
213
|
+
if (typeof constValue === "string" && constValue.length > 0) {
|
|
214
|
+
return constValue;
|
|
215
|
+
}
|
|
216
|
+
const enumValue = propSchema.enum;
|
|
217
|
+
if (Array.isArray(enumValue) && enumValue.length === 1 && typeof enumValue[0] === "string" && enumValue[0].length > 0) {
|
|
218
|
+
return enumValue[0];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
function jsonSchemaToGraphQLType(schema, parentTypeName, namedTypes, kind) {
|
|
224
|
+
if (!schema || typeof schema !== "object") return "JSON";
|
|
225
|
+
if (schema.enum && Array.isArray(schema.enum)) {
|
|
226
|
+
return "String";
|
|
227
|
+
}
|
|
228
|
+
const variants = pickVariants(schema);
|
|
229
|
+
if (variants) {
|
|
230
|
+
if (kind === "input") return "JSON";
|
|
231
|
+
return registerUnionType(parentTypeName, variants, namedTypes);
|
|
232
|
+
}
|
|
233
|
+
const type = schema.type;
|
|
234
|
+
switch (type) {
|
|
235
|
+
case "string":
|
|
236
|
+
return "String";
|
|
237
|
+
case "integer":
|
|
238
|
+
return "Int";
|
|
239
|
+
case "number":
|
|
240
|
+
return "Float";
|
|
241
|
+
case "boolean":
|
|
242
|
+
return "Boolean";
|
|
243
|
+
case "array": {
|
|
244
|
+
const items = schema.items;
|
|
245
|
+
if (!items) return "[JSON]";
|
|
246
|
+
const itemType = jsonSchemaToGraphQLType(
|
|
247
|
+
items,
|
|
248
|
+
// Singular-ish name for array element types — drop a trailing
|
|
249
|
+
// 's' when present so `Tags[]` becomes `…_Tag`. Cheap heuristic;
|
|
250
|
+
// fine for the conventional case.
|
|
251
|
+
parentTypeName.replace(/s$/, ""),
|
|
252
|
+
namedTypes,
|
|
253
|
+
kind
|
|
254
|
+
);
|
|
255
|
+
return `[${itemType}]`;
|
|
256
|
+
}
|
|
257
|
+
case "object":
|
|
258
|
+
if (kind === "input") {
|
|
259
|
+
return registerInputType(parentTypeName, schema, namedTypes);
|
|
260
|
+
}
|
|
261
|
+
return registerOutputType(parentTypeName, schema, namedTypes);
|
|
262
|
+
default:
|
|
263
|
+
if (isObjectSchema(schema)) {
|
|
264
|
+
if (kind === "input") {
|
|
265
|
+
return registerInputType(parentTypeName, schema, namedTypes);
|
|
266
|
+
}
|
|
267
|
+
return registerOutputType(parentTypeName, schema, namedTypes);
|
|
268
|
+
}
|
|
269
|
+
return "JSON";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function capitalize(str) {
|
|
273
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
274
|
+
}
|
|
275
|
+
function pascalize(str) {
|
|
276
|
+
return str.split(/[^a-zA-Z0-9]+/g).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
277
|
+
}
|
|
278
|
+
function escapeSDLString(str) {
|
|
279
|
+
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export {
|
|
283
|
+
generateGraphQLSDL
|
|
284
|
+
};
|
|
285
|
+
//# sourceMappingURL=chunk-EJNADL7J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/presentation/graphql/sdl/generate.ts"],"sourcesContent":["/**\n * @fileoverview GraphQL SDL generation from schema definitions.\n *\n * The `generateGraphQLSDL` function creates a complete GraphQL Schema\n * Definition Language string from a schema definition.\n *\n * Input/output schemas are converted to JSON Schema via `toJsonSchema()`,\n * then mapped to GraphQL type definitions.\n *\n * Supported JSON Schema → GraphQL mappings:\n * - `type: 'string' | 'integer' | 'number' | 'boolean'` → scalars\n * - `type: 'array'` → `[T]` (recursing into `items`)\n * - `enum` → `String` (named enums are a future improvement)\n * - `type: 'object'` with `properties` → emitted as a named GraphQL\n * `type`/`input` and reused via the named-types map. Nested object\n * properties get hierarchical names (`OuterType_Property`) so the\n * SDL stays valid without dropping to a `JSON` scalar.\n * - `oneOf` / `anyOf` of object schemas (zod's `discriminatedUnion`\n * and plain `union`) → emitted as a GraphQL `union` of named member\n * types. Output types only — GraphQL spec forbids unions in inputs.\n *\n * Truly unrepresentable shapes (e.g. unions of mixed scalars) still\n * fall back to `JSON`. Empty objects (no properties) also fall back so\n * we don't emit invalid empty SDL types.\n *\n * @module graphql/sdl/generate\n */\n\nimport type { SchemaAdapter, JsonSchema } from '../../http/schema/types';\nimport type {\n GraphQLSchemaConfig,\n GraphQLSchemaDefinition,\n GraphQLFieldDefinition,\n} from '../field/types';\nimport { isSchemaDefinition, collectFields } from '../field/types';\nimport { generateFieldId } from '../field/utils';\nimport type { GraphQLSDLConfig } from './types';\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Generates a GraphQL SDL string from a schema definition.\n *\n * Walks the schema structure, extracts JSON schemas from all field\n * definitions, and builds a complete SDL with Query, Mutation, and\n * type definitions.\n *\n * @param schema - Schema definition or schema config\n * @param config - Optional SDL generation configuration\n * @returns Complete GraphQL SDL string\n *\n * @example Basic usage\n * ```typescript\n * import { generateGraphQLSDL } from '@cosmneo/onion-lasagna/graphql/sdl';\n *\n * const sdl = generateGraphQLSDL(projectSchema, {\n * preamble: 'scalar DateTime',\n * });\n *\n * console.log(sdl);\n * // type Query {\n * // projectsGet(input: ProjectsGetInput!): ProjectsGetOutput\n * // projectsList: ProjectsListOutput\n * // }\n * // ...\n * ```\n */\nexport function generateGraphQLSDL<T extends GraphQLSchemaConfig>(\n schema: T | GraphQLSchemaDefinition<T>,\n config?: GraphQLSDLConfig,\n): string {\n const fields = isSchemaDefinition(schema) ? schema.fields : schema;\n const collectedFields = collectFields(fields);\n\n const includeDescriptions = config?.includeDescriptions ?? true;\n const includeDeprecations = config?.includeDeprecations ?? true;\n\n // Partition fields by operation type\n const queries: { fieldId: string; field: GraphQLFieldDefinition }[] = [];\n const mutations: { fieldId: string; field: GraphQLFieldDefinition }[] = [];\n const subscriptions: { fieldId: string; field: GraphQLFieldDefinition }[] = [];\n\n for (const { key, field } of collectedFields) {\n const fieldId = generateFieldId(key);\n if (field.operation === 'query') {\n queries.push({ fieldId, field });\n } else if (field.operation === 'mutation') {\n mutations.push({ fieldId, field });\n } else if (field.operation === 'subscription') {\n subscriptions.push({ fieldId, field });\n }\n }\n\n // Collect all named types that need to be emitted. Insertion order is\n // preserved (Map), so emitted types follow the order in which the\n // generator first encountered them.\n const namedTypes: Map<string, string> = new Map();\n const lines: string[] = [];\n\n // Preamble\n if (config?.preamble) {\n lines.push(config.preamble);\n lines.push('');\n }\n\n // Build Query type\n if (queries.length > 0) {\n lines.push('type Query {');\n for (const { fieldId, field } of queries) {\n const fieldLine = buildFieldLine(\n fieldId,\n field,\n namedTypes,\n includeDescriptions,\n includeDeprecations,\n );\n lines.push(fieldLine);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Build Mutation type\n if (mutations.length > 0) {\n lines.push('type Mutation {');\n for (const { fieldId, field } of mutations) {\n const fieldLine = buildFieldLine(\n fieldId,\n field,\n namedTypes,\n includeDescriptions,\n includeDeprecations,\n );\n lines.push(fieldLine);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Build Subscription type\n if (subscriptions.length > 0) {\n lines.push('type Subscription {');\n for (const { fieldId, field } of subscriptions) {\n const fieldLine = buildFieldLine(\n fieldId,\n field,\n namedTypes,\n includeDescriptions,\n includeDeprecations,\n );\n lines.push(fieldLine);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Emit named types (inputs and outputs)\n for (const [, typeBody] of namedTypes) {\n lines.push(typeBody);\n lines.push('');\n }\n\n return lines.join('\\n').trimEnd() + '\\n';\n}\n\n// ============================================================================\n// Internal Helpers\n// ============================================================================\n\n/**\n * Builds a single field line for a root type (Query/Mutation/Subscription).\n */\nfunction buildFieldLine(\n fieldId: string,\n field: GraphQLFieldDefinition,\n namedTypes: Map<string, string>,\n includeDescriptions: boolean,\n includeDeprecations: boolean,\n): string {\n const parts: string[] = [];\n\n // Description as SDL doc string (escaped to prevent triple-quote injection)\n if (includeDescriptions && field.docs.description) {\n const escaped = field.docs.description.replace(/\"\"\"/g, '\\\\\"\"\"');\n parts.push(` \"\"\"${escaped}\"\"\"`);\n }\n\n // Build args and return type\n const inputTypeName = field.input ? `${capitalize(fieldId)}Input` : undefined;\n const outputRootName = field.output ? `${capitalize(fieldId)}Output` : undefined;\n\n // Register named input type\n if (field.input && inputTypeName) {\n const jsonSchema = (field.input as SchemaAdapter).toJsonSchema();\n registerInputType(inputTypeName, jsonSchema, namedTypes);\n }\n\n // Register named output type — `outputTypeName` is what the field's\n // return type signature uses, which differs from `outputRootName` when\n // the schema is a union (the field references the union name; the\n // member object types live alongside it).\n let outputTypeName: string | undefined;\n if (field.output && outputRootName) {\n const jsonSchema = (field.output as SchemaAdapter).toJsonSchema();\n outputTypeName = registerOutputType(outputRootName, jsonSchema, namedTypes);\n }\n\n // Build field signature\n let signature = ` ${fieldId}`;\n\n if (inputTypeName) {\n signature += `(input: ${inputTypeName}!)`;\n }\n\n signature += ': ';\n signature += outputTypeName ?? 'JSON';\n\n // Deprecation directive\n if (includeDeprecations && field.docs.deprecated) {\n const reason = field.docs.deprecationReason;\n signature += reason ? ` @deprecated(reason: \"${escapeSDLString(reason)}\")` : ' @deprecated';\n }\n\n if (parts.length > 0) {\n return parts.join('\\n') + '\\n' + signature;\n }\n return signature;\n}\n\n/**\n * Builds a GraphQL input type from a JSON schema, recursing into nested\n * objects (which become their own named input types). Returns the\n * registered type name. Falls back to registering a `JSON`-only marker\n * if the schema has no usable structure.\n */\nfunction registerInputType(\n typeName: string,\n jsonSchema: JsonSchema,\n namedTypes: Map<string, string>,\n): string {\n if (namedTypes.has(typeName)) return typeName;\n\n // Reserve the slot upfront so cycles don't recurse forever.\n namedTypes.set(typeName, '');\n\n const properties = (jsonSchema.properties ?? {}) as Record<string, JsonSchema>;\n const required = new Set(\n Array.isArray(jsonSchema.required) ? (jsonSchema.required as string[]) : [],\n );\n\n const lines: string[] = [`input ${typeName} {`];\n for (const [propName, propSchema] of Object.entries(properties)) {\n const graphqlType = jsonSchemaToGraphQLType(\n propSchema,\n `${typeName}_${capitalize(propName)}`,\n namedTypes,\n 'input',\n );\n const isRequired = required.has(propName);\n lines.push(` ${propName}: ${graphqlType}${isRequired ? '!' : ''}`);\n }\n lines.push('}');\n\n namedTypes.set(typeName, lines.join('\\n'));\n return typeName;\n}\n\n/**\n * Builds a GraphQL output type (or union) from a JSON schema. Returns\n * the name to use in the field signature. For object schemas this is\n * `typeName`; for `oneOf` / `anyOf` schemas it's also `typeName` but\n * registered as a `union` whose members are named hierarchically.\n */\nfunction registerOutputType(\n typeName: string,\n jsonSchema: JsonSchema,\n namedTypes: Map<string, string>,\n): string {\n if (namedTypes.has(typeName)) return typeName;\n\n // Array-rooted output — emit no named wrapper for the array itself,\n // recurse into the element schema and return `[Element]`. The element\n // type is named after `typeName_Item` so callers writing a list-style\n // query against `meTeamList: [TeamListOutput_Item]` get a meaningful\n // SDL name.\n if (jsonSchema.type === 'array') {\n const items = jsonSchema.items as JsonSchema | undefined;\n if (!items) return '[JSON]';\n const itemTypeName = jsonSchemaToGraphQLType(items, `${typeName}_Item`, namedTypes, 'output');\n return `[${itemTypeName}]`;\n }\n\n // Union (oneOf / anyOf) at the root output position.\n const variants = pickVariants(jsonSchema);\n if (variants) {\n return registerUnionType(typeName, variants, namedTypes);\n }\n\n // Reserve before recursing.\n namedTypes.set(typeName, '');\n\n const properties = (jsonSchema.properties ?? {}) as Record<string, JsonSchema>;\n if (Object.keys(properties).length === 0) {\n // Nothing to emit; fall back to a JSON-shaped placeholder so the\n // field stays usable. We undo the reservation by removing the entry\n // so the caller's signature uses `JSON` instead.\n namedTypes.delete(typeName);\n return 'JSON';\n }\n\n const required = new Set(\n Array.isArray(jsonSchema.required) ? (jsonSchema.required as string[]) : [],\n );\n const lines: string[] = [`type ${typeName} {`];\n for (const [propName, propSchema] of Object.entries(properties)) {\n const graphqlType = jsonSchemaToGraphQLType(\n propSchema,\n `${typeName}_${capitalize(propName)}`,\n namedTypes,\n 'output',\n );\n const isRequired = required.has(propName);\n lines.push(` ${propName}: ${graphqlType}${isRequired ? '!' : ''}`);\n }\n lines.push('}');\n\n namedTypes.set(typeName, lines.join('\\n'));\n return typeName;\n}\n\n/**\n * Build a GraphQL union for an `oneOf` / `anyOf` schema. Each branch\n * must be an object schema; non-object branches make the union\n * unrepresentable and we fall back to `JSON`. Member types are named\n * after the discriminator literal when one is present (zod's\n * `discriminatedUnion` produces a `const` literal on the discriminator\n * field), otherwise positional (`Member1`, `Member2`).\n */\nfunction registerUnionType(\n typeName: string,\n variants: JsonSchema[],\n namedTypes: Map<string, string>,\n): string {\n if (namedTypes.has(typeName)) return typeName;\n\n // Reserve.\n namedTypes.set(typeName, '');\n\n const memberNames: string[] = [];\n const seen = new Set<string>();\n for (let i = 0; i < variants.length; i++) {\n const variant = variants[i];\n if (!variant || !isObjectSchema(variant)) {\n // Mixed-type union — bail. Drop the reservation so the field\n // signature falls back to `JSON`.\n namedTypes.delete(typeName);\n return 'JSON';\n }\n const discriminator = pickDiscriminatorLabel(variant);\n let memberName = discriminator\n ? `${typeName}_${pascalize(discriminator)}`\n : `${typeName}_Member${i + 1}`;\n // Ensure uniqueness within this union (two branches with the same\n // discriminator would be a Zod modelling bug, but we keep the\n // generator robust).\n let suffix = 2;\n while (seen.has(memberName)) {\n memberName = `${typeName}_${pascalize(discriminator ?? 'Member')}${suffix++}`;\n }\n seen.add(memberName);\n registerOutputType(memberName, variant, namedTypes);\n memberNames.push(memberName);\n }\n\n namedTypes.set(typeName, `union ${typeName} = ${memberNames.join(' | ')}`);\n return typeName;\n}\n\n/**\n * Returns the variant list for a `oneOf` / `anyOf` schema, or `null` if\n * the schema doesn't carry one. `allOf` is not treated as a union — it\n * means \"intersect all\" and the JSON schema produced by Zod for plain\n * objects with shared fields would use it; we leave that as a future\n * improvement.\n */\nfunction pickVariants(schema: JsonSchema): JsonSchema[] | null {\n if (Array.isArray(schema.oneOf)) return schema.oneOf as JsonSchema[];\n if (Array.isArray(schema.anyOf)) return schema.anyOf as JsonSchema[];\n return null;\n}\n\n/**\n * Treat a schema as an object if it has `type: 'object'` or carries\n * `properties` (zod sometimes omits the explicit type when the shape is\n * obvious).\n */\nfunction isObjectSchema(schema: JsonSchema): boolean {\n if (!schema || typeof schema !== 'object') return false;\n if (schema.type === 'object') return true;\n if (schema.properties && typeof schema.properties === 'object') return true;\n return false;\n}\n\n/**\n * Find the literal value of a discriminator-style property in an object\n * schema. Zod's `z.discriminatedUnion('kind', [...])` emits each branch\n * with `properties.kind = { type: 'string', const: 'MEMBER' }` (or\n * `enum: ['MEMBER']`). We surface that literal so union member type\n * names can carry domain meaning instead of positional indexes.\n */\nfunction pickDiscriminatorLabel(schema: JsonSchema): string | null {\n const properties = (schema.properties ?? {}) as Record<string, JsonSchema>;\n for (const propSchema of Object.values(properties)) {\n if (!propSchema || typeof propSchema !== 'object') continue;\n const constValue = (propSchema as { const?: unknown }).const;\n if (typeof constValue === 'string' && constValue.length > 0) {\n return constValue;\n }\n const enumValue = (propSchema as { enum?: unknown[] }).enum;\n if (\n Array.isArray(enumValue) &&\n enumValue.length === 1 &&\n typeof enumValue[0] === 'string' &&\n enumValue[0].length > 0\n ) {\n return enumValue[0];\n }\n }\n return null;\n}\n\n/**\n * Converts a JSON schema fragment to a GraphQL type expression.\n *\n * For nested object shapes the function registers a new named type via\n * the supplied `namedTypes` map and returns its name. Arrays produce\n * `[ItemType]` and recurse into the element schema. Scalars map to the\n * GraphQL built-ins. Anything we can't represent (e.g. mixed-type\n * unions, schemas with no shape information) falls back to the `JSON`\n * scalar so the field stays queryable as an opaque value.\n *\n * `kind: 'input'` walks down through `registerInputType` so nested\n * structures stay on the input-types side; `kind: 'output'` mirrors\n * that for output types and unions.\n */\nfunction jsonSchemaToGraphQLType(\n schema: JsonSchema,\n parentTypeName: string,\n namedTypes: Map<string, string>,\n kind: 'input' | 'output',\n): string {\n if (!schema || typeof schema !== 'object') return 'JSON';\n\n // Handle enum (single-value enums and full enums alike → String for\n // now; named GraphQL enums are a future improvement).\n if (schema.enum && Array.isArray(schema.enum)) {\n return 'String';\n }\n\n // Union — only meaningful at output-position. Inputs collapse to JSON\n // because the GraphQL spec forbids unions in input types.\n const variants = pickVariants(schema);\n if (variants) {\n if (kind === 'input') return 'JSON';\n return registerUnionType(parentTypeName, variants, namedTypes);\n }\n\n const type = schema.type as string | undefined;\n\n switch (type) {\n case 'string':\n return 'String';\n case 'integer':\n return 'Int';\n case 'number':\n return 'Float';\n case 'boolean':\n return 'Boolean';\n case 'array': {\n const items = schema.items as JsonSchema | undefined;\n if (!items) return '[JSON]';\n const itemType = jsonSchemaToGraphQLType(\n items,\n // Singular-ish name for array element types — drop a trailing\n // 's' when present so `Tags[]` becomes `…_Tag`. Cheap heuristic;\n // fine for the conventional case.\n parentTypeName.replace(/s$/, ''),\n namedTypes,\n kind,\n );\n return `[${itemType}]`;\n }\n case 'object':\n if (kind === 'input') {\n return registerInputType(parentTypeName, schema, namedTypes);\n }\n return registerOutputType(parentTypeName, schema, namedTypes);\n default:\n // Object without explicit type but has properties.\n if (isObjectSchema(schema)) {\n if (kind === 'input') {\n return registerInputType(parentTypeName, schema, namedTypes);\n }\n return registerOutputType(parentTypeName, schema, namedTypes);\n }\n return 'JSON';\n }\n}\n\n/**\n * Capitalizes the first letter of a string.\n */\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Pascal-case a string by uppercasing each segment between non-alnum\n * runs. Used to turn discriminator literals (which may be `kebab-case`,\n * `snake_case`, or `UPPER_SNAKE`) into safe GraphQL type-name segments.\n */\nfunction pascalize(str: string): string {\n return str\n .split(/[^a-zA-Z0-9]+/g)\n .filter((part) => part.length > 0)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join('');\n}\n\n/**\n * Escapes a string for use in SDL quoted string literals.\n * Handles backslashes, quotes, newlines, and triple-quote injection.\n */\nfunction escapeSDLString(str: string): string {\n return str\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t');\n}\n"],"mappings":"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","names":[]}
|
package/dist/graphql/index.cjs
CHANGED
|
@@ -1029,14 +1029,15 @@ function buildFieldLine(fieldId, field, namedTypes, includeDescriptions, include
|
|
|
1029
1029
|
parts.push(` """${escaped}"""`);
|
|
1030
1030
|
}
|
|
1031
1031
|
const inputTypeName = field.input ? `${capitalize(fieldId)}Input` : void 0;
|
|
1032
|
-
const
|
|
1032
|
+
const outputRootName = field.output ? `${capitalize(fieldId)}Output` : void 0;
|
|
1033
1033
|
if (field.input && inputTypeName) {
|
|
1034
1034
|
const jsonSchema = field.input.toJsonSchema();
|
|
1035
|
-
|
|
1035
|
+
registerInputType(inputTypeName, jsonSchema, namedTypes);
|
|
1036
1036
|
}
|
|
1037
|
-
|
|
1037
|
+
let outputTypeName;
|
|
1038
|
+
if (field.output && outputRootName) {
|
|
1038
1039
|
const jsonSchema = field.output.toJsonSchema();
|
|
1039
|
-
|
|
1040
|
+
outputTypeName = registerOutputType(outputRootName, jsonSchema, namedTypes);
|
|
1040
1041
|
}
|
|
1041
1042
|
let signature = ` ${fieldId}`;
|
|
1042
1043
|
if (inputTypeName) {
|
|
@@ -1053,45 +1054,124 @@ function buildFieldLine(fieldId, field, namedTypes, includeDescriptions, include
|
|
|
1053
1054
|
}
|
|
1054
1055
|
return signature;
|
|
1055
1056
|
}
|
|
1056
|
-
function
|
|
1057
|
+
function registerInputType(typeName, jsonSchema, namedTypes) {
|
|
1058
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
1059
|
+
namedTypes.set(typeName, "");
|
|
1060
|
+
const properties = jsonSchema.properties ?? {};
|
|
1061
|
+
const required = new Set(
|
|
1062
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
1063
|
+
);
|
|
1057
1064
|
const lines = [`input ${typeName} {`];
|
|
1058
|
-
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1065
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
1066
|
+
const graphqlType = jsonSchemaToGraphQLType(
|
|
1067
|
+
propSchema,
|
|
1068
|
+
`${typeName}_${capitalize(propName)}`,
|
|
1069
|
+
namedTypes,
|
|
1070
|
+
"input"
|
|
1061
1071
|
);
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
)) {
|
|
1065
|
-
const graphqlType = jsonSchemaToGraphQLType(propSchema);
|
|
1066
|
-
const isRequired = required.has(propName);
|
|
1067
|
-
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
1068
|
-
}
|
|
1072
|
+
const isRequired = required.has(propName);
|
|
1073
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
1069
1074
|
}
|
|
1070
1075
|
lines.push("}");
|
|
1071
|
-
|
|
1076
|
+
namedTypes.set(typeName, lines.join("\n"));
|
|
1077
|
+
return typeName;
|
|
1072
1078
|
}
|
|
1073
|
-
function
|
|
1079
|
+
function registerOutputType(typeName, jsonSchema, namedTypes) {
|
|
1080
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
1081
|
+
if (jsonSchema.type === "array") {
|
|
1082
|
+
const items = jsonSchema.items;
|
|
1083
|
+
if (!items) return "[JSON]";
|
|
1084
|
+
const itemTypeName = jsonSchemaToGraphQLType(items, `${typeName}_Item`, namedTypes, "output");
|
|
1085
|
+
return `[${itemTypeName}]`;
|
|
1086
|
+
}
|
|
1087
|
+
const variants = pickVariants(jsonSchema);
|
|
1088
|
+
if (variants) {
|
|
1089
|
+
return registerUnionType(typeName, variants, namedTypes);
|
|
1090
|
+
}
|
|
1091
|
+
namedTypes.set(typeName, "");
|
|
1092
|
+
const properties = jsonSchema.properties ?? {};
|
|
1093
|
+
if (Object.keys(properties).length === 0) {
|
|
1094
|
+
namedTypes.delete(typeName);
|
|
1095
|
+
return "JSON";
|
|
1096
|
+
}
|
|
1097
|
+
const required = new Set(
|
|
1098
|
+
Array.isArray(jsonSchema.required) ? jsonSchema.required : []
|
|
1099
|
+
);
|
|
1074
1100
|
const lines = [`type ${typeName} {`];
|
|
1075
|
-
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1101
|
+
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
1102
|
+
const graphqlType = jsonSchemaToGraphQLType(
|
|
1103
|
+
propSchema,
|
|
1104
|
+
`${typeName}_${capitalize(propName)}`,
|
|
1105
|
+
namedTypes,
|
|
1106
|
+
"output"
|
|
1078
1107
|
);
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
)) {
|
|
1082
|
-
const graphqlType = jsonSchemaToGraphQLType(propSchema);
|
|
1083
|
-
const isRequired = required.has(propName);
|
|
1084
|
-
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
1085
|
-
}
|
|
1108
|
+
const isRequired = required.has(propName);
|
|
1109
|
+
lines.push(` ${propName}: ${graphqlType}${isRequired ? "!" : ""}`);
|
|
1086
1110
|
}
|
|
1087
1111
|
lines.push("}");
|
|
1088
|
-
|
|
1112
|
+
namedTypes.set(typeName, lines.join("\n"));
|
|
1113
|
+
return typeName;
|
|
1114
|
+
}
|
|
1115
|
+
function registerUnionType(typeName, variants, namedTypes) {
|
|
1116
|
+
if (namedTypes.has(typeName)) return typeName;
|
|
1117
|
+
namedTypes.set(typeName, "");
|
|
1118
|
+
const memberNames = [];
|
|
1119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1120
|
+
for (let i = 0; i < variants.length; i++) {
|
|
1121
|
+
const variant = variants[i];
|
|
1122
|
+
if (!variant || !isObjectSchema(variant)) {
|
|
1123
|
+
namedTypes.delete(typeName);
|
|
1124
|
+
return "JSON";
|
|
1125
|
+
}
|
|
1126
|
+
const discriminator = pickDiscriminatorLabel(variant);
|
|
1127
|
+
let memberName = discriminator ? `${typeName}_${pascalize(discriminator)}` : `${typeName}_Member${i + 1}`;
|
|
1128
|
+
let suffix = 2;
|
|
1129
|
+
while (seen.has(memberName)) {
|
|
1130
|
+
memberName = `${typeName}_${pascalize(discriminator ?? "Member")}${suffix++}`;
|
|
1131
|
+
}
|
|
1132
|
+
seen.add(memberName);
|
|
1133
|
+
registerOutputType(memberName, variant, namedTypes);
|
|
1134
|
+
memberNames.push(memberName);
|
|
1135
|
+
}
|
|
1136
|
+
namedTypes.set(typeName, `union ${typeName} = ${memberNames.join(" | ")}`);
|
|
1137
|
+
return typeName;
|
|
1138
|
+
}
|
|
1139
|
+
function pickVariants(schema) {
|
|
1140
|
+
if (Array.isArray(schema.oneOf)) return schema.oneOf;
|
|
1141
|
+
if (Array.isArray(schema.anyOf)) return schema.anyOf;
|
|
1142
|
+
return null;
|
|
1143
|
+
}
|
|
1144
|
+
function isObjectSchema(schema) {
|
|
1145
|
+
if (!schema || typeof schema !== "object") return false;
|
|
1146
|
+
if (schema.type === "object") return true;
|
|
1147
|
+
if (schema.properties && typeof schema.properties === "object") return true;
|
|
1148
|
+
return false;
|
|
1089
1149
|
}
|
|
1090
|
-
function
|
|
1150
|
+
function pickDiscriminatorLabel(schema) {
|
|
1151
|
+
const properties = schema.properties ?? {};
|
|
1152
|
+
for (const propSchema of Object.values(properties)) {
|
|
1153
|
+
if (!propSchema || typeof propSchema !== "object") continue;
|
|
1154
|
+
const constValue = propSchema.const;
|
|
1155
|
+
if (typeof constValue === "string" && constValue.length > 0) {
|
|
1156
|
+
return constValue;
|
|
1157
|
+
}
|
|
1158
|
+
const enumValue = propSchema.enum;
|
|
1159
|
+
if (Array.isArray(enumValue) && enumValue.length === 1 && typeof enumValue[0] === "string" && enumValue[0].length > 0) {
|
|
1160
|
+
return enumValue[0];
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
return null;
|
|
1164
|
+
}
|
|
1165
|
+
function jsonSchemaToGraphQLType(schema, parentTypeName, namedTypes, kind) {
|
|
1091
1166
|
if (!schema || typeof schema !== "object") return "JSON";
|
|
1092
1167
|
if (schema.enum && Array.isArray(schema.enum)) {
|
|
1093
1168
|
return "String";
|
|
1094
1169
|
}
|
|
1170
|
+
const variants = pickVariants(schema);
|
|
1171
|
+
if (variants) {
|
|
1172
|
+
if (kind === "input") return "JSON";
|
|
1173
|
+
return registerUnionType(parentTypeName, variants, namedTypes);
|
|
1174
|
+
}
|
|
1095
1175
|
const type = schema.type;
|
|
1096
1176
|
switch (type) {
|
|
1097
1177
|
case "string":
|
|
@@ -1104,19 +1184,29 @@ function jsonSchemaToGraphQLType(schema) {
|
|
|
1104
1184
|
return "Boolean";
|
|
1105
1185
|
case "array": {
|
|
1106
1186
|
const items = schema.items;
|
|
1107
|
-
if (items)
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1187
|
+
if (!items) return "[JSON]";
|
|
1188
|
+
const itemType = jsonSchemaToGraphQLType(
|
|
1189
|
+
items,
|
|
1190
|
+
// Singular-ish name for array element types — drop a trailing
|
|
1191
|
+
// 's' when present so `Tags[]` becomes `…_Tag`. Cheap heuristic;
|
|
1192
|
+
// fine for the conventional case.
|
|
1193
|
+
parentTypeName.replace(/s$/, ""),
|
|
1194
|
+
namedTypes,
|
|
1195
|
+
kind
|
|
1196
|
+
);
|
|
1197
|
+
return `[${itemType}]`;
|
|
1111
1198
|
}
|
|
1112
1199
|
case "object":
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (schema.oneOf || schema.anyOf || schema.allOf) {
|
|
1116
|
-
return "JSON";
|
|
1200
|
+
if (kind === "input") {
|
|
1201
|
+
return registerInputType(parentTypeName, schema, namedTypes);
|
|
1117
1202
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1203
|
+
return registerOutputType(parentTypeName, schema, namedTypes);
|
|
1204
|
+
default:
|
|
1205
|
+
if (isObjectSchema(schema)) {
|
|
1206
|
+
if (kind === "input") {
|
|
1207
|
+
return registerInputType(parentTypeName, schema, namedTypes);
|
|
1208
|
+
}
|
|
1209
|
+
return registerOutputType(parentTypeName, schema, namedTypes);
|
|
1120
1210
|
}
|
|
1121
1211
|
return "JSON";
|
|
1122
1212
|
}
|
|
@@ -1124,6 +1214,9 @@ function jsonSchemaToGraphQLType(schema) {
|
|
|
1124
1214
|
function capitalize(str) {
|
|
1125
1215
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1126
1216
|
}
|
|
1217
|
+
function pascalize(str) {
|
|
1218
|
+
return str.split(/[^a-zA-Z0-9]+/g).filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
|
|
1219
|
+
}
|
|
1127
1220
|
function escapeSDLString(str) {
|
|
1128
1221
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
1129
1222
|
}
|