@powerduck/schema-designer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +217 -0
- package/dist/InlineSchemaEditor-BssSx3SI.d.ts +6 -0
- package/dist/InlineSchemaEditor-Bua-lDhE.d.cts +6 -0
- package/dist/chunk-2XUQB6BQ.js +1896 -0
- package/dist/chunk-4H3LXOL4.cjs +1900 -0
- package/dist/chunk-7LG4MVMD.cjs +2 -0
- package/dist/chunk-BXFABOMJ.js +1475 -0
- package/dist/chunk-FTALJIVZ.js +1 -0
- package/dist/chunk-GTZH37JS.cjs +1120 -0
- package/dist/chunk-GWHDTTQK.js +1437 -0
- package/dist/chunk-GXXD6ITE.cjs +1477 -0
- package/dist/chunk-HI5FBHCO.js +1057 -0
- package/dist/chunk-KX3LFFOV.js +88 -0
- package/dist/chunk-MADPN2PJ.js +185 -0
- package/dist/chunk-NOUORNCI.cjs +1452 -0
- package/dist/chunk-O6PTRJQ5.js +1195 -0
- package/dist/chunk-OBHJC3I2.cjs +2 -0
- package/dist/chunk-OOSNM45O.cjs +264 -0
- package/dist/chunk-P5B3HSPY.js +244 -0
- package/dist/chunk-PBE36BVA.js +1 -0
- package/dist/chunk-PVEYKCM6.js +1 -0
- package/dist/chunk-QZADGAP3.cjs +1218 -0
- package/dist/chunk-S7GNTGEE.js +1 -0
- package/dist/chunk-SMBDRWV2.cjs +2 -0
- package/dist/chunk-THYDOHOP.cjs +2 -0
- package/dist/chunk-WRHWOMZQ.cjs +190 -0
- package/dist/chunk-YNKP5JJA.cjs +32 -0
- package/dist/chunk-YWDKCX6N.cjs +91 -0
- package/dist/chunk-ZHNYNFGL.js +28 -0
- package/dist/compat/inline.cjs +137 -0
- package/dist/compat/inline.css +275 -0
- package/dist/compat/inline.d.cts +6 -0
- package/dist/compat/inline.d.ts +6 -0
- package/dist/compat/inline.js +4 -0
- package/dist/compat/parameters.cjs +90 -0
- package/dist/compat/parameters.css +997 -0
- package/dist/compat/parameters.d.cts +70 -0
- package/dist/compat/parameters.d.ts +70 -0
- package/dist/compat/parameters.js +9 -0
- package/dist/compat/tree.cjs +142 -0
- package/dist/compat/tree.css +1069 -0
- package/dist/compat/tree.d.cts +4 -0
- package/dist/compat/tree.d.ts +4 -0
- package/dist/compat/tree.js +5 -0
- package/dist/compat/variable-editor.cjs +82 -0
- package/dist/compat/variable-editor.d.cts +68 -0
- package/dist/compat/variable-editor.d.ts +68 -0
- package/dist/compat/variable-editor.js +1 -0
- package/dist/core/index.cjs +197 -0
- package/dist/core/index.d.cts +21 -0
- package/dist/core/index.d.ts +21 -0
- package/dist/core/index.js +4 -0
- package/dist/index.cjs +35 -0
- package/dist/index.css +1791 -0
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +10 -0
- package/dist/parameterValue-2pL9n-3q.d.ts +8 -0
- package/dist/parameterValue-Cky9Lnd3.d.cts +8 -0
- package/dist/react/index.cjs +35 -0
- package/dist/react/index.css +1791 -0
- package/dist/react/index.d.cts +9 -0
- package/dist/react/index.d.ts +9 -0
- package/dist/react/index.js +10 -0
- package/dist/react/inlineSchemaEditor/index.cjs +97 -0
- package/dist/react/inlineSchemaEditor/index.css +275 -0
- package/dist/react/inlineSchemaEditor/index.d.cts +6 -0
- package/dist/react/inlineSchemaEditor/index.d.ts +6 -0
- package/dist/react/inlineSchemaEditor/index.js +4 -0
- package/dist/react/parametersTable/index.cjs +22 -0
- package/dist/react/parametersTable/index.css +997 -0
- package/dist/react/parametersTable/index.d.cts +7 -0
- package/dist/react/parametersTable/index.d.ts +7 -0
- package/dist/react/parametersTable/index.js +9 -0
- package/dist/react/parametersTable/libs/generateValue.cjs +558 -0
- package/dist/react/parametersTable/libs/generateValue.d.cts +17 -0
- package/dist/react/parametersTable/libs/generateValue.d.ts +17 -0
- package/dist/react/parametersTable/libs/generateValue.js +551 -0
- package/dist/react/schemaTreeEditor/index.cjs +18 -0
- package/dist/react/schemaTreeEditor/index.css +1069 -0
- package/dist/react/schemaTreeEditor/index.d.cts +7 -0
- package/dist/react/schemaTreeEditor/index.d.ts +7 -0
- package/dist/react/schemaTreeEditor/index.js +5 -0
- package/dist/react/variableTextEditor/index.cjs +11 -0
- package/dist/react/variableTextEditor/index.css +306 -0
- package/dist/react/variableTextEditor/index.d.cts +6 -0
- package/dist/react/variableTextEditor/index.d.ts +6 -0
- package/dist/react/variableTextEditor/index.js +2 -0
- package/dist/schema-CKAPsYeW.d.cts +41 -0
- package/dist/schema-o7OJRaJ8.d.ts +41 -0
- package/dist/styles.css +1791 -0
- package/dist/tree-D06Xa6_N.d.ts +95 -0
- package/dist/tree-Dq1Rk-CF.d.cts +95 -0
- package/dist/types-B27Dw9do.d.cts +163 -0
- package/dist/types-B27Dw9do.d.ts +163 -0
- package/dist/types-Bk9rzr6l.d.cts +48 -0
- package/dist/types-D2jEaM9Z.d.cts +145 -0
- package/dist/types-D2jEaM9Z.d.ts +145 -0
- package/dist/types-xAihO_KW.d.ts +48 -0
- package/dist/variableTextEditor.types-ClzvARvK.d.cts +49 -0
- package/dist/variableTextEditor.types-ClzvARvK.d.ts +49 -0
- package/package.json +130 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var view = require('@codemirror/view');
|
|
4
|
+
|
|
5
|
+
// src/react/variableTextEditor/libs/variableTextEditor.utils.ts
|
|
6
|
+
function validCssColorSSRSafe(value) {
|
|
7
|
+
const candidate = value?.trim();
|
|
8
|
+
if (!candidate || /[;{}\r\n]/.test(candidate)) return void 0;
|
|
9
|
+
if (typeof CSS === "undefined") return candidate;
|
|
10
|
+
try {
|
|
11
|
+
if (typeof CSS.supports !== "function") return candidate;
|
|
12
|
+
if (!CSS.supports("color", candidate)) return void 0;
|
|
13
|
+
} catch {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
return candidate;
|
|
17
|
+
}
|
|
18
|
+
var VARIABLE_NAME_PATTERN = /^[\p{L}\p{N}_$.-]+$/u;
|
|
19
|
+
var VARIABLE_NAME_PATTERN_STRICT = /^[\p{L}\p{N}_$.-]+$/u;
|
|
20
|
+
var VARIABLE_TOKEN_REGEX = /\{\{([\p{L}\p{N}_$.-]+)\}\}|\{([\p{L}\p{N}_$.-]+)\}/gu;
|
|
21
|
+
var VARIABLE_QUERY_PATTERN = /(?:\{\{|\{)[\p{L}\p{N}_$.-]*$/u;
|
|
22
|
+
function tokenTypeClass(type) {
|
|
23
|
+
switch (type?.trim().toLowerCase()) {
|
|
24
|
+
case "secret":
|
|
25
|
+
case "environment":
|
|
26
|
+
case "request":
|
|
27
|
+
case "dynamic":
|
|
28
|
+
return type.trim().toLowerCase();
|
|
29
|
+
default:
|
|
30
|
+
return "unknown";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function parseVariableNameFromToken(token) {
|
|
34
|
+
if (token.startsWith("{{") && token.endsWith("}}")) {
|
|
35
|
+
const inner = token.slice(2, -2);
|
|
36
|
+
return VARIABLE_NAME_PATTERN_STRICT.test(inner) ? inner : null;
|
|
37
|
+
}
|
|
38
|
+
if (token.startsWith("{") && token.endsWith("}")) {
|
|
39
|
+
const inner = token.slice(1, -1);
|
|
40
|
+
return VARIABLE_NAME_PATTERN_STRICT.test(inner) ? inner : null;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function createVariableMap(variables) {
|
|
45
|
+
const result = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const variable of variables) {
|
|
47
|
+
const name = variable.name?.trim();
|
|
48
|
+
if (name && VARIABLE_NAME_PATTERN.test(name)) {
|
|
49
|
+
result.set(
|
|
50
|
+
name,
|
|
51
|
+
name === variable.name ? variable : { ...variable, name }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function findVariableTokens(text, variables) {
|
|
58
|
+
const variableMap = createVariableMap(variables);
|
|
59
|
+
const matches = [];
|
|
60
|
+
for (const match of text.matchAll(VARIABLE_TOKEN_REGEX)) {
|
|
61
|
+
const full = match[0];
|
|
62
|
+
const index = match.index;
|
|
63
|
+
if (index == null) continue;
|
|
64
|
+
const name = match[1] ?? match[2];
|
|
65
|
+
if (!name) continue;
|
|
66
|
+
if (!VARIABLE_NAME_PATTERN.test(name)) continue;
|
|
67
|
+
matches.push({
|
|
68
|
+
token: full,
|
|
69
|
+
name,
|
|
70
|
+
from: index,
|
|
71
|
+
to: index + full.length,
|
|
72
|
+
variable: variableMap.get(name)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return matches;
|
|
76
|
+
}
|
|
77
|
+
function splitVariableText(text, variables) {
|
|
78
|
+
const parts = [];
|
|
79
|
+
const tokens = findVariableTokens(text, variables);
|
|
80
|
+
let cursor = 0;
|
|
81
|
+
for (const token of tokens) {
|
|
82
|
+
if (token.from > cursor) {
|
|
83
|
+
parts.push({
|
|
84
|
+
key: `text-${cursor}-${token.from}`,
|
|
85
|
+
text: text.slice(cursor, token.from)
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
parts.push({
|
|
89
|
+
key: `token-${token.from}-${token.to}`,
|
|
90
|
+
text: token.token,
|
|
91
|
+
token
|
|
92
|
+
});
|
|
93
|
+
cursor = token.to;
|
|
94
|
+
}
|
|
95
|
+
if (cursor < text.length) {
|
|
96
|
+
parts.push({
|
|
97
|
+
key: `text-${cursor}-${text.length}`,
|
|
98
|
+
text: text.slice(cursor)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return parts;
|
|
102
|
+
}
|
|
103
|
+
function getTokenPresentation(variable, classes) {
|
|
104
|
+
const type = variable ? tokenTypeClass(variable.type) : "unknown";
|
|
105
|
+
const className = [classes.variableToken, classes[`variableToken_${type}`]].filter(Boolean).join(" ");
|
|
106
|
+
const color = validCssColorSSRSafe(variable?.color);
|
|
107
|
+
const bgColor = validCssColorSSRSafe(variable?.backgroundColor);
|
|
108
|
+
return {
|
|
109
|
+
className,
|
|
110
|
+
tokenColor: color,
|
|
111
|
+
tokenBgColor: bgColor
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function createTokenDecorations(state, variables, classes, tokens) {
|
|
115
|
+
const docText = state.doc.toString();
|
|
116
|
+
const docLength = state.doc.length;
|
|
117
|
+
const useTokens = tokens ?? findVariableTokens(docText, variables);
|
|
118
|
+
const ranges = useTokens.filter((match) => {
|
|
119
|
+
return match.from < docLength && match.to > match.from;
|
|
120
|
+
}).map((match) => {
|
|
121
|
+
const safeFrom = Math.max(0, Math.min(match.from, docLength));
|
|
122
|
+
const safeTo = Math.max(safeFrom, Math.min(match.to, docLength));
|
|
123
|
+
const presentation = getTokenPresentation(match.variable, classes);
|
|
124
|
+
const styleParts = [];
|
|
125
|
+
if (presentation.tokenColor)
|
|
126
|
+
styleParts.push(`color:${presentation.tokenColor}`);
|
|
127
|
+
if (presentation.tokenBgColor)
|
|
128
|
+
styleParts.push(`background-color:${presentation.tokenBgColor}`);
|
|
129
|
+
const styleStr = styleParts.join(";");
|
|
130
|
+
const attrs = {
|
|
131
|
+
"data-variable-name": match.name,
|
|
132
|
+
"data-variable-from": String(safeFrom),
|
|
133
|
+
"data-variable-to": String(safeTo),
|
|
134
|
+
"data-variable-defined": match.variable ? "true" : "false"
|
|
135
|
+
};
|
|
136
|
+
if (styleStr) {
|
|
137
|
+
attrs.style = styleStr;
|
|
138
|
+
}
|
|
139
|
+
return view.Decoration.mark({
|
|
140
|
+
class: presentation.className,
|
|
141
|
+
attributes: attrs
|
|
142
|
+
}).range(safeFrom, safeTo);
|
|
143
|
+
});
|
|
144
|
+
return view.Decoration.set(ranges, true);
|
|
145
|
+
}
|
|
146
|
+
function tokenAtPosition(tokens, position) {
|
|
147
|
+
let low = 0;
|
|
148
|
+
let high = tokens.length - 1;
|
|
149
|
+
while (low <= high) {
|
|
150
|
+
const middle = low + high >>> 1;
|
|
151
|
+
const token = tokens[middle];
|
|
152
|
+
if (position < token.from) high = middle - 1;
|
|
153
|
+
else if (position >= token.to) low = middle + 1;
|
|
154
|
+
else return token;
|
|
155
|
+
}
|
|
156
|
+
return void 0;
|
|
157
|
+
}
|
|
158
|
+
function createVariableCompletionSource(variables) {
|
|
159
|
+
const variableMap = createVariableMap(variables);
|
|
160
|
+
const candidates = [...variableMap.values()].map((variable) => ({
|
|
161
|
+
label: variable.name,
|
|
162
|
+
search: variable.name.toLowerCase(),
|
|
163
|
+
type: "variable",
|
|
164
|
+
detail: variable.type ?? "Variable",
|
|
165
|
+
info: variable.description
|
|
166
|
+
}));
|
|
167
|
+
return (context) => {
|
|
168
|
+
const lineBeforeCursor = context.state.sliceDoc(
|
|
169
|
+
context.state.doc.lineAt(context.pos).from,
|
|
170
|
+
context.pos
|
|
171
|
+
);
|
|
172
|
+
const match = lineBeforeCursor.match(VARIABLE_QUERY_PATTERN);
|
|
173
|
+
if (!match) return null;
|
|
174
|
+
const matchedText = match[0];
|
|
175
|
+
const doubleBrace = matchedText.startsWith("{{");
|
|
176
|
+
const openerLength = doubleBrace ? 2 : 1;
|
|
177
|
+
const query = matchedText.slice(openerLength).toLowerCase();
|
|
178
|
+
const from = context.pos - matchedText.length + openerLength;
|
|
179
|
+
const closing = doubleBrace ? "}}" : "}";
|
|
180
|
+
const options = candidates.filter((candidate) => candidate.search.includes(query)).map(({ search: _search, ...candidate }) => ({
|
|
181
|
+
...candidate,
|
|
182
|
+
apply: `${candidate.label}${closing}`
|
|
183
|
+
}));
|
|
184
|
+
const suffix = context.state.sliceDoc(
|
|
185
|
+
context.pos,
|
|
186
|
+
context.pos + closing.length
|
|
187
|
+
);
|
|
188
|
+
let existingClosing = 0;
|
|
189
|
+
while (existingClosing < suffix.length && suffix[existingClosing] === "}")
|
|
190
|
+
existingClosing += 1;
|
|
191
|
+
if (!options.length) return null;
|
|
192
|
+
return {
|
|
193
|
+
from,
|
|
194
|
+
to: context.pos + existingClosing,
|
|
195
|
+
options,
|
|
196
|
+
filter: true,
|
|
197
|
+
validFor: /^[\p{L}\p{N}_$.-]*$/u
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function normalizeMaximumLength(value) {
|
|
202
|
+
if (value === void 0 || !Number.isFinite(value)) return 16384;
|
|
203
|
+
return Math.max(1, Math.min(Math.floor(value), 1e6));
|
|
204
|
+
}
|
|
205
|
+
function sanitizePlainText(text, maxLength = Infinity, allowLineBreaks = false) {
|
|
206
|
+
const limit = Number.isFinite(maxLength) ? Math.max(0, Math.floor(maxLength)) : Infinity;
|
|
207
|
+
const source = limit === Infinity ? text : text.slice(0, limit);
|
|
208
|
+
if (allowLineBreaks) return source;
|
|
209
|
+
return source.replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
210
|
+
}
|
|
211
|
+
function truncateInsertion(insertedText, currentLength, replacedLength, maxLength) {
|
|
212
|
+
const available = Math.max(
|
|
213
|
+
0,
|
|
214
|
+
maxLength - Math.max(0, currentLength - replacedLength)
|
|
215
|
+
);
|
|
216
|
+
return insertedText.slice(0, available);
|
|
217
|
+
}
|
|
218
|
+
function clampSelection(anchor, head, maxDocLength) {
|
|
219
|
+
const max = Math.max(0, maxDocLength);
|
|
220
|
+
const clamp = (position) => Math.max(0, Math.min(position, max));
|
|
221
|
+
return { anchor: clamp(anchor), head: clamp(head) };
|
|
222
|
+
}
|
|
223
|
+
function escapeCssAttrValue(value) {
|
|
224
|
+
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
225
|
+
return CSS.escape(value);
|
|
226
|
+
}
|
|
227
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
228
|
+
}
|
|
229
|
+
function createMinimalChange(oldText, newText) {
|
|
230
|
+
let prefix = 0;
|
|
231
|
+
const commonLength = Math.min(oldText.length, newText.length);
|
|
232
|
+
while (prefix < commonLength && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix)) {
|
|
233
|
+
prefix += 1;
|
|
234
|
+
}
|
|
235
|
+
let suffix = 0;
|
|
236
|
+
while (suffix < oldText.length - prefix && suffix < newText.length - prefix && oldText.charCodeAt(oldText.length - 1 - suffix) === newText.charCodeAt(newText.length - 1 - suffix)) {
|
|
237
|
+
suffix += 1;
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
from: prefix,
|
|
241
|
+
to: oldText.length - suffix,
|
|
242
|
+
insert: newText.slice(prefix, newText.length - suffix)
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
exports.VARIABLE_NAME_PATTERN = VARIABLE_NAME_PATTERN;
|
|
247
|
+
exports.VARIABLE_NAME_PATTERN_STRICT = VARIABLE_NAME_PATTERN_STRICT;
|
|
248
|
+
exports.VARIABLE_QUERY_PATTERN = VARIABLE_QUERY_PATTERN;
|
|
249
|
+
exports.VARIABLE_TOKEN_REGEX = VARIABLE_TOKEN_REGEX;
|
|
250
|
+
exports.clampSelection = clampSelection;
|
|
251
|
+
exports.createMinimalChange = createMinimalChange;
|
|
252
|
+
exports.createTokenDecorations = createTokenDecorations;
|
|
253
|
+
exports.createVariableCompletionSource = createVariableCompletionSource;
|
|
254
|
+
exports.createVariableMap = createVariableMap;
|
|
255
|
+
exports.escapeCssAttrValue = escapeCssAttrValue;
|
|
256
|
+
exports.findVariableTokens = findVariableTokens;
|
|
257
|
+
exports.getTokenPresentation = getTokenPresentation;
|
|
258
|
+
exports.normalizeMaximumLength = normalizeMaximumLength;
|
|
259
|
+
exports.parseVariableNameFromToken = parseVariableNameFromToken;
|
|
260
|
+
exports.sanitizePlainText = sanitizePlainText;
|
|
261
|
+
exports.splitVariableText = splitVariableText;
|
|
262
|
+
exports.tokenAtPosition = tokenAtPosition;
|
|
263
|
+
exports.tokenTypeClass = tokenTypeClass;
|
|
264
|
+
exports.truncateInsertion = truncateInsertion;
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { Decoration } from '@codemirror/view';
|
|
2
|
+
|
|
3
|
+
// src/react/variableTextEditor/libs/variableTextEditor.utils.ts
|
|
4
|
+
function validCssColorSSRSafe(value) {
|
|
5
|
+
const candidate = value?.trim();
|
|
6
|
+
if (!candidate || /[;{}\r\n]/.test(candidate)) return void 0;
|
|
7
|
+
if (typeof CSS === "undefined") return candidate;
|
|
8
|
+
try {
|
|
9
|
+
if (typeof CSS.supports !== "function") return candidate;
|
|
10
|
+
if (!CSS.supports("color", candidate)) return void 0;
|
|
11
|
+
} catch {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
return candidate;
|
|
15
|
+
}
|
|
16
|
+
var VARIABLE_NAME_PATTERN = /^[\p{L}\p{N}_$.-]+$/u;
|
|
17
|
+
var VARIABLE_NAME_PATTERN_STRICT = /^[\p{L}\p{N}_$.-]+$/u;
|
|
18
|
+
var VARIABLE_TOKEN_REGEX = /\{\{([\p{L}\p{N}_$.-]+)\}\}|\{([\p{L}\p{N}_$.-]+)\}/gu;
|
|
19
|
+
var VARIABLE_QUERY_PATTERN = /(?:\{\{|\{)[\p{L}\p{N}_$.-]*$/u;
|
|
20
|
+
function tokenTypeClass(type) {
|
|
21
|
+
switch (type?.trim().toLowerCase()) {
|
|
22
|
+
case "secret":
|
|
23
|
+
case "environment":
|
|
24
|
+
case "request":
|
|
25
|
+
case "dynamic":
|
|
26
|
+
return type.trim().toLowerCase();
|
|
27
|
+
default:
|
|
28
|
+
return "unknown";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function parseVariableNameFromToken(token) {
|
|
32
|
+
if (token.startsWith("{{") && token.endsWith("}}")) {
|
|
33
|
+
const inner = token.slice(2, -2);
|
|
34
|
+
return VARIABLE_NAME_PATTERN_STRICT.test(inner) ? inner : null;
|
|
35
|
+
}
|
|
36
|
+
if (token.startsWith("{") && token.endsWith("}")) {
|
|
37
|
+
const inner = token.slice(1, -1);
|
|
38
|
+
return VARIABLE_NAME_PATTERN_STRICT.test(inner) ? inner : null;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
function createVariableMap(variables) {
|
|
43
|
+
const result = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const variable of variables) {
|
|
45
|
+
const name = variable.name?.trim();
|
|
46
|
+
if (name && VARIABLE_NAME_PATTERN.test(name)) {
|
|
47
|
+
result.set(
|
|
48
|
+
name,
|
|
49
|
+
name === variable.name ? variable : { ...variable, name }
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function findVariableTokens(text, variables) {
|
|
56
|
+
const variableMap = createVariableMap(variables);
|
|
57
|
+
const matches = [];
|
|
58
|
+
for (const match of text.matchAll(VARIABLE_TOKEN_REGEX)) {
|
|
59
|
+
const full = match[0];
|
|
60
|
+
const index = match.index;
|
|
61
|
+
if (index == null) continue;
|
|
62
|
+
const name = match[1] ?? match[2];
|
|
63
|
+
if (!name) continue;
|
|
64
|
+
if (!VARIABLE_NAME_PATTERN.test(name)) continue;
|
|
65
|
+
matches.push({
|
|
66
|
+
token: full,
|
|
67
|
+
name,
|
|
68
|
+
from: index,
|
|
69
|
+
to: index + full.length,
|
|
70
|
+
variable: variableMap.get(name)
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return matches;
|
|
74
|
+
}
|
|
75
|
+
function splitVariableText(text, variables) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
const tokens = findVariableTokens(text, variables);
|
|
78
|
+
let cursor = 0;
|
|
79
|
+
for (const token of tokens) {
|
|
80
|
+
if (token.from > cursor) {
|
|
81
|
+
parts.push({
|
|
82
|
+
key: `text-${cursor}-${token.from}`,
|
|
83
|
+
text: text.slice(cursor, token.from)
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
parts.push({
|
|
87
|
+
key: `token-${token.from}-${token.to}`,
|
|
88
|
+
text: token.token,
|
|
89
|
+
token
|
|
90
|
+
});
|
|
91
|
+
cursor = token.to;
|
|
92
|
+
}
|
|
93
|
+
if (cursor < text.length) {
|
|
94
|
+
parts.push({
|
|
95
|
+
key: `text-${cursor}-${text.length}`,
|
|
96
|
+
text: text.slice(cursor)
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return parts;
|
|
100
|
+
}
|
|
101
|
+
function getTokenPresentation(variable, classes) {
|
|
102
|
+
const type = variable ? tokenTypeClass(variable.type) : "unknown";
|
|
103
|
+
const className = [classes.variableToken, classes[`variableToken_${type}`]].filter(Boolean).join(" ");
|
|
104
|
+
const color = validCssColorSSRSafe(variable?.color);
|
|
105
|
+
const bgColor = validCssColorSSRSafe(variable?.backgroundColor);
|
|
106
|
+
return {
|
|
107
|
+
className,
|
|
108
|
+
tokenColor: color,
|
|
109
|
+
tokenBgColor: bgColor
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function createTokenDecorations(state, variables, classes, tokens) {
|
|
113
|
+
const docText = state.doc.toString();
|
|
114
|
+
const docLength = state.doc.length;
|
|
115
|
+
const useTokens = tokens ?? findVariableTokens(docText, variables);
|
|
116
|
+
const ranges = useTokens.filter((match) => {
|
|
117
|
+
return match.from < docLength && match.to > match.from;
|
|
118
|
+
}).map((match) => {
|
|
119
|
+
const safeFrom = Math.max(0, Math.min(match.from, docLength));
|
|
120
|
+
const safeTo = Math.max(safeFrom, Math.min(match.to, docLength));
|
|
121
|
+
const presentation = getTokenPresentation(match.variable, classes);
|
|
122
|
+
const styleParts = [];
|
|
123
|
+
if (presentation.tokenColor)
|
|
124
|
+
styleParts.push(`color:${presentation.tokenColor}`);
|
|
125
|
+
if (presentation.tokenBgColor)
|
|
126
|
+
styleParts.push(`background-color:${presentation.tokenBgColor}`);
|
|
127
|
+
const styleStr = styleParts.join(";");
|
|
128
|
+
const attrs = {
|
|
129
|
+
"data-variable-name": match.name,
|
|
130
|
+
"data-variable-from": String(safeFrom),
|
|
131
|
+
"data-variable-to": String(safeTo),
|
|
132
|
+
"data-variable-defined": match.variable ? "true" : "false"
|
|
133
|
+
};
|
|
134
|
+
if (styleStr) {
|
|
135
|
+
attrs.style = styleStr;
|
|
136
|
+
}
|
|
137
|
+
return Decoration.mark({
|
|
138
|
+
class: presentation.className,
|
|
139
|
+
attributes: attrs
|
|
140
|
+
}).range(safeFrom, safeTo);
|
|
141
|
+
});
|
|
142
|
+
return Decoration.set(ranges, true);
|
|
143
|
+
}
|
|
144
|
+
function tokenAtPosition(tokens, position) {
|
|
145
|
+
let low = 0;
|
|
146
|
+
let high = tokens.length - 1;
|
|
147
|
+
while (low <= high) {
|
|
148
|
+
const middle = low + high >>> 1;
|
|
149
|
+
const token = tokens[middle];
|
|
150
|
+
if (position < token.from) high = middle - 1;
|
|
151
|
+
else if (position >= token.to) low = middle + 1;
|
|
152
|
+
else return token;
|
|
153
|
+
}
|
|
154
|
+
return void 0;
|
|
155
|
+
}
|
|
156
|
+
function createVariableCompletionSource(variables) {
|
|
157
|
+
const variableMap = createVariableMap(variables);
|
|
158
|
+
const candidates = [...variableMap.values()].map((variable) => ({
|
|
159
|
+
label: variable.name,
|
|
160
|
+
search: variable.name.toLowerCase(),
|
|
161
|
+
type: "variable",
|
|
162
|
+
detail: variable.type ?? "Variable",
|
|
163
|
+
info: variable.description
|
|
164
|
+
}));
|
|
165
|
+
return (context) => {
|
|
166
|
+
const lineBeforeCursor = context.state.sliceDoc(
|
|
167
|
+
context.state.doc.lineAt(context.pos).from,
|
|
168
|
+
context.pos
|
|
169
|
+
);
|
|
170
|
+
const match = lineBeforeCursor.match(VARIABLE_QUERY_PATTERN);
|
|
171
|
+
if (!match) return null;
|
|
172
|
+
const matchedText = match[0];
|
|
173
|
+
const doubleBrace = matchedText.startsWith("{{");
|
|
174
|
+
const openerLength = doubleBrace ? 2 : 1;
|
|
175
|
+
const query = matchedText.slice(openerLength).toLowerCase();
|
|
176
|
+
const from = context.pos - matchedText.length + openerLength;
|
|
177
|
+
const closing = doubleBrace ? "}}" : "}";
|
|
178
|
+
const options = candidates.filter((candidate) => candidate.search.includes(query)).map(({ search: _search, ...candidate }) => ({
|
|
179
|
+
...candidate,
|
|
180
|
+
apply: `${candidate.label}${closing}`
|
|
181
|
+
}));
|
|
182
|
+
const suffix = context.state.sliceDoc(
|
|
183
|
+
context.pos,
|
|
184
|
+
context.pos + closing.length
|
|
185
|
+
);
|
|
186
|
+
let existingClosing = 0;
|
|
187
|
+
while (existingClosing < suffix.length && suffix[existingClosing] === "}")
|
|
188
|
+
existingClosing += 1;
|
|
189
|
+
if (!options.length) return null;
|
|
190
|
+
return {
|
|
191
|
+
from,
|
|
192
|
+
to: context.pos + existingClosing,
|
|
193
|
+
options,
|
|
194
|
+
filter: true,
|
|
195
|
+
validFor: /^[\p{L}\p{N}_$.-]*$/u
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function normalizeMaximumLength(value) {
|
|
200
|
+
if (value === void 0 || !Number.isFinite(value)) return 16384;
|
|
201
|
+
return Math.max(1, Math.min(Math.floor(value), 1e6));
|
|
202
|
+
}
|
|
203
|
+
function sanitizePlainText(text, maxLength = Infinity, allowLineBreaks = false) {
|
|
204
|
+
const limit = Number.isFinite(maxLength) ? Math.max(0, Math.floor(maxLength)) : Infinity;
|
|
205
|
+
const source = limit === Infinity ? text : text.slice(0, limit);
|
|
206
|
+
if (allowLineBreaks) return source;
|
|
207
|
+
return source.replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
208
|
+
}
|
|
209
|
+
function truncateInsertion(insertedText, currentLength, replacedLength, maxLength) {
|
|
210
|
+
const available = Math.max(
|
|
211
|
+
0,
|
|
212
|
+
maxLength - Math.max(0, currentLength - replacedLength)
|
|
213
|
+
);
|
|
214
|
+
return insertedText.slice(0, available);
|
|
215
|
+
}
|
|
216
|
+
function clampSelection(anchor, head, maxDocLength) {
|
|
217
|
+
const max = Math.max(0, maxDocLength);
|
|
218
|
+
const clamp = (position) => Math.max(0, Math.min(position, max));
|
|
219
|
+
return { anchor: clamp(anchor), head: clamp(head) };
|
|
220
|
+
}
|
|
221
|
+
function escapeCssAttrValue(value) {
|
|
222
|
+
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
223
|
+
return CSS.escape(value);
|
|
224
|
+
}
|
|
225
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
226
|
+
}
|
|
227
|
+
function createMinimalChange(oldText, newText) {
|
|
228
|
+
let prefix = 0;
|
|
229
|
+
const commonLength = Math.min(oldText.length, newText.length);
|
|
230
|
+
while (prefix < commonLength && oldText.charCodeAt(prefix) === newText.charCodeAt(prefix)) {
|
|
231
|
+
prefix += 1;
|
|
232
|
+
}
|
|
233
|
+
let suffix = 0;
|
|
234
|
+
while (suffix < oldText.length - prefix && suffix < newText.length - prefix && oldText.charCodeAt(oldText.length - 1 - suffix) === newText.charCodeAt(newText.length - 1 - suffix)) {
|
|
235
|
+
suffix += 1;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
from: prefix,
|
|
239
|
+
to: oldText.length - suffix,
|
|
240
|
+
insert: newText.slice(prefix, newText.length - suffix)
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export { VARIABLE_NAME_PATTERN, VARIABLE_NAME_PATTERN_STRICT, VARIABLE_QUERY_PATTERN, VARIABLE_TOKEN_REGEX, clampSelection, createMinimalChange, createTokenDecorations, createVariableCompletionSource, createVariableMap, escapeCssAttrValue, findVariableTokens, getTokenPresentation, normalizeMaximumLength, parseVariableNameFromToken, sanitizePlainText, splitVariableText, tokenAtPosition, tokenTypeClass, truncateInsertion };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|