theprogrammablemind 9.5.1-beta.3 → 9.5.1-beta.30
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 +17 -8
- package/lines.js +7 -0
- package/package.json +5 -4
- package/runtime.js +0 -1
- package/src/config.js +133 -55
- package/src/configHelpers.js +65 -20
- package/src/fragments.js +83 -0
- package/src/generators.js +11 -7
- package/src/helpers.js +106 -2
- package/src/project2.js +7 -0
- package/src/semantics.js +6 -3
package/client.js
CHANGED
|
@@ -12,9 +12,8 @@ const _ = require('lodash')
|
|
|
12
12
|
const stringify = require('json-stable-stringify')
|
|
13
13
|
const Lines = require('./lines')
|
|
14
14
|
const flattens = require('./src/flatten')
|
|
15
|
-
const { appendNoDups, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps } = require('./src/helpers')
|
|
15
|
+
const { sortJson, appendNoDups, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps } = require('./src/helpers')
|
|
16
16
|
const runtime = require('./runtime')
|
|
17
|
-
const sortJson = runtime.sortJson
|
|
18
17
|
const debug = require('./src/debug')
|
|
19
18
|
|
|
20
19
|
const getConfig_getObjectsCheck = (config, testConfig) => {
|
|
@@ -69,6 +68,7 @@ const pickObjects = (config, testConfig, getObjects) => {
|
|
|
69
68
|
if (!objects) {
|
|
70
69
|
throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
|
|
71
70
|
}
|
|
71
|
+
|
|
72
72
|
if (checks[km] && checks[km].find((check) => check.match && check.apply)) {
|
|
73
73
|
projection[km] = project2(objects, checks[km])
|
|
74
74
|
} else {
|
|
@@ -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) {
|
|
@@ -913,7 +916,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
|
913
916
|
console.log('')
|
|
914
917
|
const screen_width = process.stdout.columns
|
|
915
918
|
// || 0 for when running without a console
|
|
916
|
-
const widths = [70, 10
|
|
919
|
+
const widths = Lines.addRemainder([70, 10])
|
|
917
920
|
const lines = new Lines(widths)
|
|
918
921
|
lines.setElement(0, 0, '--- The paraphrases are ----------')
|
|
919
922
|
lines.setElement(0, 2, '--- The response strings are ----------')
|
|
@@ -970,7 +973,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
970
973
|
if (instance.fragments) {
|
|
971
974
|
pr = instance.fragments[index]
|
|
972
975
|
}
|
|
973
|
-
return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics:
|
|
976
|
+
return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics: true })
|
|
974
977
|
}
|
|
975
978
|
|
|
976
979
|
const looper = async (configs) => {
|
|
@@ -2008,9 +2011,15 @@ const ensureTestFile = (module, name, type) => {
|
|
|
2008
2011
|
}
|
|
2009
2012
|
|
|
2010
2013
|
const knowledgeModule = async (...args) => {
|
|
2011
|
-
await knowledgeModuleImpl(...args).catch((e) => {
|
|
2014
|
+
await knowledgeModuleImpl(...args).catch(async (e) => {
|
|
2012
2015
|
console.error(e)
|
|
2013
|
-
|
|
2016
|
+
function sleep(ms) {
|
|
2017
|
+
return new Promise((resolve) => {
|
|
2018
|
+
setTimeout(resolve, ms);
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
await sleep(1) // get the stderr to flush
|
|
2022
|
+
await process.exit(-1); // tiny trick: empty write forces flush of console.error buffer
|
|
2014
2023
|
})
|
|
2015
2024
|
}
|
|
2016
2025
|
|
package/lines.js
CHANGED
|
@@ -5,6 +5,13 @@ class Lines {
|
|
|
5
5
|
this.rows = []
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
static SCREEN_WIDTH = 164
|
|
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",
|
|
@@ -68,9 +70,8 @@
|
|
|
68
70
|
"node-fetch": "^2.6.1",
|
|
69
71
|
"readline": "^1.3.0",
|
|
70
72
|
"scriptjs": "^2.5.9",
|
|
71
|
-
"sort-json": "^2.0.0",
|
|
72
73
|
"uuid": "^8.3.2"
|
|
73
74
|
},
|
|
74
|
-
"version": "9.5.1-beta.
|
|
75
|
+
"version": "9.5.1-beta.30",
|
|
75
76
|
"license": "UNLICENSED"
|
|
76
77
|
}
|
package/runtime.js
CHANGED
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, fragmentMapperInstantiator } = require('./fragments')
|
|
13
14
|
|
|
14
15
|
const debugBreak = () => {
|
|
15
16
|
// debugger
|
|
@@ -20,8 +21,6 @@ const bags = [
|
|
|
20
21
|
'semantics'
|
|
21
22
|
]
|
|
22
23
|
|
|
23
|
-
global.GORDO = true
|
|
24
|
-
|
|
25
24
|
const indent = (string, indent) => {
|
|
26
25
|
return string.replace(/^/gm, ' '.repeat(indent))
|
|
27
26
|
}
|
|
@@ -401,11 +400,15 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
401
400
|
if (bridge.generatorp) {
|
|
402
401
|
const match = bridge.generatorp.match || (() => true)
|
|
403
402
|
const apply = typeof bridge.generatorp === 'function' ? bridge.generatorp : bridge.generatorp.apply || bridge.generatorp
|
|
404
|
-
|
|
403
|
+
let level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
|
|
404
|
+
if (!bridge.bridge) {
|
|
405
|
+
level = 0
|
|
406
|
+
}
|
|
405
407
|
|
|
406
408
|
const generator = {
|
|
407
409
|
where: bridge.generatorp.where || bridge.where || helpers.where(4),
|
|
408
|
-
match: async (args) => bridge.id === args.context.marker && args.context.level === level && args.context.paraphrase && await match(args),
|
|
410
|
+
// match: async (args) => bridge.id === args.context.marker && args.context.level === level && args.context.paraphrase && await match(args),
|
|
411
|
+
match: async (args) => args.isA(args.context.marker, bridge.id) && args.context.level === level && args.context.paraphrase && await match(args),
|
|
409
412
|
apply: (args) => apply(args),
|
|
410
413
|
applyWrapped: apply,
|
|
411
414
|
property: 'generatorp'
|
|
@@ -422,7 +425,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
422
425
|
const level = bridge.generatorr.level >= 0 ? bridge.generatorr.level : bridge.level + 1
|
|
423
426
|
const generator = {
|
|
424
427
|
where: bridge.generatorr.where || bridge.where || helpers.where(4),
|
|
425
|
-
match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
|
|
428
|
+
// match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
|
|
429
|
+
match: async (args) => args.isA(args.context.marker, bridge.id) && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
|
|
426
430
|
apply: (args) => apply(args),
|
|
427
431
|
applyWrapped: apply,
|
|
428
432
|
property: 'generatorr'
|
|
@@ -509,8 +513,43 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
|
509
513
|
if (moreConfig.bridges) {
|
|
510
514
|
moreConfig.bridges = moreConfig.bridges.map((bridge) => {
|
|
511
515
|
bridge = { ...bridge }
|
|
512
|
-
const valid = [
|
|
513
|
-
'
|
|
516
|
+
const valid = [
|
|
517
|
+
'after',
|
|
518
|
+
'associations',
|
|
519
|
+
'before',
|
|
520
|
+
'bridge',
|
|
521
|
+
'check',
|
|
522
|
+
'children',
|
|
523
|
+
'conditional',
|
|
524
|
+
'convolution',
|
|
525
|
+
'disabled',
|
|
526
|
+
'enhanced_associations',
|
|
527
|
+
'evaluator',
|
|
528
|
+
'evaluators',
|
|
529
|
+
'generatorp',
|
|
530
|
+
'generatorpr',
|
|
531
|
+
'generatorr',
|
|
532
|
+
'generators',
|
|
533
|
+
'id',
|
|
534
|
+
'inverted',
|
|
535
|
+
'isA',
|
|
536
|
+
'level',
|
|
537
|
+
'levelSpecificHierarchy',
|
|
538
|
+
'localHierarchy',
|
|
539
|
+
'operator',
|
|
540
|
+
'optional',
|
|
541
|
+
'parents',
|
|
542
|
+
'return_type_selector',
|
|
543
|
+
'scope',
|
|
544
|
+
'selector',
|
|
545
|
+
'semantic',
|
|
546
|
+
'semantics',
|
|
547
|
+
'separators',
|
|
548
|
+
'skipable',
|
|
549
|
+
'uuid',
|
|
550
|
+
'where',
|
|
551
|
+
'words', /Bridge$/,
|
|
552
|
+
]
|
|
514
553
|
helpers.validProps(valid, bridge, 'bridge')
|
|
515
554
|
handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
|
|
516
555
|
return bridge
|
|
@@ -673,7 +712,7 @@ function setWordsUUIDs (words, uuid) {
|
|
|
673
712
|
for (const key in literals) {
|
|
674
713
|
literals[key] = literals[key].map((o) => Object.assign(o, { uuid }))
|
|
675
714
|
}
|
|
676
|
-
const patterns = words.patterns
|
|
715
|
+
const patterns = words.patterns || []
|
|
677
716
|
for (const pattern of patterns) {
|
|
678
717
|
pattern.defs.map((def) => Object.assign(def, { uuid }))
|
|
679
718
|
}
|
|
@@ -902,6 +941,10 @@ class Config {
|
|
|
902
941
|
return config_toServer(config)
|
|
903
942
|
}
|
|
904
943
|
|
|
944
|
+
async run(handler) {
|
|
945
|
+
return configHelpers.run(this, handler)
|
|
946
|
+
}
|
|
947
|
+
|
|
905
948
|
async fixtures () {
|
|
906
949
|
if (this.testConfig?.fixtures) {
|
|
907
950
|
const args = {}
|
|
@@ -935,6 +978,7 @@ class Config {
|
|
|
935
978
|
|
|
936
979
|
getPseudoConfig (uuid, config) {
|
|
937
980
|
return {
|
|
981
|
+
pseudo: true,
|
|
938
982
|
description: 'this is a pseudo config that has limited functionality due to being available in the initializer and fixtures function context',
|
|
939
983
|
addAssociation: (...args) => this.addAssociation(...args),
|
|
940
984
|
addAssociations: (...args) => this.addAssociations(...args),
|
|
@@ -948,6 +992,14 @@ class Config {
|
|
|
948
992
|
removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
|
|
949
993
|
addWord: (...args) => this.addWord(...args, uuid),
|
|
950
994
|
addPattern: (...args) => this.addPattern(...args, uuid),
|
|
995
|
+
updateBridge: (...args) => this.updateBridge(...args),
|
|
996
|
+
processContext: (...args) => this.processContext(...args),
|
|
997
|
+
|
|
998
|
+
semantics: () => this.config.semantics,
|
|
999
|
+
getConfigs: () => this.configs,
|
|
1000
|
+
getTests: () => this.getTests(),
|
|
1001
|
+
getName: () => this.getName(),
|
|
1002
|
+
getDescription: () => this.getDescription(),
|
|
951
1003
|
|
|
952
1004
|
getHierarchy: (...args) => this.config.hierarchy,
|
|
953
1005
|
getBridges: (...args) => this.config.bridges,
|
|
@@ -957,10 +1009,33 @@ class Config {
|
|
|
957
1009
|
fragment: (...args) => this.fragment(...args),
|
|
958
1010
|
server: (...args) => this.server(...args),
|
|
959
1011
|
exists: (...args) => this.exists(...args),
|
|
960
|
-
addAPI: (...args) => this.addAPI(...args)
|
|
1012
|
+
addAPI: (...args) => this.addAPI(...args),
|
|
1013
|
+
|
|
1014
|
+
getParenthesized: () => this.getParenthesized(),
|
|
1015
|
+
setParenthesized: (...args) => this.setParenthesized(...args),
|
|
961
1016
|
}
|
|
962
1017
|
}
|
|
963
1018
|
|
|
1019
|
+
getName() {
|
|
1020
|
+
return this.name
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
getDescription() {
|
|
1024
|
+
return this.description
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
getTests() {
|
|
1028
|
+
return this.tests
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
getParenthesized(value) {
|
|
1032
|
+
return this.parenthesized
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
setParenthesized(value) {
|
|
1036
|
+
this.parenthesized = value
|
|
1037
|
+
}
|
|
1038
|
+
|
|
964
1039
|
inDevelopmentMode (call) {
|
|
965
1040
|
config.developmentModeOn += 1
|
|
966
1041
|
try {
|
|
@@ -1107,59 +1182,52 @@ class Config {
|
|
|
1107
1182
|
return instance
|
|
1108
1183
|
}
|
|
1109
1184
|
|
|
1110
|
-
|
|
1111
|
-
return new Object({
|
|
1112
|
-
contexts: () => contexts,
|
|
1113
|
-
instantiate: async (mappings) => {
|
|
1114
|
-
const instantiated = _.cloneDeep(contexts)
|
|
1115
|
-
// const todo = [...instantiated]
|
|
1116
|
-
// const todo = [...instantiated]
|
|
1117
|
-
const todo = _.clone(instantiated)
|
|
1118
|
-
args = { ...args }
|
|
1119
|
-
while (todo.length > 0) {
|
|
1120
|
-
const context = todo.pop()
|
|
1121
|
-
args.context = context
|
|
1122
|
-
for (const mapping of mappings) {
|
|
1123
|
-
if (await mapping.match(args)) {
|
|
1124
|
-
await mapping.apply(args)
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
for (const key of Object.keys(context)) {
|
|
1128
|
-
// if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
|
|
1129
|
-
if (!helpers.isCompound(context[key])) {
|
|
1130
|
-
continue
|
|
1131
|
-
}
|
|
1132
|
-
if (context[key].instantiated) {
|
|
1133
|
-
continue
|
|
1134
|
-
}
|
|
1135
|
-
todo.push(context[key])
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
return instantiated
|
|
1139
|
-
}
|
|
1140
|
-
})
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
fragment (args, query) {
|
|
1185
|
+
getFragment(query) {
|
|
1144
1186
|
for (const instance of (this.instances || [])) {
|
|
1145
1187
|
for (const fragment of (instance.fragments || [])) {
|
|
1146
1188
|
if (fragment.query === query) {
|
|
1147
|
-
return
|
|
1189
|
+
return fragment
|
|
1148
1190
|
}
|
|
1149
1191
|
}
|
|
1150
1192
|
for (const fragment of (instance.resultss || [])) {
|
|
1151
1193
|
if (fragment.isFragment && fragment.query === query) {
|
|
1152
|
-
return
|
|
1194
|
+
return fragment
|
|
1153
1195
|
}
|
|
1154
1196
|
}
|
|
1155
1197
|
for (const fragment of (this.fragmentsBeingBuilt || [])) {
|
|
1156
1198
|
if (fragment.query === query) {
|
|
1157
|
-
return
|
|
1199
|
+
return fragment
|
|
1158
1200
|
}
|
|
1159
1201
|
}
|
|
1160
1202
|
}
|
|
1161
1203
|
}
|
|
1162
1204
|
|
|
1205
|
+
// mappings are optional
|
|
1206
|
+
async fragment (args, query, mappings) {
|
|
1207
|
+
const fragment = this.getFragment(query)
|
|
1208
|
+
if (fragment) {
|
|
1209
|
+
let fi = fragmentInstantiator(args, fragment.contexts)
|
|
1210
|
+
if (mappings) {
|
|
1211
|
+
fi = await fi
|
|
1212
|
+
return fi.instantiate([{
|
|
1213
|
+
match: ({context}) => !!mappings[context.value], // is the value in the mappings
|
|
1214
|
+
apply: ({context}) => Object.assign(context, mappings[context.value]),
|
|
1215
|
+
}])
|
|
1216
|
+
} else {
|
|
1217
|
+
return fi
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
fragmentMapper (args, values, fromModelQuery, toModelQuery) {
|
|
1223
|
+
const fromModelFragment = this.getFragment(fromModelQuery)
|
|
1224
|
+
console.dir(fromModelFragment)
|
|
1225
|
+
const toModelFragment = this.getFragment(toModelQuery)
|
|
1226
|
+
console.dir(toModelFragment)
|
|
1227
|
+
const mapper = fragmentMapperInstantiator(values, fromModelFragment.contexts, toModelFragment.contexts)
|
|
1228
|
+
return mapper
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1163
1231
|
// { rebuild: false, isModule: false }
|
|
1164
1232
|
needsRebuild (template, instance, options) {
|
|
1165
1233
|
if (options.rebuild) {
|
|
@@ -1518,6 +1586,11 @@ class Config {
|
|
|
1518
1586
|
}
|
|
1519
1587
|
}
|
|
1520
1588
|
|
|
1589
|
+
updateBridge(id, updater) {
|
|
1590
|
+
const bridge = this.config.bridges.find((b) => b.id === id)
|
|
1591
|
+
updater({ config: this, bridge })
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1521
1594
|
addBridge (bridge, uuid) {
|
|
1522
1595
|
if (!this.config.bridges) {
|
|
1523
1596
|
this.config.bridges = []
|
|
@@ -1819,7 +1892,7 @@ class Config {
|
|
|
1819
1892
|
|
|
1820
1893
|
// set the args in the api's
|
|
1821
1894
|
setArgs (args) {
|
|
1822
|
-
const
|
|
1895
|
+
const setConfigArgs = (config) => {
|
|
1823
1896
|
if (!config._api) {
|
|
1824
1897
|
return
|
|
1825
1898
|
}
|
|
@@ -1832,10 +1905,10 @@ class Config {
|
|
|
1832
1905
|
}
|
|
1833
1906
|
}
|
|
1834
1907
|
|
|
1835
|
-
|
|
1908
|
+
setConfigArgs(this)
|
|
1836
1909
|
for (const config of this.configs) {
|
|
1837
1910
|
if (config.config instanceof Config) {
|
|
1838
|
-
|
|
1911
|
+
setConfigArgs(config.config)
|
|
1839
1912
|
}
|
|
1840
1913
|
}
|
|
1841
1914
|
}
|
|
@@ -1864,6 +1937,16 @@ class Config {
|
|
|
1864
1937
|
}
|
|
1865
1938
|
}
|
|
1866
1939
|
|
|
1940
|
+
getObjects () {
|
|
1941
|
+
const configs = {}
|
|
1942
|
+
const ns = this.config.objects.namespaced
|
|
1943
|
+
configs[this.name] = this
|
|
1944
|
+
for (const config of this.configs) {
|
|
1945
|
+
configs[config._name] = ns[config._uuid]
|
|
1946
|
+
}
|
|
1947
|
+
return configs
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1867
1950
|
getConfig (name) {
|
|
1868
1951
|
if (this.name === name) {
|
|
1869
1952
|
return this
|
|
@@ -1911,12 +1994,7 @@ class Config {
|
|
|
1911
1994
|
} else if (this.scope == 'development') {
|
|
1912
1995
|
new_result = !(element.scope === 'testing')
|
|
1913
1996
|
}
|
|
1914
|
-
|
|
1915
|
-
global.GORDO = false
|
|
1916
|
-
console.log("THERE WAS A DIFFERENCE ------------------------------------------------")
|
|
1917
|
-
debugger // greg23old
|
|
1918
|
-
}
|
|
1919
|
-
return old_result
|
|
1997
|
+
return new_result
|
|
1920
1998
|
}
|
|
1921
1999
|
|
|
1922
2000
|
config.operators = config.operators.filter((element) => keep(element))
|
package/src/configHelpers.js
CHANGED
|
@@ -112,14 +112,18 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
112
112
|
throw new ErrorReason(context)
|
|
113
113
|
}
|
|
114
114
|
args.kms = config.getConfigs()
|
|
115
|
-
args.config = config
|
|
115
|
+
args.config = config.getPseudoConfig(uuidForScoping, config)
|
|
116
116
|
args.hierarchy = hierarchy
|
|
117
117
|
args.isA = isA(hierarchy)
|
|
118
118
|
// args.listable = listable(hierarchy)
|
|
119
119
|
// args.asList = asList
|
|
120
120
|
args.retry = () => { throw new RetryError() }
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// mappings are optional
|
|
122
|
+
args.fragments = (query, mappings) => {
|
|
123
|
+
return config.fragment(args, query, mappings)
|
|
124
|
+
}
|
|
125
|
+
args.fragmentMapper = (values, fromModelQuery, toModelQuery) => {
|
|
126
|
+
return config.fragmentMapper(args, values, fromModelQuery, toModelQuery)
|
|
123
127
|
}
|
|
124
128
|
args.breakOnSemantics = false
|
|
125
129
|
args.theDebugger = {
|
|
@@ -133,20 +137,35 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
133
137
|
args.addPattern = (pattern, def) => config.addPattern(pattern, args.uuid)
|
|
134
138
|
args.addGenerator = (generator) => config.addGenerator(generator, args.uuid, config.name)
|
|
135
139
|
|
|
140
|
+
if (config.testConfig?.testModuleName) {
|
|
141
|
+
args.testModuleName = config.testConfig.testModuleName
|
|
142
|
+
}
|
|
136
143
|
args.addAssumedScoped = (args, assumed) => {
|
|
137
144
|
const addAssumed = (args, ...moreAssumed) => {
|
|
138
145
|
return { ...args, assumed: Object.assign({}, assumed, (args.assumed || {}), ...moreAssumed) }
|
|
139
146
|
}
|
|
140
147
|
|
|
141
|
-
args.s = (c) => config.getSemantics(logs).apply(args, c)
|
|
142
|
-
args.g = (c,
|
|
143
|
-
|
|
148
|
+
args.s = (c, options = {}) => config.getSemantics(logs).apply(args, c, options)
|
|
149
|
+
args.g = (c, rest = {}) => {
|
|
150
|
+
// if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
|
|
151
|
+
// debugger
|
|
152
|
+
// }
|
|
153
|
+
const { assumed = {}, options = {} } = rest
|
|
154
|
+
return config.getGenerators(logs).apply(addAssumed(args, assumed), c, assumed, options)
|
|
144
155
|
}
|
|
145
|
-
args.gp = (c,
|
|
146
|
-
|
|
156
|
+
args.gp = (c, rest = {}) => {
|
|
157
|
+
// if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
|
|
158
|
+
// debugger
|
|
159
|
+
// }
|
|
160
|
+
const { assumed = {}, options = {} } = rest
|
|
161
|
+
return config.getGenerators(logs).apply(addAssumed(args, assumed, { paraphrase: true, isResponse: false, response: false }), c, { paraphrase: true, isResponse: false, response: false }, options)
|
|
147
162
|
}
|
|
148
|
-
args.gr = (c,
|
|
149
|
-
|
|
163
|
+
args.gr = (c, rest = {}) => {
|
|
164
|
+
// if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
|
|
165
|
+
// debugger
|
|
166
|
+
// }
|
|
167
|
+
const { assumed = {}, options = {} } = rest
|
|
168
|
+
return config.getGenerators(logs).apply(addAssumed(args, assumed, { paraphrase: false, isResponse: true }), { ...c, paraphrase: false, isResponse: true }, options)
|
|
150
169
|
}
|
|
151
170
|
args.e = (c) => {
|
|
152
171
|
if (!c) {
|
|
@@ -181,6 +200,7 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
181
200
|
|
|
182
201
|
Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
|
|
183
202
|
args.apis = args.apis || ((name) => config.getConfig(name).api)
|
|
203
|
+
// args.apis = (name) => config.getAPIs(name)
|
|
184
204
|
/*
|
|
185
205
|
if (uuidForScoping) {
|
|
186
206
|
Object.assign(args, args.getUUIDScoped(uuidForScoping))
|
|
@@ -199,6 +219,22 @@ const getObjects = (objects) => {
|
|
|
199
219
|
}
|
|
200
220
|
}
|
|
201
221
|
|
|
222
|
+
const run = async (config, handler) => {
|
|
223
|
+
// map to hash
|
|
224
|
+
config = config || {}
|
|
225
|
+
if (config.config) {
|
|
226
|
+
config = config
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const hierarchy = new DigraphInternal((config.config || {}).hierarchy || [])
|
|
230
|
+
|
|
231
|
+
const objects = config.config.objects.namespaced[config.uuid]
|
|
232
|
+
const logs = []
|
|
233
|
+
const args = {}
|
|
234
|
+
setupArgs(args, config, logs, hierarchy)
|
|
235
|
+
return handler(args)
|
|
236
|
+
}
|
|
237
|
+
|
|
202
238
|
const processContext = async (context, { objects = {}, config, logs = [] }) => {
|
|
203
239
|
const generators = config.getGenerators(logs)
|
|
204
240
|
const semantics = config.getSemantics(logs)
|
|
@@ -291,7 +327,7 @@ const setupContexts = (rawContexts) => {
|
|
|
291
327
|
return contexts
|
|
292
328
|
}
|
|
293
329
|
|
|
294
|
-
const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate }) => {
|
|
330
|
+
const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
|
|
295
331
|
// TODO fix this name to contextsPrime
|
|
296
332
|
const contextsPrime = []
|
|
297
333
|
const generatedPrime = []
|
|
@@ -311,14 +347,13 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
311
347
|
args.insert = (context) => toDo.unshift(context)
|
|
312
348
|
let overlap, lastRange
|
|
313
349
|
config.debugLoops = commandLineArgs && commandLineArgs.debugLoops
|
|
314
|
-
let context_id_counter = 0
|
|
315
350
|
while (toDo.length > 0) {
|
|
316
351
|
const context = toDo.shift()
|
|
317
352
|
args.calls.next()
|
|
318
353
|
let contextPrime = context
|
|
319
354
|
context.topLevel = true
|
|
320
|
-
|
|
321
|
-
context.context_id =
|
|
355
|
+
contextIdCounter += 1
|
|
356
|
+
context.context_id = contextIdCounter
|
|
322
357
|
try {
|
|
323
358
|
if (json.has_errors) {
|
|
324
359
|
throw new Error('There are errors in the logs. Run with the -d flag and grep for Error')
|
|
@@ -328,6 +363,9 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
328
363
|
const semantics = config.getSemantics(json.logs)
|
|
329
364
|
try {
|
|
330
365
|
contextPrime = await semantics.apply(args, context)
|
|
366
|
+
// contextPrime.greg = 'yes'
|
|
367
|
+
// console.log("context_id", context.context_id)
|
|
368
|
+
// console.log("semantics.apply", JSON.stringify(contextPrime, null, 2))
|
|
331
369
|
} catch (e) {
|
|
332
370
|
if (e.message == 'Maximum call stack size exceeded') {
|
|
333
371
|
const mostCalled = semantics.getMostCalled()
|
|
@@ -368,21 +406,21 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
368
406
|
const generated = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
369
407
|
let generatedParenthesized = []
|
|
370
408
|
if (generateParenthesized) {
|
|
371
|
-
config.
|
|
409
|
+
config.setParenthesized(true)
|
|
372
410
|
generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
373
|
-
config.
|
|
411
|
+
config.setParenthesized(false)
|
|
374
412
|
}
|
|
375
413
|
// assumed = { paraphrase: true, response: false };
|
|
376
414
|
assumed = { paraphrase: true, isResponse: false, response: false }
|
|
377
415
|
if (generateParenthesized) {
|
|
378
|
-
config.
|
|
416
|
+
config.setParenthesized(false)
|
|
379
417
|
}
|
|
380
418
|
const paraphrases = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
381
419
|
let paraphrasesParenthesized = []
|
|
382
420
|
if (generateParenthesized) {
|
|
383
|
-
config.
|
|
421
|
+
config.setParenthesized(true)
|
|
384
422
|
paraphrasesParenthesized = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
385
|
-
config.
|
|
423
|
+
config.setParenthesized(false)
|
|
386
424
|
}
|
|
387
425
|
contextsPrime.push(contextPrime)
|
|
388
426
|
generatedPrime.push(generated)
|
|
@@ -421,7 +459,7 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
|
|
|
421
459
|
throw e
|
|
422
460
|
}
|
|
423
461
|
}
|
|
424
|
-
return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime }
|
|
462
|
+
return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime, updatedContextIdCounter: contextIdCounter }
|
|
425
463
|
}
|
|
426
464
|
|
|
427
465
|
// instance template loadTemplate
|
|
@@ -479,6 +517,9 @@ const loadInstance = async (config, instance) => {
|
|
|
479
517
|
args.isModule = true
|
|
480
518
|
args.isProcess = false
|
|
481
519
|
}
|
|
520
|
+
if (instance.name == config.testConfig.testModuleName) {
|
|
521
|
+
args.isTesting = true
|
|
522
|
+
}
|
|
482
523
|
await results.apply(args)
|
|
483
524
|
} else if (results.isFragment) {
|
|
484
525
|
} else {
|
|
@@ -490,6 +531,9 @@ const loadInstance = async (config, instance) => {
|
|
|
490
531
|
args.instance = ''
|
|
491
532
|
args.isProcess = !config.isModule
|
|
492
533
|
args.isModule = !!config.isModule
|
|
534
|
+
if (instance.name == config.testConfig.testModuleName) {
|
|
535
|
+
args.isTesting = true
|
|
536
|
+
}
|
|
493
537
|
await processContextsB(args)
|
|
494
538
|
if (results.skipSemantics) {
|
|
495
539
|
config.config.skipSemantics = null
|
|
@@ -505,6 +549,7 @@ module.exports = {
|
|
|
505
549
|
// listable,
|
|
506
550
|
setupArgs,
|
|
507
551
|
processContext,
|
|
552
|
+
run,
|
|
508
553
|
getObjects,
|
|
509
554
|
gs,
|
|
510
555
|
processContextsB,
|
package/src/fragments.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const _ = require('lodash')
|
|
2
|
+
const helpers = require('./helpers')
|
|
3
|
+
|
|
4
|
+
function fragmentInstantiator (args, contexts) {
|
|
5
|
+
return new Object({
|
|
6
|
+
contexts: () => {
|
|
7
|
+
return _.cloneDeep(contexts)
|
|
8
|
+
},
|
|
9
|
+
instantiate: async (mappings) => {
|
|
10
|
+
const instantiated = _.cloneDeep(contexts)
|
|
11
|
+
const todo = [{ context: instantiated, path: [] }]
|
|
12
|
+
args = { ...args }
|
|
13
|
+
while (todo.length > 0) {
|
|
14
|
+
const { context, path } = todo.pop()
|
|
15
|
+
args.context = context
|
|
16
|
+
args.path = path
|
|
17
|
+
for (const mapping of mappings) {
|
|
18
|
+
if (await mapping.match(args)) {
|
|
19
|
+
await mapping.apply(args)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const key of Object.keys(context)) {
|
|
23
|
+
// if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
|
|
24
|
+
if (!helpers.isCompound(context[key])) {
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
27
|
+
if (context[key].instantiated) {
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
todo.push({ context: context[key], path: [...path, key] })
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (contexts.length == 1 && instantiated.length == 1) {
|
|
34
|
+
return instantiated[0]
|
|
35
|
+
} else {
|
|
36
|
+
return instantiated
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function fragmentMapperInstantiator(values, modelFrom, modelTo) {
|
|
43
|
+
const paths = {}
|
|
44
|
+
for (const value of values) {
|
|
45
|
+
paths[value] = { value }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
const fi = fragmentInstantiator({paths}, modelFrom)
|
|
50
|
+
await fi.instantiate([
|
|
51
|
+
{
|
|
52
|
+
match: ({context, path}) => values.includes(context.value),
|
|
53
|
+
apply: ({context, path}) => paths[context.value].from = path
|
|
54
|
+
},
|
|
55
|
+
])
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
{
|
|
59
|
+
const fi = fragmentInstantiator({paths}, modelTo)
|
|
60
|
+
await fi.instantiate([
|
|
61
|
+
{
|
|
62
|
+
match: ({context, path}) => values.includes(context.value),
|
|
63
|
+
apply: ({context, path}) => paths[context.value].to = path
|
|
64
|
+
},
|
|
65
|
+
])
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
instantiate: (actualFrom) => {
|
|
69
|
+
const actualTo = structuredClone(modelTo)
|
|
70
|
+
for (const value in paths) {
|
|
71
|
+
const { from, to } = paths[value]
|
|
72
|
+
const actualValue = helpers.getByPath(actualFrom, from, null)
|
|
73
|
+
helpers.setByPath(actualTo, to, actualValue)
|
|
74
|
+
}
|
|
75
|
+
return actualTo
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
fragmentInstantiator,
|
|
82
|
+
fragmentMapperInstantiator,
|
|
83
|
+
}
|
package/src/generators.js
CHANGED
|
@@ -182,10 +182,10 @@ class Generators {
|
|
|
182
182
|
const generator = this.generators[igenerator]
|
|
183
183
|
if (await generator.matches(args, objects, context, hierarchy, config, options)) {
|
|
184
184
|
const log = (message) => { this.logs.push(message) }
|
|
185
|
-
// this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${
|
|
185
|
+
// this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
|
|
186
186
|
let errorMessage = 'The apply function did not return a value'
|
|
187
187
|
try {
|
|
188
|
-
generated = await generator.apply(args, objects, context, hierarchy, config, response, log)
|
|
188
|
+
generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
|
|
189
189
|
} catch (e) {
|
|
190
190
|
// the next if handle this
|
|
191
191
|
generated = null
|
|
@@ -202,7 +202,7 @@ class Generators {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
if (!generated && generated !== '') {
|
|
205
|
-
const widths = [10, 10
|
|
205
|
+
const widths = Lines.addRemainder([10, 10])
|
|
206
206
|
const lines = new Lines(widths)
|
|
207
207
|
lines.setElement(0, 0, 'Generator')
|
|
208
208
|
const source = `${generator.km}/#${generator.index}`
|
|
@@ -212,7 +212,7 @@ class Generators {
|
|
|
212
212
|
lines.newRow()
|
|
213
213
|
lines.setElement(0, 1, 'TO')
|
|
214
214
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
|
215
|
-
lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth:
|
|
215
|
+
lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 10 }), null, 2))
|
|
216
216
|
lines.newRow()
|
|
217
217
|
lines.setElement(0, 1, 'STACK')
|
|
218
218
|
lines.setElement(0, 2, stack)
|
|
@@ -230,7 +230,7 @@ class Generators {
|
|
|
230
230
|
throw { error: [message], logs: this.logs }
|
|
231
231
|
}
|
|
232
232
|
if (((config || {}).config || {}).debug) {
|
|
233
|
-
const widths = [10, 10
|
|
233
|
+
const widths = Lines.addRemainder([10, 10])
|
|
234
234
|
const lines = new Lines(widths)
|
|
235
235
|
lines.setElement(0, 0, 'Generator')
|
|
236
236
|
if (generator.index > -1 && generator.km) {
|
|
@@ -263,7 +263,7 @@ class Generators {
|
|
|
263
263
|
}
|
|
264
264
|
args.calls.pop()
|
|
265
265
|
if (!applied && ((config || {}).config || {}).debug) {
|
|
266
|
-
const widths = [10, 10
|
|
266
|
+
const widths = Lines.addRemainder([10, 10])
|
|
267
267
|
const lines = new Lines(widths)
|
|
268
268
|
lines.setElement(0, 0, 'Generator')
|
|
269
269
|
lines.setElement(0, 2, 'No generator applied')
|
|
@@ -275,7 +275,11 @@ class Generators {
|
|
|
275
275
|
lines.setElement(0, 2, JSON.stringify(context, null, 2))
|
|
276
276
|
this.logs.push(lines.toString())
|
|
277
277
|
}
|
|
278
|
-
|
|
278
|
+
let parenthesized = false
|
|
279
|
+
if (config && config.getParenthesized()) {
|
|
280
|
+
parenthesized = true
|
|
281
|
+
}
|
|
282
|
+
return parenthesized ? '(' + generated + ')' : generated
|
|
279
283
|
}
|
|
280
284
|
}
|
|
281
285
|
|
package/src/helpers.js
CHANGED
|
@@ -292,8 +292,53 @@ const hashCode = (str) => {
|
|
|
292
292
|
return hash
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
/**
|
|
296
|
+
* Recursively sorts object keys alphabetically.
|
|
297
|
+
* Fully handles arrays (including objects inside arrays) and preserves Date/other non-plain objects.
|
|
298
|
+
*
|
|
299
|
+
* @param {any} input - The value to sort (object, array, primitive, etc.)
|
|
300
|
+
* @param {Object} [options]
|
|
301
|
+
* - ignoreCase: boolean (default false) – case-insensitive sort
|
|
302
|
+
* - reverse: boolean (default false) – reverse alphabetical order
|
|
303
|
+
* @returns {any} New sorted value
|
|
304
|
+
*/
|
|
305
|
+
function sortJson(input, options = {}) {
|
|
306
|
+
const { ignoreCase = false, reverse = false } = options;
|
|
307
|
+
|
|
308
|
+
// Helper: is this a plain object {} (not Array, Date, Map, null, etc.)
|
|
309
|
+
function isPlainObject(value) {
|
|
310
|
+
return value !== null && typeof value === 'object' && value.constructor === Object;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Handle arrays: map over elements and recurse
|
|
314
|
+
if (Array.isArray(input)) {
|
|
315
|
+
return input.map(item => sortJson(item, options));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// If not a plain object, return unchanged (preserves Date, Map, Set, primitives, etc.)
|
|
319
|
+
if (!isPlainObject(input)) {
|
|
320
|
+
return input;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Sorter for keys
|
|
324
|
+
const sorter = (a, b) => {
|
|
325
|
+
const A = ignoreCase ? a.toLowerCase() : a;
|
|
326
|
+
const B = ignoreCase ? b.toLowerCase() : b;
|
|
327
|
+
return reverse ? B.localeCompare(A) : A.localeCompare(B);
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
// Build new sorted object
|
|
331
|
+
const sorted = {};
|
|
332
|
+
|
|
333
|
+
Object.keys(input)
|
|
334
|
+
.sort(sorter)
|
|
335
|
+
.forEach(key => {
|
|
336
|
+
const value = input[key];
|
|
337
|
+
// Always recurse: handles nested objects and arrays properly
|
|
338
|
+
sorted[key] = sortJson(value, options);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
return sorted;
|
|
297
342
|
}
|
|
298
343
|
|
|
299
344
|
const validProps = (valids, object, type) => {
|
|
@@ -436,6 +481,63 @@ const stableId = (tag) => {
|
|
|
436
481
|
return id
|
|
437
482
|
}
|
|
438
483
|
|
|
484
|
+
function getByPath(obj, path, defaultValue) {
|
|
485
|
+
let current = obj;
|
|
486
|
+
for (const key of path) {
|
|
487
|
+
if (current === null || current === undefined) return defaultValue;
|
|
488
|
+
if (typeof current !== 'object') return defaultValue;
|
|
489
|
+
current = current[key];
|
|
490
|
+
}
|
|
491
|
+
return current === undefined ? defaultValue : current;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Set a value in an object by path array.
|
|
496
|
+
* Automatically creates missing objects {} or arrays [] as needed.
|
|
497
|
+
*
|
|
498
|
+
* @param {Object} obj - The root object to modify
|
|
499
|
+
* @param {Array<string|number>} path - Array of keys/indices
|
|
500
|
+
* @param {*} value - Value to set
|
|
501
|
+
* @returns {*} The set value (for chaining)
|
|
502
|
+
*/
|
|
503
|
+
function setByPath(obj, path, value) {
|
|
504
|
+
if (!Array.isArray(path) || path.length === 0) {
|
|
505
|
+
throw new Error('Path must be a non-empty array');
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
let current = obj;
|
|
509
|
+
|
|
510
|
+
for (let i = 0; i < path.length; i++) {
|
|
511
|
+
const key = path[i];
|
|
512
|
+
const isLast = i === path.length - 1;
|
|
513
|
+
|
|
514
|
+
if (isLast) {
|
|
515
|
+
// Final step — just assign
|
|
516
|
+
current[key] = value;
|
|
517
|
+
} else {
|
|
518
|
+
// Not last — ensure next level exists
|
|
519
|
+
const nextKey = path[i + 1];
|
|
520
|
+
|
|
521
|
+
if (current[key] == null) {
|
|
522
|
+
// Auto-create: array if next key is number, otherwise object
|
|
523
|
+
current[key] = typeof nextKey === 'number' || String(nextKey >>> 0) === nextKey
|
|
524
|
+
? []
|
|
525
|
+
: {};
|
|
526
|
+
} else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
|
|
527
|
+
// Safety: if current is array but next key isn't a valid index → convert to object
|
|
528
|
+
current[key] = { ...current[key] };
|
|
529
|
+
} else if (!Array.isArray(current[key]) && typeof nextKey === 'number') {
|
|
530
|
+
// If next expects array but current is object → convert
|
|
531
|
+
current[key] = Object.values(current[key]);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
current = current[key];
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return value;
|
|
539
|
+
}
|
|
540
|
+
|
|
439
541
|
module.exports = {
|
|
440
542
|
stableId,
|
|
441
543
|
ecatch,
|
|
@@ -463,4 +565,6 @@ module.exports = {
|
|
|
463
565
|
w,
|
|
464
566
|
suggestAssociationsFix,
|
|
465
567
|
suggestAssociationsFixFromSummaries,
|
|
568
|
+
getByPath,
|
|
569
|
+
setByPath,
|
|
466
570
|
}
|
package/src/project2.js
CHANGED
|
@@ -3,6 +3,13 @@ function project(source, filters) {
|
|
|
3
3
|
return source
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
function isPlainObject(obj) {
|
|
7
|
+
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
8
|
+
}
|
|
9
|
+
if (!isPlainObject(source) && !Array.isArray(source)) {
|
|
10
|
+
return source
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
if (Object.keys(source).length === 0 && filters.length === 0) {
|
|
7
14
|
return {};
|
|
8
15
|
}
|
package/src/semantics.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { args: contextArgs, normalizeGenerator, normalizeSemantic } = require('./helpers')
|
|
2
2
|
const Lines = require('../lines')
|
|
3
3
|
const helpers = require('./helpers')
|
|
4
|
+
const debug = require('./debug')
|
|
4
5
|
|
|
5
6
|
class Semantic {
|
|
6
7
|
// constructor ({match, apply, uuid, index, km, notes}) {
|
|
@@ -70,6 +71,7 @@ class Semantic {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
async matches (args, context, options = {}) {
|
|
74
|
+
args = {...args}
|
|
73
75
|
this.fixUpArgs(args, context)
|
|
74
76
|
const matches = await this.matcher(args)
|
|
75
77
|
if (matches && (options.debug || {}).match || args.callId === this.callId) {
|
|
@@ -81,6 +83,7 @@ class Semantic {
|
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
async apply (args, context, s, options = {}) {
|
|
86
|
+
args = {...args}
|
|
84
87
|
const { config } = args
|
|
85
88
|
if (config && config.debugLoops) {
|
|
86
89
|
console.log('apply', this.toLabel())
|
|
@@ -218,7 +221,7 @@ class Semantics {
|
|
|
218
221
|
errorMessage = e.toString()
|
|
219
222
|
}
|
|
220
223
|
|
|
221
|
-
const widths = [10, 10
|
|
224
|
+
const widths = Lines.addRemainder([10, 10])
|
|
222
225
|
const lines = new Lines(widths)
|
|
223
226
|
lines.setElement(0, 0, 'Semantic')
|
|
224
227
|
const source = `${semantic.km}/#${semantic.index}`
|
|
@@ -248,7 +251,7 @@ class Semantics {
|
|
|
248
251
|
args.calls.touch(contextPrime)
|
|
249
252
|
// this.logs.push(`Semantics: applied ${semantic.toString()}\n to\n ${JSON.stringify(context)}\n the result was ${JSON.stringify(contextPrime)}\n`)
|
|
250
253
|
if (((config || {}).config || {}).debug) {
|
|
251
|
-
const widths = [10, 10
|
|
254
|
+
const widths = Lines.addRemainder([10, 10])
|
|
252
255
|
const lines = new Lines(widths)
|
|
253
256
|
lines.setElement(0, 0, 'Semantic')
|
|
254
257
|
if (semantic.index > -1 && semantic.km) {
|
|
@@ -295,7 +298,7 @@ class Semantics {
|
|
|
295
298
|
}
|
|
296
299
|
args.calls.pop()
|
|
297
300
|
if (!applied && ((config || {}).config || {}).debug) {
|
|
298
|
-
const widths = [10, 10
|
|
301
|
+
const widths = Lines.addRemainder([10, 10])
|
|
299
302
|
const lines = new Lines(widths)
|
|
300
303
|
lines.setElement(0, 0, 'Semantic')
|
|
301
304
|
lines.setElement(0, 2, 'No semantic applied')
|