@gqloom/json 0.11.0

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/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Modevol https://www.modevol.com/
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ ![GQLoom Logo](https://github.com/modevol-com/gqloom/blob/main/gqloom.svg?raw=true)
2
+
3
+ # GQLoom
4
+
5
+ GQLoom is a **Code-First** GraphQL Schema Loom used to weave **runtime types** in the **TypeScript/JavaScript** ecosystem into GraphQL Schema, helping you build GraphQL server enjoyably and efficiently.
6
+
7
+ Runtime validation libraries such as [Zod](https://zod.dev/), [Valibot](https://valibot.dev/), and [Yup](https://github.com/jquense/yup) have been widely used in backend application development. Meanwhile, when using ORM libraries like [Prisma](https://www.prisma.io/), [MikroORM](https://mikro-orm.io/), and [Drizzle](https://orm.drizzle.team/), we also pre-define database table structures or entity models that contain runtime types.
8
+ The responsibility of GQLoom is to weave these runtime types into a GraphQL Schema.
9
+
10
+ When developing backend applications with GQLoom, you only need to write types using the Schema libraries you're familiar with. Modern Schema libraries will infer TypeScript types for you, and GQLoom will weave GraphQL types for you.
11
+ In addition, the **resolver factory** of GQLoom can create CRUD interfaces for `Prisma`, `MikroORM`, and `Drizzle`, and supports custom input and adding middleware.
12
+
13
+ # @gqloom/json
14
+
15
+ This package provides GQLoom integration with [JSON Schema](https://json-schema.org/) to weave JSON Schema to GraphQL Schema.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # use npm
21
+ npm i @gqloom/core @gqloom/json
22
+
23
+ # use pnpm
24
+ pnpm add @gqloom/core @gqloom/json
25
+
26
+ # use yarn
27
+ yarn add @gqloom/core @gqloom/json
28
+ ```
29
+
30
+ ## Hello World
31
+
32
+ ```ts
33
+ import { query, resolver, weave } from "@gqloom/core"
34
+ import { jsonSilk } from "@gqloom/json"
35
+
36
+ const helloResolver = resolver({
37
+ hello: query(jsonSilk({ type: "string" }))
38
+ .input({ name: jsonSilk({ type: "string" }) })
39
+ .resolve(({ name }) => `Hello, ${name}!`),
40
+ })
41
+
42
+ export const schema = weave(helloResolver)
43
+ ```
44
+
45
+ Read more at [GQLoom Document](https://gqloom.dev/docs/schema/json).
package/dist/index.cjs ADDED
@@ -0,0 +1,227 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __gqloom_core = require("@gqloom/core");
25
+ __gqloom_core = __toESM(__gqloom_core);
26
+ let graphql = require("graphql");
27
+ graphql = __toESM(graphql);
28
+
29
+ //#region src/index.ts
30
+ var JSONWeaver = class JSONWeaver {
31
+ static vendor = "json";
32
+ /**
33
+ * Create a JSON weaver config object
34
+ * @param config JSON weaver config options
35
+ * @returns a JSON weaver config object
36
+ */
37
+ static config = function(config) {
38
+ return {
39
+ ...config,
40
+ [__gqloom_core.SYMBOLS.WEAVER_CONFIG]: "gqloom.json"
41
+ };
42
+ };
43
+ /**
44
+ * get GraphQL Silk from JSON Schema
45
+ * @param schema JSON Schema
46
+ * @returns GraphQL Silk Like JSON Schema
47
+ */
48
+ static unravel(schema) {
49
+ const config = __gqloom_core.weaverContext.value?.getConfig("gqloom.json");
50
+ if (typeof schema === "object" && !("~standard" in schema)) Object.defineProperty(schema, "~standard", {
51
+ value: {
52
+ version: 1,
53
+ vendor: "gqloom.json",
54
+ validate: (value) => ({ value })
55
+ },
56
+ enumerable: false
57
+ });
58
+ if (typeof schema === "object" && !(__gqloom_core.SYMBOLS.GET_GRAPHQL_TYPE in schema)) Object.defineProperty(schema, __gqloom_core.SYMBOLS.GET_GRAPHQL_TYPE, {
59
+ value: config ? function() {
60
+ return __gqloom_core.weaverContext.useConfig(config, () => JSONWeaver.getGraphQLTypeBySelf.call(this));
61
+ } : JSONWeaver.getGraphQLTypeBySelf,
62
+ enumerable: false
63
+ });
64
+ return schema;
65
+ }
66
+ static sourceTypeMap = /* @__PURE__ */ new Map();
67
+ static getGraphQLType(schema, { source } = {}) {
68
+ if (source) JSONWeaver.sourceTypeMap.set(schema, source);
69
+ return JSONWeaver.toNullableGraphQLType(schema);
70
+ }
71
+ static getGraphQLTypeBySelf() {
72
+ return JSONWeaver.toNullableGraphQLType(this);
73
+ }
74
+ static toNullableGraphQLType(schema) {
75
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
76
+ const gqlType = JSONWeaver.toMemoriedGraphQLType(schema);
77
+ const type = schema.type;
78
+ if (typeof schema.default !== "undefined" || Array.isArray(type) && type.includes("null") || [...schema.anyOf ?? [], ...schema.oneOf ?? []].some((s) => typeof s === "object" && s && s.type === "null")) return (0, graphql.isNonNullType)(gqlType) ? gqlType.ofType : gqlType;
79
+ return (0, graphql.isNonNullType)(gqlType) ? gqlType : new graphql.GraphQLNonNull(gqlType);
80
+ }
81
+ static toMemoriedGraphQLType(schema) {
82
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
83
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema) ?? JSONWeaver.getTypeName(schema);
84
+ const existing = __gqloom_core.weaverContext.getGraphQLType(schema) ?? (name ? __gqloom_core.weaverContext.getNamedType(name) : void 0);
85
+ if (existing) return existing;
86
+ const gqlType = JSONWeaver.toGraphQLTypeInner(schema);
87
+ if (name) __gqloom_core.weaverContext.memoNamedType(gqlType);
88
+ return __gqloom_core.weaverContext.memoGraphQLType(schema, gqlType);
89
+ }
90
+ static toGraphQLTypeInner(schema) {
91
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
92
+ const presetType = (__gqloom_core.weaverContext.value?.getConfig("gqloom.json"))?.presetGraphQLType?.(schema);
93
+ if (presetType) return presetType;
94
+ if (schema.allOf) {
95
+ const interfaceSchemas = schema.allOf.filter((s) => {
96
+ const subSchema = s;
97
+ return typeof subSchema === "object" && subSchema.title && subSchema.properties;
98
+ });
99
+ const mergedProperties = {};
100
+ const mergedRequired = [];
101
+ for (const subSchema of schema.allOf) {
102
+ const s = subSchema;
103
+ if (typeof s === "object" && s.properties) {
104
+ Object.assign(mergedProperties, s.properties);
105
+ if (s.required) mergedRequired.push(...s.required);
106
+ }
107
+ }
108
+ const mergedSchema = {
109
+ title: schema.title,
110
+ type: "object",
111
+ properties: mergedProperties,
112
+ required: mergedRequired,
113
+ description: schema.description
114
+ };
115
+ const objectType = JSONWeaver.toGraphQLTypeInner(mergedSchema);
116
+ if (interfaceSchemas.length > 0) {
117
+ const interfaceTypes = interfaceSchemas.map((interfaceSchema) => {
118
+ const interfaceObjectType = JSONWeaver.toMemoriedGraphQLType(interfaceSchema);
119
+ return (0, __gqloom_core.ensureInterfaceType)(interfaceObjectType);
120
+ });
121
+ return new graphql.GraphQLObjectType({
122
+ ...objectType.toConfig(),
123
+ interfaces: interfaceTypes
124
+ });
125
+ }
126
+ return objectType;
127
+ }
128
+ if (schema.oneOf || schema.anyOf) {
129
+ const schemas = (schema.oneOf ?? schema.anyOf).filter((s) => {
130
+ const subSchema = s;
131
+ if (typeof subSchema !== "object" || !subSchema) return true;
132
+ return subSchema.type !== "null";
133
+ });
134
+ if (schemas.length === 1) {
135
+ const unwrappedSchema = {
136
+ ...schemas[0],
137
+ title: schema.title,
138
+ $id: schema.$id,
139
+ description: schema.description
140
+ };
141
+ return JSONWeaver.toGraphQLTypeInner(unwrappedSchema);
142
+ }
143
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema);
144
+ if (!name) throw new Error("Union type must have a name");
145
+ return new graphql.GraphQLUnionType({
146
+ name,
147
+ description: schema.description,
148
+ types: () => schemas.map((s) => {
149
+ const gqlType = JSONWeaver.toMemoriedGraphQLType(s);
150
+ if (!(0, graphql.isObjectType)(gqlType)) throw new Error(`Union type member of ${name} must be an object type`);
151
+ return gqlType;
152
+ })
153
+ });
154
+ }
155
+ const type = Array.isArray(schema.type) ? schema.type.find((t) => t !== "null") : schema.type;
156
+ if (schema.enum) {
157
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema);
158
+ if (!name) throw new Error("Enum type must have a name");
159
+ const values = {};
160
+ for (const value of schema.enum) if (typeof value === "string" || typeof value === "number") {
161
+ const key = String(value).replace(/[^_a-zA-Z0-9]/g, "_");
162
+ values[key] = { value };
163
+ }
164
+ return new graphql.GraphQLEnumType({
165
+ name,
166
+ description: schema.description,
167
+ values
168
+ });
169
+ }
170
+ switch (type) {
171
+ case "string": return graphql.GraphQLString;
172
+ case "number": return graphql.GraphQLFloat;
173
+ case "integer": return graphql.GraphQLInt;
174
+ case "boolean": return graphql.GraphQLBoolean;
175
+ case "array": {
176
+ if (!schema.items || typeof schema.items !== "object" || Array.isArray(schema.items)) throw new Error("Array schema must have a single object in 'items'");
177
+ const itemType = JSONWeaver.toNullableGraphQLType(schema.items);
178
+ return new graphql.GraphQLList(itemType);
179
+ }
180
+ case "object": {
181
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema) ?? JSONWeaver.getTypeName(schema) ?? __gqloom_core.LoomObjectType.AUTO_ALIASING;
182
+ return new graphql.GraphQLObjectType({
183
+ name,
184
+ description: schema.description,
185
+ fields: () => (0, __gqloom_core.mapValue)(schema.properties ?? {}, (propSchema, key) => {
186
+ if (key.startsWith("__")) return __gqloom_core.mapValue.SKIP;
187
+ const fieldSchema = propSchema;
188
+ if (typeof fieldSchema === "boolean") throw new Error("Boolean JSON schemas are not supported in properties");
189
+ let fieldType = JSONWeaver.toMemoriedGraphQLType(fieldSchema);
190
+ if (schema.required?.includes(key)) {
191
+ if (!(0, graphql.isNonNullType)(fieldType)) fieldType = new graphql.GraphQLNonNull(fieldType);
192
+ } else if ((0, graphql.isNonNullType)(fieldType)) fieldType = fieldType.ofType;
193
+ return {
194
+ type: fieldType,
195
+ description: fieldSchema.description,
196
+ defaultValue: fieldSchema.default
197
+ };
198
+ })
199
+ });
200
+ }
201
+ case "null": throw new Error("Standalone 'null' type is not supported in GraphQL. It can only be used in a union type, like ['string', 'null']");
202
+ }
203
+ throw new Error(`Unsupported JSON schema type: ${String(type)}`);
204
+ }
205
+ static getTypeName(schema) {
206
+ if (typeof schema !== "object") return void 0;
207
+ if (!schema.properties?.__typename) return void 0;
208
+ const typenameSchema = schema.properties?.__typename;
209
+ if (typeof typenameSchema === "object" && typenameSchema.const && typeof typenameSchema.const === "string") return typenameSchema.const;
210
+ if (typeof typenameSchema === "object" && typenameSchema.enum && Array.isArray(typenameSchema.enum) && typenameSchema.enum.length === 1) return typenameSchema.enum[0];
211
+ }
212
+ static getCollectedName(schema) {
213
+ if (typeof schema !== "object") return void 0;
214
+ const name = __gqloom_core.weaverContext.names.get(schema);
215
+ if (name) return name;
216
+ const source = JSONWeaver.sourceTypeMap.get(schema);
217
+ if (source == null) return void 0;
218
+ return __gqloom_core.weaverContext.names.get(source);
219
+ }
220
+ };
221
+ function jsonSilk(schema) {
222
+ return JSONWeaver.unravel(schema);
223
+ }
224
+
225
+ //#endregion
226
+ exports.JSONWeaver = JSONWeaver;
227
+ exports.jsonSilk = jsonSilk;
@@ -0,0 +1,44 @@
1
+ import { GraphQLSilk, SYMBOLS, WeaverConfig } from "@gqloom/core";
2
+ import { GraphQLOutputType } from "graphql";
3
+ import { FromSchema, JSONSchema, JSONSchema as JSONSchema$1 } from "json-schema-to-ts";
4
+
5
+ //#region src/types.d.ts
6
+ interface JSONWeaverConfigOptions {
7
+ presetGraphQLType?: (schema: JSONSchema$1) => GraphQLOutputType | undefined;
8
+ }
9
+ interface JSONWeaverConfig extends WeaverConfig, JSONWeaverConfigOptions {
10
+ [SYMBOLS.WEAVER_CONFIG]: "gqloom.json";
11
+ }
12
+ //#endregion
13
+ //#region src/index.d.ts
14
+ declare class JSONWeaver {
15
+ static vendor: string;
16
+ /**
17
+ * Create a JSON weaver config object
18
+ * @param config JSON weaver config options
19
+ * @returns a JSON weaver config object
20
+ */
21
+ static config: (config: JSONWeaverConfigOptions) => JSONWeaverConfig;
22
+ /**
23
+ * get GraphQL Silk from JSON Schema
24
+ * @param schema JSON Schema
25
+ * @returns GraphQL Silk Like JSON Schema
26
+ */
27
+ static unravel<const TSchema extends JSONSchema, TData = FromSchema<TSchema>>(schema: TSchema): JSONSilk<TSchema, TData>;
28
+ protected static sourceTypeMap: Map<JSONSchema, any>;
29
+ static getGraphQLType(schema: JSONSchema, {
30
+ source
31
+ }?: {
32
+ source?: any;
33
+ }): GraphQLOutputType;
34
+ protected static getGraphQLTypeBySelf(this: JSONSchema): GraphQLOutputType;
35
+ protected static toNullableGraphQLType(schema: JSONSchema): GraphQLOutputType;
36
+ protected static toMemoriedGraphQLType(schema: JSONSchema): GraphQLOutputType;
37
+ protected static toGraphQLTypeInner(schema: JSONSchema): GraphQLOutputType;
38
+ protected static getTypeName(schema: JSONSchema): string | undefined;
39
+ protected static getCollectedName(schema: JSONSchema): string | undefined;
40
+ }
41
+ type JSONSilk<TSchema extends JSONSchema, TData = FromSchema<TSchema>> = TSchema & GraphQLSilk<TData, TData>;
42
+ declare function jsonSilk<const TSchema extends JSONSchema, TData = FromSchema<TSchema>>(schema: TSchema): JSONSilk<TSchema, TData>;
43
+ //#endregion
44
+ export { type FromSchema, type JSONSchema, JSONSilk, JSONWeaver, jsonSilk };
@@ -0,0 +1,44 @@
1
+ import { GraphQLSilk, SYMBOLS, WeaverConfig } from "@gqloom/core";
2
+ import { GraphQLOutputType } from "graphql";
3
+ import { FromSchema, JSONSchema, JSONSchema as JSONSchema$1 } from "json-schema-to-ts";
4
+
5
+ //#region src/types.d.ts
6
+ interface JSONWeaverConfigOptions {
7
+ presetGraphQLType?: (schema: JSONSchema$1) => GraphQLOutputType | undefined;
8
+ }
9
+ interface JSONWeaverConfig extends WeaverConfig, JSONWeaverConfigOptions {
10
+ [SYMBOLS.WEAVER_CONFIG]: "gqloom.json";
11
+ }
12
+ //#endregion
13
+ //#region src/index.d.ts
14
+ declare class JSONWeaver {
15
+ static vendor: string;
16
+ /**
17
+ * Create a JSON weaver config object
18
+ * @param config JSON weaver config options
19
+ * @returns a JSON weaver config object
20
+ */
21
+ static config: (config: JSONWeaverConfigOptions) => JSONWeaverConfig;
22
+ /**
23
+ * get GraphQL Silk from JSON Schema
24
+ * @param schema JSON Schema
25
+ * @returns GraphQL Silk Like JSON Schema
26
+ */
27
+ static unravel<const TSchema extends JSONSchema, TData = FromSchema<TSchema>>(schema: TSchema): JSONSilk<TSchema, TData>;
28
+ protected static sourceTypeMap: Map<JSONSchema, any>;
29
+ static getGraphQLType(schema: JSONSchema, {
30
+ source
31
+ }?: {
32
+ source?: any;
33
+ }): GraphQLOutputType;
34
+ protected static getGraphQLTypeBySelf(this: JSONSchema): GraphQLOutputType;
35
+ protected static toNullableGraphQLType(schema: JSONSchema): GraphQLOutputType;
36
+ protected static toMemoriedGraphQLType(schema: JSONSchema): GraphQLOutputType;
37
+ protected static toGraphQLTypeInner(schema: JSONSchema): GraphQLOutputType;
38
+ protected static getTypeName(schema: JSONSchema): string | undefined;
39
+ protected static getCollectedName(schema: JSONSchema): string | undefined;
40
+ }
41
+ type JSONSilk<TSchema extends JSONSchema, TData = FromSchema<TSchema>> = TSchema & GraphQLSilk<TData, TData>;
42
+ declare function jsonSilk<const TSchema extends JSONSchema, TData = FromSchema<TSchema>>(schema: TSchema): JSONSilk<TSchema, TData>;
43
+ //#endregion
44
+ export { type FromSchema, type JSONSchema, JSONSilk, JSONWeaver, jsonSilk };
package/dist/index.js ADDED
@@ -0,0 +1,201 @@
1
+ import { LoomObjectType, SYMBOLS, ensureInterfaceType, mapValue, weaverContext } from "@gqloom/core";
2
+ import { GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLString, GraphQLUnionType, isNonNullType, isObjectType } from "graphql";
3
+
4
+ //#region src/index.ts
5
+ var JSONWeaver = class JSONWeaver {
6
+ static vendor = "json";
7
+ /**
8
+ * Create a JSON weaver config object
9
+ * @param config JSON weaver config options
10
+ * @returns a JSON weaver config object
11
+ */
12
+ static config = function(config) {
13
+ return {
14
+ ...config,
15
+ [SYMBOLS.WEAVER_CONFIG]: "gqloom.json"
16
+ };
17
+ };
18
+ /**
19
+ * get GraphQL Silk from JSON Schema
20
+ * @param schema JSON Schema
21
+ * @returns GraphQL Silk Like JSON Schema
22
+ */
23
+ static unravel(schema) {
24
+ const config = weaverContext.value?.getConfig("gqloom.json");
25
+ if (typeof schema === "object" && !("~standard" in schema)) Object.defineProperty(schema, "~standard", {
26
+ value: {
27
+ version: 1,
28
+ vendor: "gqloom.json",
29
+ validate: (value) => ({ value })
30
+ },
31
+ enumerable: false
32
+ });
33
+ if (typeof schema === "object" && !(SYMBOLS.GET_GRAPHQL_TYPE in schema)) Object.defineProperty(schema, SYMBOLS.GET_GRAPHQL_TYPE, {
34
+ value: config ? function() {
35
+ return weaverContext.useConfig(config, () => JSONWeaver.getGraphQLTypeBySelf.call(this));
36
+ } : JSONWeaver.getGraphQLTypeBySelf,
37
+ enumerable: false
38
+ });
39
+ return schema;
40
+ }
41
+ static sourceTypeMap = /* @__PURE__ */ new Map();
42
+ static getGraphQLType(schema, { source } = {}) {
43
+ if (source) JSONWeaver.sourceTypeMap.set(schema, source);
44
+ return JSONWeaver.toNullableGraphQLType(schema);
45
+ }
46
+ static getGraphQLTypeBySelf() {
47
+ return JSONWeaver.toNullableGraphQLType(this);
48
+ }
49
+ static toNullableGraphQLType(schema) {
50
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
51
+ const gqlType = JSONWeaver.toMemoriedGraphQLType(schema);
52
+ const type = schema.type;
53
+ if (typeof schema.default !== "undefined" || Array.isArray(type) && type.includes("null") || [...schema.anyOf ?? [], ...schema.oneOf ?? []].some((s) => typeof s === "object" && s && s.type === "null")) return isNonNullType(gqlType) ? gqlType.ofType : gqlType;
54
+ return isNonNullType(gqlType) ? gqlType : new GraphQLNonNull(gqlType);
55
+ }
56
+ static toMemoriedGraphQLType(schema) {
57
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
58
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema) ?? JSONWeaver.getTypeName(schema);
59
+ const existing = weaverContext.getGraphQLType(schema) ?? (name ? weaverContext.getNamedType(name) : void 0);
60
+ if (existing) return existing;
61
+ const gqlType = JSONWeaver.toGraphQLTypeInner(schema);
62
+ if (name) weaverContext.memoNamedType(gqlType);
63
+ return weaverContext.memoGraphQLType(schema, gqlType);
64
+ }
65
+ static toGraphQLTypeInner(schema) {
66
+ if (typeof schema === "boolean") throw new Error("Boolean JSON schemas are not supported");
67
+ const presetType = (weaverContext.value?.getConfig("gqloom.json"))?.presetGraphQLType?.(schema);
68
+ if (presetType) return presetType;
69
+ if (schema.allOf) {
70
+ const interfaceSchemas = schema.allOf.filter((s) => {
71
+ const subSchema = s;
72
+ return typeof subSchema === "object" && subSchema.title && subSchema.properties;
73
+ });
74
+ const mergedProperties = {};
75
+ const mergedRequired = [];
76
+ for (const subSchema of schema.allOf) {
77
+ const s = subSchema;
78
+ if (typeof s === "object" && s.properties) {
79
+ Object.assign(mergedProperties, s.properties);
80
+ if (s.required) mergedRequired.push(...s.required);
81
+ }
82
+ }
83
+ const mergedSchema = {
84
+ title: schema.title,
85
+ type: "object",
86
+ properties: mergedProperties,
87
+ required: mergedRequired,
88
+ description: schema.description
89
+ };
90
+ const objectType = JSONWeaver.toGraphQLTypeInner(mergedSchema);
91
+ if (interfaceSchemas.length > 0) {
92
+ const interfaceTypes = interfaceSchemas.map((interfaceSchema) => {
93
+ const interfaceObjectType = JSONWeaver.toMemoriedGraphQLType(interfaceSchema);
94
+ return ensureInterfaceType(interfaceObjectType);
95
+ });
96
+ return new GraphQLObjectType({
97
+ ...objectType.toConfig(),
98
+ interfaces: interfaceTypes
99
+ });
100
+ }
101
+ return objectType;
102
+ }
103
+ if (schema.oneOf || schema.anyOf) {
104
+ const schemas = (schema.oneOf ?? schema.anyOf).filter((s) => {
105
+ const subSchema = s;
106
+ if (typeof subSchema !== "object" || !subSchema) return true;
107
+ return subSchema.type !== "null";
108
+ });
109
+ if (schemas.length === 1) {
110
+ const unwrappedSchema = {
111
+ ...schemas[0],
112
+ title: schema.title,
113
+ $id: schema.$id,
114
+ description: schema.description
115
+ };
116
+ return JSONWeaver.toGraphQLTypeInner(unwrappedSchema);
117
+ }
118
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema);
119
+ if (!name) throw new Error("Union type must have a name");
120
+ return new GraphQLUnionType({
121
+ name,
122
+ description: schema.description,
123
+ types: () => schemas.map((s) => {
124
+ const gqlType = JSONWeaver.toMemoriedGraphQLType(s);
125
+ if (!isObjectType(gqlType)) throw new Error(`Union type member of ${name} must be an object type`);
126
+ return gqlType;
127
+ })
128
+ });
129
+ }
130
+ const type = Array.isArray(schema.type) ? schema.type.find((t) => t !== "null") : schema.type;
131
+ if (schema.enum) {
132
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema);
133
+ if (!name) throw new Error("Enum type must have a name");
134
+ const values = {};
135
+ for (const value of schema.enum) if (typeof value === "string" || typeof value === "number") {
136
+ const key = String(value).replace(/[^_a-zA-Z0-9]/g, "_");
137
+ values[key] = { value };
138
+ }
139
+ return new GraphQLEnumType({
140
+ name,
141
+ description: schema.description,
142
+ values
143
+ });
144
+ }
145
+ switch (type) {
146
+ case "string": return GraphQLString;
147
+ case "number": return GraphQLFloat;
148
+ case "integer": return GraphQLInt;
149
+ case "boolean": return GraphQLBoolean;
150
+ case "array": {
151
+ if (!schema.items || typeof schema.items !== "object" || Array.isArray(schema.items)) throw new Error("Array schema must have a single object in 'items'");
152
+ const itemType = JSONWeaver.toNullableGraphQLType(schema.items);
153
+ return new GraphQLList(itemType);
154
+ }
155
+ case "object": {
156
+ const name = schema.title ?? JSONWeaver.getCollectedName(schema) ?? JSONWeaver.getTypeName(schema) ?? LoomObjectType.AUTO_ALIASING;
157
+ return new GraphQLObjectType({
158
+ name,
159
+ description: schema.description,
160
+ fields: () => mapValue(schema.properties ?? {}, (propSchema, key) => {
161
+ if (key.startsWith("__")) return mapValue.SKIP;
162
+ const fieldSchema = propSchema;
163
+ if (typeof fieldSchema === "boolean") throw new Error("Boolean JSON schemas are not supported in properties");
164
+ let fieldType = JSONWeaver.toMemoriedGraphQLType(fieldSchema);
165
+ if (schema.required?.includes(key)) {
166
+ if (!isNonNullType(fieldType)) fieldType = new GraphQLNonNull(fieldType);
167
+ } else if (isNonNullType(fieldType)) fieldType = fieldType.ofType;
168
+ return {
169
+ type: fieldType,
170
+ description: fieldSchema.description,
171
+ defaultValue: fieldSchema.default
172
+ };
173
+ })
174
+ });
175
+ }
176
+ case "null": throw new Error("Standalone 'null' type is not supported in GraphQL. It can only be used in a union type, like ['string', 'null']");
177
+ }
178
+ throw new Error(`Unsupported JSON schema type: ${String(type)}`);
179
+ }
180
+ static getTypeName(schema) {
181
+ if (typeof schema !== "object") return void 0;
182
+ if (!schema.properties?.__typename) return void 0;
183
+ const typenameSchema = schema.properties?.__typename;
184
+ if (typeof typenameSchema === "object" && typenameSchema.const && typeof typenameSchema.const === "string") return typenameSchema.const;
185
+ if (typeof typenameSchema === "object" && typenameSchema.enum && Array.isArray(typenameSchema.enum) && typenameSchema.enum.length === 1) return typenameSchema.enum[0];
186
+ }
187
+ static getCollectedName(schema) {
188
+ if (typeof schema !== "object") return void 0;
189
+ const name = weaverContext.names.get(schema);
190
+ if (name) return name;
191
+ const source = JSONWeaver.sourceTypeMap.get(schema);
192
+ if (source == null) return void 0;
193
+ return weaverContext.names.get(source);
194
+ }
195
+ };
196
+ function jsonSilk(schema) {
197
+ return JSONWeaver.unravel(schema);
198
+ }
199
+
200
+ //#endregion
201
+ export { JSONWeaver, jsonSilk };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@gqloom/json",
3
+ "version": "0.11.0",
4
+ "description": "Create GraphQL schema and resolvers easily using using JSON Schema!",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "keywords": [
24
+ "gqloom",
25
+ "graphql",
26
+ "schema",
27
+ "typescript",
28
+ "json-schema",
29
+ "validation",
30
+ "validate"
31
+ ],
32
+ "author": "xcfox",
33
+ "license": "MIT",
34
+ "peerDependencies": {
35
+ "@gqloom/core": ">= 0.11.1",
36
+ "graphql": ">= 16.8.0"
37
+ },
38
+ "devDependencies": {
39
+ "ajv": "^8.17.1",
40
+ "arktype": "^2.1.22",
41
+ "effect": "^3.17.13",
42
+ "typebox": "^1.0.4",
43
+ "@gqloom/core": "0.11.1"
44
+ },
45
+ "homepage": "https://gqloom.dev/",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/modevol-com/gqloom.git",
49
+ "directory": "packages/json"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "dependencies": {
55
+ "json-schema-to-ts": "^3.1.1"
56
+ },
57
+ "scripts": {
58
+ "build": "tsdown",
59
+ "check:type": "tsgo --noEmit"
60
+ }
61
+ }