theprogrammablemind 9.5.1-beta.3 → 9.5.1-beta.31
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 +72 -27
- package/lines.js +7 -0
- package/package.json +5 -4
- package/runtime.js +0 -1
- package/src/config.js +158 -60
- 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 +54 -4
- 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) => {
|
|
@@ -46,33 +45,33 @@ const getSuggestionMessage = (suggestion) => {
|
|
|
46
45
|
return `Try adding this to the associations: { context: ${JSON.stringify(getSuggestion(suggestion))}, choose: <indexOfMainElement> },\n If that does not work look at the logs and check when the operators become wrong during an interation. Deduce the change based on the previous iteration and what operator was applied.`
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
const getConfig_getContextCheck = (testConfig) => {
|
|
50
|
-
return (testConfig.checks && testConfig.checks.context) || []
|
|
51
|
-
}
|
|
52
|
-
|
|
53
48
|
const pickContext = (contextChecks) => (context) => {
|
|
54
49
|
return project2(context, contextChecks)
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
const pickObjects = (config, testConfig, getObjects) => {
|
|
58
|
-
/*
|
|
59
|
-
let testConfigName = config.name
|
|
60
|
-
if (testConfig.testModuleName) {
|
|
61
|
-
objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
|
|
62
|
-
testConfigName = testConfig.testModuleName
|
|
63
|
-
}
|
|
64
|
-
*/
|
|
65
53
|
const checks = getConfig_getObjectsCheck(config, testConfig)
|
|
54
|
+
const contextChecks = config.getContextChecks()
|
|
66
55
|
const projection = {}
|
|
67
56
|
for (const km in checks) {
|
|
68
57
|
const objects = getObjects(km)
|
|
69
58
|
if (!objects) {
|
|
70
59
|
throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
|
|
71
60
|
}
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
|
|
62
|
+
if (false) {
|
|
63
|
+
if (checks[km] && checks[km].find((check) => check.match && check.apply)) {
|
|
64
|
+
projection[km] = project2(objects, checks[km])
|
|
65
|
+
} else {
|
|
66
|
+
projection[km] = project(objects, checks[km])
|
|
67
|
+
}
|
|
74
68
|
} else {
|
|
75
|
-
|
|
69
|
+
const lastIndex = contextChecks.length - 1
|
|
70
|
+
const last = contextChecks[lastIndex]
|
|
71
|
+
contextChecks[lastIndex] = { match: last.match, apply: () => [...new Set([...(checks[km] || []), ...last.apply()])] }
|
|
72
|
+
|
|
73
|
+
// projection[km] = project2(objects, [...checks[km], ...contextChecks])
|
|
74
|
+
projection[km] = project2(objects, contextChecks)
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
return projection
|
|
@@ -316,6 +315,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
316
315
|
}
|
|
317
316
|
|
|
318
317
|
let startCounter = 0
|
|
318
|
+
let contextIdCounter = 0
|
|
319
319
|
while (true) {
|
|
320
320
|
if (queries.length === 0) {
|
|
321
321
|
break
|
|
@@ -356,8 +356,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
356
356
|
}
|
|
357
357
|
const summary = { summaries: json.summaries, length: json.contexts.length }
|
|
358
358
|
summaries.push(summary)
|
|
359
|
-
const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
360
|
-
await processContextsB({ isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
359
|
+
const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
360
|
+
await processContextsB({ contextIdCounter, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
361
|
+
contextIdCounter = updatedContextIdCounter
|
|
361
362
|
if (isTest) {
|
|
362
363
|
const end = runtime.performance.performance.now()
|
|
363
364
|
clientSideTime = end - start
|
|
@@ -475,6 +476,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
|
|
|
475
476
|
return
|
|
476
477
|
}
|
|
477
478
|
// initialize in between test so state is not preserved since the test was adding without state
|
|
479
|
+
config.testConfig.testModuleName = testConfig.testModuleName
|
|
478
480
|
await config.rebuild()
|
|
479
481
|
const errorHandler = (error) => {
|
|
480
482
|
if (error.metadata) {
|
|
@@ -838,7 +840,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
|
838
840
|
}
|
|
839
841
|
console.log(responses.trace)
|
|
840
842
|
|
|
841
|
-
if (
|
|
843
|
+
if (false) {
|
|
842
844
|
if (global.beforeObjects) {
|
|
843
845
|
console.log('objects', runtime.jsonDiff.diffString(global.beforeObjects, config.get('objects')))
|
|
844
846
|
} else {
|
|
@@ -913,7 +915,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
|
913
915
|
console.log('')
|
|
914
916
|
const screen_width = process.stdout.columns
|
|
915
917
|
// || 0 for when running without a console
|
|
916
|
-
const widths = [70, 10
|
|
918
|
+
const widths = Lines.addRemainder([70, 10])
|
|
917
919
|
const lines = new Lines(widths)
|
|
918
920
|
lines.setElement(0, 0, '--- The paraphrases are ----------')
|
|
919
921
|
lines.setElement(0, 2, '--- The response strings are ----------')
|
|
@@ -970,7 +972,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
970
972
|
if (instance.fragments) {
|
|
971
973
|
pr = instance.fragments[index]
|
|
972
974
|
}
|
|
973
|
-
return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics:
|
|
975
|
+
return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics: true })
|
|
974
976
|
}
|
|
975
977
|
|
|
976
978
|
const looper = async (configs) => {
|
|
@@ -1324,13 +1326,32 @@ const knowledgeModuleImpl = async ({
|
|
|
1324
1326
|
parser.add_argument('-cl', '--checkForLoop', { nargs: '?', help: 'Check for loops in the priorities, Optional argument is list of operator keys to consider. For example [["banana", 0], ["food", 1]]' })
|
|
1325
1327
|
parser.add_argument('-r', '--reset', { action: 'store_true', help: 'Get the server to bypass the cache and rebuild everything' })
|
|
1326
1328
|
parser.add_argument('-q', '--query', { help: 'Run the specified query' })
|
|
1329
|
+
parser.add_argument('-f', '--filter', { help: 'for -pd only the data for the knowledge modules that start with this string will be shown' })
|
|
1327
1330
|
parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
|
|
1328
1331
|
parser.add_argument('-qp ', '--queryParams', { help: 'Query params for the server call' })
|
|
1329
1332
|
parser.add_argument('-dt', '--deleteTest', { help: 'Delete the specified query from the tests file.' })
|
|
1330
1333
|
parser.add_argument('--parenthesized', { action: 'store_true', help: 'Show the generated phrases with parenthesis.' })
|
|
1331
1334
|
parser.add_argument('-c', '--clean', { help: 'Remove data from the test files. a === association' })
|
|
1332
1335
|
parser.add_argument('-od', '--objectDiff', { action: 'store_true', help: 'When showing the objects use a colour diff' })
|
|
1333
|
-
parser.add_argument('-p', '--print', { help:
|
|
1336
|
+
parser.add_argument('-p', '--print', { help:
|
|
1337
|
+
`Print the specified elements
|
|
1338
|
+
a === associations
|
|
1339
|
+
b === bridges,
|
|
1340
|
+
c === config,
|
|
1341
|
+
cc === test checks,
|
|
1342
|
+
d === objects (d for data),
|
|
1343
|
+
g === generators,
|
|
1344
|
+
h === hierarchy,
|
|
1345
|
+
ha === hierarchy ancestors,
|
|
1346
|
+
j === JSON sent to server,
|
|
1347
|
+
l === load ordering,
|
|
1348
|
+
o === operators,
|
|
1349
|
+
p === priorities,
|
|
1350
|
+
s === semantics,
|
|
1351
|
+
t === tests ordering,
|
|
1352
|
+
w === words,
|
|
1353
|
+
for example --print wb' })
|
|
1354
|
+
` })
|
|
1334
1355
|
parser.add_argument('-s', '--save', { action: 'store_true', help: 'When running with the --query flag this will save the current run to the test file. When running without the --query flag all tests will be run and resaved.' })
|
|
1335
1356
|
parser.add_argument('-fr', '--failRebuild', { action: 'store_true', help: 'If a rebuild is required fail out.' })
|
|
1336
1357
|
parser.add_argument('-sd', '--saveDeveloper', { action: 'store_true', help: 'Same as -s but the query will not show up in the info command.' })
|
|
@@ -1491,6 +1512,12 @@ const knowledgeModuleImpl = async ({
|
|
|
1491
1512
|
counter += 1
|
|
1492
1513
|
}
|
|
1493
1514
|
}
|
|
1515
|
+
if (hasArg('cc')) {
|
|
1516
|
+
for (const cc of config.getContextChecks()) {
|
|
1517
|
+
const printable = { ...cc, match: cc.match.toString(), apply: cc.apply.toString() }
|
|
1518
|
+
console.log(JSON.stringify(printable, null, 2))
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1494
1521
|
if (hasArg('c')) {
|
|
1495
1522
|
const { data } = setupProcessB({ config })
|
|
1496
1523
|
console.log('Config as sent to server')
|
|
@@ -1554,8 +1581,19 @@ const knowledgeModuleImpl = async ({
|
|
|
1554
1581
|
}
|
|
1555
1582
|
|
|
1556
1583
|
if (hasArg('d')) {
|
|
1557
|
-
|
|
1558
|
-
|
|
1584
|
+
if (args.filter) {
|
|
1585
|
+
console.log(`objects (data) filtered by ${args.filter} ================`)
|
|
1586
|
+
const projection = { namespaced: {} }
|
|
1587
|
+
for (const key of Object.keys(config.config.objects.namespaced)) {
|
|
1588
|
+
if (key.startsWith(args.filter)) {
|
|
1589
|
+
projection.namespaced[key] = config.config.objects.namespaced[key]
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
console.log(JSON.stringify(projection, null, 2))
|
|
1593
|
+
} else {
|
|
1594
|
+
console.log('objects (data) ================')
|
|
1595
|
+
console.log(JSON.stringify(config.config.objects, null, 2))
|
|
1596
|
+
}
|
|
1559
1597
|
}
|
|
1560
1598
|
|
|
1561
1599
|
if (hasArg('p')) {
|
|
@@ -2008,9 +2046,15 @@ const ensureTestFile = (module, name, type) => {
|
|
|
2008
2046
|
}
|
|
2009
2047
|
|
|
2010
2048
|
const knowledgeModule = async (...args) => {
|
|
2011
|
-
await knowledgeModuleImpl(...args).catch((e) => {
|
|
2049
|
+
await knowledgeModuleImpl(...args).catch(async (e) => {
|
|
2012
2050
|
console.error(e)
|
|
2013
|
-
|
|
2051
|
+
function sleep(ms) {
|
|
2052
|
+
return new Promise((resolve) => {
|
|
2053
|
+
setTimeout(resolve, ms);
|
|
2054
|
+
});
|
|
2055
|
+
}
|
|
2056
|
+
await sleep(1) // get the stderr to flush
|
|
2057
|
+
await process.exit(-1); // tiny trick: empty write forces flush of console.error buffer
|
|
2014
2058
|
})
|
|
2015
2059
|
}
|
|
2016
2060
|
|
|
@@ -2035,5 +2079,6 @@ module.exports = {
|
|
|
2035
2079
|
gs,
|
|
2036
2080
|
flattens,
|
|
2037
2081
|
writeTest,
|
|
2038
|
-
getConfigForTest
|
|
2082
|
+
getConfigForTest,
|
|
2083
|
+
debug,
|
|
2039
2084
|
}
|
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.31",
|
|
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
|
}
|
|
@@ -347,6 +346,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
347
346
|
config.testConfig.checks.context = []
|
|
348
347
|
}
|
|
349
348
|
config.testConfig.checks.context.push({
|
|
349
|
+
'bridge.id': bridge.id,
|
|
350
|
+
'bridge.check': bridge.check,
|
|
350
351
|
match: ({context}) => context.marker == bridge.id,
|
|
351
352
|
exported: true,
|
|
352
353
|
apply: ({context}) => bridge.check,
|
|
@@ -401,11 +402,15 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
401
402
|
if (bridge.generatorp) {
|
|
402
403
|
const match = bridge.generatorp.match || (() => true)
|
|
403
404
|
const apply = typeof bridge.generatorp === 'function' ? bridge.generatorp : bridge.generatorp.apply || bridge.generatorp
|
|
404
|
-
|
|
405
|
+
let level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
|
|
406
|
+
if (!bridge.bridge) {
|
|
407
|
+
level = 0
|
|
408
|
+
}
|
|
405
409
|
|
|
406
410
|
const generator = {
|
|
407
411
|
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),
|
|
412
|
+
// match: async (args) => bridge.id === args.context.marker && args.context.level === level && args.context.paraphrase && await match(args),
|
|
413
|
+
match: async (args) => args.isA(args.context.marker, bridge.id) && args.context.level === level && args.context.paraphrase && await match(args),
|
|
409
414
|
apply: (args) => apply(args),
|
|
410
415
|
applyWrapped: apply,
|
|
411
416
|
property: 'generatorp'
|
|
@@ -422,7 +427,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
422
427
|
const level = bridge.generatorr.level >= 0 ? bridge.generatorr.level : bridge.level + 1
|
|
423
428
|
const generator = {
|
|
424
429
|
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),
|
|
430
|
+
// match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
|
|
431
|
+
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
432
|
apply: (args) => apply(args),
|
|
427
433
|
applyWrapped: apply,
|
|
428
434
|
property: 'generatorr'
|
|
@@ -509,8 +515,43 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
|
509
515
|
if (moreConfig.bridges) {
|
|
510
516
|
moreConfig.bridges = moreConfig.bridges.map((bridge) => {
|
|
511
517
|
bridge = { ...bridge }
|
|
512
|
-
const valid = [
|
|
513
|
-
'
|
|
518
|
+
const valid = [
|
|
519
|
+
'after',
|
|
520
|
+
'associations',
|
|
521
|
+
'before',
|
|
522
|
+
'bridge',
|
|
523
|
+
'check',
|
|
524
|
+
'children',
|
|
525
|
+
'conditional',
|
|
526
|
+
'convolution',
|
|
527
|
+
'disabled',
|
|
528
|
+
'enhanced_associations',
|
|
529
|
+
'evaluator',
|
|
530
|
+
'evaluators',
|
|
531
|
+
'generatorp',
|
|
532
|
+
'generatorpr',
|
|
533
|
+
'generatorr',
|
|
534
|
+
'generators',
|
|
535
|
+
'id',
|
|
536
|
+
'inverted',
|
|
537
|
+
'isA',
|
|
538
|
+
'level',
|
|
539
|
+
'levelSpecificHierarchy',
|
|
540
|
+
'localHierarchy',
|
|
541
|
+
'operator',
|
|
542
|
+
'optional',
|
|
543
|
+
'parents',
|
|
544
|
+
'return_type_selector',
|
|
545
|
+
'scope',
|
|
546
|
+
'selector',
|
|
547
|
+
'semantic',
|
|
548
|
+
'semantics',
|
|
549
|
+
'separators',
|
|
550
|
+
'skipable',
|
|
551
|
+
'uuid',
|
|
552
|
+
'where',
|
|
553
|
+
'words', /Bridge$/,
|
|
554
|
+
]
|
|
514
555
|
helpers.validProps(valid, bridge, 'bridge')
|
|
515
556
|
handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
|
|
516
557
|
return bridge
|
|
@@ -673,7 +714,7 @@ function setWordsUUIDs (words, uuid) {
|
|
|
673
714
|
for (const key in literals) {
|
|
674
715
|
literals[key] = literals[key].map((o) => Object.assign(o, { uuid }))
|
|
675
716
|
}
|
|
676
|
-
const patterns = words.patterns
|
|
717
|
+
const patterns = words.patterns || []
|
|
677
718
|
for (const pattern of patterns) {
|
|
678
719
|
pattern.defs.map((def) => Object.assign(def, { uuid }))
|
|
679
720
|
}
|
|
@@ -902,6 +943,10 @@ class Config {
|
|
|
902
943
|
return config_toServer(config)
|
|
903
944
|
}
|
|
904
945
|
|
|
946
|
+
async run(handler) {
|
|
947
|
+
return configHelpers.run(this, handler)
|
|
948
|
+
}
|
|
949
|
+
|
|
905
950
|
async fixtures () {
|
|
906
951
|
if (this.testConfig?.fixtures) {
|
|
907
952
|
const args = {}
|
|
@@ -935,6 +980,7 @@ class Config {
|
|
|
935
980
|
|
|
936
981
|
getPseudoConfig (uuid, config) {
|
|
937
982
|
return {
|
|
983
|
+
pseudo: true,
|
|
938
984
|
description: 'this is a pseudo config that has limited functionality due to being available in the initializer and fixtures function context',
|
|
939
985
|
addAssociation: (...args) => this.addAssociation(...args),
|
|
940
986
|
addAssociations: (...args) => this.addAssociations(...args),
|
|
@@ -948,6 +994,14 @@ class Config {
|
|
|
948
994
|
removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
|
|
949
995
|
addWord: (...args) => this.addWord(...args, uuid),
|
|
950
996
|
addPattern: (...args) => this.addPattern(...args, uuid),
|
|
997
|
+
updateBridge: (...args) => this.updateBridge(...args),
|
|
998
|
+
processContext: (...args) => this.processContext(...args),
|
|
999
|
+
|
|
1000
|
+
semantics: () => this.config.semantics,
|
|
1001
|
+
getConfigs: () => this.configs,
|
|
1002
|
+
getTests: () => this.getTests(),
|
|
1003
|
+
getName: () => this.getName(),
|
|
1004
|
+
getDescription: () => this.getDescription(),
|
|
951
1005
|
|
|
952
1006
|
getHierarchy: (...args) => this.config.hierarchy,
|
|
953
1007
|
getBridges: (...args) => this.config.bridges,
|
|
@@ -957,10 +1011,33 @@ class Config {
|
|
|
957
1011
|
fragment: (...args) => this.fragment(...args),
|
|
958
1012
|
server: (...args) => this.server(...args),
|
|
959
1013
|
exists: (...args) => this.exists(...args),
|
|
960
|
-
addAPI: (...args) => this.addAPI(...args)
|
|
1014
|
+
addAPI: (...args) => this.addAPI(...args),
|
|
1015
|
+
|
|
1016
|
+
getParenthesized: () => this.getParenthesized(),
|
|
1017
|
+
setParenthesized: (...args) => this.setParenthesized(...args),
|
|
961
1018
|
}
|
|
962
1019
|
}
|
|
963
1020
|
|
|
1021
|
+
getName() {
|
|
1022
|
+
return this.name
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
getDescription() {
|
|
1026
|
+
return this.description
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
getTests() {
|
|
1030
|
+
return this.tests
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
getParenthesized(value) {
|
|
1034
|
+
return this.parenthesized
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
setParenthesized(value) {
|
|
1038
|
+
this.parenthesized = value
|
|
1039
|
+
}
|
|
1040
|
+
|
|
964
1041
|
inDevelopmentMode (call) {
|
|
965
1042
|
config.developmentModeOn += 1
|
|
966
1043
|
try {
|
|
@@ -1107,59 +1184,52 @@ class Config {
|
|
|
1107
1184
|
return instance
|
|
1108
1185
|
}
|
|
1109
1186
|
|
|
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) {
|
|
1187
|
+
getFragment(query) {
|
|
1144
1188
|
for (const instance of (this.instances || [])) {
|
|
1145
1189
|
for (const fragment of (instance.fragments || [])) {
|
|
1146
1190
|
if (fragment.query === query) {
|
|
1147
|
-
return
|
|
1191
|
+
return fragment
|
|
1148
1192
|
}
|
|
1149
1193
|
}
|
|
1150
1194
|
for (const fragment of (instance.resultss || [])) {
|
|
1151
1195
|
if (fragment.isFragment && fragment.query === query) {
|
|
1152
|
-
return
|
|
1196
|
+
return fragment
|
|
1153
1197
|
}
|
|
1154
1198
|
}
|
|
1155
1199
|
for (const fragment of (this.fragmentsBeingBuilt || [])) {
|
|
1156
1200
|
if (fragment.query === query) {
|
|
1157
|
-
return
|
|
1201
|
+
return fragment
|
|
1158
1202
|
}
|
|
1159
1203
|
}
|
|
1160
1204
|
}
|
|
1161
1205
|
}
|
|
1162
1206
|
|
|
1207
|
+
// mappings are optional
|
|
1208
|
+
async fragment (args, query, mappings) {
|
|
1209
|
+
const fragment = this.getFragment(query)
|
|
1210
|
+
if (fragment) {
|
|
1211
|
+
let fi = fragmentInstantiator(args, fragment.contexts)
|
|
1212
|
+
if (mappings) {
|
|
1213
|
+
fi = await fi
|
|
1214
|
+
return fi.instantiate([{
|
|
1215
|
+
match: ({context}) => !!mappings[context.value], // is the value in the mappings
|
|
1216
|
+
apply: ({context}) => Object.assign(context, mappings[context.value]),
|
|
1217
|
+
}])
|
|
1218
|
+
} else {
|
|
1219
|
+
return fi
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
fragmentMapper (args, values, fromModelQuery, toModelQuery) {
|
|
1225
|
+
const fromModelFragment = this.getFragment(fromModelQuery)
|
|
1226
|
+
console.dir(fromModelFragment)
|
|
1227
|
+
const toModelFragment = this.getFragment(toModelQuery)
|
|
1228
|
+
console.dir(toModelFragment)
|
|
1229
|
+
const mapper = fragmentMapperInstantiator(values, fromModelFragment.contexts, toModelFragment.contexts)
|
|
1230
|
+
return mapper
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1163
1233
|
// { rebuild: false, isModule: false }
|
|
1164
1234
|
needsRebuild (template, instance, options) {
|
|
1165
1235
|
if (options.rebuild) {
|
|
@@ -1518,6 +1588,11 @@ class Config {
|
|
|
1518
1588
|
}
|
|
1519
1589
|
}
|
|
1520
1590
|
|
|
1591
|
+
updateBridge(id, updater) {
|
|
1592
|
+
const bridge = this.config.bridges.find((b) => b.id === id)
|
|
1593
|
+
updater({ config: this, bridge })
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1521
1596
|
addBridge (bridge, uuid) {
|
|
1522
1597
|
if (!this.config.bridges) {
|
|
1523
1598
|
this.config.bridges = []
|
|
@@ -1819,7 +1894,7 @@ class Config {
|
|
|
1819
1894
|
|
|
1820
1895
|
// set the args in the api's
|
|
1821
1896
|
setArgs (args) {
|
|
1822
|
-
const
|
|
1897
|
+
const setConfigArgs = (config) => {
|
|
1823
1898
|
if (!config._api) {
|
|
1824
1899
|
return
|
|
1825
1900
|
}
|
|
@@ -1832,10 +1907,10 @@ class Config {
|
|
|
1832
1907
|
}
|
|
1833
1908
|
}
|
|
1834
1909
|
|
|
1835
|
-
|
|
1910
|
+
setConfigArgs(this)
|
|
1836
1911
|
for (const config of this.configs) {
|
|
1837
1912
|
if (config.config instanceof Config) {
|
|
1838
|
-
|
|
1913
|
+
setConfigArgs(config.config)
|
|
1839
1914
|
}
|
|
1840
1915
|
}
|
|
1841
1916
|
}
|
|
@@ -1864,6 +1939,16 @@ class Config {
|
|
|
1864
1939
|
}
|
|
1865
1940
|
}
|
|
1866
1941
|
|
|
1942
|
+
getObjects () {
|
|
1943
|
+
const configs = {}
|
|
1944
|
+
const ns = this.config.objects.namespaced
|
|
1945
|
+
configs[this.name] = this
|
|
1946
|
+
for (const config of this.configs) {
|
|
1947
|
+
configs[config._name] = ns[config._uuid]
|
|
1948
|
+
}
|
|
1949
|
+
return configs
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1867
1952
|
getConfig (name) {
|
|
1868
1953
|
if (this.name === name) {
|
|
1869
1954
|
return this
|
|
@@ -1911,12 +1996,7 @@ class Config {
|
|
|
1911
1996
|
} else if (this.scope == 'development') {
|
|
1912
1997
|
new_result = !(element.scope === 'testing')
|
|
1913
1998
|
}
|
|
1914
|
-
|
|
1915
|
-
global.GORDO = false
|
|
1916
|
-
console.log("THERE WAS A DIFFERENCE ------------------------------------------------")
|
|
1917
|
-
debugger // greg23old
|
|
1918
|
-
}
|
|
1919
|
-
return old_result
|
|
1999
|
+
return new_result
|
|
1920
2000
|
}
|
|
1921
2001
|
|
|
1922
2002
|
config.operators = config.operators.filter((element) => keep(element))
|
|
@@ -2707,19 +2787,37 @@ class Config {
|
|
|
2707
2787
|
|
|
2708
2788
|
getContextChecks() {
|
|
2709
2789
|
const allChecks = []
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
for (const
|
|
2713
|
-
|
|
2714
|
-
|
|
2790
|
+
let defaults = () => []
|
|
2791
|
+
if (this.loadOrdering) {
|
|
2792
|
+
for (const name of this.loadOrdering) {
|
|
2793
|
+
const checks = this.kms[name].testConfig?.checks?.context || []
|
|
2794
|
+
const oldDefaults = defaults
|
|
2795
|
+
for (const check of checks) {
|
|
2796
|
+
if (!check.match) {
|
|
2797
|
+
const oldDefaults = defaults
|
|
2798
|
+
defaults = () => [...new Set([...check.apply(), ...oldDefaults()])]
|
|
2799
|
+
continue
|
|
2800
|
+
}
|
|
2801
|
+
if (check.exported) {
|
|
2802
|
+
allChecks.push(check)
|
|
2803
|
+
}
|
|
2715
2804
|
}
|
|
2716
2805
|
}
|
|
2717
2806
|
}
|
|
2718
2807
|
for (const check of this.testConfig?.checks?.context || []) {
|
|
2808
|
+
if (!check.match) {
|
|
2809
|
+
const oldDefaults = defaults
|
|
2810
|
+
defaults = () => [...new Set([...check.apply(), ...oldDefaults()])]
|
|
2811
|
+
continue
|
|
2812
|
+
}
|
|
2719
2813
|
if (!check.exported) {
|
|
2720
2814
|
allChecks.push(check)
|
|
2721
2815
|
}
|
|
2722
2816
|
}
|
|
2817
|
+
allChecks.push({
|
|
2818
|
+
match: () => true,
|
|
2819
|
+
apply: defaults
|
|
2820
|
+
})
|
|
2723
2821
|
return allChecks
|
|
2724
2822
|
}
|
|
2725
2823
|
|
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
|
@@ -1,7 +1,32 @@
|
|
|
1
|
-
function
|
|
1
|
+
function areFirstNEqual(arr1, arr2, n) {
|
|
2
|
+
if (n <= 0) return true;
|
|
3
|
+
if (arr1.length < n || arr2.length < n) return false;
|
|
4
|
+
|
|
5
|
+
for (let i = 0; i < n; i++) {
|
|
6
|
+
if (arr1[i] !== arr2[i]) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function project(source, filters, path=[]) {
|
|
2
14
|
if (['string', 'number'].includes(typeof source)) {
|
|
3
15
|
return source
|
|
4
16
|
}
|
|
17
|
+
if (Array.isArray(source)) {
|
|
18
|
+
const result = []
|
|
19
|
+
for (const value of source) {
|
|
20
|
+
result.push(project(value, filters, [...path, '*']))
|
|
21
|
+
}
|
|
22
|
+
return result
|
|
23
|
+
}
|
|
24
|
+
function isPlainObject(obj) {
|
|
25
|
+
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
26
|
+
}
|
|
27
|
+
if (!isPlainObject(source) && !Array.isArray(source)) {
|
|
28
|
+
return source
|
|
29
|
+
}
|
|
5
30
|
|
|
6
31
|
if (Object.keys(source).length === 0 && filters.length === 0) {
|
|
7
32
|
return {};
|
|
@@ -11,7 +36,7 @@ function project(source, filters) {
|
|
|
11
36
|
const filter = filters.find(f => f.match({ context: source }));
|
|
12
37
|
if (!filter) {
|
|
13
38
|
if (Array.isArray(source)) {
|
|
14
|
-
return source.map((element) => project(element, filters))
|
|
39
|
+
return source.map((element) => project(element, filters, [...path, '*']))
|
|
15
40
|
}
|
|
16
41
|
return {};
|
|
17
42
|
}
|
|
@@ -22,6 +47,7 @@ function project(source, filters) {
|
|
|
22
47
|
// update
|
|
23
48
|
const updatedProperties = []
|
|
24
49
|
for (const property of properties) {
|
|
50
|
+
// property that contains a list of properties to be checked
|
|
25
51
|
if (property.properties) {
|
|
26
52
|
for (const moreProperty of source[property.properties] || []) {
|
|
27
53
|
updatedProperties.push(moreProperty)
|
|
@@ -35,10 +61,34 @@ function project(source, filters) {
|
|
|
35
61
|
// Build the result object
|
|
36
62
|
const result = {};
|
|
37
63
|
properties.forEach(prop => {
|
|
38
|
-
if (source.hasOwnProperty(prop)) {
|
|
64
|
+
if (prop.path && (prop.path.length === path.length + 1) && areFirstNEqual(path, prop.path, path.length) && source.hasOwnProperty(prop.path[path.length])) {
|
|
65
|
+
const endProp = prop.path[path.length]
|
|
66
|
+
if (Array.isArray(source[endProp])) {
|
|
67
|
+
result[endProp] = []
|
|
68
|
+
for (const key in source[endProp]) {
|
|
69
|
+
result[endProp].push(project(source[endProp][key], filters, [...path, endProp, key]))
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
result[endProp] = {}
|
|
73
|
+
for (const key in source[endProp]) {
|
|
74
|
+
result[endProp][key] = project(source[endProp][key], filters, [...path, endProp, key])
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else if (source.hasOwnProperty(prop)) {
|
|
39
78
|
// If the property is an object and not null, recursively project it
|
|
40
79
|
if (typeof source[prop] === 'object' && source[prop] !== null) {
|
|
41
|
-
result[prop] = project(source[prop], filters);
|
|
80
|
+
result[prop] = project(source[prop], filters, [...path, prop]);
|
|
81
|
+
} else {
|
|
82
|
+
// Copy primitive or null properties directly
|
|
83
|
+
result[prop] = source[prop];
|
|
84
|
+
}
|
|
85
|
+
} else if (prop.property && source.hasOwnProperty(prop.property)) {
|
|
86
|
+
// If the property is an object and not null, recursively project it
|
|
87
|
+
if (typeof source[prop.property] === 'object' && source[prop.property] !== null) {
|
|
88
|
+
result[prop.property] = {}
|
|
89
|
+
for (const key of prop.check) {
|
|
90
|
+
result[prop.property][key] = project(source[prop.property][key], filters, [...path, prop.property, key]);
|
|
91
|
+
}
|
|
42
92
|
} else {
|
|
43
93
|
// Copy primitive or null properties directly
|
|
44
94
|
result[prop] = source[prop];
|
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')
|