@coldsmirk/inkstone-codemirror 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/context-D86o2jK3.js +382 -0
- package/dist/index.d.ts +241 -46
- package/dist/index.js +162 -16
- package/dist/{minijinja-HpehSBbW.js → minijinja-D_5erBa7.js} +81 -18
- package/package.json +7 -12
- package/dist/context-BDibyUwD.cjs +0 -270
- package/dist/context-Dx6bPnKq.js +0 -235
- package/dist/index.cjs +0 -166
- package/dist/index.d.cts +0 -362
- package/dist/minijinja-DN9iLNbL.cjs +0 -357
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). For a drop-in React c
|
|
|
8
8
|
|
|
9
9
|
- **`ControlledEditorHost`** — the controlled-editor lifecycle solved once: the view is created once, external value changes reconcile into the document without resetting cursor/undo, and theme/extension swaps happen in place.
|
|
10
10
|
- **`documentExtensions(options)`** — the standard document editing bundle (history, brackets, completion UI, optional line numbers / wrapping / search), so hosts start from working defaults instead of a bare `EditorState`.
|
|
11
|
-
- **`codeMirrorLanguages` / `loadLanguage(language)`** — the supported `CodeMirrorLanguage` names and their lazy loaders: one dynamic `import()` per grammar, so only the selected language is fetched, never the whole catalog.
|
|
12
|
-
- **MiniJinja** — `language: "minijinja"` for standalone templates, or `minijinja-<host>` mixed variants (`minijinja-html`, `-xml`, `-json`, `-yaml`, `-css`, `-scss`, `-sass`, `-less`, `-markdown
|
|
11
|
+
- **`codeMirrorLanguages` / `loadLanguage(language)`** — the supported `CodeMirrorLanguage` names and their lazy loaders: one dynamic `import()` per grammar, so only the selected language is fetched, never the whole catalog. Two tiers back the ids: the official `@codemirror/lang-*` (Lezer) parsers where upstream ships one, plus the full [`@codemirror/legacy-modes`](https://github.com/codemirror/legacy-modes) catalog (stream-mode highlighting) for everything upstream never wrote a Lezer grammar for — `shell`, `dockerfile`, `ini` / `env` / `properties`, `toml`, `nginx`, `powershell`, `lua`, and a hundred more.
|
|
12
|
+
- **MiniJinja** — `language: "minijinja"` for standalone templates, or `minijinja-<host>` mixed variants (`minijinja-html`, `-xml`, `-json`, `-yaml`, `-css`, `-scss`, `-sass`, `-less`, `-markdown`; the SQL family — `-sql` plus every dialect id: `-mysql`, `-pgsql`, `-sqlite`, `-mssql`, `-mariadb`, `-plsql`, `-cassandra`, `-hive`, `-sparksql`, `-gql`, `-gpsql`, `-esper`; and the config/deploy hosts `-toml`, `-ini`, `-env`, `-shell`, `-dockerfile`, `-nginx`) that overlay MiniJinja tooling on the host grammar. A linter flags non-MiniJinja tags; autocomplete is restricted to MiniJinja's real tags / filters / tests / functions.
|
|
13
13
|
- **Context completion** — `normalizeContext({ schema })` (JSON Schema) or `normalizeContext({ sample })` (representative value) builds an `EditorContext`; dispatch it with `setMinijinjaContext` to make `{{ }}` / `{% if %}` / `{% for %}` complete the render context's variables and walk member access (`user.address.city`). `minijinjaContextField`, `resolveMembers`, and `typeAtPath` expose the underlying pieces.
|
|
14
14
|
- **`searchPhrasesZhCn`** — an opt-in `EditorState.phrases` table localizing the search panel to Simplified Chinese.
|
|
15
15
|
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import { StateEffect, StateField } from "@codemirror/state";
|
|
2
|
+
//#region src/context.ts
|
|
3
|
+
const ANY = { kind: "any" };
|
|
4
|
+
const NULL = { kind: "null" };
|
|
5
|
+
const MAX_DEREF = 100;
|
|
6
|
+
const setMinijinjaContext = StateEffect.define();
|
|
7
|
+
const minijinjaContextField = StateField.define({
|
|
8
|
+
create() {
|
|
9
|
+
return null;
|
|
10
|
+
},
|
|
11
|
+
update(value, transaction) {
|
|
12
|
+
let next = value;
|
|
13
|
+
for (const effect of transaction.effects) if (effect.is(setMinijinjaContext)) next = effect.value;
|
|
14
|
+
return next;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
function normalizeContext(input) {
|
|
18
|
+
if ("schema" in input) return fromJsonSchema(input.schema);
|
|
19
|
+
return {
|
|
20
|
+
root: fromSample(input.sample),
|
|
21
|
+
defs: {}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function resolveMembers(ir, path, scope) {
|
|
25
|
+
if (path.length === 0) {
|
|
26
|
+
const top = membersOf(ir, ir.root);
|
|
27
|
+
if (!scope || scope.size === 0) return top;
|
|
28
|
+
return [...[...scope].map(([name, type]) => {
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
type,
|
|
32
|
+
required: true,
|
|
33
|
+
nullable: false
|
|
34
|
+
};
|
|
35
|
+
}), ...top];
|
|
36
|
+
}
|
|
37
|
+
const type = typeAtPath(ir, path, scope);
|
|
38
|
+
return type ? membersOf(ir, type) : [];
|
|
39
|
+
}
|
|
40
|
+
function typeAtPath(ir, path, scope) {
|
|
41
|
+
const [first, ...rest] = path;
|
|
42
|
+
if (first === void 0) return deref(ir, ir.root);
|
|
43
|
+
let type = scope?.get(first) ?? stepInto(ir, ir.root, first);
|
|
44
|
+
for (const key of rest) {
|
|
45
|
+
if (type === null) return null;
|
|
46
|
+
type = stepInto(ir, type, key);
|
|
47
|
+
}
|
|
48
|
+
return type === null ? null : deref(ir, type);
|
|
49
|
+
}
|
|
50
|
+
function elementType(ir, type) {
|
|
51
|
+
const resolved = deref(ir, type);
|
|
52
|
+
return resolved.kind === "array" ? deref(ir, resolved.element) : null;
|
|
53
|
+
}
|
|
54
|
+
function followRefs(type, lookup) {
|
|
55
|
+
let current = type;
|
|
56
|
+
for (let i = 0; i < MAX_DEREF && current.kind === "ref"; i++) {
|
|
57
|
+
const next = lookup(current.name);
|
|
58
|
+
if (!next) return null;
|
|
59
|
+
current = next;
|
|
60
|
+
}
|
|
61
|
+
return current.kind === "ref" ? null : current;
|
|
62
|
+
}
|
|
63
|
+
function deref(ir, type) {
|
|
64
|
+
return followRefs(type, (name) => ir.defs[name] ?? null) ?? ANY;
|
|
65
|
+
}
|
|
66
|
+
function stepInto(ir, type, key) {
|
|
67
|
+
const resolved = deref(ir, type);
|
|
68
|
+
if (resolved.kind !== "object") return null;
|
|
69
|
+
const field = resolved.fields[key];
|
|
70
|
+
return field ? field.type : null;
|
|
71
|
+
}
|
|
72
|
+
function membersOf(ir, type) {
|
|
73
|
+
const resolved = deref(ir, type);
|
|
74
|
+
if (resolved.kind !== "object") return [];
|
|
75
|
+
return Object.entries(resolved.fields).map(([name, field]) => {
|
|
76
|
+
return {
|
|
77
|
+
name,
|
|
78
|
+
type: field.type,
|
|
79
|
+
required: field.required,
|
|
80
|
+
nullable: field.nullable,
|
|
81
|
+
doc: field.doc
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const REF_PREFIXES = ["#/$defs/", "#/definitions/"];
|
|
86
|
+
function fromJsonSchema(schema) {
|
|
87
|
+
if (!isObject(schema)) return {
|
|
88
|
+
root: ANY,
|
|
89
|
+
defs: {}
|
|
90
|
+
};
|
|
91
|
+
const context = {
|
|
92
|
+
raw: {
|
|
93
|
+
...asObject(schema.definitions),
|
|
94
|
+
...asObject(schema.$defs)
|
|
95
|
+
},
|
|
96
|
+
defs: Object.create(null),
|
|
97
|
+
resolving: /* @__PURE__ */ new Set(),
|
|
98
|
+
tainted: /* @__PURE__ */ new Set(),
|
|
99
|
+
cyclic: /* @__PURE__ */ new Set(),
|
|
100
|
+
dependents: /* @__PURE__ */ new Map(),
|
|
101
|
+
converting: []
|
|
102
|
+
};
|
|
103
|
+
for (const name of Object.keys(context.raw)) defType(name, context);
|
|
104
|
+
if (context.tainted.size > 0) {
|
|
105
|
+
const queue = [...context.tainted];
|
|
106
|
+
const pending = new Set(queue);
|
|
107
|
+
let head = 0;
|
|
108
|
+
let budget = (Object.keys(context.raw).length + 1) ** 2;
|
|
109
|
+
while (head < queue.length && budget > 0) {
|
|
110
|
+
budget -= 1;
|
|
111
|
+
const name = queue[head];
|
|
112
|
+
head += 1;
|
|
113
|
+
if (name === void 0) break;
|
|
114
|
+
pending.delete(name);
|
|
115
|
+
context.converting.push(name);
|
|
116
|
+
const next = convert(context.raw[name], context);
|
|
117
|
+
context.converting.pop();
|
|
118
|
+
if (JSON.stringify(next) !== JSON.stringify(context.defs[name])) {
|
|
119
|
+
context.defs[name] = next;
|
|
120
|
+
const stale = [...context.dependents.get(name) ?? []].filter((reader) => !pending.has(reader));
|
|
121
|
+
for (const dependent of stale) {
|
|
122
|
+
pending.add(dependent);
|
|
123
|
+
queue.push(dependent);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
root: convert(schema, context),
|
|
130
|
+
defs: context.defs
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function defType(name, context) {
|
|
134
|
+
const reader = context.converting.at(-1);
|
|
135
|
+
if (reader !== void 0 && reader !== name) {
|
|
136
|
+
const readers = context.dependents.get(name);
|
|
137
|
+
if (readers) readers.add(reader);
|
|
138
|
+
else context.dependents.set(name, /* @__PURE__ */ new Set([reader]));
|
|
139
|
+
}
|
|
140
|
+
if (Object.hasOwn(context.defs, name)) return context.defs[name] ?? null;
|
|
141
|
+
if (context.resolving.has(name)) {
|
|
142
|
+
for (const pending of context.converting) context.tainted.add(pending);
|
|
143
|
+
const cycleStart = context.converting.lastIndexOf(name);
|
|
144
|
+
if (cycleStart === -1) context.cyclic.add(name);
|
|
145
|
+
else for (const member of context.converting.slice(cycleStart)) context.cyclic.add(member);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
if (!Object.hasOwn(context.raw, name)) return null;
|
|
149
|
+
context.resolving.add(name);
|
|
150
|
+
context.converting.push(name);
|
|
151
|
+
const type = convert(context.raw[name], context);
|
|
152
|
+
context.converting.pop();
|
|
153
|
+
context.resolving.delete(name);
|
|
154
|
+
context.defs[name] = type;
|
|
155
|
+
return type;
|
|
156
|
+
}
|
|
157
|
+
function convert(node, context) {
|
|
158
|
+
if (typeof node === "boolean" || !isObject(node)) return ANY;
|
|
159
|
+
const ref = refName(node.$ref);
|
|
160
|
+
if (ref !== null) return {
|
|
161
|
+
kind: "ref",
|
|
162
|
+
name: ref
|
|
163
|
+
};
|
|
164
|
+
if (Array.isArray(node.allOf)) {
|
|
165
|
+
const branches = node.allOf.map((entry) => convert(entry, context));
|
|
166
|
+
return requireFields(mergeAll(isObject(node.properties) ? [...branches, objectType(node, context)] : branches, context, "all"), node.required, context);
|
|
167
|
+
}
|
|
168
|
+
const union = node.anyOf ?? node.oneOf;
|
|
169
|
+
if (Array.isArray(union)) {
|
|
170
|
+
const viable = union.filter((branch) => unionBranchKind(branch, context) !== "impossible");
|
|
171
|
+
const nonNull = viable.filter((branch) => unionBranchKind(branch, context) !== "null");
|
|
172
|
+
if (viable.length === 0) return ANY;
|
|
173
|
+
if (nonNull.length === 0) return NULL;
|
|
174
|
+
const merged = nonNull.length === 1 ? convert(nonNull[0], context) : mergeAll(nonNull.map((entry) => convert(entry, context)), context, "any");
|
|
175
|
+
return requireFields(isObject(node.properties) ? mergeAll([merged, objectType(node, context)], context, "all") : merged, node.required, context);
|
|
176
|
+
}
|
|
177
|
+
if (Array.isArray(node.enum)) return {
|
|
178
|
+
kind: "enum",
|
|
179
|
+
values: node.enum.filter(isLiteral)
|
|
180
|
+
};
|
|
181
|
+
if ("const" in node && isLiteral(node.const)) return {
|
|
182
|
+
kind: "enum",
|
|
183
|
+
values: [node.const]
|
|
184
|
+
};
|
|
185
|
+
const type = primaryType(node);
|
|
186
|
+
if (isObjectShape(node)) return objectType(node, context);
|
|
187
|
+
if (type === "array") return {
|
|
188
|
+
kind: "array",
|
|
189
|
+
element: convert(Array.isArray(node.items) ? node.items[0] : node.items, context)
|
|
190
|
+
};
|
|
191
|
+
if (type === "string") return { kind: "string" };
|
|
192
|
+
if (type === "integer" || type === "number") return { kind: "number" };
|
|
193
|
+
if (type === "boolean") return { kind: "boolean" };
|
|
194
|
+
if (type === "null") return NULL;
|
|
195
|
+
return ANY;
|
|
196
|
+
}
|
|
197
|
+
function isObjectShape(node) {
|
|
198
|
+
return primaryType(node) === "object" || isObject(node.properties);
|
|
199
|
+
}
|
|
200
|
+
function objectType(node, context) {
|
|
201
|
+
const properties = asObject(node.properties);
|
|
202
|
+
const required = new Set(Array.isArray(node.required) ? node.required.filter((name) => typeof name === "string") : []);
|
|
203
|
+
const fields = Object.create(null);
|
|
204
|
+
for (const [name, sub] of Object.entries(properties)) fields[name] = {
|
|
205
|
+
type: convert(sub, context),
|
|
206
|
+
required: required.has(name),
|
|
207
|
+
nullable: isNullable(sub, context),
|
|
208
|
+
doc: description(sub)
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
kind: "object",
|
|
212
|
+
fields
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function mergeAll(types, context, mode) {
|
|
216
|
+
const [only] = types;
|
|
217
|
+
if (only && types.length === 1) return only;
|
|
218
|
+
const fields = Object.create(null);
|
|
219
|
+
const appearances = /* @__PURE__ */ new Map();
|
|
220
|
+
let branches = 0;
|
|
221
|
+
for (const type of types) {
|
|
222
|
+
const resolved = derefFully(type, context);
|
|
223
|
+
if (resolved?.kind === "object") {
|
|
224
|
+
branches += 1;
|
|
225
|
+
for (const [name, field] of Object.entries(resolved.fields)) {
|
|
226
|
+
const existing = fields[name];
|
|
227
|
+
fields[name] = existing ? mergeField(existing, field, mode) : field;
|
|
228
|
+
appearances.set(name, (appearances.get(name) ?? 0) + 1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (branches > 0) {
|
|
233
|
+
if (mode === "any") {
|
|
234
|
+
for (const [name, field] of Object.entries(fields)) if (field.required && appearances.get(name) !== types.length) fields[name] = {
|
|
235
|
+
...field,
|
|
236
|
+
required: false
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
kind: "object",
|
|
241
|
+
fields
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return types.find((type) => type.kind !== "any") ?? ANY;
|
|
245
|
+
}
|
|
246
|
+
function requireFields(type, required, context) {
|
|
247
|
+
const names = Array.isArray(required) ? required.filter((name) => typeof name === "string") : [];
|
|
248
|
+
if (names.length === 0) return type;
|
|
249
|
+
const resolved = type.kind === "ref" ? derefNonCyclic(type, context) : type;
|
|
250
|
+
if (resolved === null || resolved.kind !== "object") return type;
|
|
251
|
+
const fields = Object.assign(Object.create(null), resolved.fields);
|
|
252
|
+
let changed = false;
|
|
253
|
+
for (const name of names) {
|
|
254
|
+
const field = fields[name];
|
|
255
|
+
if (field && !field.required) {
|
|
256
|
+
fields[name] = {
|
|
257
|
+
...field,
|
|
258
|
+
required: true
|
|
259
|
+
};
|
|
260
|
+
changed = true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return changed ? {
|
|
264
|
+
kind: "object",
|
|
265
|
+
fields
|
|
266
|
+
} : type;
|
|
267
|
+
}
|
|
268
|
+
function mergeField(existing, incoming, mode) {
|
|
269
|
+
return {
|
|
270
|
+
type: incoming.type,
|
|
271
|
+
required: mode === "all" ? existing.required || incoming.required : existing.required && incoming.required,
|
|
272
|
+
nullable: mode === "all" ? existing.nullable && incoming.nullable : existing.nullable || incoming.nullable,
|
|
273
|
+
doc: incoming.doc ?? existing.doc
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function derefFully(type, context) {
|
|
277
|
+
return followRefs(type, (name) => defType(name, context));
|
|
278
|
+
}
|
|
279
|
+
function derefNonCyclic(type, context) {
|
|
280
|
+
let current = type;
|
|
281
|
+
for (let i = 0; i < MAX_DEREF && current.kind === "ref"; i++) {
|
|
282
|
+
if (context.cyclic.has(current.name)) return null;
|
|
283
|
+
const next = defType(current.name, context);
|
|
284
|
+
if (!next) return null;
|
|
285
|
+
current = next;
|
|
286
|
+
}
|
|
287
|
+
return current.kind === "ref" ? null : current;
|
|
288
|
+
}
|
|
289
|
+
function fromSample(value, ancestors = /* @__PURE__ */ new WeakSet()) {
|
|
290
|
+
if (value === null || value === void 0) return ANY;
|
|
291
|
+
if (typeof value === "object") {
|
|
292
|
+
if (ancestors.has(value)) return ANY;
|
|
293
|
+
ancestors.add(value);
|
|
294
|
+
const type = Array.isArray(value) ? sampleArrayType(value, ancestors) : sampleObjectType(value, ancestors);
|
|
295
|
+
ancestors.delete(value);
|
|
296
|
+
return type;
|
|
297
|
+
}
|
|
298
|
+
if (typeof value === "string") return { kind: "string" };
|
|
299
|
+
if (typeof value === "number") return { kind: "number" };
|
|
300
|
+
if (typeof value === "boolean") return { kind: "boolean" };
|
|
301
|
+
return ANY;
|
|
302
|
+
}
|
|
303
|
+
function sampleArrayType(value, ancestors) {
|
|
304
|
+
return {
|
|
305
|
+
kind: "array",
|
|
306
|
+
element: value.length > 0 ? fromSample(value[0], ancestors) : ANY
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function sampleObjectType(value, ancestors) {
|
|
310
|
+
const fields = Object.create(null);
|
|
311
|
+
for (const [name, member] of Object.entries(value)) fields[name] = {
|
|
312
|
+
type: fromSample(member, ancestors),
|
|
313
|
+
required: true,
|
|
314
|
+
nullable: member === null
|
|
315
|
+
};
|
|
316
|
+
return {
|
|
317
|
+
kind: "object",
|
|
318
|
+
fields
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
function refName(ref) {
|
|
322
|
+
if (typeof ref !== "string") return null;
|
|
323
|
+
for (const prefix of REF_PREFIXES) if (ref.startsWith(prefix)) return decodeURIComponent(ref.slice(prefix.length));
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
function primaryType(node) {
|
|
327
|
+
const { type } = node;
|
|
328
|
+
if (typeof type === "string") return type;
|
|
329
|
+
if (Array.isArray(type)) {
|
|
330
|
+
const nonNull = type.find((entry) => typeof entry === "string" && entry !== "null");
|
|
331
|
+
if (typeof nonNull === "string") return nonNull;
|
|
332
|
+
return type.includes("null") ? "null" : null;
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
function isNullable(node, context) {
|
|
337
|
+
const pending = [node];
|
|
338
|
+
const seenRefs = /* @__PURE__ */ new Set();
|
|
339
|
+
while (pending.length > 0) {
|
|
340
|
+
const current = pending.pop();
|
|
341
|
+
if (!isObject(current)) continue;
|
|
342
|
+
const { type } = current;
|
|
343
|
+
if (type === "null" || Array.isArray(type) && type.includes("null")) return true;
|
|
344
|
+
const ref = refName(current.$ref);
|
|
345
|
+
if (ref !== null && !seenRefs.has(ref) && Object.hasOwn(context.raw, ref)) {
|
|
346
|
+
seenRefs.add(ref);
|
|
347
|
+
pending.push(context.raw[ref]);
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const union = current.anyOf ?? current.oneOf;
|
|
351
|
+
if (Array.isArray(union)) pending.push(...union);
|
|
352
|
+
}
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
function unionBranchKind(branch, context) {
|
|
356
|
+
const seenRefs = /* @__PURE__ */ new Set();
|
|
357
|
+
let current = branch;
|
|
358
|
+
for (let i = 0; i < MAX_DEREF; i++) {
|
|
359
|
+
if (current === false) return "impossible";
|
|
360
|
+
if (!isObject(current)) return "other";
|
|
361
|
+
if (current.type === "null" || Array.isArray(current.type) && current.type.length === 1 && current.type[0] === "null") return "null";
|
|
362
|
+
const ref = refName(current.$ref);
|
|
363
|
+
if (ref === null || seenRefs.has(ref) || !Object.hasOwn(context.raw, ref)) return "other";
|
|
364
|
+
seenRefs.add(ref);
|
|
365
|
+
current = context.raw[ref];
|
|
366
|
+
}
|
|
367
|
+
return "other";
|
|
368
|
+
}
|
|
369
|
+
function description(node) {
|
|
370
|
+
return isObject(node) && typeof node.description === "string" ? node.description : void 0;
|
|
371
|
+
}
|
|
372
|
+
function isObject(value) {
|
|
373
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
374
|
+
}
|
|
375
|
+
function asObject(value) {
|
|
376
|
+
return isObject(value) ? value : {};
|
|
377
|
+
}
|
|
378
|
+
function isLiteral(value) {
|
|
379
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
380
|
+
}
|
|
381
|
+
//#endregion
|
|
382
|
+
export { setMinijinjaContext as a, resolveMembers as i, minijinjaContextField as n, typeAtPath as o, normalizeContext as r, elementType as t };
|