@peter.naydenov/morph 3.3.1 → 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.
Files changed (140) hide show
  1. package/.claude/scheduled_tasks.lock +1 -0
  2. package/.claude/settings.local.json +14 -0
  3. package/.graphify_cached.json +1 -0
  4. package/.graphify_semantic_new.json +1 -0
  5. package/.graphify_uncached.txt +14 -0
  6. package/.opencode/package-lock.json +115 -0
  7. package/.opencode/plugins/graphify.js +22 -0
  8. package/AGENTS.md +8 -0
  9. package/Changelog.md +16 -0
  10. package/dist/morph.cjs +1 -1
  11. package/dist/morph.esm.mjs +1 -1
  12. package/dist/morph.umd.js +1 -1
  13. package/dist/src/main.d.ts +100 -0
  14. package/dist/src/methods/_actionSupply.d.ts +18 -0
  15. package/dist/src/methods/_chopTemplates.d.ts +22 -0
  16. package/dist/src/methods/_defineData.d.ts +25 -0
  17. package/dist/src/methods/_defineType.d.ts +15 -0
  18. package/dist/src/methods/_readTemplate.d.ts +24 -0
  19. package/dist/src/methods/_renderHolder.d.ts +17 -0
  20. package/dist/src/methods/_setupActions.d.ts +19 -0
  21. package/dist/src/methods/actionData.d.ts +10 -0
  22. package/dist/src/methods/actionExtendedRender.d.ts +10 -0
  23. package/dist/src/methods/actionMix.d.ts +10 -0
  24. package/dist/src/methods/actionRender.d.ts +13 -0
  25. package/dist/src/methods/actionSave.d.ts +8 -0
  26. package/dist/src/methods/build.d.ts +61 -0
  27. package/dist/src/methods/executeActions.d.ts +11 -0
  28. package/dist/src/methods/processCommands.d.ts +46 -0
  29. package/dist/src/methods/processPlaceholders.d.ts +27 -0
  30. package/dist/src/methods/render.d.ts +14 -0
  31. package/dist/src/methods/settings.d.ts +7 -0
  32. package/graphify-out/.graphify_python +1 -0
  33. package/graphify-out/GRAPH_REPORT.md +147 -0
  34. package/graphify-out/cache/12d38a6879ec5b7a18b61b92920684a5e915c2255c41e2c56168c678dba94023.json +1 -0
  35. package/graphify-out/cache/1ba574be094f9bd868bbce1091b9988d6188ae071762a73d483516498b742434.json +1 -0
  36. package/graphify-out/cache/2dfd19c49f88b8af0c95f7692ae9453b54cf898dba6c24cad9cbd555b365f5e7.json +1 -0
  37. package/graphify-out/cache/343264caa0702ae2210efeb2d673fb69b59bd01403803c84f9da0ce21d93c6fe.json +1 -0
  38. package/graphify-out/cache/38f82a17b2933bf14206263846c7396b46ac0db01af525300ac20f2f3f2b0534.json +1 -0
  39. package/graphify-out/cache/3a8b3ccf38f1d380228dda52c3c595ec76b5827b6905ef7e2bef6e265ee4ac16.json +1 -0
  40. package/graphify-out/cache/3b3e764a57e1d2ce17e5a74bea1c7ee493260e27266c114a72688d441f712e52.json +1 -0
  41. package/graphify-out/cache/42bc18f8ec31b043b4c4ecc11c79c288afe0801207d60a7cc322d11ab4579864.json +1 -0
  42. package/graphify-out/cache/4e3d45485b073109c7d91f18dac64ffbf0cbc21ae0edac016cb7b5f061954af6.json +1 -0
  43. package/graphify-out/cache/4ed08a09c3f090fe62cd56647a5251d60cf2f095156e502244a4f732929e342c.json +1 -0
  44. package/graphify-out/cache/51c174d3534ae05ed6dcbdb7f0d16da0b22f05677ef2863920e0a541b06090dd.json +1 -0
  45. package/graphify-out/cache/51d65b15aad6e35883d6ccaa0688273d7e14d8b7b85b194c50c365e5ea6710c6.json +1 -0
  46. package/graphify-out/cache/5d96cf59b7e5e3ea65c2ddcc6267178ea8916e104ff3f82a5a4d90179f762d11.json +1 -0
  47. package/graphify-out/cache/63fa82962f6899c2c099e95b595c5106f5dd53b2dc65037b89d6c6578033c03c.json +1 -0
  48. package/graphify-out/cache/6878c29d96e13e9fee1e01e4ca4e77d28b1e8e6c4f1d05dbffdca58625ef5694.json +1 -0
  49. package/graphify-out/cache/6c7082448b871f8cce9c6e26f788252a3b0c7e88ce40b4d3652ca9b78a2df049.json +1 -0
  50. package/graphify-out/cache/7cb42a4ad6e7c2f8b66560c9c40053e479cc1cffdf074d6b00bc23e607535376.json +1 -0
  51. package/graphify-out/cache/8712e549b4b42d5dc14c3e4b56f384c9d8e37116dc61ad906a05e10a1445ff40.json +1 -0
  52. package/graphify-out/cache/8b1ea63dfe0d47683be14dd72078eb83cf5b182d497237adbcd50ebdc1fee1bc.json +1 -0
  53. package/graphify-out/cache/8cd02cb84a50696666d33fee84a4a7e75fce651780ba7a4474bfe9b4a2b79c46.json +1 -0
  54. package/graphify-out/cache/8d0520a089ffaa71927ddddad5cb4d8f796a9febf0b8c4d54f78453b955520c5.json +1 -0
  55. package/graphify-out/cache/9406e0a23a011eaa9d74fe717280e5be52142ba4db8b7baee948dcdea6fe2617.json +1 -0
  56. package/graphify-out/cache/98abf9b9fbeb7f5fdaef6b853c949d297586b99e2965330906234f2ae331c0af.json +1 -0
  57. package/graphify-out/cache/9decf23c89efbaa42811f95c737234abee72478582ce4a46d99ba12d7446bb7b.json +1 -0
  58. package/graphify-out/cache/a37bc5340c5f31d2ef717845d339f468853e6554f753466ba2d995147d25fedf.json +1 -0
  59. package/graphify-out/cache/a77d81d5705a824ba81dc3556452ecc99978bc335e65e961aee29ce01e7cf81c.json +1 -0
  60. package/graphify-out/cache/ast/v0.8.39/21cd1a6bc5dbd687522c86e9f7db1842400b31ee3ba62127533aba56a478da5d.json +1 -0
  61. package/graphify-out/cache/ast/v0.8.39/29c3826c5e1938406f9eaf50a1354609aeb16e8f0d27e5a454c069c982f21180.json +1 -0
  62. package/graphify-out/cache/ast/v0.8.39/c31ea4d76660d1000df3bd29929d120e900297c7a1c26e5266312c21a9432e55.json +1 -0
  63. package/graphify-out/cache/ast/v0.8.39/de54c2617a64a2a1c1db34e6494216dd949fe730b51270bebba55c63d54a31e9.json +1 -0
  64. package/graphify-out/cache/b83cba0b46f18ae8fc4d50b540eaa276c28745ea4639863c082cb41681220b9d.json +1 -0
  65. package/graphify-out/cache/bd607a8d62efb3cceb791e36c2495c5ceee38e913c2386d293cca88566f4c0aa.json +1 -0
  66. package/graphify-out/cache/beb2827f4b8ad2aaacd809c8d783eb1f5f3c3c997ce6941d1cc9b2f0df7a0d6e.json +1 -0
  67. package/graphify-out/cache/ca721e7772d7906c5fecc00d69aa50bdc5e73ba087807089f3ca26509e014889.json +1 -0
  68. package/graphify-out/cache/cb49f9ceae6e04f66081b0c73c0574bddaf01240ea0c7efc1880616b94b4c0d8.json +1 -0
  69. package/graphify-out/cache/ce9874dce6f3f855a53dd706b4b83a503dc4ba72f7f36b6d73ec2cc8354f3cdf.json +1 -0
  70. package/graphify-out/cache/d3e24fc669e3f2a2c5e9e864a97ca447f0dcc1c5aad33c88a2280ac97188e888.json +1 -0
  71. package/graphify-out/cache/d6c072004e2ea18f9a5380aa75980cd08b15e7d6d893d396a5baac37dfc24310.json +1 -0
  72. package/graphify-out/cache/d99f1759a41541d9ef41aefdf89a2dbcab7272ccc91a9794062224124222e333.json +1 -0
  73. package/graphify-out/cache/dbb69ddd98951e0d5e51b2e1a2cf97a8febb147e55b81b43b05b680844bf4a1f.json +1 -0
  74. package/graphify-out/cache/df270b9b613de7bbefce4cabc6b3dd6e66ebecdbf6f0cefde05bb676569ee1c3.json +1 -0
  75. package/graphify-out/cache/e56607f0791079dbd05e56cdac41f88124785d367f9da0eb436952406cb317da.json +1 -0
  76. package/graphify-out/cache/ecdfee4e64acdd666f25596341a8ff4a41d7ee1e637de40685ff33c1efa814c7.json +1 -0
  77. package/graphify-out/cache/f0f3005c7ec68d16fcde259d6bc996520841d021ce2531cbb7f3de343996c4ea.json +1 -0
  78. package/graphify-out/cache/f2bfcd400f076a7e8a9e54b821d555c90b93ef4dd8d3652f78ec35acad5e0615.json +1 -0
  79. package/graphify-out/cache/semantic/043be2e32281a59e2bacb95418b95816b558a290aa581434b22666fb9a6a3a6c.json +1 -0
  80. package/graphify-out/cache/semantic/13439df0f4f40e2c190340576c1a46c2cc82b9fc789f262c78d7129cc56ef13c.json +1 -0
  81. package/graphify-out/cache/semantic/136052be0f52f9258076b87da6bde0ea62763a63684cc6729f759910448ae675.json +1 -0
  82. package/graphify-out/cache/semantic/15cbc6ab30bfa8cf7bb9b5646a2598aa78531047ef5096d5d8ab08edbcf8ee7d.json +1 -0
  83. package/graphify-out/cache/semantic/21cd1a6bc5dbd687522c86e9f7db1842400b31ee3ba62127533aba56a478da5d.json +1 -0
  84. package/graphify-out/cache/semantic/22bd0d40f23b81ba30a703fc290cc518f18d3148f5553ffc79f4bf8a0a71722c.json +1 -0
  85. package/graphify-out/cache/semantic/29c3826c5e1938406f9eaf50a1354609aeb16e8f0d27e5a454c069c982f21180.json +1 -0
  86. package/graphify-out/cache/semantic/2e913a06516b6bff22019b157680d17617db82a9ed2277ce1e20eac945939a7e.json +1 -0
  87. package/graphify-out/cache/semantic/30db4df562575c6116ad9e8843f19c557ab6fc25288c7aed8926641748b21fd6.json +1 -0
  88. package/graphify-out/cache/semantic/325abe6948add2e47c2271195503ab21f897e27f2cc9af292f39408b94a2f51c.json +1 -0
  89. package/graphify-out/cache/semantic/3579f6cf2c93aa83eb9396e389c195f17e4cff527d43718e61503e5c0f223f84.json +1 -0
  90. package/graphify-out/cache/semantic/36cda2fb14ba2ee3b8bc721a278f4963bf001c72258dd707b4b141334be01c15.json +1 -0
  91. package/graphify-out/cache/semantic/403b6596e3414f78206fc02adf9b62f07af237be191e0f4b26706041bf1e0ee1.json +1 -0
  92. package/graphify-out/cache/semantic/40f4144bc24d137a1afdcac95143c2bc3e26c0086d150c73df85fdf236bebe01.json +1 -0
  93. package/graphify-out/cache/semantic/45d85f3ac35b83d9a076c6e25c220324a0c92d0e955ba85e04b20ef09ddad9fd.json +1 -0
  94. package/graphify-out/cache/semantic/468d9e0c3d92cce2723852d2f29033326433cdc368203092b8470f2f356e3cec.json +1 -0
  95. package/graphify-out/cache/semantic/5983c77253844a325cb78f45828115ede5a688908bd38fa1b32ca78ab319deb9.json +1 -0
  96. package/graphify-out/cache/semantic/59ef3e18c32f0f877d8854ecb5e9f8714c608d5d90ca7adc71f2859fe496f66f.json +1 -0
  97. package/graphify-out/cache/semantic/71dd26effab66822e1d20111accfa0cc434826661da83b1b86a6fc3119980a66.json +1 -0
  98. package/graphify-out/cache/semantic/78bc10fe7d8d145c2c12af97dd75ea16f6787f1f15f0af0b145ac315ce63dcb6.json +1 -0
  99. package/graphify-out/cache/semantic/7c92d89867073cc9e54a821be558de7322fa42f342cf4c52da9bf02c29f43b1d.json +1 -0
  100. package/graphify-out/cache/semantic/82c3b90b2523c47b43a3212e2d30ed8d06c0027697f89fe177d062baf4d4202f.json +1 -0
  101. package/graphify-out/cache/semantic/8917cb163ec1afce8e5d659680749a553be3aa6aef54ebc757dd1b7c81d707c6.json +1 -0
  102. package/graphify-out/cache/semantic/8da5742abeaeadae80c4f57a4e98432a4bfc789eadb5082d3919780d646546f6.json +1 -0
  103. package/graphify-out/cache/semantic/97f4eb2208c6b1e81c84600ab52507478f5e682e63e5546a92c97b4c3d9371eb.json +1 -0
  104. package/graphify-out/cache/semantic/9c01c0ac53d626004b3d72953063c71f251710e7f23a8765c149159b0f422ecc.json +1 -0
  105. package/graphify-out/cache/semantic/9d0bbf5bdbb2aa4e3507d2e118464ce70d165916e29cae54b5ead974bfc1bd04.json +1 -0
  106. package/graphify-out/cache/semantic/9e59357a8097ad32258c2cb47c066508049e7f8c21fa55a1a5f5a4b0eee41275.json +1 -0
  107. package/graphify-out/cache/semantic/aaaff53eae109640d8e48c4585390fa7a2c2ca04088d314e578c316ca95f53e0.json +1 -0
  108. package/graphify-out/cache/semantic/b18464395b8719578b14148fd37880916c62b10f78942c862da386815c05b628.json +1 -0
  109. package/graphify-out/cache/semantic/c31ea4d76660d1000df3bd29929d120e900297c7a1c26e5266312c21a9432e55.json +1 -0
  110. package/graphify-out/cache/semantic/c74b855b4778be378db8fa05e33582c33cb563d8698ba6dae566e1cd37d0fb09.json +1 -0
  111. package/graphify-out/cache/semantic/cc8bf09a84e6fcc420e2438b3d6403560128b0edbd907761350fa58536d844ff.json +1 -0
  112. package/graphify-out/cache/semantic/d39f7cd9481b6f19c88e62ff5f7a3bddbf3a3593b2b1257a5092b44374c70874.json +1 -0
  113. package/graphify-out/cache/semantic/d5472c5e2c6560c9de5c17a444e2060eb9ccaa5dc7f4f3fe0dc3a5f68625bb91.json +1 -0
  114. package/graphify-out/cache/semantic/de54c2617a64a2a1c1db34e6494216dd949fe730b51270bebba55c63d54a31e9.json +1 -0
  115. package/graphify-out/cache/semantic/e29c1a9e35ffd56ab3b1e2f4800b48e9a6880bddecfc028dfdaf14498f52d8b4.json +1 -0
  116. package/graphify-out/cache/semantic/e39668e1347ee1000e7fba8b922c76488e34c35f2088b8334806e0256cfd71a7.json +1 -0
  117. package/graphify-out/cache/semantic/e9eea1131268a154e037e558c1856fbb2941e129b405659416b4e69746759440.json +1 -0
  118. package/graphify-out/cache/semantic/f3863c3e1c42f444b735cf4042b01a07b4e2f0bff82580bfab9bad1a784b8f4d.json +1 -0
  119. package/graphify-out/cache/semantic/f6dde571c1b88858dbf6da9b447dba7e66d9cb211c0130abcbb0768efed52e7b.json +1 -0
  120. package/graphify-out/cache/semantic/fa84dbd8fb64d52d0d43ea31da6cff178668e3eba7efb6e96ff605f3838a2bea.json +1 -0
  121. package/graphify-out/cache/stat-index.json +1 -0
  122. package/graphify-out/cost.json +18 -0
  123. package/graphify-out/graph.html +307 -0
  124. package/graphify-out/graph.json +6531 -0
  125. package/graphify-out/manifest.json +467 -0
  126. package/opencode.json +6 -0
  127. package/package.json +17 -9
  128. package/src/main.js +3 -7
  129. package/src/methods/_chopTemplates.js +56 -63
  130. package/src/methods/_setupActions.js +7 -14
  131. package/src/methods/actionData.js +35 -21
  132. package/src/methods/actionExtendedRender.js +21 -22
  133. package/src/methods/actionMix.js +47 -49
  134. package/src/methods/actionRender.js +43 -75
  135. package/src/methods/build.js +75 -97
  136. package/src/methods/executeActions.js +63 -49
  137. package/src/methods/processCommands.js +6 -10
  138. package/src/methods/processPlaceholders.js +105 -123
  139. package/src/methods/render.js +11 -13
  140. package/tsconfig.json +2 -1
