eslint-plugin-sanity 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +532 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
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/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
configs: () => configs,
|
|
24
|
+
default: () => index_default,
|
|
25
|
+
rules: () => rules
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var import_groq_lint2 = require("@sanity/groq-lint");
|
|
29
|
+
var import_schema_lint2 = require("@sanity/schema-lint");
|
|
30
|
+
|
|
31
|
+
// src/utils/rule-factory.ts
|
|
32
|
+
var import_groq_lint = require("@sanity/groq-lint");
|
|
33
|
+
|
|
34
|
+
// src/utils/groq-extractor.ts
|
|
35
|
+
function isGroqTaggedTemplate(node) {
|
|
36
|
+
const tag = node.tag;
|
|
37
|
+
if (tag.type === "Identifier" && tag.name === "groq") {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
if (tag.type === "MemberExpression" && tag.object.type === "Identifier" && tag.object.name === "groq") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
function extractGroqString(node) {
|
|
46
|
+
const { quasis, expressions } = node.quasi;
|
|
47
|
+
if (expressions.length === 0) {
|
|
48
|
+
return quasis[0]?.value.cooked ?? quasis[0]?.value.raw ?? "";
|
|
49
|
+
}
|
|
50
|
+
let result = "";
|
|
51
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
52
|
+
result += quasis[i]?.value.cooked ?? quasis[i]?.value.raw ?? "";
|
|
53
|
+
if (i < expressions.length) {
|
|
54
|
+
result += `$__expr${i}__`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/utils/rule-factory.ts
|
|
61
|
+
function buildSingleRuleConfig(ruleId) {
|
|
62
|
+
const config = {};
|
|
63
|
+
for (const rule of import_groq_lint.rules) {
|
|
64
|
+
config[rule.id] = rule.id === ruleId;
|
|
65
|
+
}
|
|
66
|
+
return config;
|
|
67
|
+
}
|
|
68
|
+
function createESLintRule(groqRule) {
|
|
69
|
+
return {
|
|
70
|
+
meta: {
|
|
71
|
+
type: groqRule.category === "correctness" ? "problem" : "suggestion",
|
|
72
|
+
docs: {
|
|
73
|
+
description: groqRule.description,
|
|
74
|
+
recommended: groqRule.severity === "error"
|
|
75
|
+
},
|
|
76
|
+
messages: {
|
|
77
|
+
[groqRule.id]: "{{ message }}"
|
|
78
|
+
},
|
|
79
|
+
schema: []
|
|
80
|
+
// No options for now
|
|
81
|
+
},
|
|
82
|
+
create(context) {
|
|
83
|
+
return {
|
|
84
|
+
TaggedTemplateExpression(eslintNode) {
|
|
85
|
+
const node = eslintNode;
|
|
86
|
+
if (!isGroqTaggedTemplate(node)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const query = extractGroqString(node);
|
|
91
|
+
const result = (0, import_groq_lint.lint)(query, { config: { rules: buildSingleRuleConfig(groqRule.id) } });
|
|
92
|
+
for (const finding of result.findings) {
|
|
93
|
+
if (finding.ruleId === groqRule.id) {
|
|
94
|
+
context.report({
|
|
95
|
+
node: eslintNode,
|
|
96
|
+
messageId: groqRule.id,
|
|
97
|
+
data: {
|
|
98
|
+
message: finding.help ? `${finding.message} ${finding.help}` : finding.message
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function createAllRules(groqRules2) {
|
|
111
|
+
const eslintRules = {};
|
|
112
|
+
for (const rule of groqRules2) {
|
|
113
|
+
const eslintRuleId = `groq-${rule.id}`;
|
|
114
|
+
eslintRules[eslintRuleId] = createESLintRule(rule);
|
|
115
|
+
}
|
|
116
|
+
return eslintRules;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/utils/schema-rule-factory.ts
|
|
120
|
+
var import_schema_lint = require("@sanity/schema-lint");
|
|
121
|
+
|
|
122
|
+
// src/utils/schema-extractor.ts
|
|
123
|
+
function isDefineTypeCall(node) {
|
|
124
|
+
const callee = node.callee;
|
|
125
|
+
if (callee.type === "Identifier" && callee.name === "defineType") {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
function isDefineFieldCall(node) {
|
|
131
|
+
const callee = node.callee;
|
|
132
|
+
if (callee.type === "Identifier" && callee.name === "defineField") {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
function toSourceSpan(loc) {
|
|
138
|
+
return {
|
|
139
|
+
start: {
|
|
140
|
+
line: loc.start.line,
|
|
141
|
+
column: loc.start.column + 1,
|
|
142
|
+
// 1-based
|
|
143
|
+
offset: 0
|
|
144
|
+
// We don't have offset info easily
|
|
145
|
+
},
|
|
146
|
+
end: {
|
|
147
|
+
line: loc.end.line,
|
|
148
|
+
column: loc.end.column + 1,
|
|
149
|
+
// 1-based
|
|
150
|
+
offset: 0
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function extractStringValue(node) {
|
|
155
|
+
if (!node) return void 0;
|
|
156
|
+
if (node.type === "Literal" && typeof node.value === "string") {
|
|
157
|
+
return node.value;
|
|
158
|
+
}
|
|
159
|
+
if (node.type === "TemplateLiteral" && node.expressions.length === 0) {
|
|
160
|
+
return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw;
|
|
161
|
+
}
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
function extractBooleanValue(node) {
|
|
165
|
+
if (!node) return void 0;
|
|
166
|
+
if (node.type === "Literal" && typeof node.value === "boolean") {
|
|
167
|
+
return node.value;
|
|
168
|
+
}
|
|
169
|
+
return void 0;
|
|
170
|
+
}
|
|
171
|
+
function hasProperty(node, name) {
|
|
172
|
+
return node.properties.some((prop) => {
|
|
173
|
+
if (prop.type === "Property" && prop.key.type === "Identifier") {
|
|
174
|
+
return prop.key.name === name;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function getProperty(node, name) {
|
|
180
|
+
for (const prop of node.properties) {
|
|
181
|
+
if (prop.type === "Property" && prop.key.type === "Identifier" && prop.key.name === name) {
|
|
182
|
+
return prop.value;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return void 0;
|
|
186
|
+
}
|
|
187
|
+
function extractFieldOptions(optionsNode) {
|
|
188
|
+
if (!optionsNode || optionsNode.type !== "ObjectExpression") {
|
|
189
|
+
return void 0;
|
|
190
|
+
}
|
|
191
|
+
const options = {};
|
|
192
|
+
for (const prop of optionsNode.properties) {
|
|
193
|
+
if (prop.type === "Property" && prop.key.type === "Identifier") {
|
|
194
|
+
const name = prop.key.name;
|
|
195
|
+
if (name === "source") {
|
|
196
|
+
const source = extractStringValue(prop.value);
|
|
197
|
+
if (source !== void 0) options.source = source;
|
|
198
|
+
} else if (name === "hotspot") {
|
|
199
|
+
const hotspot = extractBooleanValue(prop.value);
|
|
200
|
+
if (hotspot !== void 0) options.hotspot = hotspot;
|
|
201
|
+
} else if (name === "layout") {
|
|
202
|
+
const layout = extractStringValue(prop.value);
|
|
203
|
+
if (layout !== void 0) options.layout = layout;
|
|
204
|
+
} else if (name === "list" && prop.value.type === "ArrayExpression") {
|
|
205
|
+
options.list = prop.value.elements.map((el) => {
|
|
206
|
+
if (!el) return null;
|
|
207
|
+
if (el.type === "Literal") return el.value;
|
|
208
|
+
if (el.type === "ObjectExpression") {
|
|
209
|
+
const value = extractStringValue(getProperty(el, "value"));
|
|
210
|
+
return { value };
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return Object.keys(options).length > 0 ? options : void 0;
|
|
218
|
+
}
|
|
219
|
+
function extractField(node, usesDefineField) {
|
|
220
|
+
let fieldObj;
|
|
221
|
+
if (node.type === "CallExpression" && isDefineFieldCall(node)) {
|
|
222
|
+
const arg = node.arguments[0];
|
|
223
|
+
if (arg?.type === "ObjectExpression") {
|
|
224
|
+
fieldObj = arg;
|
|
225
|
+
}
|
|
226
|
+
} else if (node.type === "ObjectExpression") {
|
|
227
|
+
fieldObj = node;
|
|
228
|
+
usesDefineField.value = false;
|
|
229
|
+
}
|
|
230
|
+
if (!fieldObj) return void 0;
|
|
231
|
+
const name = extractStringValue(getProperty(fieldObj, "name"));
|
|
232
|
+
const type = extractStringValue(getProperty(fieldObj, "type"));
|
|
233
|
+
if (!name || !type) return void 0;
|
|
234
|
+
const title = extractStringValue(getProperty(fieldObj, "title"));
|
|
235
|
+
const description = extractStringValue(getProperty(fieldObj, "description"));
|
|
236
|
+
const options = extractFieldOptions(getProperty(fieldObj, "options"));
|
|
237
|
+
const field = {
|
|
238
|
+
name,
|
|
239
|
+
type,
|
|
240
|
+
hasValidation: hasProperty(fieldObj, "validation"),
|
|
241
|
+
hidden: hasProperty(fieldObj, "hidden"),
|
|
242
|
+
readOnly: hasProperty(fieldObj, "readOnly"),
|
|
243
|
+
span: toSourceSpan(fieldObj.loc),
|
|
244
|
+
...title !== void 0 && { title },
|
|
245
|
+
...description !== void 0 && { description },
|
|
246
|
+
...options !== void 0 && { options }
|
|
247
|
+
};
|
|
248
|
+
if (hasProperty(fieldObj, "deprecated")) {
|
|
249
|
+
const deprecatedNode = getProperty(fieldObj, "deprecated");
|
|
250
|
+
const deprecatedValue = extractStringValue(deprecatedNode);
|
|
251
|
+
field.deprecated = deprecatedValue ?? true;
|
|
252
|
+
}
|
|
253
|
+
return field;
|
|
254
|
+
}
|
|
255
|
+
function extractFields(node) {
|
|
256
|
+
const result = { fields: [], usesDefineField: true };
|
|
257
|
+
if (!node || node.type !== "ArrayExpression") {
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
const usesDefineFieldTracker = { value: true };
|
|
261
|
+
for (const element of node.elements) {
|
|
262
|
+
if (element) {
|
|
263
|
+
const field = extractField(element, usesDefineFieldTracker);
|
|
264
|
+
if (field) {
|
|
265
|
+
result.fields.push(field);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
result.usesDefineField = usesDefineFieldTracker.value;
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
function extractSchemaFromDefineType(node) {
|
|
273
|
+
const arg = node.arguments[0];
|
|
274
|
+
if (!arg || arg.type !== "ObjectExpression") {
|
|
275
|
+
return void 0;
|
|
276
|
+
}
|
|
277
|
+
const name = extractStringValue(getProperty(arg, "name"));
|
|
278
|
+
const type = extractStringValue(getProperty(arg, "type"));
|
|
279
|
+
if (!name || !type) {
|
|
280
|
+
return void 0;
|
|
281
|
+
}
|
|
282
|
+
const title = extractStringValue(getProperty(arg, "title"));
|
|
283
|
+
const description = extractStringValue(getProperty(arg, "description"));
|
|
284
|
+
const fieldsResult = extractFields(getProperty(arg, "fields"));
|
|
285
|
+
const hasFields = fieldsResult.fields.length > 0;
|
|
286
|
+
const schema = {
|
|
287
|
+
name,
|
|
288
|
+
type,
|
|
289
|
+
hasIcon: hasProperty(arg, "icon"),
|
|
290
|
+
hasPreview: hasProperty(arg, "preview"),
|
|
291
|
+
usesDefineType: true,
|
|
292
|
+
span: toSourceSpan(arg.loc),
|
|
293
|
+
...title !== void 0 && { title },
|
|
294
|
+
...description !== void 0 && { description },
|
|
295
|
+
...hasFields && { fields: fieldsResult.fields },
|
|
296
|
+
...hasFields && { usesDefineField: fieldsResult.usesDefineField }
|
|
297
|
+
};
|
|
298
|
+
return schema;
|
|
299
|
+
}
|
|
300
|
+
function extractSchemaFromObject(node) {
|
|
301
|
+
const name = extractStringValue(getProperty(node, "name"));
|
|
302
|
+
const type = extractStringValue(getProperty(node, "type"));
|
|
303
|
+
if (!name || !type) {
|
|
304
|
+
return void 0;
|
|
305
|
+
}
|
|
306
|
+
const title = extractStringValue(getProperty(node, "title"));
|
|
307
|
+
const description = extractStringValue(getProperty(node, "description"));
|
|
308
|
+
const fieldsResult = extractFields(getProperty(node, "fields"));
|
|
309
|
+
const hasFields = fieldsResult.fields.length > 0;
|
|
310
|
+
const schema = {
|
|
311
|
+
name,
|
|
312
|
+
type,
|
|
313
|
+
hasIcon: hasProperty(node, "icon"),
|
|
314
|
+
hasPreview: hasProperty(node, "preview"),
|
|
315
|
+
usesDefineType: false,
|
|
316
|
+
span: toSourceSpan(node.loc),
|
|
317
|
+
...title !== void 0 && { title },
|
|
318
|
+
...description !== void 0 && { description },
|
|
319
|
+
...hasFields && { fields: fieldsResult.fields },
|
|
320
|
+
...hasFields && { usesDefineField: fieldsResult.usesDefineField }
|
|
321
|
+
};
|
|
322
|
+
return schema;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/utils/schema-rule-factory.ts
|
|
326
|
+
function createSchemaESLintRule(schemaRule) {
|
|
327
|
+
return {
|
|
328
|
+
meta: {
|
|
329
|
+
type: schemaRule.category === "correctness" ? "problem" : "suggestion",
|
|
330
|
+
docs: {
|
|
331
|
+
description: schemaRule.description,
|
|
332
|
+
recommended: schemaRule.severity === "error"
|
|
333
|
+
},
|
|
334
|
+
messages: {
|
|
335
|
+
[schemaRule.id]: "{{ message }}"
|
|
336
|
+
},
|
|
337
|
+
schema: []
|
|
338
|
+
// No options for now
|
|
339
|
+
},
|
|
340
|
+
create(context) {
|
|
341
|
+
return {
|
|
342
|
+
// Handle defineType() calls
|
|
343
|
+
CallExpression(eslintNode) {
|
|
344
|
+
const node = eslintNode;
|
|
345
|
+
if (!isDefineTypeCall(node)) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
try {
|
|
349
|
+
const schema = extractSchemaFromDefineType(node);
|
|
350
|
+
if (!schema) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const result = (0, import_schema_lint.lint)(schema, import_schema_lint.rules, {
|
|
354
|
+
rules: [schemaRule],
|
|
355
|
+
filePath: context.filename
|
|
356
|
+
});
|
|
357
|
+
for (const finding of result.findings) {
|
|
358
|
+
if (finding.ruleId === schemaRule.id) {
|
|
359
|
+
context.report({
|
|
360
|
+
node: eslintNode,
|
|
361
|
+
messageId: schemaRule.id,
|
|
362
|
+
data: {
|
|
363
|
+
message: finding.help ? `${finding.message} ${finding.help}` : finding.message
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
// Handle export statements with object literals (not using defineType)
|
|
372
|
+
ExportNamedDeclaration(eslintNode) {
|
|
373
|
+
const node = eslintNode;
|
|
374
|
+
if (schemaRule.id !== "missing-define-type") {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (!node.declaration) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (node.declaration.type === "VariableDeclaration") {
|
|
381
|
+
for (const declarator of node.declaration.declarations) {
|
|
382
|
+
if (declarator.init?.type === "ObjectExpression" && !isWrappedInDefineType(declarator.init)) {
|
|
383
|
+
const schema = extractSchemaFromObject(declarator.init);
|
|
384
|
+
if (schema && (schema.type === "document" || schema.type === "object")) {
|
|
385
|
+
try {
|
|
386
|
+
const result = (0, import_schema_lint.lint)(schema, import_schema_lint.rules, {
|
|
387
|
+
rules: [schemaRule],
|
|
388
|
+
filePath: context.filename
|
|
389
|
+
});
|
|
390
|
+
for (const finding of result.findings) {
|
|
391
|
+
if (finding.ruleId === schemaRule.id) {
|
|
392
|
+
context.report({
|
|
393
|
+
node: eslintNode,
|
|
394
|
+
messageId: schemaRule.id,
|
|
395
|
+
data: {
|
|
396
|
+
message: finding.help ? `${finding.message} ${finding.help}` : finding.message
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
} catch {
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
// Handle default exports with object literals
|
|
409
|
+
ExportDefaultDeclaration(eslintNode) {
|
|
410
|
+
const node = eslintNode;
|
|
411
|
+
if (schemaRule.id !== "missing-define-type") {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (node.declaration.type === "ObjectExpression") {
|
|
415
|
+
const schema = extractSchemaFromObject(node.declaration);
|
|
416
|
+
if (schema && (schema.type === "document" || schema.type === "object")) {
|
|
417
|
+
try {
|
|
418
|
+
const result = (0, import_schema_lint.lint)(schema, import_schema_lint.rules, {
|
|
419
|
+
rules: [schemaRule],
|
|
420
|
+
filePath: context.filename
|
|
421
|
+
});
|
|
422
|
+
for (const finding of result.findings) {
|
|
423
|
+
if (finding.ruleId === schemaRule.id) {
|
|
424
|
+
context.report({
|
|
425
|
+
node: eslintNode,
|
|
426
|
+
messageId: schemaRule.id,
|
|
427
|
+
data: {
|
|
428
|
+
message: finding.help ? `${finding.message} ${finding.help}` : finding.message
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
} catch {
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function isWrappedInDefineType(_node) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
function createAllSchemaRules(rules2) {
|
|
446
|
+
const eslintRules = {};
|
|
447
|
+
for (const rule of rules2) {
|
|
448
|
+
const eslintRuleId = `schema-${rule.id}`;
|
|
449
|
+
eslintRules[eslintRuleId] = createSchemaESLintRule(rule);
|
|
450
|
+
}
|
|
451
|
+
return eslintRules;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/index.ts
|
|
455
|
+
var version = true ? "0.0.3" : "0.0.0";
|
|
456
|
+
var groqEslintRules = createAllRules(import_groq_lint2.rules);
|
|
457
|
+
var schemaEslintRules = createAllSchemaRules(import_schema_lint2.rules);
|
|
458
|
+
var rules = {
|
|
459
|
+
...groqEslintRules,
|
|
460
|
+
...schemaEslintRules
|
|
461
|
+
};
|
|
462
|
+
var plugin = {
|
|
463
|
+
meta: {
|
|
464
|
+
name: "eslint-plugin-sanity",
|
|
465
|
+
version
|
|
466
|
+
},
|
|
467
|
+
rules
|
|
468
|
+
};
|
|
469
|
+
var recommended = {
|
|
470
|
+
plugins: {
|
|
471
|
+
sanity: plugin
|
|
472
|
+
},
|
|
473
|
+
rules: {
|
|
474
|
+
// === GROQ Rules ===
|
|
475
|
+
// Errors - these are serious performance or correctness issues
|
|
476
|
+
"sanity/groq-join-in-filter": "error",
|
|
477
|
+
// Warnings - performance issues that should be addressed
|
|
478
|
+
"sanity/groq-deep-pagination": "warn",
|
|
479
|
+
"sanity/groq-large-pages": "warn",
|
|
480
|
+
"sanity/groq-many-joins": "warn",
|
|
481
|
+
"sanity/groq-computed-value-in-filter": "warn",
|
|
482
|
+
"sanity/groq-non-literal-comparison": "warn",
|
|
483
|
+
"sanity/groq-order-on-expr": "warn",
|
|
484
|
+
"sanity/groq-very-large-query": "warn",
|
|
485
|
+
"sanity/groq-extremely-large-query": "error",
|
|
486
|
+
// Info - suggestions for improvement (off by default, enable as warnings)
|
|
487
|
+
"sanity/groq-join-to-get-id": "warn",
|
|
488
|
+
"sanity/groq-repeated-dereference": "warn",
|
|
489
|
+
"sanity/groq-match-on-id": "warn",
|
|
490
|
+
"sanity/groq-count-in-correlated-subquery": "warn",
|
|
491
|
+
"sanity/groq-deep-pagination-param": "warn",
|
|
492
|
+
// === Schema Rules ===
|
|
493
|
+
// Errors - correctness issues
|
|
494
|
+
"sanity/schema-missing-define-type": "error",
|
|
495
|
+
"sanity/schema-missing-define-field": "error",
|
|
496
|
+
"sanity/schema-reserved-field-name": "error",
|
|
497
|
+
// Warnings - best practice violations
|
|
498
|
+
"sanity/schema-missing-icon": "warn",
|
|
499
|
+
"sanity/schema-missing-title": "warn",
|
|
500
|
+
"sanity/schema-presentation-field-name": "warn",
|
|
501
|
+
"sanity/schema-missing-slug-source": "warn",
|
|
502
|
+
"sanity/schema-missing-required-validation": "warn",
|
|
503
|
+
"sanity/schema-heading-level-in-schema": "warn",
|
|
504
|
+
// Info - suggestions (off by default)
|
|
505
|
+
"sanity/schema-missing-description": "off",
|
|
506
|
+
"sanity/schema-boolean-instead-of-list": "off",
|
|
507
|
+
"sanity/schema-array-missing-constraints": "off",
|
|
508
|
+
"sanity/schema-unnecessary-reference": "off"
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
var strict = {
|
|
512
|
+
plugins: {
|
|
513
|
+
sanity: plugin
|
|
514
|
+
},
|
|
515
|
+
rules: Object.fromEntries(Object.keys(rules).map((ruleId) => [`sanity/${ruleId}`, "error"]))
|
|
516
|
+
};
|
|
517
|
+
var configs = {
|
|
518
|
+
recommended,
|
|
519
|
+
strict
|
|
520
|
+
};
|
|
521
|
+
var sanityPlugin = {
|
|
522
|
+
meta: plugin.meta,
|
|
523
|
+
rules,
|
|
524
|
+
configs
|
|
525
|
+
};
|
|
526
|
+
var index_default = sanityPlugin;
|
|
527
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
528
|
+
0 && (module.exports = {
|
|
529
|
+
configs,
|
|
530
|
+
rules
|
|
531
|
+
});
|
|
532
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/rule-factory.ts","../src/utils/groq-extractor.ts","../src/utils/schema-rule-factory.ts","../src/utils/schema-extractor.ts"],"sourcesContent":["/**\n * ESLint plugin for Sanity\n *\n * This plugin provides rules for linting GROQ queries and schema definitions\n * in JavaScript/TypeScript files.\n *\n * @example\n * ```js\n * // eslint.config.js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * {\n * plugins: { sanity },\n * rules: {\n * 'sanity/groq-join-in-filter': 'error',\n * 'sanity/schema-missing-icon': 'warn',\n * },\n * },\n * ]\n * ```\n *\n * Or use the recommended config:\n * ```js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * sanity.configs.recommended,\n * ]\n * ```\n */\n\nimport type { ESLint, Linter } from 'eslint'\nimport { rules as groqRules } from '@sanity/groq-lint'\nimport { rules as schemaRules } from '@sanity/schema-lint'\nimport { createAllRules } from './utils/rule-factory'\nimport { createAllSchemaRules } from './utils/schema-rule-factory'\n\n// Version is injected at build time by tsup\ndeclare const PACKAGE_VERSION: string\nconst version = typeof PACKAGE_VERSION !== 'undefined' ? PACKAGE_VERSION : '0.0.0'\n\n// Create ESLint rules from all GROQ lint rules\nconst groqEslintRules = createAllRules(groqRules)\n\n// Create ESLint rules from all schema lint rules\nconst schemaEslintRules = createAllSchemaRules(schemaRules)\n\n// Combine all rules\nconst rules = {\n ...groqEslintRules,\n ...schemaEslintRules,\n}\n\n// Build the plugin object\nconst plugin: ESLint.Plugin = {\n meta: {\n name: 'eslint-plugin-sanity',\n version,\n },\n rules,\n}\n\n// Create recommended config\nconst recommended: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: {\n // === GROQ Rules ===\n\n // Errors - these are serious performance or correctness issues\n 'sanity/groq-join-in-filter': 'error',\n\n // Warnings - performance issues that should be addressed\n 'sanity/groq-deep-pagination': 'warn',\n 'sanity/groq-large-pages': 'warn',\n 'sanity/groq-many-joins': 'warn',\n 'sanity/groq-computed-value-in-filter': 'warn',\n 'sanity/groq-non-literal-comparison': 'warn',\n 'sanity/groq-order-on-expr': 'warn',\n 'sanity/groq-very-large-query': 'warn',\n 'sanity/groq-extremely-large-query': 'error',\n\n // Info - suggestions for improvement (off by default, enable as warnings)\n 'sanity/groq-join-to-get-id': 'warn',\n 'sanity/groq-repeated-dereference': 'warn',\n 'sanity/groq-match-on-id': 'warn',\n 'sanity/groq-count-in-correlated-subquery': 'warn',\n 'sanity/groq-deep-pagination-param': 'warn',\n\n // === Schema Rules ===\n\n // Errors - correctness issues\n 'sanity/schema-missing-define-type': 'error',\n 'sanity/schema-missing-define-field': 'error',\n 'sanity/schema-reserved-field-name': 'error',\n\n // Warnings - best practice violations\n 'sanity/schema-missing-icon': 'warn',\n 'sanity/schema-missing-title': 'warn',\n 'sanity/schema-presentation-field-name': 'warn',\n 'sanity/schema-missing-slug-source': 'warn',\n 'sanity/schema-missing-required-validation': 'warn',\n 'sanity/schema-heading-level-in-schema': 'warn',\n\n // Info - suggestions (off by default)\n 'sanity/schema-missing-description': 'off',\n 'sanity/schema-boolean-instead-of-list': 'off',\n 'sanity/schema-array-missing-constraints': 'off',\n 'sanity/schema-unnecessary-reference': 'off',\n },\n}\n\n// Create strict config (all rules as errors)\nconst strict: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: Object.fromEntries(Object.keys(rules).map((ruleId) => [`sanity/${ruleId}`, 'error'])),\n}\n\n// Configs with explicit type annotation\nconst configs: { recommended: Linter.Config; strict: Linter.Config } = {\n recommended,\n strict,\n}\n\n// Plugin type\ninterface SanityPlugin {\n meta: ESLint.Plugin['meta']\n rules: typeof rules\n configs: typeof configs\n}\n\n// Default export for ESLint flat config\nconst sanityPlugin: SanityPlugin = {\n meta: plugin.meta,\n rules,\n configs,\n}\n\nexport default sanityPlugin\n\n// Named exports for flexibility\nexport { rules, configs }\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { Rule as GroqRule } from '@sanity/groq-lint'\nimport { lint, rules as allGroqRules } from '@sanity/groq-lint'\nimport { isGroqTaggedTemplate, extractGroqString } from './groq-extractor'\n\n/**\n * Build a config that enables only the specified rule\n */\nfunction buildSingleRuleConfig(ruleId: string): Record<string, boolean> {\n const config: Record<string, boolean> = {}\n for (const rule of allGroqRules) {\n config[rule.id] = rule.id === ruleId\n }\n return config\n}\n\n/**\n * Create an ESLint rule from a GROQ lint rule.\n */\nexport function createESLintRule(groqRule: GroqRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: groqRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: groqRule.description,\n recommended: groqRule.severity === 'error',\n },\n messages: {\n [groqRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n TaggedTemplateExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.TaggedTemplateExpression\n if (!isGroqTaggedTemplate(node)) {\n return\n }\n\n try {\n const query = extractGroqString(node)\n const result = lint(query, { config: { rules: buildSingleRuleConfig(groqRule.id) } })\n\n for (const finding of result.findings) {\n if (finding.ruleId === groqRule.id) {\n context.report({\n node: eslintNode,\n messageId: groqRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report, let the user see it in runtime\n }\n },\n }\n },\n }\n}\n\n/**\n * Create all ESLint rules from GROQ lint rules.\n */\nexport function createAllRules(groqRules: GroqRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of groqRules) {\n // Convert rule ID from snake_case to kebab-case for ESLint convention\n const eslintRuleId = `groq-${rule.id}`\n eslintRules[eslintRuleId] = createESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\n\n/**\n * Check if a node is a tagged template literal with a GROQ tag.\n * Matches: groq`...`, groq.something`...`\n */\nexport function isGroqTaggedTemplate(node: TSESTree.TaggedTemplateExpression): boolean {\n const tag = node.tag\n\n // groq`...`\n if (tag.type === 'Identifier' && tag.name === 'groq') {\n return true\n }\n\n // groq.something`...` (for groq.experimental etc)\n if (\n tag.type === 'MemberExpression' &&\n tag.object.type === 'Identifier' &&\n tag.object.name === 'groq'\n ) {\n return true\n }\n\n return false\n}\n\n/**\n * Extract the GROQ query string from a tagged template literal.\n * Handles template literals with expressions by replacing them with placeholders.\n */\nexport function extractGroqString(node: TSESTree.TaggedTemplateExpression): string {\n const { quasis, expressions } = node.quasi\n\n // Simple case: no expressions\n if (expressions.length === 0) {\n return quasis[0]?.value.cooked ?? quasis[0]?.value.raw ?? ''\n }\n\n // Build the string with placeholders for expressions\n let result = ''\n for (let i = 0; i < quasis.length; i++) {\n result += quasis[i]?.value.cooked ?? quasis[i]?.value.raw ?? ''\n if (i < expressions.length) {\n // Replace expression with a parameter placeholder\n // This allows the query to still parse while marking where expressions are\n result += `$__expr${i}__`\n }\n }\n\n return result\n}\n\n/**\n * Get the source location for reporting errors.\n * Returns the location of the template literal content, not the tag.\n */\nexport function getTemplateLocation(\n node: TSESTree.TaggedTemplateExpression\n): TSESTree.SourceLocation {\n return node.quasi.loc\n}\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaRule } from '@sanity/schema-lint'\nimport { lint, rules as schemaRules } from '@sanity/schema-lint'\nimport {\n isDefineTypeCall,\n extractSchemaFromDefineType,\n extractSchemaFromObject,\n} from './schema-extractor'\n\n/**\n * Create an ESLint rule from a schema lint rule.\n */\nexport function createSchemaESLintRule(schemaRule: SchemaRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: schemaRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: schemaRule.description,\n recommended: schemaRule.severity === 'error',\n },\n messages: {\n [schemaRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n // Handle defineType() calls\n CallExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.CallExpression\n if (!isDefineTypeCall(node)) {\n return\n }\n\n try {\n const schema = extractSchemaFromDefineType(node)\n if (!schema) {\n return\n }\n\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n },\n\n // Handle export statements with object literals (not using defineType)\n ExportNamedDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportNamedDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (!node.declaration) {\n return\n }\n\n // export const foo = { name: '...', type: '...' }\n if (node.declaration.type === 'VariableDeclaration') {\n for (const declarator of node.declaration.declarations) {\n if (\n declarator.init?.type === 'ObjectExpression' &&\n !isWrappedInDefineType(declarator.init)\n ) {\n const schema = extractSchemaFromObject(declarator.init)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n }\n }\n },\n\n // Handle default exports with object literals\n ExportDefaultDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportDefaultDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (node.declaration.type === 'ObjectExpression') {\n const schema = extractSchemaFromObject(node.declaration)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n },\n }\n },\n }\n}\n\n/**\n * Check if an object expression's parent is a defineType() call\n */\nfunction isWrappedInDefineType(_node: TSESTree.ObjectExpression): boolean {\n // This is a simplified check - in practice we check by seeing if\n // the parent is a CallExpression with defineType callee\n // For now we rely on the CallExpression handler\n return false\n}\n\n/**\n * Create all ESLint rules from schema lint rules.\n */\nexport function createAllSchemaRules(rules: SchemaRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of rules) {\n // Use schema- prefix to distinguish from groq- rules\n const eslintRuleId = `schema-${rule.id}`\n eslintRules[eslintRuleId] = createSchemaESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaType, SchemaField } from '@sanity/schema-lint'\nimport type { SourceSpan } from '@sanity/lint-core'\n\n/**\n * Check if a node is a defineType() call\n */\nexport function isDefineTypeCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineType({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineType') {\n return true\n }\n\n return false\n}\n\n/**\n * Check if a node is a defineField() call\n */\nexport function isDefineFieldCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineField({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineField') {\n return true\n }\n\n return false\n}\n\n/**\n * Convert ESLint location to our SourceSpan format\n */\nfunction toSourceSpan(loc: TSESTree.SourceLocation): SourceSpan {\n return {\n start: {\n line: loc.start.line,\n column: loc.start.column + 1, // 1-based\n offset: 0, // We don't have offset info easily\n },\n end: {\n line: loc.end.line,\n column: loc.end.column + 1, // 1-based\n offset: 0,\n },\n }\n}\n\n/**\n * Extract a string value from an AST node\n */\nfunction extractStringValue(node: TSESTree.Node | undefined): string | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'string') {\n return node.value\n }\n\n // Handle template literals without expressions\n if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {\n return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw\n }\n\n return undefined\n}\n\n/**\n * Extract a boolean value from an AST node\n */\nfunction extractBooleanValue(node: TSESTree.Node | undefined): boolean | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'boolean') {\n return node.value\n }\n\n return undefined\n}\n\n/**\n * Check if a property exists in an object expression\n */\nfunction hasProperty(node: TSESTree.ObjectExpression, name: string): boolean {\n return node.properties.some((prop) => {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n return prop.key.name === name\n }\n return false\n })\n}\n\n/**\n * Get a property value from an object expression\n */\nfunction getProperty(node: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined {\n for (const prop of node.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier' && prop.key.name === name) {\n return prop.value\n }\n }\n return undefined\n}\n\n/**\n * Extract field options from an object expression\n */\nfunction extractFieldOptions(\n optionsNode: TSESTree.Node | undefined\n): SchemaField['options'] | undefined {\n if (!optionsNode || optionsNode.type !== 'ObjectExpression') {\n return undefined\n }\n\n const options: NonNullable<SchemaField['options']> = {}\n\n for (const prop of optionsNode.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n const name = prop.key.name\n\n if (name === 'source') {\n const source = extractStringValue(prop.value)\n if (source !== undefined) options.source = source\n } else if (name === 'hotspot') {\n const hotspot = extractBooleanValue(prop.value)\n if (hotspot !== undefined) options.hotspot = hotspot\n } else if (name === 'layout') {\n const layout = extractStringValue(prop.value)\n if (layout !== undefined) options.layout = layout\n } else if (name === 'list' && prop.value.type === 'ArrayExpression') {\n options.list = prop.value.elements.map((el) => {\n if (!el) return null\n if (el.type === 'Literal') return el.value\n if (el.type === 'ObjectExpression') {\n const value = extractStringValue(getProperty(el, 'value'))\n return { value }\n }\n return null\n })\n }\n }\n }\n\n return Object.keys(options).length > 0 ? options : undefined\n}\n\n/**\n * Extract a field from an object expression (either raw or wrapped in defineField)\n */\nfunction extractField(\n node: TSESTree.Node,\n usesDefineField: { value: boolean }\n): SchemaField | undefined {\n let fieldObj: TSESTree.ObjectExpression | undefined\n\n // Check if it's wrapped in defineField()\n if (node.type === 'CallExpression' && isDefineFieldCall(node)) {\n const arg = node.arguments[0]\n if (arg?.type === 'ObjectExpression') {\n fieldObj = arg\n }\n } else if (node.type === 'ObjectExpression') {\n fieldObj = node\n usesDefineField.value = false // At least one field doesn't use defineField\n }\n\n if (!fieldObj) return undefined\n\n const name = extractStringValue(getProperty(fieldObj, 'name'))\n const type = extractStringValue(getProperty(fieldObj, 'type'))\n\n if (!name || !type) return undefined\n\n const title = extractStringValue(getProperty(fieldObj, 'title'))\n const description = extractStringValue(getProperty(fieldObj, 'description'))\n const options = extractFieldOptions(getProperty(fieldObj, 'options'))\n\n const field: SchemaField = {\n name,\n type,\n hasValidation: hasProperty(fieldObj, 'validation'),\n hidden: hasProperty(fieldObj, 'hidden'),\n readOnly: hasProperty(fieldObj, 'readOnly'),\n span: toSourceSpan(fieldObj.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(options !== undefined && { options }),\n }\n\n // Check for deprecated\n if (hasProperty(fieldObj, 'deprecated')) {\n const deprecatedNode = getProperty(fieldObj, 'deprecated')\n const deprecatedValue = extractStringValue(deprecatedNode)\n field.deprecated = deprecatedValue ?? true\n }\n\n return field\n}\n\n/**\n * Extract fields from an array expression\n */\nfunction extractFields(node: TSESTree.Node | undefined): {\n fields: SchemaField[]\n usesDefineField: boolean\n} {\n const result = { fields: [] as SchemaField[], usesDefineField: true }\n\n if (!node || node.type !== 'ArrayExpression') {\n return result\n }\n\n const usesDefineFieldTracker = { value: true }\n\n for (const element of node.elements) {\n if (element) {\n const field = extractField(element, usesDefineFieldTracker)\n if (field) {\n result.fields.push(field)\n }\n }\n }\n\n result.usesDefineField = usesDefineFieldTracker.value\n\n return result\n}\n\n/**\n * Extract schema type from a defineType() call\n */\nexport function extractSchemaFromDefineType(node: TSESTree.CallExpression): SchemaType | undefined {\n const arg = node.arguments[0]\n\n if (!arg || arg.type !== 'ObjectExpression') {\n return undefined\n }\n\n const name = extractStringValue(getProperty(arg, 'name'))\n const type = extractStringValue(getProperty(arg, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n const title = extractStringValue(getProperty(arg, 'title'))\n const description = extractStringValue(getProperty(arg, 'description'))\n const fieldsResult = extractFields(getProperty(arg, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(arg, 'icon'),\n hasPreview: hasProperty(arg, 'preview'),\n usesDefineType: true,\n span: toSourceSpan(arg.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n\n/**\n * Extract schema type from a plain object literal (not wrapped in defineType)\n */\nexport function extractSchemaFromObject(node: TSESTree.ObjectExpression): SchemaType | undefined {\n const name = extractStringValue(getProperty(node, 'name'))\n const type = extractStringValue(getProperty(node, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n // Only process if it looks like a Sanity schema (has name and type)\n const title = extractStringValue(getProperty(node, 'title'))\n const description = extractStringValue(getProperty(node, 'description'))\n const fieldsResult = extractFields(getProperty(node, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(node, 'icon'),\n hasPreview: hasProperty(node, 'preview'),\n usesDefineType: false,\n span: toSourceSpan(node.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCA,IAAAA,oBAAmC;AACnC,IAAAC,sBAAqC;;;AC/BrC,uBAA4C;;;ACGrC,SAAS,qBAAqB,MAAkD;AACrF,QAAM,MAAM,KAAK;AAGjB,MAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,QAAQ;AACpD,WAAO;AAAA,EACT;AAGA,MACE,IAAI,SAAS,sBACb,IAAI,OAAO,SAAS,gBACpB,IAAI,OAAO,SAAS,QACpB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,SAAS,kBAAkB,MAAiD;AACjF,QAAM,EAAE,QAAQ,YAAY,IAAI,KAAK;AAGrC,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,OAAO,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC,GAAG,MAAM,OAAO;AAAA,EAC5D;AAGA,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAU,OAAO,CAAC,GAAG,MAAM,UAAU,OAAO,CAAC,GAAG,MAAM,OAAO;AAC7D,QAAI,IAAI,YAAY,QAAQ;AAG1B,gBAAU,UAAU,CAAC;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AACT;;;ADzCA,SAAS,sBAAsB,QAAyC;AACtE,QAAM,SAAkC,CAAC;AACzC,aAAW,QAAQ,iBAAAC,OAAc;AAC/B,WAAO,KAAK,EAAE,IAAI,KAAK,OAAO;AAAA,EAChC;AACA,SAAO;AACT;AAKO,SAAS,iBAAiB,UAA2C;AAC1E,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,MAAM,SAAS,aAAa,gBAAgB,YAAY;AAAA,MACxD,MAAM;AAAA,QACJ,aAAa,SAAS;AAAA,QACtB,aAAa,SAAS,aAAa;AAAA,MACrC;AAAA,MACA,UAAU;AAAA,QACR,CAAC,SAAS,EAAE,GAAG;AAAA,MACjB;AAAA,MACA,QAAQ,CAAC;AAAA;AAAA,IACX;AAAA,IAEA,OAAO,SAAS;AACd,aAAO;AAAA,QACL,yBAAyB,YAA6B;AAEpD,gBAAM,OAAO;AACb,cAAI,CAAC,qBAAqB,IAAI,GAAG;AAC/B;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,QAAQ,kBAAkB,IAAI;AACpC,kBAAM,aAAS,uBAAK,OAAO,EAAE,QAAQ,EAAE,OAAO,sBAAsB,SAAS,EAAE,EAAE,EAAE,CAAC;AAEpF,uBAAW,WAAW,OAAO,UAAU;AACrC,kBAAI,QAAQ,WAAW,SAAS,IAAI;AAClC,wBAAQ,OAAO;AAAA,kBACb,MAAM;AAAA,kBACN,WAAW,SAAS;AAAA,kBACpB,MAAM;AAAA,oBACJ,SAAS,QAAQ,OAAO,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAAA,kBACzE;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,eAAeC,YAA8D;AAC3F,QAAM,cAAqD,CAAC;AAE5D,aAAW,QAAQA,YAAW;AAE5B,UAAM,eAAe,QAAQ,KAAK,EAAE;AACpC,gBAAY,YAAY,IAAI,iBAAiB,IAAI;AAAA,EACnD;AAEA,SAAO;AACT;;;AE7EA,yBAA2C;;;ACIpC,SAAS,iBAAiB,MAAwC;AACvE,QAAM,SAAS,KAAK;AAGpB,MAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,cAAc;AAChE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,kBAAkB,MAAwC;AACxE,QAAM,SAAS,KAAK;AAGpB,MAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,eAAe;AACjE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,aAAa,KAA0C;AAC9D,SAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM,IAAI,MAAM;AAAA,MAChB,QAAQ,IAAI,MAAM,SAAS;AAAA;AAAA,MAC3B,QAAQ;AAAA;AAAA,IACV;AAAA,IACA,KAAK;AAAA,MACH,MAAM,IAAI,IAAI;AAAA,MACd,QAAQ,IAAI,IAAI,SAAS;AAAA;AAAA,MACzB,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAKA,SAAS,mBAAmB,MAAqD;AAC/E,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,UAAU;AAC7D,WAAO,KAAK;AAAA,EACd;AAGA,MAAI,KAAK,SAAS,qBAAqB,KAAK,YAAY,WAAW,GAAG;AACpE,WAAO,KAAK,OAAO,CAAC,GAAG,MAAM,UAAU,KAAK,OAAO,CAAC,GAAG,MAAM;AAAA,EAC/D;AAEA,SAAO;AACT;AAKA,SAAS,oBAAoB,MAAsD;AACjF,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,WAAW;AAC9D,WAAO,KAAK;AAAA,EACd;AAEA,SAAO;AACT;AAKA,SAAS,YAAY,MAAiC,MAAuB;AAC3E,SAAO,KAAK,WAAW,KAAK,CAAC,SAAS;AACpC,QAAI,KAAK,SAAS,cAAc,KAAK,IAAI,SAAS,cAAc;AAC9D,aAAO,KAAK,IAAI,SAAS;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAKA,SAAS,YAAY,MAAiC,MAAyC;AAC7F,aAAW,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,cAAc,KAAK,IAAI,SAAS,gBAAgB,KAAK,IAAI,SAAS,MAAM;AACxF,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,oBACP,aACoC;AACpC,MAAI,CAAC,eAAe,YAAY,SAAS,oBAAoB;AAC3D,WAAO;AAAA,EACT;AAEA,QAAM,UAA+C,CAAC;AAEtD,aAAW,QAAQ,YAAY,YAAY;AACzC,QAAI,KAAK,SAAS,cAAc,KAAK,IAAI,SAAS,cAAc;AAC9D,YAAM,OAAO,KAAK,IAAI;AAEtB,UAAI,SAAS,UAAU;AACrB,cAAM,SAAS,mBAAmB,KAAK,KAAK;AAC5C,YAAI,WAAW,OAAW,SAAQ,SAAS;AAAA,MAC7C,WAAW,SAAS,WAAW;AAC7B,cAAM,UAAU,oBAAoB,KAAK,KAAK;AAC9C,YAAI,YAAY,OAAW,SAAQ,UAAU;AAAA,MAC/C,WAAW,SAAS,UAAU;AAC5B,cAAM,SAAS,mBAAmB,KAAK,KAAK;AAC5C,YAAI,WAAW,OAAW,SAAQ,SAAS;AAAA,MAC7C,WAAW,SAAS,UAAU,KAAK,MAAM,SAAS,mBAAmB;AACnE,gBAAQ,OAAO,KAAK,MAAM,SAAS,IAAI,CAAC,OAAO;AAC7C,cAAI,CAAC,GAAI,QAAO;AAChB,cAAI,GAAG,SAAS,UAAW,QAAO,GAAG;AACrC,cAAI,GAAG,SAAS,oBAAoB;AAClC,kBAAM,QAAQ,mBAAmB,YAAY,IAAI,OAAO,CAAC;AACzD,mBAAO,EAAE,MAAM;AAAA,UACjB;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AACrD;AAKA,SAAS,aACP,MACA,iBACyB;AACzB,MAAI;AAGJ,MAAI,KAAK,SAAS,oBAAoB,kBAAkB,IAAI,GAAG;AAC7D,UAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,QAAI,KAAK,SAAS,oBAAoB;AACpC,iBAAW;AAAA,IACb;AAAA,EACF,WAAW,KAAK,SAAS,oBAAoB;AAC3C,eAAW;AACX,oBAAgB,QAAQ;AAAA,EAC1B;AAEA,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,OAAO,mBAAmB,YAAY,UAAU,MAAM,CAAC;AAC7D,QAAM,OAAO,mBAAmB,YAAY,UAAU,MAAM,CAAC;AAE7D,MAAI,CAAC,QAAQ,CAAC,KAAM,QAAO;AAE3B,QAAM,QAAQ,mBAAmB,YAAY,UAAU,OAAO,CAAC;AAC/D,QAAM,cAAc,mBAAmB,YAAY,UAAU,aAAa,CAAC;AAC3E,QAAM,UAAU,oBAAoB,YAAY,UAAU,SAAS,CAAC;AAEpE,QAAM,QAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,eAAe,YAAY,UAAU,YAAY;AAAA,IACjD,QAAQ,YAAY,UAAU,QAAQ;AAAA,IACtC,UAAU,YAAY,UAAU,UAAU;AAAA,IAC1C,MAAM,aAAa,SAAS,GAAG;AAAA,IAC/B,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACnC,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,IAC/C,GAAI,YAAY,UAAa,EAAE,QAAQ;AAAA,EACzC;AAGA,MAAI,YAAY,UAAU,YAAY,GAAG;AACvC,UAAM,iBAAiB,YAAY,UAAU,YAAY;AACzD,UAAM,kBAAkB,mBAAmB,cAAc;AACzD,UAAM,aAAa,mBAAmB;AAAA,EACxC;AAEA,SAAO;AACT;AAKA,SAAS,cAAc,MAGrB;AACA,QAAM,SAAS,EAAE,QAAQ,CAAC,GAAoB,iBAAiB,KAAK;AAEpE,MAAI,CAAC,QAAQ,KAAK,SAAS,mBAAmB;AAC5C,WAAO;AAAA,EACT;AAEA,QAAM,yBAAyB,EAAE,OAAO,KAAK;AAE7C,aAAW,WAAW,KAAK,UAAU;AACnC,QAAI,SAAS;AACX,YAAM,QAAQ,aAAa,SAAS,sBAAsB;AAC1D,UAAI,OAAO;AACT,eAAO,OAAO,KAAK,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,kBAAkB,uBAAuB;AAEhD,SAAO;AACT;AAKO,SAAS,4BAA4B,MAAuD;AACjG,QAAM,MAAM,KAAK,UAAU,CAAC;AAE5B,MAAI,CAAC,OAAO,IAAI,SAAS,oBAAoB;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,mBAAmB,YAAY,KAAK,MAAM,CAAC;AACxD,QAAM,OAAO,mBAAmB,YAAY,KAAK,MAAM,CAAC;AAExD,MAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,mBAAmB,YAAY,KAAK,OAAO,CAAC;AAC1D,QAAM,cAAc,mBAAmB,YAAY,KAAK,aAAa,CAAC;AACtE,QAAM,eAAe,cAAc,YAAY,KAAK,QAAQ,CAAC;AAC7D,QAAM,YAAY,aAAa,OAAO,SAAS;AAE/C,QAAM,SAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,SAAS,YAAY,KAAK,MAAM;AAAA,IAChC,YAAY,YAAY,KAAK,SAAS;AAAA,IACtC,gBAAgB;AAAA,IAChB,MAAM,aAAa,IAAI,GAAG;AAAA,IAC1B,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACnC,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,IAC/C,GAAI,aAAa,EAAE,QAAQ,aAAa,OAAO;AAAA,IAC/C,GAAI,aAAa,EAAE,iBAAiB,aAAa,gBAAgB;AAAA,EACnE;AAEA,SAAO;AACT;AAKO,SAAS,wBAAwB,MAAyD;AAC/F,QAAM,OAAO,mBAAmB,YAAY,MAAM,MAAM,CAAC;AACzD,QAAM,OAAO,mBAAmB,YAAY,MAAM,MAAM,CAAC;AAEzD,MAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,mBAAmB,YAAY,MAAM,OAAO,CAAC;AAC3D,QAAM,cAAc,mBAAmB,YAAY,MAAM,aAAa,CAAC;AACvE,QAAM,eAAe,cAAc,YAAY,MAAM,QAAQ,CAAC;AAC9D,QAAM,YAAY,aAAa,OAAO,SAAS;AAE/C,QAAM,SAAqB;AAAA,IACzB;AAAA,IACA;AAAA,IACA,SAAS,YAAY,MAAM,MAAM;AAAA,IACjC,YAAY,YAAY,MAAM,SAAS;AAAA,IACvC,gBAAgB;AAAA,IAChB,MAAM,aAAa,KAAK,GAAG;AAAA,IAC3B,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACnC,GAAI,gBAAgB,UAAa,EAAE,YAAY;AAAA,IAC/C,GAAI,aAAa,EAAE,QAAQ,aAAa,OAAO;AAAA,IAC/C,GAAI,aAAa,EAAE,iBAAiB,aAAa,gBAAgB;AAAA,EACnE;AAEA,SAAO;AACT;;;AD7RO,SAAS,uBAAuB,YAA+C;AACpF,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,MAAM,WAAW,aAAa,gBAAgB,YAAY;AAAA,MAC1D,MAAM;AAAA,QACJ,aAAa,WAAW;AAAA,QACxB,aAAa,WAAW,aAAa;AAAA,MACvC;AAAA,MACA,UAAU;AAAA,QACR,CAAC,WAAW,EAAE,GAAG;AAAA,MACnB;AAAA,MACA,QAAQ,CAAC;AAAA;AAAA,IACX;AAAA,IAEA,OAAO,SAAS;AACd,aAAO;AAAA;AAAA,QAEL,eAAe,YAA6B;AAE1C,gBAAM,OAAO;AACb,cAAI,CAAC,iBAAiB,IAAI,GAAG;AAC3B;AAAA,UACF;AAEA,cAAI;AACF,kBAAM,SAAS,4BAA4B,IAAI;AAC/C,gBAAI,CAAC,QAAQ;AACX;AAAA,YACF;AAEA,kBAAM,aAAS,yBAAK,QAAQ,mBAAAC,OAAa;AAAA,cACvC,OAAO,CAAC,UAAU;AAAA,cAClB,UAAU,QAAQ;AAAA,YACpB,CAAC;AAED,uBAAW,WAAW,OAAO,UAAU;AACrC,kBAAI,QAAQ,WAAW,WAAW,IAAI;AACpC,wBAAQ,OAAO;AAAA,kBACb,MAAM;AAAA,kBACN,WAAW,WAAW;AAAA,kBACtB,MAAM;AAAA,oBACJ,SAAS,QAAQ,OAAO,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,KAAK,QAAQ;AAAA,kBACzE;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA;AAAA,QAGA,uBAAuB,YAA6B;AAElD,gBAAM,OAAO;AAGb,cAAI,WAAW,OAAO,uBAAuB;AAC3C;AAAA,UACF;AAEA,cAAI,CAAC,KAAK,aAAa;AACrB;AAAA,UACF;AAGA,cAAI,KAAK,YAAY,SAAS,uBAAuB;AACnD,uBAAW,cAAc,KAAK,YAAY,cAAc;AACtD,kBACE,WAAW,MAAM,SAAS,sBAC1B,CAAC,sBAAsB,WAAW,IAAI,GACtC;AACA,sBAAM,SAAS,wBAAwB,WAAW,IAAI;AACtD,oBAAI,WAAW,OAAO,SAAS,cAAc,OAAO,SAAS,WAAW;AACtE,sBAAI;AACF,0BAAM,aAAS,yBAAK,QAAQ,mBAAAA,OAAa;AAAA,sBACvC,OAAO,CAAC,UAAU;AAAA,sBAClB,UAAU,QAAQ;AAAA,oBACpB,CAAC;AAED,+BAAW,WAAW,OAAO,UAAU;AACrC,0BAAI,QAAQ,WAAW,WAAW,IAAI;AACpC,gCAAQ,OAAO;AAAA,0BACb,MAAM;AAAA,0BACN,WAAW,WAAW;AAAA,0BACtB,MAAM;AAAA,4BACJ,SAAS,QAAQ,OACb,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,KAClC,QAAQ;AAAA,0BACd;AAAA,wBACF,CAAC;AAAA,sBACH;AAAA,oBACF;AAAA,kBACF,QAAQ;AAAA,kBAER;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA;AAAA,QAGA,yBAAyB,YAA6B;AAEpD,gBAAM,OAAO;AAGb,cAAI,WAAW,OAAO,uBAAuB;AAC3C;AAAA,UACF;AAEA,cAAI,KAAK,YAAY,SAAS,oBAAoB;AAChD,kBAAM,SAAS,wBAAwB,KAAK,WAAW;AACvD,gBAAI,WAAW,OAAO,SAAS,cAAc,OAAO,SAAS,WAAW;AACtE,kBAAI;AACF,sBAAM,aAAS,yBAAK,QAAQ,mBAAAA,OAAa;AAAA,kBACvC,OAAO,CAAC,UAAU;AAAA,kBAClB,UAAU,QAAQ;AAAA,gBACpB,CAAC;AAED,2BAAW,WAAW,OAAO,UAAU;AACrC,sBAAI,QAAQ,WAAW,WAAW,IAAI;AACpC,4BAAQ,OAAO;AAAA,sBACb,MAAM;AAAA,sBACN,WAAW,WAAW;AAAA,sBACtB,MAAM;AAAA,wBACJ,SAAS,QAAQ,OACb,GAAG,QAAQ,OAAO,IAAI,QAAQ,IAAI,KAClC,QAAQ;AAAA,sBACd;AAAA,oBACF,CAAC;AAAA,kBACH;AAAA,gBACF;AAAA,cACF,QAAQ;AAAA,cAER;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKA,SAAS,sBAAsB,OAA2C;AAIxE,SAAO;AACT;AAKO,SAAS,qBAAqBC,QAA4D;AAC/F,QAAM,cAAqD,CAAC;AAE5D,aAAW,QAAQA,QAAO;AAExB,UAAM,eAAe,UAAU,KAAK,EAAE;AACtC,gBAAY,YAAY,IAAI,uBAAuB,IAAI;AAAA,EACzD;AAEA,SAAO;AACT;;;AH7IA,IAAM,UAAU,OAAyC,UAAkB;AAG3E,IAAM,kBAAkB,eAAe,kBAAAC,KAAS;AAGhD,IAAM,oBAAoB,qBAAqB,oBAAAC,KAAW;AAG1D,IAAM,QAAQ;AAAA,EACZ,GAAG;AAAA,EACH,GAAG;AACL;AAGA,IAAM,SAAwB;AAAA,EAC5B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN;AAAA,EACF;AAAA,EACA;AACF;AAGA,IAAM,cAA6B;AAAA,EACjC,SAAS;AAAA,IACP,QAAQ;AAAA,EACV;AAAA,EACA,OAAO;AAAA;AAAA;AAAA,IAIL,8BAA8B;AAAA;AAAA,IAG9B,+BAA+B;AAAA,IAC/B,2BAA2B;AAAA,IAC3B,0BAA0B;AAAA,IAC1B,wCAAwC;AAAA,IACxC,sCAAsC;AAAA,IACtC,6BAA6B;AAAA,IAC7B,gCAAgC;AAAA,IAChC,qCAAqC;AAAA;AAAA,IAGrC,8BAA8B;AAAA,IAC9B,oCAAoC;AAAA,IACpC,2BAA2B;AAAA,IAC3B,4CAA4C;AAAA,IAC5C,qCAAqC;AAAA;AAAA;AAAA,IAKrC,qCAAqC;AAAA,IACrC,sCAAsC;AAAA,IACtC,qCAAqC;AAAA;AAAA,IAGrC,8BAA8B;AAAA,IAC9B,+BAA+B;AAAA,IAC/B,yCAAyC;AAAA,IACzC,qCAAqC;AAAA,IACrC,6CAA6C;AAAA,IAC7C,yCAAyC;AAAA;AAAA,IAGzC,qCAAqC;AAAA,IACrC,yCAAyC;AAAA,IACzC,2CAA2C;AAAA,IAC3C,uCAAuC;AAAA,EACzC;AACF;AAGA,IAAM,SAAwB;AAAA,EAC5B,SAAS;AAAA,IACP,QAAQ;AAAA,EACV;AAAA,EACA,OAAO,OAAO,YAAY,OAAO,KAAK,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,MAAM,IAAI,OAAO,CAAC,CAAC;AAC7F;AAGA,IAAM,UAAiE;AAAA,EACrE;AAAA,EACA;AACF;AAUA,IAAM,eAA6B;AAAA,EACjC,MAAM,OAAO;AAAA,EACb;AAAA,EACA;AACF;AAEA,IAAO,gBAAQ;","names":["import_groq_lint","import_schema_lint","allGroqRules","groqRules","schemaRules","rules","groqRules","schemaRules"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as eslint from 'eslint';
|
|
2
|
+
import { ESLint, Linter } from 'eslint';
|
|
3
|
+
|
|
4
|
+
declare const rules: {
|
|
5
|
+
[x: string]: eslint.Rule.RuleModule;
|
|
6
|
+
};
|
|
7
|
+
declare const configs: {
|
|
8
|
+
recommended: Linter.Config;
|
|
9
|
+
strict: Linter.Config;
|
|
10
|
+
};
|
|
11
|
+
interface SanityPlugin {
|
|
12
|
+
meta: ESLint.Plugin['meta'];
|
|
13
|
+
rules: typeof rules;
|
|
14
|
+
configs: typeof configs;
|
|
15
|
+
}
|
|
16
|
+
declare const sanityPlugin: SanityPlugin;
|
|
17
|
+
|
|
18
|
+
export { configs, sanityPlugin as default, rules };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { createRequire } from "module";
|
|
3
2
|
import { rules as groqRules } from "@sanity/groq-lint";
|
|
4
3
|
import { rules as schemaRules2 } from "@sanity/schema-lint";
|
|
5
4
|
|
|
@@ -427,8 +426,7 @@ function createAllSchemaRules(rules2) {
|
|
|
427
426
|
}
|
|
428
427
|
|
|
429
428
|
// src/index.ts
|
|
430
|
-
var
|
|
431
|
-
var { version } = require2("../package.json");
|
|
429
|
+
var version = true ? "0.0.3" : "0.0.0";
|
|
432
430
|
var groqEslintRules = createAllRules(groqRules);
|
|
433
431
|
var schemaEslintRules = createAllSchemaRules(schemaRules2);
|
|
434
432
|
var rules = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/utils/rule-factory.ts","../src/utils/groq-extractor.ts","../src/utils/schema-rule-factory.ts","../src/utils/schema-extractor.ts"],"sourcesContent":["/**\n * ESLint plugin for Sanity\n *\n * This plugin provides rules for linting GROQ queries and schema definitions\n * in JavaScript/TypeScript files.\n *\n * @example\n * ```js\n * // eslint.config.js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * {\n * plugins: { sanity },\n * rules: {\n * 'sanity/groq-join-in-filter': 'error',\n * 'sanity/schema-missing-icon': 'warn',\n * },\n * },\n * ]\n * ```\n *\n * Or use the recommended config:\n * ```js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * sanity.configs.recommended,\n * ]\n * ```\n */\n\nimport type { ESLint, Linter } from 'eslint'\nimport { createRequire } from 'node:module'\nimport { rules as groqRules } from '@sanity/groq-lint'\nimport { rules as schemaRules } from '@sanity/schema-lint'\nimport { createAllRules } from './utils/rule-factory'\nimport { createAllSchemaRules } from './utils/schema-rule-factory'\n\nconst require = createRequire(import.meta.url)\nconst { version } = require('../package.json') as { version: string }\n\n// Create ESLint rules from all GROQ lint rules\nconst groqEslintRules = createAllRules(groqRules)\n\n// Create ESLint rules from all schema lint rules\nconst schemaEslintRules = createAllSchemaRules(schemaRules)\n\n// Combine all rules\nconst rules = {\n ...groqEslintRules,\n ...schemaEslintRules,\n}\n\n// Build the plugin object\nconst plugin: ESLint.Plugin = {\n meta: {\n name: 'eslint-plugin-sanity',\n version,\n },\n rules,\n}\n\n// Create recommended config\nconst recommended: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: {\n // === GROQ Rules ===\n\n // Errors - these are serious performance or correctness issues\n 'sanity/groq-join-in-filter': 'error',\n\n // Warnings - performance issues that should be addressed\n 'sanity/groq-deep-pagination': 'warn',\n 'sanity/groq-large-pages': 'warn',\n 'sanity/groq-many-joins': 'warn',\n 'sanity/groq-computed-value-in-filter': 'warn',\n 'sanity/groq-non-literal-comparison': 'warn',\n 'sanity/groq-order-on-expr': 'warn',\n 'sanity/groq-very-large-query': 'warn',\n 'sanity/groq-extremely-large-query': 'error',\n\n // Info - suggestions for improvement (off by default, enable as warnings)\n 'sanity/groq-join-to-get-id': 'warn',\n 'sanity/groq-repeated-dereference': 'warn',\n 'sanity/groq-match-on-id': 'warn',\n 'sanity/groq-count-in-correlated-subquery': 'warn',\n 'sanity/groq-deep-pagination-param': 'warn',\n\n // === Schema Rules ===\n\n // Errors - correctness issues\n 'sanity/schema-missing-define-type': 'error',\n 'sanity/schema-missing-define-field': 'error',\n 'sanity/schema-reserved-field-name': 'error',\n\n // Warnings - best practice violations\n 'sanity/schema-missing-icon': 'warn',\n 'sanity/schema-missing-title': 'warn',\n 'sanity/schema-presentation-field-name': 'warn',\n 'sanity/schema-missing-slug-source': 'warn',\n 'sanity/schema-missing-required-validation': 'warn',\n 'sanity/schema-heading-level-in-schema': 'warn',\n\n // Info - suggestions (off by default)\n 'sanity/schema-missing-description': 'off',\n 'sanity/schema-boolean-instead-of-list': 'off',\n 'sanity/schema-array-missing-constraints': 'off',\n 'sanity/schema-unnecessary-reference': 'off',\n },\n}\n\n// Create strict config (all rules as errors)\nconst strict: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: Object.fromEntries(Object.keys(rules).map((ruleId) => [`sanity/${ruleId}`, 'error'])),\n}\n\n// Configs with explicit type annotation\nconst configs: { recommended: Linter.Config; strict: Linter.Config } = {\n recommended,\n strict,\n}\n\n// Plugin type\ninterface SanityPlugin {\n meta: ESLint.Plugin['meta']\n rules: typeof rules\n configs: typeof configs\n}\n\n// Default export for ESLint flat config\nconst sanityPlugin: SanityPlugin = {\n meta: plugin.meta,\n rules,\n configs,\n}\n\nexport default sanityPlugin\n\n// Named exports for flexibility\nexport { rules, configs }\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { Rule as GroqRule } from '@sanity/groq-lint'\nimport { lint, rules as allGroqRules } from '@sanity/groq-lint'\nimport { isGroqTaggedTemplate, extractGroqString } from './groq-extractor'\n\n/**\n * Build a config that enables only the specified rule\n */\nfunction buildSingleRuleConfig(ruleId: string): Record<string, boolean> {\n const config: Record<string, boolean> = {}\n for (const rule of allGroqRules) {\n config[rule.id] = rule.id === ruleId\n }\n return config\n}\n\n/**\n * Create an ESLint rule from a GROQ lint rule.\n */\nexport function createESLintRule(groqRule: GroqRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: groqRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: groqRule.description,\n recommended: groqRule.severity === 'error',\n },\n messages: {\n [groqRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n TaggedTemplateExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.TaggedTemplateExpression\n if (!isGroqTaggedTemplate(node)) {\n return\n }\n\n try {\n const query = extractGroqString(node)\n const result = lint(query, { config: { rules: buildSingleRuleConfig(groqRule.id) } })\n\n for (const finding of result.findings) {\n if (finding.ruleId === groqRule.id) {\n context.report({\n node: eslintNode,\n messageId: groqRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report, let the user see it in runtime\n }\n },\n }\n },\n }\n}\n\n/**\n * Create all ESLint rules from GROQ lint rules.\n */\nexport function createAllRules(groqRules: GroqRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of groqRules) {\n // Convert rule ID from snake_case to kebab-case for ESLint convention\n const eslintRuleId = `groq-${rule.id}`\n eslintRules[eslintRuleId] = createESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\n\n/**\n * Check if a node is a tagged template literal with a GROQ tag.\n * Matches: groq`...`, groq.something`...`\n */\nexport function isGroqTaggedTemplate(node: TSESTree.TaggedTemplateExpression): boolean {\n const tag = node.tag\n\n // groq`...`\n if (tag.type === 'Identifier' && tag.name === 'groq') {\n return true\n }\n\n // groq.something`...` (for groq.experimental etc)\n if (\n tag.type === 'MemberExpression' &&\n tag.object.type === 'Identifier' &&\n tag.object.name === 'groq'\n ) {\n return true\n }\n\n return false\n}\n\n/**\n * Extract the GROQ query string from a tagged template literal.\n * Handles template literals with expressions by replacing them with placeholders.\n */\nexport function extractGroqString(node: TSESTree.TaggedTemplateExpression): string {\n const { quasis, expressions } = node.quasi\n\n // Simple case: no expressions\n if (expressions.length === 0) {\n return quasis[0]?.value.cooked ?? quasis[0]?.value.raw ?? ''\n }\n\n // Build the string with placeholders for expressions\n let result = ''\n for (let i = 0; i < quasis.length; i++) {\n result += quasis[i]?.value.cooked ?? quasis[i]?.value.raw ?? ''\n if (i < expressions.length) {\n // Replace expression with a parameter placeholder\n // This allows the query to still parse while marking where expressions are\n result += `$__expr${i}__`\n }\n }\n\n return result\n}\n\n/**\n * Get the source location for reporting errors.\n * Returns the location of the template literal content, not the tag.\n */\nexport function getTemplateLocation(\n node: TSESTree.TaggedTemplateExpression\n): TSESTree.SourceLocation {\n return node.quasi.loc\n}\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaRule } from '@sanity/schema-lint'\nimport { lint, rules as schemaRules } from '@sanity/schema-lint'\nimport {\n isDefineTypeCall,\n extractSchemaFromDefineType,\n extractSchemaFromObject,\n} from './schema-extractor'\n\n/**\n * Create an ESLint rule from a schema lint rule.\n */\nexport function createSchemaESLintRule(schemaRule: SchemaRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: schemaRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: schemaRule.description,\n recommended: schemaRule.severity === 'error',\n },\n messages: {\n [schemaRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n // Handle defineType() calls\n CallExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.CallExpression\n if (!isDefineTypeCall(node)) {\n return\n }\n\n try {\n const schema = extractSchemaFromDefineType(node)\n if (!schema) {\n return\n }\n\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n },\n\n // Handle export statements with object literals (not using defineType)\n ExportNamedDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportNamedDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (!node.declaration) {\n return\n }\n\n // export const foo = { name: '...', type: '...' }\n if (node.declaration.type === 'VariableDeclaration') {\n for (const declarator of node.declaration.declarations) {\n if (\n declarator.init?.type === 'ObjectExpression' &&\n !isWrappedInDefineType(declarator.init)\n ) {\n const schema = extractSchemaFromObject(declarator.init)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n }\n }\n },\n\n // Handle default exports with object literals\n ExportDefaultDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportDefaultDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (node.declaration.type === 'ObjectExpression') {\n const schema = extractSchemaFromObject(node.declaration)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n },\n }\n },\n }\n}\n\n/**\n * Check if an object expression's parent is a defineType() call\n */\nfunction isWrappedInDefineType(_node: TSESTree.ObjectExpression): boolean {\n // This is a simplified check - in practice we check by seeing if\n // the parent is a CallExpression with defineType callee\n // For now we rely on the CallExpression handler\n return false\n}\n\n/**\n * Create all ESLint rules from schema lint rules.\n */\nexport function createAllSchemaRules(rules: SchemaRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of rules) {\n // Use schema- prefix to distinguish from groq- rules\n const eslintRuleId = `schema-${rule.id}`\n eslintRules[eslintRuleId] = createSchemaESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaType, SchemaField } from '@sanity/schema-lint'\nimport type { SourceSpan } from '@sanity/lint-core'\n\n/**\n * Check if a node is a defineType() call\n */\nexport function isDefineTypeCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineType({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineType') {\n return true\n }\n\n return false\n}\n\n/**\n * Check if a node is a defineField() call\n */\nexport function isDefineFieldCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineField({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineField') {\n return true\n }\n\n return false\n}\n\n/**\n * Convert ESLint location to our SourceSpan format\n */\nfunction toSourceSpan(loc: TSESTree.SourceLocation): SourceSpan {\n return {\n start: {\n line: loc.start.line,\n column: loc.start.column + 1, // 1-based\n offset: 0, // We don't have offset info easily\n },\n end: {\n line: loc.end.line,\n column: loc.end.column + 1, // 1-based\n offset: 0,\n },\n }\n}\n\n/**\n * Extract a string value from an AST node\n */\nfunction extractStringValue(node: TSESTree.Node | undefined): string | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'string') {\n return node.value\n }\n\n // Handle template literals without expressions\n if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {\n return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw\n }\n\n return undefined\n}\n\n/**\n * Extract a boolean value from an AST node\n */\nfunction extractBooleanValue(node: TSESTree.Node | undefined): boolean | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'boolean') {\n return node.value\n }\n\n return undefined\n}\n\n/**\n * Check if a property exists in an object expression\n */\nfunction hasProperty(node: TSESTree.ObjectExpression, name: string): boolean {\n return node.properties.some((prop) => {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n return prop.key.name === name\n }\n return false\n })\n}\n\n/**\n * Get a property value from an object expression\n */\nfunction getProperty(node: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined {\n for (const prop of node.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier' && prop.key.name === name) {\n return prop.value\n }\n }\n return undefined\n}\n\n/**\n * Extract field options from an object expression\n */\nfunction extractFieldOptions(\n optionsNode: TSESTree.Node | undefined\n): SchemaField['options'] | undefined {\n if (!optionsNode || optionsNode.type !== 'ObjectExpression') {\n return undefined\n }\n\n const options: NonNullable<SchemaField['options']> = {}\n\n for (const prop of optionsNode.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n const name = prop.key.name\n\n if (name === 'source') {\n const source = extractStringValue(prop.value)\n if (source !== undefined) options.source = source\n } else if (name === 'hotspot') {\n const hotspot = extractBooleanValue(prop.value)\n if (hotspot !== undefined) options.hotspot = hotspot\n } else if (name === 'layout') {\n const layout = extractStringValue(prop.value)\n if (layout !== undefined) options.layout = layout\n } else if (name === 'list' && prop.value.type === 'ArrayExpression') {\n options.list = prop.value.elements.map((el) => {\n if (!el) return null\n if (el.type === 'Literal') return el.value\n if (el.type === 'ObjectExpression') {\n const value = extractStringValue(getProperty(el, 'value'))\n return { value }\n }\n return null\n })\n }\n }\n }\n\n return Object.keys(options).length > 0 ? options : undefined\n}\n\n/**\n * Extract a field from an object expression (either raw or wrapped in defineField)\n */\nfunction extractField(\n node: TSESTree.Node,\n usesDefineField: { value: boolean }\n): SchemaField | undefined {\n let fieldObj: TSESTree.ObjectExpression | undefined\n\n // Check if it's wrapped in defineField()\n if (node.type === 'CallExpression' && isDefineFieldCall(node)) {\n const arg = node.arguments[0]\n if (arg?.type === 'ObjectExpression') {\n fieldObj = arg\n }\n } else if (node.type === 'ObjectExpression') {\n fieldObj = node\n usesDefineField.value = false // At least one field doesn't use defineField\n }\n\n if (!fieldObj) return undefined\n\n const name = extractStringValue(getProperty(fieldObj, 'name'))\n const type = extractStringValue(getProperty(fieldObj, 'type'))\n\n if (!name || !type) return undefined\n\n const title = extractStringValue(getProperty(fieldObj, 'title'))\n const description = extractStringValue(getProperty(fieldObj, 'description'))\n const options = extractFieldOptions(getProperty(fieldObj, 'options'))\n\n const field: SchemaField = {\n name,\n type,\n hasValidation: hasProperty(fieldObj, 'validation'),\n hidden: hasProperty(fieldObj, 'hidden'),\n readOnly: hasProperty(fieldObj, 'readOnly'),\n span: toSourceSpan(fieldObj.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(options !== undefined && { options }),\n }\n\n // Check for deprecated\n if (hasProperty(fieldObj, 'deprecated')) {\n const deprecatedNode = getProperty(fieldObj, 'deprecated')\n const deprecatedValue = extractStringValue(deprecatedNode)\n field.deprecated = deprecatedValue ?? true\n }\n\n return field\n}\n\n/**\n * Extract fields from an array expression\n */\nfunction extractFields(node: TSESTree.Node | undefined): {\n fields: SchemaField[]\n usesDefineField: boolean\n} {\n const result = { fields: [] as SchemaField[], usesDefineField: true }\n\n if (!node || node.type !== 'ArrayExpression') {\n return result\n }\n\n const usesDefineFieldTracker = { value: true }\n\n for (const element of node.elements) {\n if (element) {\n const field = extractField(element, usesDefineFieldTracker)\n if (field) {\n result.fields.push(field)\n }\n }\n }\n\n result.usesDefineField = usesDefineFieldTracker.value\n\n return result\n}\n\n/**\n * Extract schema type from a defineType() call\n */\nexport function extractSchemaFromDefineType(node: TSESTree.CallExpression): SchemaType | undefined {\n const arg = node.arguments[0]\n\n if (!arg || arg.type !== 'ObjectExpression') {\n return undefined\n }\n\n const name = extractStringValue(getProperty(arg, 'name'))\n const type = extractStringValue(getProperty(arg, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n const title = extractStringValue(getProperty(arg, 'title'))\n const description = extractStringValue(getProperty(arg, 'description'))\n const fieldsResult = extractFields(getProperty(arg, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(arg, 'icon'),\n hasPreview: hasProperty(arg, 'preview'),\n usesDefineType: true,\n span: toSourceSpan(arg.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n\n/**\n * Extract schema type from a plain object literal (not wrapped in defineType)\n */\nexport function extractSchemaFromObject(node: TSESTree.ObjectExpression): SchemaType | undefined {\n const name = extractStringValue(getProperty(node, 'name'))\n const type = extractStringValue(getProperty(node, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n // Only process if it looks like a Sanity schema (has name and type)\n const title = extractStringValue(getProperty(node, 'title'))\n const description = extractStringValue(getProperty(node, 'description'))\n const fieldsResult = extractFields(getProperty(node, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(node, 'icon'),\n hasPreview: hasProperty(node, 'preview'),\n usesDefineType: false,\n span: toSourceSpan(node.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n"],"mappings":"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","names":["schemaRules","groqRules","lint","lint","rules","require","schemaRules"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/utils/rule-factory.ts","../src/utils/groq-extractor.ts","../src/utils/schema-rule-factory.ts","../src/utils/schema-extractor.ts"],"sourcesContent":["/**\n * ESLint plugin for Sanity\n *\n * This plugin provides rules for linting GROQ queries and schema definitions\n * in JavaScript/TypeScript files.\n *\n * @example\n * ```js\n * // eslint.config.js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * {\n * plugins: { sanity },\n * rules: {\n * 'sanity/groq-join-in-filter': 'error',\n * 'sanity/schema-missing-icon': 'warn',\n * },\n * },\n * ]\n * ```\n *\n * Or use the recommended config:\n * ```js\n * import sanity from 'eslint-plugin-sanity'\n *\n * export default [\n * sanity.configs.recommended,\n * ]\n * ```\n */\n\nimport type { ESLint, Linter } from 'eslint'\nimport { rules as groqRules } from '@sanity/groq-lint'\nimport { rules as schemaRules } from '@sanity/schema-lint'\nimport { createAllRules } from './utils/rule-factory'\nimport { createAllSchemaRules } from './utils/schema-rule-factory'\n\n// Version is injected at build time by tsup\ndeclare const PACKAGE_VERSION: string\nconst version = typeof PACKAGE_VERSION !== 'undefined' ? PACKAGE_VERSION : '0.0.0'\n\n// Create ESLint rules from all GROQ lint rules\nconst groqEslintRules = createAllRules(groqRules)\n\n// Create ESLint rules from all schema lint rules\nconst schemaEslintRules = createAllSchemaRules(schemaRules)\n\n// Combine all rules\nconst rules = {\n ...groqEslintRules,\n ...schemaEslintRules,\n}\n\n// Build the plugin object\nconst plugin: ESLint.Plugin = {\n meta: {\n name: 'eslint-plugin-sanity',\n version,\n },\n rules,\n}\n\n// Create recommended config\nconst recommended: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: {\n // === GROQ Rules ===\n\n // Errors - these are serious performance or correctness issues\n 'sanity/groq-join-in-filter': 'error',\n\n // Warnings - performance issues that should be addressed\n 'sanity/groq-deep-pagination': 'warn',\n 'sanity/groq-large-pages': 'warn',\n 'sanity/groq-many-joins': 'warn',\n 'sanity/groq-computed-value-in-filter': 'warn',\n 'sanity/groq-non-literal-comparison': 'warn',\n 'sanity/groq-order-on-expr': 'warn',\n 'sanity/groq-very-large-query': 'warn',\n 'sanity/groq-extremely-large-query': 'error',\n\n // Info - suggestions for improvement (off by default, enable as warnings)\n 'sanity/groq-join-to-get-id': 'warn',\n 'sanity/groq-repeated-dereference': 'warn',\n 'sanity/groq-match-on-id': 'warn',\n 'sanity/groq-count-in-correlated-subquery': 'warn',\n 'sanity/groq-deep-pagination-param': 'warn',\n\n // === Schema Rules ===\n\n // Errors - correctness issues\n 'sanity/schema-missing-define-type': 'error',\n 'sanity/schema-missing-define-field': 'error',\n 'sanity/schema-reserved-field-name': 'error',\n\n // Warnings - best practice violations\n 'sanity/schema-missing-icon': 'warn',\n 'sanity/schema-missing-title': 'warn',\n 'sanity/schema-presentation-field-name': 'warn',\n 'sanity/schema-missing-slug-source': 'warn',\n 'sanity/schema-missing-required-validation': 'warn',\n 'sanity/schema-heading-level-in-schema': 'warn',\n\n // Info - suggestions (off by default)\n 'sanity/schema-missing-description': 'off',\n 'sanity/schema-boolean-instead-of-list': 'off',\n 'sanity/schema-array-missing-constraints': 'off',\n 'sanity/schema-unnecessary-reference': 'off',\n },\n}\n\n// Create strict config (all rules as errors)\nconst strict: Linter.Config = {\n plugins: {\n sanity: plugin,\n },\n rules: Object.fromEntries(Object.keys(rules).map((ruleId) => [`sanity/${ruleId}`, 'error'])),\n}\n\n// Configs with explicit type annotation\nconst configs: { recommended: Linter.Config; strict: Linter.Config } = {\n recommended,\n strict,\n}\n\n// Plugin type\ninterface SanityPlugin {\n meta: ESLint.Plugin['meta']\n rules: typeof rules\n configs: typeof configs\n}\n\n// Default export for ESLint flat config\nconst sanityPlugin: SanityPlugin = {\n meta: plugin.meta,\n rules,\n configs,\n}\n\nexport default sanityPlugin\n\n// Named exports for flexibility\nexport { rules, configs }\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { Rule as GroqRule } from '@sanity/groq-lint'\nimport { lint, rules as allGroqRules } from '@sanity/groq-lint'\nimport { isGroqTaggedTemplate, extractGroqString } from './groq-extractor'\n\n/**\n * Build a config that enables only the specified rule\n */\nfunction buildSingleRuleConfig(ruleId: string): Record<string, boolean> {\n const config: Record<string, boolean> = {}\n for (const rule of allGroqRules) {\n config[rule.id] = rule.id === ruleId\n }\n return config\n}\n\n/**\n * Create an ESLint rule from a GROQ lint rule.\n */\nexport function createESLintRule(groqRule: GroqRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: groqRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: groqRule.description,\n recommended: groqRule.severity === 'error',\n },\n messages: {\n [groqRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n TaggedTemplateExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.TaggedTemplateExpression\n if (!isGroqTaggedTemplate(node)) {\n return\n }\n\n try {\n const query = extractGroqString(node)\n const result = lint(query, { config: { rules: buildSingleRuleConfig(groqRule.id) } })\n\n for (const finding of result.findings) {\n if (finding.ruleId === groqRule.id) {\n context.report({\n node: eslintNode,\n messageId: groqRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report, let the user see it in runtime\n }\n },\n }\n },\n }\n}\n\n/**\n * Create all ESLint rules from GROQ lint rules.\n */\nexport function createAllRules(groqRules: GroqRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of groqRules) {\n // Convert rule ID from snake_case to kebab-case for ESLint convention\n const eslintRuleId = `groq-${rule.id}`\n eslintRules[eslintRuleId] = createESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\n\n/**\n * Check if a node is a tagged template literal with a GROQ tag.\n * Matches: groq`...`, groq.something`...`\n */\nexport function isGroqTaggedTemplate(node: TSESTree.TaggedTemplateExpression): boolean {\n const tag = node.tag\n\n // groq`...`\n if (tag.type === 'Identifier' && tag.name === 'groq') {\n return true\n }\n\n // groq.something`...` (for groq.experimental etc)\n if (\n tag.type === 'MemberExpression' &&\n tag.object.type === 'Identifier' &&\n tag.object.name === 'groq'\n ) {\n return true\n }\n\n return false\n}\n\n/**\n * Extract the GROQ query string from a tagged template literal.\n * Handles template literals with expressions by replacing them with placeholders.\n */\nexport function extractGroqString(node: TSESTree.TaggedTemplateExpression): string {\n const { quasis, expressions } = node.quasi\n\n // Simple case: no expressions\n if (expressions.length === 0) {\n return quasis[0]?.value.cooked ?? quasis[0]?.value.raw ?? ''\n }\n\n // Build the string with placeholders for expressions\n let result = ''\n for (let i = 0; i < quasis.length; i++) {\n result += quasis[i]?.value.cooked ?? quasis[i]?.value.raw ?? ''\n if (i < expressions.length) {\n // Replace expression with a parameter placeholder\n // This allows the query to still parse while marking where expressions are\n result += `$__expr${i}__`\n }\n }\n\n return result\n}\n\n/**\n * Get the source location for reporting errors.\n * Returns the location of the template literal content, not the tag.\n */\nexport function getTemplateLocation(\n node: TSESTree.TaggedTemplateExpression\n): TSESTree.SourceLocation {\n return node.quasi.loc\n}\n","import type { Rule as ESLintRule } from 'eslint'\nimport type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaRule } from '@sanity/schema-lint'\nimport { lint, rules as schemaRules } from '@sanity/schema-lint'\nimport {\n isDefineTypeCall,\n extractSchemaFromDefineType,\n extractSchemaFromObject,\n} from './schema-extractor'\n\n/**\n * Create an ESLint rule from a schema lint rule.\n */\nexport function createSchemaESLintRule(schemaRule: SchemaRule): ESLintRule.RuleModule {\n return {\n meta: {\n type: schemaRule.category === 'correctness' ? 'problem' : 'suggestion',\n docs: {\n description: schemaRule.description,\n recommended: schemaRule.severity === 'error',\n },\n messages: {\n [schemaRule.id]: '{{ message }}',\n },\n schema: [], // No options for now\n },\n\n create(context) {\n return {\n // Handle defineType() calls\n CallExpression(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.CallExpression\n if (!isDefineTypeCall(node)) {\n return\n }\n\n try {\n const schema = extractSchemaFromDefineType(node)\n if (!schema) {\n return\n }\n\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help ? `${finding.message} ${finding.help}` : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n },\n\n // Handle export statements with object literals (not using defineType)\n ExportNamedDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportNamedDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (!node.declaration) {\n return\n }\n\n // export const foo = { name: '...', type: '...' }\n if (node.declaration.type === 'VariableDeclaration') {\n for (const declarator of node.declaration.declarations) {\n if (\n declarator.init?.type === 'ObjectExpression' &&\n !isWrappedInDefineType(declarator.init)\n ) {\n const schema = extractSchemaFromObject(declarator.init)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n }\n }\n },\n\n // Handle default exports with object literals\n ExportDefaultDeclaration(eslintNode: ESLintRule.Node) {\n // Cast to our TSESTree type for type-safe property access\n const node = eslintNode as unknown as TSESTree.ExportDefaultDeclaration\n\n // Only check the missing-define-type rule for non-defineType exports\n if (schemaRule.id !== 'missing-define-type') {\n return\n }\n\n if (node.declaration.type === 'ObjectExpression') {\n const schema = extractSchemaFromObject(node.declaration)\n if (schema && (schema.type === 'document' || schema.type === 'object')) {\n try {\n const result = lint(schema, schemaRules, {\n rules: [schemaRule],\n filePath: context.filename,\n })\n\n for (const finding of result.findings) {\n if (finding.ruleId === schemaRule.id) {\n context.report({\n node: eslintNode,\n messageId: schemaRule.id,\n data: {\n message: finding.help\n ? `${finding.message} ${finding.help}`\n : finding.message,\n },\n })\n }\n }\n } catch {\n // Parse error - don't report\n }\n }\n }\n },\n }\n },\n }\n}\n\n/**\n * Check if an object expression's parent is a defineType() call\n */\nfunction isWrappedInDefineType(_node: TSESTree.ObjectExpression): boolean {\n // This is a simplified check - in practice we check by seeing if\n // the parent is a CallExpression with defineType callee\n // For now we rely on the CallExpression handler\n return false\n}\n\n/**\n * Create all ESLint rules from schema lint rules.\n */\nexport function createAllSchemaRules(rules: SchemaRule[]): Record<string, ESLintRule.RuleModule> {\n const eslintRules: Record<string, ESLintRule.RuleModule> = {}\n\n for (const rule of rules) {\n // Use schema- prefix to distinguish from groq- rules\n const eslintRuleId = `schema-${rule.id}`\n eslintRules[eslintRuleId] = createSchemaESLintRule(rule)\n }\n\n return eslintRules\n}\n","import type { TSESTree } from '@typescript-eslint/types'\nimport type { SchemaType, SchemaField } from '@sanity/schema-lint'\nimport type { SourceSpan } from '@sanity/lint-core'\n\n/**\n * Check if a node is a defineType() call\n */\nexport function isDefineTypeCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineType({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineType') {\n return true\n }\n\n return false\n}\n\n/**\n * Check if a node is a defineField() call\n */\nexport function isDefineFieldCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee\n\n // defineField({ ... })\n if (callee.type === 'Identifier' && callee.name === 'defineField') {\n return true\n }\n\n return false\n}\n\n/**\n * Convert ESLint location to our SourceSpan format\n */\nfunction toSourceSpan(loc: TSESTree.SourceLocation): SourceSpan {\n return {\n start: {\n line: loc.start.line,\n column: loc.start.column + 1, // 1-based\n offset: 0, // We don't have offset info easily\n },\n end: {\n line: loc.end.line,\n column: loc.end.column + 1, // 1-based\n offset: 0,\n },\n }\n}\n\n/**\n * Extract a string value from an AST node\n */\nfunction extractStringValue(node: TSESTree.Node | undefined): string | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'string') {\n return node.value\n }\n\n // Handle template literals without expressions\n if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {\n return node.quasis[0]?.value.cooked ?? node.quasis[0]?.value.raw\n }\n\n return undefined\n}\n\n/**\n * Extract a boolean value from an AST node\n */\nfunction extractBooleanValue(node: TSESTree.Node | undefined): boolean | undefined {\n if (!node) return undefined\n\n if (node.type === 'Literal' && typeof node.value === 'boolean') {\n return node.value\n }\n\n return undefined\n}\n\n/**\n * Check if a property exists in an object expression\n */\nfunction hasProperty(node: TSESTree.ObjectExpression, name: string): boolean {\n return node.properties.some((prop) => {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n return prop.key.name === name\n }\n return false\n })\n}\n\n/**\n * Get a property value from an object expression\n */\nfunction getProperty(node: TSESTree.ObjectExpression, name: string): TSESTree.Node | undefined {\n for (const prop of node.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier' && prop.key.name === name) {\n return prop.value\n }\n }\n return undefined\n}\n\n/**\n * Extract field options from an object expression\n */\nfunction extractFieldOptions(\n optionsNode: TSESTree.Node | undefined\n): SchemaField['options'] | undefined {\n if (!optionsNode || optionsNode.type !== 'ObjectExpression') {\n return undefined\n }\n\n const options: NonNullable<SchemaField['options']> = {}\n\n for (const prop of optionsNode.properties) {\n if (prop.type === 'Property' && prop.key.type === 'Identifier') {\n const name = prop.key.name\n\n if (name === 'source') {\n const source = extractStringValue(prop.value)\n if (source !== undefined) options.source = source\n } else if (name === 'hotspot') {\n const hotspot = extractBooleanValue(prop.value)\n if (hotspot !== undefined) options.hotspot = hotspot\n } else if (name === 'layout') {\n const layout = extractStringValue(prop.value)\n if (layout !== undefined) options.layout = layout\n } else if (name === 'list' && prop.value.type === 'ArrayExpression') {\n options.list = prop.value.elements.map((el) => {\n if (!el) return null\n if (el.type === 'Literal') return el.value\n if (el.type === 'ObjectExpression') {\n const value = extractStringValue(getProperty(el, 'value'))\n return { value }\n }\n return null\n })\n }\n }\n }\n\n return Object.keys(options).length > 0 ? options : undefined\n}\n\n/**\n * Extract a field from an object expression (either raw or wrapped in defineField)\n */\nfunction extractField(\n node: TSESTree.Node,\n usesDefineField: { value: boolean }\n): SchemaField | undefined {\n let fieldObj: TSESTree.ObjectExpression | undefined\n\n // Check if it's wrapped in defineField()\n if (node.type === 'CallExpression' && isDefineFieldCall(node)) {\n const arg = node.arguments[0]\n if (arg?.type === 'ObjectExpression') {\n fieldObj = arg\n }\n } else if (node.type === 'ObjectExpression') {\n fieldObj = node\n usesDefineField.value = false // At least one field doesn't use defineField\n }\n\n if (!fieldObj) return undefined\n\n const name = extractStringValue(getProperty(fieldObj, 'name'))\n const type = extractStringValue(getProperty(fieldObj, 'type'))\n\n if (!name || !type) return undefined\n\n const title = extractStringValue(getProperty(fieldObj, 'title'))\n const description = extractStringValue(getProperty(fieldObj, 'description'))\n const options = extractFieldOptions(getProperty(fieldObj, 'options'))\n\n const field: SchemaField = {\n name,\n type,\n hasValidation: hasProperty(fieldObj, 'validation'),\n hidden: hasProperty(fieldObj, 'hidden'),\n readOnly: hasProperty(fieldObj, 'readOnly'),\n span: toSourceSpan(fieldObj.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(options !== undefined && { options }),\n }\n\n // Check for deprecated\n if (hasProperty(fieldObj, 'deprecated')) {\n const deprecatedNode = getProperty(fieldObj, 'deprecated')\n const deprecatedValue = extractStringValue(deprecatedNode)\n field.deprecated = deprecatedValue ?? true\n }\n\n return field\n}\n\n/**\n * Extract fields from an array expression\n */\nfunction extractFields(node: TSESTree.Node | undefined): {\n fields: SchemaField[]\n usesDefineField: boolean\n} {\n const result = { fields: [] as SchemaField[], usesDefineField: true }\n\n if (!node || node.type !== 'ArrayExpression') {\n return result\n }\n\n const usesDefineFieldTracker = { value: true }\n\n for (const element of node.elements) {\n if (element) {\n const field = extractField(element, usesDefineFieldTracker)\n if (field) {\n result.fields.push(field)\n }\n }\n }\n\n result.usesDefineField = usesDefineFieldTracker.value\n\n return result\n}\n\n/**\n * Extract schema type from a defineType() call\n */\nexport function extractSchemaFromDefineType(node: TSESTree.CallExpression): SchemaType | undefined {\n const arg = node.arguments[0]\n\n if (!arg || arg.type !== 'ObjectExpression') {\n return undefined\n }\n\n const name = extractStringValue(getProperty(arg, 'name'))\n const type = extractStringValue(getProperty(arg, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n const title = extractStringValue(getProperty(arg, 'title'))\n const description = extractStringValue(getProperty(arg, 'description'))\n const fieldsResult = extractFields(getProperty(arg, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(arg, 'icon'),\n hasPreview: hasProperty(arg, 'preview'),\n usesDefineType: true,\n span: toSourceSpan(arg.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n\n/**\n * Extract schema type from a plain object literal (not wrapped in defineType)\n */\nexport function extractSchemaFromObject(node: TSESTree.ObjectExpression): SchemaType | undefined {\n const name = extractStringValue(getProperty(node, 'name'))\n const type = extractStringValue(getProperty(node, 'type'))\n\n if (!name || !type) {\n return undefined\n }\n\n // Only process if it looks like a Sanity schema (has name and type)\n const title = extractStringValue(getProperty(node, 'title'))\n const description = extractStringValue(getProperty(node, 'description'))\n const fieldsResult = extractFields(getProperty(node, 'fields'))\n const hasFields = fieldsResult.fields.length > 0\n\n const schema: SchemaType = {\n name,\n type,\n hasIcon: hasProperty(node, 'icon'),\n hasPreview: hasProperty(node, 'preview'),\n usesDefineType: false,\n span: toSourceSpan(node.loc),\n ...(title !== undefined && { title }),\n ...(description !== undefined && { description }),\n ...(hasFields && { fields: fieldsResult.fields }),\n ...(hasFields && { usesDefineField: fieldsResult.usesDefineField }),\n }\n\n return schema\n}\n"],"mappings":"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","names":["schemaRules","groqRules","lint","lint","rules","schemaRules"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-sanity",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "ESLint plugin for Sanity Lint - lint GROQ queries and schema definitions",
|
|
5
5
|
"author": "Sanity.io <hello@sanity.io>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,18 +17,19 @@
|
|
|
17
17
|
"exports": {
|
|
18
18
|
".": {
|
|
19
19
|
"types": "./dist/index.d.ts",
|
|
20
|
-
"import": "./dist/index.js"
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
21
22
|
}
|
|
22
23
|
},
|
|
23
|
-
"main": "./dist/index.
|
|
24
|
+
"main": "./dist/index.cjs",
|
|
24
25
|
"types": "./dist/index.d.ts",
|
|
25
26
|
"files": [
|
|
26
27
|
"dist"
|
|
27
28
|
],
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@sanity/lint
|
|
30
|
-
"@sanity/
|
|
31
|
-
"@sanity/
|
|
30
|
+
"@sanity/groq-lint": "0.0.2",
|
|
31
|
+
"@sanity/lint-core": "0.0.2",
|
|
32
|
+
"@sanity/schema-lint": "0.0.2"
|
|
32
33
|
},
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"eslint": ">=8.0.0"
|