@peter.naydenov/morph 3.1.4 → 3.2.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.
Files changed (61) hide show
  1. package/.mocharc.json +1 -0
  2. package/.opencode/command/speckit.analyze.md +184 -0
  3. package/.opencode/command/speckit.checklist.md +294 -0
  4. package/.opencode/command/speckit.clarify.md +181 -0
  5. package/.opencode/command/speckit.constitution.md +82 -0
  6. package/.opencode/command/speckit.implement.md +135 -0
  7. package/.opencode/command/speckit.plan.md +89 -0
  8. package/.opencode/command/speckit.specify.md +257 -0
  9. package/.opencode/command/speckit.tasks.md +137 -0
  10. package/.opencode/command/speckit.taskstoissues.md +28 -0
  11. package/.specify/memory/constitution.md +43 -0
  12. package/.specify/scripts/bash/check-prerequisites.sh +166 -0
  13. package/.specify/scripts/bash/common.sh +156 -0
  14. package/.specify/scripts/bash/create-new-feature.sh +305 -0
  15. package/.specify/scripts/bash/setup-plan.sh +61 -0
  16. package/.specify/scripts/bash/update-agent-context.sh +790 -0
  17. package/.specify/templates/agent-file-template.md +28 -0
  18. package/.specify/templates/checklist-template.md +40 -0
  19. package/.specify/templates/plan-template.md +104 -0
  20. package/.specify/templates/spec-template.md +115 -0
  21. package/.specify/templates/tasks-template.md +251 -0
  22. package/Changelog.md +17 -0
  23. package/README.md +154 -3
  24. package/dist/main.d.ts +100 -0
  25. package/dist/methods/_actionSupply.d.ts +18 -0
  26. package/dist/methods/_chopTemplates.d.ts +22 -0
  27. package/dist/methods/_defineData.d.ts +25 -0
  28. package/dist/methods/_defineType.d.ts +15 -0
  29. package/dist/methods/_readTemplate.d.ts +24 -0
  30. package/dist/methods/_renderHolder.d.ts +17 -0
  31. package/dist/methods/_setupActions.d.ts +19 -0
  32. package/dist/methods/build.d.ts +35 -0
  33. package/dist/methods/render.d.ts +25 -0
  34. package/dist/methods/settings.d.ts +7 -0
  35. package/dist/morph.cjs +1 -1
  36. package/dist/morph.esm.mjs +1 -1
  37. package/dist/morph.umd.js +1 -1
  38. package/morph.png +0 -0
  39. package/package.json +10 -7
  40. package/simple.js +17 -0
  41. package/specs/001-extend-templates/checklists/requirements.md +35 -0
  42. package/specs/001-extend-templates/contracts/set-method.json +39 -0
  43. package/specs/001-extend-templates/data-model.md +76 -0
  44. package/specs/001-extend-templates/plan.md +90 -0
  45. package/specs/001-extend-templates/quickstart.md +56 -0
  46. package/specs/001-extend-templates/research.md +18 -0
  47. package/specs/001-extend-templates/spec.md +139 -0
  48. package/specs/001-extend-templates/tasks.md +255 -0
  49. package/src/main.js +70 -32
  50. package/src/methods/_actionSupply.js +16 -0
  51. package/src/methods/_chopTemplates.js +22 -1
  52. package/src/methods/_defineData.js +33 -1
  53. package/src/methods/_defineType.js +13 -0
  54. package/src/methods/_readTemplate.js +46 -46
  55. package/src/methods/_renderHolder.js +15 -0
  56. package/src/methods/_setupActions.js +18 -8
  57. package/src/methods/build.js +98 -43
  58. package/src/methods/render.js +32 -11
  59. package/src/methods/settings.js +11 -0
  60. package/tsconfig.json +27 -0
  61. package/types/index.d.ts +0 -60
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <img src="morph.png" alt="morph header image">
2
+
1
3
  # Morph (@peter.naydenov/morph)
2
4
 