@@ -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
- let { hasError, placeholders, chop, helpers, handshake, snippets } = _readTemplate(tpl);
56
+ const { hasError, placeholders, chop, helpers, handshake, snippets } = _readTemplate ( tpl );
54
57
 
55
58
  if ( hasError ) {
56
- function fail() { return hasError }
57
- return extra ? [false, fail] : fail
59
+ const fail = () => hasError
60
+ return extra ? [ false, fail ] : fail
58
61
  }
59
- else {
60
- const originalPlaceholders = structuredClone(placeholders);
61
-
62
- function success ( command = 'render', d = {}, dependencies = {}, ...args ) {
63
- const cuts = structuredClone(chop)
64
- let onlySnippets = false;
65
-
66
- // Command Validation
67
- if (typeof command !== 'string') return `Error: Wrong command "${command}". Available commands: render, debug, snippets, set, curry.`
68
- if (!['render', 'debug', 'snippets', 'set', 'curry'].includes(command) && !command.startsWith('snippets')) return `Error: Wrong command "${command}". Available commands: render, debug, snippets, set, curry.`
69
-
70
-
71
- // Handle Commands
72
- if (command.startsWith('snippets')) {
73
- onlySnippets = true
74
- const subset = handleSnippets(command, snippets)
75
- if (subset) placeholders = subset
76
- }
77
- else if (command === 'snippets') {
78
- onlySnippets = true
79
- }
80
- else if (command === 'set') {
81
- return handleSet(d, { helpers, handshake, placeholders, chop, build, buildDependencies })
82
- }
83
- else if (command === 'curry') {
84
- // Curry logic
85
- const rendered = success ( 'render', d, dependencies, ...args );
86
- const newTpl = {
87
- template: rendered,
88
- helpers,
89
- handshake
90
- };
91
- return build ( newTpl, false, buildDependencies )
92
- }
93
- else {
94
- placeholders = structuredClone ( originalPlaceholders )
95
- }
96
-
97
-
98
- // Handle 'DEBUG' (if d is string and command render/debug?)
99
- // Original logic: if (typeof d === 'string').
100
- // Wait, success('debug', 'raw') -> command='debug', d='raw'.
101
- // success('render', 'demo') -> command='render', d='demo'.
102
- // So any string d is treated as instruction ??
103
- if (typeof d === 'string') {
104
- const res = handleDebug(d, { handshake, helpers, placeholders, cuts })
105
- // If handleDebug returns string/number/object, return it.
106
- // Unless d='demo' which returns handshake object, then we proceed to render?
107
- if (d === 'demo' && typeof res === 'object') d = res
108
- else return res
109
- }
110
- // Proceed to Rendering
111
- const memory = {};
112
- let topLevelType = _defineDataType(d);
113
- let deps = { ...buildDependencies, ...dependencies }
114
-
115
- d = walk({ data: d })
116
- let original = walk({ data: d })
117
-
118
- if (topLevelType === 'null') return cuts.join('')
119
- if (topLevelType !== 'array') d = [d]
120
- if (topLevelType === 'null') return cuts.join('') // Redundant check?
121
-
122
-
123
- const endData = processPlaceholders({
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
- function executeActions({ nestedData, actSetup, helpers, original, dependencies, memory, dElement, createUseHelper }) {
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 (let step of actSetup) {
14
- let
15
- { type, name, level } = step
16
- , levelData = nestedData[level] || []
17
- ;
30
+ for ( const step of actSetup ) {
31
+ const
32
+ { type, level } = step
33
+ , levelData = nestedData[level] || []
34
+ ;
18
35
 
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] || []`
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
- 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
- }
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).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
- })
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 process only snippets
21
- * @returns {array} Processed template parts
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
- // 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 => {
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
- { index, data, action } = holder
57
- , dataOnly = !action
58
- , mem = structuredClone(memory)
30
+ targetFn = helpers[targetName]
31
+ , isCompiledTemplate = targetFn && typeof targetFn === 'function' && targetFn.length >= 2
59
32
  ;
60
- let info = currentDElement;
33
+ if ( !targetFn ) return `( Error: Helper '${targetName}' is not available )`
61
34
 
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
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
- 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
39
+ return render ( targetData || currentData, targetName, helpers, original, dependencies, ...args )
40
+ } // createUseHelperFactory func.
41
+
146
42
 
147
- if (onlySnippets) endData.push(placeholders.map(x => cuts[x.index]).join('<~>'))
148
- else endData.push(cuts.join(''))
43
+ d.forEach ( dElement => {
44
+ let
45
+ cuts = structuredClone ( chop )
46
+ , currentDElement = dElement // 'overwrite' action can replace it
47
+ ;
149
48
 
150
- }) // d.forEach
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
+
@@ -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
- 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
-
24
- if ( isRenderFunction ) return helpers[name]({ data: theData, dependencies, full: original, useHelper }, ...args)
25
- else {
26
- let dataForHolder = theData
27
- if ( typeof theData !== 'object' || theData === null ) dataForHolder = { text: theData }
28
- return _renderHolder ( helpers[name], dataForHolder )
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