theprogrammablemind_4wp 9.5.1-beta.7 → 9.5.1-beta.9

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/package.json CHANGED
@@ -45,7 +45,7 @@
45
45
  "runtime.js",
46
46
  "src/helpers.js",
47
47
  "src/flatten.js",
48
- "src/fragment.js",
48
+ "src/fragments.js",
49
49
  "src/unflatten.js",
50
50
  "src/config.js",
51
51
  "src/configHelpers.js",
@@ -62,6 +62,7 @@
62
62
  "dependencies": {
63
63
  "base-64": "^1.0.0",
64
64
  "deep-equal": "^2.0.4",
65
+ "flatted": "^3.3.3",
65
66
  "fs": "0.0.1-security",
66
67
  "json-diff": "^1.0.3",
67
68
  "json-stable-stringify": "^1.0.1",
@@ -72,6 +73,6 @@
72
73
  "sort-json": "^2.0.0",
73
74
  "uuid": "^8.3.2"
74
75
  },
75
- "version": "9.5.1-beta.7",
76
+ "version": "9.5.1-beta.9",
76
77
  "license": "UNLICENSED"
77
78
  }
@@ -0,0 +1,126 @@
1
+ const _ = require('lodash')
2
+ const helpers = require('./helpers')
3
+
4
+ function fragmentInstantiator(args, contexts) {
5
+ return new Object({
6
+ contexts: () => contexts,
7
+
8
+ instantiate: async (mappings) => {
9
+ const root = _.cloneDeep(contexts);
10
+
11
+ // To prevent infinite loops on circular references
12
+ const visited = new WeakSet();
13
+
14
+ // Stack item: { node, path }
15
+ // path is an array like: [], ['user'], ['users', 0], ['users', 0, 'address']
16
+ const todo = [{ node: root, path: [] }];
17
+
18
+ args = { ...args };
19
+
20
+ while (todo.length > 0) {
21
+ const { node, path } = todo.pop();
22
+
23
+ // Skip non-compound values early
24
+ if (!helpers.isCompound(node)) continue;
25
+
26
+ // Prevent reprocessing (including circular refs)
27
+ if (visited.has(node)) continue;
28
+ visited.add(node);
29
+
30
+ // Attach clean, frozen path array (non-enumerable)
31
+ Object.defineProperty(node, '__path', {
32
+ value: Object.freeze(path.slice()), // immutable copy
33
+ writable: false,
34
+ enumerable: false,
35
+ configurable: false
36
+ });
37
+
38
+ // Helpful string version
39
+ Object.defineProperty(node, '__pathString', {
40
+ value: path.map(p => String(p)).join('.'),
41
+ enumerable: false
42
+ });
43
+
44
+ // Pass rich context to mappings
45
+ args.context = node;
46
+ args.path = path; // e.g. ['users', 0, 'profile']
47
+ args.pathString = path.map(p => String(p)).join('.'); // "users.0.profile"
48
+
49
+ // Apply mappings
50
+ for (const mapping of mappings) {
51
+ if (await mapping.match(args)) {
52
+ await mapping.apply(args);
53
+ }
54
+ }
55
+
56
+ // Traverse children — build path correctly for objects AND arrays
57
+ if (Array.isArray(node)) {
58
+ node.forEach((child, index) => {
59
+ if (helpers.isCompound(child)) {
60
+ todo.push({
61
+ node: child,
62
+ path: [...path, index] // index as number!
63
+ });
64
+ }
65
+ });
66
+ } else {
67
+ // Plain object
68
+ for (const key of Object.keys(node)) {
69
+ const child = node[key];
70
+ if (helpers.isCompound(child)) {
71
+ todo.push({
72
+ node: child,
73
+ path: [...path, key] // key as string
74
+ });
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ return root;
81
+ }
82
+ });
83
+ }
84
+
85
+ async function fragmentMapperInstantiator(values, modelFrom, modelTo) {
86
+ const paths = {}
87
+ for (const value of values) {
88
+ paths[value] = { value }
89
+ }
90
+
91
+ {
92
+ const fi = fragmentInstantiator({paths}, modelFrom)
93
+ await fi.instantiate([
94
+ {
95
+ match: ({context, path}) => values.includes(context.value),
96
+ apply: ({context, path}) => paths[context.value].from = path
97
+ },
98
+ ])
99
+ }
100
+
101
+ {
102
+ const fi = fragmentInstantiator({paths}, modelTo)
103
+ await fi.instantiate([
104
+ {
105
+ match: ({context, path}) => values.includes(context.value),
106
+ apply: ({context, path}) => paths[context.value].to = path
107
+ },
108
+ ])
109
+ }
110
+ return {
111
+ instantiate: (actualFrom) => {
112
+ const actualTo = structuredClone(modelTo)
113
+ for (const value in paths) {
114
+ const { from, to } = paths[value]
115
+ const actualValue = helpers.getByPath(actualFrom, from, null)
116
+ helpers.setByPath(actualTo, to, actualValue)
117
+ }
118
+ return actualTo
119
+ }
120
+ }
121
+ }
122
+
123
+ module.exports = {
124
+ fragmentInstantiator,
125
+ fragmentMapperInstantiator,
126
+ }
package/src/generators.js CHANGED
@@ -1,3 +1,4 @@
1
+ const { stringify } = require('flatted');
1
2
  const { args: contextArgs, normalizeGenerator } = require('./helpers')
2
3
  const Lines = require('../lines')
3
4
  const helpers = require('./helpers')
@@ -182,7 +183,7 @@ class Generators {
182
183
  const generator = this.generators[igenerator]
183
184
  if (await generator.matches(args, objects, context, hierarchy, config, options)) {
184
185
  const log = (message) => { this.logs.push(message) }
185
- // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${JSON.stringify(context)}`)
186
+ // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
186
187
  let errorMessage = 'The apply function did not return a value'
187
188
  try {
188
189
  generated = await generator.apply(args, objects, context, hierarchy, config, response, log)
@@ -212,7 +213,7 @@ class Generators {
212
213
  lines.newRow()
213
214
  lines.setElement(0, 1, 'TO')
214
215
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
215
- lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
216
+ lines.setElement(1, 2, stringify(helpers.sortJson(context, { depth: 10 }), null, 2))
216
217
  lines.newRow()
217
218
  lines.setElement(0, 1, 'STACK')
218
219
  lines.setElement(0, 2, stack)
@@ -223,7 +224,7 @@ class Generators {
223
224
  lines.setElement(0, 1, 'ERROR')
224
225
  lines.setElement(0, 2, errorMessage)
225
226
  this.logs.push(lines.toString())
226
- const message = `ERROR while applying (${source}) ${generator.toLabel()}\n to\n ${JSON.stringify(context, null, 2)}.\n${errorMessage}'`
227
+ const message = `ERROR while applying (${source}) ${generator.toLabel()}\n to\n ${stringify(context, null, 2)}.\n${errorMessage}'`
227
228
  // this.logs.push(message)
228
229
  // return [message]
229
230
  args.calls.pop()
@@ -254,7 +255,7 @@ class Generators {
254
255
  lines.newRow()
255
256
  lines.setElement(0, 1, 'TO')
256
257
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
257
- lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
258
+ lines.setElement(1, 2, stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
258
259
  this.logs.push(lines.toString())
259
260
  }
260
261
  applied = true
@@ -272,7 +273,7 @@ class Generators {
272
273
  lines.setElement(0, 2, stack)
273
274
  lines.newRow()
274
275
  lines.setElement(0, 1, 'TO')
275
- lines.setElement(0, 2, JSON.stringify(context, null, 2))
276
+ lines.setElement(0, 2, stringify(context, null, 2))
276
277
  this.logs.push(lines.toString())
277
278
  }
278
279
  return ((config || {}).parenthesized ? '(' + generated + ')' : generated)