@coldsmirk/inkstone-codemirror 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -3
- package/dist/{context-D86o2jK3.js → context-BJzyiP0A.js} +12 -5
- package/dist/index.d.ts +131 -3
- package/dist/index.js +216 -58
- package/dist/minijinja-D5ANOjtx.js +700 -0
- package/dist/sql-schema-DiPx5-bu.js +15 -0
- package/dist/sql-support-Gk7Wv9Kj.js +29 -0
- package/package.json +2 -1
- package/dist/minijinja-D_5erBa7.js +0 -418
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StateEffect, StateField } from "@codemirror/state";
|
|
2
|
+
//#region src/sql-schema.ts
|
|
3
|
+
const setSqlSchema = StateEffect.define();
|
|
4
|
+
const sqlSchemaField = StateField.define({
|
|
5
|
+
create() {
|
|
6
|
+
return null;
|
|
7
|
+
},
|
|
8
|
+
update(value, transaction) {
|
|
9
|
+
let next = value;
|
|
10
|
+
for (const effect of transaction.effects) if (effect.is(setSqlSchema)) next = effect.value;
|
|
11
|
+
return next;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { sqlSchemaField as n, setSqlSchema as t };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { n as sqlSchemaField } from "./sql-schema-DiPx5-bu.js";
|
|
2
|
+
import { LanguageSupport } from "@codemirror/language";
|
|
3
|
+
import { schemaCompletionSource } from "@codemirror/lang-sql";
|
|
4
|
+
//#region src/sql-support.ts
|
|
5
|
+
function withSqlSchema(base, dialect) {
|
|
6
|
+
const delegates = /* @__PURE__ */ new WeakMap();
|
|
7
|
+
const source = (context) => {
|
|
8
|
+
const schema = context.state.field(sqlSchemaField, false) ?? null;
|
|
9
|
+
if (schema === null) return null;
|
|
10
|
+
let delegate = delegates.get(schema);
|
|
11
|
+
if (delegate === void 0) {
|
|
12
|
+
delegate = schemaCompletionSource({
|
|
13
|
+
dialect,
|
|
14
|
+
schema: schema.tables,
|
|
15
|
+
defaultTable: schema.defaultTable,
|
|
16
|
+
defaultSchema: schema.defaultSchema
|
|
17
|
+
});
|
|
18
|
+
delegates.set(schema, delegate);
|
|
19
|
+
}
|
|
20
|
+
return delegate(context);
|
|
21
|
+
};
|
|
22
|
+
return new LanguageSupport(base.language, [
|
|
23
|
+
base.support,
|
|
24
|
+
sqlSchemaField,
|
|
25
|
+
base.language.data.of({ autocomplete: source })
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { withSqlSchema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-codemirror",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Framework-agnostic CodeMirror 6 plumbing: a controlled editor host (create-once, external-value reconcile, in-place theme swap) and the standard document extension bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codemirror",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@codemirror/lang-yaml": "^6.1.3",
|
|
59
59
|
"@codemirror/legacy-modes": "^6.5.3",
|
|
60
60
|
"@codemirror/lint": "^6.9.7",
|
|
61
|
+
"@codemirror/merge": "^6.12.2",
|
|
61
62
|
"@lezer/common": "^1.5.2"
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
import { i as resolveMembers, n as minijinjaContextField, o as typeAtPath, r as normalizeContext, t as elementType } from "./context-D86o2jK3.js";
|
|
2
|
-
import { LanguageSupport, syntaxTree } from "@codemirror/language";
|
|
3
|
-
import { jinja, jinjaLanguage } from "@codemirror/lang-jinja";
|
|
4
|
-
import { linter } from "@codemirror/lint";
|
|
5
|
-
//#region src/minijinja.ts
|
|
6
|
-
const MINIJINJA_TAGS = /* @__PURE__ */ new Set([
|
|
7
|
-
"autoescape",
|
|
8
|
-
"endautoescape",
|
|
9
|
-
"block",
|
|
10
|
-
"endblock",
|
|
11
|
-
"call",
|
|
12
|
-
"endcall",
|
|
13
|
-
"filter",
|
|
14
|
-
"endfilter",
|
|
15
|
-
"for",
|
|
16
|
-
"endfor",
|
|
17
|
-
"if",
|
|
18
|
-
"elif",
|
|
19
|
-
"else",
|
|
20
|
-
"endif",
|
|
21
|
-
"macro",
|
|
22
|
-
"endmacro",
|
|
23
|
-
"set",
|
|
24
|
-
"endset",
|
|
25
|
-
"with",
|
|
26
|
-
"endwith",
|
|
27
|
-
"raw",
|
|
28
|
-
"endraw",
|
|
29
|
-
"extends",
|
|
30
|
-
"include",
|
|
31
|
-
"import",
|
|
32
|
-
"from",
|
|
33
|
-
"do",
|
|
34
|
-
"break",
|
|
35
|
-
"continue"
|
|
36
|
-
]);
|
|
37
|
-
const MINIJINJA_FILTERS = [
|
|
38
|
-
"abs",
|
|
39
|
-
"attr",
|
|
40
|
-
"batch",
|
|
41
|
-
"bool",
|
|
42
|
-
"capitalize",
|
|
43
|
-
"chain",
|
|
44
|
-
"count",
|
|
45
|
-
"d",
|
|
46
|
-
"default",
|
|
47
|
-
"dictsort",
|
|
48
|
-
"e",
|
|
49
|
-
"escape",
|
|
50
|
-
"first",
|
|
51
|
-
"float",
|
|
52
|
-
"format",
|
|
53
|
-
"groupby",
|
|
54
|
-
"indent",
|
|
55
|
-
"int",
|
|
56
|
-
"items",
|
|
57
|
-
"join",
|
|
58
|
-
"last",
|
|
59
|
-
"length",
|
|
60
|
-
"lines",
|
|
61
|
-
"list",
|
|
62
|
-
"lower",
|
|
63
|
-
"map",
|
|
64
|
-
"max",
|
|
65
|
-
"min",
|
|
66
|
-
"pprint",
|
|
67
|
-
"reject",
|
|
68
|
-
"rejectattr",
|
|
69
|
-
"replace",
|
|
70
|
-
"reverse",
|
|
71
|
-
"round",
|
|
72
|
-
"safe",
|
|
73
|
-
"select",
|
|
74
|
-
"selectattr",
|
|
75
|
-
"slice",
|
|
76
|
-
"sort",
|
|
77
|
-
"split",
|
|
78
|
-
"string",
|
|
79
|
-
"sum",
|
|
80
|
-
"title",
|
|
81
|
-
"tojson",
|
|
82
|
-
"trim",
|
|
83
|
-
"unique",
|
|
84
|
-
"upper",
|
|
85
|
-
"urlencode",
|
|
86
|
-
"zip"
|
|
87
|
-
];
|
|
88
|
-
const MINIJINJA_TESTS = [
|
|
89
|
-
"boolean",
|
|
90
|
-
"defined",
|
|
91
|
-
"divisibleby",
|
|
92
|
-
"endingwith",
|
|
93
|
-
"eq",
|
|
94
|
-
"equalto",
|
|
95
|
-
"escaped",
|
|
96
|
-
"even",
|
|
97
|
-
"false",
|
|
98
|
-
"filter",
|
|
99
|
-
"float",
|
|
100
|
-
"ge",
|
|
101
|
-
"greaterthan",
|
|
102
|
-
"in",
|
|
103
|
-
"int",
|
|
104
|
-
"integer",
|
|
105
|
-
"iterable",
|
|
106
|
-
"le",
|
|
107
|
-
"lessthan",
|
|
108
|
-
"lower",
|
|
109
|
-
"lt",
|
|
110
|
-
"gt",
|
|
111
|
-
"mapping",
|
|
112
|
-
"ne",
|
|
113
|
-
"none",
|
|
114
|
-
"number",
|
|
115
|
-
"odd",
|
|
116
|
-
"safe",
|
|
117
|
-
"sameas",
|
|
118
|
-
"sequence",
|
|
119
|
-
"startingwith",
|
|
120
|
-
"string",
|
|
121
|
-
"test",
|
|
122
|
-
"true",
|
|
123
|
-
"undefined",
|
|
124
|
-
"upper"
|
|
125
|
-
];
|
|
126
|
-
const MINIJINJA_FUNCTIONS = [
|
|
127
|
-
"debug",
|
|
128
|
-
"dict",
|
|
129
|
-
"namespace",
|
|
130
|
-
"range"
|
|
131
|
-
];
|
|
132
|
-
function toCompletions(labels, type) {
|
|
133
|
-
return [...labels].toSorted().map((label) => {
|
|
134
|
-
return {
|
|
135
|
-
label,
|
|
136
|
-
type
|
|
137
|
-
};
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
const tagCompletions = toCompletions(MINIJINJA_TAGS, "keyword");
|
|
141
|
-
const filterCompletions = toCompletions(MINIJINJA_FILTERS, "function");
|
|
142
|
-
const testCompletions = toCompletions(MINIJINJA_TESTS, "function");
|
|
143
|
-
const functionCompletions = toCompletions(MINIJINJA_FUNCTIONS, "function");
|
|
144
|
-
function memberCompletions(members, type) {
|
|
145
|
-
return members.map((member) => {
|
|
146
|
-
return {
|
|
147
|
-
label: member.name,
|
|
148
|
-
type,
|
|
149
|
-
detail: `${irTypeToString(member.type)}${member.nullable ? "?" : ""}`,
|
|
150
|
-
info: member.doc
|
|
151
|
-
};
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
function irTypeToString(type) {
|
|
155
|
-
switch (type.kind) {
|
|
156
|
-
case "object": return "object";
|
|
157
|
-
case "array": return `${irTypeToString(type.element)}[]`;
|
|
158
|
-
case "enum": return type.values.map((value) => typeof value === "string" ? `"${value}"` : String(value)).join(" | ");
|
|
159
|
-
case "ref": return type.name;
|
|
160
|
-
default: return type.kind;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function walkBase(state, node) {
|
|
164
|
-
if (!node) return null;
|
|
165
|
-
if (node.name === "VariableName" || node.name === "loop") return [state.sliceDoc(node.from, node.to)];
|
|
166
|
-
if (node.name === "MemberExpression") {
|
|
167
|
-
const inner = walkBase(state, node.firstChild);
|
|
168
|
-
const property = node.lastChild;
|
|
169
|
-
if (inner === null || !property || property.name !== "PropertyName") return null;
|
|
170
|
-
return [...inner, state.sliceDoc(property.from, property.to)];
|
|
171
|
-
}
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
function contextTarget(state, pos) {
|
|
175
|
-
const node = syntaxTree(state).resolveInner(pos, -1);
|
|
176
|
-
if (node.name === "PropertyName" && node.parent?.name === "MemberExpression") {
|
|
177
|
-
const path = walkBase(state, node.parent.firstChild);
|
|
178
|
-
return path ? {
|
|
179
|
-
path,
|
|
180
|
-
from: node.from
|
|
181
|
-
} : null;
|
|
182
|
-
}
|
|
183
|
-
if (node.name === "." && node.parent?.name === "MemberExpression") {
|
|
184
|
-
const path = walkBase(state, node.parent.firstChild);
|
|
185
|
-
return path ? {
|
|
186
|
-
path,
|
|
187
|
-
from: pos
|
|
188
|
-
} : null;
|
|
189
|
-
}
|
|
190
|
-
if (node.name === "Definition") return null;
|
|
191
|
-
const word = state.wordAt(pos);
|
|
192
|
-
return {
|
|
193
|
-
path: [],
|
|
194
|
-
from: word ? word.from : pos
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
const LOOP_TYPE = {
|
|
198
|
-
kind: "object",
|
|
199
|
-
fields: {
|
|
200
|
-
index: loopField("number"),
|
|
201
|
-
index0: loopField("number"),
|
|
202
|
-
revindex: loopField("number"),
|
|
203
|
-
revindex0: loopField("number"),
|
|
204
|
-
first: loopField("boolean"),
|
|
205
|
-
last: loopField("boolean"),
|
|
206
|
-
length: loopField("number"),
|
|
207
|
-
depth: loopField("number"),
|
|
208
|
-
depth0: loopField("number"),
|
|
209
|
-
previtem: loopField("any"),
|
|
210
|
-
nextitem: loopField("any"),
|
|
211
|
-
cycle: loopField("any"),
|
|
212
|
-
changed: loopField("any")
|
|
213
|
-
}
|
|
214
|
-
};
|
|
215
|
-
function loopField(kind) {
|
|
216
|
-
return {
|
|
217
|
-
type: { kind },
|
|
218
|
-
required: true,
|
|
219
|
-
nullable: false
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
const ROOT_SCOPE = -1;
|
|
223
|
-
function scopeBindings(state, pos, ir) {
|
|
224
|
-
const bindings = /* @__PURE__ */ new Map();
|
|
225
|
-
const enclosing = [];
|
|
226
|
-
for (let node = syntaxTree(state).resolveInner(pos, -1); node; node = node.parent) if (node.name === "ForStatement" || node.name === "MacroStatement" || node.name === "WithStatement") enclosing.push(node);
|
|
227
|
-
const scopes = enclosing.toReversed();
|
|
228
|
-
const sets = collectSetBindings(state, pos, scopes);
|
|
229
|
-
const applySets = (scopeKey) => {
|
|
230
|
-
const definitions = sets.get(scopeKey) ?? [];
|
|
231
|
-
for (const definition of definitions) bindings.set(state.sliceDoc(definition.from, definition.to), { kind: "any" });
|
|
232
|
-
};
|
|
233
|
-
applySets(ROOT_SCOPE);
|
|
234
|
-
for (const node of scopes) {
|
|
235
|
-
if (node.name === "ForStatement") collectForBindings(state, node, pos, ir, bindings);
|
|
236
|
-
else if (node.name === "MacroStatement") collectMacroBindings(state, node, pos, bindings);
|
|
237
|
-
else collectWithBindings(state, node, pos, ir, bindings);
|
|
238
|
-
applySets(node.from);
|
|
239
|
-
}
|
|
240
|
-
return bindings;
|
|
241
|
-
}
|
|
242
|
-
function collectForBindings(state, forNode, pos, ir, bindings) {
|
|
243
|
-
const tag = forNode.firstChild;
|
|
244
|
-
if (!tag || !tagBodyStarted(tag, pos)) return;
|
|
245
|
-
const definitions = [];
|
|
246
|
-
let iterable = null;
|
|
247
|
-
let seenIn = false;
|
|
248
|
-
for (let child = tag.firstChild; child; child = child.nextSibling) if (child.name === "in") seenIn = true;
|
|
249
|
-
else if (!seenIn && child.name === "Definition") definitions.push(child);
|
|
250
|
-
else if (seenIn && !iterable && child.name !== "%}") iterable = child;
|
|
251
|
-
let element = null;
|
|
252
|
-
if (definitions.length === 1 && iterable) {
|
|
253
|
-
const path = walkBase(state, iterable);
|
|
254
|
-
const iterableType = path ? typeAtPath(ir, path, bindings) : null;
|
|
255
|
-
element = iterableType ? elementType(ir, iterableType) : null;
|
|
256
|
-
}
|
|
257
|
-
bindings.set("loop", LOOP_TYPE);
|
|
258
|
-
for (const definition of definitions) bindings.set(state.sliceDoc(definition.from, definition.to), element ?? { kind: "any" });
|
|
259
|
-
}
|
|
260
|
-
function collectWithBindings(state, withNode, pos, ir, bindings) {
|
|
261
|
-
const tag = withNode.firstChild;
|
|
262
|
-
if (!tag || tag.name !== "Tag") return;
|
|
263
|
-
const inBody = tagBodyStarted(tag, pos);
|
|
264
|
-
let targets = [];
|
|
265
|
-
for (let child = tag.firstChild; child; child = child.nextSibling) {
|
|
266
|
-
if (child.name === "Definition") {
|
|
267
|
-
targets.push(child);
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
if (child.name !== "AssignOp" || targets.length === 0) continue;
|
|
271
|
-
const value = child.nextSibling;
|
|
272
|
-
const delimiter = value?.nextSibling;
|
|
273
|
-
if (inBody || delimiter?.name === "," && delimiter.to <= pos) {
|
|
274
|
-
const path = targets.length === 1 && value ? walkBase(state, value) : null;
|
|
275
|
-
const type = path ? typeAtPath(ir, path, bindings) : null;
|
|
276
|
-
for (const target of targets) bindings.set(state.sliceDoc(target.from, target.to), type ?? { kind: "any" });
|
|
277
|
-
}
|
|
278
|
-
targets = [];
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
function collectMacroBindings(state, macroNode, pos, bindings) {
|
|
282
|
-
const tag = macroNode.firstChild;
|
|
283
|
-
if (!tag || !tagBodyStarted(tag, pos)) return;
|
|
284
|
-
const paramList = tag.getChild("ParamList");
|
|
285
|
-
if (!paramList) return;
|
|
286
|
-
for (let child = paramList.firstChild; child; child = child.nextSibling) if (child.name === "Definition") bindings.set(state.sliceDoc(child.from, child.to), { kind: "any" });
|
|
287
|
-
}
|
|
288
|
-
function tagBodyStarted(tag, pos) {
|
|
289
|
-
return tag.name === "Tag" && tag.getChild("%}") !== null && pos >= tag.to;
|
|
290
|
-
}
|
|
291
|
-
function collectSetBindings(state, pos, scopes) {
|
|
292
|
-
const scopeStarts = new Set(scopes.map((scope) => scope.from));
|
|
293
|
-
const sets = /* @__PURE__ */ new Map();
|
|
294
|
-
syntaxTree(state).iterate({
|
|
295
|
-
to: pos,
|
|
296
|
-
enter: (node) => {
|
|
297
|
-
if (node.name !== "Tag" || node.to > pos) return;
|
|
298
|
-
const keyword = node.node.firstChild?.nextSibling;
|
|
299
|
-
if (!keyword || state.sliceDoc(keyword.from, keyword.to) !== "set") return;
|
|
300
|
-
const definitions = [];
|
|
301
|
-
let assignment = false;
|
|
302
|
-
for (let child = keyword.nextSibling; child; child = child.nextSibling) {
|
|
303
|
-
if (child.name === "AssignOp") {
|
|
304
|
-
assignment = true;
|
|
305
|
-
break;
|
|
306
|
-
}
|
|
307
|
-
if (child.name === "Definition") definitions.push(child);
|
|
308
|
-
}
|
|
309
|
-
if (definitions.length === 0) return;
|
|
310
|
-
const statement = node.node.parent;
|
|
311
|
-
if (assignment) {
|
|
312
|
-
if (!node.node.getChild("%}")) return;
|
|
313
|
-
} else if (statement?.name !== "SetStatement" || statement.to > pos || !statement.getChild("EndTag")) return;
|
|
314
|
-
let scopeKey = ROOT_SCOPE;
|
|
315
|
-
for (let { parent } = node.node; parent; parent = parent.parent) if (parent.name === "ForStatement" || parent.name === "MacroStatement" || parent.name === "WithStatement") {
|
|
316
|
-
if (!scopeStarts.has(parent.from)) return;
|
|
317
|
-
scopeKey = parent.from;
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
const bucket = sets.get(scopeKey);
|
|
321
|
-
if (bucket) bucket.push(...definitions);
|
|
322
|
-
else sets.set(scopeKey, definitions);
|
|
323
|
-
}
|
|
324
|
-
});
|
|
325
|
-
return sets;
|
|
326
|
-
}
|
|
327
|
-
function jinjaContext(state, pos, side) {
|
|
328
|
-
for (let node = syntaxTree(state).resolveInner(pos, side); node; node = node.parent) {
|
|
329
|
-
const { name } = node;
|
|
330
|
-
if (name === "Comment") return "comment";
|
|
331
|
-
if (name === "StringLiteral" || name === "NumberLiteral") return null;
|
|
332
|
-
if (name === "Interpolation" || name === "Tag" || name === "EndTag") return "expr";
|
|
333
|
-
}
|
|
334
|
-
return null;
|
|
335
|
-
}
|
|
336
|
-
function minijinjaCompletion(context) {
|
|
337
|
-
const word = context.matchBefore(/\w*/);
|
|
338
|
-
if (!word) return null;
|
|
339
|
-
const { from } = word;
|
|
340
|
-
const before = context.state.sliceDoc(Math.max(0, from - 24), from);
|
|
341
|
-
let side = from === context.pos ? 1 : -1;
|
|
342
|
-
if (side === 1 && context.pos === context.state.doc.length) {
|
|
343
|
-
const left = syntaxTree(context.state).resolveInner(context.pos, -1);
|
|
344
|
-
if (left.name !== "}}" && left.name !== "%}" && left.name !== "#}") side = -1;
|
|
345
|
-
}
|
|
346
|
-
if (jinjaContext(context.state, context.pos, side) !== "expr") return null;
|
|
347
|
-
if (/\{%[-+]?\s*$/.test(before)) return {
|
|
348
|
-
from,
|
|
349
|
-
options: tagCompletions,
|
|
350
|
-
validFor: /^\w*$/
|
|
351
|
-
};
|
|
352
|
-
if (/\|\s*$/.test(before)) return {
|
|
353
|
-
from,
|
|
354
|
-
options: filterCompletions,
|
|
355
|
-
validFor: /^\w*$/
|
|
356
|
-
};
|
|
357
|
-
if (/\bis\s+(?:not\s+)?$/.test(before)) return {
|
|
358
|
-
from,
|
|
359
|
-
options: testCompletions,
|
|
360
|
-
validFor: /^\w*$/
|
|
361
|
-
};
|
|
362
|
-
const ir = context.state.field(minijinjaContextField, false);
|
|
363
|
-
if (ir) {
|
|
364
|
-
const target = contextTarget(context.state, context.pos);
|
|
365
|
-
if (!target) return null;
|
|
366
|
-
const scope = scopeBindings(context.state, context.pos, ir);
|
|
367
|
-
const members = resolveMembers(ir, target.path, scope);
|
|
368
|
-
if (target.path.length > 0) return members.length > 0 ? {
|
|
369
|
-
from: target.from,
|
|
370
|
-
options: memberCompletions(members, "property"),
|
|
371
|
-
validFor: /^\w*$/
|
|
372
|
-
} : null;
|
|
373
|
-
if (target.from === context.pos && !context.explicit) return null;
|
|
374
|
-
return {
|
|
375
|
-
from: target.from,
|
|
376
|
-
options: [...memberCompletions(members, "variable"), ...functionCompletions],
|
|
377
|
-
validFor: /^\w*$/
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
if (from === context.pos && !context.explicit) return null;
|
|
381
|
-
return {
|
|
382
|
-
from,
|
|
383
|
-
options: functionCompletions,
|
|
384
|
-
validFor: /^\w*$/
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
function minijinjaDiagnostics(state) {
|
|
388
|
-
const diagnostics = [];
|
|
389
|
-
const { doc } = state;
|
|
390
|
-
syntaxTree(state).iterate({ enter: (node) => {
|
|
391
|
-
if (node.name !== "Tag" && node.name !== "EndTag") return;
|
|
392
|
-
const keywordNode = node.node.firstChild?.nextSibling;
|
|
393
|
-
if (!keywordNode || keywordNode.type.isError) return;
|
|
394
|
-
const keyword = doc.sliceString(keywordNode.from, keywordNode.to);
|
|
395
|
-
if (!MINIJINJA_TAGS.has(keyword)) diagnostics.push({
|
|
396
|
-
from: keywordNode.from,
|
|
397
|
-
to: keywordNode.to,
|
|
398
|
-
severity: "error",
|
|
399
|
-
message: `"${keyword}" is not a MiniJinja tag.`
|
|
400
|
-
});
|
|
401
|
-
} });
|
|
402
|
-
return diagnostics;
|
|
403
|
-
}
|
|
404
|
-
const minijinjaLinter = linter((view) => minijinjaDiagnostics(view.state));
|
|
405
|
-
function minijinja(config = {}) {
|
|
406
|
-
const { base, context } = config;
|
|
407
|
-
const language = base ? jinja({ base }).language : jinjaLanguage;
|
|
408
|
-
const contextField = context ? minijinjaContextField.init(() => normalizeContext(context)) : minijinjaContextField;
|
|
409
|
-
const support = [
|
|
410
|
-
language.data.of({ autocomplete: minijinjaCompletion }),
|
|
411
|
-
minijinjaLinter,
|
|
412
|
-
contextField
|
|
413
|
-
];
|
|
414
|
-
if (base) support.push(base.support);
|
|
415
|
-
return new LanguageSupport(language, support);
|
|
416
|
-
}
|
|
417
|
-
//#endregion
|
|
418
|
-
export { minijinja, minijinjaCompletion, minijinjaDiagnostics };
|