3
5
  ![version](https://img.shields.io/github/package-json/v/peterNaydenov/morph)
@@ -12,9 +14,9 @@
12
14
 
13
15
  In version 3 introduced `snippets`, you can choose to render only certain placeholders or groups of placeholders from the template. This lets you use templates as collections of reusable templates, so you can extract and use just the parts you need without having to render the whole template. This makes it easier to create and manage reusable template libraries for your project or rerender only the parts that need to be updated.
14
16
 
15
- The `render` function now takes a command as its first argument. Available commands are: `render`, `debug`, and `snippets`. Other arguments have no changes. Just shifted right. The second argument becomes the data, the third is dependencies, and the fourth is a list of post-processing functions.
17
+ The `render` function now takes a command as its first argument. Available commands are: `render`, `debug`, `snippets`, `curry`, and `set`. Other arguments have no changes. Just shifted right. The second argument becomes the data, the third is dependencies, and the fourth is a list of post-processing functions.
16
18
 
17
- In version 3.x.x, the data is always the second argument. It can be a string, as in version 2.x.x. The term "command" is no longer used for this argument; instead, it is called "instructions". Available instructions include: `raw`, `demo`, `handshake`, and `placeholders`.
19
+ In version 3.x.x, the data is always the second argument. It can be a string, as in version 2.x.x. The term "command" is no longer used for this argument; instead, it is called "instructions". Available instructions include: `raw`, `demo`, `handshake`, `placeholders`, and `count`.
18
20
 
19
21
  How to migrate to version 3.x.x, please read the [Migration guide](./Migration.guide.md). Read more about `snippets` down below.
20
22
 
@@ -260,7 +262,24 @@ Helpers are templates and functions that are used by actions to decorate the dat
260
262
 
261
263
 
262
264
  ## Commands
263
- The first argument of the render function is the command. Available commands are: `render`, `debug`, and `snippets`. Default command is `render` so if template doesn't need external information we can call the function without arguments.
265
+ The first argument of the render function is the command. Available commands are: `render`, `debug`, `snippets`, `curry`, and `set`. Default command is `render` so if template doesn't need external information we can call the function without arguments.
266
+
267
+
268
+ ## Debug
269
+ The `debug` command provides information about the template. The second argument is an instruction. Available instructions: `raw`, `demo`, `handshake`, `placeholders`, `count`.
270
+
271
+ - `raw`: Returns the original template string.
272
+ - `demo`: Renders the template with handshake data.
273
+ - `handshake`: Returns the handshake object.
274
+ - `placeholders`: Returns a string of placeholder names separated by commas.
275
+ - `count`: Returns the number of unresolved placeholders in the current template state.
276
+
277
+ ```js
278
+ const fn = morph.build(template);
279
+
280
+ let raw = fn('debug', 'raw'); // Original template
281
+ let count = fn('debug', 'count'); // Number of unresolved placeholders
282
+ ```
264
283
 
265
284
 
266
285
  ## Snippets
@@ -308,9 +327,141 @@ let res4 = fn ( 'snippets:2,3', 'demo' )
308
327
  ```
309
328
 
310
329
 
330
+ ## Curry
331
+ The `curry` command performs partial rendering with the provided data and returns a new render function. The new function uses the rendered output as the new template, while preserving the original helpers and handshake.
332
+
333
+ ```js
334
+ const template = morph.build({
335
+ template: 'Hello {{name}}! Welcome to {{place}}.',
336
+ helpers: { format: ({data}) => data.toUpperCase() },
337
+ handshake: { name: 'World', place: 'Earth' }
338
+ });
339
+
340
+ const curried = template('curry', { name: 'Alice' });
341
+ // curried is a new function with template 'Hello Alice! Welcome to {{place}}.'
342
+
343
+ const result = curried('render', { place: 'Mars' });
344
+ // result: 'Hello Alice! Welcome to Mars.'
345
+ ```
346
+
347
+ This allows chaining partial renders or completing with defaults using `('render', 'demo')`.
348
+
349
+
350
+ ## Set
351
+ The `set` command modifies the template by merging new helpers, handshake, or replacing placeholders, then returns a new render function with the changes applied.
352
+
353
+ ```js
354
+ const template = morph.build({
355
+ template: 'Hello {{name}}!',
356
+ helpers: { format: ({data}) => data.toLowerCase() },
357
+ handshake: { name: 'World' }
358
+ });
359
+
360
+ const modified = template('set', {
361
+ helpers: { format: ({data}) => data.toUpperCase() },
362
+ placeholders: { 0: '{{greeting}}' } // Replace first placeholder
363
+ });
364
+ // modified has updated helpers and template 'Hello {{greeting}}!'
365
+
366
+ const result = modified('render', { greeting: 'Hi' });
367
+ // result: 'HELLO HI!' (note: format applied to 'Hi')
368
+ ```
369
+
370
+
371
+ ## Experimentals
372
+
373
+ ### `.morph` File Extension
374
+
375
+ Describe Morph templates within `.morph` file extensions. Available after version 3.5.x. This allows you to create the template files with HTML-like syntax, CSS modules, and JavaScript helpers. During the build process, vite plugin will extract the template, helpers, and handshake data from the file, will compile it to function and will save as ES module, ready to import from other files. CSS support comes as extension of what Morph can do. Writing a Morph file that contains only CSS will be converted to CSS file. In morph files that contain mix of HTML, CSS, and JavaScript, the CSS will be converted to CSS modules.
376
+
377
+ A `.morph` file contains four separate sections.
378
+
379
+ The four sections are:
380
+ - **Template (HTML)** - The main template with Morph syntax
381
+ - **Script (JavaScript)** - Helper functions and logic
382
+ - **Style (CSS)** - CSS with automatic module scoping
383
+ - **Handshake (JSON)** - Demo data for testing
384
+
385
+ Example `.morph` file structure:
386
+ ```html
387
+ <!-- Template (HTML) -->
388
+ <div class="card">
389
+ <h2>{{ title : formatTitle }}</h2>
390
+ <p>{{ description : truncate }}</p>
391
+ <h3>Items</h3>
392
+ {{ items : ul, [], renderItem }}
393
+ <button data-click="save">Save</button>
394
+ </div>
395
+
396
+
397
+
398
+ <script>
399
+ // Place for helpers
400
+ // Function definition
401
+ function formatTitle ({ data }) {
402
+ return data.toUpperCase();
403
+ }
404
+
405
+ function truncate ({data}) {
406
+ const length = 100;
407
+ return data.length > length ? data.substring(0, length) + '...' : data;
408
+ }
409
+
410
+ // Template definition
411
+ let renderItem = `<li>{{name}}</li>`;
412
+ let ul = `<ul>{{text}}</ul>`
413
+ </script>
414
+
415
+ <style>
416
+ .card {
417
+ background: var(--card-bg, #fff);
418
+ padding: 1rem;
419
+ border-radius: 8px;
420
+ }
421
+ </style>
422
+
423
+ <script type="application/json">
424
+ // Script with type: application/json
425
+ // Handshake - Place for demo data
426
+ {
427
+ "title": "Card Title",
428
+ "description": "Card description",
429
+ "items": [
430
+ { "name": "Item 1" },
431
+ { "name": "Item 2" },
432
+ { "name": "Item 3" }
433
+ ]
434
+ }
435
+ </script>
436
+ ```
437
+
438
+ Get started with the official Vite plugin:
439
+ **GitHub Repository:** [vite-plugin-morph](https://github.com/PeterNaydenov/vite-plugin-morph)
440
+
441
+ Once configured, you can directly import `.morph` files in your code:
442
+ ```js
443
+ import myTemplate from './templates/my-template.morph'
444
+
445
+ // The imported template is ready to use
446
+ const result = myTemplate ( 'render', { name: 'Peter' })
447
+ ```
448
+
449
+
450
+
451
+ ### VSCode Extension
452
+
453
+ For better development experience with `.morph` files, you can install the official VSCode extension that provides syntax highlighting:
454
+
455
+ **Extension Name:** [Morph Template Syntax Highlighting](https://marketplace.visualstudio.com/items?itemName=PeterNaydenov.morph-template-syntax-highlighting)
456
+
457
+ Install directly from the VSCode Marketplace or search for "Morph Template Syntax Highlighting" in your VSCode extensions panel.
458
+
459
+
311
460
  ## Links
312
461
  - [Release history](Changelog.md)
313
462
  - [ Migration guide ](https://github.com/PeterNaydenov/morph/blob/master/Migration.guide.md)
463
+ - [ Vite Plugin ](https://github.com/PeterNaydenov/vite-plugin-morph)
464
+ - [ VSCode Extension ](https://marketplace.visualstudio.com/items?itemName=PeterNaydenov.morph-template-syntax-highlighting)
314
465
 
315
466
 
316
467
 
package/dist/main.d.ts ADDED
@@ -0,0 +1,100 @@
1
+ export default morphAPI;
2
+ declare namespace morphAPI {
3
+ export { build };
4
+ export { get };
5
+ export { add };
6
+ export { list };
7
+ export { clear };
8
+ export { remove };
9
+ }
10
+ import build from "./methods/build.js";
11
+ /**
12
+ * Retrieves a template from storage.
13
+ *
14
+ * @param {string[]} location - The location of the template. Array of two elements:
15
+ * - First element: The name of the template
16
+ * - Second element (optional): The name of the storage. Defaults to 'default'
17
+ *
18
+ * @returns {Function} The template (render function) if found, or an error function that returns
19
+ * an error message if the storage or template doesn't exist.
20
+ *
21
+ * @example
22
+ * // Get template from default storage
23
+ * const template = get(['myTemplate']);
24
+ *
25
+ * @example
26
+ * // Get template from custom storage
27
+ * const template = get(['myTemplate', 'customStorage']);
28
+ */
29
+ declare function get(location: string[]): Function;
30
+ /**
31
+ * Adds a template to storage.
32
+ *
33
+ * If the template is already a function, it's added directly to storage.
34
+ * If it's a template description object, it's built first and then added.
35
+ * If the template is null or broken, a warning/error is logged and it's not added.
36
+ *
37
+ * @param {string[]} location - The location to add the template to. Array of two elements:
38
+ * - First element: The name of the template
39
+ * - Second element (optional): The name of the storage. Defaults to 'default'
40
+ * @param {object|function|null} tplfn - The template description object, pre-built template function, or null
41
+ * @param {...any} args - Additional arguments passed to the build function (only used when tplfn is a template description)
42
+ *
43
+ * @example
44
+ * // Add a pre-built template function
45
+ * add(['myTemplate'], templateFunction);
46
+ *
47
+ * @example
48
+ * // Add and build a template description
49
+ * add(['myTemplate'], {
50
+ * template: 'Hello {{name}}!',
51
+ * helpers: { name: (data) => data.data.name }
52
+ * });
53
+ */
54
+ declare function add(location: string[], tplfn: object | Function | null, ...args: any[]): void;
55
+ /**
56
+ * Returns an array of template names from specified storages.
57
+ *
58
+ * @param {string[]} [storageNames=['default']] - Array of storage names to retrieve template names from.
59
+ * Defaults to ['default'] if not provided.
60
+ *
61
+ * @returns {string[]} Array of all template names from the specified storages.
62
+ *
63
+ * @example
64
+ * // List templates from default storage
65
+ * const templates = list();
66
+ *
67
+ * @example
68
+ * // List templates from multiple storages
69
+ * const templates = list(['default', 'customStorage']);
70
+ */
71
+ declare function list(storageNames?: string[]): string[];
72
+ /**
73
+ * Clears all templates from all storages.
74
+ *
75
+ * Deletes all custom storages and resets the 'default' storage to an empty object.
76
+ *
77
+ * @example
78
+ * // Clear all templates
79
+ * clear();
80
+ */
81
+ declare function clear(): void;
82
+ /**
83
+ * Removes a template from storage.
84
+ *
85
+ * @param {string[]} location - The location of the template to remove. Array of two elements:
86
+ * - First element: The name of the template
87
+ * - Second element (optional): The name of the storage. Defaults to 'default'
88
+ *
89
+ * @returns {void|string} Returns an error message if the storage or template doesn't exist,
90
+ * otherwise returns undefined.
91
+ *
92
+ * @example
93
+ * // Remove template from default storage
94
+ * remove(['myTemplate']);
95
+ *
96
+ * @example
97
+ * // Remove template from custom storage
98
+ * remove(['myTemplate', 'customStorage']);
99
+ */
100
+ declare function remove(location: string[]): void | string;
@@ -0,0 +1,18 @@
1
+ export default _actionSupply;
2
+ /**
3
+ * Generator function that supplies actions in a controlled sequence using a stack.
4
+ *
5
+ * Manages the flow of actions through different processing levels, allowing for
6
+ * dynamic action insertion during processing.
7
+ *
8
+ * @param {Object} act - Object containing action arrays organized by level
9
+ * @param {number} level - Maximum processing level
10
+ * @returns {Generator} Generator that yields action objects in sequence
11
+ *
12
+ * @example
13
+ * const generator = _actionSupply(actionSetup, 2);
14
+ * for (const action of generator) {
15
+ * // Process each action
16
+ * }
17
+ */
18
+ declare function _actionSupply(act: any, level: number): Generator;
@@ -0,0 +1,22 @@
1
+ export default _chopTemplate;
2
+ /**
3
+ * Creates a template chopping function that splits text into parts and placeholders.
4
+ *
5
+ * @param {object} settings - Configuration object containing template delimiters
6
+ * @param {string} settings.TG_PRX - Opening delimiter (e.g., '{{')
7
+ * @param {string} settings.TG_SFX - Closing delimiter (e.g., '}}')
8
+ * @param {number} settings.TG_SIZE_P - Length of opening delimiter
9
+ * @param {number} settings.TG_SIZE_S - Length of closing delimiter
10
+ *
11
+ * @returns {Function} Function that chops template text into array parts
12
+ *
13
+ * @example
14
+ * const chop = _chopTemplate(settings);
15
+ * const result = chop('Hello {{name}}!');
16
+ */
17
+ declare function _chopTemplate(settings: {
18
+ TG_PRX: string;
19
+ TG_SFX: string;
20
+ TG_SIZE_P: number;
21
+ TG_SIZE_S: number;
22
+ }): Function;
@@ -0,0 +1,25 @@
1
+ export default _defineData;
2
+ /**
3
+ * Processes data source based on action requirements and creates nested data structure.
4
+ *
5
+ * Analyzes the data source and action to determine if nested data processing is needed.
6
+ * If action contains '#', it walks through the data structure to collect nested objects.
7
+ *
8
+ * @param {any} dSource - The data source to process (function, null, string, or object)
9
+ * @param {string} action - Action string that may contain '#' indicating nested processing
10
+ *
11
+ * @returns {object} Data processing result containing:
12
+ * - dataDeepLevel: Maximum nesting level found
13
+ * - nestedData: Array of nested data arrays organized by level
14
+ *
15
+ * @example
16
+ * // Simple data without nesting
17
+ * const result = _defineData('hello', 'render');
18
+ * // Returns: { dataDeepLevel: 0, nestedData: [['hello']] }
19
+ *
20
+ * @example
21
+ * // Nested data with '#' action
22
+ * const result = _defineData({ user: { name: 'John' } }, 'render:#');
23
+ * // Returns: { dataDeepLevel: 1, nestedData: [[{ name: 'John' }]] }
24
+ */
25
+ declare function _defineData(dSource: any, action: string): object;
@@ -0,0 +1,15 @@
1
+ export default _defineDataType;
2
+ /**
3
+ * Determines the data type of a value for template processing.
4
+ *
5
+ * @param {any} data - Value to type-check
6
+ * @returns {string|undefined} Returns one of: 'null', 'primitive', 'function', 'array', 'object', or undefined
7
+ *
8
+ * @example
9
+ * _defineDataType(null); // 'null'
10
+ * _defineDataType('hello'); // 'primitive'
11
+ * _defineDataType([1,2,3]); // 'array'
12
+ * _defineDataType({}); // 'object'
13
+ * _defineDataType(() => {}); // 'function'
14
+ */
15
+ declare function _defineDataType(data: any): string | undefined;
@@ -0,0 +1,24 @@
1
+ export default _readTemplate;
2
+ /**
3
+ * Parses and validates a template description object.
4
+ *
5
+ * Extracts placeholders, validates helpers, and prepares template for building.
6
+ *
7
+ * @param {object} tpl - Template description object
8
+ * @param {string} tpl.template - Template string with placeholders
9
+ * @param {object} [tpl.helpers={}] - Optional helper functions
10
+ * @param {object} [tpl.handshake] - Optional example data
11
+ *
12
+ * @returns {object} Template parsing result containing:
13
+ * - hasError: Error message or null
14
+ * - placeholders: Array of placeholder objects
15
+ * - chop: Array of template parts
16
+ * - helpers: Helper functions object
17
+ * - handshake: Example data object
18
+ * - snippets: Object mapping snippet names to placeholders
19
+ */
20
+ declare function _readTemplate(tpl: {
21
+ template: string;
22
+ helpers?: object;
23
+ handshake?: object;
24
+ }): object;
@@ -0,0 +1,17 @@
1
+ export default _renderHolder;
2
+ /**
3
+ * Renders a simple template by replacing placeholders with data values.
4
+ *
5
+ * Processes templates with basic placeholder substitution without actions or helpers.
6
+ * Only supports direct field replacement from the data object.
7
+ *
8
+ * @param {string} template - Template string with placeholders
9
+ * @param {object} data - Data object containing values for placeholder replacement
10
+ *
11
+ * @returns {string|null} Rendered template string or null if data is null
12
+ *
13
+ * @example
14
+ * const result = _renderHolder('Hello {{name}}!', { name: 'World' });
15
+ * // Returns: 'Hello World!'
16
+ */
17
+ declare function _renderHolder(template: string, data: object): string | null;
@@ -0,0 +1,19 @@
1
+ export default _setupActions;
2
+ /**
3
+ * Parses and organizes template actions into a structured setup by processing level.
4
+ *
5
+ * Converts action strings into structured objects with types and levels. Validates that
6
+ * there are enough level markers (#) for the data depth.
7
+ *
8
+ * @param {string[]} actions - Array of action strings to process
9
+ * @param {number} [dataDeepLevel=10] - Maximum depth level for nested data processing
10
+ *
11
+ * @returns {Object} Object with numeric keys containing arrays of action objects by level
12
+ *
13
+ * @example
14
+ * const setup = _setupActions(['render', '#', 'save:var'], 2);
15
+ * // Returns: { 0: [{type: 'render', name: 'render', level: 0}],
16
+ * // 1: [{type: 'save', name: 'var', level: 1}],
17
+ * // 2: [] }
18
+ */
19
+ declare function _setupActions(actions: string[], dataDeepLevel?: number): any;
@@ -0,0 +1,35 @@
1
+ export default build;
2
+ export type Template = {
3
+ /**
4
+ * - Data to be rendered;
5
+ */
6
+ template: string;
7
+ /**
8
+ * - Optional. Object with helper functions or simple templates for this template;
9
+ */
10
+ helpers?: object;
11
+ /**
12
+ * - Optional. Example for data to be rendered with;
13
+ */
14
+ handshake?: object;
15
+ };
16
+ export type tupleResult = any[];
17
+ /**
18
+ * @typedef {Object} Template
19
+ * @property {string} template - Data to be rendered;
20
+ * @property {object} [helpers] - Optional. Object with helper functions or simple templates for this template;
21
+ * @property {object} [handshake] - Optional. Example for data to be rendered with;
22
+ */
23
+ /**
24
+ * @typedef {Array} tupleResult
25
+ * @property {boolean} 0 - Indicates success (true) or failure (false).
26
+ * @property {function} 1 - The rendering function or an error function.
27
+ */
28
+ /**
29
+ *
30
+ * @param {Template} tpl - template definition;
31
+ * @param {boolean} [extra] - Optional. How to receive the answer - false:as a string(answer) or true: as tuple[success, answer];
32
+ * @param {object} [buildDependencies] - Optional. External dependencies injected;
33
+ * @returns {function|tupleResult} - rendering function
34
+ */
35
+ declare function build(tpl: Template, extra?: boolean, buildDependencies?: object): Function | tupleResult;
@@ -0,0 +1,25 @@
1
+ export default render;
2
+ /**
3
+ * Executes rendering and returns the rendered result.
4
+ *
5
+ * Handles both function-based and template-based rendering. Normalizes data objects
6
+ * by converting nested objects to their 'text' properties and arrays to their first elements.
7
+ *
8
+ * @param {object|string} theData - Data to be rendered. If string, becomes the 'text' property value.
9
+ * @param {string} name - Name of the render helper/template to execute
10
+ * @param {object} helpers - Object containing helper functions and templates
11
+ * @param {object} original - Original data context for full data access
12
+ * @param {object} dependencies - External dependencies available to helpers
13
+ * @param {...any} args - Additional arguments passed to the render function
14
+ *
15
+ * @returns {string} Rendered string result
16
+ *
17
+ * @example
18
+ * // Render with function helper
19
+ * const result = render(data, 'myHelper', helpers, originalData, deps);
20
+ *
21
+ * @example
22
+ * // Render with template
23
+ * const result = render(data, 'myTemplate', helpers, originalData, deps);
24
+ */
25
+ declare function render(theData: object | string, name: string, helpers: object, original: object, dependencies: object, ...args: any[]): string;
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ TG_PRX: string;
3
+ TG_SFX: string;
4
+ TG_SIZE_P: number;
5
+ TG_SIZE_S: number;
6
+ };
7
+ export default _default;
package/dist/morph.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:l}=e;let i,c,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<i)return n("closedBeforeOpened");if(c+=l,-1!=u&&u<c)return n("newBeforeClosed");f.push(r.slice(i,c));let e=t(r.slice(c));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,t,n,o,s,...l){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const i="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?n[t]({theData:e,dependencies:s,full:o},...l):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function l(n,l=!1,i={}){let{hasError:c,placeholders:u,chop:f,helpers:d,handshake:p,snippets:h}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:l}=a,i=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let f=null;const d=r(a)(u);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};i.push(o),c[i.length-1]=o,o.name&&(c[o.name]=o)}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:i,chop:d,helpers:n,handshake:o,snippets:c}}(n);if(c){function m(){return c}return l?[!1,m]:m}{const b=structuredClone(u);function y(r="render",n={},a={},...l){const c=structuredClone(f);let m=!1;if(!["render","debug","snippets"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets.`;if(r.startsWith("snippets")&&r.includes(":")){m=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));u=e.map((e=>h[e]))}else"snippets"===r?m=!0:u=structuredClone(b);if("string"==typeof n)switch(n){case"raw":return c.join("");case"demo":if(!p)return"Error: No handshake data.";n=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>c[e.index])).join(", ");default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, placeholders.`}const y=[],g={};let v=o(n),E={...i,...a};n=e({data:n});let k=e({data:n});return"null"===v?c.join(""):("array"!==v&&(n=[n]),"null"===v?c.join(""):(n.forEach((r=>{u.forEach((a=>{const{index:l,data:i,action:u}=a,f=!u&&i,p=structuredClone(g),h={dependencies:E,memory:p};let m=r;if(i&&i.includes("/")?m.hasOwnProperty(i)?m=m[i]:i.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===i||null===i||"@root"===i?m=r:i&&(m=m[i]),f){switch(o(m)){case"function":return void(c[l]=m());case"primitive":return void(c[l]=m);case"array":return void("primitive"===o(m[0])&&(c[l]=m[0]));case"object":return void(m.text&&(c[l]=m.text))}}else{let{dataDeepLevel:a,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(m,u),f=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(u,a),a);for(let t of f){let{type:a,name:l,level:c}=t;(i[c]||[]).forEach(((t,u)=>{let f=o(t);switch(a){case"route":switch(f){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=d[l]({data:e,...h,full:e});null!=a&&("object"===n?t[r].text=s(e,a,d,k,E):t[r]=s(e,a,d,k,E))}));break;case"object":t.text=s(t,l,d,k,E)}break;case"save":g[l]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(f){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?d[l]({data:e(),...h,full:e}):d[l]({data:e,...h,full:e})));break;case"object":i[c]=[d[l]({data:t,...h,full:n})];break;case"function":i[c]=[d[l]({data:t(),...h,full:n})];break;case"primitive":i[c]=d[l]({data:t,...h,full:n})}break;case"render":const p="function"==typeof d[l];switch(f){case"array":p?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=d[l]({data:e,...h,full:k});null==a&&(t[r]=null),"object"===n?e.text=a:t[r]=a})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=s(e,l,d,k,E);null==a?t[r]=null:"object"===n?e.text=a:t[r]=a}));break;case"function":i[c]=d[l]({data:t(),...h,full:n});break;case"primitive":i[c]=p?d[l]({data:t,...h,full:n}):s(t,l,d,k,E);break;case"object":p?i[c][u].text=d[l]({data:t,...h,full:n}):t.text=s(t,l,d,k,E)}break;case"extendedRender":"function"==typeof d[l]&&i[0].forEach(((e,t)=>i[0][t]=d[l]({data:e,...h,full:e})));break;case"mix":if(""===l)switch(f){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[c][e]=t.text)):i[c]=t.text;for(let b=c-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:m});function m({value:e,breadcrumbs:t}){return i[c][t]?i[c][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=d[l]({data:t,...h,full:n}),v=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,v){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let p=o(i[0]),b=i[0];switch(p){case"primitive":if(null==b)return;c[l]=b;break;case"object":if(null==b.text)return;c[l]=b.text;break;case"array":const e=o(b[0]);c[l]="object"===e?b.map((e=>e.text)).join(""):b.join("")}}})),m?y.push(u.map((e=>c[e.index])).join("<~>")):y.push(c.join(""))})),"array"===v?y:l?l.reduce(((e,t)=>"function"!=typeof t?e:t(e,E)),y.join("")):y.join("")))}return l?[!0,y]:y}}const i={default:{}};const c={build:l,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return i[r]?i[r][t]?i[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(i[a]||(i[a]={}),"function"!=typeof t){let e=l(t,!0,...r);s=e[0],o=e[1]}s?i[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>i[e]?Object.keys(i[e]):[])).flat()},clear:function(){Object.keys(i).forEach((e=>{"default"!=e?delete i[e]:i.default={}}))},remove:function(e){const[t,r="default"]=e;return i[r]?i[r][t]?void delete i[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};module.exports=c;
1
+ "use strict";var e=require("@peter.naydenov/walk"),t=require("@peter.naydenov/stack");function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:l}=e;let i,c,u,d=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&d.push(r.slice(0,i)),-1==i)return d.push(r),d;{if(u=r.indexOf(a,i+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<i)return n("closedBeforeOpened");if(c+=l,-1!=u&&u<c)return n("newBeforeClosed");d.push(r.slice(i,c));let e=t(r.slice(c));return d.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,t,n,o,s,...l){if(e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])})),!n[t])return`{{ Error: Helper '${t}' is not available}}`;const i="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?n[t]({theData:e,dependencies:s,full:o},...l):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function l(n,i=!1,c={}){let{hasError:u,placeholders:d,chop:f,helpers:p,handshake:h,snippets:m}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:l}=a,i=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let d=null;const f=r(a)(u);return"string"==typeof f?d=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};i.push(o),c[i.length-1]=o,o.name&&(c[o.name]=o)}var n})),{hasError:d,placeholders:i,chop:f,helpers:n,handshake:o,snippets:c}}(n);if(u){function b(){return u}return i?[!1,b]:b}{const y=structuredClone(d);function g(r="render",n={},a={},...i){const u=structuredClone(f);let b=!1;if("string"!=typeof r)return`Error: Wrong command "${r}". Available commands: render, debug, snippets, set, curry.`;if(!["render","debug","snippets","set","curry"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets, set, curry.`;if(r.startsWith("snippets")&&r.includes(":")){b=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));d=e.map((e=>m[e]))}else if("snippets"===r)b=!0;else{if("set"===r){if("object"!=typeof n||!n)return"Error: 'set' command requires an object with placeholders, helpers, handshake.";const e={...p,...n.helpers||{}},t=h?{...h,...n.handshake||{}}:n.handshake||{},r=[...f];n.placeholders&&Object.entries(n.placeholders).forEach((([e,t])=>{if(isNaN(e)){let n=d.find((t=>t.name===e));r[n.index]=t}else{let n=d[e].index;r[n]=t}}));const a=l({template:r.join(""),helpers:e,handshake:t},!1,c);return"function"==typeof a?a:()=>a}if("curry"===r){return l({template:g("render",n,a,...i),helpers:p,handshake:h},!1,c)}d=structuredClone(y)}if("string"==typeof n)switch(n){case"raw":return u.join("");case"demo":if(!h)return"Error: No handshake data.";n=h;break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"helpers":return Object.keys(p).join(", ");case"placeholders":return d.map((e=>u[e.index])).join(", ");case"count":return d.length;default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, helpers, placeholders, count.`}const v=[],E={};let k=o(n),j={...c,...a};n=e({data:n});let x=e({data:n});return"null"===k?u.join(""):("array"!==k&&(n=[n]),"null"===k?u.join(""):(n.forEach((r=>{d.forEach((a=>{const{index:l,data:i,action:c}=a,d=!c&&i,f=structuredClone(E),h={dependencies:j,memory:f};let m=r;if(i&&i.includes("/")?m.hasOwnProperty(i)?m=m[i]:i.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===i||null===i||"@root"===i?m=r:i&&(m=m[i]),d){switch(o(m)){case"function":return void(u[l]=m());case"primitive":return void(u[l]=m);case"array":return void("primitive"===o(m[0])&&(u[l]=m[0]));case"object":return void(m.text&&(u[l]=m.text))}}else{let{dataDeepLevel:a,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(m,c),d=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(c,a),a);for(let t of d){let{type:a,name:l,level:c}=t;(i[c]||[]).forEach(((t,u)=>{let d=o(t);switch(a){case"route":switch(d){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=p[l]({data:e,...h,full:e});null!=a&&("object"===n?t[r].text=s(e,a,p,x,j):t[r]=s(e,a,p,x,j))}));break;case"object":t.text=s(t,l,p,x,j)}break;case"save":E[l]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(d){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?p[l]({data:e(),...h,full:e}):p[l]({data:e,...h,full:e})));break;case"object":i[c]=[p[l]({data:t,...h,full:n})];break;case"function":i[c]=[p[l]({data:t(),...h,full:n})];break;case"primitive":i[c]=p[l]({data:t,...h,full:n})}break;case"render":const f="function"==typeof p[l];switch(d){case"array":f?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=p[l]({data:e,...h,full:x});null==a&&(t[r]=null),"object"===n?e.text=a:t[r]=a})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=s(e,l,p,x,j);null==a?t[r]=null:"object"===n?e.text=a:t[r]=a}));break;case"function":i[c]=p[l]({data:t(),...h,full:n});break;case"primitive":i[c]=f?p[l]({data:t,...h,full:n}):s(t,l,p,x,j);break;case"object":f?i[c][u].text=p[l]({data:t,...h,full:n}):t.text=s(t,l,p,x,j)}break;case"extendedRender":"function"==typeof p[l]&&i[0].forEach(((e,t)=>i[0][t]=p[l]({data:e,...h,full:e})));break;case"mix":if(""===l)switch(d){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[c][e]=t.text)):i[c]=t.text;for(let b=c-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:m});function m({value:e,breadcrumbs:t}){return i[c][t]?i[c][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=p[l]({data:t,...h,full:n}),g=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let f=o(i[0]),b=i[0];switch(f){case"primitive":if(null==b)return;u[l]=b;break;case"object":if(null==b.text)return;u[l]=b.text;break;case"array":const e=o(b[0]);u[l]="object"===e?b.map((e=>e.text)).join(""):b.join("")}}})),b?v.push(d.map((e=>u[e.index])).join("<~>")):v.push(u.join(""))})),"array"===k?v:i?i.reduce(((e,t)=>"function"!=typeof t?e:t(e,j)),v.join("")):v.join("")))}return i?[!0,g]:g}}const i={default:{}};const c={build:l,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return i[r]?i[r][t]?i[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(i[a]||(i[a]={}),"function"!=typeof t){let e=l(t,!0,...r);s=e[0],o=e[1]}s?i[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>i[e]?Object.keys(i[e]):[])).flat()},clear:function(){Object.keys(i).forEach((e=>{"default"!=e?delete i[e]:i.default={}}))},remove:function(e){const[t,r="default"]=e;return i[r]?i[r][t]?void delete i[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};module.exports=c;
@@ -1 +1 @@
1
- import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:l}=e;let i,c,u,f=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&f.push(r.slice(0,i)),-1==i)return f.push(r),f;{if(u=r.indexOf(a,i+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<i)return n("closedBeforeOpened");if(c+=l,-1!=u&&u<c)return n("newBeforeClosed");f.push(r.slice(i,c));let e=t(r.slice(c));return f.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,t,n,o,s,...l){e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])}));const i="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?n[t]({theData:e,dependencies:s,full:o},...l):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function l(n,l=!1,i={}){let{hasError:c,placeholders:u,chop:f,helpers:d,handshake:p,snippets:h}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:l}=a,i=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let f=null;const d=r(a)(u);return"string"==typeof d?f=d:d.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};i.push(o),c[i.length-1]=o,o.name&&(c[o.name]=o)}var n})),i.forEach((e=>{e.action&&e.action.every((e=>"#"===e||"^^"===e||!(!e.startsWith("^")||"^^"===e)||(e.startsWith("?")&&(e=e.replace("?","")),e.startsWith("+")&&(e=e.replace("+","")),e.startsWith("[]")&&(e=e.replace("[]","")),e.startsWith(">")&&(e=e.replace(">","")),""===e||!!n[e]||(f=`Error: Missing helper: ${e}`,!1))))})),{hasError:f,placeholders:i,chop:d,helpers:n,handshake:o,snippets:c}}(n);if(c){function m(){return c}return l?[!1,m]:m}{const b=structuredClone(u);function y(r="render",n={},a={},...l){const c=structuredClone(f);let m=!1;if(!["render","debug","snippets"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets.`;if(r.startsWith("snippets")&&r.includes(":")){m=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));u=e.map((e=>h[e]))}else"snippets"===r?m=!0:u=structuredClone(b);if("string"==typeof n)switch(n){case"raw":return c.join("");case"demo":if(!p)return"Error: No handshake data.";n=p;break;case"handshake":return p?structuredClone(p):"Error: No handshake data.";case"placeholders":return u.map((e=>c[e.index])).join(", ");default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, placeholders.`}const y=[],g={};let v=o(n),E={...i,...a};n=e({data:n});let k=e({data:n});return"null"===v?c.join(""):("array"!==v&&(n=[n]),"null"===v?c.join(""):(n.forEach((r=>{u.forEach((a=>{const{index:l,data:i,action:u}=a,f=!u&&i,p=structuredClone(g),h={dependencies:E,memory:p};let m=r;if(i&&i.includes("/")?m.hasOwnProperty(i)?m=m[i]:i.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===i||null===i||"@root"===i?m=r:i&&(m=m[i]),f){switch(o(m)){case"function":return void(c[l]=m());case"primitive":return void(c[l]=m);case"array":return void("primitive"===o(m[0])&&(c[l]=m[0]));case"object":return void(m.text&&(c[l]=m.text))}}else{let{dataDeepLevel:a,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(m,u),f=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("?")?(r[a].push({type:"route",name:e.replace("?",""),level:a}),!0):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(u,a),a);for(let t of f){let{type:a,name:l,level:c}=t;(i[c]||[]).forEach(((t,u)=>{let f=o(t);switch(a){case"route":switch(f){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=d[l]({data:e,...h,full:e});null!=a&&("object"===n?t[r].text=s(e,a,d,k,E):t[r]=s(e,a,d,k,E))}));break;case"object":t.text=s(t,l,d,k,E)}break;case"save":g[l]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(f){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?d[l]({data:e(),...h,full:e}):d[l]({data:e,...h,full:e})));break;case"object":i[c]=[d[l]({data:t,...h,full:n})];break;case"function":i[c]=[d[l]({data:t(),...h,full:n})];break;case"primitive":i[c]=d[l]({data:t,...h,full:n})}break;case"render":const p="function"==typeof d[l];switch(f){case"array":p?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=d[l]({data:e,...h,full:k});null==a&&(t[r]=null),"object"===n?e.text=a:t[r]=a})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=s(e,l,d,k,E);null==a?t[r]=null:"object"===n?e.text=a:t[r]=a}));break;case"function":i[c]=d[l]({data:t(),...h,full:n});break;case"primitive":i[c]=p?d[l]({data:t,...h,full:n}):s(t,l,d,k,E);break;case"object":p?i[c][u].text=d[l]({data:t,...h,full:n}):t.text=s(t,l,d,k,E)}break;case"extendedRender":"function"==typeof d[l]&&i[0].forEach(((e,t)=>i[0][t]=d[l]({data:e,...h,full:e})));break;case"mix":if(""===l)switch(f){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[c][e]=t.text)):i[c]=t.text;for(let b=c-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:m});function m({value:e,breadcrumbs:t}){return i[c][t]?i[c][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=d[l]({data:t,...h,full:n}),v=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,v){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let p=o(i[0]),b=i[0];switch(p){case"primitive":if(null==b)return;c[l]=b;break;case"object":if(null==b.text)return;c[l]=b.text;break;case"array":const e=o(b[0]);c[l]="object"===e?b.map((e=>e.text)).join(""):b.join("")}}})),m?y.push(u.map((e=>c[e.index])).join("<~>")):y.push(c.join(""))})),"array"===v?y:l?l.reduce(((e,t)=>"function"!=typeof t?e:t(e,E)),y.join("")):y.join("")))}return l?[!0,y]:y}}const i={default:{}};const c={build:l,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return i[r]?i[r][t]?i[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(i[a]||(i[a]={}),"function"!=typeof t){let e=l(t,!0,...r);s=e[0],o=e[1]}s?i[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>i[e]?Object.keys(i[e]):[])).flat()},clear:function(){Object.keys(i).forEach((e=>{"default"!=e?delete i[e]:i.default={}}))},remove:function(e){const[t,r="default"]=e;return i[r]?i[r][t]?void delete i[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{c as default};
1
+ import e from"@peter.naydenov/walk";import t from"@peter.naydenov/stack";function r(e){return function t(r){const{TG_PRX:a,TG_SFX:o,TG_SIZE_P:s,TG_SIZE_S:l}=e;let i,c,u,d=[];if("string"!=typeof r)return n("notAString");if(0==r.length)return[];if(i=r.indexOf(a),0<i&&d.push(r.slice(0,i)),-1==i)return d.push(r),d;{if(u=r.indexOf(a,i+s),c=r.indexOf(o),-1==c)return n("missingClosing");if(c<i)return n("closedBeforeOpened");if(c+=l,-1!=u&&u<c)return n("newBeforeClosed");d.push(r.slice(i,c));let e=t(r.slice(c));return d.concat(e)}}}function n(e){switch(e){case"notAString":return"Error: Template is not a string.";case"missingClosing":return"Error: Placeholder with missing closing tag.";case"closedBeforeOpened":return"Error: Placeholder closing tag without starting one.";case"newBeforeClosed":return"Error: Nested placeholders. Close placeholder before open new one.";default:return"Error: Unknown template error."}}var a={TG_PRX:"{{",TG_SFX:"}}",TG_SIZE_P:2,TG_SIZE_S:2};function o(e){return null==e?"null":"string"==typeof e||"number"==typeof e||"boolean"==typeof e?"primitive":"function"==typeof e?"function":e instanceof Array?"array":e instanceof Object?"object":void 0}function s(e,t,n,o,s,...l){if(e instanceof Object&&Object.entries(e).forEach((([t,r])=>{r instanceof Object&&(e[t]=r.text),r instanceof Array&&(e[t]=r[0])})),!n[t])return`{{ Error: Helper '${t}' is not available}}`;const i="function"==typeof n[t];return e=function(e={}){return"string"==typeof e?{text:e}:e}(e),i?n[t]({theData:e,dependencies:s,full:o},...l):function(e,t){if(null==t)return null;const n=r(a)(e),o=a;return n.forEach(((e,r)=>{if(e.includes(o.TG_PRX)){const a=e.replace(o.TG_PRX,"").replace(o.TG_SFX,"").trim();t.hasOwnProperty(a)&&null!=t[a]&&(n[r]=t[a])}})),n.join("")}(n[t],e)}function l(n,i=!1,c={}){let{hasError:u,placeholders:d,chop:f,helpers:p,handshake:h,snippets:m}=function(e){const{template:t,helpers:n={},handshake:o}=e,{TG_PRX:s,TG_SFX:l}=a,i=[],c={},u="string"==typeof t?t.replace(/<!--[\s\S]*?-->/g,"").replace(/\s{2,}/g," "):t;let d=null;const f=r(a)(u);return"string"==typeof f?d=f:f.forEach(((e,t)=>{const r=RegExp(s+"\\s*(.*?)\\s*(?::\\s*(.*?)\\s*)?(?::\\s*(.*?)\\s*)?"+l,"g");if(e.includes(s)){const a=r.exec(e);if(!a)return;let o={index:t,data:(n=a[1],n||null),action:a[2]?a[2].split(",").map((e=>e.trim())):null,name:a[3]?a[3].trim():null};i.push(o),c[i.length-1]=o,o.name&&(c[o.name]=o)}var n})),{hasError:d,placeholders:i,chop:f,helpers:n,handshake:o,snippets:c}}(n);if(u){function b(){return u}return i?[!1,b]:b}{const y=structuredClone(d);function g(r="render",n={},a={},...i){const u=structuredClone(f);let b=!1;if("string"!=typeof r)return`Error: Wrong command "${r}". Available commands: render, debug, snippets, set, curry.`;if(!["render","debug","snippets","set","curry"].includes(r)&&!r.startsWith("snippets"))return`Error: Wrong command "${r}". Available commands: render, debug, snippets, set, curry.`;if(r.startsWith("snippets")&&r.includes(":")){b=!0;let e=r.split(":").slice(1)[0].trim().split(",").map((e=>e.trim()));d=e.map((e=>m[e]))}else if("snippets"===r)b=!0;else{if("set"===r){if("object"!=typeof n||!n)return"Error: 'set' command requires an object with placeholders, helpers, handshake.";const e={...p,...n.helpers||{}},t=h?{...h,...n.handshake||{}}:n.handshake||{},r=[...f];n.placeholders&&Object.entries(n.placeholders).forEach((([e,t])=>{if(isNaN(e)){let n=d.find((t=>t.name===e));r[n.index]=t}else{let n=d[e].index;r[n]=t}}));const a=l({template:r.join(""),helpers:e,handshake:t},!1,c);return"function"==typeof a?a:()=>a}if("curry"===r){return l({template:g("render",n,a,...i),helpers:p,handshake:h},!1,c)}d=structuredClone(y)}if("string"==typeof n)switch(n){case"raw":return u.join("");case"demo":if(!h)return"Error: No handshake data.";n=h;break;case"handshake":return h?structuredClone(h):"Error: No handshake data.";case"helpers":return Object.keys(p).join(", ");case"placeholders":return d.map((e=>u[e.index])).join(", ");case"count":return d.length;default:return`Error: Wrong instruction "${n}". Available instructions: raw, demo, handshake, helpers, placeholders, count.`}const v=[],E={};let k=o(n),j={...c,...a};n=e({data:n});let x=e({data:n});return"null"===k?u.join(""):("array"!==k&&(n=[n]),"null"===k?u.join(""):(n.forEach((r=>{d.forEach((a=>{const{index:l,data:i,action:c}=a,d=!c&&i,f=structuredClone(E),h={dependencies:j,memory:f};let m=r;if(i&&i.includes("/")?m.hasOwnProperty(i)?m=m[i]:i.split("/").forEach((e=>{m=m.hasOwnProperty(e)?m[e]:[]})):"@all"===i||null===i||"@root"===i?m=r:i&&(m=m[i]),d){switch(o(m)){case"function":return void(u[l]=m());case"primitive":return void(u[l]=m);case"array":return void("primitive"===o(m[0])&&(u[l]=m[0]));case"object":return void(m.text&&(u[l]=m.text))}}else{let{dataDeepLevel:a,nestedData:i}=function(t,r){const n=[];let a=0;if(t instanceof Function)return{dataDeepLevel:0,nestedData:[[t()]]};if(null==t)return{dataDeepLevel:0,nestedData:[null]};if("string"==typeof t)return{dataDeepLevel:0,nestedData:[[t]]};const o=structuredClone(t);return r.includes("#")?(e({data:o,objectCallback:function({key:e,value:t,breadcrumbs:r}){return e===r?(n[0]=[t],t):(a=r.split("/").length-1,n[a]||(n[a]=[]),n[a].push(t),t)}}),{dataDeepLevel:a,nestedData:n}):(n.push([o]),{dataDeepLevel:0,nestedData:n})}(m,c),d=function*(e,r){let n=t({type:"LIFO"});for(let t=0;t<=r;t++)n.push(e[t]);for(;n&&!n.isEmpty();){let e=yield n.pull();e&&n.push(e)}}(function(e,t=10){let r={},n=[...e],a=0,o=0,s=0;n.forEach((e=>{"#"===e&&s++})),s<t&&console.error(`Error: Not enough level markers (#) for data with depth level ${t}. Found ${s} level markers in actions: ${e.join(", ")}`);do{r[o]=[],o++}while(o<=t);return n.every((e=>"#"===e?(a++,!(a>t)):e.startsWith("^")&&"^^"!==e?(r[a].push({type:"save",name:e.replace("^",""),level:a}),!0):"^^"===e?(r[a].push({type:"overwrite",name:"none",level:a}),!0):e.startsWith("+")?(r[a].push({type:"extendedRender",name:e.replace("+",""),level:a}),!0):e.startsWith("[]")?(r[a].push({type:"mix",name:e.replace("[]",""),level:a}),!0):e.startsWith(">")?(r[a].push({type:"data",name:e.replace(">",""),level:a}),!0):(""===e||r[a].push({type:"render",name:e,level:a}),!0))),r}(c,a),a);for(let t of d){let{type:a,name:l,level:c}=t;(i[c]||[]).forEach(((t,u)=>{let d=o(t);switch(a){case"route":switch(d){case"array":t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=p[l]({data:e,...h,full:e});null!=a&&("object"===n?t[r].text=s(e,a,p,x,j):t[r]=s(e,a,p,x,j))}));break;case"object":t.text=s(t,l,p,x,j)}break;case"save":E[l]=structuredClone(t);break;case"overwrite":r=structuredClone(t);break;case"data":switch(d){case"array":t.forEach(((e,r)=>t[r]=e instanceof Function?p[l]({data:e(),...h,full:e}):p[l]({data:e,...h,full:e})));break;case"object":i[c]=[p[l]({data:t,...h,full:n})];break;case"function":i[c]=[p[l]({data:t(),...h,full:n})];break;case"primitive":i[c]=p[l]({data:t,...h,full:n})}break;case"render":const f="function"==typeof p[l];switch(d){case"array":f?t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=p[l]({data:e,...h,full:x});null==a&&(t[r]=null),"object"===n?e.text=a:t[r]=a})):t.forEach(((e,r)=>{if(null==e)return;const n=o(e),a=s(e,l,p,x,j);null==a?t[r]=null:"object"===n?e.text=a:t[r]=a}));break;case"function":i[c]=p[l]({data:t(),...h,full:n});break;case"primitive":i[c]=f?p[l]({data:t,...h,full:n}):s(t,l,p,x,j);break;case"object":f?i[c][u].text=p[l]({data:t,...h,full:n}):t.text=s(t,l,p,x,j)}break;case"extendedRender":"function"==typeof p[l]&&i[0].forEach(((e,t)=>i[0][t]=p[l]({data:e,...h,full:e})));break;case"mix":if(""===l)switch(d){case"object":Object.keys(t).find((e=>e.includes("/")))?Object.entries(t).forEach((([e,t])=>i[c][e]=t.text)):i[c]=t.text;for(let b=c-1;b>=0;b--)i[b]=e({data:i[b],objectCallback:m});function m({value:e,breadcrumbs:t}){return i[c][t]?i[c][t]:e}break;case"array":t.forEach(((e,r)=>{if(r>0){let n=o(e);if(null==e)return;t[0]+="object"===n?`${e.text}`:`${e}`,t.toSpliced(r,1)}else{let r=o(e);if(t[0]="",null===r)return;t[0]="object"===r?`${e.text}`:`${e}`}})),t.length=1}else{let y=p[l]({data:t,...h,full:n}),g=o(y);switch(t.forEach(((e,r)=>t.splice(r,1))),t.length=0,g){case"primitive":t[0]=y;break;case"array":t.push(...y)}}}}))}if(i instanceof Array&&1===i.length&&i[0]instanceof Array&&(i=i[0]),null==i[0])return;let f=o(i[0]),b=i[0];switch(f){case"primitive":if(null==b)return;u[l]=b;break;case"object":if(null==b.text)return;u[l]=b.text;break;case"array":const e=o(b[0]);u[l]="object"===e?b.map((e=>e.text)).join(""):b.join("")}}})),b?v.push(d.map((e=>u[e.index])).join("<~>")):v.push(u.join(""))})),"array"===k?v:i?i.reduce(((e,t)=>"function"!=typeof t?e:t(e,j)),v.join("")):v.join("")))}return i?[!0,g]:g}}const i={default:{}};const c={build:l,get:function(e){if(!(e instanceof Array))return function(){return'Error: Argument "location" is a string. Should be an array. E.g. ["templateName", "storageName"].'};const[t,r="default"]=e;return i[r]?i[r][t]?i[r][t]:function(){return`Error: Template "${t}" does not exist in storage "${r}".`}:function(){return`Error: Storage "${r}" does not exist.`}},add:function(e,t,...r){const[n,a="default"]=e;if(null==t)return void console.warn(`Warning: Template ${a}/${n} is not added to storage. The template is null.`);let o=t,s=!0;if(i[a]||(i[a]={}),"function"!=typeof t){let e=l(t,!0,...r);s=e[0],o=e[1]}s?i[a][n]=o:console.error(`Error: Template "${n}" looks broken and is not added to storage.`)},list:function(e=["default"]){return e.map((e=>i[e]?Object.keys(i[e]):[])).flat()},clear:function(){Object.keys(i).forEach((e=>{"default"!=e?delete i[e]:i.default={}}))},remove:function(e){const[t,r="default"]=e;return i[r]?i[r][t]?void delete i[r][t]:`Error: Template "${t}" does not exist in storage "${r}".`:`Error: Storage "${r}" does not exist.`}};export{c as default};