theprogrammablemind 9.5.1-beta.0 → 9.5.1-beta.10
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/client.js +5 -2
- package/lines.js +7 -0
- package/package.json +5 -3
- package/src/config.js +44 -41
- package/src/configHelpers.js +16 -5
- package/src/fragments.js +77 -0
- package/src/generators.js +9 -8
- package/src/helpers.js +59 -0
- package/src/semantics.js +3 -3
package/client.js
CHANGED
|
@@ -316,6 +316,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
let startCounter = 0
|
|
319
|
+
let contextIdCounter = 0
|
|
319
320
|
while (true) {
|
|
320
321
|
if (queries.length === 0) {
|
|
321
322
|
break
|
|
@@ -356,8 +357,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
356
357
|
}
|
|
357
358
|
const summary = { summaries: json.summaries, length: json.contexts.length }
|
|
358
359
|
summaries.push(summary)
|
|
359
|
-
const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
360
|
-
await processContextsB({ isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
360
|
+
const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
361
|
+
await processContextsB({ contextIdCounter, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
362
|
+
contextIdCounter = updatedContextIdCounter
|
|
361
363
|
if (isTest) {
|
|
362
364
|
const end = runtime.performance.performance.now()
|
|
363
365
|
clientSideTime = end - start
|
|
@@ -475,6 +477,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
|
|
|
475
477
|
return
|
|
476
478
|
}
|
|
477
479
|
// initialize in between test so state is not preserved since the test was adding without state
|
|
480
|
+
config.testConfig.testModuleName = testConfig.testModuleName
|
|
478
481
|
await config.rebuild()
|
|
479
482
|
const errorHandler = (error) => {
|
|
480
483
|
if (error.metadata) {
|
package/lines.js
CHANGED
|
@@ -5,6 +5,13 @@ class Lines {
|
|
|
5
5
|
this.rows = []
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
static SCREEN_WIDTH = 132
|
|
9
|
+
|
|
10
|
+
static addRemainder(widths) {
|
|
11
|
+
const sum = widths.reduce((a, b) => a + b)
|
|
12
|
+
return [...widths, Lines.SCREEN_WIDTH - sum]
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
addLine () {
|
|
9
16
|
this.lines.push(this.widths.map((width) => ''.padEnd(width)))
|
|
10
17
|
}
|
package/package.json
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
"@eslint/js": "^9.21.0",
|
|
4
4
|
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
|
5
5
|
"@typescript-eslint/parser": "^4.28.4",
|
|
6
|
+
"argparse": "^2.0.1",
|
|
6
7
|
"eslint": "^7.32.0",
|
|
7
8
|
"eslint-config-standard": "^16.0.3",
|
|
8
9
|
"eslint-plugin-import": "^2.23.4",
|
|
9
10
|
"eslint-plugin-node": "^11.1.0",
|
|
10
11
|
"eslint-plugin-promise": "^5.1.0",
|
|
11
12
|
"globals": "^16.0.0",
|
|
12
|
-
"jest": "^
|
|
13
|
-
"argparse": "^2.0.1"
|
|
13
|
+
"jest": "^30.2.0"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"to:debug": "node inspect node_modules/.bin/jest --runInBand -t NEO23",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"runtime.js",
|
|
46
46
|
"src/helpers.js",
|
|
47
47
|
"src/flatten.js",
|
|
48
|
+
"src/fragments.js",
|
|
48
49
|
"src/unflatten.js",
|
|
49
50
|
"src/config.js",
|
|
50
51
|
"src/configHelpers.js",
|
|
@@ -61,6 +62,7 @@
|
|
|
61
62
|
"dependencies": {
|
|
62
63
|
"base-64": "^1.0.0",
|
|
63
64
|
"deep-equal": "^2.0.4",
|
|
65
|
+
"flatted": "^3.3.3",
|
|
64
66
|
"fs": "0.0.1-security",
|
|
65
67
|
"json-diff": "^1.0.3",
|
|
66
68
|
"json-stable-stringify": "^1.0.1",
|
|
@@ -71,6 +73,6 @@
|
|
|
71
73
|
"sort-json": "^2.0.0",
|
|
72
74
|
"uuid": "^8.3.2"
|
|
73
75
|
},
|
|
74
|
-
"version": "9.5.1-beta.
|
|
76
|
+
"version": "9.5.1-beta.10",
|
|
75
77
|
"license": "UNLICENSED"
|
|
76
78
|
}
|
package/src/config.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ecatch } = require('./helpers')
|
|
|
10
10
|
const runtime = require('../runtime')
|
|
11
11
|
const _ = require('lodash')
|
|
12
12
|
const db = require('./debug')
|
|
13
|
+
const { fragmentInstantiator } = require('./fragments')
|
|
13
14
|
|
|
14
15
|
const debugBreak = () => {
|
|
15
16
|
// debugger
|
|
@@ -289,11 +290,9 @@ const priority_valid = (cp) => {
|
|
|
289
290
|
const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
290
291
|
ecatch(`While processing the bridge for ${bridge.id}#${bridge.level}`,
|
|
291
292
|
() => {
|
|
292
|
-
|
|
293
|
-
if (bridge.development && config.isModule) {
|
|
293
|
+
if (bridge.scope && config.isModule) {
|
|
294
294
|
return
|
|
295
295
|
}
|
|
296
|
-
*/
|
|
297
296
|
if (false && !bridge.bridge) {
|
|
298
297
|
bridge.bridge = '{ ...next(operator) }'
|
|
299
298
|
}
|
|
@@ -1109,54 +1108,21 @@ class Config {
|
|
|
1109
1108
|
return instance
|
|
1110
1109
|
}
|
|
1111
1110
|
|
|
1112
|
-
fragmentInstantiator (args, contexts) {
|
|
1113
|
-
return new Object({
|
|
1114
|
-
contexts: () => contexts,
|
|
1115
|
-
instantiate: async (mappings) => {
|
|
1116
|
-
const instantiated = _.cloneDeep(contexts)
|
|
1117
|
-
// const todo = [...instantiated]
|
|
1118
|
-
// const todo = [...instantiated]
|
|
1119
|
-
const todo = _.clone(instantiated)
|
|
1120
|
-
args = { ...args }
|
|
1121
|
-
while (todo.length > 0) {
|
|
1122
|
-
const context = todo.pop()
|
|
1123
|
-
args.context = context
|
|
1124
|
-
for (const mapping of mappings) {
|
|
1125
|
-
if (await mapping.match(args)) {
|
|
1126
|
-
await mapping.apply(args)
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
for (const key of Object.keys(context)) {
|
|
1130
|
-
// if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
|
|
1131
|
-
if (!helpers.isCompound(context[key])) {
|
|
1132
|
-
continue
|
|
1133
|
-
}
|
|
1134
|
-
if (context[key].instantiated) {
|
|
1135
|
-
continue
|
|
1136
|
-
}
|
|
1137
|
-
todo.push(context[key])
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
return instantiated
|
|
1141
|
-
}
|
|
1142
|
-
})
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
1111
|
fragment (args, query) {
|
|
1146
1112
|
for (const instance of (this.instances || [])) {
|
|
1147
1113
|
for (const fragment of (instance.fragments || [])) {
|
|
1148
1114
|
if (fragment.query === query) {
|
|
1149
|
-
return
|
|
1115
|
+
return fragmentInstantiator(args, fragment.contexts)
|
|
1150
1116
|
}
|
|
1151
1117
|
}
|
|
1152
1118
|
for (const fragment of (instance.resultss || [])) {
|
|
1153
1119
|
if (fragment.isFragment && fragment.query === query) {
|
|
1154
|
-
return
|
|
1120
|
+
return fragmentInstantiator(args, fragment.contexts)
|
|
1155
1121
|
}
|
|
1156
1122
|
}
|
|
1157
1123
|
for (const fragment of (this.fragmentsBeingBuilt || [])) {
|
|
1158
1124
|
if (fragment.query === query) {
|
|
1159
|
-
return
|
|
1125
|
+
return fragmentInstantiator(args, fragment.contexts)
|
|
1160
1126
|
}
|
|
1161
1127
|
}
|
|
1162
1128
|
}
|
|
@@ -1898,6 +1864,13 @@ class Config {
|
|
|
1898
1864
|
return
|
|
1899
1865
|
}
|
|
1900
1866
|
|
|
1867
|
+
const idToScope = {}
|
|
1868
|
+
for (const bridge in config.bridges) {
|
|
1869
|
+
if (bridge.scope) {
|
|
1870
|
+
idToScope[bridge.id] = scope
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1901
1874
|
const keep = (element) => {
|
|
1902
1875
|
const old_result = element.scope !== 'testing'
|
|
1903
1876
|
let new_result = false
|
|
@@ -1906,18 +1879,48 @@ class Config {
|
|
|
1906
1879
|
} else if (this.scope == 'development') {
|
|
1907
1880
|
new_result = !(element.scope === 'testing')
|
|
1908
1881
|
}
|
|
1882
|
+
/*
|
|
1909
1883
|
if (global.GORDO && old_result !== new_result) {
|
|
1910
1884
|
global.GORDO = false
|
|
1885
|
+
console.log("THERE WAS A DIFFERENCE ------------------------------------------------")
|
|
1911
1886
|
debugger // greg23old
|
|
1912
1887
|
}
|
|
1913
|
-
|
|
1888
|
+
*/
|
|
1889
|
+
// return old_result
|
|
1890
|
+
return new_result
|
|
1914
1891
|
}
|
|
1915
1892
|
|
|
1916
1893
|
config.operators = config.operators.filter((element) => keep(element))
|
|
1917
1894
|
config.bridges = config.bridges.filter((element) => keep(element))
|
|
1918
1895
|
config.generators = config.generators.filter((element) => keep(element))
|
|
1919
1896
|
config.semantics = config.semantics.filter((element) => keep(element))
|
|
1920
|
-
|
|
1897
|
+
|
|
1898
|
+
// account for element missing correct scope
|
|
1899
|
+
config.hierarchy = (config.hierarchy).filter((element) => {
|
|
1900
|
+
if (!keep(element)) {
|
|
1901
|
+
return false
|
|
1902
|
+
}
|
|
1903
|
+
const discard = (id) => {
|
|
1904
|
+
if (idToScope[id]) {
|
|
1905
|
+
return !keep({ scope: idToScope[id] })
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
if (element.child && discard(element.child)) {
|
|
1909
|
+
return false
|
|
1910
|
+
}
|
|
1911
|
+
if (element.parent && discard(element.parent)) {
|
|
1912
|
+
return false
|
|
1913
|
+
}
|
|
1914
|
+
if (Array.isArray(element)) {
|
|
1915
|
+
if (discard(element[0])) {
|
|
1916
|
+
return false
|
|
1917
|
+
}
|
|
1918
|
+
if (discard(element[1])) {
|
|
1919
|
+
return false
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
return true
|
|
1923
|
+
})
|
|
1921
1924
|
|
|
1922
1925
|
const literals = config.words.literals
|
|
1923
1926
|
for (const word in literals) {
|
package/src/configHelpers.js
CHANGED
|
@@ -133,6 +133,9 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
133
133
|
args.addPattern = (pattern, def) => config.addPattern(pattern, args.uuid)
|
|
134
134
|
args.addGenerator = (generator) => config.addGenerator(generator, args.uuid, config.name)
|
|
135
135
|
|
|
136
|
+
if (config.testConfig?.testModuleName) {
|
|
137
|
+
args.testModuleName = config.testConfig.testModuleName
|
|
138
|
+
}
|
|
136
139
|
args.addAssumedScoped = (args, assumed) => {
|
|
137
140
|
const addAssumed = (args, ...moreAssumed) => {
|
|
138
141
|
return { ...args, assumed: Object.assign({}, assumed, (args.assumed || {}), ...moreAssumed) }
|
|
@@ -291,7 +294,7 @@ const setupContexts = (rawContexts) => {
|
|
|
291
294
|
return contexts
|
|
292
295
|
}
|
|
293
296
|
|
|
294
|
-
const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate }) => {
|
|
297
|
+
const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
|
|
295
298
|
// TODO fix this name to contextsPrime
|
|
296
299
|
const contextsPrime = []
|
|
297
300
|
const generatedPrime = []
|
|
@@ -311,14 +314,13 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
311
314
|
args.insert = (context) => toDo.unshift(context)
|
|
312
315
|
let overlap, lastRange
|
|
313
316
|
config.debugLoops = commandLineArgs && commandLineArgs.debugLoops
|
|
314
|
-
let context_id_counter = 0
|
|
315
317
|
while (toDo.length > 0) {
|
|
316
318
|
const context = toDo.shift()
|
|
317
319
|
args.calls.next()
|
|
318
320
|
let contextPrime = context
|
|
319
321
|
context.topLevel = true
|
|
320
|
-
|
|
321
|
-
context.context_id =
|
|
322
|
+
contextIdCounter += 1
|
|
323
|
+
context.context_id = contextIdCounter
|
|
322
324
|
try {
|
|
323
325
|
if (json.has_errors) {
|
|
324
326
|
throw new Error('There are errors in the logs. Run with the -d flag and grep for Error')
|
|
@@ -328,6 +330,9 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
328
330
|
const semantics = config.getSemantics(json.logs)
|
|
329
331
|
try {
|
|
330
332
|
contextPrime = await semantics.apply(args, context)
|
|
333
|
+
// contextPrime.greg = 'yes'
|
|
334
|
+
// console.log("context_id", context.context_id)
|
|
335
|
+
// console.log("semantics.apply", JSON.stringify(contextPrime, null, 2))
|
|
331
336
|
} catch (e) {
|
|
332
337
|
if (e.message == 'Maximum call stack size exceeded') {
|
|
333
338
|
const mostCalled = semantics.getMostCalled()
|
|
@@ -421,7 +426,7 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
421
426
|
throw e
|
|
422
427
|
}
|
|
423
428
|
}
|
|
424
|
-
return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime }
|
|
429
|
+
return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime, updatedContextIdCounter: contextIdCounter }
|
|
425
430
|
}
|
|
426
431
|
|
|
427
432
|
// instance template loadTemplate
|
|
@@ -479,6 +484,9 @@ const loadInstance = async (config, instance) => {
|
|
|
479
484
|
args.isModule = true
|
|
480
485
|
args.isProcess = false
|
|
481
486
|
}
|
|
487
|
+
if (instance.name == config.testConfig.testModuleName) {
|
|
488
|
+
args.isTesting = true
|
|
489
|
+
}
|
|
482
490
|
await results.apply(args)
|
|
483
491
|
} else if (results.isFragment) {
|
|
484
492
|
} else {
|
|
@@ -490,6 +498,9 @@ const loadInstance = async (config, instance) => {
|
|
|
490
498
|
args.instance = ''
|
|
491
499
|
args.isProcess = !config.isModule
|
|
492
500
|
args.isModule = !!config.isModule
|
|
501
|
+
if (instance.name == config.testConfig.testModuleName) {
|
|
502
|
+
args.isTesting = true
|
|
503
|
+
}
|
|
493
504
|
await processContextsB(args)
|
|
494
505
|
if (results.skipSemantics) {
|
|
495
506
|
config.config.skipSemantics = null
|
package/src/fragments.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const _ = require('lodash')
|
|
2
|
+
const helpers = require('./helpers')
|
|
3
|
+
|
|
4
|
+
function fragmentInstantiator (args, contexts) {
|
|
5
|
+
return new Object({
|
|
6
|
+
contexts: () => contexts,
|
|
7
|
+
instantiate: async (mappings) => {
|
|
8
|
+
const instantiated = _.cloneDeep(contexts)
|
|
9
|
+
const todo = [{ context: instantiated, path: [] }]
|
|
10
|
+
args = { ...args }
|
|
11
|
+
while (todo.length > 0) {
|
|
12
|
+
const { context, path } = todo.pop()
|
|
13
|
+
args.context = context
|
|
14
|
+
args.path = path
|
|
15
|
+
for (const mapping of mappings) {
|
|
16
|
+
if (await mapping.match(args)) {
|
|
17
|
+
await mapping.apply(args)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const key of Object.keys(context)) {
|
|
21
|
+
// if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
|
|
22
|
+
if (!helpers.isCompound(context[key])) {
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
if (context[key].instantiated) {
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
todo.push({ context: context[key], path: [...path, key] })
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return instantiated
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function fragmentMapperInstantiator(values, modelFrom, modelTo) {
|
|
37
|
+
const paths = {}
|
|
38
|
+
for (const value of values) {
|
|
39
|
+
paths[value] = { value }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
const fi = fragmentInstantiator({paths}, modelFrom)
|
|
44
|
+
await fi.instantiate([
|
|
45
|
+
{
|
|
46
|
+
match: ({context, path}) => values.includes(context.value),
|
|
47
|
+
apply: ({context, path}) => paths[context.value].from = path
|
|
48
|
+
},
|
|
49
|
+
])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
const fi = fragmentInstantiator({paths}, modelTo)
|
|
54
|
+
await fi.instantiate([
|
|
55
|
+
{
|
|
56
|
+
match: ({context, path}) => values.includes(context.value),
|
|
57
|
+
apply: ({context, path}) => paths[context.value].to = path
|
|
58
|
+
},
|
|
59
|
+
])
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
instantiate: (actualFrom) => {
|
|
63
|
+
const actualTo = structuredClone(modelTo)
|
|
64
|
+
for (const value in paths) {
|
|
65
|
+
const { from, to } = paths[value]
|
|
66
|
+
const actualValue = helpers.getByPath(actualFrom, from, null)
|
|
67
|
+
helpers.setByPath(actualTo, to, actualValue)
|
|
68
|
+
}
|
|
69
|
+
return actualTo
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = {
|
|
75
|
+
fragmentInstantiator,
|
|
76
|
+
fragmentMapperInstantiator,
|
|
77
|
+
}
|
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 ${
|
|
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)
|
|
@@ -202,7 +203,7 @@ class Generators {
|
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
if (!generated && generated !== '') {
|
|
205
|
-
const widths = [10, 10
|
|
206
|
+
const widths = Lines.addRemainder([10, 10])
|
|
206
207
|
const lines = new Lines(widths)
|
|
207
208
|
lines.setElement(0, 0, 'Generator')
|
|
208
209
|
const source = `${generator.km}/#${generator.index}`
|
|
@@ -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,
|
|
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,14 +224,14 @@ 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 ${
|
|
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()
|
|
230
231
|
throw { error: [message], logs: this.logs }
|
|
231
232
|
}
|
|
232
233
|
if (((config || {}).config || {}).debug) {
|
|
233
|
-
const widths = [10, 10
|
|
234
|
+
const widths = Lines.addRemainder([10, 10])
|
|
234
235
|
const lines = new Lines(widths)
|
|
235
236
|
lines.setElement(0, 0, 'Generator')
|
|
236
237
|
if (generator.index > -1 && generator.km) {
|
|
@@ -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,
|
|
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
|
|
@@ -263,7 +264,7 @@ class Generators {
|
|
|
263
264
|
}
|
|
264
265
|
args.calls.pop()
|
|
265
266
|
if (!applied && ((config || {}).config || {}).debug) {
|
|
266
|
-
const widths = [10, 10
|
|
267
|
+
const widths = Lines.addRemainder([10, 10])
|
|
267
268
|
const lines = new Lines(widths)
|
|
268
269
|
lines.setElement(0, 0, 'Generator')
|
|
269
270
|
lines.setElement(0, 2, 'No generator applied')
|
|
@@ -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,
|
|
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)
|
package/src/helpers.js
CHANGED
|
@@ -436,6 +436,63 @@ const stableId = (tag) => {
|
|
|
436
436
|
return id
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
+
function getByPath(obj, path, defaultValue) {
|
|
440
|
+
let current = obj;
|
|
441
|
+
for (const key of path) {
|
|
442
|
+
if (current === null || current === undefined) return defaultValue;
|
|
443
|
+
if (typeof current !== 'object') return defaultValue;
|
|
444
|
+
current = current[key];
|
|
445
|
+
}
|
|
446
|
+
return current === undefined ? defaultValue : current;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Set a value in an object by path array.
|
|
451
|
+
* Automatically creates missing objects {} or arrays [] as needed.
|
|
452
|
+
*
|
|
453
|
+
* @param {Object} obj - The root object to modify
|
|
454
|
+
* @param {Array<string|number>} path - Array of keys/indices
|
|
455
|
+
* @param {*} value - Value to set
|
|
456
|
+
* @returns {*} The set value (for chaining)
|
|
457
|
+
*/
|
|
458
|
+
function setByPath(obj, path, value) {
|
|
459
|
+
if (!Array.isArray(path) || path.length === 0) {
|
|
460
|
+
throw new Error('Path must be a non-empty array');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
let current = obj;
|
|
464
|
+
|
|
465
|
+
for (let i = 0; i < path.length; i++) {
|
|
466
|
+
const key = path[i];
|
|
467
|
+
const isLast = i === path.length - 1;
|
|
468
|
+
|
|
469
|
+
if (isLast) {
|
|
470
|
+
// Final step — just assign
|
|
471
|
+
current[key] = value;
|
|
472
|
+
} else {
|
|
473
|
+
// Not last — ensure next level exists
|
|
474
|
+
const nextKey = path[i + 1];
|
|
475
|
+
|
|
476
|
+
if (current[key] == null) {
|
|
477
|
+
// Auto-create: array if next key is number, otherwise object
|
|
478
|
+
current[key] = typeof nextKey === 'number' || String(nextKey >>> 0) === nextKey
|
|
479
|
+
? []
|
|
480
|
+
: {};
|
|
481
|
+
} else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
|
|
482
|
+
// Safety: if current is array but next key isn't a valid index → convert to object
|
|
483
|
+
current[key] = { ...current[key] };
|
|
484
|
+
} else if (!Array.isArray(current[key]) && typeof nextKey === 'number') {
|
|
485
|
+
// If next expects array but current is object → convert
|
|
486
|
+
current[key] = Object.values(current[key]);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
current = current[key];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return value;
|
|
494
|
+
}
|
|
495
|
+
|
|
439
496
|
module.exports = {
|
|
440
497
|
stableId,
|
|
441
498
|
ecatch,
|
|
@@ -463,4 +520,6 @@ module.exports = {
|
|
|
463
520
|
w,
|
|
464
521
|
suggestAssociationsFix,
|
|
465
522
|
suggestAssociationsFixFromSummaries,
|
|
523
|
+
getByPath,
|
|
524
|
+
setByPath,
|
|
466
525
|
}
|
package/src/semantics.js
CHANGED
|
@@ -218,7 +218,7 @@ class Semantics {
|
|
|
218
218
|
errorMessage = e.toString()
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
const widths = [10, 10
|
|
221
|
+
const widths = Lines.addRemainder([10, 10])
|
|
222
222
|
const lines = new Lines(widths)
|
|
223
223
|
lines.setElement(0, 0, 'Semantic')
|
|
224
224
|
const source = `${semantic.km}/#${semantic.index}`
|
|
@@ -248,7 +248,7 @@ class Semantics {
|
|
|
248
248
|
args.calls.touch(contextPrime)
|
|
249
249
|
// this.logs.push(`Semantics: applied ${semantic.toString()}\n to\n ${JSON.stringify(context)}\n the result was ${JSON.stringify(contextPrime)}\n`)
|
|
250
250
|
if (((config || {}).config || {}).debug) {
|
|
251
|
-
const widths = [10, 10
|
|
251
|
+
const widths = Lines.addRemainder([10, 10])
|
|
252
252
|
const lines = new Lines(widths)
|
|
253
253
|
lines.setElement(0, 0, 'Semantic')
|
|
254
254
|
if (semantic.index > -1 && semantic.km) {
|
|
@@ -295,7 +295,7 @@ class Semantics {
|
|
|
295
295
|
}
|
|
296
296
|
args.calls.pop()
|
|
297
297
|
if (!applied && ((config || {}).config || {}).debug) {
|
|
298
|
-
const widths = [10, 10
|
|
298
|
+
const widths = Lines.addRemainder([10, 10])
|
|
299
299
|
const lines = new Lines(widths)
|
|
300
300
|
lines.setElement(0, 0, 'Semantic')
|
|
301
301
|
lines.setElement(0, 2, 'No semantic applied')
|