@soda-gql/lsp 0.14.0 → 0.14.2
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/README.md +45 -0
- package/dist/bin.cjs +1 -1
- package/dist/bin.mjs +1 -1
- package/dist/index.cjs +298 -2
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +42 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +44 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +297 -2
- package/dist/index.mjs.map +1 -0
- package/dist/{server-DsJ1bZ7i.cjs → server-C1MSX490.cjs} +1101 -410
- package/dist/server-C1MSX490.cjs.map +1 -0
- package/dist/{server-CqOUHwDk.mjs → server-wPCHK04O.mjs} +1087 -414
- package/dist/server-wPCHK04O.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/server-CqOUHwDk.mjs.map +0 -1
- package/dist/server-DsJ1bZ7i.cjs.map +0 -1
|
@@ -25,23 +25,158 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
|
|
27
27
|
//#endregion
|
|
28
|
+
let node_fs = require("node:fs");
|
|
29
|
+
let node_path = require("node:path");
|
|
30
|
+
let __soda_gql_builder = require("@soda-gql/builder");
|
|
31
|
+
let __soda_gql_config = require("@soda-gql/config");
|
|
32
|
+
let graphql = require("graphql");
|
|
33
|
+
let graphql_language_service = require("graphql-language-service");
|
|
28
34
|
let node_module = require("node:module");
|
|
29
35
|
let node_url = require("node:url");
|
|
30
36
|
let __soda_gql_common = require("@soda-gql/common");
|
|
31
37
|
let __soda_gql_common_template_extraction = require("@soda-gql/common/template-extraction");
|
|
32
|
-
let graphql = require("graphql");
|
|
33
|
-
let node_fs = require("node:fs");
|
|
34
|
-
let node_path = require("node:path");
|
|
35
|
-
let __soda_gql_tools_codegen = require("@soda-gql/tools/codegen");
|
|
36
38
|
let neverthrow = require("neverthrow");
|
|
37
|
-
let
|
|
39
|
+
let __soda_gql_tools_codegen = require("@soda-gql/tools/codegen");
|
|
38
40
|
let vscode_languageserver_node = require("vscode-languageserver/node");
|
|
39
41
|
let vscode_languageserver_textdocument = require("vscode-languageserver-textdocument");
|
|
40
|
-
let __soda_gql_builder = require("@soda-gql/builder");
|
|
41
42
|
let typescript = require("typescript");
|
|
42
43
|
typescript = __toESM(typescript);
|
|
43
|
-
let graphql_language_service = require("graphql-language-service");
|
|
44
44
|
|
|
45
|
+
//#region packages/lsp/src/field-tree-resolver.ts
|
|
46
|
+
/** Get the root type name for an operation kind from the schema. */
|
|
47
|
+
const getRootTypeName = (schema, kind) => {
|
|
48
|
+
switch (kind) {
|
|
49
|
+
case "query": return schema.getQueryType()?.name ?? null;
|
|
50
|
+
case "mutation": return schema.getMutationType()?.name ?? null;
|
|
51
|
+
case "subscription": return schema.getSubscriptionType()?.name ?? null;
|
|
52
|
+
default: return null;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/** Classify a GraphQL named type into a kind string. */
|
|
56
|
+
const classifyType = (namedType) => {
|
|
57
|
+
if ((0, graphql.isObjectType)(namedType)) return "object";
|
|
58
|
+
if (namedType instanceof graphql.GraphQLUnionType) return "union";
|
|
59
|
+
if ("getValues" in namedType) return "enum";
|
|
60
|
+
return "scalar";
|
|
61
|
+
};
|
|
62
|
+
/** Resolve a single field from a parent object type. */
|
|
63
|
+
const resolveField = (schema, parentTypeName, fieldName) => {
|
|
64
|
+
const parentType = schema.getType(parentTypeName);
|
|
65
|
+
if (!parentType || !(0, graphql.isObjectType)(parentType)) return null;
|
|
66
|
+
const fields = parentType.getFields();
|
|
67
|
+
const fieldDef = fields[fieldName];
|
|
68
|
+
if (!fieldDef) return null;
|
|
69
|
+
const namedType = (0, graphql.getNamedType)(fieldDef.type);
|
|
70
|
+
if (!namedType) return null;
|
|
71
|
+
return {
|
|
72
|
+
fieldDef,
|
|
73
|
+
namedType
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
/** Resolve untyped FieldCallNode children into typed nodes. */
|
|
77
|
+
const resolveChildren = (schema, parentTypeName, children) => {
|
|
78
|
+
return children.map((child) => resolveNode(schema, parentTypeName, child));
|
|
79
|
+
};
|
|
80
|
+
/** Resolve a single FieldCallNode into a TypedFieldNode. */
|
|
81
|
+
const resolveNode = (schema, parentTypeName, node) => {
|
|
82
|
+
const resolved = resolveField(schema, parentTypeName, node.fieldName);
|
|
83
|
+
const fieldTypeName = resolved?.namedType.name ?? null;
|
|
84
|
+
const fieldTypeKind = resolved ? classifyType(resolved.namedType) : null;
|
|
85
|
+
let nested = null;
|
|
86
|
+
if (node.nested) {
|
|
87
|
+
if (node.nested.kind === "object" && fieldTypeName) {
|
|
88
|
+
nested = {
|
|
89
|
+
kind: "object",
|
|
90
|
+
span: node.nested.span,
|
|
91
|
+
children: resolveChildren(schema, fieldTypeName, node.nested.children)
|
|
92
|
+
};
|
|
93
|
+
} else if (node.nested.kind === "union") {
|
|
94
|
+
nested = resolveUnionNested(schema, resolved?.namedType ?? null, node.nested);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
fieldName: node.fieldName,
|
|
99
|
+
fieldNameSpan: node.fieldNameSpan,
|
|
100
|
+
callSpan: node.callSpan,
|
|
101
|
+
parentTypeName,
|
|
102
|
+
fieldTypeName,
|
|
103
|
+
fieldTypeKind,
|
|
104
|
+
nested
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/** Resolve union branches against a union type. */
|
|
108
|
+
const resolveUnionNested = (schema, unionType, nested) => {
|
|
109
|
+
const memberNames = new Set();
|
|
110
|
+
if (unionType instanceof graphql.GraphQLUnionType) {
|
|
111
|
+
for (const member of unionType.getTypes()) {
|
|
112
|
+
memberNames.add(member.name);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const branches = nested.branches.map((branch) => ({
|
|
116
|
+
typeName: branch.typeName,
|
|
117
|
+
typeNameSpan: branch.typeNameSpan,
|
|
118
|
+
branchSpan: branch.branchSpan,
|
|
119
|
+
valid: memberNames.has(branch.typeName),
|
|
120
|
+
children: resolveChildren(schema, branch.typeName, branch.children)
|
|
121
|
+
}));
|
|
122
|
+
return {
|
|
123
|
+
kind: "union",
|
|
124
|
+
span: nested.span,
|
|
125
|
+
branches
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Resolve an ExtractedFieldTree against a GraphQL schema.
|
|
130
|
+
* Returns null if the operation kind has no corresponding root type.
|
|
131
|
+
*/
|
|
132
|
+
const resolveFieldTree = (tree, schema) => {
|
|
133
|
+
const rootTypeName = getRootTypeName(schema, tree.kind);
|
|
134
|
+
if (!rootTypeName) return null;
|
|
135
|
+
return {
|
|
136
|
+
schemaName: tree.schemaName,
|
|
137
|
+
rootTypeName,
|
|
138
|
+
rootSpan: tree.rootSpan,
|
|
139
|
+
children: resolveChildren(schema, rootTypeName, tree.children)
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Find the TypedFieldNode or TypedUnionBranch at a given offset.
|
|
144
|
+
* Searches fieldNameSpan for field matches and typeNameSpan for union member matches.
|
|
145
|
+
*/
|
|
146
|
+
const findNodeAtOffset = (tree, offset) => {
|
|
147
|
+
return findInChildren(tree.children, offset, null);
|
|
148
|
+
};
|
|
149
|
+
const findInChildren = (children, offset, _parentForUnion) => {
|
|
150
|
+
for (const node of children) {
|
|
151
|
+
if (offset >= node.fieldNameSpan.start && offset <= node.fieldNameSpan.end) {
|
|
152
|
+
return {
|
|
153
|
+
kind: "field",
|
|
154
|
+
node
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (node.nested) {
|
|
158
|
+
if (node.nested.kind === "object") {
|
|
159
|
+
const result = findInChildren(node.nested.children, offset, null);
|
|
160
|
+
if (result) return result;
|
|
161
|
+
} else if (node.nested.kind === "union") {
|
|
162
|
+
for (const branch of node.nested.branches) {
|
|
163
|
+
if (offset >= branch.typeNameSpan.start && offset <= branch.typeNameSpan.end) {
|
|
164
|
+
return {
|
|
165
|
+
kind: "unionMember",
|
|
166
|
+
branch,
|
|
167
|
+
parentNode: node
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const result = findInChildren(branch.children, offset, node);
|
|
171
|
+
if (result) return result;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
45
180
|
//#region packages/lsp/src/fragment-args-preprocessor.ts
|
|
46
181
|
/**
|
|
47
182
|
* Find the matching closing parenthesis for a balanced group.
|
|
@@ -199,9 +334,17 @@ const collectGqlIdentifiers = (module$1, filePath, helper) => {
|
|
|
199
334
|
/**
|
|
200
335
|
* Reconstruct full GraphQL source from an extracted template.
|
|
201
336
|
* Prepends the definition header from curried tag call arguments.
|
|
337
|
+
*
|
|
338
|
+
* For callback-variables templates (source === "callback-variables"), wraps the
|
|
339
|
+
* partial variables string in a dummy operation to produce valid GraphQL that
|
|
340
|
+
* graphql-language-service can parse.
|
|
202
341
|
*/
|
|
203
342
|
const reconstructGraphql = (template) => {
|
|
204
343
|
const content = template.content;
|
|
344
|
+
if (template.source === "callback-variables") {
|
|
345
|
+
const name = template.elementName ?? "__variables__";
|
|
346
|
+
return `${template.kind} ${name} ${content} { __typename }`;
|
|
347
|
+
}
|
|
205
348
|
if (template.elementName) {
|
|
206
349
|
if (template.kind === "fragment" && template.typeName) {
|
|
207
350
|
return `fragment ${template.elementName} on ${template.typeName} ${content}`;
|
|
@@ -210,6 +353,21 @@ const reconstructGraphql = (template) => {
|
|
|
210
353
|
}
|
|
211
354
|
return content;
|
|
212
355
|
};
|
|
356
|
+
/**
|
|
357
|
+
* Compute the length of the synthesized prefix before the template content
|
|
358
|
+
* in the reconstructed GraphQL string.
|
|
359
|
+
*
|
|
360
|
+
* For tagged templates, headerLen = reconstructed.length - content.length (content is at the end).
|
|
361
|
+
* For callback-variables, content is in the MIDDLE (prefix + content + suffix), so we must
|
|
362
|
+
* compute the prefix length explicitly.
|
|
363
|
+
*/
|
|
364
|
+
const computeHeaderLen = (template, reconstructed) => {
|
|
365
|
+
if (template.source === "callback-variables") {
|
|
366
|
+
const name = template.elementName ?? "__variables__";
|
|
367
|
+
return `${template.kind} ${name} `.length;
|
|
368
|
+
}
|
|
369
|
+
return reconstructed.length - template.content.length;
|
|
370
|
+
};
|
|
213
371
|
const indexFragments = (uri, templates, source) => {
|
|
214
372
|
const fragments = [];
|
|
215
373
|
for (const template of templates) {
|
|
@@ -217,7 +375,7 @@ const indexFragments = (uri, templates, source) => {
|
|
|
217
375
|
continue;
|
|
218
376
|
}
|
|
219
377
|
const reconstructed = reconstructGraphql(template);
|
|
220
|
-
const headerLen = reconstructed
|
|
378
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
221
379
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
222
380
|
try {
|
|
223
381
|
const ast = (0, graphql.parse)(preprocessed, { noLocation: false });
|
|
@@ -291,33 +449,45 @@ const createDocumentManager = (helper, swcOptions) => {
|
|
|
291
449
|
};
|
|
292
450
|
const cache = new Map();
|
|
293
451
|
const fragmentIndex = new Map();
|
|
294
|
-
const
|
|
452
|
+
const extractAll = (uri, source) => {
|
|
295
453
|
const isTsx = uri.endsWith(".tsx");
|
|
296
454
|
const program = safeParseSync(source, isTsx);
|
|
297
455
|
if (!program) {
|
|
298
|
-
return
|
|
456
|
+
return {
|
|
457
|
+
templates: [],
|
|
458
|
+
fieldTrees: []
|
|
459
|
+
};
|
|
299
460
|
}
|
|
300
461
|
const converter = (0, __soda_gql_common.createSwcSpanConverter)(source);
|
|
301
462
|
const spanOffset = program.span.end - converter.byteLength + 1;
|
|
302
463
|
const filePath = uri.startsWith("file://") ? (0, node_url.fileURLToPath)(uri) : uri;
|
|
303
464
|
const gqlIdentifiers = collectGqlIdentifiers(program, filePath, helper);
|
|
304
465
|
if (gqlIdentifiers.size === 0) {
|
|
305
|
-
return
|
|
466
|
+
return {
|
|
467
|
+
templates: [],
|
|
468
|
+
fieldTrees: []
|
|
469
|
+
};
|
|
306
470
|
}
|
|
307
471
|
const positionCtx = {
|
|
308
472
|
spanOffset,
|
|
309
473
|
converter
|
|
310
474
|
};
|
|
311
|
-
|
|
475
|
+
const templates = (0, __soda_gql_common_template_extraction.walkAndExtract)(program, gqlIdentifiers, positionCtx);
|
|
476
|
+
const fieldTrees = (0, __soda_gql_common_template_extraction.walkAndExtractFieldTrees)(program, gqlIdentifiers, positionCtx);
|
|
477
|
+
return {
|
|
478
|
+
templates,
|
|
479
|
+
fieldTrees
|
|
480
|
+
};
|
|
312
481
|
};
|
|
313
482
|
return {
|
|
314
483
|
update: (uri, version, source) => {
|
|
315
|
-
const templates =
|
|
484
|
+
const { templates, fieldTrees } = extractAll(uri, source);
|
|
316
485
|
const state = {
|
|
317
486
|
uri,
|
|
318
487
|
version,
|
|
319
488
|
source,
|
|
320
489
|
templates,
|
|
490
|
+
fieldTrees,
|
|
321
491
|
...swcUnavailable ? { swcUnavailable: true } : {}
|
|
322
492
|
};
|
|
323
493
|
cache.set(uri, state);
|
|
@@ -340,6 +510,20 @@ const createDocumentManager = (helper, swcOptions) => {
|
|
|
340
510
|
}
|
|
341
511
|
return state.templates.find((t) => offset >= t.contentRange.start && offset <= t.contentRange.end);
|
|
342
512
|
},
|
|
513
|
+
findFieldTreeAtOffset: (uri, offset) => {
|
|
514
|
+
const state = cache.get(uri);
|
|
515
|
+
if (!state) {
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
518
|
+
return state.fieldTrees.find((t) => offset >= t.rootSpan.start && offset <= t.rootSpan.end);
|
|
519
|
+
},
|
|
520
|
+
findTemplateByTypeNameOffset: (uri, offset) => {
|
|
521
|
+
const state = cache.get(uri);
|
|
522
|
+
if (!state) {
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
return state.templates.find((t) => t.typeNameSpan && offset >= t.typeNameSpan.start && offset <= t.typeNameSpan.end);
|
|
526
|
+
},
|
|
343
527
|
getExternalFragments: (uri, schemaName) => {
|
|
344
528
|
const result = [];
|
|
345
529
|
for (const [fragmentUri, fragments] of fragmentIndex) {
|
|
@@ -373,7 +557,7 @@ const createDocumentManager = (helper, swcOptions) => {
|
|
|
373
557
|
continue;
|
|
374
558
|
}
|
|
375
559
|
const reconstructed = reconstructGraphql(template);
|
|
376
|
-
const headerLen = reconstructed
|
|
560
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
377
561
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
378
562
|
try {
|
|
379
563
|
const ast = (0, graphql.parse)(preprocessed, { noLocation: false });
|
|
@@ -408,50 +592,6 @@ const createDocumentManager = (helper, swcOptions) => {
|
|
|
408
592
|
};
|
|
409
593
|
};
|
|
410
594
|
|
|
411
|
-
//#endregion
|
|
412
|
-
//#region packages/lsp/src/errors.ts
|
|
413
|
-
/** Error constructor helpers for concise error creation. */
|
|
414
|
-
const lspErrors = {
|
|
415
|
-
configLoadFailed: (message, cause) => ({
|
|
416
|
-
code: "CONFIG_LOAD_FAILED",
|
|
417
|
-
message,
|
|
418
|
-
cause
|
|
419
|
-
}),
|
|
420
|
-
schemaLoadFailed: (schemaName, message, cause) => ({
|
|
421
|
-
code: "SCHEMA_LOAD_FAILED",
|
|
422
|
-
message: message ?? `Failed to load schema: ${schemaName}`,
|
|
423
|
-
schemaName,
|
|
424
|
-
cause
|
|
425
|
-
}),
|
|
426
|
-
schemaBuildFailed: (schemaName, message, cause) => ({
|
|
427
|
-
code: "SCHEMA_BUILD_FAILED",
|
|
428
|
-
message: message ?? `Failed to build schema: ${schemaName}`,
|
|
429
|
-
schemaName,
|
|
430
|
-
cause
|
|
431
|
-
}),
|
|
432
|
-
schemaNotConfigured: (schemaName) => ({
|
|
433
|
-
code: "SCHEMA_NOT_CONFIGURED",
|
|
434
|
-
message: `Schema "${schemaName}" is not configured in soda-gql.config`,
|
|
435
|
-
schemaName
|
|
436
|
-
}),
|
|
437
|
-
parseFailed: (uri, message, cause) => ({
|
|
438
|
-
code: "PARSE_FAILED",
|
|
439
|
-
message: message ?? `Failed to parse: ${uri}`,
|
|
440
|
-
uri,
|
|
441
|
-
cause
|
|
442
|
-
}),
|
|
443
|
-
internalInvariant: (message, context, cause) => ({
|
|
444
|
-
code: "INTERNAL_INVARIANT",
|
|
445
|
-
message,
|
|
446
|
-
context,
|
|
447
|
-
cause
|
|
448
|
-
}),
|
|
449
|
-
swcResolutionFailed: (message) => ({
|
|
450
|
-
code: "SWC_RESOLUTION_FAILED",
|
|
451
|
-
message: message ?? "@swc/core not found. Install @soda-gql/builder (which provides @swc/core) in your project and restart the LSP server to enable template extraction."
|
|
452
|
-
})
|
|
453
|
-
};
|
|
454
|
-
|
|
455
595
|
//#endregion
|
|
456
596
|
//#region packages/lsp/src/position-mapping.ts
|
|
457
597
|
/** Compute byte offsets for the start of each line in the source text. */
|
|
@@ -529,164 +669,67 @@ const createPositionMapper = (input) => {
|
|
|
529
669
|
};
|
|
530
670
|
|
|
531
671
|
//#endregion
|
|
532
|
-
//#region packages/lsp/src/
|
|
533
|
-
/**
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
const loadAndBuildSchema = (schemaName, schemaPaths) => {
|
|
546
|
-
const documents = [];
|
|
547
|
-
const files = [];
|
|
548
|
-
for (const schemaPath of schemaPaths) {
|
|
549
|
-
const resolvedPath = (0, node_path.resolve)(schemaPath);
|
|
550
|
-
try {
|
|
551
|
-
const content = (0, node_fs.readFileSync)(resolvedPath, "utf8");
|
|
552
|
-
documents.push((0, graphql.parse)(content));
|
|
553
|
-
files.push({
|
|
554
|
-
filePath: resolvedPath,
|
|
555
|
-
content
|
|
556
|
-
});
|
|
557
|
-
} catch (e) {
|
|
558
|
-
return (0, neverthrow.err)(lspErrors.schemaLoadFailed(schemaName, e instanceof Error ? e.message : String(e)));
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
const documentNode = (0, graphql.concatAST)(documents);
|
|
562
|
-
const hash = (0, __soda_gql_tools_codegen.hashSchema)(documentNode);
|
|
563
|
-
const buildResult = safeBuildASTSchema(schemaName, documentNode);
|
|
564
|
-
if (buildResult.isErr()) {
|
|
565
|
-
return (0, neverthrow.err)(buildResult.error);
|
|
566
|
-
}
|
|
567
|
-
return (0, neverthrow.ok)({
|
|
568
|
-
name: schemaName,
|
|
569
|
-
schema: buildResult.value,
|
|
570
|
-
documentNode,
|
|
571
|
-
hash,
|
|
572
|
-
files
|
|
672
|
+
//#region packages/lsp/src/handlers/diagnostics.ts
|
|
673
|
+
/** Compute LSP diagnostics for a single GraphQL template. */
|
|
674
|
+
const computeTemplateDiagnostics = (input) => {
|
|
675
|
+
const { template, schema, tsSource } = input;
|
|
676
|
+
const reconstructed = reconstructGraphql(template);
|
|
677
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
678
|
+
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
679
|
+
const mapper = createPositionMapper({
|
|
680
|
+
tsSource,
|
|
681
|
+
contentStartOffset: template.contentRange.start,
|
|
682
|
+
graphqlContent: template.content
|
|
573
683
|
});
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
const
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
684
|
+
const gqlDiagnostics = (0, graphql_language_service.getDiagnostics)(preprocessed, schema, undefined, undefined, input.externalFragments);
|
|
685
|
+
const placeholderPattern = /__FRAG_SPREAD_\d+__/;
|
|
686
|
+
const isCallbackVariables = template.source === "callback-variables";
|
|
687
|
+
const reconstructedLineOffsets = computeLineOffsets(preprocessed);
|
|
688
|
+
const contentLineOffsets = computeLineOffsets(template.content);
|
|
689
|
+
const toContentPosition = (pos) => {
|
|
690
|
+
const offset = positionToOffset$1(reconstructedLineOffsets, pos);
|
|
691
|
+
const contentOffset = Math.max(0, offset - headerLen);
|
|
692
|
+
return offsetToPosition(contentLineOffsets, contentOffset);
|
|
693
|
+
};
|
|
694
|
+
return gqlDiagnostics.filter((diag) => {
|
|
695
|
+
if (placeholderPattern.test(diag.message)) {
|
|
696
|
+
return false;
|
|
582
697
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
if (result.isErr()) {
|
|
595
|
-
return (0, neverthrow.err)(result.error);
|
|
596
|
-
}
|
|
597
|
-
cache.set(schemaName, result.value);
|
|
598
|
-
return (0, neverthrow.ok)(result.value);
|
|
599
|
-
},
|
|
600
|
-
reloadAll: () => {
|
|
601
|
-
const errors = [];
|
|
602
|
-
for (const [name, schemaConfig] of Object.entries(config.schemas)) {
|
|
603
|
-
const result = loadAndBuildSchema(name, schemaConfig.schema);
|
|
604
|
-
if (result.isErr()) {
|
|
605
|
-
errors.push(result.error);
|
|
606
|
-
} else {
|
|
607
|
-
cache.set(name, result.value);
|
|
608
|
-
}
|
|
698
|
+
if (isCallbackVariables && diag.message.includes("is never used")) {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
const offset = positionToOffset$1(reconstructedLineOffsets, diag.range.start);
|
|
702
|
+
if (offset < headerLen) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
if (isCallbackVariables) {
|
|
706
|
+
const contentEnd = headerLen + template.content.length;
|
|
707
|
+
if (offset >= contentEnd) {
|
|
708
|
+
return false;
|
|
609
709
|
}
|
|
610
|
-
return errors.length > 0 ? (0, neverthrow.err)(errors) : (0, neverthrow.ok)(undefined);
|
|
611
710
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (resolverResult.isErr()) {
|
|
635
|
-
return (0, neverthrow.err)(resolverResult.error);
|
|
636
|
-
}
|
|
637
|
-
contexts.set(configPath, {
|
|
638
|
-
configPath,
|
|
639
|
-
config,
|
|
640
|
-
helper,
|
|
641
|
-
schemaResolver: resolverResult.value,
|
|
642
|
-
documentManager: createDocumentManager(helper, { resolveFrom: configPath })
|
|
643
|
-
});
|
|
644
|
-
}
|
|
645
|
-
const uriCache = new Map();
|
|
646
|
-
const resolveConfigPath = (dirPath) => {
|
|
647
|
-
const cached = uriCache.get(dirPath);
|
|
648
|
-
if (cached !== undefined) {
|
|
649
|
-
return cached;
|
|
650
|
-
}
|
|
651
|
-
for (const configPath of sortedPaths) {
|
|
652
|
-
const configDir = (0, node_path.dirname)(configPath);
|
|
653
|
-
if (dirPath === configDir || dirPath.startsWith(`${configDir}${node_path.sep}`)) {
|
|
654
|
-
uriCache.set(dirPath, configPath);
|
|
655
|
-
return configPath;
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
uriCache.set(dirPath, null);
|
|
659
|
-
return null;
|
|
660
|
-
};
|
|
661
|
-
return (0, neverthrow.ok)({
|
|
662
|
-
resolveForUri: (uri) => {
|
|
663
|
-
if (!uri.startsWith("file://") && !uri.startsWith("/")) {
|
|
664
|
-
return undefined;
|
|
665
|
-
}
|
|
666
|
-
const filePath = uri.startsWith("file://") ? (0, node_url.fileURLToPath)(uri) : uri;
|
|
667
|
-
const dirPath = (0, node_path.dirname)(filePath);
|
|
668
|
-
const configPath = resolveConfigPath(dirPath);
|
|
669
|
-
return configPath ? contexts.get(configPath) : undefined;
|
|
670
|
-
},
|
|
671
|
-
getAllContexts: () => [...contexts.values()],
|
|
672
|
-
reloadSchemas: (configPath) => {
|
|
673
|
-
const ctx = contexts.get(configPath);
|
|
674
|
-
if (!ctx) {
|
|
675
|
-
return (0, neverthrow.err)([lspErrors.configLoadFailed(`Config not found: ${configPath}`)]);
|
|
676
|
-
}
|
|
677
|
-
return ctx.schemaResolver.reloadAll();
|
|
678
|
-
},
|
|
679
|
-
reloadAllSchemas: () => {
|
|
680
|
-
const errors = [];
|
|
681
|
-
for (const ctx of contexts.values()) {
|
|
682
|
-
const result = ctx.schemaResolver.reloadAll();
|
|
683
|
-
if (result.isErr()) {
|
|
684
|
-
errors.push(...result.error);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
return errors.length > 0 ? (0, neverthrow.err)(errors) : (0, neverthrow.ok)(undefined);
|
|
688
|
-
}
|
|
689
|
-
});
|
|
711
|
+
return true;
|
|
712
|
+
}).map((diag) => {
|
|
713
|
+
const startContent = toContentPosition(diag.range.start);
|
|
714
|
+
const endContent = toContentPosition(diag.range.end);
|
|
715
|
+
const startTs = mapper.graphqlToTs(startContent);
|
|
716
|
+
const endTs = mapper.graphqlToTs(endContent);
|
|
717
|
+
return {
|
|
718
|
+
range: {
|
|
719
|
+
start: {
|
|
720
|
+
line: startTs.line,
|
|
721
|
+
character: startTs.character
|
|
722
|
+
},
|
|
723
|
+
end: {
|
|
724
|
+
line: endTs.line,
|
|
725
|
+
character: endTs.character
|
|
726
|
+
}
|
|
727
|
+
},
|
|
728
|
+
message: diag.message,
|
|
729
|
+
severity: diag.severity,
|
|
730
|
+
source: "soda-gql"
|
|
731
|
+
};
|
|
732
|
+
});
|
|
690
733
|
};
|
|
691
734
|
|
|
692
735
|
//#endregion
|
|
@@ -2949,6 +2992,303 @@ var Is;
|
|
|
2949
2992
|
Is$1.typedArray = typedArray;
|
|
2950
2993
|
})(Is || (Is = {}));
|
|
2951
2994
|
|
|
2995
|
+
//#endregion
|
|
2996
|
+
//#region packages/lsp/src/handlers/field-tree-diagnostics.ts
|
|
2997
|
+
/**
|
|
2998
|
+
* Diagnostics handler for callback builder field tree nodes.
|
|
2999
|
+
* Reports unknown fields and invalid union member types.
|
|
3000
|
+
* @module
|
|
3001
|
+
*/
|
|
3002
|
+
/** Compute LSP diagnostics for a callback builder field tree. */
|
|
3003
|
+
const computeFieldTreeDiagnostics = (input) => {
|
|
3004
|
+
const { fieldTree, tsSource } = input;
|
|
3005
|
+
const lineOffsets = computeLineOffsets(tsSource);
|
|
3006
|
+
const diagnostics = [];
|
|
3007
|
+
const walkNodes = (nodes) => {
|
|
3008
|
+
for (const node of nodes) {
|
|
3009
|
+
if (node.fieldTypeName === null) {
|
|
3010
|
+
const start = offsetToPosition(lineOffsets, node.fieldNameSpan.start);
|
|
3011
|
+
const end = offsetToPosition(lineOffsets, node.fieldNameSpan.end);
|
|
3012
|
+
diagnostics.push({
|
|
3013
|
+
range: {
|
|
3014
|
+
start,
|
|
3015
|
+
end
|
|
3016
|
+
},
|
|
3017
|
+
message: `Unknown field "${node.fieldName}" on type "${node.parentTypeName}"`,
|
|
3018
|
+
severity: DiagnosticSeverity.Error,
|
|
3019
|
+
source: "soda-gql"
|
|
3020
|
+
});
|
|
3021
|
+
}
|
|
3022
|
+
if (node.nested) {
|
|
3023
|
+
walkNested(node.nested);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
};
|
|
3027
|
+
const walkNested = (nested) => {
|
|
3028
|
+
if (nested.kind === "object") {
|
|
3029
|
+
walkNodes(nested.children);
|
|
3030
|
+
} else {
|
|
3031
|
+
for (const branch of nested.branches) {
|
|
3032
|
+
if (!branch.valid) {
|
|
3033
|
+
const start = offsetToPosition(lineOffsets, branch.typeNameSpan.start);
|
|
3034
|
+
const end = offsetToPosition(lineOffsets, branch.typeNameSpan.end);
|
|
3035
|
+
diagnostics.push({
|
|
3036
|
+
range: {
|
|
3037
|
+
start,
|
|
3038
|
+
end
|
|
3039
|
+
},
|
|
3040
|
+
message: `Type "${branch.typeName}" is not a member of union type`,
|
|
3041
|
+
severity: DiagnosticSeverity.Error,
|
|
3042
|
+
source: "soda-gql"
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
walkNodes(branch.children);
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
};
|
|
3049
|
+
walkNodes(fieldTree.children);
|
|
3050
|
+
return diagnostics;
|
|
3051
|
+
};
|
|
3052
|
+
|
|
3053
|
+
//#endregion
|
|
3054
|
+
//#region packages/lsp/src/diagnostics-collector.ts
|
|
3055
|
+
/** Collect all diagnostics (template + field tree) for a document state. */
|
|
3056
|
+
const collectRawDiagnostics = (state, ctx) => {
|
|
3057
|
+
const templateDiagnostics = state.templates.flatMap((template) => {
|
|
3058
|
+
const entry = ctx.schemaResolver.getSchema(template.schemaName);
|
|
3059
|
+
if (!entry) {
|
|
3060
|
+
return [];
|
|
3061
|
+
}
|
|
3062
|
+
const externalFragments = ctx.documentManager.getExternalFragments(state.uri, template.schemaName).map((f) => f.definition);
|
|
3063
|
+
return [...computeTemplateDiagnostics({
|
|
3064
|
+
template,
|
|
3065
|
+
schema: entry.schema,
|
|
3066
|
+
tsSource: state.source,
|
|
3067
|
+
externalFragments
|
|
3068
|
+
})];
|
|
3069
|
+
});
|
|
3070
|
+
const fieldTreeDiagnostics = state.fieldTrees.flatMap((tree) => {
|
|
3071
|
+
const entry = ctx.schemaResolver.getSchema(tree.schemaName);
|
|
3072
|
+
if (!entry) {
|
|
3073
|
+
return [];
|
|
3074
|
+
}
|
|
3075
|
+
const typedTree = resolveFieldTree(tree, entry.schema);
|
|
3076
|
+
if (!typedTree) {
|
|
3077
|
+
return [];
|
|
3078
|
+
}
|
|
3079
|
+
return [...computeFieldTreeDiagnostics({
|
|
3080
|
+
fieldTree: typedTree,
|
|
3081
|
+
tsSource: state.source
|
|
3082
|
+
})];
|
|
3083
|
+
});
|
|
3084
|
+
return [...templateDiagnostics, ...fieldTreeDiagnostics];
|
|
3085
|
+
};
|
|
3086
|
+
|
|
3087
|
+
//#endregion
|
|
3088
|
+
//#region packages/lsp/src/errors.ts
|
|
3089
|
+
/** Error constructor helpers for concise error creation. */
|
|
3090
|
+
const lspErrors = {
|
|
3091
|
+
configLoadFailed: (message, cause) => ({
|
|
3092
|
+
code: "CONFIG_LOAD_FAILED",
|
|
3093
|
+
message,
|
|
3094
|
+
cause
|
|
3095
|
+
}),
|
|
3096
|
+
schemaLoadFailed: (schemaName, message, cause) => ({
|
|
3097
|
+
code: "SCHEMA_LOAD_FAILED",
|
|
3098
|
+
message: message ?? `Failed to load schema: ${schemaName}`,
|
|
3099
|
+
schemaName,
|
|
3100
|
+
cause
|
|
3101
|
+
}),
|
|
3102
|
+
schemaBuildFailed: (schemaName, message, cause) => ({
|
|
3103
|
+
code: "SCHEMA_BUILD_FAILED",
|
|
3104
|
+
message: message ?? `Failed to build schema: ${schemaName}`,
|
|
3105
|
+
schemaName,
|
|
3106
|
+
cause
|
|
3107
|
+
}),
|
|
3108
|
+
schemaNotConfigured: (schemaName) => ({
|
|
3109
|
+
code: "SCHEMA_NOT_CONFIGURED",
|
|
3110
|
+
message: `Schema "${schemaName}" is not configured in soda-gql.config`,
|
|
3111
|
+
schemaName
|
|
3112
|
+
}),
|
|
3113
|
+
parseFailed: (uri, message, cause) => ({
|
|
3114
|
+
code: "PARSE_FAILED",
|
|
3115
|
+
message: message ?? `Failed to parse: ${uri}`,
|
|
3116
|
+
uri,
|
|
3117
|
+
cause
|
|
3118
|
+
}),
|
|
3119
|
+
internalInvariant: (message, context, cause) => ({
|
|
3120
|
+
code: "INTERNAL_INVARIANT",
|
|
3121
|
+
message,
|
|
3122
|
+
context,
|
|
3123
|
+
cause
|
|
3124
|
+
}),
|
|
3125
|
+
swcResolutionFailed: (message) => ({
|
|
3126
|
+
code: "SWC_RESOLUTION_FAILED",
|
|
3127
|
+
message: message ?? "@swc/core not found. Install @soda-gql/builder (which provides @swc/core) in your project and restart the LSP server to enable template extraction."
|
|
3128
|
+
})
|
|
3129
|
+
};
|
|
3130
|
+
|
|
3131
|
+
//#endregion
|
|
3132
|
+
//#region packages/lsp/src/schema-resolver.ts
|
|
3133
|
+
/**
|
|
3134
|
+
* Schema resolver: maps schema names to GraphQLSchema objects.
|
|
3135
|
+
* @module
|
|
3136
|
+
*/
|
|
3137
|
+
/** Wrap buildASTSchema (which throws) in a Result. */
|
|
3138
|
+
const safeBuildASTSchema = (schemaName, documentNode) => {
|
|
3139
|
+
try {
|
|
3140
|
+
return (0, neverthrow.ok)((0, graphql.buildASTSchema)(documentNode));
|
|
3141
|
+
} catch (e) {
|
|
3142
|
+
return (0, neverthrow.err)(lspErrors.schemaBuildFailed(schemaName, e instanceof Error ? e.message : String(e), e));
|
|
3143
|
+
}
|
|
3144
|
+
};
|
|
3145
|
+
const loadAndBuildSchema = (schemaName, schemaPaths) => {
|
|
3146
|
+
const documents = [];
|
|
3147
|
+
const files = [];
|
|
3148
|
+
for (const schemaPath of schemaPaths) {
|
|
3149
|
+
const resolvedPath = (0, node_path.resolve)(schemaPath);
|
|
3150
|
+
try {
|
|
3151
|
+
const content = (0, node_fs.readFileSync)(resolvedPath, "utf8");
|
|
3152
|
+
documents.push((0, graphql.parse)(content));
|
|
3153
|
+
files.push({
|
|
3154
|
+
filePath: resolvedPath,
|
|
3155
|
+
content
|
|
3156
|
+
});
|
|
3157
|
+
} catch (e) {
|
|
3158
|
+
return (0, neverthrow.err)(lspErrors.schemaLoadFailed(schemaName, e instanceof Error ? e.message : String(e)));
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
const documentNode = (0, graphql.concatAST)(documents);
|
|
3162
|
+
const hash = (0, __soda_gql_tools_codegen.hashSchema)(documentNode);
|
|
3163
|
+
const buildResult = safeBuildASTSchema(schemaName, documentNode);
|
|
3164
|
+
if (buildResult.isErr()) {
|
|
3165
|
+
return (0, neverthrow.err)(buildResult.error);
|
|
3166
|
+
}
|
|
3167
|
+
return (0, neverthrow.ok)({
|
|
3168
|
+
name: schemaName,
|
|
3169
|
+
schema: buildResult.value,
|
|
3170
|
+
documentNode,
|
|
3171
|
+
hash,
|
|
3172
|
+
files
|
|
3173
|
+
});
|
|
3174
|
+
};
|
|
3175
|
+
/** Create a schema resolver from config. Loads all schemas eagerly. */
|
|
3176
|
+
const createSchemaResolver = (config) => {
|
|
3177
|
+
const cache = new Map();
|
|
3178
|
+
for (const [name, schemaConfig] of Object.entries(config.schemas)) {
|
|
3179
|
+
const result = loadAndBuildSchema(name, schemaConfig.schema);
|
|
3180
|
+
if (result.isErr()) {
|
|
3181
|
+
return (0, neverthrow.err)(result.error);
|
|
3182
|
+
}
|
|
3183
|
+
cache.set(name, result.value);
|
|
3184
|
+
}
|
|
3185
|
+
const resolver = {
|
|
3186
|
+
getSchema: (schemaName) => cache.get(schemaName),
|
|
3187
|
+
getSchemaNames: () => [...cache.keys()],
|
|
3188
|
+
reloadSchema: (schemaName) => {
|
|
3189
|
+
const schemaConfig = config.schemas[schemaName];
|
|
3190
|
+
if (!schemaConfig) {
|
|
3191
|
+
return (0, neverthrow.err)(lspErrors.schemaNotConfigured(schemaName));
|
|
3192
|
+
}
|
|
3193
|
+
const result = loadAndBuildSchema(schemaName, schemaConfig.schema);
|
|
3194
|
+
if (result.isErr()) {
|
|
3195
|
+
return (0, neverthrow.err)(result.error);
|
|
3196
|
+
}
|
|
3197
|
+
cache.set(schemaName, result.value);
|
|
3198
|
+
return (0, neverthrow.ok)(result.value);
|
|
3199
|
+
},
|
|
3200
|
+
reloadAll: () => {
|
|
3201
|
+
const errors = [];
|
|
3202
|
+
for (const [name, schemaConfig] of Object.entries(config.schemas)) {
|
|
3203
|
+
const result = loadAndBuildSchema(name, schemaConfig.schema);
|
|
3204
|
+
if (result.isErr()) {
|
|
3205
|
+
errors.push(result.error);
|
|
3206
|
+
} else {
|
|
3207
|
+
cache.set(name, result.value);
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
return errors.length > 0 ? (0, neverthrow.err)(errors) : (0, neverthrow.ok)(undefined);
|
|
3211
|
+
}
|
|
3212
|
+
};
|
|
3213
|
+
return (0, neverthrow.ok)(resolver);
|
|
3214
|
+
};
|
|
3215
|
+
|
|
3216
|
+
//#endregion
|
|
3217
|
+
//#region packages/lsp/src/config-registry.ts
|
|
3218
|
+
/**
|
|
3219
|
+
* Config registry: maps document URIs to their nearest config context.
|
|
3220
|
+
* Supports multiple soda-gql configs in a monorepo workspace.
|
|
3221
|
+
* @module
|
|
3222
|
+
*/
|
|
3223
|
+
const createConfigRegistry = (configPaths) => {
|
|
3224
|
+
const sortedPaths = [...configPaths].sort((a, b) => b.length - a.length);
|
|
3225
|
+
const contexts = new Map();
|
|
3226
|
+
for (const configPath of sortedPaths) {
|
|
3227
|
+
const configResult = (0, __soda_gql_config.loadConfig)(configPath);
|
|
3228
|
+
if (configResult.isErr()) {
|
|
3229
|
+
return (0, neverthrow.err)(lspErrors.configLoadFailed(`Failed to load config ${configPath}: ${configResult.error.message}`, configResult.error));
|
|
3230
|
+
}
|
|
3231
|
+
const config = configResult.value;
|
|
3232
|
+
const helper = (0, __soda_gql_builder.createGraphqlSystemIdentifyHelper)(config);
|
|
3233
|
+
const resolverResult = createSchemaResolver(config);
|
|
3234
|
+
if (resolverResult.isErr()) {
|
|
3235
|
+
return (0, neverthrow.err)(resolverResult.error);
|
|
3236
|
+
}
|
|
3237
|
+
contexts.set(configPath, {
|
|
3238
|
+
configPath,
|
|
3239
|
+
config,
|
|
3240
|
+
helper,
|
|
3241
|
+
schemaResolver: resolverResult.value,
|
|
3242
|
+
documentManager: createDocumentManager(helper, { resolveFrom: configPath })
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
const uriCache = new Map();
|
|
3246
|
+
const resolveConfigPath = (dirPath) => {
|
|
3247
|
+
const cached = uriCache.get(dirPath);
|
|
3248
|
+
if (cached !== undefined) {
|
|
3249
|
+
return cached;
|
|
3250
|
+
}
|
|
3251
|
+
for (const configPath of sortedPaths) {
|
|
3252
|
+
const configDir = (0, node_path.dirname)(configPath);
|
|
3253
|
+
if (dirPath === configDir || dirPath.startsWith(`${configDir}${node_path.sep}`)) {
|
|
3254
|
+
uriCache.set(dirPath, configPath);
|
|
3255
|
+
return configPath;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
uriCache.set(dirPath, null);
|
|
3259
|
+
return null;
|
|
3260
|
+
};
|
|
3261
|
+
return (0, neverthrow.ok)({
|
|
3262
|
+
resolveForUri: (uri) => {
|
|
3263
|
+
if (!uri.startsWith("file://") && !uri.startsWith("/")) {
|
|
3264
|
+
return undefined;
|
|
3265
|
+
}
|
|
3266
|
+
const filePath = uri.startsWith("file://") ? (0, node_url.fileURLToPath)(uri) : uri;
|
|
3267
|
+
const dirPath = (0, node_path.dirname)(filePath);
|
|
3268
|
+
const configPath = resolveConfigPath(dirPath);
|
|
3269
|
+
return configPath ? contexts.get(configPath) : undefined;
|
|
3270
|
+
},
|
|
3271
|
+
getAllContexts: () => [...contexts.values()],
|
|
3272
|
+
reloadSchemas: (configPath) => {
|
|
3273
|
+
const ctx = contexts.get(configPath);
|
|
3274
|
+
if (!ctx) {
|
|
3275
|
+
return (0, neverthrow.err)([lspErrors.configLoadFailed(`Config not found: ${configPath}`)]);
|
|
3276
|
+
}
|
|
3277
|
+
return ctx.schemaResolver.reloadAll();
|
|
3278
|
+
},
|
|
3279
|
+
reloadAllSchemas: () => {
|
|
3280
|
+
const errors = [];
|
|
3281
|
+
for (const ctx of contexts.values()) {
|
|
3282
|
+
const result = ctx.schemaResolver.reloadAll();
|
|
3283
|
+
if (result.isErr()) {
|
|
3284
|
+
errors.push(...result.error);
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
return errors.length > 0 ? (0, neverthrow.err)(errors) : (0, neverthrow.ok)(undefined);
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
3290
|
+
};
|
|
3291
|
+
|
|
2952
3292
|
//#endregion
|
|
2953
3293
|
//#region packages/lsp/src/handlers/code-action.ts
|
|
2954
3294
|
/** Handle a code action request for a GraphQL template. */
|
|
@@ -3106,7 +3446,7 @@ const findStatementStart = (source, offset) => {
|
|
|
3106
3446
|
const handleCompletion = (input) => {
|
|
3107
3447
|
const { template, schema, tsSource, tsPosition } = input;
|
|
3108
3448
|
const reconstructed = reconstructGraphql(template);
|
|
3109
|
-
const headerLen = reconstructed
|
|
3449
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
3110
3450
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
3111
3451
|
const mapper = createPositionMapper({
|
|
3112
3452
|
tsSource,
|
|
@@ -3129,6 +3469,27 @@ const handleCompletion = (input) => {
|
|
|
3129
3469
|
//#endregion
|
|
3130
3470
|
//#region packages/lsp/src/handlers/_utils.ts
|
|
3131
3471
|
/**
|
|
3472
|
+
* Shared handler utilities for fragment spread and definition lookup.
|
|
3473
|
+
* @module
|
|
3474
|
+
*/
|
|
3475
|
+
/** Build ObjectTypeInfo[] from schema file info for graphql-language-service definition APIs. */
|
|
3476
|
+
const buildObjectTypeInfos = (files) => {
|
|
3477
|
+
const result = [];
|
|
3478
|
+
for (const file of files) {
|
|
3479
|
+
const doc = (0, graphql.parse)(file.content);
|
|
3480
|
+
for (const def of doc.definitions) {
|
|
3481
|
+
if ((0, graphql.isTypeDefinitionNode)(def)) {
|
|
3482
|
+
result.push({
|
|
3483
|
+
filePath: (0, node_url.pathToFileURL)(file.filePath).href,
|
|
3484
|
+
content: file.content,
|
|
3485
|
+
definition: def
|
|
3486
|
+
});
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
return result;
|
|
3491
|
+
};
|
|
3492
|
+
/**
|
|
3132
3493
|
* Find the fragment spread node at the given GraphQL offset using AST.
|
|
3133
3494
|
* Returns the FragmentSpreadNode if cursor is on a `...FragmentName` pattern.
|
|
3134
3495
|
*/
|
|
@@ -3258,35 +3619,41 @@ const computeSpreadLocationRanges = (spreadLocations) => {
|
|
|
3258
3619
|
}
|
|
3259
3620
|
return ranges;
|
|
3260
3621
|
};
|
|
3261
|
-
|
|
3262
|
-
//#endregion
|
|
3263
|
-
//#region packages/lsp/src/handlers/definition.ts
|
|
3264
3622
|
/**
|
|
3265
|
-
*
|
|
3266
|
-
*
|
|
3623
|
+
* Resolve a directive name to its definition in schema files.
|
|
3624
|
+
* Parses each schema file and finds DirectiveDefinitionNode matching the name.
|
|
3267
3625
|
*/
|
|
3268
|
-
|
|
3269
|
-
const
|
|
3270
|
-
const
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3626
|
+
const resolveDirectiveDefinition = (directiveName, schemaFiles) => {
|
|
3627
|
+
const locations = [];
|
|
3628
|
+
for (const file of schemaFiles) {
|
|
3629
|
+
try {
|
|
3630
|
+
const doc = (0, graphql.parse)(file.content, { noLocation: false });
|
|
3631
|
+
const lineOffsets = computeLineOffsets(file.content);
|
|
3632
|
+
for (const def of doc.definitions) {
|
|
3633
|
+
if (def.kind === "DirectiveDefinition" && def.name.value === directiveName && def.name.loc) {
|
|
3634
|
+
const start = offsetToPosition(lineOffsets, def.name.loc.start);
|
|
3635
|
+
const end = offsetToPosition(lineOffsets, def.name.loc.end);
|
|
3636
|
+
locations.push({
|
|
3637
|
+
uri: (0, node_url.pathToFileURL)(file.filePath).href,
|
|
3638
|
+
range: {
|
|
3639
|
+
start,
|
|
3640
|
+
end
|
|
3641
|
+
}
|
|
3642
|
+
});
|
|
3643
|
+
}
|
|
3280
3644
|
}
|
|
3281
|
-
}
|
|
3645
|
+
} catch {}
|
|
3282
3646
|
}
|
|
3283
|
-
return
|
|
3647
|
+
return locations;
|
|
3284
3648
|
};
|
|
3649
|
+
|
|
3650
|
+
//#endregion
|
|
3651
|
+
//#region packages/lsp/src/handlers/definition.ts
|
|
3285
3652
|
/** Handle a definition request for a GraphQL template. */
|
|
3286
3653
|
const handleDefinition = async (input) => {
|
|
3287
3654
|
const { template, tsSource, tsPosition, externalFragments } = input;
|
|
3288
3655
|
const reconstructed = reconstructGraphql(template);
|
|
3289
|
-
const headerLen = reconstructed
|
|
3656
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
3290
3657
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
3291
3658
|
const mapper = createPositionMapper({
|
|
3292
3659
|
tsSource,
|
|
@@ -3304,10 +3671,16 @@ const handleDefinition = async (input) => {
|
|
|
3304
3671
|
if (fragmentSpread) {
|
|
3305
3672
|
return resolveFragmentSpreadDefinition(preprocessed, fragmentSpread, externalFragments);
|
|
3306
3673
|
}
|
|
3674
|
+
if (input.schemaFiles && input.schemaFiles.length > 0) {
|
|
3675
|
+
const varTypeResult = await resolveVariableTypeDefinition(preprocessed, reconstructedOffset, input.schemaFiles);
|
|
3676
|
+
if (varTypeResult.length > 0) {
|
|
3677
|
+
return varTypeResult;
|
|
3678
|
+
}
|
|
3679
|
+
}
|
|
3307
3680
|
if (input.schema && input.schemaFiles && input.schemaFiles.length > 0) {
|
|
3308
3681
|
const reconstructedLineOffsets = computeLineOffsets(preprocessed);
|
|
3309
3682
|
const reconstructedPosition = offsetToPosition(reconstructedLineOffsets, reconstructedOffset);
|
|
3310
|
-
return resolveSchemaDefinition(preprocessed, reconstructedPosition, input.schema, input.schemaFiles);
|
|
3683
|
+
return resolveSchemaDefinition(preprocessed, reconstructedPosition, reconstructedOffset, input.schema, input.schemaFiles);
|
|
3311
3684
|
}
|
|
3312
3685
|
return [];
|
|
3313
3686
|
};
|
|
@@ -3372,22 +3745,78 @@ const resolveFragmentSpreadDefinition = async (preprocessed, fragmentSpread, ext
|
|
|
3372
3745
|
return [];
|
|
3373
3746
|
}
|
|
3374
3747
|
};
|
|
3748
|
+
/** Unwrap NonNullType/ListType wrappers to get the inner NamedType node. */
|
|
3749
|
+
const unwrapToNamedType = (typeNode) => {
|
|
3750
|
+
if (typeNode.kind === "NamedType") return typeNode;
|
|
3751
|
+
if (typeNode.kind === "NonNullType" || typeNode.kind === "ListType") {
|
|
3752
|
+
return unwrapToNamedType(typeNode.type);
|
|
3753
|
+
}
|
|
3754
|
+
return null;
|
|
3755
|
+
};
|
|
3756
|
+
/**
|
|
3757
|
+
* Resolve variable type reference to its definition in a schema file.
|
|
3758
|
+
* Parses the GraphQL source to find VariableDefinition nodes, checks if the
|
|
3759
|
+
* cursor offset falls within a type name, and resolves via getDefinitionQueryResultForNamedType.
|
|
3760
|
+
*/
|
|
3761
|
+
const resolveVariableTypeDefinition = async (preprocessed, reconstructedOffset, schemaFiles) => {
|
|
3762
|
+
let ast;
|
|
3763
|
+
try {
|
|
3764
|
+
ast = (0, graphql.parse)(preprocessed, { noLocation: false });
|
|
3765
|
+
} catch {
|
|
3766
|
+
return [];
|
|
3767
|
+
}
|
|
3768
|
+
let matchedNode = null;
|
|
3769
|
+
(0, graphql.visit)(ast, { VariableDefinition(node) {
|
|
3770
|
+
if (matchedNode) return;
|
|
3771
|
+
const namedType = unwrapToNamedType(node.type);
|
|
3772
|
+
if (!namedType?.name.loc) return;
|
|
3773
|
+
const { start, end } = namedType.name.loc;
|
|
3774
|
+
if (reconstructedOffset >= start && reconstructedOffset < end) {
|
|
3775
|
+
matchedNode = namedType;
|
|
3776
|
+
}
|
|
3777
|
+
} });
|
|
3778
|
+
if (!matchedNode) return [];
|
|
3779
|
+
const objectTypeInfos = buildObjectTypeInfos(schemaFiles);
|
|
3780
|
+
try {
|
|
3781
|
+
const result = await (0, graphql_language_service.getDefinitionQueryResultForNamedType)(preprocessed, matchedNode, objectTypeInfos);
|
|
3782
|
+
return result.definitions.map((def) => ({
|
|
3783
|
+
uri: def.path ?? "",
|
|
3784
|
+
range: {
|
|
3785
|
+
start: {
|
|
3786
|
+
line: def.position.line,
|
|
3787
|
+
character: def.position.character
|
|
3788
|
+
},
|
|
3789
|
+
end: {
|
|
3790
|
+
line: def.range?.end?.line ?? def.position.line,
|
|
3791
|
+
character: def.range?.end?.character ?? def.position.character
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
}));
|
|
3795
|
+
} catch {
|
|
3796
|
+
return [];
|
|
3797
|
+
}
|
|
3798
|
+
};
|
|
3375
3799
|
/** Resolve field or type name to its definition in a schema .graphql file. */
|
|
3376
|
-
const resolveSchemaDefinition = (preprocessed, position, schema, schemaFiles) => {
|
|
3800
|
+
const resolveSchemaDefinition = async (preprocessed, position, reconstructedOffset, schema, schemaFiles) => {
|
|
3801
|
+
const astResult = await tryResolveTypeConditionOrDirective(preprocessed, reconstructedOffset, schemaFiles);
|
|
3802
|
+
if (astResult.matched) {
|
|
3803
|
+
return astResult.locations;
|
|
3804
|
+
}
|
|
3377
3805
|
const context = (0, graphql_language_service.getContextAtPosition)(preprocessed, toIPosition(position), schema);
|
|
3378
3806
|
if (!context) {
|
|
3379
|
-
return
|
|
3807
|
+
return [];
|
|
3380
3808
|
}
|
|
3381
3809
|
const { typeInfo } = context;
|
|
3382
3810
|
if (typeInfo.fieldDef && typeInfo.parentType) {
|
|
3383
3811
|
const fieldName = typeInfo.fieldDef.name;
|
|
3384
3812
|
const namedParentType = (0, graphql.getNamedType)(typeInfo.parentType);
|
|
3385
3813
|
if (!namedParentType) {
|
|
3386
|
-
return
|
|
3814
|
+
return [];
|
|
3387
3815
|
}
|
|
3388
3816
|
const parentTypeName = namedParentType.name;
|
|
3389
3817
|
const objectTypeInfos = buildObjectTypeInfos(schemaFiles);
|
|
3390
|
-
|
|
3818
|
+
const result = await (0, graphql_language_service.getDefinitionQueryResultForField)(fieldName, parentTypeName, objectTypeInfos);
|
|
3819
|
+
return result.definitions.map((def) => ({
|
|
3391
3820
|
uri: def.path ?? "",
|
|
3392
3821
|
range: {
|
|
3393
3822
|
start: {
|
|
@@ -3399,63 +3828,99 @@ const resolveSchemaDefinition = (preprocessed, position, schema, schemaFiles) =>
|
|
|
3399
3828
|
character: def.range?.end?.character ?? def.position.character
|
|
3400
3829
|
}
|
|
3401
3830
|
}
|
|
3402
|
-
}))
|
|
3831
|
+
}));
|
|
3403
3832
|
}
|
|
3404
|
-
return
|
|
3833
|
+
return [];
|
|
3405
3834
|
};
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
}
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3835
|
+
/**
|
|
3836
|
+
* Try to resolve inline fragment type conditions and directive names via AST walking.
|
|
3837
|
+
* Returns { matched: true, locations } when cursor is on a type condition or directive,
|
|
3838
|
+
* or { matched: false } when cursor is on neither (caller should try field resolution).
|
|
3839
|
+
*/
|
|
3840
|
+
const tryResolveTypeConditionOrDirective = async (preprocessed, reconstructedOffset, schemaFiles) => {
|
|
3841
|
+
let ast;
|
|
3842
|
+
try {
|
|
3843
|
+
ast = (0, graphql.parse)(preprocessed, { noLocation: false });
|
|
3844
|
+
} catch {
|
|
3845
|
+
return { matched: false };
|
|
3846
|
+
}
|
|
3847
|
+
let matchedTypeName = null;
|
|
3848
|
+
let matchedDirectiveName = null;
|
|
3849
|
+
(0, graphql.visit)(ast, {
|
|
3850
|
+
InlineFragment(node) {
|
|
3851
|
+
const loc = node.typeCondition?.name.loc;
|
|
3852
|
+
if (loc && reconstructedOffset >= loc.start && reconstructedOffset < loc.end) {
|
|
3853
|
+
matchedTypeName = node.typeCondition.name.value;
|
|
3854
|
+
}
|
|
3855
|
+
},
|
|
3856
|
+
FragmentDefinition(node) {
|
|
3857
|
+
const loc = node.typeCondition.name.loc;
|
|
3858
|
+
if (loc && reconstructedOffset >= loc.start && reconstructedOffset < loc.end) {
|
|
3859
|
+
matchedTypeName = node.typeCondition.name.value;
|
|
3860
|
+
}
|
|
3861
|
+
},
|
|
3862
|
+
Directive(node) {
|
|
3863
|
+
const loc = node.name.loc;
|
|
3864
|
+
if (loc && reconstructedOffset >= loc.start && reconstructedOffset < loc.end) {
|
|
3865
|
+
matchedDirectiveName = node.name.value;
|
|
3866
|
+
}
|
|
3436
3867
|
}
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3868
|
+
});
|
|
3869
|
+
if (matchedTypeName) {
|
|
3870
|
+
return {
|
|
3871
|
+
matched: true,
|
|
3872
|
+
locations: await resolveTypeNameToSchemaDefinition(matchedTypeName, schemaFiles)
|
|
3873
|
+
};
|
|
3874
|
+
}
|
|
3875
|
+
if (matchedDirectiveName) {
|
|
3443
3876
|
return {
|
|
3877
|
+
matched: true,
|
|
3878
|
+
locations: resolveDirectiveDefinition(matchedDirectiveName, schemaFiles)
|
|
3879
|
+
};
|
|
3880
|
+
}
|
|
3881
|
+
return { matched: false };
|
|
3882
|
+
};
|
|
3883
|
+
/**
|
|
3884
|
+
* Resolve a type name to its definition in a schema file.
|
|
3885
|
+
* Used for fragment type names and inline fragment type conditions.
|
|
3886
|
+
*/
|
|
3887
|
+
const resolveTypeNameToSchemaDefinition = async (typeName, schemaFiles) => {
|
|
3888
|
+
const typeNameLen = typeName.length;
|
|
3889
|
+
const dummyLoc = {
|
|
3890
|
+
start: 0,
|
|
3891
|
+
end: typeNameLen,
|
|
3892
|
+
startToken: null,
|
|
3893
|
+
endToken: null,
|
|
3894
|
+
source: null
|
|
3895
|
+
};
|
|
3896
|
+
const namedTypeNode = {
|
|
3897
|
+
kind: graphql.Kind.NAMED_TYPE,
|
|
3898
|
+
name: {
|
|
3899
|
+
kind: graphql.Kind.NAME,
|
|
3900
|
+
value: typeName,
|
|
3901
|
+
loc: dummyLoc
|
|
3902
|
+
},
|
|
3903
|
+
loc: dummyLoc
|
|
3904
|
+
};
|
|
3905
|
+
const objectTypeInfos = buildObjectTypeInfos(schemaFiles);
|
|
3906
|
+
try {
|
|
3907
|
+
const result = await (0, graphql_language_service.getDefinitionQueryResultForNamedType)("", namedTypeNode, objectTypeInfos);
|
|
3908
|
+
return result.definitions.map((def) => ({
|
|
3909
|
+
uri: def.path ?? "",
|
|
3444
3910
|
range: {
|
|
3445
3911
|
start: {
|
|
3446
|
-
line:
|
|
3447
|
-
character:
|
|
3912
|
+
line: def.position.line,
|
|
3913
|
+
character: def.position.character
|
|
3448
3914
|
},
|
|
3449
3915
|
end: {
|
|
3450
|
-
line:
|
|
3451
|
-
character:
|
|
3916
|
+
line: def.range?.end?.line ?? def.position.line,
|
|
3917
|
+
character: def.range?.end?.character ?? def.position.character
|
|
3452
3918
|
}
|
|
3453
|
-
}
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
});
|
|
3919
|
+
}
|
|
3920
|
+
}));
|
|
3921
|
+
} catch {
|
|
3922
|
+
return [];
|
|
3923
|
+
}
|
|
3459
3924
|
};
|
|
3460
3925
|
|
|
3461
3926
|
//#endregion
|
|
@@ -3523,7 +3988,7 @@ const handleDocumentSymbol = (input) => {
|
|
|
3523
3988
|
const symbols = [];
|
|
3524
3989
|
for (const template of templates) {
|
|
3525
3990
|
const reconstructed = reconstructGraphql(template);
|
|
3526
|
-
const headerLen = reconstructed
|
|
3991
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
3527
3992
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
3528
3993
|
const outline = (0, graphql_language_service.getOutline)(preprocessed);
|
|
3529
3994
|
if (!outline) {
|
|
@@ -3544,6 +4009,11 @@ const handleDocumentSymbol = (input) => {
|
|
|
3544
4009
|
for (const tree of outline.outlineTrees) {
|
|
3545
4010
|
const symbol = convertTree(tree, toContentPos, mapper);
|
|
3546
4011
|
if (symbol) {
|
|
4012
|
+
if (template.kind === "fragment" && template.typeName) {
|
|
4013
|
+
symbol.detail = `on ${template.typeName}`;
|
|
4014
|
+
} else if (template.kind !== "fragment") {
|
|
4015
|
+
symbol.detail = template.kind;
|
|
4016
|
+
}
|
|
3547
4017
|
symbols.push(symbol);
|
|
3548
4018
|
}
|
|
3549
4019
|
}
|
|
@@ -3551,6 +4021,129 @@ const handleDocumentSymbol = (input) => {
|
|
|
3551
4021
|
return symbols;
|
|
3552
4022
|
};
|
|
3553
4023
|
|
|
4024
|
+
//#endregion
|
|
4025
|
+
//#region packages/lsp/src/handlers/field-tree-completion.ts
|
|
4026
|
+
/** Handle a completion request for a callback builder field tree node. */
|
|
4027
|
+
const handleFieldTreeCompletion = (input) => {
|
|
4028
|
+
const { fieldTree, schema, tsSource, offset } = input;
|
|
4029
|
+
const result = findNodeAtOffset(fieldTree, offset);
|
|
4030
|
+
if (!result) return [];
|
|
4031
|
+
if (result.kind === "field") {
|
|
4032
|
+
const { node } = result;
|
|
4033
|
+
const prefix = tsSource.slice(node.fieldNameSpan.start, offset);
|
|
4034
|
+
const parentType = schema.getType(node.parentTypeName);
|
|
4035
|
+
if (!parentType || !(0, graphql.isObjectType)(parentType)) return [];
|
|
4036
|
+
const fields = parentType.getFields();
|
|
4037
|
+
const items = [];
|
|
4038
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
4039
|
+
if (!name.startsWith(prefix)) continue;
|
|
4040
|
+
const namedType = (0, graphql.getNamedType)(field.type);
|
|
4041
|
+
items.push({
|
|
4042
|
+
label: name,
|
|
4043
|
+
kind: CompletionItemKind.Field,
|
|
4044
|
+
detail: namedType?.name
|
|
4045
|
+
});
|
|
4046
|
+
}
|
|
4047
|
+
return items;
|
|
4048
|
+
}
|
|
4049
|
+
if (result.kind === "unionMember") {
|
|
4050
|
+
const { parentNode } = result;
|
|
4051
|
+
const fieldType = parentNode.fieldTypeName ? schema.getType(parentNode.fieldTypeName) : null;
|
|
4052
|
+
if (!fieldType || !(fieldType instanceof graphql.GraphQLUnionType)) return [];
|
|
4053
|
+
const prefix = tsSource.slice(result.branch.typeNameSpan.start, offset);
|
|
4054
|
+
return fieldType.getTypes().filter((member) => member.name.startsWith(prefix)).map((member) => ({
|
|
4055
|
+
label: member.name,
|
|
4056
|
+
kind: CompletionItemKind.Class,
|
|
4057
|
+
detail: `member of ${parentNode.fieldTypeName}`
|
|
4058
|
+
}));
|
|
4059
|
+
}
|
|
4060
|
+
return [];
|
|
4061
|
+
};
|
|
4062
|
+
|
|
4063
|
+
//#endregion
|
|
4064
|
+
//#region packages/lsp/src/handlers/field-tree-definition.ts
|
|
4065
|
+
/** Handle a definition request for a callback builder field tree. */
|
|
4066
|
+
const handleFieldTreeDefinition = async (input) => {
|
|
4067
|
+
const { fieldTree, offset, schemaFiles } = input;
|
|
4068
|
+
const result = findNodeAtOffset(fieldTree, offset);
|
|
4069
|
+
if (!result) return [];
|
|
4070
|
+
const objectTypeInfos = buildObjectTypeInfos(schemaFiles);
|
|
4071
|
+
if (result.kind === "field") {
|
|
4072
|
+
const { node } = result;
|
|
4073
|
+
try {
|
|
4074
|
+
const defResult = await (0, graphql_language_service.getDefinitionQueryResultForField)(node.fieldName, node.parentTypeName, objectTypeInfos);
|
|
4075
|
+
return defResult.definitions.map((def) => ({
|
|
4076
|
+
uri: def.path ?? "",
|
|
4077
|
+
range: {
|
|
4078
|
+
start: {
|
|
4079
|
+
line: def.position.line,
|
|
4080
|
+
character: def.position.character
|
|
4081
|
+
},
|
|
4082
|
+
end: {
|
|
4083
|
+
line: def.range?.end?.line ?? def.position.line,
|
|
4084
|
+
character: def.range?.end?.character ?? def.position.character
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
}));
|
|
4088
|
+
} catch {
|
|
4089
|
+
return [];
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
if (result.kind === "unionMember") {
|
|
4093
|
+
const typeNameLen = result.branch.typeName.length;
|
|
4094
|
+
const dummyLoc = {
|
|
4095
|
+
start: 0,
|
|
4096
|
+
end: typeNameLen,
|
|
4097
|
+
startToken: null,
|
|
4098
|
+
endToken: null,
|
|
4099
|
+
source: null
|
|
4100
|
+
};
|
|
4101
|
+
const namedTypeNode = {
|
|
4102
|
+
kind: graphql.Kind.NAMED_TYPE,
|
|
4103
|
+
name: {
|
|
4104
|
+
kind: graphql.Kind.NAME,
|
|
4105
|
+
value: result.branch.typeName,
|
|
4106
|
+
loc: dummyLoc
|
|
4107
|
+
},
|
|
4108
|
+
loc: dummyLoc
|
|
4109
|
+
};
|
|
4110
|
+
try {
|
|
4111
|
+
const defResult = await (0, graphql_language_service.getDefinitionQueryResultForNamedType)("", namedTypeNode, objectTypeInfos);
|
|
4112
|
+
return defResult.definitions.map((def) => ({
|
|
4113
|
+
uri: def.path ?? "",
|
|
4114
|
+
range: {
|
|
4115
|
+
start: {
|
|
4116
|
+
line: def.position.line,
|
|
4117
|
+
character: def.position.character
|
|
4118
|
+
},
|
|
4119
|
+
end: {
|
|
4120
|
+
line: def.range?.end?.line ?? def.position.line,
|
|
4121
|
+
character: def.range?.end?.character ?? def.position.character
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
}));
|
|
4125
|
+
} catch {
|
|
4126
|
+
return [];
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
return [];
|
|
4130
|
+
};
|
|
4131
|
+
|
|
4132
|
+
//#endregion
|
|
4133
|
+
//#region packages/lsp/src/handlers/field-tree-hover.ts
|
|
4134
|
+
/** Handle a hover request for a callback builder field tree node. */
|
|
4135
|
+
const handleFieldTreeHover = (input) => {
|
|
4136
|
+
const { fieldTree, offset } = input;
|
|
4137
|
+
const result = findNodeAtOffset(fieldTree, offset);
|
|
4138
|
+
if (!result || result.kind !== "field") return null;
|
|
4139
|
+
const { node } = result;
|
|
4140
|
+
if (!node.fieldTypeName) return null;
|
|
4141
|
+
return { contents: {
|
|
4142
|
+
kind: "markdown",
|
|
4143
|
+
value: `${node.fieldName}: ${node.fieldTypeName}`
|
|
4144
|
+
} };
|
|
4145
|
+
};
|
|
4146
|
+
|
|
3554
4147
|
//#endregion
|
|
3555
4148
|
//#region packages/lsp/src/handlers/formatting.ts
|
|
3556
4149
|
/**
|
|
@@ -3582,7 +4175,7 @@ const handleFormatting = (input) => {
|
|
|
3582
4175
|
const handleHover = (input) => {
|
|
3583
4176
|
const { template, schema, tsSource, tsPosition } = input;
|
|
3584
4177
|
const reconstructed = reconstructGraphql(template);
|
|
3585
|
-
const headerLen = reconstructed
|
|
4178
|
+
const headerLen = computeHeaderLen(template, reconstructed);
|
|
3586
4179
|
const { preprocessed } = preprocessFragmentArgs(reconstructed);
|
|
3587
4180
|
const mapper = createPositionMapper({
|
|
3588
4181
|
tsSource,
|
|
@@ -3746,6 +4339,115 @@ const handleRename = (input) => {
|
|
|
3746
4339
|
* LSP server: wires all components together via vscode-languageserver.
|
|
3747
4340
|
* @module
|
|
3748
4341
|
*/
|
|
4342
|
+
/**
|
|
4343
|
+
* Shared 3-phase dispatch: registry/ctx/doc guard → field-tree → template.
|
|
4344
|
+
* Used by completion, hover, and definition handlers.
|
|
4345
|
+
*/
|
|
4346
|
+
const resolvePositionContext = (registry, documents, uri, position) => {
|
|
4347
|
+
if (!registry) {
|
|
4348
|
+
return undefined;
|
|
4349
|
+
}
|
|
4350
|
+
const ctx = registry.resolveForUri(uri);
|
|
4351
|
+
if (!ctx) {
|
|
4352
|
+
return undefined;
|
|
4353
|
+
}
|
|
4354
|
+
const doc = documents.get(uri);
|
|
4355
|
+
if (!doc) {
|
|
4356
|
+
return undefined;
|
|
4357
|
+
}
|
|
4358
|
+
const tsSource = doc.getText();
|
|
4359
|
+
const offset = positionToOffset(tsSource, position);
|
|
4360
|
+
const tsPosition = {
|
|
4361
|
+
line: position.line,
|
|
4362
|
+
character: position.character
|
|
4363
|
+
};
|
|
4364
|
+
const untypedTree = ctx.documentManager.findFieldTreeAtOffset(uri, offset);
|
|
4365
|
+
if (untypedTree) {
|
|
4366
|
+
const schemaEntry$1 = ctx.schemaResolver.getSchema(untypedTree.schemaName);
|
|
4367
|
+
if (schemaEntry$1) {
|
|
4368
|
+
const typedTree = resolveFieldTree(untypedTree, schemaEntry$1.schema);
|
|
4369
|
+
if (typedTree) {
|
|
4370
|
+
return {
|
|
4371
|
+
kind: "fieldTree",
|
|
4372
|
+
ctx,
|
|
4373
|
+
tsSource,
|
|
4374
|
+
offset,
|
|
4375
|
+
tsPosition,
|
|
4376
|
+
typedTree,
|
|
4377
|
+
schema: schemaEntry$1.schema,
|
|
4378
|
+
schemaEntry: schemaEntry$1
|
|
4379
|
+
};
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
const template = ctx.documentManager.findTemplateAtOffset(uri, offset);
|
|
4384
|
+
if (!template) {
|
|
4385
|
+
return undefined;
|
|
4386
|
+
}
|
|
4387
|
+
const schemaEntry = ctx.schemaResolver.getSchema(template.schemaName);
|
|
4388
|
+
return {
|
|
4389
|
+
kind: "template",
|
|
4390
|
+
ctx,
|
|
4391
|
+
tsSource,
|
|
4392
|
+
offset,
|
|
4393
|
+
tsPosition,
|
|
4394
|
+
template,
|
|
4395
|
+
schemaEntry
|
|
4396
|
+
};
|
|
4397
|
+
};
|
|
4398
|
+
/** Server capabilities shared between direct and proxy initialization. */
|
|
4399
|
+
const serverCapabilities = {
|
|
4400
|
+
textDocumentSync: vscode_languageserver_node.TextDocumentSyncKind.Full,
|
|
4401
|
+
hoverProvider: true,
|
|
4402
|
+
documentSymbolProvider: true,
|
|
4403
|
+
definitionProvider: true,
|
|
4404
|
+
referencesProvider: true,
|
|
4405
|
+
renameProvider: { prepareProvider: true },
|
|
4406
|
+
documentFormattingProvider: true,
|
|
4407
|
+
completionProvider: { triggerCharacters: [
|
|
4408
|
+
"{",
|
|
4409
|
+
"(",
|
|
4410
|
+
":",
|
|
4411
|
+
"@",
|
|
4412
|
+
"$",
|
|
4413
|
+
" ",
|
|
4414
|
+
"\n",
|
|
4415
|
+
".",
|
|
4416
|
+
"\""
|
|
4417
|
+
] },
|
|
4418
|
+
codeActionProvider: { codeActionKinds: ["refactor.extract"] }
|
|
4419
|
+
};
|
|
4420
|
+
/** Initialize the LSP server from InitializeParams. Used by both direct and proxy modes. */
|
|
4421
|
+
const initializeFromParams = (params, connection) => {
|
|
4422
|
+
const roots = resolveWorkspaceRoots(params);
|
|
4423
|
+
if (roots.length === 0) {
|
|
4424
|
+
connection.window.showErrorMessage("soda-gql LSP: no workspace root provided");
|
|
4425
|
+
return {
|
|
4426
|
+
result: { capabilities: {} },
|
|
4427
|
+
registry: undefined
|
|
4428
|
+
};
|
|
4429
|
+
}
|
|
4430
|
+
const configPaths = discoverConfigs(roots);
|
|
4431
|
+
if (configPaths.length === 0) {
|
|
4432
|
+
connection.window.showErrorMessage("soda-gql LSP: no config file found");
|
|
4433
|
+
return {
|
|
4434
|
+
result: { capabilities: {} },
|
|
4435
|
+
registry: undefined
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
const registryResult = createConfigRegistry(configPaths);
|
|
4439
|
+
if (registryResult.isErr()) {
|
|
4440
|
+
connection.window.showErrorMessage(`soda-gql LSP: ${registryResult.error.message}`);
|
|
4441
|
+
return {
|
|
4442
|
+
result: { capabilities: {} },
|
|
4443
|
+
registry: undefined
|
|
4444
|
+
};
|
|
4445
|
+
}
|
|
4446
|
+
return {
|
|
4447
|
+
result: { capabilities: serverCapabilities },
|
|
4448
|
+
registry: registryResult.value
|
|
4449
|
+
};
|
|
4450
|
+
};
|
|
3749
4451
|
const createLspServer = (options) => {
|
|
3750
4452
|
const connection = options?.connection ?? (0, vscode_languageserver_node.createConnection)(vscode_languageserver_node.ProposedFeatures.all);
|
|
3751
4453
|
const documents = new vscode_languageserver_node.TextDocuments(vscode_languageserver_textdocument.TextDocument);
|
|
@@ -3771,22 +4473,10 @@ const createLspServer = (options) => {
|
|
|
3771
4473
|
});
|
|
3772
4474
|
return;
|
|
3773
4475
|
}
|
|
3774
|
-
const
|
|
3775
|
-
const entry = ctx.schemaResolver.getSchema(template.schemaName);
|
|
3776
|
-
if (!entry) {
|
|
3777
|
-
return [];
|
|
3778
|
-
}
|
|
3779
|
-
const externalFragments = ctx.documentManager.getExternalFragments(uri, template.schemaName).map((f) => f.definition);
|
|
3780
|
-
return [...computeTemplateDiagnostics({
|
|
3781
|
-
template,
|
|
3782
|
-
schema: entry.schema,
|
|
3783
|
-
tsSource: state.source,
|
|
3784
|
-
externalFragments
|
|
3785
|
-
})];
|
|
3786
|
-
});
|
|
4476
|
+
const diagnostics = collectRawDiagnostics(state, ctx);
|
|
3787
4477
|
connection.sendDiagnostics({
|
|
3788
4478
|
uri,
|
|
3789
|
-
diagnostics:
|
|
4479
|
+
diagnostics: [...diagnostics]
|
|
3790
4480
|
});
|
|
3791
4481
|
};
|
|
3792
4482
|
const publishDiagnosticsForAllOpen = () => {
|
|
@@ -3794,46 +4484,20 @@ const createLspServer = (options) => {
|
|
|
3794
4484
|
publishDiagnosticsForDocument(doc.uri);
|
|
3795
4485
|
}
|
|
3796
4486
|
};
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
return
|
|
3807
|
-
}
|
|
3808
|
-
|
|
3809
|
-
if (registryResult.isErr()) {
|
|
3810
|
-
connection.window.showErrorMessage(`soda-gql LSP: ${registryResult.error.message}`);
|
|
3811
|
-
return { capabilities: {} };
|
|
3812
|
-
}
|
|
3813
|
-
registry = registryResult.value;
|
|
3814
|
-
return { capabilities: {
|
|
3815
|
-
textDocumentSync: vscode_languageserver_node.TextDocumentSyncKind.Full,
|
|
3816
|
-
hoverProvider: true,
|
|
3817
|
-
documentSymbolProvider: true,
|
|
3818
|
-
definitionProvider: true,
|
|
3819
|
-
referencesProvider: true,
|
|
3820
|
-
renameProvider: { prepareProvider: true },
|
|
3821
|
-
documentFormattingProvider: true,
|
|
3822
|
-
completionProvider: { triggerCharacters: [
|
|
3823
|
-
"{",
|
|
3824
|
-
"(",
|
|
3825
|
-
":",
|
|
3826
|
-
"@",
|
|
3827
|
-
"$",
|
|
3828
|
-
" ",
|
|
3829
|
-
"\n",
|
|
3830
|
-
"."
|
|
3831
|
-
] },
|
|
3832
|
-
codeActionProvider: { codeActionKinds: ["refactor.extract"] }
|
|
3833
|
-
} };
|
|
3834
|
-
});
|
|
4487
|
+
let initializeResult;
|
|
4488
|
+
if (options?.initializeParams) {
|
|
4489
|
+
const init = initializeFromParams(options.initializeParams, connection);
|
|
4490
|
+
registry = init.registry;
|
|
4491
|
+
initializeResult = init.result;
|
|
4492
|
+
} else {
|
|
4493
|
+
connection.onInitialize((params) => {
|
|
4494
|
+
const init = initializeFromParams(params, connection);
|
|
4495
|
+
registry = init.registry;
|
|
4496
|
+
return init.result;
|
|
4497
|
+
});
|
|
4498
|
+
}
|
|
3835
4499
|
connection.onInitialized(() => {
|
|
3836
|
-
connection.client.register(vscode_languageserver_node.DidChangeWatchedFilesNotification.type, { watchers: [{ globPattern: "**/*.graphql" }] });
|
|
4500
|
+
connection.client.register(vscode_languageserver_node.DidChangeWatchedFilesNotification.type, { watchers: [{ globPattern: "**/*.graphql" }, { globPattern: "**/soda-gql.config.*" }] });
|
|
3837
4501
|
});
|
|
3838
4502
|
documents.onDidChangeContent((change) => {
|
|
3839
4503
|
if (!registry) {
|
|
@@ -3861,95 +4525,97 @@ const createLspServer = (options) => {
|
|
|
3861
4525
|
});
|
|
3862
4526
|
});
|
|
3863
4527
|
connection.onCompletion((params) => {
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
}
|
|
3867
|
-
const ctx = registry.resolveForUri(params.textDocument.uri);
|
|
3868
|
-
if (!ctx) {
|
|
3869
|
-
return [];
|
|
3870
|
-
}
|
|
3871
|
-
const template = ctx.documentManager.findTemplateAtOffset(params.textDocument.uri, positionToOffset(documents.get(params.textDocument.uri)?.getText() ?? "", params.position));
|
|
3872
|
-
if (!template) {
|
|
4528
|
+
const resolved = resolvePositionContext(registry, documents, params.textDocument.uri, params.position);
|
|
4529
|
+
if (!resolved) {
|
|
3873
4530
|
return [];
|
|
3874
4531
|
}
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
4532
|
+
if (resolved.kind === "fieldTree") {
|
|
4533
|
+
return handleFieldTreeCompletion({
|
|
4534
|
+
fieldTree: resolved.typedTree,
|
|
4535
|
+
schema: resolved.schema,
|
|
4536
|
+
tsSource: resolved.tsSource,
|
|
4537
|
+
tsPosition: resolved.tsPosition,
|
|
4538
|
+
offset: resolved.offset
|
|
4539
|
+
});
|
|
3878
4540
|
}
|
|
3879
|
-
|
|
3880
|
-
if (!doc) {
|
|
4541
|
+
if (!resolved.schemaEntry) {
|
|
3881
4542
|
return [];
|
|
3882
4543
|
}
|
|
3883
|
-
const externalFragments = ctx.documentManager.getExternalFragments(params.textDocument.uri, template.schemaName).map((f) => f.definition);
|
|
4544
|
+
const externalFragments = resolved.ctx.documentManager.getExternalFragments(params.textDocument.uri, resolved.template.schemaName).map((f) => f.definition);
|
|
3884
4545
|
return handleCompletion({
|
|
3885
|
-
template,
|
|
3886
|
-
schema:
|
|
3887
|
-
tsSource:
|
|
3888
|
-
tsPosition:
|
|
3889
|
-
line: params.position.line,
|
|
3890
|
-
character: params.position.character
|
|
3891
|
-
},
|
|
4546
|
+
template: resolved.template,
|
|
4547
|
+
schema: resolved.schemaEntry.schema,
|
|
4548
|
+
tsSource: resolved.tsSource,
|
|
4549
|
+
tsPosition: resolved.tsPosition,
|
|
3892
4550
|
externalFragments
|
|
3893
4551
|
});
|
|
3894
4552
|
});
|
|
3895
4553
|
connection.onHover((params) => {
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
}
|
|
3899
|
-
const ctx = registry.resolveForUri(params.textDocument.uri);
|
|
3900
|
-
if (!ctx) {
|
|
3901
|
-
return null;
|
|
3902
|
-
}
|
|
3903
|
-
const doc = documents.get(params.textDocument.uri);
|
|
3904
|
-
if (!doc) {
|
|
4554
|
+
const resolved = resolvePositionContext(registry, documents, params.textDocument.uri, params.position);
|
|
4555
|
+
if (!resolved) {
|
|
3905
4556
|
return null;
|
|
3906
4557
|
}
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
4558
|
+
if (resolved.kind === "fieldTree") {
|
|
4559
|
+
return handleFieldTreeHover({
|
|
4560
|
+
fieldTree: resolved.typedTree,
|
|
4561
|
+
offset: resolved.offset
|
|
4562
|
+
});
|
|
3910
4563
|
}
|
|
3911
|
-
|
|
3912
|
-
if (!entry) {
|
|
4564
|
+
if (!resolved.schemaEntry) {
|
|
3913
4565
|
return null;
|
|
3914
4566
|
}
|
|
3915
4567
|
return handleHover({
|
|
3916
|
-
template,
|
|
3917
|
-
schema:
|
|
3918
|
-
tsSource:
|
|
3919
|
-
tsPosition:
|
|
3920
|
-
line: params.position.line,
|
|
3921
|
-
character: params.position.character
|
|
3922
|
-
}
|
|
4568
|
+
template: resolved.template,
|
|
4569
|
+
schema: resolved.schemaEntry.schema,
|
|
4570
|
+
tsSource: resolved.tsSource,
|
|
4571
|
+
tsPosition: resolved.tsPosition
|
|
3923
4572
|
});
|
|
3924
4573
|
});
|
|
3925
4574
|
connection.onDefinition(async (params) => {
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
4575
|
+
const resolved = resolvePositionContext(registry, documents, params.textDocument.uri, params.position);
|
|
4576
|
+
if (!resolved) {
|
|
4577
|
+
if (!registry) {
|
|
4578
|
+
return [];
|
|
4579
|
+
}
|
|
4580
|
+
const ctx = registry.resolveForUri(params.textDocument.uri);
|
|
4581
|
+
if (!ctx) {
|
|
4582
|
+
return [];
|
|
4583
|
+
}
|
|
4584
|
+
const doc = documents.get(params.textDocument.uri);
|
|
4585
|
+
if (!doc) {
|
|
4586
|
+
return [];
|
|
4587
|
+
}
|
|
4588
|
+
const offset = positionToOffset(doc.getText(), params.position);
|
|
4589
|
+
const typeNameTemplate = ctx.documentManager.findTemplateByTypeNameOffset(params.textDocument.uri, offset);
|
|
4590
|
+
if (typeNameTemplate?.typeName) {
|
|
4591
|
+
const typeNameEntry = ctx.schemaResolver.getSchema(typeNameTemplate.schemaName);
|
|
4592
|
+
if (typeNameEntry?.files) {
|
|
4593
|
+
return resolveTypeNameToSchemaDefinition(typeNameTemplate.typeName, typeNameEntry.files);
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
3935
4596
|
return [];
|
|
3936
4597
|
}
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4598
|
+
if (resolved.kind === "fieldTree") {
|
|
4599
|
+
if (!resolved.schemaEntry.files) {
|
|
4600
|
+
return [];
|
|
4601
|
+
}
|
|
4602
|
+
return handleFieldTreeDefinition({
|
|
4603
|
+
fieldTree: resolved.typedTree,
|
|
4604
|
+
schema: resolved.schema,
|
|
4605
|
+
tsSource: resolved.tsSource,
|
|
4606
|
+
tsPosition: resolved.tsPosition,
|
|
4607
|
+
offset: resolved.offset,
|
|
4608
|
+
schemaFiles: resolved.schemaEntry.files
|
|
4609
|
+
});
|
|
3940
4610
|
}
|
|
3941
|
-
const externalFragments = ctx.documentManager.getExternalFragments(params.textDocument.uri, template.schemaName);
|
|
3942
|
-
const entry = ctx.schemaResolver.getSchema(template.schemaName);
|
|
4611
|
+
const externalFragments = resolved.ctx.documentManager.getExternalFragments(params.textDocument.uri, resolved.template.schemaName);
|
|
3943
4612
|
return handleDefinition({
|
|
3944
|
-
template,
|
|
3945
|
-
tsSource:
|
|
3946
|
-
tsPosition:
|
|
3947
|
-
line: params.position.line,
|
|
3948
|
-
character: params.position.character
|
|
3949
|
-
},
|
|
4613
|
+
template: resolved.template,
|
|
4614
|
+
tsSource: resolved.tsSource,
|
|
4615
|
+
tsPosition: resolved.tsPosition,
|
|
3950
4616
|
externalFragments,
|
|
3951
|
-
schema:
|
|
3952
|
-
schemaFiles:
|
|
4617
|
+
schema: resolved.schemaEntry?.schema,
|
|
4618
|
+
schemaFiles: resolved.schemaEntry?.files
|
|
3953
4619
|
});
|
|
3954
4620
|
});
|
|
3955
4621
|
connection.onReferences((params) => {
|
|
@@ -4117,11 +4783,18 @@ const createLspServer = (options) => {
|
|
|
4117
4783
|
}
|
|
4118
4784
|
}
|
|
4119
4785
|
}
|
|
4786
|
+
const configChanged = _params.changes.some((change) => /soda-gql\.config\.[cm]?[jt]s$/.test(change.uri) && (change.type === vscode_languageserver_node.FileChangeType.Changed || change.type === vscode_languageserver_node.FileChangeType.Created));
|
|
4787
|
+
if (configChanged) {
|
|
4788
|
+
connection.window.showInformationMessage("soda-gql: config file changed. Restart the language server to apply.");
|
|
4789
|
+
}
|
|
4120
4790
|
});
|
|
4121
4791
|
documents.listen(connection);
|
|
4122
|
-
return {
|
|
4123
|
-
|
|
4124
|
-
|
|
4792
|
+
return {
|
|
4793
|
+
start: () => {
|
|
4794
|
+
connection.listen();
|
|
4795
|
+
},
|
|
4796
|
+
initializeResult
|
|
4797
|
+
};
|
|
4125
4798
|
};
|
|
4126
4799
|
/** Check if SWC is unavailable and show a one-time error notification. */
|
|
4127
4800
|
const checkSwcUnavailable = (swcUnavailable, state, showError) => {
|
|
@@ -4178,6 +4851,24 @@ const positionToOffset = (source, position) => {
|
|
|
4178
4851
|
};
|
|
4179
4852
|
|
|
4180
4853
|
//#endregion
|
|
4854
|
+
Object.defineProperty(exports, '__toESM', {
|
|
4855
|
+
enumerable: true,
|
|
4856
|
+
get: function () {
|
|
4857
|
+
return __toESM;
|
|
4858
|
+
}
|
|
4859
|
+
});
|
|
4860
|
+
Object.defineProperty(exports, 'collectRawDiagnostics', {
|
|
4861
|
+
enumerable: true,
|
|
4862
|
+
get: function () {
|
|
4863
|
+
return collectRawDiagnostics;
|
|
4864
|
+
}
|
|
4865
|
+
});
|
|
4866
|
+
Object.defineProperty(exports, 'createConfigRegistry', {
|
|
4867
|
+
enumerable: true,
|
|
4868
|
+
get: function () {
|
|
4869
|
+
return createConfigRegistry;
|
|
4870
|
+
}
|
|
4871
|
+
});
|
|
4181
4872
|
Object.defineProperty(exports, 'createDocumentManager', {
|
|
4182
4873
|
enumerable: true,
|
|
4183
4874
|
get: function () {
|
|
@@ -4214,4 +4905,4 @@ Object.defineProperty(exports, 'preprocessFragmentArgs', {
|
|
|
4214
4905
|
return preprocessFragmentArgs;
|
|
4215
4906
|
}
|
|
4216
4907
|
});
|
|
4217
|
-
//# sourceMappingURL=server-
|
|
4908
|
+
//# sourceMappingURL=server-C1MSX490.cjs.map
|