@symbo.ls/mermaid 3.14.1 → 3.14.5

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/src/template.html DELETED
@@ -1,22 +0,0 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- '${{{ META }}}'
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <meta charset="UTF-8" />
7
- '${{{ IMPORTMAP }}}'
8
- </head>
9
- <body>
10
- <div data-ssr>'${{{ BODY }}}'</div>
11
- <script>
12
- window.process = { env: { NODE_ENV: '${{{ NODE_ENV }}}' } };
13
- </script>
14
- <script>
15
- '${{{ SMBLS_IIFE }}}';
16
- </script>
17
- <script>
18
- '${{{ BUNDLE }}}';
19
- </script>
20
- '${{{ EDITOR }}}'
21
- </body>
22
- </html>
@@ -1,149 +0,0 @@
1
- 'use strict';
2
-
3
- // Inspired by @symbo.ls/utils deepDestringifyFunctions but implemented locally to remove the
4
- // dependency on the external package. The implementation is pure-JS and node
5
- // friendly (it works whether `window` is available or not).
6
- //
7
- // The function walks an object tree and converts any string that represents a
8
- // JavaScript function back into an executable function by using `eval`.
9
- //
10
- // const obj = { fn: "(x) => x * 2" }
11
- // deepDestringifyFunctions(obj) // => { fn: [Function] }
12
- //
13
- // It keeps the structure (arrays / nested objects) intact and leaves all other
14
- // primitives untouched.
15
- //
16
- // NOTE: Executing code coming from a string is potentially dangerous. Make sure
17
- // the input is trusted or sandboxed appropriately before calling this helper.
18
-
19
- /**
20
- * Tests if the provided string represents a JavaScript function.
21
- * We intentionally keep the (rather heavy) RegExp logic from the original
22
- * implementation because it has been field-tested and produces reliable
23
- * results for arrow functions, classic functions and async functions.
24
- *
25
- * @param {string} str
26
- * @returns {boolean}
27
- */
28
- function hasFunction(str) {
29
- if (!str) return false;
30
-
31
- const trimmed = str.trim().replace(/\n\s*/g, ' ').trim();
32
- if (trimmed === '' || trimmed === '{}' || trimmed === '[]') return false;
33
-
34
- const patterns = [
35
- /^\(\s*\{[^}]*\}\s*\)\s*=>/, // ({ ... }) =>
36
- /^(\([^)]*\)|[^=]*)\s*=>/, // () => or x =>
37
- /^function[\s(]/, // function () {}
38
- /^async\s+/, // async () => {}
39
- /^\(\s*function/, // (function () { })
40
- /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*=>/, // named =>
41
- ];
42
-
43
- const isFunctionLike = patterns.some((p) => p.test(trimmed));
44
- const isObjectLiteral = trimmed.startsWith('{') && !trimmed.includes('=>');
45
- const isArrayLiteral = trimmed.startsWith('[');
46
- const isJSONLike = /^["[{]/.test(trimmed) && !trimmed.includes('=>');
47
-
48
- return isFunctionLike && !isObjectLiteral && !isArrayLiteral && !isJSONLike;
49
- }
50
-
51
- const isString = (val) => typeof val === 'string';
52
- const isArray = Array.isArray;
53
- const isObject = (val) => val !== null && typeof val === 'object' && !isArray(val);
54
-
55
- /**
56
- * Recursively converts stringified functions inside an object (or array) back
57
- * to real functions.
58
- *
59
- * @template T
60
- * @param {T} obj - The source object (or array).
61
- * @param {any} [target={}] - Used internally for recursion, pass nothing.
62
- * @returns {T} A new object with functions revived.
63
- */
64
- export function deepDestringifyFunctions(obj, target = Array.isArray(obj) ? [] : {}) {
65
- for (const prop in obj) {
66
- if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue;
67
-
68
- const value = obj[prop];
69
-
70
- // 1. String ==> maybe turn into function
71
- if (isString(value)) {
72
- if (hasFunction(value)) {
73
- try {
74
- const fn = (0, Function)('return (' + value + ')')();
75
- target[prop] = fn;
76
- } catch (_) {
77
- // If evaluation fails, preserve the original string.
78
- target[prop] = value;
79
- }
80
- } else {
81
- target[prop] = value;
82
- }
83
- continue;
84
- }
85
-
86
- // 2. Array ==> recurse per entry
87
- if (isArray(value)) {
88
- target[prop] = [];
89
- value.forEach((item) => {
90
- if (isString(item)) {
91
- if (hasFunction(item)) {
92
- try {
93
- const fn = (0, Function)('return (' + item + ')')();
94
- target[prop].push(fn);
95
- } catch (_) {
96
- target[prop].push(item);
97
- }
98
- } else {
99
- target[prop].push(item);
100
- }
101
- } else if (isObject(item) || isArray(item)) {
102
- target[prop].push(deepDestringifyFunctions(item));
103
- } else {
104
- target[prop].push(item);
105
- }
106
- });
107
- continue;
108
- }
109
-
110
- // 3. Nested object ==> recurse
111
- if (isObject(value)) {
112
- target[prop] = deepDestringifyFunctions(value);
113
- continue;
114
- }
115
-
116
- // 4. Primitive (number, boolean, function, null, undefined)
117
- target[prop] = value;
118
- }
119
-
120
- return target;
121
- }
122
-
123
- /**
124
- * Strips function-like strings from an object tree, replacing them with null.
125
- * Use in environments where eval/Function are blocked (e.g. Cloudflare Workers)
126
- * so that brender renders empty placeholders instead of raw function source code.
127
- */
128
- export function stripFunctionStrings(obj, target = Array.isArray(obj) ? [] : {}) {
129
- for (const prop in obj) {
130
- if (!Object.prototype.hasOwnProperty.call(obj, prop)) continue;
131
- const value = obj[prop];
132
- if (isString(value)) {
133
- target[prop] = hasFunction(value) ? null : value;
134
- } else if (isArray(value)) {
135
- target[prop] = value.map((item) => {
136
- if (isString(item) && hasFunction(item)) return null;
137
- if (isObject(item) || isArray(item)) return stripFunctionStrings(item);
138
- return item;
139
- });
140
- } else if (isObject(value)) {
141
- target[prop] = stripFunctionStrings(value);
142
- } else {
143
- target[prop] = value;
144
- }
145
- }
146
- return target;
147
- }
148
-
149
- export default deepDestringifyFunctions;
@@ -1,346 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Transpile a stringified JavaScript function into a funcql schema.
5
- *
6
- * Handles common DOMQL patterns:
7
- * - Property access: (el, s) => s.visible
8
- * - Ternary: (el, s) => s.active ? 'yes' : 'no'
9
- * - Negation: (el, s) => !s.hidden
10
- * - Comparison: (el, s) => s.count > 0
11
- * - el.call(): (el, s) => el.call("polyglot", s.key)
12
- * - Logical AND/OR: (el, s) => s.a && s.b
13
- * - Void comparison: (el, s) => s.x !== void 0
14
- * - Concatenation: (el, s) => s.count + " items"
15
- *
16
- * For unsupported patterns, returns null (caller should keep the original string).
17
- *
18
- * @param {string} source - stringified JS function
19
- * @returns {{ schema: *, args: string[] } | null}
20
- */
21
- export const transpile = (source) => {
22
- if (typeof source !== 'string') return null;
23
-
24
- const trimmed = source.trim();
25
-
26
- // Parse arrow function: (args) => body
27
- const arrowMatch = trimmed.match(/^\(?([^)]*?)\)?\s*=>\s*([\s\S]+)$/);
28
- if (!arrowMatch) return null;
29
-
30
- const rawArgs = arrowMatch[1];
31
- const body = arrowMatch[2].trim();
32
-
33
- // Extract argument names
34
- const args = rawArgs
35
- .split(',')
36
- .map((a) => a.trim())
37
- .filter(Boolean);
38
-
39
- // Skip multi-line / block bodies
40
- if (body.startsWith('{')) return null;
41
-
42
- // Map standard DOMQL arg names to funcql context paths
43
- // (el, s) → el = element, s = state
44
- // (el, s, ctx) → ctx = context
45
- const argMap = buildArgMap(args);
46
-
47
- // Try to transpile the expression body
48
- const schema = transpileExpr(body, argMap);
49
- if (schema === null) return null;
50
-
51
- return { schema, args };
52
- };
53
-
54
- /**
55
- * Build a mapping from arg names to funcql context paths.
56
- * Standard DOMQL patterns: (el, s, ctx) or (element, state, context)
57
- */
58
- const buildArgMap = (args) => {
59
- const map = {};
60
- if (args[0]) map[args[0]] = 'el'; // element
61
- if (args[1]) map[args[1]] = 'state'; // state
62
- if (args[2]) map[args[2]] = 'context'; // context
63
- return map;
64
- };
65
-
66
- /**
67
- * Transpile a single JS expression to a funcql schema node.
68
- */
69
- const transpileExpr = (expr, argMap) => {
70
- const e = expr.trim();
71
- if (!e) return null;
72
-
73
- // Ternary: condition ? thenExpr : elseExpr
74
- const ternary = splitTernary(e);
75
- if (ternary) {
76
- const cond = transpileExpr(ternary.condition, argMap);
77
- const then_ = transpileExpr(ternary.consequent, argMap);
78
- const else_ = transpileExpr(ternary.alternate, argMap);
79
- if (cond !== null && then_ !== null && else_ !== null) {
80
- return { if: [cond, then_, else_] };
81
- }
82
- return null;
83
- }
84
-
85
- // el.call("polyglot", ...) → ['call', 'polyglot', ...args]
86
- const callMatch = e.match(/^(\w+)\.call\((.+)\)$/);
87
- if (callMatch) {
88
- const callArgs = splitCallArgs(callMatch[2]);
89
- if (callArgs) {
90
- const resolvedArgs = callArgs.map((a) => transpileExpr(a.trim(), argMap));
91
- if (resolvedArgs.every((a) => a !== null)) {
92
- return ['call', ...resolvedArgs];
93
- }
94
- }
95
- return null;
96
- }
97
-
98
- // Logical OR: a || b (lowest precedence, split first)
99
- {
100
- const parts = splitOnOperator(e, '||');
101
- if (parts) {
102
- const left = transpileExpr(parts.left, argMap);
103
- const right = transpileExpr(parts.right, argMap);
104
- if (left !== null && right !== null) {
105
- return ['||', left, right];
106
- }
107
- return null;
108
- }
109
- }
110
-
111
- // Logical AND: a && b
112
- {
113
- const parts = splitOnOperator(e, '&&');
114
- if (parts) {
115
- const left = transpileExpr(parts.left, argMap);
116
- const right = transpileExpr(parts.right, argMap);
117
- if (left !== null && right !== null) {
118
- return ['&&', left, right];
119
- }
120
- return null;
121
- }
122
- }
123
-
124
- // Comparison operators: ===, !==, >, <, >=, <=
125
- for (const op of ['!==', '===', '>=', '<=', '>', '<']) {
126
- const parts = splitOnOperator(e, op);
127
- if (parts) {
128
- const left = transpileExpr(parts.left, argMap);
129
- const right = transpileExpr(parts.right, argMap);
130
- if (left !== null && right !== null) {
131
- return [op, left, right];
132
- }
133
- return null;
134
- }
135
- }
136
-
137
- // Negation: !expr
138
- if (e.startsWith('!')) {
139
- const inner = transpileExpr(e.slice(1).trim(), argMap);
140
- if (inner !== null && typeof inner === 'string') {
141
- return '!' + inner;
142
- }
143
- return null;
144
- }
145
-
146
- // String concatenation with + (left-associative, collect all parts)
147
- if (e.includes('+') && !e.startsWith('"') && !e.startsWith("'")) {
148
- const allParts = splitAllOnOperator(e, '+');
149
- if (allParts && allParts.length >= 2) {
150
- const transpiled = allParts.map((p) => transpileExpr(p.trim(), argMap));
151
- if (transpiled.every((t) => t !== null)) {
152
- // Build left-associative tree: ['+', ['+', a, b], c]
153
- let result = transpiled[0];
154
- for (let i = 1; i < transpiled.length; i++) {
155
- result = ['+', result, transpiled[i]];
156
- }
157
- return result;
158
- }
159
- }
160
- }
161
-
162
- // String literal: "..." or '...' → prefix with = so funcql treats as literal
163
- if ((e.startsWith('"') && e.endsWith('"')) || (e.startsWith("'") && e.endsWith("'"))) {
164
- return '=' + e.slice(1, -1);
165
- }
166
-
167
- // void 0 / undefined — use special sentinel that funcql evaluate can handle
168
- if (e === 'void 0' || e === 'undefined') return '__undefined__';
169
-
170
- // Numeric literal
171
- if (/^-?\d+(\.\d+)?$/.test(e)) return Number(e);
172
-
173
- // Boolean
174
- if (e === 'true') return true;
175
- if (e === 'false') return false;
176
- if (e === 'null') return null;
177
-
178
- // Empty string
179
- if (e === '""' || e === "''") return '';
180
-
181
- // Property access path: s.x.y.z → remap arg names
182
- if (/^[\w$.[\]]+$/.test(e) && !e.includes('(')) {
183
- return remapPath(e, argMap);
184
- }
185
-
186
- // Bracket access: s["key"] or s[variable]
187
- // Skip for now — too complex
188
-
189
- return null;
190
- };
191
-
192
- /**
193
- * Remap argument names in a dot-path to funcql context paths.
194
- * e.g. s.root.lang → state.root.lang (when argMap says s→state)
195
- */
196
- const remapPath = (path, argMap) => {
197
- const parts = path.split('.');
198
- const first = parts[0];
199
- if (argMap[first]) {
200
- parts[0] = argMap[first];
201
- return parts.join('.');
202
- }
203
- return path;
204
- };
205
-
206
- /**
207
- * Split a ternary expression respecting nesting.
208
- * Returns { condition, consequent, alternate } or null.
209
- */
210
- const splitTernary = (expr) => {
211
- let depth = 0;
212
- let qIdx = -1;
213
- let cIdx = -1;
214
-
215
- for (let i = 0; i < expr.length; i++) {
216
- const ch = expr[i];
217
- if (ch === '(' || ch === '[' || ch === '{') depth++;
218
- else if (ch === ')' || ch === ']' || ch === '}') depth--;
219
- else if (ch === '?' && depth === 0 && qIdx === -1) qIdx = i;
220
- else if (ch === ':' && depth === 0 && qIdx !== -1) {
221
- cIdx = i;
222
- break;
223
- }
224
- // Skip strings
225
- if (ch === '"' || ch === "'") {
226
- const quote = ch;
227
- i++;
228
- while (i < expr.length && expr[i] !== quote) {
229
- if (expr[i] === '\\') i++;
230
- i++;
231
- }
232
- }
233
- }
234
-
235
- if (qIdx === -1 || cIdx === -1) return null;
236
-
237
- return {
238
- condition: expr.slice(0, qIdx).trim(),
239
- consequent: expr.slice(qIdx + 1, cIdx).trim(),
240
- alternate: expr.slice(cIdx + 1).trim(),
241
- };
242
- };
243
-
244
- /**
245
- * Split expression on a binary operator (respecting nesting).
246
- * Returns { left, right } or null.
247
- */
248
- const splitOnOperator = (expr, op) => {
249
- let depth = 0;
250
- const opLen = op.length;
251
-
252
- for (let i = 0; i < expr.length - opLen + 1; i++) {
253
- const ch = expr[i];
254
- if (ch === '(' || ch === '[' || ch === '{') depth++;
255
- else if (ch === ')' || ch === ']' || ch === '}') depth--;
256
- // Skip strings
257
- if (ch === '"' || ch === "'") {
258
- const quote = ch;
259
- i++;
260
- while (i < expr.length && expr[i] !== quote) {
261
- if (expr[i] === '\\') i++;
262
- i++;
263
- }
264
- continue;
265
- }
266
- if (depth === 0 && expr.slice(i, i + opLen) === op) {
267
- // Make sure we're not inside a longer operator
268
- const before = i > 0 ? expr[i - 1] : '';
269
- const after = i + opLen < expr.length ? expr[i + opLen] : '';
270
- // Skip if this is part of ===, !==, etc.
271
- if (op === '=' && (before === '!' || before === '=' || after === '=')) continue;
272
- if (op === '>' && before === '=') continue;
273
- if (op === '<' && after === '=') continue;
274
-
275
- return {
276
- left: expr.slice(0, i).trim(),
277
- right: expr.slice(i + opLen).trim(),
278
- };
279
- }
280
- }
281
- return null;
282
- };
283
-
284
- /**
285
- * Split expression on ALL occurrences of a binary operator (respecting nesting).
286
- * Returns array of parts or null.
287
- */
288
- const splitAllOnOperator = (expr, op) => {
289
- const parts = [];
290
- let depth = 0;
291
- let start = 0;
292
- const opLen = op.length;
293
-
294
- for (let i = 0; i < expr.length; i++) {
295
- const ch = expr[i];
296
- if (ch === '(' || ch === '[' || ch === '{') depth++;
297
- else if (ch === ')' || ch === ']' || ch === '}') depth--;
298
- if (ch === '"' || ch === "'") {
299
- const quote = ch;
300
- i++;
301
- while (i < expr.length && expr[i] !== quote) {
302
- if (expr[i] === '\\') i++;
303
- i++;
304
- }
305
- continue;
306
- }
307
- if (depth === 0 && expr.slice(i, i + opLen) === op) {
308
- parts.push(expr.slice(start, i));
309
- start = i + opLen;
310
- }
311
- }
312
- parts.push(expr.slice(start));
313
-
314
- if (parts.length < 2) return null;
315
- return parts;
316
- };
317
-
318
- /**
319
- * Split function call arguments respecting nesting.
320
- */
321
- const splitCallArgs = (str) => {
322
- const args = [];
323
- let depth = 0;
324
- let start = 0;
325
-
326
- for (let i = 0; i < str.length; i++) {
327
- const ch = str[i];
328
- if (ch === '(' || ch === '[' || ch === '{') depth++;
329
- else if (ch === ')' || ch === ']' || ch === '}') depth--;
330
- else if (ch === ',' && depth === 0) {
331
- args.push(str.slice(start, i));
332
- start = i + 1;
333
- }
334
- // Skip strings
335
- if (ch === '"' || ch === "'") {
336
- const quote = ch;
337
- i++;
338
- while (i < str.length && str[i] !== quote) {
339
- if (str[i] === '\\') i++;
340
- i++;
341
- }
342
- }
343
- }
344
- args.push(str.slice(start));
345
- return args.filter((a) => a.trim());
346
- };
@@ -1,131 +0,0 @@
1
- // Lightweight logger replacement (no external deps)
2
- // Provides log.trace/debug/info/warn/error/fatal
3
-
4
- const LEVELS = {
5
- trace: 10,
6
- debug: 20,
7
- info: 30,
8
- warn: 40,
9
- error: 50,
10
- fatal: 60,
11
- };
12
-
13
- let currentLevelName = process.env.LOG_LEVEL || 'info';
14
- if (!Object.prototype.hasOwnProperty.call(LEVELS, currentLevelName)) currentLevelName = 'info';
15
- let currentLevel = LEVELS[currentLevelName];
16
-
17
- let isLocal = process.env.NODE_ENV === 'local' || process.env.NODE_ENV === 'development';
18
-
19
- const COLORS = {
20
- trace: '\x1b[34m',
21
- debug: '\x1b[36m',
22
- info: '\x1b[32m',
23
- warn: '\x1b[33m',
24
- error: '\x1b[31m',
25
- fatal: '\x1b[35m',
26
- reset: '\x1b[0m',
27
- };
28
-
29
- function pad(num, size = 2) {
30
- let s = String(num);
31
- while (s.length < size) s = '0' + s;
32
- return s;
33
- }
34
-
35
- function utcTimestamp() {
36
- const d = new Date();
37
- const yyyy = d.getUTCFullYear();
38
- const mm = pad(d.getUTCMonth() + 1);
39
- const dd = pad(d.getUTCDate());
40
- const hh = pad(d.getUTCHours());
41
- const min = pad(d.getUTCMinutes());
42
- const ss = pad(d.getUTCSeconds());
43
- const ms = pad(d.getUTCMilliseconds(), 3);
44
- return `${yyyy}-${mm}-${dd} ${hh}:${min}:${ss}.${ms} +0000`;
45
- }
46
-
47
- function shouldLog(levelName) {
48
- return LEVELS[levelName] >= currentLevel;
49
- }
50
-
51
- function stringifyMeta(metaObjects) {
52
- if (!metaObjects.length) return '';
53
- try {
54
- return JSON.stringify(Object.assign({}, ...metaObjects));
55
- } catch {
56
- return '';
57
- }
58
- }
59
-
60
- function makeLoggerFn(levelName) {
61
- const color = COLORS[levelName];
62
- const useStderr = levelName === 'error' || levelName === 'fatal';
63
- const stream = useStderr ? console.error : console.log;
64
-
65
- return (...args) => {
66
- if (!shouldLog(levelName)) return;
67
-
68
- if (!args.length) {
69
- stream('');
70
- return;
71
- }
72
-
73
- let msg = '';
74
- let metaObjects = [];
75
-
76
- if (typeof args[0] === 'string') {
77
- msg = args[0];
78
- metaObjects = args.slice(1).filter((a) => typeof a === 'object' && a !== null);
79
-
80
- if (levelName === 'error' && args[1] instanceof Error) {
81
- metaObjects.push({
82
- err: {
83
- message: args[1].message,
84
- stack: args[1].stack,
85
- },
86
- });
87
- }
88
- } else {
89
- metaObjects = args.filter((a) => typeof a === 'object' && a !== null);
90
- }
91
-
92
- const metaStr = stringifyMeta(metaObjects);
93
- const timeStr = utcTimestamp();
94
- const lvl = levelName.toUpperCase();
95
-
96
- let output = `[${timeStr}] ${lvl}: ${msg}`;
97
- if (metaStr) output += ` ${metaStr}`;
98
-
99
- if (isLocal && color) {
100
- output = `${color}${output}${COLORS.reset}`;
101
- }
102
-
103
- stream(output);
104
- };
105
- }
106
-
107
- const log = {};
108
- for (const lvl of Object.keys(LEVELS)) {
109
- log[lvl] = makeLoggerFn(lvl);
110
- }
111
-
112
- Object.defineProperty(log, 'level', {
113
- get: () => currentLevelName,
114
- set: (lvl) => {
115
- if (Object.prototype.hasOwnProperty.call(LEVELS, lvl)) {
116
- currentLevelName = lvl;
117
- currentLevel = LEVELS[lvl];
118
- }
119
- },
120
- });
121
-
122
- export const updateLoggerConfig = (config) => {
123
- if (config?.logging?.level) {
124
- log.level = config.logging.level;
125
- }
126
- if (config?.env) {
127
- isLocal = config.env === 'local' || config.env === 'development';
128
- }
129
- };
130
-
131
- export default log;
@@ -1,30 +0,0 @@
1
- 'use strict';
2
- import log from './logger.js';
3
-
4
- export default function replaceVariablesInFileSync(filedata, replacementObject, opts = {}) {
5
- try {
6
- const regex = /(['"])\${{{\s*([^}\s]+)\s*}}}\1/g;
7
- if (!filedata) {
8
- const error = new Error('File data is empty');
9
- log.error('[REQ_FLOW] File data is empty in replaceVariablesInFileSync');
10
- throw error;
11
- }
12
-
13
- const replacedData = filedata.replace(regex, (match, quoteChar, variableName) => {
14
- if (Object.hasOwn(replacementObject, variableName)) {
15
- const value = replacementObject[variableName];
16
- return opts.allowScript ? value : value.replace(/<\/?script>/g, '&lt;/?script&gt;');
17
- } else {
18
- log.warn(
19
- `[REQ_FLOW] Missing replacement value for ${JSON.stringify({ name: variableName })}`,
20
- );
21
- return match;
22
- }
23
- });
24
-
25
- return replacedData;
26
- } catch (err) {
27
- log.error(`[REQ_FLOW] Error in replaceVariablesInFileSync: ${err}`);
28
- return null;
29
- }
30
- }