@sanity/prettier-plugin-groq 0.0.1 → 0.0.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/dist/embed.cjs ADDED
@@ -0,0 +1,513 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/embed.ts
21
+ var embed_exports = {};
22
+ __export(embed_exports, {
23
+ default: () => embed_default,
24
+ embed: () => embed,
25
+ parsers: () => parsers
26
+ });
27
+ module.exports = __toCommonJS(embed_exports);
28
+ var import_estree = require("prettier/plugins/estree.mjs");
29
+
30
+ // src/index.ts
31
+ var import_prettier = require("prettier");
32
+
33
+ // src/parser.ts
34
+ var import_groq_js = require("groq-js");
35
+ function locStart(_node) {
36
+ return 0;
37
+ }
38
+ function locEnd(_node) {
39
+ return 0;
40
+ }
41
+ var groqParser = {
42
+ parse(text) {
43
+ const trimmed = text.trim();
44
+ if (!trimmed) {
45
+ throw new Error("Empty GROQ query");
46
+ }
47
+ const node = (0, import_groq_js.parse)(trimmed);
48
+ return {
49
+ type: "groq-root",
50
+ node
51
+ };
52
+ },
53
+ astFormat: "groq-ast",
54
+ locStart,
55
+ locEnd
56
+ };
57
+
58
+ // src/printer.ts
59
+ function createPrintNode(builders) {
60
+ const { group, indent, join, line, softline } = builders;
61
+ return function printNode(node, print, path) {
62
+ switch (node.type) {
63
+ case "Everything":
64
+ return "*";
65
+ case "This":
66
+ return "@";
67
+ case "Parent":
68
+ return "^";
69
+ case "Value":
70
+ return printValue(node.value);
71
+ case "Parameter":
72
+ return `$${node.name}`;
73
+ case "AccessAttribute":
74
+ if (node.base) {
75
+ const base = path.call((p) => printNode(p.node, print, p), "base");
76
+ if (isDerefNode(node.base)) {
77
+ return [base, node.name];
78
+ }
79
+ return [base, ".", node.name];
80
+ }
81
+ return node.name;
82
+ case "AccessElement":
83
+ return [
84
+ path.call((p) => printNode(p.node, print, p), "base"),
85
+ "[",
86
+ path.call((p) => printNode(p.node, print, p), "index"),
87
+ "]"
88
+ ];
89
+ case "Filter":
90
+ return [
91
+ path.call((p) => printNode(p.node, print, p), "base"),
92
+ group([
93
+ "[",
94
+ indent([softline, path.call((p) => printNode(p.node, print, p), "expr")]),
95
+ softline,
96
+ "]"
97
+ ])
98
+ ];
99
+ case "Slice":
100
+ return [
101
+ path.call((p) => printNode(p.node, print, p), "base"),
102
+ "[",
103
+ String(node.left),
104
+ node.isInclusive ? ".." : "...",
105
+ String(node.right),
106
+ "]"
107
+ ];
108
+ case "Map": {
109
+ const base = path.call((p) => printNode(p.node, print, p), "base");
110
+ const expr = path.call((p) => printNode(p.node, print, p), "expr");
111
+ if (node.base.type === "ArrayCoerce" && isDerefOfThis(node.expr)) {
112
+ return [base, expr];
113
+ }
114
+ return [base, " ", expr];
115
+ }
116
+ case "Projection": {
117
+ const base = path.call((p) => printNode(p.node, print, p), "base");
118
+ const expr = path.call((p) => printNode(p.node, print, p), "expr");
119
+ if (node.base.type === "This") {
120
+ return expr;
121
+ }
122
+ if (node.base.type === "Deref") {
123
+ return [base, expr];
124
+ }
125
+ return [base, " ", expr];
126
+ }
127
+ case "Object": {
128
+ if (node.attributes.length === 0) {
129
+ return "{}";
130
+ }
131
+ const attrs = path.map((p) => printNode(p.node, print, p), "attributes");
132
+ return group(["{", indent([line, join([",", line], attrs)]), line, "}"]);
133
+ }
134
+ case "ObjectAttributeValue": {
135
+ const value = path.call((p) => printNode(p.node, print, p), "value");
136
+ const leadingAttr = getLeadingAttribute(node.value);
137
+ if (leadingAttr === node.name) {
138
+ return value;
139
+ }
140
+ return ['"', escapeString(node.name), '": ', value];
141
+ }
142
+ case "ObjectSplat":
143
+ if (node.value) {
144
+ return ["...", path.call((p) => printNode(p.node, print, p), "value")];
145
+ }
146
+ return "...";
147
+ case "ObjectConditionalSplat":
148
+ return [
149
+ "...",
150
+ path.call((p) => printNode(p.node, print, p), "condition"),
151
+ " => ",
152
+ path.call((p) => printNode(p.node, print, p), "value")
153
+ ];
154
+ case "Array": {
155
+ if (node.elements.length === 0) {
156
+ return "[]";
157
+ }
158
+ const elems = path.map((p) => printNode(p.node, print, p), "elements");
159
+ return group(["[", indent([softline, join([",", line], elems)]), softline, "]"]);
160
+ }
161
+ case "ArrayElement":
162
+ if (node.isSplat) {
163
+ return ["...", path.call((p) => printNode(p.node, print, p), "value")];
164
+ }
165
+ return path.call((p) => printNode(p.node, print, p), "value");
166
+ case "Tuple": {
167
+ const members = path.map((p) => printNode(p.node, print, p), "members");
168
+ return ["(", join([",", " "], members), ")"];
169
+ }
170
+ case "Range":
171
+ return [
172
+ path.call((p) => printNode(p.node, print, p), "left"),
173
+ node.isInclusive ? ".." : "...",
174
+ path.call((p) => printNode(p.node, print, p), "right")
175
+ ];
176
+ case "And":
177
+ return group([
178
+ path.call((p) => printNode(p.node, print, p), "left"),
179
+ indent([line, "&& ", path.call((p) => printNode(p.node, print, p), "right")])
180
+ ]);
181
+ case "Or":
182
+ return group([
183
+ path.call((p) => printNode(p.node, print, p), "left"),
184
+ indent([line, "|| ", path.call((p) => printNode(p.node, print, p), "right")])
185
+ ]);
186
+ case "Not":
187
+ return ["!", path.call((p) => printNode(p.node, print, p), "base")];
188
+ case "Neg":
189
+ return ["-", path.call((p) => printNode(p.node, print, p), "base")];
190
+ case "Pos":
191
+ return ["+", path.call((p) => printNode(p.node, print, p), "base")];
192
+ case "OpCall": {
193
+ const left = path.call((p) => printNode(p.node, print, p), "left");
194
+ const right = path.call((p) => printNode(p.node, print, p), "right");
195
+ return [left, ` ${node.op} `, right];
196
+ }
197
+ case "FuncCall": {
198
+ const name = node.namespace && node.namespace !== "global" ? `${node.namespace}::${node.name}` : node.name;
199
+ if (node.args.length === 0) {
200
+ return `${name}()`;
201
+ }
202
+ const args = path.map((p) => printNode(p.node, print, p), "args");
203
+ return group([name, "(", indent([softline, join([",", line], args)]), softline, ")"]);
204
+ }
205
+ case "PipeFuncCall": {
206
+ const base = path.call((p) => printNode(p.node, print, p), "base");
207
+ const name = node.namespace && node.namespace !== "global" ? `${node.namespace}::${node.name}` : node.name;
208
+ const args = path.map((p) => printNode(p.node, print, p), "args");
209
+ const argsDoc = args.length === 0 ? "" : group(["(", join([", "], args), ")"]);
210
+ return group([base, indent([line, "| ", name, argsDoc])]);
211
+ }
212
+ case "Deref": {
213
+ if (node.base.type === "This") {
214
+ return "->";
215
+ }
216
+ const base = path.call((p) => printNode(p.node, print, p), "base");
217
+ return [base, "->"];
218
+ }
219
+ case "Asc":
220
+ return [path.call((p) => printNode(p.node, print, p), "base"), " asc"];
221
+ case "Desc":
222
+ return [path.call((p) => printNode(p.node, print, p), "base"), " desc"];
223
+ case "Group":
224
+ return ["(", path.call((p) => printNode(p.node, print, p), "base"), ")"];
225
+ case "ArrayCoerce":
226
+ return [path.call((p) => printNode(p.node, print, p), "base"), "[]"];
227
+ case "FlatMap":
228
+ return [
229
+ path.call((p) => printNode(p.node, print, p), "base"),
230
+ "[]",
231
+ path.call((p) => printNode(p.node, print, p), "expr")
232
+ ];
233
+ case "Select": {
234
+ const alternatives = path.map((p) => printNode(p.node, print, p), "alternatives");
235
+ const fallback = node.fallback ? path.call((p) => printNode(p.node, print, p), "fallback") : null;
236
+ const allArgs = fallback ? [...alternatives, fallback] : alternatives;
237
+ return group(["select(", indent([softline, join([",", line], allArgs)]), softline, ")"]);
238
+ }
239
+ case "SelectAlternative":
240
+ return [
241
+ path.call((p) => printNode(p.node, print, p), "condition"),
242
+ " => ",
243
+ path.call((p) => printNode(p.node, print, p), "value")
244
+ ];
245
+ case "InRange":
246
+ return [
247
+ path.call((p) => printNode(p.node, print, p), "base"),
248
+ " in ",
249
+ path.call((p) => printNode(p.node, print, p), "range")
250
+ ];
251
+ case "Context":
252
+ return path.call((p) => printNode(p.node, print, p), "base");
253
+ default:
254
+ throw new Error(`Unknown GROQ node type: ${node.type}`);
255
+ }
256
+ };
257
+ }
258
+ function printValue(value) {
259
+ if (value === null) {
260
+ return "null";
261
+ }
262
+ if (typeof value === "string") {
263
+ return `"${escapeString(value)}"`;
264
+ }
265
+ if (typeof value === "number") {
266
+ return formatNumber(value);
267
+ }
268
+ if (typeof value === "boolean") {
269
+ return value ? "true" : "false";
270
+ }
271
+ return String(value);
272
+ }
273
+ function escapeString(s) {
274
+ let result = "";
275
+ for (const ch of s) {
276
+ switch (ch) {
277
+ case '"':
278
+ result += '\\"';
279
+ break;
280
+ case "\\":
281
+ result += "\\\\";
282
+ break;
283
+ case "\n":
284
+ result += "\\n";
285
+ break;
286
+ case "\r":
287
+ result += "\\r";
288
+ break;
289
+ case " ":
290
+ result += "\\t";
291
+ break;
292
+ default:
293
+ if (ch.charCodeAt(0) < 32) {
294
+ result += `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`;
295
+ } else {
296
+ result += ch;
297
+ }
298
+ }
299
+ }
300
+ return result;
301
+ }
302
+ function formatNumber(value) {
303
+ return String(value);
304
+ }
305
+ function isDerefNode(node) {
306
+ return node.type === "Deref";
307
+ }
308
+ function isDerefOfThis(node) {
309
+ if (node.type === "Deref" && node.base.type === "This") {
310
+ return true;
311
+ }
312
+ if (node.type === "Projection" && node.base.type === "Deref" && node.base.base.type === "This") {
313
+ return true;
314
+ }
315
+ return false;
316
+ }
317
+ function getLeadingAttribute(node) {
318
+ switch (node.type) {
319
+ case "AccessAttribute":
320
+ if (!node.base) {
321
+ return node.name;
322
+ }
323
+ return null;
324
+ case "Deref":
325
+ return getLeadingAttribute(node.base);
326
+ case "Projection":
327
+ return getLeadingAttribute(node.base);
328
+ case "ArrayCoerce":
329
+ return getLeadingAttribute(node.base);
330
+ case "Map":
331
+ return getLeadingAttribute(node.base);
332
+ default:
333
+ return null;
334
+ }
335
+ }
336
+ function createGroqPrinter(builders) {
337
+ const printNode = createPrintNode(builders);
338
+ return {
339
+ print(path, options, print) {
340
+ const node = path.node;
341
+ if ("type" in node && node.type === "groq-root") {
342
+ return path.call(
343
+ (p) => printNode(p.node, print, p),
344
+ "node"
345
+ );
346
+ }
347
+ return printNode(node, print, path);
348
+ }
349
+ };
350
+ }
351
+
352
+ // src/wasm-printer.ts
353
+ var wasmAvailable = false;
354
+ var wasmModule = null;
355
+ function createWasmGroqPrinter(builders) {
356
+ const tsPrinter = createGroqPrinter(builders);
357
+ return {
358
+ print(path, options, print) {
359
+ if (wasmAvailable && wasmModule && options.originalText) {
360
+ try {
361
+ const width = options.printWidth || 80;
362
+ const formatted = wasmModule.format(options.originalText, { width });
363
+ return formatted;
364
+ } catch {
365
+ }
366
+ }
367
+ return tsPrinter.print(path, options, print);
368
+ }
369
+ };
370
+ }
371
+
372
+ // src/index.ts
373
+ var parsers = {
374
+ groq: groqParser
375
+ };
376
+ var printers = {
377
+ "groq-ast": createWasmGroqPrinter(import_prettier.doc.builders)
378
+ };
379
+
380
+ // src/embed.ts
381
+ var defaultEstreePrinter = import_estree.printers.estree;
382
+ var defaultEmbed = defaultEstreePrinter.embed;
383
+ var GROQ_IDENTIFIERS = ["groq", "defineQuery"];
384
+ function getTagName(node) {
385
+ if (node.type !== "TaggedTemplateExpression") return null;
386
+ const tag = node.tag;
387
+ if (!tag) return null;
388
+ if (tag.type === "Identifier" && typeof tag.name === "string") {
389
+ return tag.name;
390
+ }
391
+ if (tag.type === "MemberExpression" && tag.object?.type === "Identifier") {
392
+ return tag.object.name ?? null;
393
+ }
394
+ return null;
395
+ }
396
+ function getCallName(node) {
397
+ if (node.type !== "CallExpression") return null;
398
+ const callee = node.callee;
399
+ if (!callee) return null;
400
+ if (callee.type === "Identifier" && typeof callee.name === "string") {
401
+ return callee.name;
402
+ }
403
+ return null;
404
+ }
405
+ function isGroqTaggedTemplate(node) {
406
+ const tagName = getTagName(node);
407
+ return tagName !== null && GROQ_IDENTIFIERS.includes(tagName);
408
+ }
409
+ function isGroqFunctionCall(node) {
410
+ const callName = getCallName(node);
411
+ return callName !== null && GROQ_IDENTIFIERS.includes(callName);
412
+ }
413
+ function extractFromTemplate(node) {
414
+ const quasi = node.quasi;
415
+ if (!quasi || !quasi.quasis) return null;
416
+ const quasis = quasi.quasis;
417
+ const expressions = quasi.expressions || [];
418
+ if (expressions.length === 0) {
419
+ const first = quasis[0];
420
+ if (!first) return null;
421
+ return first.value?.cooked ?? first.value?.raw ?? null;
422
+ }
423
+ let result = "";
424
+ for (let i = 0; i < quasis.length; i++) {
425
+ const q = quasis[i];
426
+ if (!q) continue;
427
+ result += q.value?.cooked ?? q.value?.raw ?? "";
428
+ if (i < expressions.length) {
429
+ result += `$__expr${i}__`;
430
+ }
431
+ }
432
+ return result;
433
+ }
434
+ function extractFromFunctionCall(node) {
435
+ const args = node.arguments;
436
+ if (!args || args.length === 0) return null;
437
+ const firstArg = args[0];
438
+ if (!firstArg) return null;
439
+ if ((firstArg.type === "Literal" || firstArg.type === "StringLiteral") && typeof firstArg.value === "string") {
440
+ return firstArg.value;
441
+ }
442
+ if (firstArg.type === "TemplateLiteral") {
443
+ const quasis = firstArg.quasis;
444
+ const expressions = firstArg.expressions || [];
445
+ if (!quasis || quasis.length === 0) return null;
446
+ if (expressions.length === 0) {
447
+ const first = quasis[0];
448
+ return first?.value?.cooked ?? first?.value?.raw ?? null;
449
+ }
450
+ let result = "";
451
+ for (let i = 0; i < quasis.length; i++) {
452
+ const q = quasis[i];
453
+ if (!q) continue;
454
+ result += q.value?.cooked ?? q.value?.raw ?? "";
455
+ if (i < expressions.length) {
456
+ result += `$__expr${i}__`;
457
+ }
458
+ }
459
+ return result;
460
+ }
461
+ return null;
462
+ }
463
+ function embed(path, options) {
464
+ const node = path.node;
465
+ if (isGroqTaggedTemplate(node)) {
466
+ const content = extractFromTemplate(node);
467
+ if (!content) {
468
+ return defaultEmbed ? defaultEmbed(path, options) : void 0;
469
+ }
470
+ return async (textToDoc, print) => {
471
+ try {
472
+ const formattedGroq = await textToDoc(content.trim(), { parser: "groq" });
473
+ const tag = print("tag");
474
+ return [tag, "`", formattedGroq, "`"];
475
+ } catch {
476
+ return void 0;
477
+ }
478
+ };
479
+ }
480
+ if (isGroqFunctionCall(node)) {
481
+ const content = extractFromFunctionCall(node);
482
+ if (!content) {
483
+ return defaultEmbed ? defaultEmbed(path, options) : void 0;
484
+ }
485
+ return async (textToDoc, print) => {
486
+ try {
487
+ const formattedGroq = await textToDoc(content.trim(), { parser: "groq" });
488
+ const callee = print("callee");
489
+ return [callee, "(`", formattedGroq, "`)"];
490
+ } catch {
491
+ return void 0;
492
+ }
493
+ };
494
+ }
495
+ return defaultEmbed ? defaultEmbed(path, options) : void 0;
496
+ }
497
+ var estreePrinter = {
498
+ ...defaultEstreePrinter,
499
+ embed
500
+ };
501
+ var embedPlugin = {
502
+ parsers,
503
+ printers: {
504
+ estree: estreePrinter
505
+ }
506
+ };
507
+ var embed_default = embedPlugin;
508
+ // Annotate the CommonJS export names for ESM import in node:
509
+ 0 && (module.exports = {
510
+ embed,
511
+ parsers
512
+ });
513
+ //# sourceMappingURL=embed.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/embed.ts","../src/index.ts","../src/parser.ts","../src/printer.ts","../src/wasm-printer.ts"],"sourcesContent":["/**\n * Embedded GROQ support for JavaScript/TypeScript files.\n *\n * This module provides an estree printer with an embed function that formats\n * GROQ queries inside:\n * - Tagged template literals: groq`...`, defineQuery`...`\n * - Function calls: defineQuery(\"...\")\n *\n * Usage in .prettierrc:\n * ```json\n * {\n * \"plugins\": [\"prettier-plugin-groq\", \"prettier-plugin-groq/embed\"]\n * }\n * ```\n */\n\nimport type { AstPath, Doc, Options, Plugin, Printer } from 'prettier'\n// @ts-expect-error - Prettier internal module\nimport { printers as estreePrinters } from 'prettier/plugins/estree.mjs'\nimport { parsers } from './index.js'\n\n// Get the default estree printer to wrap\nconst defaultEstreePrinter = estreePrinters.estree as Printer\nconst defaultEmbed = defaultEstreePrinter.embed\n\n// Tags and function names that indicate GROQ content\nconst GROQ_IDENTIFIERS = ['groq', 'defineQuery']\n\n/**\n * Get the tag name from a TaggedTemplateExpression\n */\nfunction getTagName(node: EstreeLikeNode): string | null {\n if (node.type !== 'TaggedTemplateExpression') return null\n\n const tag = node.tag\n if (!tag) return null\n\n // groq`...`\n if (tag.type === 'Identifier' && typeof tag.name === 'string') {\n return tag.name\n }\n\n // groq.experimental`...` - get the object name\n if (tag.type === 'MemberExpression' && tag.object?.type === 'Identifier') {\n return tag.object.name ?? null\n }\n\n return null\n}\n\n/**\n * Get the function name from a CallExpression\n */\nfunction getCallName(node: EstreeLikeNode): string | null {\n if (node.type !== 'CallExpression') return null\n\n const callee = node.callee\n if (!callee) return null\n\n // defineQuery(\"...\")\n if (callee.type === 'Identifier' && typeof callee.name === 'string') {\n return callee.name\n }\n\n return null\n}\n\n/**\n * Check if a node is a GROQ tagged template literal\n */\nfunction isGroqTaggedTemplate(node: EstreeLikeNode): boolean {\n const tagName = getTagName(node)\n return tagName !== null && GROQ_IDENTIFIERS.includes(tagName)\n}\n\n/**\n * Check if a node is a GROQ function call like defineQuery(\"...\")\n */\nfunction isGroqFunctionCall(node: EstreeLikeNode): boolean {\n const callName = getCallName(node)\n return callName !== null && GROQ_IDENTIFIERS.includes(callName)\n}\n\n/**\n * Extract GROQ content from a tagged template literal\n */\nfunction extractFromTemplate(node: EstreeLikeNode): string | null {\n const quasi = node.quasi\n if (!quasi || !quasi.quasis) return null\n\n const quasis = quasi.quasis\n const expressions = quasi.expressions || []\n\n // Simple case: no expressions\n if (expressions.length === 0) {\n const first = quasis[0]\n if (!first) return null\n return first.value?.cooked ?? first.value?.raw ?? null\n }\n\n // Build string with placeholders for expressions\n let result = ''\n for (let i = 0; i < quasis.length; i++) {\n const q = quasis[i]\n if (!q) continue\n result += q.value?.cooked ?? q.value?.raw ?? ''\n if (i < expressions.length) {\n // Use a GROQ parameter placeholder that will parse correctly\n result += `$__expr${i}__`\n }\n }\n\n return result\n}\n\n/**\n * Extract GROQ content from a function call like defineQuery(\"...\")\n */\nfunction extractFromFunctionCall(node: EstreeLikeNode): string | null {\n const args = node.arguments\n if (!args || args.length === 0) return null\n\n const firstArg = args[0]\n if (!firstArg) return null\n\n // String literal: defineQuery(\"*[_type == 'post']\")\n // Handle both ESTree (Literal) and Babel (StringLiteral) AST types\n if (\n (firstArg.type === 'Literal' || firstArg.type === 'StringLiteral') &&\n typeof firstArg.value === 'string'\n ) {\n return firstArg.value\n }\n\n // Template literal: defineQuery(`*[_type == 'post']`)\n if (firstArg.type === 'TemplateLiteral') {\n const quasis = firstArg.quasis\n const expressions = firstArg.expressions || []\n\n if (!quasis || quasis.length === 0) return null\n\n if (expressions.length === 0) {\n const first = quasis[0]\n return first?.value?.cooked ?? first?.value?.raw ?? null\n }\n\n // Build string with placeholders\n let result = ''\n for (let i = 0; i < quasis.length; i++) {\n const q = quasis[i]\n if (!q) continue\n result += q.value?.cooked ?? q.value?.raw ?? ''\n if (i < expressions.length) {\n result += `$__expr${i}__`\n }\n }\n return result\n }\n\n return null\n}\n\n// Minimal type for AST nodes we care about\ninterface EstreeLikeNode {\n type: string\n tag?: EstreeLikeNode\n callee?: EstreeLikeNode\n object?: EstreeLikeNode\n name?: string\n quasi?: {\n quasis?: {\n value?: { cooked?: string | null; raw?: string }\n }[]\n expressions?: unknown[]\n }\n arguments?: {\n type: string\n value?: unknown\n quasis?: {\n value?: { cooked?: string | null; raw?: string }\n }[]\n expressions?: unknown[]\n }[]\n}\n\ntype EmbedFn = (\n textToDoc: (text: string, options: Options) => Promise<Doc>,\n print: (selector?: string | number | (string | number)[] | AstPath) => Doc,\n path: AstPath,\n options: Options\n) => Promise<Doc | undefined> | Doc | undefined\n\n/**\n * The embed function for estree that handles GROQ\n */\nfunction embed(path: AstPath<EstreeLikeNode>, options: Options): EmbedFn | undefined {\n const node = path.node\n\n // Handle tagged template literals: groq`...`\n if (isGroqTaggedTemplate(node)) {\n const content = extractFromTemplate(node)\n if (!content) {\n // Fall back to default embed behavior\n return defaultEmbed ? (defaultEmbed(path, options) as EmbedFn | undefined) : undefined\n }\n\n return async (textToDoc, print): Promise<Doc | undefined> => {\n try {\n // Format the GROQ content\n const formattedGroq = await textToDoc(content.trim(), { parser: 'groq' })\n\n // Get the tag printed normally\n const tag = print('tag')\n\n // Return the tag followed by formatted template literal\n return [tag, '`', formattedGroq, '`']\n } catch {\n // If GROQ formatting fails, return undefined to use default printing\n return undefined\n }\n }\n }\n\n // Handle function calls: defineQuery(\"...\")\n if (isGroqFunctionCall(node)) {\n const content = extractFromFunctionCall(node)\n if (!content) {\n // Fall back to default embed behavior\n return defaultEmbed ? (defaultEmbed(path, options) as EmbedFn | undefined) : undefined\n }\n\n return async (textToDoc, print): Promise<Doc | undefined> => {\n try {\n // Format the GROQ content\n const formattedGroq = await textToDoc(content.trim(), { parser: 'groq' })\n\n // Get the function name printed normally\n const callee = print('callee')\n\n // Return the function call with formatted GROQ\n return [callee, '(`', formattedGroq, '`)']\n } catch {\n // If GROQ formatting fails, return undefined to use default printing\n return undefined\n }\n }\n }\n\n // Fall back to default embed behavior for all other nodes\n return defaultEmbed ? (defaultEmbed(path, options) as EmbedFn | undefined) : undefined\n}\n\n/**\n * The estree printer that wraps the default estree printer with GROQ embed support\n */\nconst estreePrinter: Printer = {\n ...defaultEstreePrinter,\n embed: embed as Printer['embed'],\n}\n\n/**\n * The embed plugin exports an estree printer with embed support.\n * Load this alongside the main prettier-plugin-groq for embedded GROQ in JS/TS.\n */\nconst embedPlugin: Plugin = {\n parsers,\n printers: {\n estree: estreePrinter,\n },\n}\n\nexport default embedPlugin\nexport { embed, parsers }\n","import type { Plugin, SupportLanguage, Parser, Printer } from 'prettier'\nimport { doc } from 'prettier'\nimport { groqParser, type GroqAst } from './parser.js'\nimport {\n createWasmGroqPrinter,\n initWasmFormatter,\n isWasmFormatterAvailable,\n} from './wasm-printer.js'\n\nconst languages: SupportLanguage[] = [\n {\n name: 'GROQ',\n parsers: ['groq'],\n extensions: ['.groq'],\n vscodeLanguageIds: ['groq'],\n },\n]\n\nconst parsers: Record<string, Parser<GroqAst>> = {\n groq: groqParser,\n}\n\nconst printers: Record<string, Printer> = {\n 'groq-ast': createWasmGroqPrinter(doc.builders),\n}\n\nconst plugin: Plugin = {\n languages,\n parsers,\n printers,\n}\n\nexport default plugin\nexport { languages, parsers, printers, initWasmFormatter, isWasmFormatterAvailable }\n\n// Re-export TS printer for direct use\nexport { createGroqPrinter } from './printer.js'\n","import { parse as groqParse } from 'groq-js'\nimport type { Parser } from 'prettier'\nimport type { ExprNode } from 'groq-js'\n\nexport interface GroqAst {\n type: 'groq-root'\n node: ExprNode\n}\n\nfunction locStart(_node: GroqAst): number {\n // groq-js doesn't provide location info, so we return 0\n return 0\n}\n\nfunction locEnd(_node: GroqAst): number {\n // groq-js doesn't provide location info, so we return 0\n return 0\n}\n\nexport const groqParser: Parser<GroqAst> = {\n parse(text: string): GroqAst {\n const trimmed = text.trim()\n if (!trimmed) {\n throw new Error('Empty GROQ query')\n }\n const node = groqParse(trimmed)\n return {\n type: 'groq-root',\n node,\n }\n },\n astFormat: 'groq-ast',\n locStart,\n locEnd,\n}\n","import type { AstPath, Doc, Printer, doc } from 'prettier'\nimport type { ExprNode } from 'groq-js'\nimport type { GroqAst } from './parser.js'\n\ntype Builders = typeof doc.builders\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrintFn = (path: AstPath<any>) => Doc\n\n// Note: groq-js TypeScript types are incomplete - many node types exist at runtime\n// but aren't in the type definitions (ObjectSplat, Range, SelectAlternative, etc.)\n// We use 'any' here to handle all runtime node types correctly.\nfunction createPrintNode(builders: Builders) {\n const { group, indent, join, line, softline } = builders\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function printNode(node: any, print: PrintFn, path: AstPath<any>): Doc {\n switch (node.type) {\n case 'Everything':\n return '*'\n\n case 'This':\n return '@'\n\n case 'Parent':\n return '^'\n\n case 'Value':\n return printValue(node.value)\n\n case 'Parameter':\n return `$${node.name}`\n\n case 'AccessAttribute':\n if (node.base) {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n // Don't add dot after dereference\n if (isDerefNode(node.base)) {\n return [base, node.name]\n }\n return [base, '.', node.name]\n }\n return node.name\n\n case 'AccessElement':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[',\n path.call((p) => printNode(p.node, print, p), 'index'),\n ']',\n ]\n\n case 'Filter':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n group([\n '[',\n indent([softline, path.call((p) => printNode(p.node, print, p), 'expr')]),\n softline,\n ']',\n ]),\n ]\n\n case 'Slice':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[',\n String(node.left),\n node.isInclusive ? '..' : '...',\n String(node.right),\n ']',\n ]\n\n case 'Map': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const expr = path.call((p) => printNode(p.node, print, p), 'expr')\n // Special case: when base is ArrayCoerce and expr starts with Deref(This),\n // collapse to the common `field[]->{ ... }` notation instead of `field[] @->{ ... }`\n if (node.base.type === 'ArrayCoerce' && isDerefOfThis(node.expr)) {\n // No space needed - the expr will start with ->\n return [base, expr]\n }\n return [base, ' ', expr]\n }\n\n case 'Projection': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const expr = path.call((p) => printNode(p.node, print, p), 'expr')\n // If base is This (@), omit it\n if (node.base.type === 'This') {\n return expr\n }\n // No space after dereference (author->{ name } not author-> { name })\n if (node.base.type === 'Deref') {\n return [base, expr]\n }\n return [base, ' ', expr]\n }\n\n case 'Object': {\n if (node.attributes.length === 0) {\n return '{}'\n }\n const attrs = path.map((p) => printNode(p.node, print, p), 'attributes')\n return group(['{', indent([line, join([',', line], attrs)]), line, '}'])\n }\n\n case 'ObjectAttributeValue': {\n const value = path.call((p) => printNode(p.node, print, p), 'value')\n // Check if we can use shorthand (omit the key entirely)\n // Shorthand is valid when the leading attribute name matches the key\n // e.g., { title } for { \"title\": title }\n // e.g., { author->{ name } } for { \"author\": author->{ name } }\n // e.g., { categories[]->{ title } } for { \"categories\": categories[]->{ title } }\n const leadingAttr = getLeadingAttribute(node.value)\n if (leadingAttr === node.name) {\n return value\n }\n // For all other cases, we MUST quote the key in GROQ\n // e.g., { \"slug\": slug.current } not { slug: slug.current }\n return ['\"', escapeString(node.name), '\": ', value]\n }\n\n case 'ObjectSplat':\n if (node.value) {\n return ['...', path.call((p) => printNode(p.node, print, p), 'value')]\n }\n return '...'\n\n case 'ObjectConditionalSplat':\n return [\n '...',\n path.call((p) => printNode(p.node, print, p), 'condition'),\n ' => ',\n path.call((p) => printNode(p.node, print, p), 'value'),\n ]\n\n case 'Array': {\n if (node.elements.length === 0) {\n return '[]'\n }\n const elems = path.map((p) => printNode(p.node, print, p), 'elements')\n return group(['[', indent([softline, join([',', line], elems)]), softline, ']'])\n }\n\n case 'ArrayElement':\n if (node.isSplat) {\n return ['...', path.call((p) => printNode(p.node, print, p), 'value')]\n }\n return path.call((p) => printNode(p.node, print, p), 'value')\n\n case 'Tuple': {\n const members = path.map((p) => printNode(p.node, print, p), 'members')\n return ['(', join([',', ' '], members), ')']\n }\n\n case 'Range':\n return [\n path.call((p) => printNode(p.node, print, p), 'left'),\n node.isInclusive ? '..' : '...',\n path.call((p) => printNode(p.node, print, p), 'right'),\n ]\n\n case 'And':\n return group([\n path.call((p) => printNode(p.node, print, p), 'left'),\n indent([line, '&& ', path.call((p) => printNode(p.node, print, p), 'right')]),\n ])\n\n case 'Or':\n return group([\n path.call((p) => printNode(p.node, print, p), 'left'),\n indent([line, '|| ', path.call((p) => printNode(p.node, print, p), 'right')]),\n ])\n\n case 'Not':\n return ['!', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'Neg':\n return ['-', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'Pos':\n return ['+', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'OpCall': {\n const left = path.call((p) => printNode(p.node, print, p), 'left')\n const right = path.call((p) => printNode(p.node, print, p), 'right')\n return [left, ` ${node.op} `, right]\n }\n\n case 'FuncCall': {\n const name =\n node.namespace && node.namespace !== 'global'\n ? `${node.namespace}::${node.name}`\n : node.name\n if (node.args.length === 0) {\n return `${name}()`\n }\n const args = path.map((p) => printNode(p.node, print, p), 'args')\n return group([name, '(', indent([softline, join([',', line], args)]), softline, ')'])\n }\n\n case 'PipeFuncCall': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const name =\n node.namespace && node.namespace !== 'global'\n ? `${node.namespace}::${node.name}`\n : node.name\n const args = path.map((p) => printNode(p.node, print, p), 'args')\n const argsDoc = args.length === 0 ? '' : group(['(', join([', '], args), ')'])\n return group([base, indent([line, '| ', name, argsDoc])])\n }\n\n case 'Deref': {\n // When base is This (@), omit it - this is the implicit dereference in array traversals\n // e.g., categories[]->{ title } should not become categories[] @->{ title }\n if (node.base.type === 'This') {\n return '->'\n }\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n return [base, '->']\n }\n\n case 'Asc':\n return [path.call((p) => printNode(p.node, print, p), 'base'), ' asc']\n\n case 'Desc':\n return [path.call((p) => printNode(p.node, print, p), 'base'), ' desc']\n\n case 'Group':\n return ['(', path.call((p) => printNode(p.node, print, p), 'base'), ')']\n\n case 'ArrayCoerce':\n return [path.call((p) => printNode(p.node, print, p), 'base'), '[]']\n\n case 'FlatMap':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[]',\n path.call((p) => printNode(p.node, print, p), 'expr'),\n ]\n\n case 'Select': {\n const alternatives = path.map((p) => printNode(p.node, print, p), 'alternatives')\n const fallback = node.fallback\n ? path.call((p) => printNode(p.node, print, p), 'fallback')\n : null\n const allArgs = fallback ? [...alternatives, fallback] : alternatives\n return group(['select(', indent([softline, join([',', line], allArgs)]), softline, ')'])\n }\n\n case 'SelectAlternative':\n return [\n path.call((p) => printNode(p.node, print, p), 'condition'),\n ' => ',\n path.call((p) => printNode(p.node, print, p), 'value'),\n ]\n\n case 'InRange':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n ' in ',\n path.call((p) => printNode(p.node, print, p), 'range'),\n ]\n\n case 'Context':\n // Internal node, shouldn't appear in user queries\n return path.call((p) => printNode(p.node, print, p), 'base')\n\n default:\n // Fallback for any unhandled node types\n throw new Error(`Unknown GROQ node type: ${(node as { type: string }).type}`)\n }\n }\n}\n\nfunction printValue(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (typeof value === 'string') {\n return `\"${escapeString(value)}\"`\n }\n if (typeof value === 'number') {\n return formatNumber(value)\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n // Arrays and objects shouldn't appear as raw values\n return String(value)\n}\n\nfunction escapeString(s: string): string {\n let result = ''\n for (const ch of s) {\n switch (ch) {\n case '\"':\n result += '\\\\\"'\n break\n case '\\\\':\n result += '\\\\\\\\'\n break\n case '\\n':\n result += '\\\\n'\n break\n case '\\r':\n result += '\\\\r'\n break\n case '\\t':\n result += '\\\\t'\n break\n default:\n if (ch.charCodeAt(0) < 32) {\n result += `\\\\u${ch.charCodeAt(0).toString(16).padStart(4, '0')}`\n } else {\n result += ch\n }\n }\n }\n return result\n}\n\nfunction formatNumber(value: number): string {\n return String(value)\n}\n\nfunction isDerefNode(node: ExprNode): boolean {\n return node.type === 'Deref'\n}\n\n/**\n * Check if a node represents a Deref of This (@->)\n * This handles both direct Deref(This) and Projection with Deref(This) as base\n */\nfunction isDerefOfThis(node: ExprNode): boolean {\n if (node.type === 'Deref' && node.base.type === 'This') {\n return true\n }\n if (node.type === 'Projection' && node.base.type === 'Deref' && node.base.base.type === 'This') {\n return true\n }\n return false\n}\n\n/**\n * Get the attribute name that can be used for shorthand in projections.\n * Returns the name only when shorthand is valid in GROQ.\n *\n * Valid shorthand cases:\n * - { title } → simple attribute access\n * - { author->{ name } } → dereference of attribute\n * - { categories[]->{ title } } → array traversal of attribute\n *\n * Invalid shorthand (returns null):\n * - { slug.current } → dot access (GROQ can't infer key)\n */\nfunction getLeadingAttribute(node: ExprNode): string | null {\n switch (node.type) {\n case 'AccessAttribute':\n // Only valid for shorthand if there's NO base (simple attribute)\n // { title } is valid, but { slug.current } is NOT\n if (!node.base) {\n return node.name\n }\n // Dot access - shorthand not valid\n return null\n case 'Deref':\n // { author->{ name } } - check if base is a simple attribute\n return getLeadingAttribute(node.base)\n case 'Projection':\n // Projection's base determines the leading attribute\n return getLeadingAttribute(node.base)\n case 'ArrayCoerce':\n // { tags[] } - check if base is a simple attribute\n return getLeadingAttribute(node.base)\n case 'Map':\n // Map's base determines the leading attribute\n return getLeadingAttribute(node.base)\n default:\n return null\n }\n}\n\nexport function createGroqPrinter(builders: Builders): Printer<GroqAst | ExprNode> {\n const printNode = createPrintNode(builders)\n\n return {\n print(path, options, print) {\n const node = path.node\n\n // Handle root wrapper\n if ('type' in node && node.type === 'groq-root') {\n return path.call(\n (p) => printNode(p.node as ExprNode, print as PrintFn, p as AstPath<ExprNode>),\n 'node'\n )\n }\n\n // Handle ExprNode\n return printNode(node as ExprNode, print as PrintFn, path as AstPath<ExprNode>)\n },\n }\n}\n","/**\n * WASM-based GROQ printer for Prettier\n *\n * Uses @sanity/groq-wasm for high-performance formatting.\n * Falls back to the TypeScript printer if WASM is not available.\n */\n\nimport type { Printer, doc } from 'prettier'\nimport { createGroqPrinter } from './printer.js'\n\n// WASM module state\nlet wasmAvailable = false\nlet wasmInitialized = false\nlet wasmInitPromise: Promise<boolean> | null = null\n\n// WASM module reference\ntype WasmModule = typeof import('@sanity/groq-wasm')\nlet wasmModule: WasmModule | null = null\n\n/**\n * Initialize the WASM formatter\n *\n * Call this once at application startup for best performance.\n * The plugin will fall back to TypeScript formatting if WASM is not available.\n *\n * @returns Promise that resolves to true if WASM is available\n *\n * @example\n * ```typescript\n * import { initWasmFormatter } from 'prettier-plugin-groq'\n *\n * // Optional: Initialize WASM for better performance\n * await initWasmFormatter()\n * ```\n */\nexport async function initWasmFormatter(): Promise<boolean> {\n if (wasmInitialized) {\n return wasmAvailable\n }\n\n if (wasmInitPromise) {\n return wasmInitPromise\n }\n\n wasmInitPromise = doInit()\n return wasmInitPromise\n}\n\nasync function doInit(): Promise<boolean> {\n try {\n wasmModule = await import('@sanity/groq-wasm')\n await wasmModule.initWasm()\n wasmAvailable = true\n wasmInitialized = true\n return true\n } catch {\n wasmAvailable = false\n wasmInitialized = true\n return false\n }\n}\n\n/**\n * Check if WASM formatter is available\n */\nexport function isWasmFormatterAvailable(): boolean {\n return wasmAvailable\n}\n\n/**\n * Format a GROQ query using WASM\n *\n * @param query - The GROQ query to format\n * @param width - Maximum line width (default: 80)\n * @returns Formatted query string\n * @throws If WASM is not initialized\n */\nexport function formatWithWasm(query: string, width?: number): string {\n if (!wasmAvailable || !wasmModule) {\n throw new Error('WASM formatter not initialized. Call initWasmFormatter() first.')\n }\n return wasmModule.format(query, width !== undefined ? { width } : undefined)\n}\n\n/**\n * Create a WASM-accelerated GROQ printer\n *\n * Uses WASM formatting when available, falls back to TypeScript printer otherwise.\n */\nexport function createWasmGroqPrinter(builders: typeof doc.builders): Printer {\n // Create TS fallback printer\n const tsPrinter = createGroqPrinter(builders)\n\n return {\n print(path, options, print) {\n // If WASM is available and we have the original text, use WASM\n if (wasmAvailable && wasmModule && options.originalText) {\n try {\n const width = options.printWidth || 80\n const formatted = wasmModule.format(options.originalText, { width })\n // Return as a simple string Doc\n return formatted\n } catch {\n // Fall back to TS printer on error\n }\n }\n\n // Fall back to TypeScript printer\n return tsPrinter.print(path, options, print)\n },\n }\n}\n"],"mappings":"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","names":["groqParse","estreePrinters"]}
@@ -0,0 +1,59 @@
1
+ import { Plugin, AstPath, Options, Doc } from 'prettier';
2
+ export { parsers } from './index.cjs';
3
+ import 'groq-js';
4
+
5
+ /**
6
+ * Embedded GROQ support for JavaScript/TypeScript files.
7
+ *
8
+ * This module provides an estree printer with an embed function that formats
9
+ * GROQ queries inside:
10
+ * - Tagged template literals: groq`...`, defineQuery`...`
11
+ * - Function calls: defineQuery("...")
12
+ *
13
+ * Usage in .prettierrc:
14
+ * ```json
15
+ * {
16
+ * "plugins": ["prettier-plugin-groq", "prettier-plugin-groq/embed"]
17
+ * }
18
+ * ```
19
+ */
20
+
21
+ interface EstreeLikeNode {
22
+ type: string;
23
+ tag?: EstreeLikeNode;
24
+ callee?: EstreeLikeNode;
25
+ object?: EstreeLikeNode;
26
+ name?: string;
27
+ quasi?: {
28
+ quasis?: {
29
+ value?: {
30
+ cooked?: string | null;
31
+ raw?: string;
32
+ };
33
+ }[];
34
+ expressions?: unknown[];
35
+ };
36
+ arguments?: {
37
+ type: string;
38
+ value?: unknown;
39
+ quasis?: {
40
+ value?: {
41
+ cooked?: string | null;
42
+ raw?: string;
43
+ };
44
+ }[];
45
+ expressions?: unknown[];
46
+ }[];
47
+ }
48
+ type EmbedFn = (textToDoc: (text: string, options: Options) => Promise<Doc>, print: (selector?: string | number | (string | number)[] | AstPath) => Doc, path: AstPath, options: Options) => Promise<Doc | undefined> | Doc | undefined;
49
+ /**
50
+ * The embed function for estree that handles GROQ
51
+ */
52
+ declare function embed(path: AstPath<EstreeLikeNode>, options: Options): EmbedFn | undefined;
53
+ /**
54
+ * The embed plugin exports an estree printer with embed support.
55
+ * Load this alongside the main prettier-plugin-groq for embedded GROQ in JS/TS.
56
+ */
57
+ declare const embedPlugin: Plugin;
58
+
59
+ export { embedPlugin as default, embed };
package/dist/index.cjs ADDED
@@ -0,0 +1,441 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createGroqPrinter: () => createGroqPrinter,
34
+ default: () => index_default,
35
+ initWasmFormatter: () => initWasmFormatter,
36
+ isWasmFormatterAvailable: () => isWasmFormatterAvailable,
37
+ languages: () => languages,
38
+ parsers: () => parsers,
39
+ printers: () => printers
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+ var import_prettier = require("prettier");
43
+
44
+ // src/parser.ts
45
+ var import_groq_js = require("groq-js");
46
+ function locStart(_node) {
47
+ return 0;
48
+ }
49
+ function locEnd(_node) {
50
+ return 0;
51
+ }
52
+ var groqParser = {
53
+ parse(text) {
54
+ const trimmed = text.trim();
55
+ if (!trimmed) {
56
+ throw new Error("Empty GROQ query");
57
+ }
58
+ const node = (0, import_groq_js.parse)(trimmed);
59
+ return {
60
+ type: "groq-root",
61
+ node
62
+ };
63
+ },
64
+ astFormat: "groq-ast",
65
+ locStart,
66
+ locEnd
67
+ };
68
+
69
+ // src/printer.ts
70
+ function createPrintNode(builders) {
71
+ const { group, indent, join, line, softline } = builders;
72
+ return function printNode(node, print, path) {
73
+ switch (node.type) {
74
+ case "Everything":
75
+ return "*";
76
+ case "This":
77
+ return "@";
78
+ case "Parent":
79
+ return "^";
80
+ case "Value":
81
+ return printValue(node.value);
82
+ case "Parameter":
83
+ return `$${node.name}`;
84
+ case "AccessAttribute":
85
+ if (node.base) {
86
+ const base = path.call((p) => printNode(p.node, print, p), "base");
87
+ if (isDerefNode(node.base)) {
88
+ return [base, node.name];
89
+ }
90
+ return [base, ".", node.name];
91
+ }
92
+ return node.name;
93
+ case "AccessElement":
94
+ return [
95
+ path.call((p) => printNode(p.node, print, p), "base"),
96
+ "[",
97
+ path.call((p) => printNode(p.node, print, p), "index"),
98
+ "]"
99
+ ];
100
+ case "Filter":
101
+ return [
102
+ path.call((p) => printNode(p.node, print, p), "base"),
103
+ group([
104
+ "[",
105
+ indent([softline, path.call((p) => printNode(p.node, print, p), "expr")]),
106
+ softline,
107
+ "]"
108
+ ])
109
+ ];
110
+ case "Slice":
111
+ return [
112
+ path.call((p) => printNode(p.node, print, p), "base"),
113
+ "[",
114
+ String(node.left),
115
+ node.isInclusive ? ".." : "...",
116
+ String(node.right),
117
+ "]"
118
+ ];
119
+ case "Map": {
120
+ const base = path.call((p) => printNode(p.node, print, p), "base");
121
+ const expr = path.call((p) => printNode(p.node, print, p), "expr");
122
+ if (node.base.type === "ArrayCoerce" && isDerefOfThis(node.expr)) {
123
+ return [base, expr];
124
+ }
125
+ return [base, " ", expr];
126
+ }
127
+ case "Projection": {
128
+ const base = path.call((p) => printNode(p.node, print, p), "base");
129
+ const expr = path.call((p) => printNode(p.node, print, p), "expr");
130
+ if (node.base.type === "This") {
131
+ return expr;
132
+ }
133
+ if (node.base.type === "Deref") {
134
+ return [base, expr];
135
+ }
136
+ return [base, " ", expr];
137
+ }
138
+ case "Object": {
139
+ if (node.attributes.length === 0) {
140
+ return "{}";
141
+ }
142
+ const attrs = path.map((p) => printNode(p.node, print, p), "attributes");
143
+ return group(["{", indent([line, join([",", line], attrs)]), line, "}"]);
144
+ }
145
+ case "ObjectAttributeValue": {
146
+ const value = path.call((p) => printNode(p.node, print, p), "value");
147
+ const leadingAttr = getLeadingAttribute(node.value);
148
+ if (leadingAttr === node.name) {
149
+ return value;
150
+ }
151
+ return ['"', escapeString(node.name), '": ', value];
152
+ }
153
+ case "ObjectSplat":
154
+ if (node.value) {
155
+ return ["...", path.call((p) => printNode(p.node, print, p), "value")];
156
+ }
157
+ return "...";
158
+ case "ObjectConditionalSplat":
159
+ return [
160
+ "...",
161
+ path.call((p) => printNode(p.node, print, p), "condition"),
162
+ " => ",
163
+ path.call((p) => printNode(p.node, print, p), "value")
164
+ ];
165
+ case "Array": {
166
+ if (node.elements.length === 0) {
167
+ return "[]";
168
+ }
169
+ const elems = path.map((p) => printNode(p.node, print, p), "elements");
170
+ return group(["[", indent([softline, join([",", line], elems)]), softline, "]"]);
171
+ }
172
+ case "ArrayElement":
173
+ if (node.isSplat) {
174
+ return ["...", path.call((p) => printNode(p.node, print, p), "value")];
175
+ }
176
+ return path.call((p) => printNode(p.node, print, p), "value");
177
+ case "Tuple": {
178
+ const members = path.map((p) => printNode(p.node, print, p), "members");
179
+ return ["(", join([",", " "], members), ")"];
180
+ }
181
+ case "Range":
182
+ return [
183
+ path.call((p) => printNode(p.node, print, p), "left"),
184
+ node.isInclusive ? ".." : "...",
185
+ path.call((p) => printNode(p.node, print, p), "right")
186
+ ];
187
+ case "And":
188
+ return group([
189
+ path.call((p) => printNode(p.node, print, p), "left"),
190
+ indent([line, "&& ", path.call((p) => printNode(p.node, print, p), "right")])
191
+ ]);
192
+ case "Or":
193
+ return group([
194
+ path.call((p) => printNode(p.node, print, p), "left"),
195
+ indent([line, "|| ", path.call((p) => printNode(p.node, print, p), "right")])
196
+ ]);
197
+ case "Not":
198
+ return ["!", path.call((p) => printNode(p.node, print, p), "base")];
199
+ case "Neg":
200
+ return ["-", path.call((p) => printNode(p.node, print, p), "base")];
201
+ case "Pos":
202
+ return ["+", path.call((p) => printNode(p.node, print, p), "base")];
203
+ case "OpCall": {
204
+ const left = path.call((p) => printNode(p.node, print, p), "left");
205
+ const right = path.call((p) => printNode(p.node, print, p), "right");
206
+ return [left, ` ${node.op} `, right];
207
+ }
208
+ case "FuncCall": {
209
+ const name = node.namespace && node.namespace !== "global" ? `${node.namespace}::${node.name}` : node.name;
210
+ if (node.args.length === 0) {
211
+ return `${name}()`;
212
+ }
213
+ const args = path.map((p) => printNode(p.node, print, p), "args");
214
+ return group([name, "(", indent([softline, join([",", line], args)]), softline, ")"]);
215
+ }
216
+ case "PipeFuncCall": {
217
+ const base = path.call((p) => printNode(p.node, print, p), "base");
218
+ const name = node.namespace && node.namespace !== "global" ? `${node.namespace}::${node.name}` : node.name;
219
+ const args = path.map((p) => printNode(p.node, print, p), "args");
220
+ const argsDoc = args.length === 0 ? "" : group(["(", join([", "], args), ")"]);
221
+ return group([base, indent([line, "| ", name, argsDoc])]);
222
+ }
223
+ case "Deref": {
224
+ if (node.base.type === "This") {
225
+ return "->";
226
+ }
227
+ const base = path.call((p) => printNode(p.node, print, p), "base");
228
+ return [base, "->"];
229
+ }
230
+ case "Asc":
231
+ return [path.call((p) => printNode(p.node, print, p), "base"), " asc"];
232
+ case "Desc":
233
+ return [path.call((p) => printNode(p.node, print, p), "base"), " desc"];
234
+ case "Group":
235
+ return ["(", path.call((p) => printNode(p.node, print, p), "base"), ")"];
236
+ case "ArrayCoerce":
237
+ return [path.call((p) => printNode(p.node, print, p), "base"), "[]"];
238
+ case "FlatMap":
239
+ return [
240
+ path.call((p) => printNode(p.node, print, p), "base"),
241
+ "[]",
242
+ path.call((p) => printNode(p.node, print, p), "expr")
243
+ ];
244
+ case "Select": {
245
+ const alternatives = path.map((p) => printNode(p.node, print, p), "alternatives");
246
+ const fallback = node.fallback ? path.call((p) => printNode(p.node, print, p), "fallback") : null;
247
+ const allArgs = fallback ? [...alternatives, fallback] : alternatives;
248
+ return group(["select(", indent([softline, join([",", line], allArgs)]), softline, ")"]);
249
+ }
250
+ case "SelectAlternative":
251
+ return [
252
+ path.call((p) => printNode(p.node, print, p), "condition"),
253
+ " => ",
254
+ path.call((p) => printNode(p.node, print, p), "value")
255
+ ];
256
+ case "InRange":
257
+ return [
258
+ path.call((p) => printNode(p.node, print, p), "base"),
259
+ " in ",
260
+ path.call((p) => printNode(p.node, print, p), "range")
261
+ ];
262
+ case "Context":
263
+ return path.call((p) => printNode(p.node, print, p), "base");
264
+ default:
265
+ throw new Error(`Unknown GROQ node type: ${node.type}`);
266
+ }
267
+ };
268
+ }
269
+ function printValue(value) {
270
+ if (value === null) {
271
+ return "null";
272
+ }
273
+ if (typeof value === "string") {
274
+ return `"${escapeString(value)}"`;
275
+ }
276
+ if (typeof value === "number") {
277
+ return formatNumber(value);
278
+ }
279
+ if (typeof value === "boolean") {
280
+ return value ? "true" : "false";
281
+ }
282
+ return String(value);
283
+ }
284
+ function escapeString(s) {
285
+ let result = "";
286
+ for (const ch of s) {
287
+ switch (ch) {
288
+ case '"':
289
+ result += '\\"';
290
+ break;
291
+ case "\\":
292
+ result += "\\\\";
293
+ break;
294
+ case "\n":
295
+ result += "\\n";
296
+ break;
297
+ case "\r":
298
+ result += "\\r";
299
+ break;
300
+ case " ":
301
+ result += "\\t";
302
+ break;
303
+ default:
304
+ if (ch.charCodeAt(0) < 32) {
305
+ result += `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`;
306
+ } else {
307
+ result += ch;
308
+ }
309
+ }
310
+ }
311
+ return result;
312
+ }
313
+ function formatNumber(value) {
314
+ return String(value);
315
+ }
316
+ function isDerefNode(node) {
317
+ return node.type === "Deref";
318
+ }
319
+ function isDerefOfThis(node) {
320
+ if (node.type === "Deref" && node.base.type === "This") {
321
+ return true;
322
+ }
323
+ if (node.type === "Projection" && node.base.type === "Deref" && node.base.base.type === "This") {
324
+ return true;
325
+ }
326
+ return false;
327
+ }
328
+ function getLeadingAttribute(node) {
329
+ switch (node.type) {
330
+ case "AccessAttribute":
331
+ if (!node.base) {
332
+ return node.name;
333
+ }
334
+ return null;
335
+ case "Deref":
336
+ return getLeadingAttribute(node.base);
337
+ case "Projection":
338
+ return getLeadingAttribute(node.base);
339
+ case "ArrayCoerce":
340
+ return getLeadingAttribute(node.base);
341
+ case "Map":
342
+ return getLeadingAttribute(node.base);
343
+ default:
344
+ return null;
345
+ }
346
+ }
347
+ function createGroqPrinter(builders) {
348
+ const printNode = createPrintNode(builders);
349
+ return {
350
+ print(path, options, print) {
351
+ const node = path.node;
352
+ if ("type" in node && node.type === "groq-root") {
353
+ return path.call(
354
+ (p) => printNode(p.node, print, p),
355
+ "node"
356
+ );
357
+ }
358
+ return printNode(node, print, path);
359
+ }
360
+ };
361
+ }
362
+
363
+ // src/wasm-printer.ts
364
+ var wasmAvailable = false;
365
+ var wasmInitialized = false;
366
+ var wasmInitPromise = null;
367
+ var wasmModule = null;
368
+ async function initWasmFormatter() {
369
+ if (wasmInitialized) {
370
+ return wasmAvailable;
371
+ }
372
+ if (wasmInitPromise) {
373
+ return wasmInitPromise;
374
+ }
375
+ wasmInitPromise = doInit();
376
+ return wasmInitPromise;
377
+ }
378
+ async function doInit() {
379
+ try {
380
+ wasmModule = await import("@sanity/groq-wasm");
381
+ await wasmModule.initWasm();
382
+ wasmAvailable = true;
383
+ wasmInitialized = true;
384
+ return true;
385
+ } catch {
386
+ wasmAvailable = false;
387
+ wasmInitialized = true;
388
+ return false;
389
+ }
390
+ }
391
+ function isWasmFormatterAvailable() {
392
+ return wasmAvailable;
393
+ }
394
+ function createWasmGroqPrinter(builders) {
395
+ const tsPrinter = createGroqPrinter(builders);
396
+ return {
397
+ print(path, options, print) {
398
+ if (wasmAvailable && wasmModule && options.originalText) {
399
+ try {
400
+ const width = options.printWidth || 80;
401
+ const formatted = wasmModule.format(options.originalText, { width });
402
+ return formatted;
403
+ } catch {
404
+ }
405
+ }
406
+ return tsPrinter.print(path, options, print);
407
+ }
408
+ };
409
+ }
410
+
411
+ // src/index.ts
412
+ var languages = [
413
+ {
414
+ name: "GROQ",
415
+ parsers: ["groq"],
416
+ extensions: [".groq"],
417
+ vscodeLanguageIds: ["groq"]
418
+ }
419
+ ];
420
+ var parsers = {
421
+ groq: groqParser
422
+ };
423
+ var printers = {
424
+ "groq-ast": createWasmGroqPrinter(import_prettier.doc.builders)
425
+ };
426
+ var plugin = {
427
+ languages,
428
+ parsers,
429
+ printers
430
+ };
431
+ var index_default = plugin;
432
+ // Annotate the CommonJS export names for ESM import in node:
433
+ 0 && (module.exports = {
434
+ createGroqPrinter,
435
+ initWasmFormatter,
436
+ isWasmFormatterAvailable,
437
+ languages,
438
+ parsers,
439
+ printers
440
+ });
441
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/parser.ts","../src/printer.ts","../src/wasm-printer.ts"],"sourcesContent":["import type { Plugin, SupportLanguage, Parser, Printer } from 'prettier'\nimport { doc } from 'prettier'\nimport { groqParser, type GroqAst } from './parser.js'\nimport {\n createWasmGroqPrinter,\n initWasmFormatter,\n isWasmFormatterAvailable,\n} from './wasm-printer.js'\n\nconst languages: SupportLanguage[] = [\n {\n name: 'GROQ',\n parsers: ['groq'],\n extensions: ['.groq'],\n vscodeLanguageIds: ['groq'],\n },\n]\n\nconst parsers: Record<string, Parser<GroqAst>> = {\n groq: groqParser,\n}\n\nconst printers: Record<string, Printer> = {\n 'groq-ast': createWasmGroqPrinter(doc.builders),\n}\n\nconst plugin: Plugin = {\n languages,\n parsers,\n printers,\n}\n\nexport default plugin\nexport { languages, parsers, printers, initWasmFormatter, isWasmFormatterAvailable }\n\n// Re-export TS printer for direct use\nexport { createGroqPrinter } from './printer.js'\n","import { parse as groqParse } from 'groq-js'\nimport type { Parser } from 'prettier'\nimport type { ExprNode } from 'groq-js'\n\nexport interface GroqAst {\n type: 'groq-root'\n node: ExprNode\n}\n\nfunction locStart(_node: GroqAst): number {\n // groq-js doesn't provide location info, so we return 0\n return 0\n}\n\nfunction locEnd(_node: GroqAst): number {\n // groq-js doesn't provide location info, so we return 0\n return 0\n}\n\nexport const groqParser: Parser<GroqAst> = {\n parse(text: string): GroqAst {\n const trimmed = text.trim()\n if (!trimmed) {\n throw new Error('Empty GROQ query')\n }\n const node = groqParse(trimmed)\n return {\n type: 'groq-root',\n node,\n }\n },\n astFormat: 'groq-ast',\n locStart,\n locEnd,\n}\n","import type { AstPath, Doc, Printer, doc } from 'prettier'\nimport type { ExprNode } from 'groq-js'\nimport type { GroqAst } from './parser.js'\n\ntype Builders = typeof doc.builders\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrintFn = (path: AstPath<any>) => Doc\n\n// Note: groq-js TypeScript types are incomplete - many node types exist at runtime\n// but aren't in the type definitions (ObjectSplat, Range, SelectAlternative, etc.)\n// We use 'any' here to handle all runtime node types correctly.\nfunction createPrintNode(builders: Builders) {\n const { group, indent, join, line, softline } = builders\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return function printNode(node: any, print: PrintFn, path: AstPath<any>): Doc {\n switch (node.type) {\n case 'Everything':\n return '*'\n\n case 'This':\n return '@'\n\n case 'Parent':\n return '^'\n\n case 'Value':\n return printValue(node.value)\n\n case 'Parameter':\n return `$${node.name}`\n\n case 'AccessAttribute':\n if (node.base) {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n // Don't add dot after dereference\n if (isDerefNode(node.base)) {\n return [base, node.name]\n }\n return [base, '.', node.name]\n }\n return node.name\n\n case 'AccessElement':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[',\n path.call((p) => printNode(p.node, print, p), 'index'),\n ']',\n ]\n\n case 'Filter':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n group([\n '[',\n indent([softline, path.call((p) => printNode(p.node, print, p), 'expr')]),\n softline,\n ']',\n ]),\n ]\n\n case 'Slice':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[',\n String(node.left),\n node.isInclusive ? '..' : '...',\n String(node.right),\n ']',\n ]\n\n case 'Map': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const expr = path.call((p) => printNode(p.node, print, p), 'expr')\n // Special case: when base is ArrayCoerce and expr starts with Deref(This),\n // collapse to the common `field[]->{ ... }` notation instead of `field[] @->{ ... }`\n if (node.base.type === 'ArrayCoerce' && isDerefOfThis(node.expr)) {\n // No space needed - the expr will start with ->\n return [base, expr]\n }\n return [base, ' ', expr]\n }\n\n case 'Projection': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const expr = path.call((p) => printNode(p.node, print, p), 'expr')\n // If base is This (@), omit it\n if (node.base.type === 'This') {\n return expr\n }\n // No space after dereference (author->{ name } not author-> { name })\n if (node.base.type === 'Deref') {\n return [base, expr]\n }\n return [base, ' ', expr]\n }\n\n case 'Object': {\n if (node.attributes.length === 0) {\n return '{}'\n }\n const attrs = path.map((p) => printNode(p.node, print, p), 'attributes')\n return group(['{', indent([line, join([',', line], attrs)]), line, '}'])\n }\n\n case 'ObjectAttributeValue': {\n const value = path.call((p) => printNode(p.node, print, p), 'value')\n // Check if we can use shorthand (omit the key entirely)\n // Shorthand is valid when the leading attribute name matches the key\n // e.g., { title } for { \"title\": title }\n // e.g., { author->{ name } } for { \"author\": author->{ name } }\n // e.g., { categories[]->{ title } } for { \"categories\": categories[]->{ title } }\n const leadingAttr = getLeadingAttribute(node.value)\n if (leadingAttr === node.name) {\n return value\n }\n // For all other cases, we MUST quote the key in GROQ\n // e.g., { \"slug\": slug.current } not { slug: slug.current }\n return ['\"', escapeString(node.name), '\": ', value]\n }\n\n case 'ObjectSplat':\n if (node.value) {\n return ['...', path.call((p) => printNode(p.node, print, p), 'value')]\n }\n return '...'\n\n case 'ObjectConditionalSplat':\n return [\n '...',\n path.call((p) => printNode(p.node, print, p), 'condition'),\n ' => ',\n path.call((p) => printNode(p.node, print, p), 'value'),\n ]\n\n case 'Array': {\n if (node.elements.length === 0) {\n return '[]'\n }\n const elems = path.map((p) => printNode(p.node, print, p), 'elements')\n return group(['[', indent([softline, join([',', line], elems)]), softline, ']'])\n }\n\n case 'ArrayElement':\n if (node.isSplat) {\n return ['...', path.call((p) => printNode(p.node, print, p), 'value')]\n }\n return path.call((p) => printNode(p.node, print, p), 'value')\n\n case 'Tuple': {\n const members = path.map((p) => printNode(p.node, print, p), 'members')\n return ['(', join([',', ' '], members), ')']\n }\n\n case 'Range':\n return [\n path.call((p) => printNode(p.node, print, p), 'left'),\n node.isInclusive ? '..' : '...',\n path.call((p) => printNode(p.node, print, p), 'right'),\n ]\n\n case 'And':\n return group([\n path.call((p) => printNode(p.node, print, p), 'left'),\n indent([line, '&& ', path.call((p) => printNode(p.node, print, p), 'right')]),\n ])\n\n case 'Or':\n return group([\n path.call((p) => printNode(p.node, print, p), 'left'),\n indent([line, '|| ', path.call((p) => printNode(p.node, print, p), 'right')]),\n ])\n\n case 'Not':\n return ['!', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'Neg':\n return ['-', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'Pos':\n return ['+', path.call((p) => printNode(p.node, print, p), 'base')]\n\n case 'OpCall': {\n const left = path.call((p) => printNode(p.node, print, p), 'left')\n const right = path.call((p) => printNode(p.node, print, p), 'right')\n return [left, ` ${node.op} `, right]\n }\n\n case 'FuncCall': {\n const name =\n node.namespace && node.namespace !== 'global'\n ? `${node.namespace}::${node.name}`\n : node.name\n if (node.args.length === 0) {\n return `${name}()`\n }\n const args = path.map((p) => printNode(p.node, print, p), 'args')\n return group([name, '(', indent([softline, join([',', line], args)]), softline, ')'])\n }\n\n case 'PipeFuncCall': {\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n const name =\n node.namespace && node.namespace !== 'global'\n ? `${node.namespace}::${node.name}`\n : node.name\n const args = path.map((p) => printNode(p.node, print, p), 'args')\n const argsDoc = args.length === 0 ? '' : group(['(', join([', '], args), ')'])\n return group([base, indent([line, '| ', name, argsDoc])])\n }\n\n case 'Deref': {\n // When base is This (@), omit it - this is the implicit dereference in array traversals\n // e.g., categories[]->{ title } should not become categories[] @->{ title }\n if (node.base.type === 'This') {\n return '->'\n }\n const base = path.call((p) => printNode(p.node, print, p), 'base')\n return [base, '->']\n }\n\n case 'Asc':\n return [path.call((p) => printNode(p.node, print, p), 'base'), ' asc']\n\n case 'Desc':\n return [path.call((p) => printNode(p.node, print, p), 'base'), ' desc']\n\n case 'Group':\n return ['(', path.call((p) => printNode(p.node, print, p), 'base'), ')']\n\n case 'ArrayCoerce':\n return [path.call((p) => printNode(p.node, print, p), 'base'), '[]']\n\n case 'FlatMap':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n '[]',\n path.call((p) => printNode(p.node, print, p), 'expr'),\n ]\n\n case 'Select': {\n const alternatives = path.map((p) => printNode(p.node, print, p), 'alternatives')\n const fallback = node.fallback\n ? path.call((p) => printNode(p.node, print, p), 'fallback')\n : null\n const allArgs = fallback ? [...alternatives, fallback] : alternatives\n return group(['select(', indent([softline, join([',', line], allArgs)]), softline, ')'])\n }\n\n case 'SelectAlternative':\n return [\n path.call((p) => printNode(p.node, print, p), 'condition'),\n ' => ',\n path.call((p) => printNode(p.node, print, p), 'value'),\n ]\n\n case 'InRange':\n return [\n path.call((p) => printNode(p.node, print, p), 'base'),\n ' in ',\n path.call((p) => printNode(p.node, print, p), 'range'),\n ]\n\n case 'Context':\n // Internal node, shouldn't appear in user queries\n return path.call((p) => printNode(p.node, print, p), 'base')\n\n default:\n // Fallback for any unhandled node types\n throw new Error(`Unknown GROQ node type: ${(node as { type: string }).type}`)\n }\n }\n}\n\nfunction printValue(value: unknown): string {\n if (value === null) {\n return 'null'\n }\n if (typeof value === 'string') {\n return `\"${escapeString(value)}\"`\n }\n if (typeof value === 'number') {\n return formatNumber(value)\n }\n if (typeof value === 'boolean') {\n return value ? 'true' : 'false'\n }\n // Arrays and objects shouldn't appear as raw values\n return String(value)\n}\n\nfunction escapeString(s: string): string {\n let result = ''\n for (const ch of s) {\n switch (ch) {\n case '\"':\n result += '\\\\\"'\n break\n case '\\\\':\n result += '\\\\\\\\'\n break\n case '\\n':\n result += '\\\\n'\n break\n case '\\r':\n result += '\\\\r'\n break\n case '\\t':\n result += '\\\\t'\n break\n default:\n if (ch.charCodeAt(0) < 32) {\n result += `\\\\u${ch.charCodeAt(0).toString(16).padStart(4, '0')}`\n } else {\n result += ch\n }\n }\n }\n return result\n}\n\nfunction formatNumber(value: number): string {\n return String(value)\n}\n\nfunction isDerefNode(node: ExprNode): boolean {\n return node.type === 'Deref'\n}\n\n/**\n * Check if a node represents a Deref of This (@->)\n * This handles both direct Deref(This) and Projection with Deref(This) as base\n */\nfunction isDerefOfThis(node: ExprNode): boolean {\n if (node.type === 'Deref' && node.base.type === 'This') {\n return true\n }\n if (node.type === 'Projection' && node.base.type === 'Deref' && node.base.base.type === 'This') {\n return true\n }\n return false\n}\n\n/**\n * Get the attribute name that can be used for shorthand in projections.\n * Returns the name only when shorthand is valid in GROQ.\n *\n * Valid shorthand cases:\n * - { title } → simple attribute access\n * - { author->{ name } } → dereference of attribute\n * - { categories[]->{ title } } → array traversal of attribute\n *\n * Invalid shorthand (returns null):\n * - { slug.current } → dot access (GROQ can't infer key)\n */\nfunction getLeadingAttribute(node: ExprNode): string | null {\n switch (node.type) {\n case 'AccessAttribute':\n // Only valid for shorthand if there's NO base (simple attribute)\n // { title } is valid, but { slug.current } is NOT\n if (!node.base) {\n return node.name\n }\n // Dot access - shorthand not valid\n return null\n case 'Deref':\n // { author->{ name } } - check if base is a simple attribute\n return getLeadingAttribute(node.base)\n case 'Projection':\n // Projection's base determines the leading attribute\n return getLeadingAttribute(node.base)\n case 'ArrayCoerce':\n // { tags[] } - check if base is a simple attribute\n return getLeadingAttribute(node.base)\n case 'Map':\n // Map's base determines the leading attribute\n return getLeadingAttribute(node.base)\n default:\n return null\n }\n}\n\nexport function createGroqPrinter(builders: Builders): Printer<GroqAst | ExprNode> {\n const printNode = createPrintNode(builders)\n\n return {\n print(path, options, print) {\n const node = path.node\n\n // Handle root wrapper\n if ('type' in node && node.type === 'groq-root') {\n return path.call(\n (p) => printNode(p.node as ExprNode, print as PrintFn, p as AstPath<ExprNode>),\n 'node'\n )\n }\n\n // Handle ExprNode\n return printNode(node as ExprNode, print as PrintFn, path as AstPath<ExprNode>)\n },\n }\n}\n","/**\n * WASM-based GROQ printer for Prettier\n *\n * Uses @sanity/groq-wasm for high-performance formatting.\n * Falls back to the TypeScript printer if WASM is not available.\n */\n\nimport type { Printer, doc } from 'prettier'\nimport { createGroqPrinter } from './printer.js'\n\n// WASM module state\nlet wasmAvailable = false\nlet wasmInitialized = false\nlet wasmInitPromise: Promise<boolean> | null = null\n\n// WASM module reference\ntype WasmModule = typeof import('@sanity/groq-wasm')\nlet wasmModule: WasmModule | null = null\n\n/**\n * Initialize the WASM formatter\n *\n * Call this once at application startup for best performance.\n * The plugin will fall back to TypeScript formatting if WASM is not available.\n *\n * @returns Promise that resolves to true if WASM is available\n *\n * @example\n * ```typescript\n * import { initWasmFormatter } from 'prettier-plugin-groq'\n *\n * // Optional: Initialize WASM for better performance\n * await initWasmFormatter()\n * ```\n */\nexport async function initWasmFormatter(): Promise<boolean> {\n if (wasmInitialized) {\n return wasmAvailable\n }\n\n if (wasmInitPromise) {\n return wasmInitPromise\n }\n\n wasmInitPromise = doInit()\n return wasmInitPromise\n}\n\nasync function doInit(): Promise<boolean> {\n try {\n wasmModule = await import('@sanity/groq-wasm')\n await wasmModule.initWasm()\n wasmAvailable = true\n wasmInitialized = true\n return true\n } catch {\n wasmAvailable = false\n wasmInitialized = true\n return false\n }\n}\n\n/**\n * Check if WASM formatter is available\n */\nexport function isWasmFormatterAvailable(): boolean {\n return wasmAvailable\n}\n\n/**\n * Format a GROQ query using WASM\n *\n * @param query - The GROQ query to format\n * @param width - Maximum line width (default: 80)\n * @returns Formatted query string\n * @throws If WASM is not initialized\n */\nexport function formatWithWasm(query: string, width?: number): string {\n if (!wasmAvailable || !wasmModule) {\n throw new Error('WASM formatter not initialized. Call initWasmFormatter() first.')\n }\n return wasmModule.format(query, width !== undefined ? { width } : undefined)\n}\n\n/**\n * Create a WASM-accelerated GROQ printer\n *\n * Uses WASM formatting when available, falls back to TypeScript printer otherwise.\n */\nexport function createWasmGroqPrinter(builders: typeof doc.builders): Printer {\n // Create TS fallback printer\n const tsPrinter = createGroqPrinter(builders)\n\n return {\n print(path, options, print) {\n // If WASM is available and we have the original text, use WASM\n if (wasmAvailable && wasmModule && options.originalText) {\n try {\n const width = options.printWidth || 80\n const formatted = wasmModule.format(options.originalText, { width })\n // Return as a simple string Doc\n return formatted\n } catch {\n // Fall back to TS printer on error\n }\n }\n\n // Fall back to TypeScript printer\n return tsPrinter.print(path, options, print)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,sBAAoB;;;ACDpB,qBAAmC;AASnC,SAAS,SAAS,OAAwB;AAExC,SAAO;AACT;AAEA,SAAS,OAAO,OAAwB;AAEtC,SAAO;AACT;AAEO,IAAM,aAA8B;AAAA,EACzC,MAAM,MAAuB;AAC3B,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,kBAAkB;AAAA,IACpC;AACA,UAAM,WAAO,eAAAA,OAAU,OAAO;AAC9B,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF;;;ACvBA,SAAS,gBAAgB,UAAoB;AAC3C,QAAM,EAAE,OAAO,QAAQ,MAAM,MAAM,SAAS,IAAI;AAGhD,SAAO,SAAS,UAAU,MAAW,OAAgB,MAAyB;AAC5E,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AACH,eAAO,WAAW,KAAK,KAAK;AAAA,MAE9B,KAAK;AACH,eAAO,IAAI,KAAK,IAAI;AAAA,MAEtB,KAAK;AACH,YAAI,KAAK,MAAM;AACb,gBAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAEjE,cAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,mBAAO,CAAC,MAAM,KAAK,IAAI;AAAA,UACzB;AACA,iBAAO,CAAC,MAAM,KAAK,KAAK,IAAI;AAAA,QAC9B;AACA,eAAO,KAAK;AAAA,MAEd,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,UACrD;AAAA,QACF;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD,MAAM;AAAA,YACJ;AAAA,YACA,OAAO,CAAC,UAAU,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;AAAA,YACxE;AAAA,YACA;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD;AAAA,UACA,OAAO,KAAK,IAAI;AAAA,UAChB,KAAK,cAAc,OAAO;AAAA,UAC1B,OAAO,KAAK,KAAK;AAAA,UACjB;AAAA,QACF;AAAA,MAEF,KAAK,OAAO;AACV,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AACjE,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAGjE,YAAI,KAAK,KAAK,SAAS,iBAAiB,cAAc,KAAK,IAAI,GAAG;AAEhE,iBAAO,CAAC,MAAM,IAAI;AAAA,QACpB;AACA,eAAO,CAAC,MAAM,KAAK,IAAI;AAAA,MACzB;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AACjE,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAEjE,YAAI,KAAK,KAAK,SAAS,QAAQ;AAC7B,iBAAO;AAAA,QACT;AAEA,YAAI,KAAK,KAAK,SAAS,SAAS;AAC9B,iBAAO,CAAC,MAAM,IAAI;AAAA,QACpB;AACA,eAAO,CAAC,MAAM,KAAK,IAAI;AAAA,MACzB;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,KAAK,WAAW,WAAW,GAAG;AAChC,iBAAO;AAAA,QACT;AACA,cAAM,QAAQ,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,YAAY;AACvE,eAAO,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,KAAK,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,MAAM,GAAG,CAAC;AAAA,MACzE;AAAA,MAEA,KAAK,wBAAwB;AAC3B,cAAM,QAAQ,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAMnE,cAAM,cAAc,oBAAoB,KAAK,KAAK;AAClD,YAAI,gBAAgB,KAAK,MAAM;AAC7B,iBAAO;AAAA,QACT;AAGA,eAAO,CAAC,KAAK,aAAa,KAAK,IAAI,GAAG,OAAO,KAAK;AAAA,MACpD;AAAA,MAEA,KAAK;AACH,YAAI,KAAK,OAAO;AACd,iBAAO,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,QACvE;AACA,eAAO;AAAA,MAET,KAAK;AACH,eAAO;AAAA,UACL;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,WAAW;AAAA,UACzD;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,QACvD;AAAA,MAEF,KAAK,SAAS;AACZ,YAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,iBAAO;AAAA,QACT;AACA,cAAM,QAAQ,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,UAAU;AACrE,eAAO,MAAM,CAAC,KAAK,OAAO,CAAC,UAAU,KAAK,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;AAAA,MACjF;AAAA,MAEA,KAAK;AACH,YAAI,KAAK,SAAS;AAChB,iBAAO,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC;AAAA,QACvE;AACA,eAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,MAE9D,KAAK,SAAS;AACZ,cAAM,UAAU,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,SAAS;AACtE,eAAO,CAAC,KAAK,KAAK,CAAC,KAAK,GAAG,GAAG,OAAO,GAAG,GAAG;AAAA,MAC7C;AAAA,MAEA,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD,KAAK,cAAc,OAAO;AAAA,UAC1B,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,QACvD;AAAA,MAEF,KAAK;AACH,eAAO,MAAM;AAAA,UACX,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD,OAAO,CAAC,MAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AAAA,QAC9E,CAAC;AAAA,MAEH,KAAK;AACH,eAAO,MAAM;AAAA,UACX,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD,OAAO,CAAC,MAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AAAA,QAC9E,CAAC;AAAA,MAEH,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,CAAC;AAAA,MAEpE,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,CAAC;AAAA,MAEpE,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,CAAC;AAAA,MAEpE,KAAK,UAAU;AACb,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AACjE,cAAM,QAAQ,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AACnE,eAAO,CAAC,MAAM,IAAI,KAAK,EAAE,KAAK,KAAK;AAAA,MACrC;AAAA,MAEA,KAAK,YAAY;AACf,cAAM,OACJ,KAAK,aAAa,KAAK,cAAc,WACjC,GAAG,KAAK,SAAS,KAAK,KAAK,IAAI,KAC/B,KAAK;AACX,YAAI,KAAK,KAAK,WAAW,GAAG;AAC1B,iBAAO,GAAG,IAAI;AAAA,QAChB;AACA,cAAM,OAAO,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAChE,eAAO,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC,UAAU,KAAK,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;AAAA,MACtF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AACjE,cAAM,OACJ,KAAK,aAAa,KAAK,cAAc,WACjC,GAAG,KAAK,SAAS,KAAK,KAAK,IAAI,KAC/B,KAAK;AACX,cAAM,OAAO,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAChE,cAAM,UAAU,KAAK,WAAW,IAAI,KAAK,MAAM,CAAC,KAAK,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;AAC7E,eAAO,MAAM,CAAC,MAAM,OAAO,CAAC,MAAM,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,MAC1D;AAAA,MAEA,KAAK,SAAS;AAGZ,YAAI,KAAK,KAAK,SAAS,QAAQ;AAC7B,iBAAO;AAAA,QACT;AACA,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AACjE,eAAO,CAAC,MAAM,IAAI;AAAA,MACpB;AAAA,MAEA,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,GAAG,MAAM;AAAA,MAEvE,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,GAAG,OAAO;AAAA,MAExE,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,GAAG,GAAG;AAAA,MAEzE,KAAK;AACH,eAAO,CAAC,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI;AAAA,MAErE,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,QACtD;AAAA,MAEF,KAAK,UAAU;AACb,cAAM,eAAe,KAAK,IAAI,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,cAAc;AAChF,cAAM,WAAW,KAAK,WAClB,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,UAAU,IACxD;AACJ,cAAM,UAAU,WAAW,CAAC,GAAG,cAAc,QAAQ,IAAI;AACzD,eAAO,MAAM,CAAC,WAAW,OAAO,CAAC,UAAU,KAAK,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;AAAA,MACzF;AAAA,MAEA,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,WAAW;AAAA,UACzD;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,QACvD;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,UACpD;AAAA,UACA,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,OAAO;AAAA,QACvD;AAAA,MAEF,KAAK;AAEH,eAAO,KAAK,KAAK,CAAC,MAAM,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,MAAM;AAAA,MAE7D;AAEE,cAAM,IAAI,MAAM,2BAA4B,KAA0B,IAAI,EAAE;AAAA,IAChF;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAAwB;AAC1C,MAAI,UAAU,MAAM;AAClB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,IAAI,aAAa,KAAK,CAAC;AAAA,EAChC;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,aAAa,KAAK;AAAA,EAC3B;AACA,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO,QAAQ,SAAS;AAAA,EAC1B;AAEA,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,aAAa,GAAmB;AACvC,MAAI,SAAS;AACb,aAAW,MAAM,GAAG;AAClB,YAAQ,IAAI;AAAA,MACV,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF,KAAK;AACH,kBAAU;AACV;AAAA,MACF;AACE,YAAI,GAAG,WAAW,CAAC,IAAI,IAAI;AACzB,oBAAU,MAAM,GAAG,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,QAChE,OAAO;AACL,oBAAU;AAAA,QACZ;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,OAAO,KAAK;AACrB;AAEA,SAAS,YAAY,MAAyB;AAC5C,SAAO,KAAK,SAAS;AACvB;AAMA,SAAS,cAAc,MAAyB;AAC9C,MAAI,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,QAAQ;AACtD,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,gBAAgB,KAAK,KAAK,SAAS,WAAW,KAAK,KAAK,KAAK,SAAS,QAAQ;AAC9F,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAcA,SAAS,oBAAoB,MAA+B;AAC1D,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AAGH,UAAI,CAAC,KAAK,MAAM;AACd,eAAO,KAAK;AAAA,MACd;AAEA,aAAO;AAAA,IACT,KAAK;AAEH,aAAO,oBAAoB,KAAK,IAAI;AAAA,IACtC,KAAK;AAEH,aAAO,oBAAoB,KAAK,IAAI;AAAA,IACtC,KAAK;AAEH,aAAO,oBAAoB,KAAK,IAAI;AAAA,IACtC,KAAK;AAEH,aAAO,oBAAoB,KAAK,IAAI;AAAA,IACtC;AACE,aAAO;AAAA,EACX;AACF;AAEO,SAAS,kBAAkB,UAAiD;AACjF,QAAM,YAAY,gBAAgB,QAAQ;AAE1C,SAAO;AAAA,IACL,MAAM,MAAM,SAAS,OAAO;AAC1B,YAAM,OAAO,KAAK;AAGlB,UAAI,UAAU,QAAQ,KAAK,SAAS,aAAa;AAC/C,eAAO,KAAK;AAAA,UACV,CAAC,MAAM,UAAU,EAAE,MAAkB,OAAkB,CAAsB;AAAA,UAC7E;AAAA,QACF;AAAA,MACF;AAGA,aAAO,UAAU,MAAkB,OAAkB,IAAyB;AAAA,IAChF;AAAA,EACF;AACF;;;ACvYA,IAAI,gBAAgB;AACpB,IAAI,kBAAkB;AACtB,IAAI,kBAA2C;AAI/C,IAAI,aAAgC;AAkBpC,eAAsB,oBAAsC;AAC1D,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAEA,oBAAkB,OAAO;AACzB,SAAO;AACT;AAEA,eAAe,SAA2B;AACxC,MAAI;AACF,iBAAa,MAAM,OAAO,mBAAmB;AAC7C,UAAM,WAAW,SAAS;AAC1B,oBAAgB;AAChB,sBAAkB;AAClB,WAAO;AAAA,EACT,QAAQ;AACN,oBAAgB;AAChB,sBAAkB;AAClB,WAAO;AAAA,EACT;AACF;AAKO,SAAS,2BAAoC;AAClD,SAAO;AACT;AAsBO,SAAS,sBAAsB,UAAwC;AAE5E,QAAM,YAAY,kBAAkB,QAAQ;AAE5C,SAAO;AAAA,IACL,MAAM,MAAM,SAAS,OAAO;AAE1B,UAAI,iBAAiB,cAAc,QAAQ,cAAc;AACvD,YAAI;AACF,gBAAM,QAAQ,QAAQ,cAAc;AACpC,gBAAM,YAAY,WAAW,OAAO,QAAQ,cAAc,EAAE,MAAM,CAAC;AAEnE,iBAAO;AAAA,QACT,QAAQ;AAAA,QAER;AAAA,MACF;AAGA,aAAO,UAAU,MAAM,MAAM,SAAS,KAAK;AAAA,IAC7C;AAAA,EACF;AACF;;;AHtGA,IAAM,YAA+B;AAAA,EACnC;AAAA,IACE,MAAM;AAAA,IACN,SAAS,CAAC,MAAM;AAAA,IAChB,YAAY,CAAC,OAAO;AAAA,IACpB,mBAAmB,CAAC,MAAM;AAAA,EAC5B;AACF;AAEA,IAAM,UAA2C;AAAA,EAC/C,MAAM;AACR;AAEA,IAAM,WAAoC;AAAA,EACxC,YAAY,sBAAsB,oBAAI,QAAQ;AAChD;AAEA,IAAM,SAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAO,gBAAQ;","names":["groqParse"]}
@@ -0,0 +1,46 @@
1
+ import { doc, Printer, Parser, Plugin, SupportLanguage } from 'prettier';
2
+ import { ExprNode } from 'groq-js';
3
+
4
+ interface GroqAst {
5
+ type: 'groq-root';
6
+ node: ExprNode;
7
+ }
8
+
9
+ /**
10
+ * WASM-based GROQ printer for Prettier
11
+ *
12
+ * Uses @sanity/groq-wasm for high-performance formatting.
13
+ * Falls back to the TypeScript printer if WASM is not available.
14
+ */
15
+
16
+ /**
17
+ * Initialize the WASM formatter
18
+ *
19
+ * Call this once at application startup for best performance.
20
+ * The plugin will fall back to TypeScript formatting if WASM is not available.
21
+ *
22
+ * @returns Promise that resolves to true if WASM is available
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * import { initWasmFormatter } from 'prettier-plugin-groq'
27
+ *
28
+ * // Optional: Initialize WASM for better performance
29
+ * await initWasmFormatter()
30
+ * ```
31
+ */
32
+ declare function initWasmFormatter(): Promise<boolean>;
33
+ /**
34
+ * Check if WASM formatter is available
35
+ */
36
+ declare function isWasmFormatterAvailable(): boolean;
37
+
38
+ type Builders = typeof doc.builders;
39
+ declare function createGroqPrinter(builders: Builders): Printer<GroqAst | ExprNode>;
40
+
41
+ declare const languages: SupportLanguage[];
42
+ declare const parsers: Record<string, Parser<GroqAst>>;
43
+ declare const printers: Record<string, Printer>;
44
+ declare const plugin: Plugin;
45
+
46
+ export { createGroqPrinter, plugin as default, initWasmFormatter, isWasmFormatterAvailable, languages, parsers, printers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/prettier-plugin-groq",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -16,14 +16,16 @@
16
16
  "exports": {
17
17
  ".": {
18
18
  "types": "./dist/index.d.ts",
19
- "import": "./dist/index.js"
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/index.cjs"
20
21
  },
21
22
  "./embed": {
22
23
  "types": "./dist/embed.d.ts",
23
- "import": "./dist/embed.js"
24
+ "import": "./dist/embed.js",
25
+ "require": "./dist/embed.cjs"
24
26
  }
25
27
  },
26
- "main": "./dist/index.js",
28
+ "main": "./dist/index.cjs",
27
29
  "types": "./dist/index.d.ts",
28
30
  "files": [
29
31
  "dist"
@@ -40,7 +42,7 @@
40
42
  "tsup": "^8.3.5",
41
43
  "typescript": "^5.7.2",
42
44
  "vitest": "^2.1.8",
43
- "@sanity/lint-core": "0.0.1"
45
+ "@sanity/lint-core": "0.0.2"
44
46
  },
45
47
  "keywords": [
46
48
  "sanity",