@uni2c/graphqlapi4mp 1.0.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/dist/index.cjs +315 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.mjs +310 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +43 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
const STR = "\0s";
|
|
4
|
+
const NUM = "\0n";
|
|
5
|
+
const EMPTY_ARGS = Object.freeze(Object.create(null));
|
|
6
|
+
const isNameStart = (c) => c === 95 || c >= 65 && c <= 90 || c >= 97 && c <= 122;
|
|
7
|
+
const isNameChar = (c) => isNameStart(c) || c >= 48 && c <= 57;
|
|
8
|
+
const isDigit = (c) => c >= 48 && c <= 57;
|
|
9
|
+
const TYPE_NAME_CACHE = Object.create(null);
|
|
10
|
+
function parseSDL(s) {
|
|
11
|
+
let i = s.charCodeAt(0) === 65279 ? 1 : 0;
|
|
12
|
+
const n = s.length;
|
|
13
|
+
let look;
|
|
14
|
+
const types = Object.create(null);
|
|
15
|
+
const scalars = /* @__PURE__ */ new Set([
|
|
16
|
+
"String",
|
|
17
|
+
"Int",
|
|
18
|
+
"Float",
|
|
19
|
+
"Boolean",
|
|
20
|
+
"ID"
|
|
21
|
+
]);
|
|
22
|
+
const enums = /* @__PURE__ */ new Set();
|
|
23
|
+
function scan() {
|
|
24
|
+
for (;;) {
|
|
25
|
+
if (i >= n) return;
|
|
26
|
+
const c = s.charCodeAt(i);
|
|
27
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 44) {
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (c === 35) {
|
|
32
|
+
while (++i < n) {
|
|
33
|
+
const x = s.charCodeAt(i);
|
|
34
|
+
if (x === 10 || x === 13) break;
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (c === 34 && s.charCodeAt(i + 1) === 34 && s.charCodeAt(i + 2) === 34) {
|
|
39
|
+
i += 3;
|
|
40
|
+
while (i < n) {
|
|
41
|
+
if (s.charCodeAt(i) === 34 && s.charCodeAt(i + 1) === 34 && s.charCodeAt(i + 2) === 34) {
|
|
42
|
+
i += 3;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
i += s.charCodeAt(i) === 92 ? 2 : 1;
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (c === 34) {
|
|
50
|
+
i++;
|
|
51
|
+
while (i < n) {
|
|
52
|
+
const x = s.charCodeAt(i++);
|
|
53
|
+
if (x === 92) i++;
|
|
54
|
+
else if (x === 34) break;
|
|
55
|
+
}
|
|
56
|
+
return STR;
|
|
57
|
+
}
|
|
58
|
+
if (isNameStart(c)) {
|
|
59
|
+
const p = i++;
|
|
60
|
+
while (i < n && isNameChar(s.charCodeAt(i))) i++;
|
|
61
|
+
return s.slice(p, i);
|
|
62
|
+
}
|
|
63
|
+
if (isDigit(c) || c === 45 && isDigit(s.charCodeAt(i + 1))) {
|
|
64
|
+
i++;
|
|
65
|
+
while (i < n) {
|
|
66
|
+
const x = s.charCodeAt(i);
|
|
67
|
+
if (isDigit(x) || x === 46 || x === 101 || x === 69 || x === 43 || x === 45) i++;
|
|
68
|
+
else break;
|
|
69
|
+
}
|
|
70
|
+
return NUM;
|
|
71
|
+
}
|
|
72
|
+
if (c === 46 && s.charCodeAt(i + 1) === 46 && s.charCodeAt(i + 2) === 46) {
|
|
73
|
+
i += 3;
|
|
74
|
+
return "...";
|
|
75
|
+
}
|
|
76
|
+
if (c === 123 || c === 125 || c === 40 || c === 41 || c === 91 || c === 93 || c === 58 || c === 33 || c === 61 || c === 36 || c === 64 || c === 124 || c === 38) {
|
|
77
|
+
i++;
|
|
78
|
+
return String.fromCharCode(c);
|
|
79
|
+
}
|
|
80
|
+
i++;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const peek = () => look ??= scan();
|
|
84
|
+
const take = () => {
|
|
85
|
+
const v = look ?? scan();
|
|
86
|
+
look = void 0;
|
|
87
|
+
return v;
|
|
88
|
+
};
|
|
89
|
+
const eat = (v) => {
|
|
90
|
+
if (peek() !== v) return false;
|
|
91
|
+
take();
|
|
92
|
+
return true;
|
|
93
|
+
};
|
|
94
|
+
const need = (v) => {
|
|
95
|
+
const x = take();
|
|
96
|
+
if (x !== v) throw new Error(`parseSDL: expected "${v}", got "${x ?? "EOF"}"`);
|
|
97
|
+
};
|
|
98
|
+
const needName = () => {
|
|
99
|
+
const x = take();
|
|
100
|
+
if (!x || x === STR || x === NUM || !isNameStart(x.charCodeAt(0))) throw new Error(`parseSDL: expected NAME, got "${x ?? "EOF"}"`);
|
|
101
|
+
return x;
|
|
102
|
+
};
|
|
103
|
+
function typeRef() {
|
|
104
|
+
if (eat("[")) {
|
|
105
|
+
let v = `[${typeRef()}]`;
|
|
106
|
+
need("]");
|
|
107
|
+
if (eat("!")) v += "!";
|
|
108
|
+
return v;
|
|
109
|
+
}
|
|
110
|
+
let v = needName();
|
|
111
|
+
if (eat("!")) v += "!";
|
|
112
|
+
return v;
|
|
113
|
+
}
|
|
114
|
+
function skipValue() {
|
|
115
|
+
if (eat("[")) {
|
|
116
|
+
while (peek() && peek() !== "]") skipValue();
|
|
117
|
+
need("]");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (eat("{")) {
|
|
121
|
+
while (peek() && peek() !== "}") {
|
|
122
|
+
needName();
|
|
123
|
+
need(":");
|
|
124
|
+
skipValue();
|
|
125
|
+
}
|
|
126
|
+
need("}");
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
take();
|
|
130
|
+
}
|
|
131
|
+
function skipDirectives() {
|
|
132
|
+
while (eat("@")) {
|
|
133
|
+
needName();
|
|
134
|
+
if (!eat("(")) continue;
|
|
135
|
+
let d = 1;
|
|
136
|
+
while (d && peek()) if (eat("(")) d++;
|
|
137
|
+
else if (eat(")")) d--;
|
|
138
|
+
else take();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function args() {
|
|
142
|
+
if (!eat("(")) return EMPTY_ARGS;
|
|
143
|
+
const out = Object.create(null);
|
|
144
|
+
while (peek() && peek() !== ")") {
|
|
145
|
+
const k = needName();
|
|
146
|
+
need(":");
|
|
147
|
+
out[k] = typeRef();
|
|
148
|
+
if (eat("=")) skipValue();
|
|
149
|
+
skipDirectives();
|
|
150
|
+
}
|
|
151
|
+
need(")");
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
function fields() {
|
|
155
|
+
const out = Object.create(null);
|
|
156
|
+
need("{");
|
|
157
|
+
while (peek() && peek() !== "}") {
|
|
158
|
+
const name = needName();
|
|
159
|
+
const a = args();
|
|
160
|
+
need(":");
|
|
161
|
+
const type = typeRef();
|
|
162
|
+
skipDirectives();
|
|
163
|
+
out[name] = {
|
|
164
|
+
name,
|
|
165
|
+
args: a,
|
|
166
|
+
type
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
need("}");
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
function objectType() {
|
|
173
|
+
const name = needName();
|
|
174
|
+
if (eat("implements")) {
|
|
175
|
+
eat("&");
|
|
176
|
+
while (peek() && peek() !== "{") take();
|
|
177
|
+
}
|
|
178
|
+
skipDirectives();
|
|
179
|
+
if (peek() !== "{") return;
|
|
180
|
+
types[name] = {
|
|
181
|
+
name,
|
|
182
|
+
fields: fields()
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function scalar() {
|
|
186
|
+
scalars.add(needName());
|
|
187
|
+
skipDirectives();
|
|
188
|
+
}
|
|
189
|
+
function enumType() {
|
|
190
|
+
enums.add(needName());
|
|
191
|
+
skipDirectives();
|
|
192
|
+
if (!eat("{")) return;
|
|
193
|
+
while (peek() && peek() !== "}") {
|
|
194
|
+
take();
|
|
195
|
+
skipDirectives();
|
|
196
|
+
}
|
|
197
|
+
need("}");
|
|
198
|
+
}
|
|
199
|
+
while (peek()) switch (take()) {
|
|
200
|
+
case "type":
|
|
201
|
+
objectType();
|
|
202
|
+
break;
|
|
203
|
+
case "scalar":
|
|
204
|
+
scalar();
|
|
205
|
+
break;
|
|
206
|
+
case "enum": enumType();
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
query: types.Query?.fields || {},
|
|
210
|
+
mutation: types.Mutation?.fields || {},
|
|
211
|
+
types,
|
|
212
|
+
scalars,
|
|
213
|
+
enums
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function unwrapType(type) {
|
|
217
|
+
let a = 0;
|
|
218
|
+
let b = type.length;
|
|
219
|
+
const first = type.charCodeAt(0);
|
|
220
|
+
const last = type.charCodeAt(b - 1);
|
|
221
|
+
if (first !== 91 && first !== 33 && last !== 93 && last !== 33) return type;
|
|
222
|
+
const cached = TYPE_NAME_CACHE[type];
|
|
223
|
+
if (cached) return cached;
|
|
224
|
+
while (a < b) {
|
|
225
|
+
const c = type.charCodeAt(a);
|
|
226
|
+
if (c !== 91 && c !== 33) break;
|
|
227
|
+
a++;
|
|
228
|
+
}
|
|
229
|
+
while (b > a) {
|
|
230
|
+
const c = type.charCodeAt(b - 1);
|
|
231
|
+
if (c !== 93 && c !== 33) break;
|
|
232
|
+
b--;
|
|
233
|
+
}
|
|
234
|
+
const name = type.slice(a, b);
|
|
235
|
+
TYPE_NAME_CACHE[type] = name;
|
|
236
|
+
return name;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* 根据 SDL Schema 为一个 Query/Mutation 字段生成 selection-set。
|
|
240
|
+
*
|
|
241
|
+
* 普通 scalar/enum 字段默认包含;对象字段仅在 config 中显式声明时展开。
|
|
242
|
+
* 该函数只生成字段树,不修改传入的 operation。
|
|
243
|
+
*/
|
|
244
|
+
function buildSelectionFields(schema, operation, config = {}) {
|
|
245
|
+
const schemaType = schema.types[unwrapType(operation.type)];
|
|
246
|
+
if (!schemaType) return [];
|
|
247
|
+
const result = [];
|
|
248
|
+
const fields = schemaType.fields;
|
|
249
|
+
for (const fieldName in fields) {
|
|
250
|
+
const fieldInfo = fields[fieldName];
|
|
251
|
+
const fieldConfig = config[fieldName];
|
|
252
|
+
if (fieldConfig === false) continue;
|
|
253
|
+
if (!schema.types[unwrapType(fieldInfo.type)]) {
|
|
254
|
+
result.push(fieldName);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (fieldConfig === void 0) continue;
|
|
258
|
+
result.push({
|
|
259
|
+
name: fieldName,
|
|
260
|
+
fields: buildSelectionFields(schema, fieldInfo, fieldConfig === true ? {} : fieldConfig)
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
/** 将递归字段树渲染为 GraphQL selection-set 文本。 */
|
|
266
|
+
function renderSelectionFields(fields, indent = " ") {
|
|
267
|
+
let out = "";
|
|
268
|
+
for (const field of fields) {
|
|
269
|
+
if (out) out += "\n";
|
|
270
|
+
if (typeof field === "string") {
|
|
271
|
+
out += indent + field;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const children = renderSelectionFields(field.fields, indent + " ");
|
|
275
|
+
out += children ? `${indent}${field.name} {\n${children}\n${indent}}` : indent + field.name;
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* 根据解析后的操作描述生成完整 GraphQL 文本。
|
|
281
|
+
*
|
|
282
|
+
* 参数定义全部来自 SDL,例如:
|
|
283
|
+
* query Company($id: Int, $pageNo: Int) { ... }
|
|
284
|
+
*
|
|
285
|
+
* operation.fields 可通过 buildSelectionFields() 生成,也可以自行传入。
|
|
286
|
+
*/
|
|
287
|
+
function buildGraphQLQuery(operation, operationType = "query") {
|
|
288
|
+
const { name, args = EMPTY_ARGS, fields = [] } = operation;
|
|
289
|
+
let variableDefinitions = "";
|
|
290
|
+
let argumentsText = "";
|
|
291
|
+
for (const argName in args) {
|
|
292
|
+
if (variableDefinitions) variableDefinitions += ", ";
|
|
293
|
+
variableDefinitions += `$${argName}: ${args[argName]}`;
|
|
294
|
+
argumentsText += `${argumentsText ? "\n" : ""} ${argName}: $${argName}`;
|
|
295
|
+
}
|
|
296
|
+
const selectionText = renderSelectionFields(fields);
|
|
297
|
+
let gql = `${operationType} ${name}`;
|
|
298
|
+
if (variableDefinitions) gql += `(${variableDefinitions})`;
|
|
299
|
+
gql += ` {\n ${name}`;
|
|
300
|
+
if (argumentsText) gql += `(\n${argumentsText}\n )`;
|
|
301
|
+
if (selectionText) gql += ` {\n${selectionText}\n }`;
|
|
302
|
+
return gql + "\n}";
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* 向后兼容旧名称。新代码建议使用 buildGraphQLQuery()。
|
|
306
|
+
*/
|
|
307
|
+
const buildQuery = buildGraphQLQuery;
|
|
308
|
+
//#endregion
|
|
309
|
+
exports.buildGraphQLQuery = buildGraphQLQuery;
|
|
310
|
+
exports.buildQuery = buildQuery;
|
|
311
|
+
exports.buildSelectionFields = buildSelectionFields;
|
|
312
|
+
exports.parseSDL = parseSDL;
|
|
313
|
+
exports.unwrapType = unwrapType;
|
|
314
|
+
|
|
315
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export interface SchemaField {\n name: string;\n args: Record<string, string>;\n type: string;\n}\n\nexport interface SchemaType {\n name: string;\n fields: Record<string, SchemaField>;\n}\n\nexport interface SchemaMeta {\n query: Record<string, SchemaField>;\n mutation: Record<string, SchemaField>;\n types: Record<string, SchemaType>;\n scalars: Set<string>;\n enums: Set<string>;\n}\n\n/** GraphQL selection-set 中的字段;对象字段可继续递归包含子字段。 */\nexport type GraphQLSelectionField =\n | string\n | {\n name: string;\n fields: GraphQLSelectionField[];\n };\n\n/**\n * 对象字段展开配置:\n * - 未定义:普通字段默认显示,对象字段默认不展开;\n * - false:明确隐藏字段;\n * - true:展开对象,并显示其普通字段;\n * - object:按配置递归展开子对象。\n */\nexport type GraphQLSelectionConfig = {\n [fieldName: string]: boolean | GraphQLSelectionConfig;\n};\n\n/** 可直接交给查询生成器的操作描述。 */\nexport type GraphQLOperation = SchemaField & {\n fields?: GraphQLSelectionField[];\n};\n\n/** GraphQL 根操作类型。 */\nexport type GraphQLOperationType = 'query' | 'mutation';\n\nconst STR = '\\0s';\nconst NUM = '\\0n';\n// 无参数字段共用同一个只读空对象,避免大型 SDL 中产生大量空 args 对象。\nconst EMPTY_ARGS: Record<string, string> = Object.freeze(Object.create(null));\n\nconst isNameStart = (c: number) =>\n c === 95 || (c >= 65 && c <= 90) || (c >= 97 && c <= 122);\nconst isNameChar = (c: number) => isNameStart(c) || (c >= 48 && c <= 57);\nconst isDigit = (c: number) => c >= 48 && c <= 57;\n// 仅缓存 [Type] / Type! 等包装类型的解包结果;普通类型走 unwrapType 快路径。\nconst TYPE_NAME_CACHE: Record<string, string> = Object.create(null);\n\nexport function parseSDL(s: string): SchemaMeta {\n let i = s.charCodeAt(0) === 0xfeff ? 1 : 0;\n const n = s.length;\n let look: string | undefined;\n\n const types: Record<string, SchemaType> = Object.create(null);\n const scalars = new Set(['String', 'Int', 'Float', 'Boolean', 'ID']);\n const enums = new Set<string>();\n\n function scan(): string | undefined {\n for (;;) {\n if (i >= n) return;\n const c = s.charCodeAt(i);\n\n // whitespace + comma\n if (c === 32 || c === 9 || c === 10 || c === 13 || c === 44) {\n i++;\n continue;\n }\n\n // # comment\n if (c === 35) {\n while (++i < n) {\n const x = s.charCodeAt(i);\n if (x === 10 || x === 13) break;\n }\n continue;\n }\n\n // block string / description: content is irrelevant for runtime schema\n if (\n c === 34 &&\n s.charCodeAt(i + 1) === 34 &&\n s.charCodeAt(i + 2) === 34\n ) {\n i += 3;\n while (i < n) {\n if (\n s.charCodeAt(i) === 34 &&\n s.charCodeAt(i + 1) === 34 &&\n s.charCodeAt(i + 2) === 34\n ) {\n i += 3;\n break;\n }\n // escaped character\n i += s.charCodeAt(i) === 92 ? 2 : 1;\n }\n continue;\n }\n\n // normal string; its value is not needed\n if (c === 34) {\n i++;\n while (i < n) {\n const x = s.charCodeAt(i++);\n if (x === 92) i++;\n else if (x === 34) break;\n }\n return STR;\n }\n\n // name / keyword\n if (isNameStart(c)) {\n const p = i++;\n while (i < n && isNameChar(s.charCodeAt(i))) i++;\n return s.slice(p, i);\n }\n\n // number; exact value is not needed\n if (isDigit(c) || (c === 45 && isDigit(s.charCodeAt(i + 1)))) {\n i++;\n while (i < n) {\n const x = s.charCodeAt(i);\n if (\n isDigit(x) ||\n x === 46 ||\n x === 101 ||\n x === 69 ||\n x === 43 ||\n x === 45\n )\n i++;\n else break;\n }\n return NUM;\n }\n\n // spread\n if (\n c === 46 &&\n s.charCodeAt(i + 1) === 46 &&\n s.charCodeAt(i + 2) === 46\n ) {\n i += 3;\n return '...';\n }\n\n // punctuation used by SDL\n if (\n c === 123 ||\n c === 125 ||\n c === 40 ||\n c === 41 ||\n c === 91 ||\n c === 93 ||\n c === 58 ||\n c === 33 ||\n c === 61 ||\n c === 36 ||\n c === 64 ||\n c === 124 ||\n c === 38\n ) {\n i++;\n return String.fromCharCode(c);\n }\n\n i++;\n }\n }\n\n const peek = () => (look ??= scan());\n const take = () => {\n const v = look ?? scan();\n look = undefined;\n return v;\n };\n const eat = (v: string) => {\n if (peek() !== v) return false;\n take();\n return true;\n };\n const need = (v: string) => {\n const x = take();\n if (x !== v)\n throw new Error(`parseSDL: expected \"${v}\", got \"${x ?? 'EOF'}\"`);\n };\n const needName = () => {\n const x = take();\n if (!x || x === STR || x === NUM || !isNameStart(x.charCodeAt(0)))\n throw new Error(`parseSDL: expected NAME, got \"${x ?? 'EOF'}\"`);\n return x;\n };\n\n function typeRef(): string {\n if (eat('[')) {\n let v = `[${typeRef()}]`;\n need(']');\n if (eat('!')) v += '!';\n return v;\n }\n let v = needName();\n if (eat('!')) v += '!';\n return v;\n }\n\n function skipValue() {\n if (eat('[')) {\n while (peek() && peek() !== ']') skipValue();\n need(']');\n return;\n }\n if (eat('{')) {\n while (peek() && peek() !== '}') {\n needName();\n need(':');\n skipValue();\n }\n need('}');\n return;\n }\n take();\n }\n\n function skipDirectives() {\n while (eat('@')) {\n needName();\n if (!eat('(')) continue;\n let d = 1;\n while (d && peek()) {\n if (eat('(')) d++;\n else if (eat(')')) d--;\n else take();\n }\n }\n }\n\n function args(): Record<string, string> {\n if (!eat('(')) return EMPTY_ARGS;\n\n const out: Record<string, string> = Object.create(null);\n while (peek() && peek() !== ')') {\n const k = needName();\n need(':');\n out[k] = typeRef();\n if (eat('=')) skipValue();\n skipDirectives();\n }\n need(')');\n return out;\n }\n\n function fields() {\n const out: Record<string, SchemaField> = Object.create(null);\n need('{');\n while (peek() && peek() !== '}') {\n const name = needName();\n const a = args();\n need(':');\n const type = typeRef();\n skipDirectives();\n out[name] = { name, args: a, type };\n }\n need('}');\n return out;\n }\n\n function objectType() {\n const name = needName();\n if (eat('implements')) {\n eat('&');\n while (peek() && peek() !== '{') take();\n }\n skipDirectives();\n if (peek() !== '{') return;\n types[name] = { name, fields: fields() };\n }\n\n function scalar() {\n scalars.add(needName());\n skipDirectives();\n }\n\n function enumType() {\n enums.add(needName());\n skipDirectives();\n if (!eat('{')) return;\n while (peek() && peek() !== '}') {\n take();\n skipDirectives();\n }\n need('}');\n }\n\n while (peek()) {\n switch (take()) {\n case 'type':\n objectType();\n break;\n case 'scalar':\n scalar();\n break;\n case 'enum':\n enumType();\n break;\n }\n }\n\n return {\n query: types.Query?.fields || {},\n mutation: types.Mutation?.fields || {},\n types,\n scalars,\n enums,\n };\n}\n\nexport function unwrapType(type: string): string {\n let a = 0;\n let b = type.length;\n\n const first = type.charCodeAt(0);\n const last = type.charCodeAt(b - 1);\n if (first !== 91 && first !== 33 && last !== 93 && last !== 33) return type;\n\n const cached = TYPE_NAME_CACHE[type];\n if (cached) return cached;\n\n while (a < b) {\n const c = type.charCodeAt(a);\n if (c !== 91 && c !== 33) break;\n a++;\n }\n while (b > a) {\n const c = type.charCodeAt(b - 1);\n if (c !== 93 && c !== 33) break;\n b--;\n }\n const name = type.slice(a, b);\n TYPE_NAME_CACHE[type] = name;\n return name;\n}\n\n/**\n * 根据 SDL Schema 为一个 Query/Mutation 字段生成 selection-set。\n *\n * 普通 scalar/enum 字段默认包含;对象字段仅在 config 中显式声明时展开。\n * 该函数只生成字段树,不修改传入的 operation。\n */\nexport function buildSelectionFields(\n schema: SchemaMeta,\n operation: SchemaField,\n config: GraphQLSelectionConfig = {},\n): GraphQLSelectionField[] {\n const schemaType = schema.types[unwrapType(operation.type)];\n if (!schemaType) return [];\n\n const result: GraphQLSelectionField[] = [];\n const fields = schemaType.fields;\n\n for (const fieldName in fields) {\n const fieldInfo = fields[fieldName];\n const fieldConfig = config[fieldName];\n\n // false:显式隐藏;undefined:scalar 默认显示、object 默认不展开。\n if (fieldConfig === false) continue;\n\n const childType = schema.types[unwrapType(fieldInfo.type)];\n if (!childType) {\n result.push(fieldName);\n continue;\n }\n\n if (fieldConfig === undefined) continue;\n\n result.push({\n name: fieldName,\n fields: buildSelectionFields(\n schema,\n fieldInfo,\n fieldConfig === true ? {} : fieldConfig,\n ),\n });\n }\n\n return result;\n}\n\n/** 将递归字段树渲染为 GraphQL selection-set 文本。 */\nfunction renderSelectionFields(\n fields: GraphQLSelectionField[],\n indent = ' ',\n): string {\n let out = '';\n\n for (const field of fields) {\n if (out) out += '\\n';\n\n if (typeof field === 'string') {\n out += indent + field;\n continue;\n }\n\n const children = renderSelectionFields(field.fields, indent + ' ');\n out += children\n ? `${indent}${field.name} {\\n${children}\\n${indent}}`\n : indent + field.name;\n }\n\n return out;\n}\n\n/**\n * 根据解析后的操作描述生成完整 GraphQL 文本。\n *\n * 参数定义全部来自 SDL,例如:\n * query Company($id: Int, $pageNo: Int) { ... }\n *\n * operation.fields 可通过 buildSelectionFields() 生成,也可以自行传入。\n */\nexport function buildGraphQLQuery(\n operation: GraphQLOperation,\n operationType: GraphQLOperationType = 'query',\n): string {\n const { name, args = EMPTY_ARGS, fields = [] } = operation;\n\n let variableDefinitions = '';\n let argumentsText = '';\n\n for (const argName in args) {\n if (variableDefinitions) variableDefinitions += ', ';\n variableDefinitions += `$${argName}: ${args[argName]}`;\n argumentsText += `${argumentsText ? '\\n' : ''} ${argName}: $${argName}`;\n }\n\n const selectionText = renderSelectionFields(fields);\n\n let gql = `${operationType} ${name}`;\n if (variableDefinitions) gql += `(${variableDefinitions})`;\n\n gql += ` {\\n ${name}`;\n if (argumentsText) gql += `(\\n${argumentsText}\\n )`;\n if (selectionText) gql += ` {\\n${selectionText}\\n }`;\n return gql + '\\n}';\n}\n\n/**\n * 向后兼容旧名称。新代码建议使用 buildGraphQLQuery()。\n */\nexport const buildQuery = buildGraphQLQuery;\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface SchemaField {
|
|
2
|
+
name: string;
|
|
3
|
+
args: Record<string, string>;
|
|
4
|
+
type: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SchemaType {
|
|
7
|
+
name: string;
|
|
8
|
+
fields: Record<string, SchemaField>;
|
|
9
|
+
}
|
|
10
|
+
export interface SchemaMeta {
|
|
11
|
+
query: Record<string, SchemaField>;
|
|
12
|
+
mutation: Record<string, SchemaField>;
|
|
13
|
+
types: Record<string, SchemaType>;
|
|
14
|
+
scalars: Set<string>;
|
|
15
|
+
enums: Set<string>;
|
|
16
|
+
}
|
|
17
|
+
/** GraphQL selection-set 中的字段;对象字段可继续递归包含子字段。 */
|
|
18
|
+
export type GraphQLSelectionField = string | {
|
|
19
|
+
name: string;
|
|
20
|
+
fields: GraphQLSelectionField[];
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* 对象字段展开配置:
|
|
24
|
+
* - 未定义:普通字段默认显示,对象字段默认不展开;
|
|
25
|
+
* - false:明确隐藏字段;
|
|
26
|
+
* - true:展开对象,并显示其普通字段;
|
|
27
|
+
* - object:按配置递归展开子对象。
|
|
28
|
+
*/
|
|
29
|
+
export type GraphQLSelectionConfig = {
|
|
30
|
+
[fieldName: string]: boolean | GraphQLSelectionConfig;
|
|
31
|
+
};
|
|
32
|
+
/** 可直接交给查询生成器的操作描述。 */
|
|
33
|
+
export type GraphQLOperation = SchemaField & {
|
|
34
|
+
fields?: GraphQLSelectionField[];
|
|
35
|
+
};
|
|
36
|
+
/** GraphQL 根操作类型。 */
|
|
37
|
+
export type GraphQLOperationType = 'query' | 'mutation';
|
|
38
|
+
export declare function parseSDL(s: string): SchemaMeta;
|
|
39
|
+
export declare function unwrapType(type: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* 根据 SDL Schema 为一个 Query/Mutation 字段生成 selection-set。
|
|
42
|
+
*
|
|
43
|
+
* 普通 scalar/enum 字段默认包含;对象字段仅在 config 中显式声明时展开。
|
|
44
|
+
* 该函数只生成字段树,不修改传入的 operation。
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildSelectionFields(schema: SchemaMeta, operation: SchemaField, config?: GraphQLSelectionConfig): GraphQLSelectionField[];
|
|
47
|
+
/**
|
|
48
|
+
* 根据解析后的操作描述生成完整 GraphQL 文本。
|
|
49
|
+
*
|
|
50
|
+
* 参数定义全部来自 SDL,例如:
|
|
51
|
+
* query Company($id: Int, $pageNo: Int) { ... }
|
|
52
|
+
*
|
|
53
|
+
* operation.fields 可通过 buildSelectionFields() 生成,也可以自行传入。
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildGraphQLQuery(operation: GraphQLOperation, operationType?: GraphQLOperationType): string;
|
|
56
|
+
/**
|
|
57
|
+
* 向后兼容旧名称。新代码建议使用 buildGraphQLQuery()。
|
|
58
|
+
*/
|
|
59
|
+
export declare const buildQuery: typeof buildGraphQLQuery;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
const STR = "\0s";
|
|
3
|
+
const NUM = "\0n";
|
|
4
|
+
const EMPTY_ARGS = Object.freeze(Object.create(null));
|
|
5
|
+
const isNameStart = (c) => c === 95 || c >= 65 && c <= 90 || c >= 97 && c <= 122;
|
|
6
|
+
const isNameChar = (c) => isNameStart(c) || c >= 48 && c <= 57;
|
|
7
|
+
const isDigit = (c) => c >= 48 && c <= 57;
|
|
8
|
+
const TYPE_NAME_CACHE = Object.create(null);
|
|
9
|
+
function parseSDL(s) {
|
|
10
|
+
let i = s.charCodeAt(0) === 65279 ? 1 : 0;
|
|
11
|
+
const n = s.length;
|
|
12
|
+
let look;
|
|
13
|
+
const types = Object.create(null);
|
|
14
|
+
const scalars = /* @__PURE__ */ new Set([
|
|
15
|
+
"String",
|
|
16
|
+
"Int",
|
|
17
|
+
"Float",
|
|
18
|
+
"Boolean",
|
|
19
|
+
"ID"
|
|
20
|
+
]);
|
|
21
|
+
const enums = /* @__PURE__ */ new Set();
|
|
22
|
+
function scan() {
|
|
23
|
+
for (;;) {
|
|
24
|
+
if (i >= n) return;
|
|
25
|
+
const c = s.charCodeAt(i);
|
|
26
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 44) {
|
|
27
|
+
i++;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (c === 35) {
|
|
31
|
+
while (++i < n) {
|
|
32
|
+
const x = s.charCodeAt(i);
|
|
33
|
+
if (x === 10 || x === 13) break;
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (c === 34 && s.charCodeAt(i + 1) === 34 && s.charCodeAt(i + 2) === 34) {
|
|
38
|
+
i += 3;
|
|
39
|
+
while (i < n) {
|
|
40
|
+
if (s.charCodeAt(i) === 34 && s.charCodeAt(i + 1) === 34 && s.charCodeAt(i + 2) === 34) {
|
|
41
|
+
i += 3;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
i += s.charCodeAt(i) === 92 ? 2 : 1;
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (c === 34) {
|
|
49
|
+
i++;
|
|
50
|
+
while (i < n) {
|
|
51
|
+
const x = s.charCodeAt(i++);
|
|
52
|
+
if (x === 92) i++;
|
|
53
|
+
else if (x === 34) break;
|
|
54
|
+
}
|
|
55
|
+
return STR;
|
|
56
|
+
}
|
|
57
|
+
if (isNameStart(c)) {
|
|
58
|
+
const p = i++;
|
|
59
|
+
while (i < n && isNameChar(s.charCodeAt(i))) i++;
|
|
60
|
+
return s.slice(p, i);
|
|
61
|
+
}
|
|
62
|
+
if (isDigit(c) || c === 45 && isDigit(s.charCodeAt(i + 1))) {
|
|
63
|
+
i++;
|
|
64
|
+
while (i < n) {
|
|
65
|
+
const x = s.charCodeAt(i);
|
|
66
|
+
if (isDigit(x) || x === 46 || x === 101 || x === 69 || x === 43 || x === 45) i++;
|
|
67
|
+
else break;
|
|
68
|
+
}
|
|
69
|
+
return NUM;
|
|
70
|
+
}
|
|
71
|
+
if (c === 46 && s.charCodeAt(i + 1) === 46 && s.charCodeAt(i + 2) === 46) {
|
|
72
|
+
i += 3;
|
|
73
|
+
return "...";
|
|
74
|
+
}
|
|
75
|
+
if (c === 123 || c === 125 || c === 40 || c === 41 || c === 91 || c === 93 || c === 58 || c === 33 || c === 61 || c === 36 || c === 64 || c === 124 || c === 38) {
|
|
76
|
+
i++;
|
|
77
|
+
return String.fromCharCode(c);
|
|
78
|
+
}
|
|
79
|
+
i++;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const peek = () => look ??= scan();
|
|
83
|
+
const take = () => {
|
|
84
|
+
const v = look ?? scan();
|
|
85
|
+
look = void 0;
|
|
86
|
+
return v;
|
|
87
|
+
};
|
|
88
|
+
const eat = (v) => {
|
|
89
|
+
if (peek() !== v) return false;
|
|
90
|
+
take();
|
|
91
|
+
return true;
|
|
92
|
+
};
|
|
93
|
+
const need = (v) => {
|
|
94
|
+
const x = take();
|
|
95
|
+
if (x !== v) throw new Error(`parseSDL: expected "${v}", got "${x ?? "EOF"}"`);
|
|
96
|
+
};
|
|
97
|
+
const needName = () => {
|
|
98
|
+
const x = take();
|
|
99
|
+
if (!x || x === STR || x === NUM || !isNameStart(x.charCodeAt(0))) throw new Error(`parseSDL: expected NAME, got "${x ?? "EOF"}"`);
|
|
100
|
+
return x;
|
|
101
|
+
};
|
|
102
|
+
function typeRef() {
|
|
103
|
+
if (eat("[")) {
|
|
104
|
+
let v = `[${typeRef()}]`;
|
|
105
|
+
need("]");
|
|
106
|
+
if (eat("!")) v += "!";
|
|
107
|
+
return v;
|
|
108
|
+
}
|
|
109
|
+
let v = needName();
|
|
110
|
+
if (eat("!")) v += "!";
|
|
111
|
+
return v;
|
|
112
|
+
}
|
|
113
|
+
function skipValue() {
|
|
114
|
+
if (eat("[")) {
|
|
115
|
+
while (peek() && peek() !== "]") skipValue();
|
|
116
|
+
need("]");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (eat("{")) {
|
|
120
|
+
while (peek() && peek() !== "}") {
|
|
121
|
+
needName();
|
|
122
|
+
need(":");
|
|
123
|
+
skipValue();
|
|
124
|
+
}
|
|
125
|
+
need("}");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
take();
|
|
129
|
+
}
|
|
130
|
+
function skipDirectives() {
|
|
131
|
+
while (eat("@")) {
|
|
132
|
+
needName();
|
|
133
|
+
if (!eat("(")) continue;
|
|
134
|
+
let d = 1;
|
|
135
|
+
while (d && peek()) if (eat("(")) d++;
|
|
136
|
+
else if (eat(")")) d--;
|
|
137
|
+
else take();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function args() {
|
|
141
|
+
if (!eat("(")) return EMPTY_ARGS;
|
|
142
|
+
const out = Object.create(null);
|
|
143
|
+
while (peek() && peek() !== ")") {
|
|
144
|
+
const k = needName();
|
|
145
|
+
need(":");
|
|
146
|
+
out[k] = typeRef();
|
|
147
|
+
if (eat("=")) skipValue();
|
|
148
|
+
skipDirectives();
|
|
149
|
+
}
|
|
150
|
+
need(")");
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
function fields() {
|
|
154
|
+
const out = Object.create(null);
|
|
155
|
+
need("{");
|
|
156
|
+
while (peek() && peek() !== "}") {
|
|
157
|
+
const name = needName();
|
|
158
|
+
const a = args();
|
|
159
|
+
need(":");
|
|
160
|
+
const type = typeRef();
|
|
161
|
+
skipDirectives();
|
|
162
|
+
out[name] = {
|
|
163
|
+
name,
|
|
164
|
+
args: a,
|
|
165
|
+
type
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
need("}");
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
function objectType() {
|
|
172
|
+
const name = needName();
|
|
173
|
+
if (eat("implements")) {
|
|
174
|
+
eat("&");
|
|
175
|
+
while (peek() && peek() !== "{") take();
|
|
176
|
+
}
|
|
177
|
+
skipDirectives();
|
|
178
|
+
if (peek() !== "{") return;
|
|
179
|
+
types[name] = {
|
|
180
|
+
name,
|
|
181
|
+
fields: fields()
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function scalar() {
|
|
185
|
+
scalars.add(needName());
|
|
186
|
+
skipDirectives();
|
|
187
|
+
}
|
|
188
|
+
function enumType() {
|
|
189
|
+
enums.add(needName());
|
|
190
|
+
skipDirectives();
|
|
191
|
+
if (!eat("{")) return;
|
|
192
|
+
while (peek() && peek() !== "}") {
|
|
193
|
+
take();
|
|
194
|
+
skipDirectives();
|
|
195
|
+
}
|
|
196
|
+
need("}");
|
|
197
|
+
}
|
|
198
|
+
while (peek()) switch (take()) {
|
|
199
|
+
case "type":
|
|
200
|
+
objectType();
|
|
201
|
+
break;
|
|
202
|
+
case "scalar":
|
|
203
|
+
scalar();
|
|
204
|
+
break;
|
|
205
|
+
case "enum": enumType();
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
query: types.Query?.fields || {},
|
|
209
|
+
mutation: types.Mutation?.fields || {},
|
|
210
|
+
types,
|
|
211
|
+
scalars,
|
|
212
|
+
enums
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function unwrapType(type) {
|
|
216
|
+
let a = 0;
|
|
217
|
+
let b = type.length;
|
|
218
|
+
const first = type.charCodeAt(0);
|
|
219
|
+
const last = type.charCodeAt(b - 1);
|
|
220
|
+
if (first !== 91 && first !== 33 && last !== 93 && last !== 33) return type;
|
|
221
|
+
const cached = TYPE_NAME_CACHE[type];
|
|
222
|
+
if (cached) return cached;
|
|
223
|
+
while (a < b) {
|
|
224
|
+
const c = type.charCodeAt(a);
|
|
225
|
+
if (c !== 91 && c !== 33) break;
|
|
226
|
+
a++;
|
|
227
|
+
}
|
|
228
|
+
while (b > a) {
|
|
229
|
+
const c = type.charCodeAt(b - 1);
|
|
230
|
+
if (c !== 93 && c !== 33) break;
|
|
231
|
+
b--;
|
|
232
|
+
}
|
|
233
|
+
const name = type.slice(a, b);
|
|
234
|
+
TYPE_NAME_CACHE[type] = name;
|
|
235
|
+
return name;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* 根据 SDL Schema 为一个 Query/Mutation 字段生成 selection-set。
|
|
239
|
+
*
|
|
240
|
+
* 普通 scalar/enum 字段默认包含;对象字段仅在 config 中显式声明时展开。
|
|
241
|
+
* 该函数只生成字段树,不修改传入的 operation。
|
|
242
|
+
*/
|
|
243
|
+
function buildSelectionFields(schema, operation, config = {}) {
|
|
244
|
+
const schemaType = schema.types[unwrapType(operation.type)];
|
|
245
|
+
if (!schemaType) return [];
|
|
246
|
+
const result = [];
|
|
247
|
+
const fields = schemaType.fields;
|
|
248
|
+
for (const fieldName in fields) {
|
|
249
|
+
const fieldInfo = fields[fieldName];
|
|
250
|
+
const fieldConfig = config[fieldName];
|
|
251
|
+
if (fieldConfig === false) continue;
|
|
252
|
+
if (!schema.types[unwrapType(fieldInfo.type)]) {
|
|
253
|
+
result.push(fieldName);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (fieldConfig === void 0) continue;
|
|
257
|
+
result.push({
|
|
258
|
+
name: fieldName,
|
|
259
|
+
fields: buildSelectionFields(schema, fieldInfo, fieldConfig === true ? {} : fieldConfig)
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
/** 将递归字段树渲染为 GraphQL selection-set 文本。 */
|
|
265
|
+
function renderSelectionFields(fields, indent = " ") {
|
|
266
|
+
let out = "";
|
|
267
|
+
for (const field of fields) {
|
|
268
|
+
if (out) out += "\n";
|
|
269
|
+
if (typeof field === "string") {
|
|
270
|
+
out += indent + field;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const children = renderSelectionFields(field.fields, indent + " ");
|
|
274
|
+
out += children ? `${indent}${field.name} {\n${children}\n${indent}}` : indent + field.name;
|
|
275
|
+
}
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* 根据解析后的操作描述生成完整 GraphQL 文本。
|
|
280
|
+
*
|
|
281
|
+
* 参数定义全部来自 SDL,例如:
|
|
282
|
+
* query Company($id: Int, $pageNo: Int) { ... }
|
|
283
|
+
*
|
|
284
|
+
* operation.fields 可通过 buildSelectionFields() 生成,也可以自行传入。
|
|
285
|
+
*/
|
|
286
|
+
function buildGraphQLQuery(operation, operationType = "query") {
|
|
287
|
+
const { name, args = EMPTY_ARGS, fields = [] } = operation;
|
|
288
|
+
let variableDefinitions = "";
|
|
289
|
+
let argumentsText = "";
|
|
290
|
+
for (const argName in args) {
|
|
291
|
+
if (variableDefinitions) variableDefinitions += ", ";
|
|
292
|
+
variableDefinitions += `$${argName}: ${args[argName]}`;
|
|
293
|
+
argumentsText += `${argumentsText ? "\n" : ""} ${argName}: $${argName}`;
|
|
294
|
+
}
|
|
295
|
+
const selectionText = renderSelectionFields(fields);
|
|
296
|
+
let gql = `${operationType} ${name}`;
|
|
297
|
+
if (variableDefinitions) gql += `(${variableDefinitions})`;
|
|
298
|
+
gql += ` {\n ${name}`;
|
|
299
|
+
if (argumentsText) gql += `(\n${argumentsText}\n )`;
|
|
300
|
+
if (selectionText) gql += ` {\n${selectionText}\n }`;
|
|
301
|
+
return gql + "\n}";
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 向后兼容旧名称。新代码建议使用 buildGraphQLQuery()。
|
|
305
|
+
*/
|
|
306
|
+
const buildQuery = buildGraphQLQuery;
|
|
307
|
+
//#endregion
|
|
308
|
+
export { buildGraphQLQuery, buildQuery, buildSelectionFields, parseSDL, unwrapType };
|
|
309
|
+
|
|
310
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export interface SchemaField {\n name: string;\n args: Record<string, string>;\n type: string;\n}\n\nexport interface SchemaType {\n name: string;\n fields: Record<string, SchemaField>;\n}\n\nexport interface SchemaMeta {\n query: Record<string, SchemaField>;\n mutation: Record<string, SchemaField>;\n types: Record<string, SchemaType>;\n scalars: Set<string>;\n enums: Set<string>;\n}\n\n/** GraphQL selection-set 中的字段;对象字段可继续递归包含子字段。 */\nexport type GraphQLSelectionField =\n | string\n | {\n name: string;\n fields: GraphQLSelectionField[];\n };\n\n/**\n * 对象字段展开配置:\n * - 未定义:普通字段默认显示,对象字段默认不展开;\n * - false:明确隐藏字段;\n * - true:展开对象,并显示其普通字段;\n * - object:按配置递归展开子对象。\n */\nexport type GraphQLSelectionConfig = {\n [fieldName: string]: boolean | GraphQLSelectionConfig;\n};\n\n/** 可直接交给查询生成器的操作描述。 */\nexport type GraphQLOperation = SchemaField & {\n fields?: GraphQLSelectionField[];\n};\n\n/** GraphQL 根操作类型。 */\nexport type GraphQLOperationType = 'query' | 'mutation';\n\nconst STR = '\\0s';\nconst NUM = '\\0n';\n// 无参数字段共用同一个只读空对象,避免大型 SDL 中产生大量空 args 对象。\nconst EMPTY_ARGS: Record<string, string> = Object.freeze(Object.create(null));\n\nconst isNameStart = (c: number) =>\n c === 95 || (c >= 65 && c <= 90) || (c >= 97 && c <= 122);\nconst isNameChar = (c: number) => isNameStart(c) || (c >= 48 && c <= 57);\nconst isDigit = (c: number) => c >= 48 && c <= 57;\n// 仅缓存 [Type] / Type! 等包装类型的解包结果;普通类型走 unwrapType 快路径。\nconst TYPE_NAME_CACHE: Record<string, string> = Object.create(null);\n\nexport function parseSDL(s: string): SchemaMeta {\n let i = s.charCodeAt(0) === 0xfeff ? 1 : 0;\n const n = s.length;\n let look: string | undefined;\n\n const types: Record<string, SchemaType> = Object.create(null);\n const scalars = new Set(['String', 'Int', 'Float', 'Boolean', 'ID']);\n const enums = new Set<string>();\n\n function scan(): string | undefined {\n for (;;) {\n if (i >= n) return;\n const c = s.charCodeAt(i);\n\n // whitespace + comma\n if (c === 32 || c === 9 || c === 10 || c === 13 || c === 44) {\n i++;\n continue;\n }\n\n // # comment\n if (c === 35) {\n while (++i < n) {\n const x = s.charCodeAt(i);\n if (x === 10 || x === 13) break;\n }\n continue;\n }\n\n // block string / description: content is irrelevant for runtime schema\n if (\n c === 34 &&\n s.charCodeAt(i + 1) === 34 &&\n s.charCodeAt(i + 2) === 34\n ) {\n i += 3;\n while (i < n) {\n if (\n s.charCodeAt(i) === 34 &&\n s.charCodeAt(i + 1) === 34 &&\n s.charCodeAt(i + 2) === 34\n ) {\n i += 3;\n break;\n }\n // escaped character\n i += s.charCodeAt(i) === 92 ? 2 : 1;\n }\n continue;\n }\n\n // normal string; its value is not needed\n if (c === 34) {\n i++;\n while (i < n) {\n const x = s.charCodeAt(i++);\n if (x === 92) i++;\n else if (x === 34) break;\n }\n return STR;\n }\n\n // name / keyword\n if (isNameStart(c)) {\n const p = i++;\n while (i < n && isNameChar(s.charCodeAt(i))) i++;\n return s.slice(p, i);\n }\n\n // number; exact value is not needed\n if (isDigit(c) || (c === 45 && isDigit(s.charCodeAt(i + 1)))) {\n i++;\n while (i < n) {\n const x = s.charCodeAt(i);\n if (\n isDigit(x) ||\n x === 46 ||\n x === 101 ||\n x === 69 ||\n x === 43 ||\n x === 45\n )\n i++;\n else break;\n }\n return NUM;\n }\n\n // spread\n if (\n c === 46 &&\n s.charCodeAt(i + 1) === 46 &&\n s.charCodeAt(i + 2) === 46\n ) {\n i += 3;\n return '...';\n }\n\n // punctuation used by SDL\n if (\n c === 123 ||\n c === 125 ||\n c === 40 ||\n c === 41 ||\n c === 91 ||\n c === 93 ||\n c === 58 ||\n c === 33 ||\n c === 61 ||\n c === 36 ||\n c === 64 ||\n c === 124 ||\n c === 38\n ) {\n i++;\n return String.fromCharCode(c);\n }\n\n i++;\n }\n }\n\n const peek = () => (look ??= scan());\n const take = () => {\n const v = look ?? scan();\n look = undefined;\n return v;\n };\n const eat = (v: string) => {\n if (peek() !== v) return false;\n take();\n return true;\n };\n const need = (v: string) => {\n const x = take();\n if (x !== v)\n throw new Error(`parseSDL: expected \"${v}\", got \"${x ?? 'EOF'}\"`);\n };\n const needName = () => {\n const x = take();\n if (!x || x === STR || x === NUM || !isNameStart(x.charCodeAt(0)))\n throw new Error(`parseSDL: expected NAME, got \"${x ?? 'EOF'}\"`);\n return x;\n };\n\n function typeRef(): string {\n if (eat('[')) {\n let v = `[${typeRef()}]`;\n need(']');\n if (eat('!')) v += '!';\n return v;\n }\n let v = needName();\n if (eat('!')) v += '!';\n return v;\n }\n\n function skipValue() {\n if (eat('[')) {\n while (peek() && peek() !== ']') skipValue();\n need(']');\n return;\n }\n if (eat('{')) {\n while (peek() && peek() !== '}') {\n needName();\n need(':');\n skipValue();\n }\n need('}');\n return;\n }\n take();\n }\n\n function skipDirectives() {\n while (eat('@')) {\n needName();\n if (!eat('(')) continue;\n let d = 1;\n while (d && peek()) {\n if (eat('(')) d++;\n else if (eat(')')) d--;\n else take();\n }\n }\n }\n\n function args(): Record<string, string> {\n if (!eat('(')) return EMPTY_ARGS;\n\n const out: Record<string, string> = Object.create(null);\n while (peek() && peek() !== ')') {\n const k = needName();\n need(':');\n out[k] = typeRef();\n if (eat('=')) skipValue();\n skipDirectives();\n }\n need(')');\n return out;\n }\n\n function fields() {\n const out: Record<string, SchemaField> = Object.create(null);\n need('{');\n while (peek() && peek() !== '}') {\n const name = needName();\n const a = args();\n need(':');\n const type = typeRef();\n skipDirectives();\n out[name] = { name, args: a, type };\n }\n need('}');\n return out;\n }\n\n function objectType() {\n const name = needName();\n if (eat('implements')) {\n eat('&');\n while (peek() && peek() !== '{') take();\n }\n skipDirectives();\n if (peek() !== '{') return;\n types[name] = { name, fields: fields() };\n }\n\n function scalar() {\n scalars.add(needName());\n skipDirectives();\n }\n\n function enumType() {\n enums.add(needName());\n skipDirectives();\n if (!eat('{')) return;\n while (peek() && peek() !== '}') {\n take();\n skipDirectives();\n }\n need('}');\n }\n\n while (peek()) {\n switch (take()) {\n case 'type':\n objectType();\n break;\n case 'scalar':\n scalar();\n break;\n case 'enum':\n enumType();\n break;\n }\n }\n\n return {\n query: types.Query?.fields || {},\n mutation: types.Mutation?.fields || {},\n types,\n scalars,\n enums,\n };\n}\n\nexport function unwrapType(type: string): string {\n let a = 0;\n let b = type.length;\n\n const first = type.charCodeAt(0);\n const last = type.charCodeAt(b - 1);\n if (first !== 91 && first !== 33 && last !== 93 && last !== 33) return type;\n\n const cached = TYPE_NAME_CACHE[type];\n if (cached) return cached;\n\n while (a < b) {\n const c = type.charCodeAt(a);\n if (c !== 91 && c !== 33) break;\n a++;\n }\n while (b > a) {\n const c = type.charCodeAt(b - 1);\n if (c !== 93 && c !== 33) break;\n b--;\n }\n const name = type.slice(a, b);\n TYPE_NAME_CACHE[type] = name;\n return name;\n}\n\n/**\n * 根据 SDL Schema 为一个 Query/Mutation 字段生成 selection-set。\n *\n * 普通 scalar/enum 字段默认包含;对象字段仅在 config 中显式声明时展开。\n * 该函数只生成字段树,不修改传入的 operation。\n */\nexport function buildSelectionFields(\n schema: SchemaMeta,\n operation: SchemaField,\n config: GraphQLSelectionConfig = {},\n): GraphQLSelectionField[] {\n const schemaType = schema.types[unwrapType(operation.type)];\n if (!schemaType) return [];\n\n const result: GraphQLSelectionField[] = [];\n const fields = schemaType.fields;\n\n for (const fieldName in fields) {\n const fieldInfo = fields[fieldName];\n const fieldConfig = config[fieldName];\n\n // false:显式隐藏;undefined:scalar 默认显示、object 默认不展开。\n if (fieldConfig === false) continue;\n\n const childType = schema.types[unwrapType(fieldInfo.type)];\n if (!childType) {\n result.push(fieldName);\n continue;\n }\n\n if (fieldConfig === undefined) continue;\n\n result.push({\n name: fieldName,\n fields: buildSelectionFields(\n schema,\n fieldInfo,\n fieldConfig === true ? {} : fieldConfig,\n ),\n });\n }\n\n return result;\n}\n\n/** 将递归字段树渲染为 GraphQL selection-set 文本。 */\nfunction renderSelectionFields(\n fields: GraphQLSelectionField[],\n indent = ' ',\n): string {\n let out = '';\n\n for (const field of fields) {\n if (out) out += '\\n';\n\n if (typeof field === 'string') {\n out += indent + field;\n continue;\n }\n\n const children = renderSelectionFields(field.fields, indent + ' ');\n out += children\n ? `${indent}${field.name} {\\n${children}\\n${indent}}`\n : indent + field.name;\n }\n\n return out;\n}\n\n/**\n * 根据解析后的操作描述生成完整 GraphQL 文本。\n *\n * 参数定义全部来自 SDL,例如:\n * query Company($id: Int, $pageNo: Int) { ... }\n *\n * operation.fields 可通过 buildSelectionFields() 生成,也可以自行传入。\n */\nexport function buildGraphQLQuery(\n operation: GraphQLOperation,\n operationType: GraphQLOperationType = 'query',\n): string {\n const { name, args = EMPTY_ARGS, fields = [] } = operation;\n\n let variableDefinitions = '';\n let argumentsText = '';\n\n for (const argName in args) {\n if (variableDefinitions) variableDefinitions += ', ';\n variableDefinitions += `$${argName}: ${args[argName]}`;\n argumentsText += `${argumentsText ? '\\n' : ''} ${argName}: $${argName}`;\n }\n\n const selectionText = renderSelectionFields(fields);\n\n let gql = `${operationType} ${name}`;\n if (variableDefinitions) gql += `(${variableDefinitions})`;\n\n gql += ` {\\n ${name}`;\n if (argumentsText) gql += `(\\n${argumentsText}\\n )`;\n if (selectionText) gql += ` {\\n${selectionText}\\n }`;\n return gql + '\\n}';\n}\n\n/**\n * 向后兼容旧名称。新代码建议使用 buildGraphQLQuery()。\n */\nexport const buildQuery = buildGraphQLQuery;\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uni2c/graphqlapi4mp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Parse GraphQL SDL and build GraphQL operation documents.",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"scripts": {
|
|
21
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
22
|
+
"prebuild": "npm run clean",
|
|
23
|
+
"build": "rolldown -c && tsc -p tsconfig.build.json",
|
|
24
|
+
"prepack": "npm run build",
|
|
25
|
+
"test": "npm run build && node --import tsx --test test/**/*.test.ts",
|
|
26
|
+
"test:demo": "tsx test.ts",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"npm:publish": "npm run build;npm publish --access public --tag latest",
|
|
29
|
+
"version:patch": "npm version patch",
|
|
30
|
+
"version:minor": "npm version minor",
|
|
31
|
+
"version:major": "npm version major"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [],
|
|
34
|
+
"author": "",
|
|
35
|
+
"license": "ISC",
|
|
36
|
+
"type": "commonjs",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^26.4.0",
|
|
39
|
+
"rolldown": "^1.2.6",
|
|
40
|
+
"tsx": "^4.23.13",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
}
|
|
43
|
+
}
|