@peter.naydenov/morph 3.3.0 → 3.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build.architecture.png +0 -0
- package/dist/methods/actionData.d.ts +10 -0
- package/dist/methods/actionExtendedRender.d.ts +10 -0
- package/dist/methods/actionMix.d.ts +10 -0
- package/dist/methods/actionRender.d.ts +13 -0
- package/dist/methods/actionSave.d.ts +8 -0
- package/dist/methods/executeActions.d.ts +11 -0
- package/dist/methods/processCommands.d.ts +46 -0
- package/dist/methods/processPlaceholders.d.ts +27 -0
- package/dist/methods/render.d.ts +1 -1
- package/package.json +1 -1
- package/src/methods/actionData.js +30 -0
- package/src/methods/actionExtendedRender.js +28 -0
- package/src/methods/actionMix.js +66 -0
- package/src/methods/actionRender.js +86 -0
- package/src/methods/actionSave.js +9 -0
- package/src/methods/build.js +81 -444
- package/src/methods/executeActions.js +65 -0
- package/src/methods/processCommands.js +97 -0
- package/src/methods/processPlaceholders.js +155 -0
- package/src/methods/render.js +1 -1
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import actionRender from './actionRender.js'
|
|
2
|
+
import actionData from './actionData.js'
|
|
3
|
+
import actionMix from './actionMix.js'
|
|
4
|
+
import actionExtendedRender from './actionExtendedRender.js'
|
|
5
|
+
import _defineDataType from "./_defineType.js"
|
|
6
|
+
import { actionSave, actionOverwrite } from './actionSave.js'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
function executeActions({ nestedData, actSetup, helpers, original, dependencies, memory, dElement, createUseHelper }) {
|
|
11
|
+
let currentDElement = dElement;
|
|
12
|
+
|
|
13
|
+
for (let step of actSetup) {
|
|
14
|
+
let
|
|
15
|
+
{ type, name, level } = step
|
|
16
|
+
, levelData = nestedData[level] || []
|
|
17
|
+
;
|
|
18
|
+
|
|
19
|
+
// If levelData is undefined, we can't loop. But it should be [] from _defineData?
|
|
20
|
+
// nestedData[level] might be undefined?
|
|
21
|
+
// build.js said: `let levelData = nestedData[level] || []`
|
|
22
|
+
|
|
23
|
+
levelData.forEach((theData, iData) => {
|
|
24
|
+
const context = {
|
|
25
|
+
helpers
|
|
26
|
+
, original
|
|
27
|
+
, dependencies
|
|
28
|
+
, memory
|
|
29
|
+
, useHelper: createUseHelper
|
|
30
|
+
, nestedData
|
|
31
|
+
, level
|
|
32
|
+
, iData
|
|
33
|
+
, extendArguments: { dependencies, memory }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
switch (type) {
|
|
37
|
+
case 'render':
|
|
38
|
+
actionRender(step, theData, context)
|
|
39
|
+
break
|
|
40
|
+
case 'data':
|
|
41
|
+
actionData(step, theData, context)
|
|
42
|
+
break
|
|
43
|
+
case 'mix':
|
|
44
|
+
actionMix(step, theData, context)
|
|
45
|
+
break
|
|
46
|
+
case 'save':
|
|
47
|
+
actionSave(step, theData, context)
|
|
48
|
+
break
|
|
49
|
+
case 'overwrite':
|
|
50
|
+
currentDElement = actionOverwrite(step, theData)
|
|
51
|
+
break
|
|
52
|
+
case 'route':
|
|
53
|
+
// Deprecated, removed as per refactoring plan
|
|
54
|
+
break
|
|
55
|
+
case 'extendedRender':
|
|
56
|
+
actionExtendedRender(step, theData, context)
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return currentDElement
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default executeActions
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Handles debug commands for template inspection.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} d - Debug instruction
|
|
6
|
+
* @param {object} context - Context object
|
|
7
|
+
* @param {object} context.handshake - Example data
|
|
8
|
+
* @param {object} context.helpers - Helper functions
|
|
9
|
+
* @param {array} context.placeholders - Placeholder definitions
|
|
10
|
+
* @param {array} context.cuts - Chopped template parts
|
|
11
|
+
* @returns {any} Debug result or error message
|
|
12
|
+
*/
|
|
13
|
+
function handleDebug(d, { handshake, helpers, placeholders, cuts }) {
|
|
14
|
+
switch (d) {
|
|
15
|
+
case 'raw':
|
|
16
|
+
return cuts.join('')
|
|
17
|
+
case 'demo':
|
|
18
|
+
if (!handshake) return `Error: No handshake data.`
|
|
19
|
+
return handshake // Caller handles rendering handshake
|
|
20
|
+
case 'handshake':
|
|
21
|
+
if (!handshake) return `Error: No handshake data.`
|
|
22
|
+
return structuredClone(handshake)
|
|
23
|
+
case 'helpers':
|
|
24
|
+
return Object.keys(helpers).join(', ')
|
|
25
|
+
case 'placeholders':
|
|
26
|
+
return placeholders.map(h => cuts[h.index]).join(', ')
|
|
27
|
+
case 'count':
|
|
28
|
+
return placeholders.length
|
|
29
|
+
default:
|
|
30
|
+
return `Error: Wrong instruction "${d}". Available instructions: raw, demo, handshake, helpers, placeholders, count.`
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Handles the 'set' command to modify template properties.
|
|
36
|
+
*
|
|
37
|
+
* @param {object} d - Modification data
|
|
38
|
+
* @param {object} context - Context object
|
|
39
|
+
* @param {object} context.helpers - Current helper functions
|
|
40
|
+
* @param {object} context.handshake - Current handshake data
|
|
41
|
+
* @param {array} context.placeholders - Current placeholders
|
|
42
|
+
* @param {array} context.chop - Current chopped template
|
|
43
|
+
* @param {function} context.build - Build function
|
|
44
|
+
* @param {object} context.buildDependencies - Build dependencies
|
|
45
|
+
* @returns {function} Modified template function
|
|
46
|
+
*/
|
|
47
|
+
function handleSet(d, { helpers, handshake, placeholders, chop, build, buildDependencies }) {
|
|
48
|
+
if (typeof d !== 'object' || !d) return `Error: 'set' command requires an object with placeholders, helpers, handshake.`
|
|
49
|
+
|
|
50
|
+
const newHelpers = { ...helpers, ...(d.helpers || {}) }
|
|
51
|
+
const newHandshake = handshake ? { ...handshake, ...(d.handshake || {}) } : d.handshake || {}
|
|
52
|
+
const newChop = [...chop]
|
|
53
|
+
|
|
54
|
+
if (d.placeholders) {
|
|
55
|
+
Object.entries(d.placeholders).forEach(([k, v]) => {
|
|
56
|
+
if (!isNaN(k)) {
|
|
57
|
+
let index = placeholders[k].index;
|
|
58
|
+
newChop[index] = v
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
let plx = placeholders.find(p => p.name === k)
|
|
62
|
+
newChop[plx.index] = v
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const newTemplateStr = newChop.join('');
|
|
68
|
+
const newTpl = {
|
|
69
|
+
template: newTemplateStr,
|
|
70
|
+
helpers: newHelpers,
|
|
71
|
+
handshake: newHandshake
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const result = build(newTpl, false, buildDependencies)
|
|
75
|
+
return typeof result === 'function' ? result : () => result
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handles snippets command to select specific placeholders.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} command - Snippets command
|
|
82
|
+
* @param {object} snippets - Snippets mapping
|
|
83
|
+
* @returns {array|null} Selected placeholders or null
|
|
84
|
+
*/
|
|
85
|
+
function handleSnippets(command, snippets) {
|
|
86
|
+
if (command.includes(':')) {
|
|
87
|
+
let snippetNames = command.split(':')
|
|
88
|
+
.slice(1)[0]
|
|
89
|
+
.trim()
|
|
90
|
+
.split(',')
|
|
91
|
+
.map(t => t.trim())
|
|
92
|
+
return snippetNames.map(item => snippets[item])
|
|
93
|
+
}
|
|
94
|
+
return null // Indicates 'all snippets' or logic handled by caller
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { handleDebug, handleSet, handleSnippets }
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import _defineData from "./_defineData.js"
|
|
2
|
+
import _defineDataType from "./_defineType.js"
|
|
3
|
+
import _actionSupply from "./_actionSupply.js"
|
|
4
|
+
import _setupActions from "./_setupActions.js"
|
|
5
|
+
import executeActions from "./executeActions.js"
|
|
6
|
+
import render from "./render.js"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Processes placeholders in the template with provided data and context.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} params - Parameters object
|
|
12
|
+
* @param {array} params.d - Data array to process
|
|
13
|
+
* @param {array} params.chop - Chopped template parts
|
|
14
|
+
* @param {array} params.placeholders - Placeholder definitions
|
|
15
|
+
* @param {any} params.original - Original data context
|
|
16
|
+
* @param {object} params.helpers - Helper functions
|
|
17
|
+
* @param {object} params.dependencies - Injected dependencies
|
|
18
|
+
* @param {object} params.memory - Internal memory state
|
|
19
|
+
* @param {array} params.args - Additional arguments
|
|
20
|
+
* @param {boolean} params.onlySnippets - Whether to process only snippets
|
|
21
|
+
* @returns {array} Processed template parts
|
|
22
|
+
*/
|
|
23
|
+
function processPlaceholders ({ d, chop, placeholders, original, helpers, dependencies, memory, args, onlySnippets }) {
|
|
24
|
+
const endData = []
|
|
25
|
+
// We need a factory for useHelper.
|
|
26
|
+
// It depends on 'currentData'. But here we are iterating 'd'.
|
|
27
|
+
|
|
28
|
+
// Helper factory to share with executeActions
|
|
29
|
+
const createUseHelperFactory = (currentData) => (targetName, targetData) => {
|
|
30
|
+
let
|
|
31
|
+
targetFn = helpers[targetName]
|
|
32
|
+
, isCompiledTemplate = targetFn && typeof targetFn === 'function' && targetFn.length >= 2
|
|
33
|
+
;
|
|
34
|
+
if (!targetFn) return `( Error: Helper '${targetName}' is not available )`
|
|
35
|
+
|
|
36
|
+
if (isCompiledTemplate) {
|
|
37
|
+
try {
|
|
38
|
+
return targetFn('render', targetData || currentData, dependencies)
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
return render(targetData || currentData, targetName, helpers, original, dependencies, ...args)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return render(targetData || currentData, targetName, helpers, original, dependencies, ...args)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
d.forEach(dElement => {
|
|
49
|
+
let
|
|
50
|
+
cuts = structuredClone(chop)
|
|
51
|
+
, currentDElement = dElement // Can be updated by overwrite
|
|
52
|
+
;
|
|
53
|
+
|
|
54
|
+
placeholders.forEach(holder => {
|
|
55
|
+
const
|
|
56
|
+
{ index, data, action } = holder
|
|
57
|
+
, dataOnly = !action
|
|
58
|
+
, mem = structuredClone(memory)
|
|
59
|
+
;
|
|
60
|
+
let info = currentDElement;
|
|
61
|
+
|
|
62
|
+
// Data Resolution
|
|
63
|
+
if (data && data.includes('/')) {
|
|
64
|
+
if (info.hasOwnProperty(data)) {
|
|
65
|
+
info = info[data]
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
data.split('/').forEach(d => {
|
|
69
|
+
if (info.hasOwnProperty(d)) info = info[d]
|
|
70
|
+
else info = [] // Bug in original? info = [] then info['next'] crashes?
|
|
71
|
+
// Original: else info = []. 256.
|
|
72
|
+
// If info is [], next iteration info['key'] is undefined.
|
|
73
|
+
// So safe.
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (data === '@all' || data === null || data === '@root') info = currentDElement
|
|
78
|
+
else if (data) info = info[data]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
if (dataOnly) {
|
|
82
|
+
const type = _defineDataType(info);
|
|
83
|
+
switch (type) {
|
|
84
|
+
case 'function':
|
|
85
|
+
cuts[index] = info()
|
|
86
|
+
break
|
|
87
|
+
case 'primitive':
|
|
88
|
+
cuts[index] = info
|
|
89
|
+
break
|
|
90
|
+
case 'array':
|
|
91
|
+
if (_defineDataType(info[0]) === 'primitive') cuts[index] = info[0]
|
|
92
|
+
break
|
|
93
|
+
case 'object':
|
|
94
|
+
if (info.text) cuts[index] = info.text
|
|
95
|
+
break
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Logic for data processing via actions
|
|
100
|
+
let
|
|
101
|
+
{ dataDeepLevel, nestedData } = _defineData(info, action)
|
|
102
|
+
, actSetup = _actionSupply(_setupActions(action, dataDeepLevel), dataDeepLevel)
|
|
103
|
+
;
|
|
104
|
+
|
|
105
|
+
const createUseHelper = createUseHelperFactory(info); // use info as context?
|
|
106
|
+
// In build.js it was `d` (the item from levelData).
|
|
107
|
+
// `executeActions` passes `theData` to `createUseHelper`.
|
|
108
|
+
|
|
109
|
+
currentDElement = executeActions({
|
|
110
|
+
nestedData
|
|
111
|
+
, actSetup
|
|
112
|
+
, helpers
|
|
113
|
+
, original
|
|
114
|
+
, dependencies
|
|
115
|
+
, memory
|
|
116
|
+
, dElement: currentDElement
|
|
117
|
+
, createUseHelper: createUseHelperFactory
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Flatten Step
|
|
121
|
+
if (nestedData instanceof Array && nestedData.length === 1 && nestedData[0] instanceof Array) nestedData = nestedData[0]
|
|
122
|
+
if (nestedData[0] == null) return
|
|
123
|
+
|
|
124
|
+
let
|
|
125
|
+
accType = _defineDataType(nestedData[0])
|
|
126
|
+
, fineData = nestedData[0]
|
|
127
|
+
;
|
|
128
|
+
|
|
129
|
+
switch (accType) {
|
|
130
|
+
case 'primitive':
|
|
131
|
+
if (fineData == null) return
|
|
132
|
+
cuts[index] = fineData
|
|
133
|
+
break
|
|
134
|
+
case 'object':
|
|
135
|
+
if (fineData['text'] == null) return
|
|
136
|
+
cuts[index] = fineData['text']
|
|
137
|
+
break
|
|
138
|
+
case 'array':
|
|
139
|
+
const aType = _defineDataType(fineData[0])
|
|
140
|
+
if (aType === 'object') cuts[index] = fineData.map(x => x.text).join('')
|
|
141
|
+
else cuts[index] = fineData.join('')
|
|
142
|
+
break
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}) // placeholders loop
|
|
146
|
+
|
|
147
|
+
if (onlySnippets) endData.push(placeholders.map(x => cuts[x.index]).join('<~>'))
|
|
148
|
+
else endData.push(cuts.join(''))
|
|
149
|
+
|
|
150
|
+
}) // d.forEach
|
|
151
|
+
|
|
152
|
+
return endData
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default processPlaceholders
|
package/src/methods/render.js
CHANGED
|
@@ -13,7 +13,7 @@ import _renderHolder from './_renderHolder.js'
|
|
|
13
13
|
* @param {object} dependencies - injected dependencies.
|
|
14
14
|
* @param {...any} args - Additional arguments.
|
|
15
15
|
*
|
|
16
|
-
* @returns {any} The result of the rendering process.
|
|
16
|
+
* @returns {any} The result of the rendering process, or an error string if the helper is not available.
|
|
17
17
|
*/
|
|
18
18
|
function render ( theData, name, helpers, original, dependencies, ...args) {
|
|
19
19
|
const useHelper = ( targetName, targetData ) => render ( targetData || theData, targetName, helpers, original, dependencies, ...args )
|