@peter.naydenov/morph 3.3.2 → 3.3.3
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/.claude/scheduled_tasks.lock +1 -0
- package/.claude/settings.local.json +14 -0
- package/.graphify_cached.json +1 -0
- package/.graphify_semantic_new.json +1 -0
- package/.graphify_uncached.txt +14 -0
- package/.opencode/package-lock.json +115 -0
- package/.opencode/plugins/graphify.js +22 -0
- package/AGENTS.md +8 -0
- package/Changelog.md +10 -0
- package/graphify-out/.graphify_python +1 -0
- package/graphify-out/GRAPH_REPORT.md +147 -0
- package/graphify-out/cache/12d38a6879ec5b7a18b61b92920684a5e915c2255c41e2c56168c678dba94023.json +1 -0
- package/graphify-out/cache/1ba574be094f9bd868bbce1091b9988d6188ae071762a73d483516498b742434.json +1 -0
- package/graphify-out/cache/2dfd19c49f88b8af0c95f7692ae9453b54cf898dba6c24cad9cbd555b365f5e7.json +1 -0
- package/graphify-out/cache/343264caa0702ae2210efeb2d673fb69b59bd01403803c84f9da0ce21d93c6fe.json +1 -0
- package/graphify-out/cache/38f82a17b2933bf14206263846c7396b46ac0db01af525300ac20f2f3f2b0534.json +1 -0
- package/graphify-out/cache/3a8b3ccf38f1d380228dda52c3c595ec76b5827b6905ef7e2bef6e265ee4ac16.json +1 -0
- package/graphify-out/cache/3b3e764a57e1d2ce17e5a74bea1c7ee493260e27266c114a72688d441f712e52.json +1 -0
- package/graphify-out/cache/42bc18f8ec31b043b4c4ecc11c79c288afe0801207d60a7cc322d11ab4579864.json +1 -0
- package/graphify-out/cache/4e3d45485b073109c7d91f18dac64ffbf0cbc21ae0edac016cb7b5f061954af6.json +1 -0
- package/graphify-out/cache/4ed08a09c3f090fe62cd56647a5251d60cf2f095156e502244a4f732929e342c.json +1 -0
- package/graphify-out/cache/51c174d3534ae05ed6dcbdb7f0d16da0b22f05677ef2863920e0a541b06090dd.json +1 -0
- package/graphify-out/cache/51d65b15aad6e35883d6ccaa0688273d7e14d8b7b85b194c50c365e5ea6710c6.json +1 -0
- package/graphify-out/cache/5d96cf59b7e5e3ea65c2ddcc6267178ea8916e104ff3f82a5a4d90179f762d11.json +1 -0
- package/graphify-out/cache/63fa82962f6899c2c099e95b595c5106f5dd53b2dc65037b89d6c6578033c03c.json +1 -0
- package/graphify-out/cache/6878c29d96e13e9fee1e01e4ca4e77d28b1e8e6c4f1d05dbffdca58625ef5694.json +1 -0
- package/graphify-out/cache/6c7082448b871f8cce9c6e26f788252a3b0c7e88ce40b4d3652ca9b78a2df049.json +1 -0
- package/graphify-out/cache/7cb42a4ad6e7c2f8b66560c9c40053e479cc1cffdf074d6b00bc23e607535376.json +1 -0
- package/graphify-out/cache/8712e549b4b42d5dc14c3e4b56f384c9d8e37116dc61ad906a05e10a1445ff40.json +1 -0
- package/graphify-out/cache/8b1ea63dfe0d47683be14dd72078eb83cf5b182d497237adbcd50ebdc1fee1bc.json +1 -0
- package/graphify-out/cache/8cd02cb84a50696666d33fee84a4a7e75fce651780ba7a4474bfe9b4a2b79c46.json +1 -0
- package/graphify-out/cache/8d0520a089ffaa71927ddddad5cb4d8f796a9febf0b8c4d54f78453b955520c5.json +1 -0
- package/graphify-out/cache/9406e0a23a011eaa9d74fe717280e5be52142ba4db8b7baee948dcdea6fe2617.json +1 -0
- package/graphify-out/cache/98abf9b9fbeb7f5fdaef6b853c949d297586b99e2965330906234f2ae331c0af.json +1 -0
- package/graphify-out/cache/9decf23c89efbaa42811f95c737234abee72478582ce4a46d99ba12d7446bb7b.json +1 -0
- package/graphify-out/cache/a37bc5340c5f31d2ef717845d339f468853e6554f753466ba2d995147d25fedf.json +1 -0
- package/graphify-out/cache/a77d81d5705a824ba81dc3556452ecc99978bc335e65e961aee29ce01e7cf81c.json +1 -0
- package/graphify-out/cache/ast/v0.8.39/21cd1a6bc5dbd687522c86e9f7db1842400b31ee3ba62127533aba56a478da5d.json +1 -0
- package/graphify-out/cache/ast/v0.8.39/29c3826c5e1938406f9eaf50a1354609aeb16e8f0d27e5a454c069c982f21180.json +1 -0
- package/graphify-out/cache/ast/v0.8.39/c31ea4d76660d1000df3bd29929d120e900297c7a1c26e5266312c21a9432e55.json +1 -0
- package/graphify-out/cache/ast/v0.8.39/de54c2617a64a2a1c1db34e6494216dd949fe730b51270bebba55c63d54a31e9.json +1 -0
- package/graphify-out/cache/b83cba0b46f18ae8fc4d50b540eaa276c28745ea4639863c082cb41681220b9d.json +1 -0
- package/graphify-out/cache/bd607a8d62efb3cceb791e36c2495c5ceee38e913c2386d293cca88566f4c0aa.json +1 -0
- package/graphify-out/cache/beb2827f4b8ad2aaacd809c8d783eb1f5f3c3c997ce6941d1cc9b2f0df7a0d6e.json +1 -0
- package/graphify-out/cache/ca721e7772d7906c5fecc00d69aa50bdc5e73ba087807089f3ca26509e014889.json +1 -0
- package/graphify-out/cache/cb49f9ceae6e04f66081b0c73c0574bddaf01240ea0c7efc1880616b94b4c0d8.json +1 -0
- package/graphify-out/cache/ce9874dce6f3f855a53dd706b4b83a503dc4ba72f7f36b6d73ec2cc8354f3cdf.json +1 -0
- package/graphify-out/cache/d3e24fc669e3f2a2c5e9e864a97ca447f0dcc1c5aad33c88a2280ac97188e888.json +1 -0
- package/graphify-out/cache/d6c072004e2ea18f9a5380aa75980cd08b15e7d6d893d396a5baac37dfc24310.json +1 -0
- package/graphify-out/cache/d99f1759a41541d9ef41aefdf89a2dbcab7272ccc91a9794062224124222e333.json +1 -0
- package/graphify-out/cache/dbb69ddd98951e0d5e51b2e1a2cf97a8febb147e55b81b43b05b680844bf4a1f.json +1 -0
- package/graphify-out/cache/df270b9b613de7bbefce4cabc6b3dd6e66ebecdbf6f0cefde05bb676569ee1c3.json +1 -0
- package/graphify-out/cache/e56607f0791079dbd05e56cdac41f88124785d367f9da0eb436952406cb317da.json +1 -0
- package/graphify-out/cache/ecdfee4e64acdd666f25596341a8ff4a41d7ee1e637de40685ff33c1efa814c7.json +1 -0
- package/graphify-out/cache/f0f3005c7ec68d16fcde259d6bc996520841d021ce2531cbb7f3de343996c4ea.json +1 -0
- package/graphify-out/cache/f2bfcd400f076a7e8a9e54b821d555c90b93ef4dd8d3652f78ec35acad5e0615.json +1 -0
- package/graphify-out/cache/semantic/043be2e32281a59e2bacb95418b95816b558a290aa581434b22666fb9a6a3a6c.json +1 -0
- package/graphify-out/cache/semantic/13439df0f4f40e2c190340576c1a46c2cc82b9fc789f262c78d7129cc56ef13c.json +1 -0
- package/graphify-out/cache/semantic/136052be0f52f9258076b87da6bde0ea62763a63684cc6729f759910448ae675.json +1 -0
- package/graphify-out/cache/semantic/15cbc6ab30bfa8cf7bb9b5646a2598aa78531047ef5096d5d8ab08edbcf8ee7d.json +1 -0
- package/graphify-out/cache/semantic/21cd1a6bc5dbd687522c86e9f7db1842400b31ee3ba62127533aba56a478da5d.json +1 -0
- package/graphify-out/cache/semantic/22bd0d40f23b81ba30a703fc290cc518f18d3148f5553ffc79f4bf8a0a71722c.json +1 -0
- package/graphify-out/cache/semantic/29c3826c5e1938406f9eaf50a1354609aeb16e8f0d27e5a454c069c982f21180.json +1 -0
- package/graphify-out/cache/semantic/2e913a06516b6bff22019b157680d17617db82a9ed2277ce1e20eac945939a7e.json +1 -0
- package/graphify-out/cache/semantic/30db4df562575c6116ad9e8843f19c557ab6fc25288c7aed8926641748b21fd6.json +1 -0
- package/graphify-out/cache/semantic/325abe6948add2e47c2271195503ab21f897e27f2cc9af292f39408b94a2f51c.json +1 -0
- package/graphify-out/cache/semantic/3579f6cf2c93aa83eb9396e389c195f17e4cff527d43718e61503e5c0f223f84.json +1 -0
- package/graphify-out/cache/semantic/36cda2fb14ba2ee3b8bc721a278f4963bf001c72258dd707b4b141334be01c15.json +1 -0
- package/graphify-out/cache/semantic/403b6596e3414f78206fc02adf9b62f07af237be191e0f4b26706041bf1e0ee1.json +1 -0
- package/graphify-out/cache/semantic/40f4144bc24d137a1afdcac95143c2bc3e26c0086d150c73df85fdf236bebe01.json +1 -0
- package/graphify-out/cache/semantic/45d85f3ac35b83d9a076c6e25c220324a0c92d0e955ba85e04b20ef09ddad9fd.json +1 -0
- package/graphify-out/cache/semantic/468d9e0c3d92cce2723852d2f29033326433cdc368203092b8470f2f356e3cec.json +1 -0
- package/graphify-out/cache/semantic/5983c77253844a325cb78f45828115ede5a688908bd38fa1b32ca78ab319deb9.json +1 -0
- package/graphify-out/cache/semantic/59ef3e18c32f0f877d8854ecb5e9f8714c608d5d90ca7adc71f2859fe496f66f.json +1 -0
- package/graphify-out/cache/semantic/71dd26effab66822e1d20111accfa0cc434826661da83b1b86a6fc3119980a66.json +1 -0
- package/graphify-out/cache/semantic/78bc10fe7d8d145c2c12af97dd75ea16f6787f1f15f0af0b145ac315ce63dcb6.json +1 -0
- package/graphify-out/cache/semantic/7c92d89867073cc9e54a821be558de7322fa42f342cf4c52da9bf02c29f43b1d.json +1 -0
- package/graphify-out/cache/semantic/82c3b90b2523c47b43a3212e2d30ed8d06c0027697f89fe177d062baf4d4202f.json +1 -0
- package/graphify-out/cache/semantic/8917cb163ec1afce8e5d659680749a553be3aa6aef54ebc757dd1b7c81d707c6.json +1 -0
- package/graphify-out/cache/semantic/8da5742abeaeadae80c4f57a4e98432a4bfc789eadb5082d3919780d646546f6.json +1 -0
- package/graphify-out/cache/semantic/97f4eb2208c6b1e81c84600ab52507478f5e682e63e5546a92c97b4c3d9371eb.json +1 -0
- package/graphify-out/cache/semantic/9c01c0ac53d626004b3d72953063c71f251710e7f23a8765c149159b0f422ecc.json +1 -0
- package/graphify-out/cache/semantic/9d0bbf5bdbb2aa4e3507d2e118464ce70d165916e29cae54b5ead974bfc1bd04.json +1 -0
- package/graphify-out/cache/semantic/9e59357a8097ad32258c2cb47c066508049e7f8c21fa55a1a5f5a4b0eee41275.json +1 -0
- package/graphify-out/cache/semantic/aaaff53eae109640d8e48c4585390fa7a2c2ca04088d314e578c316ca95f53e0.json +1 -0
- package/graphify-out/cache/semantic/b18464395b8719578b14148fd37880916c62b10f78942c862da386815c05b628.json +1 -0
- package/graphify-out/cache/semantic/c31ea4d76660d1000df3bd29929d120e900297c7a1c26e5266312c21a9432e55.json +1 -0
- package/graphify-out/cache/semantic/c74b855b4778be378db8fa05e33582c33cb563d8698ba6dae566e1cd37d0fb09.json +1 -0
- package/graphify-out/cache/semantic/cc8bf09a84e6fcc420e2438b3d6403560128b0edbd907761350fa58536d844ff.json +1 -0
- package/graphify-out/cache/semantic/d39f7cd9481b6f19c88e62ff5f7a3bddbf3a3593b2b1257a5092b44374c70874.json +1 -0
- package/graphify-out/cache/semantic/d5472c5e2c6560c9de5c17a444e2060eb9ccaa5dc7f4f3fe0dc3a5f68625bb91.json +1 -0
- package/graphify-out/cache/semantic/de54c2617a64a2a1c1db34e6494216dd949fe730b51270bebba55c63d54a31e9.json +1 -0
- package/graphify-out/cache/semantic/e29c1a9e35ffd56ab3b1e2f4800b48e9a6880bddecfc028dfdaf14498f52d8b4.json +1 -0
- package/graphify-out/cache/semantic/e39668e1347ee1000e7fba8b922c76488e34c35f2088b8334806e0256cfd71a7.json +1 -0
- package/graphify-out/cache/semantic/e9eea1131268a154e037e558c1856fbb2941e129b405659416b4e69746759440.json +1 -0
- package/graphify-out/cache/semantic/f3863c3e1c42f444b735cf4042b01a07b4e2f0bff82580bfab9bad1a784b8f4d.json +1 -0
- package/graphify-out/cache/semantic/f6dde571c1b88858dbf6da9b447dba7e66d9cb211c0130abcbb0768efed52e7b.json +1 -0
- package/graphify-out/cache/semantic/fa84dbd8fb64d52d0d43ea31da6cff178668e3eba7efb6e96ff605f3838a2bea.json +1 -0
- package/graphify-out/cache/stat-index.json +1 -0
- package/graphify-out/cost.json +18 -0
- package/graphify-out/graph.html +307 -0
- package/graphify-out/graph.json +6531 -0
- package/graphify-out/manifest.json +467 -0
- package/opencode.json +6 -0
- package/package.json +14 -6
- package/src/main.js +3 -7
- package/src/methods/_chopTemplates.js +56 -63
- package/src/methods/_setupActions.js +7 -14
- package/src/methods/actionData.js +35 -21
- package/src/methods/actionExtendedRender.js +21 -22
- package/src/methods/actionMix.js +47 -49
- package/src/methods/actionRender.js +43 -75
- package/src/methods/build.js +75 -97
- package/src/methods/executeActions.js +63 -49
- package/src/methods/processCommands.js +6 -10
- package/src/methods/processPlaceholders.js +105 -123
- package/src/methods/render.js +11 -13
package/src/methods/build.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import _chopTemplate from "./_chopTemplates.js"
|
|
2
1
|
import _readTemplate from "./_readTemplate.js"
|
|
3
2
|
import _defineDataType from "./_defineType.js"
|
|
4
3
|
import walk from '@peter.naydenov/walk'
|
|
5
4
|
import processPlaceholders from './processPlaceholders.js'
|
|
6
|
-
import {
|
|
5
|
+
import {
|
|
7
6
|
handleDebug
|
|
8
7
|
, handleSet
|
|
9
8
|
, handleSnippets } from './processCommands.js'
|
|
@@ -30,7 +29,7 @@ import {
|
|
|
30
29
|
/**
|
|
31
30
|
* @typedef {Object} Template
|
|
32
31
|
* @property {string} template - Data to be rendered;
|
|
33
|
-
* @property {Object.<string, HelperFn|string>} [helpers] - Optional. Object with helper functions or simple templates for this template;
|
|
32
|
+
* @property {Object.<string, HelperFn|string>} [helpers] - Optional. Object with helper functions or simple templates for this template;
|
|
34
33
|
* @property {object} [handshake] - Optional. Example for data to be rendered with;
|
|
35
34
|
*/
|
|
36
35
|
|
|
@@ -42,110 +41,89 @@ import {
|
|
|
42
41
|
|
|
43
42
|
|
|
44
43
|
|
|
44
|
+
const COMMANDS = [ 'render', 'debug', 'snippets', 'set', 'curry' ]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
45
48
|
/**
|
|
46
|
-
*
|
|
49
|
+
*
|
|
47
50
|
* @param {Template} tpl - template definition;
|
|
48
51
|
* @param {boolean} [extra] - Optional. How to receive the answer - false:as a string(answer) or true: as tuple[success, answer];
|
|
49
52
|
* @param {object} [buildDependencies] - Optional. External dependencies injected;
|
|
50
53
|
* @returns {function|tupleResult} - rendering function
|
|
51
54
|
*/
|
|
52
55
|
function build ( tpl, extra = false, buildDependencies = {}) {
|
|
53
|
-
|
|
56
|
+
const { hasError, placeholders, chop, helpers, handshake, snippets } = _readTemplate ( tpl );
|
|
54
57
|
|
|
55
58
|
if ( hasError ) {
|
|
56
|
-
|
|
57
|
-
return extra ? [false, fail] : fail
|
|
59
|
+
const fail = () => hasError
|
|
60
|
+
return extra ? [ false, fail ] : fail
|
|
58
61
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
d
|
|
125
|
-
, chop
|
|
126
|
-
, placeholders
|
|
127
|
-
, original
|
|
128
|
-
, helpers
|
|
129
|
-
, dependencies: deps
|
|
130
|
-
, memory
|
|
131
|
-
, args
|
|
132
|
-
, onlySnippets
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if ( topLevelType === 'array' ) return endData
|
|
137
|
-
|
|
138
|
-
// Post-process
|
|
139
|
-
if (args) {
|
|
140
|
-
return args.reduce ( ( acc, fn ) => {
|
|
141
|
-
if (typeof fn !== 'function') return acc
|
|
142
|
-
return fn ( acc, deps )
|
|
143
|
-
}, endData.join(''))
|
|
144
|
-
}
|
|
145
|
-
else return endData.join ( '' )
|
|
146
|
-
} // success func.
|
|
147
|
-
return extra ? [true, success] : success
|
|
148
|
-
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Rendering function. First argument selects a command,
|
|
65
|
+
* the rest of the arguments depend on the command:
|
|
66
|
+
* - 'render' : ( 'render', data, dependencies, ...postprocessFn ) -> string
|
|
67
|
+
* - 'debug' : ( 'debug', instruction ) -> template internals
|
|
68
|
+
* - 'snippets' : ( 'snippets[: names]', data ) -> selected placeholders joined with '<~>'
|
|
69
|
+
* - 'set' : ( 'set', { placeholders, helpers, handshake }) -> new rendering function
|
|
70
|
+
* - 'curry' : ( 'curry', partialData ) -> new rendering function
|
|
71
|
+
*/
|
|
72
|
+
function success ( command = 'render', d = {}, dependencies = {}, ...args ) {
|
|
73
|
+
|
|
74
|
+
const knownCommand = ( typeof command === 'string' ) && ( COMMANDS.includes ( command ) || command.startsWith ( 'snippets' ))
|
|
75
|
+
if ( !knownCommand ) return `Error: Wrong command "${command}". Available commands: ${COMMANDS.join ( ', ' )}.`
|
|
76
|
+
|
|
77
|
+
// Commands 'set' and 'curry' do not render. They produce a new rendering function.
|
|
78
|
+
if ( command === 'set' ) return handleSet ( d, { helpers, handshake, placeholders, chop, build, buildDependencies })
|
|
79
|
+
if ( command === 'curry' ) {
|
|
80
|
+
const rendered = success ( 'render', d, dependencies, ...args )
|
|
81
|
+
return build ({ template: rendered, helpers, handshake }, false, buildDependencies )
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Command 'snippets' renders only the selected placeholders. 'snippets: a, b' selects, plain 'snippets' takes all.
|
|
85
|
+
const
|
|
86
|
+
onlySnippets = command.startsWith ( 'snippets' )
|
|
87
|
+
, activePlaceholders = onlySnippets ? ( handleSnippets ( command, snippets ) || placeholders ) : placeholders
|
|
88
|
+
;
|
|
89
|
+
|
|
90
|
+
// A string instead of data is a debug instruction. Instruction 'demo' continues by rendering the handshake data.
|
|
91
|
+
if ( typeof d === 'string' ) {
|
|
92
|
+
const result = handleDebug ( d, { handshake, helpers, placeholders : activePlaceholders, cuts : chop })
|
|
93
|
+
const renderTheDemo = ( d === 'demo' ) && ( typeof result === 'object' )
|
|
94
|
+
if ( !renderTheDemo ) return result
|
|
95
|
+
d = result
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Rendering
|
|
99
|
+
const dataType = _defineDataType ( d )
|
|
100
|
+
if ( dataType === 'null' ) return chop.join ( '' )
|
|
101
|
+
|
|
102
|
+
const
|
|
103
|
+
deps = { ...buildDependencies, ...dependencies }
|
|
104
|
+
, data = walk ({ data: d }) // Deep copy. Rendering should never touch caller's data.
|
|
105
|
+
, original = walk ({ data })
|
|
106
|
+
, levelData = ( dataType === 'array' ) ? data : [ data ]
|
|
107
|
+
;
|
|
108
|
+
|
|
109
|
+
const endData = processPlaceholders ({
|
|
110
|
+
d : levelData
|
|
111
|
+
, chop
|
|
112
|
+
, placeholders : activePlaceholders
|
|
113
|
+
, original
|
|
114
|
+
, helpers
|
|
115
|
+
, dependencies : deps
|
|
116
|
+
, memory : {}
|
|
117
|
+
, args
|
|
118
|
+
, onlySnippets
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if ( dataType === 'array' ) return endData
|
|
122
|
+
// Extra arguments are post-processing functions: ( result, dependencies ) -> result
|
|
123
|
+
return args.reduce (( acc, fn ) => ( typeof fn === 'function' ) ? fn ( acc, deps ) : acc, endData.join ( '' ))
|
|
124
|
+
} // success func.
|
|
125
|
+
|
|
126
|
+
return extra ? [ true, success ] : success
|
|
149
127
|
} // build func.
|
|
150
128
|
|
|
151
129
|
|
|
@@ -2,64 +2,78 @@ import actionRender from './actionRender.js'
|
|
|
2
2
|
import actionData from './actionData.js'
|
|
3
3
|
import actionMix from './actionMix.js'
|
|
4
4
|
import actionExtendedRender from './actionExtendedRender.js'
|
|
5
|
-
import _defineDataType from "./_defineType.js"
|
|
6
5
|
import { actionSave, actionOverwrite } from './actionSave.js'
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Executes the action chain of a placeholder over the prepared nested data.
|
|
11
|
+
*
|
|
12
|
+
* Actions arrive from the action supplier level by level. Each action type has a
|
|
13
|
+
* dedicated handler that writes its result into `nestedData`. Only 'overwrite'
|
|
14
|
+
* replaces the current data element and hands it back to the caller.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} params - Parameters object
|
|
17
|
+
* @param {array} params.nestedData - Data slices organized by depth level
|
|
18
|
+
* @param {Generator} params.actSetup - Action supplier (see _actionSupply.js)
|
|
19
|
+
* @param {object} params.helpers - Helper functions
|
|
20
|
+
* @param {any} params.original - Original data context
|
|
21
|
+
* @param {object} params.dependencies - Injected dependencies
|
|
22
|
+
* @param {object} params.memory - Internal memory state ('save' action writes here)
|
|
23
|
+
* @param {any} params.dElement - Current top-level data element
|
|
24
|
+
* @param {function} params.createUseHelper - Factory for useHelper functions
|
|
25
|
+
* @returns {any} The (possibly overwritten) data element
|
|
26
|
+
*/
|
|
27
|
+
function executeActions ({ nestedData, actSetup, helpers, original, dependencies, memory, dElement, createUseHelper }) {
|
|
11
28
|
let currentDElement = dElement;
|
|
12
29
|
|
|
13
|
-
for (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
for ( const step of actSetup ) {
|
|
31
|
+
const
|
|
32
|
+
{ type, level } = step
|
|
33
|
+
, levelData = nestedData[level] || []
|
|
34
|
+
;
|
|
18
35
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
levelData.forEach ( ( theData, iData ) => {
|
|
37
|
+
const context = {
|
|
38
|
+
helpers
|
|
39
|
+
, original
|
|
40
|
+
, dependencies
|
|
41
|
+
, memory
|
|
42
|
+
, useHelper : createUseHelper
|
|
43
|
+
, nestedData
|
|
44
|
+
, level
|
|
45
|
+
, iData
|
|
46
|
+
, extendArguments : { dependencies, memory }
|
|
47
|
+
}
|
|
22
48
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
}
|
|
49
|
+
switch ( type ) {
|
|
50
|
+
case 'render':
|
|
51
|
+
actionRender ( step, theData, context )
|
|
52
|
+
break
|
|
53
|
+
case 'data':
|
|
54
|
+
actionData ( step, theData, context )
|
|
55
|
+
break
|
|
56
|
+
case 'mix':
|
|
57
|
+
actionMix ( step, theData, context )
|
|
58
|
+
break
|
|
59
|
+
case 'save':
|
|
60
|
+
actionSave ( step, theData, context )
|
|
61
|
+
break
|
|
62
|
+
case 'overwrite':
|
|
63
|
+
currentDElement = actionOverwrite ( step, theData )
|
|
64
|
+
break
|
|
65
|
+
case 'extendedRender':
|
|
66
|
+
actionExtendedRender ( step, theData, context )
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
}) // forEach levelData
|
|
70
|
+
} // for actSetup
|
|
61
71
|
|
|
62
72
|
return currentDElement
|
|
63
|
-
}
|
|
73
|
+
} // executeActions func.
|
|
74
|
+
|
|
75
|
+
|
|
64
76
|
|
|
65
77
|
export default executeActions
|
|
78
|
+
|
|
79
|
+
|
|
@@ -52,16 +52,12 @@ function handleSet(d, { helpers, handshake, placeholders, chop, build, buildDepe
|
|
|
52
52
|
const newChop = [...chop]
|
|
53
53
|
|
|
54
54
|
if (d.placeholders) {
|
|
55
|
-
Object.entries(d.placeholders)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let plx = placeholders.find(p => p.name === k)
|
|
62
|
-
newChop[plx.index] = v
|
|
63
|
-
}
|
|
64
|
-
})
|
|
55
|
+
for (const [k, v] of Object.entries(d.placeholders)) {
|
|
56
|
+
// Placeholders are addressed by position ('0', '1', ...) or by name
|
|
57
|
+
const holder = !isNaN(k) ? placeholders[k] : placeholders.find(p => p.name === k)
|
|
58
|
+
if (!holder) return `Error: Placeholder "${k}" does not exist in the template.`
|
|
59
|
+
newChop[holder.index] = v
|
|
60
|
+
}
|
|
65
61
|
}
|
|
66
62
|
|
|
67
63
|
const newTemplateStr = newChop.join('');
|
|
@@ -17,139 +17,121 @@ import render from "./render.js"
|
|
|
17
17
|
* @param {object} params.dependencies - Injected dependencies
|
|
18
18
|
* @param {object} params.memory - Internal memory state
|
|
19
19
|
* @param {array} params.args - Additional arguments
|
|
20
|
-
* @param {boolean} params.onlySnippets - Whether to
|
|
21
|
-
* @returns {array}
|
|
20
|
+
* @param {boolean} params.onlySnippets - Whether to render only the selected placeholders
|
|
21
|
+
* @returns {array} Rendered result - one string per data element
|
|
22
22
|
*/
|
|
23
23
|
function processPlaceholders ({ d, chop, placeholders, original, helpers, dependencies, memory, args, onlySnippets }) {
|
|
24
24
|
const endData = []
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
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 => {
|
|
25
|
+
|
|
26
|
+
// useHelper factory, shared with executeActions. 'currentData' is the fallback
|
|
27
|
+
// when the helper calls useHelper without its own data.
|
|
28
|
+
const createUseHelperFactory = ( currentData ) => ( targetName, targetData ) => {
|
|
55
29
|
const
|
|
56
|
-
|
|
57
|
-
,
|
|
58
|
-
, mem = structuredClone(memory)
|
|
30
|
+
targetFn = helpers[targetName]
|
|
31
|
+
, isCompiledTemplate = targetFn && typeof targetFn === 'function' && targetFn.length >= 2
|
|
59
32
|
;
|
|
60
|
-
|
|
33
|
+
if ( !targetFn ) return `( Error: Helper '${targetName}' is not available )`
|
|
61
34
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
|
35
|
+
if ( isCompiledTemplate ) {
|
|
36
|
+
try { return targetFn ( 'render', targetData || currentData, dependencies ) }
|
|
37
|
+
catch ( e ) { return render ( targetData || currentData, targetName, helpers, original, dependencies, ...args ) }
|
|
96
38
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
39
|
+
return render ( targetData || currentData, targetName, helpers, original, dependencies, ...args )
|
|
40
|
+
} // createUseHelperFactory func.
|
|
41
|
+
|
|
146
42
|
|
|
147
|
-
|
|
148
|
-
|
|
43
|
+
d.forEach ( dElement => {
|
|
44
|
+
let
|
|
45
|
+
cuts = structuredClone ( chop )
|
|
46
|
+
, currentDElement = dElement // 'overwrite' action can replace it
|
|
47
|
+
;
|
|
149
48
|
|
|
150
|
-
|
|
49
|
+
placeholders.forEach ( holder => {
|
|
50
|
+
const
|
|
51
|
+
{ index, data, action } = holder
|
|
52
|
+
, dataOnly = !action
|
|
53
|
+
;
|
|
54
|
+
let info = currentDElement;
|
|
55
|
+
|
|
56
|
+
// Data resolution. A name with '/' is a breadcrumb path into the data,
|
|
57
|
+
// unless the data has it as a literal key. Missing or null steps resolve to [].
|
|
58
|
+
if ( data && data.includes ( '/' )) {
|
|
59
|
+
if ( info != null && info.hasOwnProperty ( data )) info = info[data]
|
|
60
|
+
else {
|
|
61
|
+
data.split ( '/' ).forEach ( step => {
|
|
62
|
+
if ( info != null && info.hasOwnProperty ( step )) info = info[step]
|
|
63
|
+
else info = []
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if ( data === '@all' || data === null || data === '@root' ) info = currentDElement
|
|
68
|
+
else if ( data ) info = ( info != null ) ? info[data] : null
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
if ( dataOnly ) { // No actions - place the data directly
|
|
72
|
+
switch ( _defineDataType ( info )) {
|
|
73
|
+
case 'function':
|
|
74
|
+
cuts[index] = info ()
|
|
75
|
+
break
|
|
76
|
+
case 'primitive':
|
|
77
|
+
cuts[index] = info
|
|
78
|
+
break
|
|
79
|
+
case 'array':
|
|
80
|
+
if ( _defineDataType ( info[0] ) === 'primitive' ) cuts[index] = info[0]
|
|
81
|
+
break
|
|
82
|
+
case 'object':
|
|
83
|
+
if ( info.text ) cuts[index] = info.text
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else { // Run the action chain over the data
|
|
88
|
+
let { dataDeepLevel, nestedData } = _defineData ( info, action )
|
|
89
|
+
const actSetup = _actionSupply ( _setupActions ( action, dataDeepLevel ), dataDeepLevel )
|
|
90
|
+
|
|
91
|
+
currentDElement = executeActions ({
|
|
92
|
+
nestedData
|
|
93
|
+
, actSetup
|
|
94
|
+
, helpers
|
|
95
|
+
, original
|
|
96
|
+
, dependencies
|
|
97
|
+
, memory
|
|
98
|
+
, dElement : currentDElement
|
|
99
|
+
, createUseHelper : createUseHelperFactory
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
// The action chain leaves the result at the root level. Unwrap it.
|
|
103
|
+
if ( nestedData instanceof Array && nestedData.length === 1 && nestedData[0] instanceof Array ) nestedData = nestedData[0]
|
|
104
|
+
if ( nestedData[0] == null ) return
|
|
105
|
+
|
|
106
|
+
const fineData = nestedData[0]
|
|
107
|
+
switch ( _defineDataType ( fineData )) {
|
|
108
|
+
case 'primitive':
|
|
109
|
+
cuts[index] = fineData
|
|
110
|
+
break
|
|
111
|
+
case 'object':
|
|
112
|
+
if ( fineData['text'] == null ) return
|
|
113
|
+
cuts[index] = fineData['text']
|
|
114
|
+
break
|
|
115
|
+
case 'array': {
|
|
116
|
+
const itemType = _defineDataType ( fineData[0] )
|
|
117
|
+
if ( itemType === 'object' ) cuts[index] = fineData.map ( x => x.text ).join ( '' )
|
|
118
|
+
else cuts[index] = fineData.join ( '' )
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}) // forEach placeholders
|
|
124
|
+
|
|
125
|
+
if ( onlySnippets ) endData.push ( placeholders.map ( x => cuts[x.index] ).join ( '<~>' ))
|
|
126
|
+
else endData.push ( cuts.join ( '' ))
|
|
127
|
+
|
|
128
|
+
}) // forEach d
|
|
151
129
|
|
|
152
130
|
return endData
|
|
153
|
-
}
|
|
131
|
+
} // processPlaceholders func.
|
|
132
|
+
|
|
133
|
+
|
|
154
134
|
|
|
155
135
|
export default processPlaceholders
|
|
136
|
+
|
|
137
|
+
|
package/src/methods/render.js
CHANGED
|
@@ -15,19 +15,17 @@ import _renderHolder from './_renderHolder.js'
|
|
|
15
15
|
*
|
|
16
16
|
* @returns {any} The result of the rendering process, or an error string if the helper is not available.
|
|
17
17
|
*/
|
|
18
|
-
function render ( theData, name, helpers, original, dependencies, ...args) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
} // render func.
|
|
18
|
+
function render ( theData, name, helpers, original, dependencies, ...args ) {
|
|
19
|
+
const useHelper = ( targetName, targetData ) => render ( targetData || theData, targetName, helpers, original, dependencies, ...args )
|
|
20
|
+
if ( !helpers[name] ) return `( Error: Helper '${name}' is not available )`
|
|
21
|
+
|
|
22
|
+
const isRenderFunction = typeof helpers[name] === 'function';
|
|
23
|
+
if ( isRenderFunction ) return helpers[name] ({ data: theData, dependencies, full: original, useHelper }, ...args )
|
|
24
|
+
|
|
25
|
+
// String helpers are mini templates. Wrap primitives, so the template can address them as {{ text }}.
|
|
26
|
+
const dataForHolder = ( typeof theData === 'object' && theData !== null ) ? theData : { text: theData }
|
|
27
|
+
return _renderHolder ( helpers[name], dataForHolder )
|
|
28
|
+
} // render func.
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
|