theprogrammablemind 9.7.1 → 9.8.0
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 +63 -41
- package/index.js +5 -2
- package/package.json +1 -1
- package/src/config.js +33 -3
- package/src/configHelpers.js +31 -13
- package/src/debug.js +17 -2
- package/src/digraph.js +18 -16
- package/src/digraph_internal.js +20 -12
- package/src/flatten.js +15 -19
- package/src/fragments.js +29 -2
- package/src/generators.js +26 -15
- package/src/helpers.js +73 -22
- package/src/project2.js +4 -0
- package/src/semantics.js +35 -24
package/client.js
CHANGED
|
@@ -12,7 +12,7 @@ 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 { sortJson, appendNoDups, InitCalls, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps } = require('./src/helpers')
|
|
15
|
+
const { helpDebugHierarchy, sortJson, appendNoDups, InitCalls, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps, OverrideCheck, } = require('./src/helpers')
|
|
16
16
|
const runtime = require('./runtime')
|
|
17
17
|
const db = require('./src/debug')
|
|
18
18
|
|
|
@@ -167,10 +167,12 @@ const writeTest = (fn, query, objects, generated, paraphrases, responses, contex
|
|
|
167
167
|
if (runtime.fs.existsSync(fn)) {
|
|
168
168
|
tests = JSON.parse(runtime.fs.readFileSync(fn))
|
|
169
169
|
}
|
|
170
|
+
/*
|
|
170
171
|
for (const association of associations) {
|
|
171
172
|
association.sort()
|
|
172
173
|
}
|
|
173
174
|
associations.sort()
|
|
175
|
+
*/
|
|
174
176
|
// tests[query] = sortJson({ paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
|
|
175
177
|
const results = sortJson({
|
|
176
178
|
query,
|
|
@@ -265,7 +267,7 @@ const throwErrorHandler = (error) => {
|
|
|
265
267
|
throw error
|
|
266
268
|
}
|
|
267
269
|
|
|
268
|
-
const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
|
|
270
|
+
const _process = async (config, query, { queryNumber, initializer, commandLineArgs, credentials, writeTests, logs, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
|
|
269
271
|
if (credentials) {
|
|
270
272
|
config.server(credentials.server, credentials.key)
|
|
271
273
|
}
|
|
@@ -296,11 +298,12 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
296
298
|
// '\\n' from tests of '\n' from users. the former is because newline is not a valid json character so the testfile has it encoded
|
|
297
299
|
let queries = query.split(/\\n|\n/)
|
|
298
300
|
const summaries = [] // for error
|
|
301
|
+
logs = logs || []
|
|
299
302
|
try {
|
|
300
303
|
const response = {
|
|
301
304
|
hierarchy: [],
|
|
302
305
|
load_cache_time: 0.0,
|
|
303
|
-
logs:
|
|
306
|
+
logs: logs,
|
|
304
307
|
metadata: {
|
|
305
308
|
opChoices: []
|
|
306
309
|
},
|
|
@@ -334,6 +337,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
334
337
|
data.utterance = queries[0]
|
|
335
338
|
data.start_counter = startCounter
|
|
336
339
|
let json = await doWithRetries(retries, url, queryParams, data)
|
|
340
|
+
if (json.logs) {
|
|
341
|
+
logs.push(...json.logs)
|
|
342
|
+
}
|
|
337
343
|
let resetData = false
|
|
338
344
|
if (json.code === 'NOT_IN_CACHE') {
|
|
339
345
|
resetData = true
|
|
@@ -367,28 +373,26 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
367
373
|
const summary = { summaries: json.summaries, length: json.contexts.length }
|
|
368
374
|
summaries.push(summary)
|
|
369
375
|
const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
370
|
-
await processContextsB({ contextIdCounter, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
376
|
+
await processContextsB({ contextIdCounter, logs, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
371
377
|
contextIdCounter = updatedContextIdCounter
|
|
372
378
|
if (isTest) {
|
|
373
379
|
const end = runtime.performance.performance.now()
|
|
374
380
|
clientSideTime = end - start
|
|
375
381
|
}
|
|
376
|
-
response.associations = json.associations
|
|
382
|
+
// response.associations = json.associations
|
|
377
383
|
response.learned_contextual_priorities = json.learned_contextual_priorities
|
|
378
384
|
response.hierarchy = json.hierarchy
|
|
379
385
|
response.load_cache_time += json.load_cache_time
|
|
380
|
-
appendNoDups(response.logs, json.logs)
|
|
381
386
|
response.memory_free_percent = json.memory_free_percent
|
|
382
|
-
// appendNoDups(response.metadata.associations, json.metadata.associations)
|
|
383
|
-
// appendNoDups(response.metadata.priorities, json.metadata.priorities)
|
|
384
387
|
appendNoDups(response.metadata.opChoices, json.metadata.opChoices)
|
|
385
388
|
response.times += json.times
|
|
386
389
|
response.clientSideTimes += clientSideTime
|
|
387
390
|
response.trace = response.trace.concat(json.trace)
|
|
388
391
|
response.version = json.version
|
|
389
392
|
response.explain_priorities = json.explain_priorities
|
|
393
|
+
response.explain_associations = json.explain_associations
|
|
390
394
|
response.contextual_priorities_ambiguities = json.contextual_priorities_ambiguities
|
|
391
|
-
response.rtf_associations = json.rtf_associations
|
|
395
|
+
// response.rtf_associations = json.rtf_associations
|
|
392
396
|
|
|
393
397
|
response.contexts = response.contexts.concat(contextsPrime)
|
|
394
398
|
response.generated = response.generated.concat(generatedPrime)
|
|
@@ -414,6 +418,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
414
418
|
return response
|
|
415
419
|
} catch (error) {
|
|
416
420
|
error.summaries = summaries
|
|
421
|
+
error.queryNumber = queryNumber
|
|
417
422
|
error.query = query
|
|
418
423
|
errorHandler(error)
|
|
419
424
|
}
|
|
@@ -479,7 +484,7 @@ const getConfigForTest = (config, testConfig) => {
|
|
|
479
484
|
return configForTest
|
|
480
485
|
}
|
|
481
486
|
|
|
482
|
-
const runTest = async (config, expected, { args, verbose, testConfig, debug, timings = { server: 0, client: 0 } }) => {
|
|
487
|
+
const runTest = async (config, expected, { args, verbose, testConfig, debug, timings = { server: 0, client: 0 }, index = 0 }) => {
|
|
483
488
|
const test = expected.query
|
|
484
489
|
if (args.query && args.query != test) {
|
|
485
490
|
// no run this
|
|
@@ -506,16 +511,17 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
|
|
|
506
511
|
setupArgs(args, config)
|
|
507
512
|
await testConfig.initializer(args)
|
|
508
513
|
}
|
|
509
|
-
const result = await _process(config, test, { errorHandler, isTest: true, isProcess: true, isModule: false })
|
|
514
|
+
const result = await _process(config, test, { queryNumber: args.queryNumber, errorHandler, isTest: true, isProcess: true, isModule: false })
|
|
510
515
|
result.query = test
|
|
511
516
|
if (debug) {
|
|
512
517
|
defaultInnerProcess(config, errorHandler, result)
|
|
513
518
|
}
|
|
514
519
|
if (verbose) {
|
|
515
|
-
const widths = [100, 60]
|
|
520
|
+
const widths = [4, 100, 60]
|
|
516
521
|
const lines = new Lines(widths)
|
|
517
|
-
lines.setElement(0, 0,
|
|
518
|
-
lines.setElement(0, 1,
|
|
522
|
+
lines.setElement(0, 0, index)
|
|
523
|
+
lines.setElement(0, 1, test)
|
|
524
|
+
lines.setElement(0, 2, `time on server: ${result.times.toFixed(2)} client: ${(result.clientSideTimes / 1000).toFixed(2)}`)
|
|
519
525
|
timings.server += result.times
|
|
520
526
|
timings.client += result.clientSideTimes / 1000
|
|
521
527
|
lines.log()
|
|
@@ -618,18 +624,23 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
|
|
|
618
624
|
|
|
619
625
|
const runTestsHelper = async (config, tests, failed, juicyBits) => {
|
|
620
626
|
const { stopAtFirstError } = juicyBits
|
|
627
|
+
let index = 0
|
|
621
628
|
while (true) {
|
|
622
629
|
if (tests.length === 0) {
|
|
623
630
|
return Promise.resolve(failed)
|
|
624
631
|
}
|
|
625
632
|
const test = tests.shift()
|
|
633
|
+
juicyBits.index = index
|
|
634
|
+
juicyBits.args.queryNumber = index
|
|
626
635
|
const result = await runTest(config, test, juicyBits)
|
|
627
636
|
if (result != null) {
|
|
637
|
+
result.index = index
|
|
628
638
|
failed.push(result)
|
|
629
639
|
if (stopAtFirstError) {
|
|
630
640
|
return failed
|
|
631
641
|
}
|
|
632
642
|
}
|
|
643
|
+
index += 1
|
|
633
644
|
}
|
|
634
645
|
}
|
|
635
646
|
|
|
@@ -678,13 +689,6 @@ const saveTests = (config, testFile, testConfig) => {
|
|
|
678
689
|
return saveTestsHelper(testFile, config, tests, tests.map((test) => test.query), testConfig)
|
|
679
690
|
}
|
|
680
691
|
|
|
681
|
-
/*
|
|
682
|
-
const showExamples = (testFile) => {
|
|
683
|
-
const tests = JSON.parse(fs.readFileSync(testFile))
|
|
684
|
-
Object.keys(tests).forEach((test) => console.log(test))
|
|
685
|
-
}
|
|
686
|
-
*/
|
|
687
|
-
|
|
688
692
|
const showInfo = (description, section, config) => {
|
|
689
693
|
console.log(JSON.stringify(config.getInfo(), null, 2))
|
|
690
694
|
}
|
|
@@ -798,7 +802,7 @@ const defaultErrorHandler = async (error) => {
|
|
|
798
802
|
}
|
|
799
803
|
|
|
800
804
|
if (error.query) {
|
|
801
|
-
console.log(
|
|
805
|
+
console.log(`query: #${error.queryNumber} ${error.query}`)
|
|
802
806
|
doErrorExit = true
|
|
803
807
|
}
|
|
804
808
|
|
|
@@ -890,6 +894,11 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
|
890
894
|
console.log(` inputs: ${JSON.stringify(inputs)} output: ${JSON.stringify(output)} reason: ${reason}`)
|
|
891
895
|
}
|
|
892
896
|
}
|
|
897
|
+
|
|
898
|
+
if (responses.explain_associations) {
|
|
899
|
+
console.log(responses.explain_associations)
|
|
900
|
+
}
|
|
901
|
+
|
|
893
902
|
// const objects = config.get('objects').namespaced[config.uuid]
|
|
894
903
|
const actualGetObjects = (name) => {
|
|
895
904
|
if (!name) {
|
|
@@ -1066,7 +1075,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1066
1075
|
config.fragmentsBeingBuilt.push({ query: query.query, contexts: results.contexts })
|
|
1067
1076
|
}
|
|
1068
1077
|
accumulators.summaries = accumulators.summaries.concat(results.summaries)
|
|
1069
|
-
accumulators.associations = accumulators.associations.concat(results.associations)
|
|
1078
|
+
// accumulators.associations = accumulators.associations.concat(results.associations)
|
|
1070
1079
|
accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
|
|
1071
1080
|
await looper(configs)
|
|
1072
1081
|
} catch (e) {
|
|
@@ -1102,7 +1111,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1102
1111
|
await looper([])
|
|
1103
1112
|
} else {
|
|
1104
1113
|
try {
|
|
1105
|
-
config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true })
|
|
1114
|
+
config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true, addFirst: true })
|
|
1106
1115
|
} catch (e) {
|
|
1107
1116
|
const where = extraConfig.where ? ` ${extraConfig.where}` : ''
|
|
1108
1117
|
throw new Error(`Error processing extra config${where}: ${e.stack}}`)
|
|
@@ -1124,7 +1133,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1124
1133
|
associations.sort()
|
|
1125
1134
|
}
|
|
1126
1135
|
const stabilizeOutput = (template) => {
|
|
1127
|
-
stabilizeAssociations(template.associations)
|
|
1136
|
+
// stabilizeAssociations(template.associations)
|
|
1128
1137
|
const stabilize = (results) => {
|
|
1129
1138
|
for (let i = 0; i < results.length; ++i) {
|
|
1130
1139
|
const result = results[i]
|
|
@@ -1138,8 +1147,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1138
1147
|
delete result.memory_free_percent
|
|
1139
1148
|
delete result.logs
|
|
1140
1149
|
delete result.version
|
|
1141
|
-
result.
|
|
1142
|
-
stabilizeAssociations(result.associations)
|
|
1150
|
+
// stabilizeAssociations(result.associations)
|
|
1143
1151
|
result.learned_contextual_priorities = safeNoDups(result.learned_contextual_priorities)
|
|
1144
1152
|
}
|
|
1145
1153
|
}
|
|
@@ -1314,7 +1322,6 @@ const knowledgeModuleImpl = async ({
|
|
|
1314
1322
|
|
|
1315
1323
|
const helpDebugWord = 'In order to get a debug break when a specific word is created set the DEBUG_WORD environment variable to the JSON of the association to break on. For example DEBUG_WORD=\'"the"\''
|
|
1316
1324
|
const helpDebugAssociation = 'In order to get a debug break when a specific association is created set the DEBUG_ASSOCIATION environment variable to the JSON of the association to break on. For example DEBUG_ASSOCIATION=\'[["the", 0], ["mammal", 1]]\''
|
|
1317
|
-
const helpDebugHierarchy = 'In order to get a debug break when a specific hierarchy is created set the DEBUG_HIERARCHY environment variable to the JSON of the child-parent pair to break on. For example DEBUG_HIERARCHY=\'[["cat", 1], ["mammel", 1]]\''
|
|
1318
1325
|
const helpDebugPriority = 'In order to get a debug break when a specific set of priorities is created set set DEBUG_PRIORITY environment variable to the JSON of the priorities that you want to break on. For example DEBUG_PRIORITY=\'[["verb", 0], ["article", 0]]\''
|
|
1319
1326
|
const helpDebugContextualPriority = 'In order to get a debug break when a specific set of contextual priorities is created set set DEBUG_CONTEXTUAL_PRIORITY environment variable to the JSON of the priorities that you want to break on. For example DEBUG_CONTEXTUAL_PRIORITY=\'{ context: [["verb", 0], ["article", 0], select: 1}\''
|
|
1320
1327
|
const helpDebugBridge = 'In order to get a debug break when a specific bridge is created set the DEBUG_BRIDGE environment variable to id to break on. For example DEBUG_BRIDGE=\'car\''
|
|
@@ -1337,6 +1344,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1337
1344
|
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]]' })
|
|
1338
1345
|
parser.add_argument('-r', '--reset', { action: 'store_true', help: 'Get the server to bypass the cache and rebuild everything' })
|
|
1339
1346
|
parser.add_argument('-q', '--query', { help: 'Run the specified query' })
|
|
1347
|
+
parser.add_argument('-qn', '--queryNumber', { help: 'Run the query specified by the given index' })
|
|
1340
1348
|
parser.add_argument('-f', '--filter', { help: 'for -pd only the data for the knowledge modules that start with this string will be shown' })
|
|
1341
1349
|
parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
|
|
1342
1350
|
parser.add_argument('--trace', { action: 'store_true', help: 'Trace the semantics and generator calls.' })
|
|
@@ -1376,6 +1384,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1376
1384
|
parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
|
|
1377
1385
|
parser.add_argument('-db', '--debugBridge', { action: 'store_true', help: helpDebugBridge })
|
|
1378
1386
|
parser.add_argument('-do', '--debugOperator', { action: 'store_true', help: helpDebugOperator })
|
|
1387
|
+
parser.add_argument('-ea', '--explainAssociations', { action: 'store_true', help: 'The server will return information about the associations used to decide on the interpretation.' })
|
|
1379
1388
|
parser.add_argument('-ep', '--explainPriorities', { action: 'store_true', help: 'The server will return all priorities including the generated one along with an explanation of there they came from' })
|
|
1380
1389
|
parser.add_argument('-dic', '--debugIncludeConvolutions', { nargs: '?', help: 'When running with the --debugIncludeConvolutions flag the logs will include convolutions which are somewhat annoyingly verbose. Default is false' })
|
|
1381
1390
|
parser.add_argument('-bc', '--bypassCache', { action: 'store_true', help: 'Bypass the cache on the server side and rebuild' })
|
|
@@ -1383,6 +1392,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1383
1392
|
const args = parser.parse_args()
|
|
1384
1393
|
args.count = args.count || 1
|
|
1385
1394
|
|
|
1395
|
+
if (args.queryNumber) {
|
|
1396
|
+
args.query = test.contents[args.queryNumber].query
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1386
1399
|
if (args.rebuildTemplateFull) {
|
|
1387
1400
|
args.rebuildTemplate = true
|
|
1388
1401
|
}
|
|
@@ -1476,9 +1489,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1476
1489
|
|
|
1477
1490
|
if (args.deleteTest) {
|
|
1478
1491
|
let tests = JSON.parse(runtime.fs.readFileSync(testConfig.name))
|
|
1492
|
+
const nTests = tests.length
|
|
1479
1493
|
tests = tests.filter((test) => test.query !== args.deleteTest)
|
|
1480
1494
|
writeTestFile(testConfig.name, tests)
|
|
1481
|
-
console.log(`
|
|
1495
|
+
console.log(`Deleted ${nTests - tests.length} tests for "${args.deleteTest}"`)
|
|
1482
1496
|
return
|
|
1483
1497
|
}
|
|
1484
1498
|
|
|
@@ -1509,6 +1523,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1509
1523
|
config.config.explain_priorities = true
|
|
1510
1524
|
}
|
|
1511
1525
|
|
|
1526
|
+
if (args.explainAssociations) {
|
|
1527
|
+
config.config.explain_associations = true
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1512
1530
|
config.config.debugIncludeConvolutions = args.debugIncludeConvolutions || process.argv.includes('--debugIncludeConvolutions') || process.argv.includes('-dic')
|
|
1513
1531
|
|
|
1514
1532
|
let configPrinted = false
|
|
@@ -1528,7 +1546,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1528
1546
|
console.log('Test queries')
|
|
1529
1547
|
let counter = 0
|
|
1530
1548
|
for (const test of config.tests) {
|
|
1531
|
-
console.log(
|
|
1549
|
+
console.log(`#${counter} - ${test.query}`)
|
|
1532
1550
|
counter += 1
|
|
1533
1551
|
}
|
|
1534
1552
|
}
|
|
@@ -1541,7 +1559,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1541
1559
|
if (hasArg('c')) {
|
|
1542
1560
|
const { data } = setupProcessB({ config })
|
|
1543
1561
|
console.log('Config as sent to server')
|
|
1544
|
-
|
|
1562
|
+
const toPrint = { ...data }
|
|
1563
|
+
toPrint['priorities'] = toPrint['priorities'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
|
|
1564
|
+
toPrint['associations']['positive'] = toPrint['associations']['positive'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
|
|
1565
|
+
console.log(JSON.stringify(toPrint, null, 2).replace(/\\"/g, '"'))
|
|
1545
1566
|
}
|
|
1546
1567
|
if (hasArg('l')) {
|
|
1547
1568
|
console.log('Module load ordering')
|
|
@@ -1635,12 +1656,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1635
1656
|
}
|
|
1636
1657
|
|
|
1637
1658
|
if (hasArg('s')) {
|
|
1638
|
-
|
|
1639
|
-
for (const semantic of easyToRead) {
|
|
1640
|
-
semantic.match = semantic.match.toString()
|
|
1641
|
-
semantic.apply = semantic.apply.toString()
|
|
1642
|
-
}
|
|
1643
|
-
console.dir(easyToRead)
|
|
1659
|
+
config.printSemantics()
|
|
1644
1660
|
}
|
|
1645
1661
|
}
|
|
1646
1662
|
}
|
|
@@ -1757,7 +1773,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1757
1773
|
if (hasError) {
|
|
1758
1774
|
console.log('**************************** ERRORS ************************')
|
|
1759
1775
|
for (const result of results) {
|
|
1760
|
-
console.log(
|
|
1776
|
+
console.log(`Utterance: #${result.index} ${result.utterance}`)
|
|
1761
1777
|
if (!result.hasError) {
|
|
1762
1778
|
continue
|
|
1763
1779
|
}
|
|
@@ -1773,7 +1789,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1773
1789
|
newError = true
|
|
1774
1790
|
headerShown = true
|
|
1775
1791
|
if (args.vimdiff) {
|
|
1776
|
-
vimdiff(actual, expected, `"${label} - ${result.utterance}"`)
|
|
1792
|
+
vimdiff(actual, expected, `"${label} - #${result.index} ${result.utterance}"`)
|
|
1777
1793
|
}
|
|
1778
1794
|
result.hasError = true
|
|
1779
1795
|
}
|
|
@@ -1916,12 +1932,17 @@ const knowledgeModuleImpl = async ({
|
|
|
1916
1932
|
console.log('use -v arg to write files expected.json and actual.json in the current directory for detailed comparison. Or do -s and then git diff the changes.')
|
|
1917
1933
|
// console.log(JSON.stringify(contexts))
|
|
1918
1934
|
let errorCount = 0
|
|
1935
|
+
const failedTests = []
|
|
1919
1936
|
for (const result of results) {
|
|
1920
1937
|
if (result.hasError) {
|
|
1921
|
-
console.log(`FAILED ${result.utterance}`)
|
|
1938
|
+
console.log(`FAILED #${result.index} ${result.utterance}`)
|
|
1939
|
+
failedTests.push({ index: result.index, utterance: result.utterance })
|
|
1922
1940
|
errorCount += 1
|
|
1923
1941
|
}
|
|
1924
1942
|
}
|
|
1943
|
+
const failedFile = './FAILED.json'
|
|
1944
|
+
console.log(`Failed tests are written to ${failedFile}`)
|
|
1945
|
+
runtime.fs.writeFileSync(failedFile, JSON.stringify(failedTests, 0, 2))
|
|
1925
1946
|
console.log(`**************************** THERE WERE ${errorCount} TEST FAILURES ************************`)
|
|
1926
1947
|
}
|
|
1927
1948
|
}
|
|
@@ -1980,7 +2001,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1980
2001
|
global.beforeObjects = _.cloneDeep(objects)
|
|
1981
2002
|
}
|
|
1982
2003
|
try {
|
|
1983
|
-
await processResults(_process(config, args.query, { commandLineArgs: args, isProcess, isModule: !isProcess, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
|
|
2004
|
+
await processResults(_process(config, args.query, { commandLineArgs: args, isProcess, logs: [], isModule: !isProcess, dontAddAssociations: args.dontAddAssociations, writeTests: args.save || args.saveDeveloper, saveDeveloper: args.saveDeveloper, testConfig, testsFN: test }))
|
|
1984
2005
|
} catch (error) {
|
|
1985
2006
|
printConfig()
|
|
1986
2007
|
console.log('Error', error)
|
|
@@ -2104,4 +2125,5 @@ module.exports = {
|
|
|
2104
2125
|
writeTest,
|
|
2105
2126
|
getConfigForTest,
|
|
2106
2127
|
debug: db,
|
|
2128
|
+
OverrideCheck,
|
|
2107
2129
|
}
|
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { Semantics, Semantic } = require('./src/semantics')
|
|
2
2
|
const { Generators, Generator } = require('./src/generators')
|
|
3
3
|
const { Config } = require('./src/config')
|
|
4
|
-
const { w, where } = require('./src/helpers')
|
|
4
|
+
const { w, where, OverrideCheck, setByPath, getByPath } = require('./src/helpers')
|
|
5
5
|
const Digraph = require('./src/digraph')
|
|
6
6
|
const client = require('./client')
|
|
7
7
|
const flattens = require('./src/flatten')
|
|
@@ -16,6 +16,8 @@ module.exports = {
|
|
|
16
16
|
runTests: client.runTests,
|
|
17
17
|
knowledgeModule: client.knowledgeModule,
|
|
18
18
|
ensureTestFile: client.ensureTestFile,
|
|
19
|
+
setByPath,
|
|
20
|
+
getByPath,
|
|
19
21
|
where,
|
|
20
22
|
stableId: client.stableId,
|
|
21
23
|
w,
|
|
@@ -28,5 +30,6 @@ module.exports = {
|
|
|
28
30
|
flattens: flattens.flattens,
|
|
29
31
|
flatten: flattens.flatten,
|
|
30
32
|
unflatten: unflatten.unflatten,
|
|
31
|
-
debug
|
|
33
|
+
debug,
|
|
34
|
+
OverrideCheck,
|
|
32
35
|
}
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -454,7 +454,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
|
454
454
|
// match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
|
|
455
455
|
match: async (args) => {
|
|
456
456
|
if (bridge.callId == args.callId) {
|
|
457
|
-
debugger
|
|
457
|
+
debugger // eslint-disable-line no-debugger
|
|
458
458
|
}
|
|
459
459
|
return args.isA(args.context.marker, bridge.id) && args.context.level === level && !args.context.paraphrase && (args.context.response != null || args.context.isResponse) && await match(args)
|
|
460
460
|
},
|
|
@@ -563,7 +563,7 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
|
563
563
|
'generatorr',
|
|
564
564
|
'generators',
|
|
565
565
|
'id',
|
|
566
|
-
'
|
|
566
|
+
'initial',
|
|
567
567
|
'inverted',
|
|
568
568
|
'isA',
|
|
569
569
|
'level',
|
|
@@ -572,6 +572,7 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
|
572
572
|
'operator',
|
|
573
573
|
'optional',
|
|
574
574
|
'parents',
|
|
575
|
+
'preferOver',
|
|
575
576
|
'return_type_selector',
|
|
576
577
|
'scope',
|
|
577
578
|
'selector',
|
|
@@ -601,7 +602,12 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
|
601
602
|
}
|
|
602
603
|
|
|
603
604
|
if (runtime.process.env.DEBUG_HIERARCHY) {
|
|
604
|
-
|
|
605
|
+
try {
|
|
606
|
+
global.entodictonDebugHierarchy = JSON.parse(runtime.process.env.DEBUG_HIERARCHY)
|
|
607
|
+
} catch( e ) {
|
|
608
|
+
console.error("Invalid valid for DEBUG_HIERARCHY")
|
|
609
|
+
console.error(helpers.helpDebugHierarchy)
|
|
610
|
+
}
|
|
605
611
|
}
|
|
606
612
|
|
|
607
613
|
// i keep randomly doing one of the other so I will just make both work the same way
|
|
@@ -975,6 +981,15 @@ class Config {
|
|
|
975
981
|
return config_toServer(config)
|
|
976
982
|
}
|
|
977
983
|
|
|
984
|
+
printSemantics() {
|
|
985
|
+
const easyToRead = _.cloneDeep(this.config.semantics)
|
|
986
|
+
for (const semantic of easyToRead) {
|
|
987
|
+
semantic.match = semantic.match.toString()
|
|
988
|
+
semantic.apply = semantic.apply.toString()
|
|
989
|
+
}
|
|
990
|
+
console.dir(easyToRead)
|
|
991
|
+
}
|
|
992
|
+
|
|
978
993
|
async run(handler) {
|
|
979
994
|
return configHelpers.run(this, handler)
|
|
980
995
|
}
|
|
@@ -1285,6 +1300,8 @@ class Config {
|
|
|
1285
1300
|
} else {
|
|
1286
1301
|
return fi
|
|
1287
1302
|
}
|
|
1303
|
+
} else {
|
|
1304
|
+
throw new Error(`The fragment for '${query} was not found.`)
|
|
1288
1305
|
}
|
|
1289
1306
|
}
|
|
1290
1307
|
|
|
@@ -1655,6 +1672,7 @@ class Config {
|
|
|
1655
1672
|
}
|
|
1656
1673
|
}
|
|
1657
1674
|
|
|
1675
|
+
// handler/listener
|
|
1658
1676
|
updateBridge(id, updater) {
|
|
1659
1677
|
const bridge = this.config.bridges.find((b) => b.id === id)
|
|
1660
1678
|
updater({ config: this, bridge })
|
|
@@ -1674,6 +1692,7 @@ class Config {
|
|
|
1674
1692
|
return
|
|
1675
1693
|
}
|
|
1676
1694
|
}
|
|
1695
|
+
|
|
1677
1696
|
if (global.transitoryMode) {
|
|
1678
1697
|
def.transitoryMode = true
|
|
1679
1698
|
}
|
|
@@ -2313,6 +2332,7 @@ class Config {
|
|
|
2313
2332
|
}
|
|
2314
2333
|
}
|
|
2315
2334
|
|
|
2335
|
+
// TODO Api or API -> pick one and do that
|
|
2316
2336
|
async setMultiApi (initializer) {
|
|
2317
2337
|
await this.setApi(() => multiApiImpl(initializer))
|
|
2318
2338
|
}
|
|
@@ -2420,11 +2440,17 @@ class Config {
|
|
|
2420
2440
|
if (!api.initialize) {
|
|
2421
2441
|
throw new Error(`Expected the API for ${this.name} to have an initialize function.`)
|
|
2422
2442
|
}
|
|
2443
|
+
if (api.baseAPI) {
|
|
2444
|
+
new helpers.OverrideCheck(api.baseAPI).check(api)
|
|
2445
|
+
}
|
|
2423
2446
|
}
|
|
2424
2447
|
} else {
|
|
2425
2448
|
if (!value.initialize) {
|
|
2426
2449
|
throw new Error(`Expected the API to have an initialize function for ${this.name}. If you are trying to pass in multiple API configs at once use setApiKMs to set the names of the configs that you want set.`)
|
|
2427
2450
|
}
|
|
2451
|
+
if (value.baseAPI) {
|
|
2452
|
+
new helpers.OverrideCheck(value.baseAPI).check(value)
|
|
2453
|
+
}
|
|
2428
2454
|
}
|
|
2429
2455
|
|
|
2430
2456
|
if (this._api && this._api.multiApi) {
|
|
@@ -3368,6 +3394,10 @@ class Config {
|
|
|
3368
3394
|
let duplicated = new Set()
|
|
3369
3395
|
const seen = new Set()
|
|
3370
3396
|
for (const bridge of this.config.bridges) {
|
|
3397
|
+
if (typeof bridge.id !== 'string') {
|
|
3398
|
+
throw new Error('Config.addBridge: expected the bridge id to be a non-empty string.')
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3371
3401
|
const id = `${bridge.id}/${bridge.level} (namespace: ${bridge.uuid || this.uuid})`
|
|
3372
3402
|
if (seen.has(id)) {
|
|
3373
3403
|
duplicated.add(id)
|
package/src/configHelpers.js
CHANGED
|
@@ -145,6 +145,7 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
145
145
|
args.objects = config.get('objects')
|
|
146
146
|
args.getObjects = getObjects(args.objects)
|
|
147
147
|
}
|
|
148
|
+
args.debug = debug
|
|
148
149
|
args.enable = (key) => {
|
|
149
150
|
config.addEnable(key)
|
|
150
151
|
}
|
|
@@ -163,7 +164,23 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
args.contextHierarchy = new ContextHierarchy()
|
|
166
|
-
args.
|
|
167
|
+
args.namespaced = {
|
|
168
|
+
get: (km, context, property, _default) => {
|
|
169
|
+
context.namespaced ??= {}
|
|
170
|
+
context.namespaced[km] ??= {}
|
|
171
|
+
const value = context.namespaced[km][property]
|
|
172
|
+
if (value == undefined) {
|
|
173
|
+
return _default
|
|
174
|
+
}
|
|
175
|
+
return value
|
|
176
|
+
},
|
|
177
|
+
set: (km, context, property, value) => {
|
|
178
|
+
context.namespaced ??= {}
|
|
179
|
+
context.namespaced[km] ??= {}
|
|
180
|
+
return context.namespaced[km][property] = value
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
args.stack = new HandlerStack()
|
|
167
184
|
args.cleanAssign = cleanAssign
|
|
168
185
|
args.km = (name) => config.getConfig(name)
|
|
169
186
|
args.api = (name) => config.getConfig(name).api
|
|
@@ -332,9 +349,11 @@ const processContext = async (context, { objects = {}, config, logs = [] }) => {
|
|
|
332
349
|
const setupProcessB = ({ config, initializer, allowDelta = false, rebuildingTemplate = false } = {}) => {
|
|
333
350
|
const key = config._key
|
|
334
351
|
const data = Object.assign({ key, version: '3' }, { uuid: config._uuid })
|
|
352
|
+
/*
|
|
335
353
|
if (rebuildingTemplate) {
|
|
336
354
|
data.return_rtf_associations = true
|
|
337
355
|
}
|
|
356
|
+
*/
|
|
338
357
|
if (allowDelta && config.allowDelta && config.hasDelta()) {
|
|
339
358
|
// console.log('config', config)
|
|
340
359
|
data.delta = config.delta()
|
|
@@ -392,7 +411,7 @@ const setupContexts = (rawContexts) => {
|
|
|
392
411
|
return contexts
|
|
393
412
|
}
|
|
394
413
|
|
|
395
|
-
const processContextsB = async ({ config, calls, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
|
|
414
|
+
const processContextsB = async ({ config, calls, hierarchy, logs, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
|
|
396
415
|
// TODO fix this name to contextsPrime
|
|
397
416
|
const contextsPrime = []
|
|
398
417
|
const generatedPrime = []
|
|
@@ -404,10 +423,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
404
423
|
|
|
405
424
|
const objects = config.get('objects')
|
|
406
425
|
const args = { objects, isResponse: true, response: json, isTest, isInstance, getObjects: getObjects(objects), instance, contexts, isProcess, isModule, calls }
|
|
407
|
-
|
|
408
|
-
json.logs = []
|
|
409
|
-
}
|
|
410
|
-
setupArgs(args, config, json.logs, hierarchy)
|
|
426
|
+
setupArgs(args, config, logs, hierarchy)
|
|
411
427
|
const toDo = [...contexts]
|
|
412
428
|
args.insert = (context) => toDo.unshift(context)
|
|
413
429
|
let overlap, lastRange
|
|
@@ -425,7 +441,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
425
441
|
}
|
|
426
442
|
const generateParenthesized = isTest || (commandLineArgs && commandLineArgs.save)
|
|
427
443
|
if (!config.get('skipSemantics')) {
|
|
428
|
-
const semantics = config.getSemantics(
|
|
444
|
+
const semantics = config.getSemantics(logs)
|
|
429
445
|
try {
|
|
430
446
|
contextPrime = await semantics.apply(args, context)
|
|
431
447
|
// contextPrime.greg = 'yes'
|
|
@@ -468,11 +484,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
468
484
|
// noop
|
|
469
485
|
} else {
|
|
470
486
|
let assumed = { isResponse: true }
|
|
471
|
-
const generated = contextPrime.isResponse ? await config.getGenerators(
|
|
487
|
+
const generated = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
472
488
|
let generatedParenthesized = []
|
|
473
489
|
if (generateParenthesized) {
|
|
474
490
|
config.setParenthesized(true)
|
|
475
|
-
generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(
|
|
491
|
+
generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
476
492
|
config.setParenthesized(false)
|
|
477
493
|
}
|
|
478
494
|
// assumed = { paraphrase: true, response: false };
|
|
@@ -480,11 +496,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
480
496
|
if (generateParenthesized) {
|
|
481
497
|
config.setParenthesized(false)
|
|
482
498
|
}
|
|
483
|
-
const paraphrases = await config.getGenerators(
|
|
499
|
+
const paraphrases = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
484
500
|
let paraphrasesParenthesized = []
|
|
485
501
|
if (generateParenthesized) {
|
|
486
502
|
config.setParenthesized(true)
|
|
487
|
-
paraphrasesParenthesized = await config.getGenerators(
|
|
503
|
+
paraphrasesParenthesized = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
488
504
|
config.setParenthesized(false)
|
|
489
505
|
}
|
|
490
506
|
contextsPrime.push(contextPrime)
|
|
@@ -513,9 +529,9 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
513
529
|
}
|
|
514
530
|
e.context = contextPrime
|
|
515
531
|
if (e.logs) {
|
|
516
|
-
e.logs = e.logs.concat(
|
|
532
|
+
e.logs = e.logs.concat(logs)
|
|
517
533
|
} else {
|
|
518
|
-
e.logs =
|
|
534
|
+
e.logs = logs
|
|
519
535
|
}
|
|
520
536
|
e.metadata = json.metadata
|
|
521
537
|
if (json.trace) {
|
|
@@ -532,10 +548,12 @@ const loadInstance = async (config, instance) => {
|
|
|
532
548
|
const transitoryMode = global.transitoryMode
|
|
533
549
|
global.transitoryMode = false
|
|
534
550
|
|
|
551
|
+
/*
|
|
535
552
|
const rl = instance.resultss.length
|
|
536
553
|
if (rl > 0) {
|
|
537
554
|
config.addAssociations(instance.resultss[instance.resultss.length - 1].rtf_associations || [])
|
|
538
555
|
}
|
|
556
|
+
*/
|
|
539
557
|
/*
|
|
540
558
|
TODO needs updating if still wanted
|
|
541
559
|
if (instance && (instance.associations || instance.learned_contextual_priorities)) {
|
package/src/debug.js
CHANGED
|
@@ -27,6 +27,18 @@ const unhit = (name) => {
|
|
|
27
27
|
hits[name] = false
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
const hitScoped = async (name, call) => {
|
|
31
|
+
hit(name)
|
|
32
|
+
try {
|
|
33
|
+
const result = await call()
|
|
34
|
+
unhit(name)
|
|
35
|
+
return result
|
|
36
|
+
} catch( e ) {
|
|
37
|
+
unhit(name)
|
|
38
|
+
throw e
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
const wasHit = (name) => {
|
|
31
43
|
return hits[name]
|
|
32
44
|
}
|
|
@@ -64,16 +76,19 @@ const _break = (name) => {
|
|
|
64
76
|
}
|
|
65
77
|
}
|
|
66
78
|
|
|
79
|
+
const breakAt = _break;
|
|
80
|
+
|
|
67
81
|
module.exports = {
|
|
68
82
|
counter,
|
|
69
83
|
get,
|
|
70
84
|
_break, // break is a keyword
|
|
71
|
-
|
|
85
|
+
breakAt,
|
|
72
86
|
// used for tests
|
|
73
87
|
reset,
|
|
74
88
|
hit,
|
|
75
89
|
unhit,
|
|
76
90
|
wasHit,
|
|
77
91
|
getDb,
|
|
78
|
-
setDb
|
|
92
|
+
setDb,
|
|
93
|
+
hitScoped,
|
|
79
94
|
}
|
package/src/digraph.js
CHANGED
|
@@ -73,11 +73,25 @@ class Digraph {
|
|
|
73
73
|
this._edges = edges
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
tos(from) {
|
|
77
|
+
const tos = []
|
|
78
|
+
for (const edge of this._edges) {
|
|
79
|
+
if (edge[0] == from) {
|
|
80
|
+
tos.push(edge[1])
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return tos
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
froms(to) {
|
|
87
|
+
const froms = []
|
|
88
|
+
for (const edge of this._edges) {
|
|
89
|
+
if (edge[1] == to) {
|
|
90
|
+
froms.push(edge[0])
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return froms
|
|
79
94
|
}
|
|
80
|
-
*/
|
|
81
95
|
|
|
82
96
|
acdcs (s, from, to) {
|
|
83
97
|
if (!s) {
|
|
@@ -170,18 +184,6 @@ class Digraph {
|
|
|
170
184
|
return this.minima(common)
|
|
171
185
|
}
|
|
172
186
|
|
|
173
|
-
/*
|
|
174
|
-
maxima (nodes) {
|
|
175
|
-
const maxima = new Set(nodes)
|
|
176
|
-
const descendants = new Set([])
|
|
177
|
-
nodes.forEach((node) => {
|
|
178
|
-
this.descendants(node).forEach((n) => descendants.add(n))
|
|
179
|
-
})
|
|
180
|
-
descendants.forEach((n) => maxima.delete(n))
|
|
181
|
-
return maxima
|
|
182
|
-
}
|
|
183
|
-
*/
|
|
184
|
-
|
|
185
187
|
add (child, parent) {
|
|
186
188
|
this._edges.push([child, parent])
|
|
187
189
|
}
|
package/src/digraph_internal.js
CHANGED
|
@@ -39,6 +39,26 @@ class DigraphInternal {
|
|
|
39
39
|
this._edges = edges
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
tos(from) {
|
|
43
|
+
const tos = []
|
|
44
|
+
for (const edge of this._edges) {
|
|
45
|
+
if (edge[0] == from) {
|
|
46
|
+
tos.push(edge[1])
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return tos
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
froms(to) {
|
|
53
|
+
const froms = []
|
|
54
|
+
for (const edge of this._edges) {
|
|
55
|
+
if (edge[1] == to) {
|
|
56
|
+
froms.push(edge[0])
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return froms
|
|
60
|
+
}
|
|
61
|
+
|
|
42
62
|
get length () {
|
|
43
63
|
return this._edges.length
|
|
44
64
|
}
|
|
@@ -137,18 +157,6 @@ class DigraphInternal {
|
|
|
137
157
|
return this.minima(common)
|
|
138
158
|
}
|
|
139
159
|
|
|
140
|
-
/*
|
|
141
|
-
maxima (nodes) {
|
|
142
|
-
const maxima = new Set(nodes)
|
|
143
|
-
const descendants = new Set([])
|
|
144
|
-
nodes.forEach((node) => {
|
|
145
|
-
this.descendants(node).forEach((n) => descendants.add(n))
|
|
146
|
-
})
|
|
147
|
-
descendants.forEach((n) => maxima.delete(n))
|
|
148
|
-
return maxima
|
|
149
|
-
}
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
160
|
add (child, parent) {
|
|
153
161
|
this._edges.push([child, parent])
|
|
154
162
|
}
|
package/src/flatten.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
const { isArray, isObject, isCompound } = require('./helpers')
|
|
1
|
+
const { isArray, isObject, isCompound, } = require('./helpers')
|
|
2
|
+
const debug = require('./debug')
|
|
2
3
|
const _ = require('lodash')
|
|
3
4
|
|
|
4
|
-
const DEBUG = (
|
|
5
|
+
const DEBUG = (label, details) => {
|
|
5
6
|
// DEBUG(...args)
|
|
6
7
|
}
|
|
7
8
|
|
|
@@ -46,33 +47,24 @@ const zip = (a1, a2) => {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
const flattenListHelper = (markers, values) => {
|
|
49
|
-
const flats = []
|
|
50
50
|
let wasFlattened = false
|
|
51
|
-
|
|
51
|
+
const all = []
|
|
52
52
|
for (const value of values) {
|
|
53
53
|
if (!isCompound(value)) {
|
|
54
|
-
|
|
54
|
+
all.push([value])
|
|
55
55
|
} else {
|
|
56
56
|
const [more, wf] = flatten(markers, value)
|
|
57
57
|
if (wf) {
|
|
58
58
|
wasFlattened = wasFlattened || wf
|
|
59
|
-
|
|
59
|
+
all.push(more)
|
|
60
60
|
} else {
|
|
61
|
-
|
|
61
|
+
all.push(...more.map((m) => [m]))
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return [[singles], wasFlattened]
|
|
69
|
-
} else {
|
|
70
|
-
const results = []
|
|
71
|
-
for (const flat of cartesian(...flats)) {
|
|
72
|
-
results.push(singles.concat(flat))
|
|
73
|
-
}
|
|
74
|
-
return [results, wasFlattened]
|
|
75
|
-
}
|
|
66
|
+
const result = cartesian(...all)
|
|
67
|
+
return [result, wasFlattened]
|
|
76
68
|
}
|
|
77
69
|
|
|
78
70
|
// returns (list, wasFlattened)
|
|
@@ -84,6 +76,9 @@ const flatten = (markers, value) => {
|
|
|
84
76
|
if (value.flatten === false) {
|
|
85
77
|
return [[value], false]
|
|
86
78
|
}
|
|
79
|
+
|
|
80
|
+
const flatten_ignore = value.flatten_ignore || []
|
|
81
|
+
|
|
87
82
|
const marker = value.marker
|
|
88
83
|
let properties = value
|
|
89
84
|
|
|
@@ -113,8 +108,9 @@ const flatten = (markers, value) => {
|
|
|
113
108
|
for (const key in properties) {
|
|
114
109
|
let wf = false
|
|
115
110
|
let values
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
if (flatten_ignore.includes(key)) {
|
|
112
|
+
values = [properties[key]]
|
|
113
|
+
} else if (isObject(properties[key])) {
|
|
118
114
|
const context = properties[key];
|
|
119
115
|
[values, wf] = flatten(markers, context)
|
|
120
116
|
// } else if (isinstance(properties[key], list)) {
|
package/src/fragments.js
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
const _ = require('lodash')
|
|
2
2
|
const helpers = require('./helpers')
|
|
3
3
|
|
|
4
|
+
function createChangeTracker(obj) {
|
|
5
|
+
const changes = new Set();
|
|
6
|
+
|
|
7
|
+
const handler = {
|
|
8
|
+
set(target, prop, value) {
|
|
9
|
+
changes.add(prop);
|
|
10
|
+
target[prop] = value;
|
|
11
|
+
return true;
|
|
12
|
+
},
|
|
13
|
+
deleteProperty(target, prop) {
|
|
14
|
+
changes.add(prop);
|
|
15
|
+
delete target[prop];
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
proxy: new Proxy(obj, handler),
|
|
22
|
+
getChanges: () => Array.from(changes)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
4
27
|
function fragmentInstantiator (args, contexts) {
|
|
5
28
|
return new Object({
|
|
6
29
|
contexts: () => {
|
|
@@ -13,13 +36,15 @@ function fragmentInstantiator (args, contexts) {
|
|
|
13
36
|
args.pathEquals = helpers.pathEquals
|
|
14
37
|
while (todo.length > 0) {
|
|
15
38
|
const { context, path } = todo.pop()
|
|
16
|
-
|
|
39
|
+
const { proxy, getChanges } = createChangeTracker(context);
|
|
40
|
+
args.context = proxy
|
|
17
41
|
args.path = path
|
|
18
42
|
for (const mapping of mappings) {
|
|
19
43
|
if (await mapping.match(args)) {
|
|
20
44
|
await mapping.apply(args)
|
|
21
45
|
}
|
|
22
46
|
}
|
|
47
|
+
const ignore = getChanges()
|
|
23
48
|
for (const key of Object.keys(context)) {
|
|
24
49
|
// if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
|
|
25
50
|
if (!helpers.isCompound(context[key])) {
|
|
@@ -28,7 +53,9 @@ function fragmentInstantiator (args, contexts) {
|
|
|
28
53
|
if (context[key].instantiated) {
|
|
29
54
|
continue
|
|
30
55
|
}
|
|
31
|
-
|
|
56
|
+
if (!ignore.includes(key)) {
|
|
57
|
+
todo.push({ context: context[key], path: [...path, key] })
|
|
58
|
+
}
|
|
32
59
|
}
|
|
33
60
|
}
|
|
34
61
|
if (contexts.length == 1 && instantiated.length == 1) {
|
package/src/generators.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { args: contextArgs, normalizeGenerator } = require('./helpers')
|
|
2
2
|
const Lines = require('../lines')
|
|
3
3
|
const helpers = require('./helpers')
|
|
4
|
+
const debug = require('./debug')
|
|
4
5
|
|
|
5
6
|
class Generator {
|
|
6
7
|
// constructor ({ match, apply, uuid, index, km, priority, notes }) {
|
|
@@ -65,14 +66,16 @@ class Generator {
|
|
|
65
66
|
}
|
|
66
67
|
const args = Object.assign({}, baseArgs, moreArgs, (baseArgs.getUUIDScoped || (() => { return {} }))(this.uuid))
|
|
67
68
|
// return this.match(args)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
return await debug.hitScoped(args.callId, async () => {
|
|
70
|
+
const matches = await this.match(args)
|
|
71
|
+
if ((matches && (options.debug || {}).match) ||
|
|
72
|
+
callId === this.callId) {
|
|
73
|
+
// next line is the matcher
|
|
74
|
+
debugger // eslint-disable-line no-debugger
|
|
75
|
+
await this.match(args)
|
|
76
|
+
}
|
|
77
|
+
return matches
|
|
78
|
+
})
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
// apply (baseArgs, objects, g, gs, context, hierarchy, config, response, log, options = {}) {
|
|
@@ -121,11 +124,12 @@ class Generator {
|
|
|
121
124
|
if (this.property === 'generatorp') {
|
|
122
125
|
args.g = args.gp
|
|
123
126
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
return await debug.hitScoped(args.callId, async () => {
|
|
128
|
+
if ((options.debug || {}).apply || process.env.DEBUG_CALLID == args.callId || callId === this.callId) {
|
|
129
|
+
debugger // eslint-disable-line no-debugger
|
|
130
|
+
}
|
|
131
|
+
return await this._apply(args) // DEBUG: This is the line you want to step into
|
|
132
|
+
})
|
|
129
133
|
}
|
|
130
134
|
}
|
|
131
135
|
|
|
@@ -186,6 +190,13 @@ class Generators {
|
|
|
186
190
|
const log = (message) => { this.logs.push(message) }
|
|
187
191
|
// this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
|
|
188
192
|
let errorMessage = 'The apply function did not return a value'
|
|
193
|
+
if (process.env.TPMKMS_TRACE) {
|
|
194
|
+
console.error("TPMKMS_TRACE", debug.counter("TPMKMS_TRACE"))
|
|
195
|
+
console.error(generator.toLabel())
|
|
196
|
+
console.error(generator.toString())
|
|
197
|
+
console.log(`To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
|
|
198
|
+
}
|
|
199
|
+
|
|
189
200
|
try {
|
|
190
201
|
generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
|
|
191
202
|
} catch (e) {
|
|
@@ -220,7 +231,7 @@ class Generators {
|
|
|
220
231
|
lines.setElement(0, 2, stack)
|
|
221
232
|
lines.newRow()
|
|
222
233
|
lines.setElement(0, 1, 'DEBUG')
|
|
223
|
-
lines.setElement(0, 2, `To debug this use args.
|
|
234
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
|
|
224
235
|
lines.newRow()
|
|
225
236
|
lines.setElement(0, 1, 'ERROR')
|
|
226
237
|
lines.setElement(0, 2, errorMessage)
|
|
@@ -252,7 +263,7 @@ class Generators {
|
|
|
252
263
|
lines.setElement(0, 2, stack)
|
|
253
264
|
lines.newRow()
|
|
254
265
|
lines.setElement(0, 1, 'DEBUG')
|
|
255
|
-
lines.setElement(0, 2, `To debug this use
|
|
266
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
|
|
256
267
|
lines.newRow()
|
|
257
268
|
lines.setElement(0, 1, 'TO')
|
|
258
269
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
package/src/helpers.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
const deepEqual = require('deep-equal')
|
|
2
2
|
const stringify = require('json-stable-stringify')
|
|
3
3
|
|
|
4
|
+
|
|
5
|
+
// check if member function of a class have been overriden by an subclass
|
|
6
|
+
class OverrideCheck {
|
|
7
|
+
constructor(base, suffix='API') {
|
|
8
|
+
this.base = base
|
|
9
|
+
this.checks = Object.getOwnPropertyNames(base.prototype).filter(key => typeof base.prototype[key] === 'function' && key.endsWith(suffix));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
check(obj) {
|
|
13
|
+
const overriden = obj.constructor !== obj.baseAPI
|
|
14
|
+
if (!overriden) {
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
for (const check of this.checks) {
|
|
18
|
+
if (obj[check] == this.base.prototype[check]) {
|
|
19
|
+
throw new Error(`For ${obj.constructor.name} you need to override ${check}`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
4
25
|
function pathEquals (p1, p2) {
|
|
5
26
|
if (p1.length !== p2.length) {
|
|
6
27
|
return false
|
|
@@ -523,52 +544,77 @@ const stableId = (tag) => {
|
|
|
523
544
|
}
|
|
524
545
|
|
|
525
546
|
function getByPath(obj, path, defaultValue) {
|
|
547
|
+
const segments = Array.isArray(path) ? path : [path];
|
|
548
|
+
const keys = segments.flatMap((segment) => {
|
|
549
|
+
if (typeof segment !== "string") return [segment];
|
|
550
|
+
return segment
|
|
551
|
+
.replace(/\[(\d+)\]/g, ".$1")
|
|
552
|
+
.split(".")
|
|
553
|
+
.filter((key) => key !== "");
|
|
554
|
+
});
|
|
555
|
+
|
|
526
556
|
let current = obj;
|
|
527
|
-
for (const key of
|
|
557
|
+
for (const key of keys) {
|
|
528
558
|
if (current === null || current === undefined) return defaultValue;
|
|
529
|
-
if (typeof current !==
|
|
559
|
+
if (typeof current !== "object") return defaultValue;
|
|
530
560
|
current = current[key];
|
|
531
561
|
}
|
|
532
562
|
return current === undefined ? defaultValue : current;
|
|
533
563
|
}
|
|
534
564
|
|
|
565
|
+
function normalizePath(path) {
|
|
566
|
+
const segments = Array.isArray(path) ? path : [path];
|
|
567
|
+
return segments.flatMap((segment) => {
|
|
568
|
+
if (typeof segment !== "string") return [segment];
|
|
569
|
+
return segment
|
|
570
|
+
.replace(/\[(\d+)\]/g, ".$1")
|
|
571
|
+
.split(".")
|
|
572
|
+
.filter((key) => key !== "");
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function isArrayIndex(key) {
|
|
577
|
+
if (typeof key === "number") return Number.isInteger(key) && key >= 0;
|
|
578
|
+
return key !== "" && String(key >>> 0) === String(key);
|
|
579
|
+
}
|
|
580
|
+
|
|
535
581
|
/**
|
|
536
|
-
* Set a value in an object by path array.
|
|
582
|
+
* Set a value in an object by path (string or array).
|
|
537
583
|
* Automatically creates missing objects {} or arrays [] as needed.
|
|
538
584
|
*
|
|
539
585
|
* @param {Object} obj - The root object to modify
|
|
540
|
-
* @param {Array<string|number>} path -
|
|
586
|
+
* @param {string|Array<string|number>} path - Path keys/indices
|
|
541
587
|
* @param {*} value - Value to set
|
|
542
588
|
* @returns {*} The set value (for chaining)
|
|
543
589
|
*/
|
|
544
590
|
function setByPath(obj, path, value) {
|
|
545
|
-
|
|
546
|
-
|
|
591
|
+
const keys = normalizePath(path);
|
|
592
|
+
|
|
593
|
+
if (keys.length === 0) {
|
|
594
|
+
throw new Error("Path must be a non-empty string or array");
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (obj == null || typeof obj !== "object") {
|
|
598
|
+
throw new Error("Target must be an object or array");
|
|
547
599
|
}
|
|
548
600
|
|
|
549
601
|
let current = obj;
|
|
550
602
|
|
|
551
|
-
for (let i = 0; i <
|
|
552
|
-
const key =
|
|
553
|
-
const isLast = i ===
|
|
603
|
+
for (let i = 0; i < keys.length; i++) {
|
|
604
|
+
const key = keys[i];
|
|
605
|
+
const isLast = i === keys.length - 1;
|
|
554
606
|
|
|
555
607
|
if (isLast) {
|
|
556
|
-
// Final step — just assign
|
|
557
608
|
current[key] = value;
|
|
558
609
|
} else {
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
if (current[key] == null) {
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
? []
|
|
566
|
-
: {};
|
|
567
|
-
} else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
|
|
568
|
-
// Safety: if current is array but next key isn't a valid index → convert to object
|
|
610
|
+
const nextKey = keys[i + 1];
|
|
611
|
+
const nextIsIndex = isArrayIndex(nextKey);
|
|
612
|
+
|
|
613
|
+
if (current[key] == null || typeof current[key] !== "object") {
|
|
614
|
+
current[key] = nextIsIndex ? [] : {};
|
|
615
|
+
} else if (Array.isArray(current[key]) && !nextIsIndex) {
|
|
569
616
|
current[key] = { ...current[key] };
|
|
570
|
-
} else if (!Array.isArray(current[key]) &&
|
|
571
|
-
// If next expects array but current is object → convert
|
|
617
|
+
} else if (!Array.isArray(current[key]) && nextIsIndex) {
|
|
572
618
|
current[key] = Object.values(current[key]);
|
|
573
619
|
}
|
|
574
620
|
|
|
@@ -579,7 +625,11 @@ function setByPath(obj, path, value) {
|
|
|
579
625
|
return value;
|
|
580
626
|
}
|
|
581
627
|
|
|
628
|
+
const helpDebugHierarchy = 'In order to get a debug break when a specific hierarchy is created set the DEBUG_HIERARCHY environment variable to the JSON of the child-parent pair to break on. For example DEBUG_HIERARCHY=\'["cat", "mammel"]\''
|
|
629
|
+
|
|
582
630
|
module.exports = {
|
|
631
|
+
helpDebugHierarchy,
|
|
632
|
+
|
|
583
633
|
stableId,
|
|
584
634
|
ecatch,
|
|
585
635
|
functionsToStrings,
|
|
@@ -611,4 +661,5 @@ module.exports = {
|
|
|
611
661
|
assignAssumed,
|
|
612
662
|
watchProperty,
|
|
613
663
|
pathEquals,
|
|
664
|
+
OverrideCheck,
|
|
614
665
|
}
|
package/src/project2.js
CHANGED
|
@@ -101,6 +101,10 @@ function project(source, filters, path=[]) {
|
|
|
101
101
|
} else if (prop.property && source.hasOwnProperty(prop.property)) {
|
|
102
102
|
// If the property is an object and not null, recursively project it
|
|
103
103
|
if (typeof source[prop.property] === 'object' && source[prop.property] !== null) {
|
|
104
|
+
if (prop.all) {
|
|
105
|
+
result[prop.property] = source[prop.property]
|
|
106
|
+
return
|
|
107
|
+
}
|
|
104
108
|
result[prop.property] = {}
|
|
105
109
|
const instantiatedCheck = []
|
|
106
110
|
for (const check of prop.check) {
|
package/src/semantics.js
CHANGED
|
@@ -75,13 +75,16 @@ class Semantic {
|
|
|
75
75
|
async matches (args, context, options = {}) {
|
|
76
76
|
args = {...args}
|
|
77
77
|
this.fixUpArgs(args, context)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
return await debug.hitScoped(args.callId, async () => {
|
|
79
|
+
const matches = await this.matcher(args)
|
|
80
|
+
if (matches) {
|
|
81
|
+
if ((options.debug || {}).match || args.callId === this.callId || process.env.DEBUG_CALLID == args.callId) {
|
|
82
|
+
debugger // eslint-disable-line no-debugger
|
|
83
|
+
await this.matcher(args) // DEBUG: This is the line you step into
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return matches
|
|
87
|
+
})
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
async apply (args, context, s, options = {}) {
|
|
@@ -97,21 +100,24 @@ class Semantic {
|
|
|
97
100
|
const contextPrime = Object.assign({}, context)
|
|
98
101
|
this.fixUpArgs(args, contextPrime)
|
|
99
102
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
103
|
+
return await debug.hitScoped(args.callId, async () => {
|
|
104
|
+
if ((options.debug || {}).apply || args.callId === this.callId || process.env.DEBUG_CALLID == args.callId) {
|
|
105
|
+
debugger // eslint-disable-line no-debugger // STEP ABOUT THREE TIMES TO THE DEBUG LINE
|
|
106
|
+
}
|
|
107
|
+
if (args.breakOnSemantics) {
|
|
108
|
+
debugger // eslint-disable-line no-debugger
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
args.stack.push(this)
|
|
113
|
+
await this._apply(args) // DEBUG: This is the line you want to step into
|
|
114
|
+
args.stack.pop()
|
|
115
|
+
} catch( e ) {
|
|
116
|
+
args.stack.pop()
|
|
117
|
+
throw e
|
|
118
|
+
}
|
|
119
|
+
return contextPrime
|
|
120
|
+
})
|
|
115
121
|
}
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -187,6 +193,8 @@ class Semantics {
|
|
|
187
193
|
let seenQuestion = false
|
|
188
194
|
const deferred = []
|
|
189
195
|
args.log = (message) => { this.logs.push(message) }
|
|
196
|
+
const finallyList = []; // called after the semantic is processed
|
|
197
|
+
args._finally = (call) => finallyList.unshift(call)
|
|
190
198
|
for (const isemantic in this.semantics) {
|
|
191
199
|
const semantic = this.semantics[isemantic]
|
|
192
200
|
// only one question at a time
|
|
@@ -253,7 +261,7 @@ class Semantics {
|
|
|
253
261
|
lines.setElement(0, 2, semantic.toString())
|
|
254
262
|
lines.newRow()
|
|
255
263
|
lines.setElement(0, 1, 'DEBUG')
|
|
256
|
-
lines.setElement(0, 2, `To debug this use args.
|
|
264
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
|
|
257
265
|
lines.newRow()
|
|
258
266
|
lines.setElement(0, 1, 'TO')
|
|
259
267
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
|
@@ -288,7 +296,7 @@ class Semantics {
|
|
|
288
296
|
lines.setElement(0, 2, semantic.toString())
|
|
289
297
|
lines.newRow()
|
|
290
298
|
lines.setElement(0, 1, 'DEBUG')
|
|
291
|
-
lines.setElement(0, 2, `To debug this use args.
|
|
299
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
|
|
292
300
|
lines.newRow()
|
|
293
301
|
lines.setElement(0, 1, 'TO')
|
|
294
302
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
|
@@ -319,6 +327,9 @@ class Semantics {
|
|
|
319
327
|
}
|
|
320
328
|
counter += 1
|
|
321
329
|
}
|
|
330
|
+
for (const f of finallyList) {
|
|
331
|
+
await f()
|
|
332
|
+
}
|
|
322
333
|
args.calls.pop()
|
|
323
334
|
if (!applied && debug) {
|
|
324
335
|
const widths = Lines.addRemainder([10, 10])
|