@sanity-labs/prettier-plugin-groq 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +112 -0
- package/dist/chunk-TUFZP5UF.js +402 -0
- package/dist/chunk-TUFZP5UF.js.map +1 -0
- package/dist/embed.cjs +513 -0
- package/dist/embed.cjs.map +1 -0
- package/dist/embed.d.cts +59 -0
- package/dist/embed.d.ts +59 -0
- package/dist/embed.js +139 -0
- package/dist/embed.js.map +1 -0
- package/dist/index.cjs +441 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +46 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/dist/embed.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Plugin, AstPath, Options, Doc } from 'prettier';
|
|
2
|
+
export { parsers } from './index.js';
|
|
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/embed.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parsers
|
|
3
|
+
} from "./chunk-TUFZP5UF.js";
|
|
4
|
+
|
|
5
|
+
// src/embed.ts
|
|
6
|
+
import { printers as estreePrinters } from "prettier/plugins/estree.mjs";
|
|
7
|
+
var defaultEstreePrinter = estreePrinters.estree;
|
|
8
|
+
var defaultEmbed = defaultEstreePrinter.embed;
|
|
9
|
+
var GROQ_IDENTIFIERS = ["groq", "defineQuery"];
|
|
10
|
+
function getTagName(node) {
|
|
11
|
+
if (node.type !== "TaggedTemplateExpression") return null;
|
|
12
|
+
const tag = node.tag;
|
|
13
|
+
if (!tag) return null;
|
|
14
|
+
if (tag.type === "Identifier" && typeof tag.name === "string") {
|
|
15
|
+
return tag.name;
|
|
16
|
+
}
|
|
17
|
+
if (tag.type === "MemberExpression" && tag.object?.type === "Identifier") {
|
|
18
|
+
return tag.object.name ?? null;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
function getCallName(node) {
|
|
23
|
+
if (node.type !== "CallExpression") return null;
|
|
24
|
+
const callee = node.callee;
|
|
25
|
+
if (!callee) return null;
|
|
26
|
+
if (callee.type === "Identifier" && typeof callee.name === "string") {
|
|
27
|
+
return callee.name;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function isGroqTaggedTemplate(node) {
|
|
32
|
+
const tagName = getTagName(node);
|
|
33
|
+
return tagName !== null && GROQ_IDENTIFIERS.includes(tagName);
|
|
34
|
+
}
|
|
35
|
+
function isGroqFunctionCall(node) {
|
|
36
|
+
const callName = getCallName(node);
|
|
37
|
+
return callName !== null && GROQ_IDENTIFIERS.includes(callName);
|
|
38
|
+
}
|
|
39
|
+
function extractFromTemplate(node) {
|
|
40
|
+
const quasi = node.quasi;
|
|
41
|
+
if (!quasi || !quasi.quasis) return null;
|
|
42
|
+
const quasis = quasi.quasis;
|
|
43
|
+
const expressions = quasi.expressions || [];
|
|
44
|
+
if (expressions.length === 0) {
|
|
45
|
+
const first = quasis[0];
|
|
46
|
+
if (!first) return null;
|
|
47
|
+
return first.value?.cooked ?? first.value?.raw ?? null;
|
|
48
|
+
}
|
|
49
|
+
let result = "";
|
|
50
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
51
|
+
const q = quasis[i];
|
|
52
|
+
if (!q) continue;
|
|
53
|
+
result += q.value?.cooked ?? q.value?.raw ?? "";
|
|
54
|
+
if (i < expressions.length) {
|
|
55
|
+
result += `$__expr${i}__`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function extractFromFunctionCall(node) {
|
|
61
|
+
const args = node.arguments;
|
|
62
|
+
if (!args || args.length === 0) return null;
|
|
63
|
+
const firstArg = args[0];
|
|
64
|
+
if (!firstArg) return null;
|
|
65
|
+
if ((firstArg.type === "Literal" || firstArg.type === "StringLiteral") && typeof firstArg.value === "string") {
|
|
66
|
+
return firstArg.value;
|
|
67
|
+
}
|
|
68
|
+
if (firstArg.type === "TemplateLiteral") {
|
|
69
|
+
const quasis = firstArg.quasis;
|
|
70
|
+
const expressions = firstArg.expressions || [];
|
|
71
|
+
if (!quasis || quasis.length === 0) return null;
|
|
72
|
+
if (expressions.length === 0) {
|
|
73
|
+
const first = quasis[0];
|
|
74
|
+
return first?.value?.cooked ?? first?.value?.raw ?? null;
|
|
75
|
+
}
|
|
76
|
+
let result = "";
|
|
77
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
78
|
+
const q = quasis[i];
|
|
79
|
+
if (!q) continue;
|
|
80
|
+
result += q.value?.cooked ?? q.value?.raw ?? "";
|
|
81
|
+
if (i < expressions.length) {
|
|
82
|
+
result += `$__expr${i}__`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
function embed(path, options) {
|
|
90
|
+
const node = path.node;
|
|
91
|
+
if (isGroqTaggedTemplate(node)) {
|
|
92
|
+
const content = extractFromTemplate(node);
|
|
93
|
+
if (!content) {
|
|
94
|
+
return defaultEmbed ? defaultEmbed(path, options) : void 0;
|
|
95
|
+
}
|
|
96
|
+
return async (textToDoc, print) => {
|
|
97
|
+
try {
|
|
98
|
+
const formattedGroq = await textToDoc(content.trim(), { parser: "groq" });
|
|
99
|
+
const tag = print("tag");
|
|
100
|
+
return [tag, "`", formattedGroq, "`"];
|
|
101
|
+
} catch {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (isGroqFunctionCall(node)) {
|
|
107
|
+
const content = extractFromFunctionCall(node);
|
|
108
|
+
if (!content) {
|
|
109
|
+
return defaultEmbed ? defaultEmbed(path, options) : void 0;
|
|
110
|
+
}
|
|
111
|
+
return async (textToDoc, print) => {
|
|
112
|
+
try {
|
|
113
|
+
const formattedGroq = await textToDoc(content.trim(), { parser: "groq" });
|
|
114
|
+
const callee = print("callee");
|
|
115
|
+
return [callee, "(`", formattedGroq, "`)"];
|
|
116
|
+
} catch {
|
|
117
|
+
return void 0;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return defaultEmbed ? defaultEmbed(path, options) : void 0;
|
|
122
|
+
}
|
|
123
|
+
var estreePrinter = {
|
|
124
|
+
...defaultEstreePrinter,
|
|
125
|
+
embed
|
|
126
|
+
};
|
|
127
|
+
var embedPlugin = {
|
|
128
|
+
parsers,
|
|
129
|
+
printers: {
|
|
130
|
+
estree: estreePrinter
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var embed_default = embedPlugin;
|
|
134
|
+
export {
|
|
135
|
+
embed_default as default,
|
|
136
|
+
embed,
|
|
137
|
+
parsers
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=embed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/embed.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"],"mappings":"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","names":[]}
|
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-labs/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
|