entodicton 9.7.1-beta.9 → 9.8.0-beta.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 +62 -49
- package/index.js +4 -1
- package/package.json +1 -1
- package/src/config.js +17 -1
- package/src/configHelpers.js +19 -14
- package/src/digraph.js +18 -16
- package/src/digraph_internal.js +20 -12
- package/src/flatten.js +6 -2
- package/src/fragments.js +0 -1
- package/src/generators.js +20 -5
- package/src/helpers.js +100 -22
- package/src/project2.js +4 -0
- package/src/semantics.js +18 -9
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 { helpDebugHierarchy, sortJson, appendNoDups, InitCalls, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps, OverrideCheck, } = require('./src/helpers')
|
|
15
|
+
const { helpDebugHierarchy, sortJson, appendNoDups, InitCalls, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps, OverrideCheck, removeProp, } = require('./src/helpers')
|
|
16
16
|
const runtime = require('./runtime')
|
|
17
17
|
const db = require('./src/debug')
|
|
18
18
|
|
|
@@ -59,20 +59,11 @@ const pickObjects = (config, testConfig, getObjects) => {
|
|
|
59
59
|
throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} else {
|
|
66
|
-
projection[km] = project(objects, checks[km])
|
|
67
|
-
}
|
|
68
|
-
} else {
|
|
69
|
-
const lastIndex = contextChecks.length - 1
|
|
70
|
-
const last = contextChecks[lastIndex]
|
|
71
|
-
contextChecks[lastIndex] = { match: last.match, apply: () => [...new Set([...(checks[km] || []), ...last.apply()])] }
|
|
62
|
+
const lastIndex = contextChecks.length - 1
|
|
63
|
+
const last = contextChecks[lastIndex]
|
|
64
|
+
contextChecks[lastIndex] = { match: last.match, apply: () => [...new Set([...(checks[km] || []), ...last.apply()])] }
|
|
72
65
|
|
|
73
|
-
|
|
74
|
-
projection[km] = project2(objects, contextChecks)
|
|
75
|
-
}
|
|
66
|
+
projection[km] = project2(objects, contextChecks)
|
|
76
67
|
}
|
|
77
68
|
return projection
|
|
78
69
|
}
|
|
@@ -167,10 +158,12 @@ const writeTest = (fn, query, objects, generated, paraphrases, responses, contex
|
|
|
167
158
|
if (runtime.fs.existsSync(fn)) {
|
|
168
159
|
tests = JSON.parse(runtime.fs.readFileSync(fn))
|
|
169
160
|
}
|
|
161
|
+
/*
|
|
170
162
|
for (const association of associations) {
|
|
171
163
|
association.sort()
|
|
172
164
|
}
|
|
173
165
|
associations.sort()
|
|
166
|
+
*/
|
|
174
167
|
// tests[query] = sortJson({ paraphrases, responses, contexts, objects: convertToStable(objects), associations, metadata, config, developerTest: saveDeveloper }, { depth: 25 })
|
|
175
168
|
const results = sortJson({
|
|
176
169
|
query,
|
|
@@ -265,7 +258,7 @@ const throwErrorHandler = (error) => {
|
|
|
265
258
|
throw error
|
|
266
259
|
}
|
|
267
260
|
|
|
268
|
-
const _process = async (config, query, { initializer, commandLineArgs, credentials, writeTests, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
|
|
261
|
+
const _process = async (config, query, { queryNumber, initializer, commandLineArgs, credentials, writeTests, logs, isProcess, isModule, isTest, saveDeveloper, rebuildingTemplate, testConfig, testsFN, errorHandler = throwErrorHandler } = {}) => {
|
|
269
262
|
if (credentials) {
|
|
270
263
|
config.server(credentials.server, credentials.key)
|
|
271
264
|
}
|
|
@@ -296,11 +289,12 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
296
289
|
// '\\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
290
|
let queries = query.split(/\\n|\n/)
|
|
298
291
|
const summaries = [] // for error
|
|
292
|
+
logs = logs || []
|
|
299
293
|
try {
|
|
300
294
|
const response = {
|
|
301
295
|
hierarchy: [],
|
|
302
296
|
load_cache_time: 0.0,
|
|
303
|
-
logs:
|
|
297
|
+
logs: logs,
|
|
304
298
|
metadata: {
|
|
305
299
|
opChoices: []
|
|
306
300
|
},
|
|
@@ -334,6 +328,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
334
328
|
data.utterance = queries[0]
|
|
335
329
|
data.start_counter = startCounter
|
|
336
330
|
let json = await doWithRetries(retries, url, queryParams, data)
|
|
331
|
+
if (json.logs) {
|
|
332
|
+
logs.push(...json.logs)
|
|
333
|
+
}
|
|
337
334
|
let resetData = false
|
|
338
335
|
if (json.code === 'NOT_IN_CACHE') {
|
|
339
336
|
resetData = true
|
|
@@ -367,28 +364,27 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
367
364
|
const summary = { summaries: json.summaries, length: json.contexts.length }
|
|
368
365
|
summaries.push(summary)
|
|
369
366
|
const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
|
|
370
|
-
await processContextsB({ contextIdCounter, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
367
|
+
await processContextsB({ contextIdCounter, logs, calls, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
|
|
371
368
|
contextIdCounter = updatedContextIdCounter
|
|
372
369
|
if (isTest) {
|
|
373
370
|
const end = runtime.performance.performance.now()
|
|
374
371
|
clientSideTime = end - start
|
|
375
372
|
}
|
|
376
|
-
response.associations = json.associations
|
|
373
|
+
// response.associations = json.associations
|
|
377
374
|
response.learned_contextual_priorities = json.learned_contextual_priorities
|
|
378
375
|
response.hierarchy = json.hierarchy
|
|
379
376
|
response.load_cache_time += json.load_cache_time
|
|
380
|
-
appendNoDups(response.logs, json.logs)
|
|
381
377
|
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
378
|
appendNoDups(response.metadata.opChoices, json.metadata.opChoices)
|
|
385
379
|
response.times += json.times
|
|
386
380
|
response.clientSideTimes += clientSideTime
|
|
387
381
|
response.trace = response.trace.concat(json.trace)
|
|
388
382
|
response.version = json.version
|
|
389
383
|
response.explain_priorities = json.explain_priorities
|
|
384
|
+
response.explain_associations_details = (response.explain_associations_details || []).concat(json.explain_associations_details)
|
|
385
|
+
response.explain_associations_trie = json.explain_associations_trie
|
|
390
386
|
response.contextual_priorities_ambiguities = json.contextual_priorities_ambiguities
|
|
391
|
-
response.rtf_associations = json.rtf_associations
|
|
387
|
+
// response.rtf_associations = json.rtf_associations
|
|
392
388
|
|
|
393
389
|
response.contexts = response.contexts.concat(contextsPrime)
|
|
394
390
|
response.generated = response.generated.concat(generatedPrime)
|
|
@@ -414,6 +410,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
|
|
|
414
410
|
return response
|
|
415
411
|
} catch (error) {
|
|
416
412
|
error.summaries = summaries
|
|
413
|
+
error.queryNumber = queryNumber
|
|
417
414
|
error.query = query
|
|
418
415
|
errorHandler(error)
|
|
419
416
|
}
|
|
@@ -506,7 +503,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
|
|
|
506
503
|
setupArgs(args, config)
|
|
507
504
|
await testConfig.initializer(args)
|
|
508
505
|
}
|
|
509
|
-
const result = await _process(config, test, { errorHandler, isTest: true, isProcess: true, isModule: false })
|
|
506
|
+
const result = await _process(config, test, { queryNumber: args.queryNumber, errorHandler, isTest: true, isProcess: true, isModule: false })
|
|
510
507
|
result.query = test
|
|
511
508
|
if (debug) {
|
|
512
509
|
defaultInnerProcess(config, errorHandler, result)
|
|
@@ -626,6 +623,7 @@ const runTestsHelper = async (config, tests, failed, juicyBits) => {
|
|
|
626
623
|
}
|
|
627
624
|
const test = tests.shift()
|
|
628
625
|
juicyBits.index = index
|
|
626
|
+
juicyBits.args.queryNumber = index
|
|
629
627
|
const result = await runTest(config, test, juicyBits)
|
|
630
628
|
if (result != null) {
|
|
631
629
|
result.index = index
|
|
@@ -683,13 +681,6 @@ const saveTests = (config, testFile, testConfig) => {
|
|
|
683
681
|
return saveTestsHelper(testFile, config, tests, tests.map((test) => test.query), testConfig)
|
|
684
682
|
}
|
|
685
683
|
|
|
686
|
-
/*
|
|
687
|
-
const showExamples = (testFile) => {
|
|
688
|
-
const tests = JSON.parse(fs.readFileSync(testFile))
|
|
689
|
-
Object.keys(tests).forEach((test) => console.log(test))
|
|
690
|
-
}
|
|
691
|
-
*/
|
|
692
|
-
|
|
693
684
|
const showInfo = (description, section, config) => {
|
|
694
685
|
console.log(JSON.stringify(config.getInfo(), null, 2))
|
|
695
686
|
}
|
|
@@ -803,7 +794,7 @@ const defaultErrorHandler = async (error) => {
|
|
|
803
794
|
}
|
|
804
795
|
|
|
805
796
|
if (error.query) {
|
|
806
|
-
console.log(
|
|
797
|
+
console.log(`query: #${error.queryNumber} ${error.query}`)
|
|
807
798
|
doErrorExit = true
|
|
808
799
|
}
|
|
809
800
|
|
|
@@ -895,6 +886,14 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
|
895
886
|
console.log(` inputs: ${JSON.stringify(inputs)} output: ${JSON.stringify(output)} reason: ${reason}`)
|
|
896
887
|
}
|
|
897
888
|
}
|
|
889
|
+
|
|
890
|
+
if (responses.explain_associations_details) {
|
|
891
|
+
console.log(responses.explain_associations_trie)
|
|
892
|
+
for (const l of responses.explain_associations_details) {
|
|
893
|
+
console.log(l)
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
|
|
898
897
|
// const objects = config.get('objects').namespaced[config.uuid]
|
|
899
898
|
const actualGetObjects = (name) => {
|
|
900
899
|
if (!name) {
|
|
@@ -1071,7 +1070,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1071
1070
|
config.fragmentsBeingBuilt.push({ query: query.query, contexts: results.contexts })
|
|
1072
1071
|
}
|
|
1073
1072
|
accumulators.summaries = accumulators.summaries.concat(results.summaries)
|
|
1074
|
-
accumulators.associations = accumulators.associations.concat(results.associations)
|
|
1073
|
+
// accumulators.associations = accumulators.associations.concat(results.associations)
|
|
1075
1074
|
accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
|
|
1076
1075
|
await looper(configs)
|
|
1077
1076
|
} catch (e) {
|
|
@@ -1107,7 +1106,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1107
1106
|
await looper([])
|
|
1108
1107
|
} else {
|
|
1109
1108
|
try {
|
|
1110
|
-
config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true })
|
|
1109
|
+
config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true, addFirst: true })
|
|
1111
1110
|
} catch (e) {
|
|
1112
1111
|
const where = extraConfig.where ? ` ${extraConfig.where}` : ''
|
|
1113
1112
|
throw new Error(`Error processing extra config${where}: ${e.stack}}`)
|
|
@@ -1129,8 +1128,9 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1129
1128
|
associations.sort()
|
|
1130
1129
|
}
|
|
1131
1130
|
const stabilizeOutput = (template) => {
|
|
1132
|
-
stabilizeAssociations(template.associations)
|
|
1131
|
+
// stabilizeAssociations(template.associations)
|
|
1133
1132
|
const stabilize = (results) => {
|
|
1133
|
+
removeProp(results, (_, k) => k === "context_id")
|
|
1134
1134
|
for (let i = 0; i < results.length; ++i) {
|
|
1135
1135
|
const result = results[i]
|
|
1136
1136
|
if (result.apply) {
|
|
@@ -1143,8 +1143,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
|
|
|
1143
1143
|
delete result.memory_free_percent
|
|
1144
1144
|
delete result.logs
|
|
1145
1145
|
delete result.version
|
|
1146
|
-
result.
|
|
1147
|
-
stabilizeAssociations(result.associations)
|
|
1146
|
+
// stabilizeAssociations(result.associations)
|
|
1148
1147
|
result.learned_contextual_priorities = safeNoDups(result.learned_contextual_priorities)
|
|
1149
1148
|
}
|
|
1150
1149
|
}
|
|
@@ -1341,6 +1340,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1341
1340
|
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]]' })
|
|
1342
1341
|
parser.add_argument('-r', '--reset', { action: 'store_true', help: 'Get the server to bypass the cache and rebuild everything' })
|
|
1343
1342
|
parser.add_argument('-q', '--query', { help: 'Run the specified query' })
|
|
1343
|
+
parser.add_argument('-qn', '--queryNumber', { help: 'Run the query specified by the given index' })
|
|
1344
1344
|
parser.add_argument('-f', '--filter', { help: 'for -pd only the data for the knowledge modules that start with this string will be shown' })
|
|
1345
1345
|
parser.add_argument('-ip ', '--server', { help: 'Server to run against' })
|
|
1346
1346
|
parser.add_argument('--trace', { action: 'store_true', help: 'Trace the semantics and generator calls.' })
|
|
@@ -1380,6 +1380,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1380
1380
|
parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
|
|
1381
1381
|
parser.add_argument('-db', '--debugBridge', { action: 'store_true', help: helpDebugBridge })
|
|
1382
1382
|
parser.add_argument('-do', '--debugOperator', { action: 'store_true', help: helpDebugOperator })
|
|
1383
|
+
parser.add_argument('-ea', '--explainAssociations', { action: 'store_true', help: 'The server will return information about the associations used to decide on the interpretation.' })
|
|
1383
1384
|
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' })
|
|
1384
1385
|
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' })
|
|
1385
1386
|
parser.add_argument('-bc', '--bypassCache', { action: 'store_true', help: 'Bypass the cache on the server side and rebuild' })
|
|
@@ -1387,6 +1388,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1387
1388
|
const args = parser.parse_args()
|
|
1388
1389
|
args.count = args.count || 1
|
|
1389
1390
|
|
|
1391
|
+
if (args.queryNumber) {
|
|
1392
|
+
args.query = test.contents[args.queryNumber].query
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1390
1395
|
if (args.rebuildTemplateFull) {
|
|
1391
1396
|
args.rebuildTemplate = true
|
|
1392
1397
|
}
|
|
@@ -1480,9 +1485,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1480
1485
|
|
|
1481
1486
|
if (args.deleteTest) {
|
|
1482
1487
|
let tests = JSON.parse(runtime.fs.readFileSync(testConfig.name))
|
|
1488
|
+
const nTests = tests.length
|
|
1483
1489
|
tests = tests.filter((test) => test.query !== args.deleteTest)
|
|
1484
1490
|
writeTestFile(testConfig.name, tests)
|
|
1485
|
-
console.log(`
|
|
1491
|
+
console.log(`Deleted ${nTests - tests.length} tests for "${args.deleteTest}"`)
|
|
1486
1492
|
return
|
|
1487
1493
|
}
|
|
1488
1494
|
|
|
@@ -1513,6 +1519,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1513
1519
|
config.config.explain_priorities = true
|
|
1514
1520
|
}
|
|
1515
1521
|
|
|
1522
|
+
if (args.explainAssociations) {
|
|
1523
|
+
config.config.explain_associations = true
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1516
1526
|
config.config.debugIncludeConvolutions = args.debugIncludeConvolutions || process.argv.includes('--debugIncludeConvolutions') || process.argv.includes('-dic')
|
|
1517
1527
|
|
|
1518
1528
|
let configPrinted = false
|
|
@@ -1532,7 +1542,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1532
1542
|
console.log('Test queries')
|
|
1533
1543
|
let counter = 0
|
|
1534
1544
|
for (const test of config.tests) {
|
|
1535
|
-
console.log(
|
|
1545
|
+
console.log(`#${counter} - ${test.query}`)
|
|
1536
1546
|
counter += 1
|
|
1537
1547
|
}
|
|
1538
1548
|
}
|
|
@@ -1545,7 +1555,10 @@ const knowledgeModuleImpl = async ({
|
|
|
1545
1555
|
if (hasArg('c')) {
|
|
1546
1556
|
const { data } = setupProcessB({ config })
|
|
1547
1557
|
console.log('Config as sent to server')
|
|
1548
|
-
|
|
1558
|
+
const toPrint = { ...data }
|
|
1559
|
+
toPrint['priorities'] = toPrint['priorities'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
|
|
1560
|
+
toPrint['associations']['positive'] = toPrint['associations']['positive'].map((value) => JSON.stringify(value).replace(/\\"/g, '"'))
|
|
1561
|
+
console.log(JSON.stringify(toPrint, null, 2).replace(/\\"/g, '"'))
|
|
1549
1562
|
}
|
|
1550
1563
|
if (hasArg('l')) {
|
|
1551
1564
|
console.log('Module load ordering')
|
|
@@ -1639,12 +1652,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1639
1652
|
}
|
|
1640
1653
|
|
|
1641
1654
|
if (hasArg('s')) {
|
|
1642
|
-
|
|
1643
|
-
for (const semantic of easyToRead) {
|
|
1644
|
-
semantic.match = semantic.match.toString()
|
|
1645
|
-
semantic.apply = semantic.apply.toString()
|
|
1646
|
-
}
|
|
1647
|
-
console.dir(easyToRead)
|
|
1655
|
+
config.printSemantics()
|
|
1648
1656
|
}
|
|
1649
1657
|
}
|
|
1650
1658
|
}
|
|
@@ -1761,7 +1769,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1761
1769
|
if (hasError) {
|
|
1762
1770
|
console.log('**************************** ERRORS ************************')
|
|
1763
1771
|
for (const result of results) {
|
|
1764
|
-
console.log(
|
|
1772
|
+
console.log(`Utterance: #${result.index} ${result.utterance}`)
|
|
1765
1773
|
if (!result.hasError) {
|
|
1766
1774
|
continue
|
|
1767
1775
|
}
|
|
@@ -1777,7 +1785,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1777
1785
|
newError = true
|
|
1778
1786
|
headerShown = true
|
|
1779
1787
|
if (args.vimdiff) {
|
|
1780
|
-
vimdiff(actual, expected, `"${label} -
|
|
1788
|
+
vimdiff(actual, expected, `"${label} - #${result.index} ${result.utterance}"`)
|
|
1781
1789
|
}
|
|
1782
1790
|
result.hasError = true
|
|
1783
1791
|
}
|
|
@@ -1920,12 +1928,17 @@ const knowledgeModuleImpl = async ({
|
|
|
1920
1928
|
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.')
|
|
1921
1929
|
// console.log(JSON.stringify(contexts))
|
|
1922
1930
|
let errorCount = 0
|
|
1931
|
+
const failedTests = []
|
|
1923
1932
|
for (const result of results) {
|
|
1924
1933
|
if (result.hasError) {
|
|
1925
|
-
console.log(`FAILED ${result.utterance}`)
|
|
1934
|
+
console.log(`FAILED #${result.index} ${result.utterance}`)
|
|
1935
|
+
failedTests.push({ index: result.index, utterance: result.utterance })
|
|
1926
1936
|
errorCount += 1
|
|
1927
1937
|
}
|
|
1928
1938
|
}
|
|
1939
|
+
const failedFile = './FAILED.json'
|
|
1940
|
+
console.log(`Failed tests are written to ${failedFile}`)
|
|
1941
|
+
runtime.fs.writeFileSync(failedFile, JSON.stringify(failedTests, 0, 2))
|
|
1929
1942
|
console.log(`**************************** THERE WERE ${errorCount} TEST FAILURES ************************`)
|
|
1930
1943
|
}
|
|
1931
1944
|
}
|
|
@@ -1984,7 +1997,7 @@ const knowledgeModuleImpl = async ({
|
|
|
1984
1997
|
global.beforeObjects = _.cloneDeep(objects)
|
|
1985
1998
|
}
|
|
1986
1999
|
try {
|
|
1987
|
-
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 }))
|
|
2000
|
+
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 }))
|
|
1988
2001
|
} catch (error) {
|
|
1989
2002
|
printConfig()
|
|
1990
2003
|
console.log('Error', error)
|
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, OverrideCheck } = require('./src/helpers')
|
|
4
|
+
const { w, where, OverrideCheck, setByPath, getByPath, removeProp } = 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,
|
|
@@ -30,4 +32,5 @@ module.exports = {
|
|
|
30
32
|
unflatten: unflatten.unflatten,
|
|
31
33
|
debug,
|
|
32
34
|
OverrideCheck,
|
|
35
|
+
removeProp,
|
|
33
36
|
}
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -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',
|
|
@@ -981,6 +981,15 @@ class Config {
|
|
|
981
981
|
return config_toServer(config)
|
|
982
982
|
}
|
|
983
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
|
+
|
|
984
993
|
async run(handler) {
|
|
985
994
|
return configHelpers.run(this, handler)
|
|
986
995
|
}
|
|
@@ -1291,6 +1300,8 @@ class Config {
|
|
|
1291
1300
|
} else {
|
|
1292
1301
|
return fi
|
|
1293
1302
|
}
|
|
1303
|
+
} else {
|
|
1304
|
+
throw new Error(`The fragment for '${query} was not found.`)
|
|
1294
1305
|
}
|
|
1295
1306
|
}
|
|
1296
1307
|
|
|
@@ -1681,6 +1692,7 @@ class Config {
|
|
|
1681
1692
|
return
|
|
1682
1693
|
}
|
|
1683
1694
|
}
|
|
1695
|
+
|
|
1684
1696
|
if (global.transitoryMode) {
|
|
1685
1697
|
def.transitoryMode = true
|
|
1686
1698
|
}
|
|
@@ -3382,6 +3394,10 @@ class Config {
|
|
|
3382
3394
|
let duplicated = new Set()
|
|
3383
3395
|
const seen = new Set()
|
|
3384
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
|
+
|
|
3385
3401
|
const id = `${bridge.id}/${bridge.level} (namespace: ${bridge.uuid || this.uuid})`
|
|
3386
3402
|
if (seen.has(id)) {
|
|
3387
3403
|
duplicated.add(id)
|
package/src/configHelpers.js
CHANGED
|
@@ -165,10 +165,14 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
|
165
165
|
}
|
|
166
166
|
args.contextHierarchy = new ContextHierarchy()
|
|
167
167
|
args.namespaced = {
|
|
168
|
-
get: (km, context, property) => {
|
|
168
|
+
get: (km, context, property, _default) => {
|
|
169
169
|
context.namespaced ??= {}
|
|
170
170
|
context.namespaced[km] ??= {}
|
|
171
|
-
|
|
171
|
+
const value = context.namespaced[km][property]
|
|
172
|
+
if (value == undefined) {
|
|
173
|
+
return _default
|
|
174
|
+
}
|
|
175
|
+
return value
|
|
172
176
|
},
|
|
173
177
|
set: (km, context, property, value) => {
|
|
174
178
|
context.namespaced ??= {}
|
|
@@ -345,9 +349,11 @@ const processContext = async (context, { objects = {}, config, logs = [] }) => {
|
|
|
345
349
|
const setupProcessB = ({ config, initializer, allowDelta = false, rebuildingTemplate = false } = {}) => {
|
|
346
350
|
const key = config._key
|
|
347
351
|
const data = Object.assign({ key, version: '3' }, { uuid: config._uuid })
|
|
352
|
+
/*
|
|
348
353
|
if (rebuildingTemplate) {
|
|
349
354
|
data.return_rtf_associations = true
|
|
350
355
|
}
|
|
356
|
+
*/
|
|
351
357
|
if (allowDelta && config.allowDelta && config.hasDelta()) {
|
|
352
358
|
// console.log('config', config)
|
|
353
359
|
data.delta = config.delta()
|
|
@@ -405,7 +411,7 @@ const setupContexts = (rawContexts) => {
|
|
|
405
411
|
return contexts
|
|
406
412
|
}
|
|
407
413
|
|
|
408
|
-
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 }) => {
|
|
409
415
|
// TODO fix this name to contextsPrime
|
|
410
416
|
const contextsPrime = []
|
|
411
417
|
const generatedPrime = []
|
|
@@ -417,10 +423,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
417
423
|
|
|
418
424
|
const objects = config.get('objects')
|
|
419
425
|
const args = { objects, isResponse: true, response: json, isTest, isInstance, getObjects: getObjects(objects), instance, contexts, isProcess, isModule, calls }
|
|
420
|
-
|
|
421
|
-
json.logs = []
|
|
422
|
-
}
|
|
423
|
-
setupArgs(args, config, json.logs, hierarchy)
|
|
426
|
+
setupArgs(args, config, logs, hierarchy)
|
|
424
427
|
const toDo = [...contexts]
|
|
425
428
|
args.insert = (context) => toDo.unshift(context)
|
|
426
429
|
let overlap, lastRange
|
|
@@ -438,7 +441,7 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
438
441
|
}
|
|
439
442
|
const generateParenthesized = isTest || (commandLineArgs && commandLineArgs.save)
|
|
440
443
|
if (!config.get('skipSemantics')) {
|
|
441
|
-
const semantics = config.getSemantics(
|
|
444
|
+
const semantics = config.getSemantics(logs)
|
|
442
445
|
try {
|
|
443
446
|
contextPrime = await semantics.apply(args, context)
|
|
444
447
|
// contextPrime.greg = 'yes'
|
|
@@ -481,11 +484,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
481
484
|
// noop
|
|
482
485
|
} else {
|
|
483
486
|
let assumed = { isResponse: true }
|
|
484
|
-
const generated = contextPrime.isResponse ? await config.getGenerators(
|
|
487
|
+
const generated = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
485
488
|
let generatedParenthesized = []
|
|
486
489
|
if (generateParenthesized) {
|
|
487
490
|
config.setParenthesized(true)
|
|
488
|
-
generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(
|
|
491
|
+
generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
|
|
489
492
|
config.setParenthesized(false)
|
|
490
493
|
}
|
|
491
494
|
// assumed = { paraphrase: true, response: false };
|
|
@@ -493,11 +496,11 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
493
496
|
if (generateParenthesized) {
|
|
494
497
|
config.setParenthesized(false)
|
|
495
498
|
}
|
|
496
|
-
const paraphrases = await config.getGenerators(
|
|
499
|
+
const paraphrases = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
497
500
|
let paraphrasesParenthesized = []
|
|
498
501
|
if (generateParenthesized) {
|
|
499
502
|
config.setParenthesized(true)
|
|
500
|
-
paraphrasesParenthesized = await config.getGenerators(
|
|
503
|
+
paraphrasesParenthesized = await config.getGenerators(logs).apply({ ...args, assumed }, contextPrime, assumed)
|
|
501
504
|
config.setParenthesized(false)
|
|
502
505
|
}
|
|
503
506
|
contextsPrime.push(contextPrime)
|
|
@@ -526,9 +529,9 @@ const processContextsB = async ({ config, calls, hierarchy, semantics, generator
|
|
|
526
529
|
}
|
|
527
530
|
e.context = contextPrime
|
|
528
531
|
if (e.logs) {
|
|
529
|
-
e.logs = e.logs.concat(
|
|
532
|
+
e.logs = e.logs.concat(logs)
|
|
530
533
|
} else {
|
|
531
|
-
e.logs =
|
|
534
|
+
e.logs = logs
|
|
532
535
|
}
|
|
533
536
|
e.metadata = json.metadata
|
|
534
537
|
if (json.trace) {
|
|
@@ -545,10 +548,12 @@ const loadInstance = async (config, instance) => {
|
|
|
545
548
|
const transitoryMode = global.transitoryMode
|
|
546
549
|
global.transitoryMode = false
|
|
547
550
|
|
|
551
|
+
/*
|
|
548
552
|
const rl = instance.resultss.length
|
|
549
553
|
if (rl > 0) {
|
|
550
554
|
config.addAssociations(instance.resultss[instance.resultss.length - 1].rtf_associations || [])
|
|
551
555
|
}
|
|
556
|
+
*/
|
|
552
557
|
/*
|
|
553
558
|
TODO needs updating if still wanted
|
|
554
559
|
if (instance && (instance.associations || instance.learned_contextual_priorities)) {
|
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
|
@@ -76,6 +76,9 @@ const flatten = (markers, value) => {
|
|
|
76
76
|
if (value.flatten === false) {
|
|
77
77
|
return [[value], false]
|
|
78
78
|
}
|
|
79
|
+
|
|
80
|
+
const flatten_ignore = value.flatten_ignore || []
|
|
81
|
+
|
|
79
82
|
const marker = value.marker
|
|
80
83
|
let properties = value
|
|
81
84
|
|
|
@@ -105,8 +108,9 @@ const flatten = (markers, value) => {
|
|
|
105
108
|
for (const key in properties) {
|
|
106
109
|
let wf = false
|
|
107
110
|
let values
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
if (flatten_ignore.includes(key)) {
|
|
112
|
+
values = [properties[key]]
|
|
113
|
+
} else if (isObject(properties[key])) {
|
|
110
114
|
const context = properties[key];
|
|
111
115
|
[values, wf] = flatten(markers, context)
|
|
112
116
|
// } else if (isinstance(properties[key], list)) {
|
package/src/fragments.js
CHANGED
package/src/generators.js
CHANGED
|
@@ -125,11 +125,10 @@ class Generator {
|
|
|
125
125
|
args.g = args.gp
|
|
126
126
|
}
|
|
127
127
|
return await debug.hitScoped(args.callId, async () => {
|
|
128
|
-
if ((options.debug || {}).apply ||
|
|
129
|
-
callId === this.callId) {
|
|
128
|
+
if ((options.debug || {}).apply || process.env.DEBUG_CALLID == args.callId || callId === this.callId) {
|
|
130
129
|
debugger // eslint-disable-line no-debugger
|
|
131
130
|
}
|
|
132
|
-
return await this._apply(args)
|
|
131
|
+
return await this._apply(args) // DEBUG: This is the line you want to step into
|
|
133
132
|
})
|
|
134
133
|
}
|
|
135
134
|
}
|
|
@@ -185,12 +184,22 @@ class Generators {
|
|
|
185
184
|
let generated = ''
|
|
186
185
|
let applied = false
|
|
187
186
|
const stack = args.calls.push()
|
|
187
|
+
const pOrRTag = assumed.isResponse ? "(RESPONSE)" : "(PARAPHRASE)"
|
|
188
|
+
const finallyList = []; // called after the generator is processed
|
|
189
|
+
args._finally = (call) => finallyList.unshift(call)
|
|
188
190
|
for (let igenerator = 0; igenerator < this.generators.length; ++igenerator) {
|
|
189
191
|
const generator = this.generators[igenerator]
|
|
190
192
|
if (await generator.matches(args, objects, context, hierarchy, config, options)) {
|
|
191
193
|
const log = (message) => { this.logs.push(message) }
|
|
192
194
|
// this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
|
|
193
195
|
let errorMessage = 'The apply function did not return a value'
|
|
196
|
+
if (process.env.TPMKMS_TRACE) {
|
|
197
|
+
console.error("TPMKMS_TRACE", debug.counter("TPMKMS_TRACE"))
|
|
198
|
+
console.error(generator.toLabel())
|
|
199
|
+
console.error(generator.toString())
|
|
200
|
+
console.log(`To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
|
|
201
|
+
}
|
|
202
|
+
|
|
194
203
|
try {
|
|
195
204
|
generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
|
|
196
205
|
} catch (e) {
|
|
@@ -212,6 +221,7 @@ class Generators {
|
|
|
212
221
|
const widths = Lines.addRemainder([10, 10])
|
|
213
222
|
const lines = new Lines(widths)
|
|
214
223
|
lines.setElement(0, 0, 'Generator')
|
|
224
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
215
225
|
const source = `${generator.km}/#${generator.index}`
|
|
216
226
|
lines.setElement(0, 2, `ERROR while applying (${source}) ${generator.toLabel()}`)
|
|
217
227
|
lines.newRow()
|
|
@@ -225,7 +235,7 @@ class Generators {
|
|
|
225
235
|
lines.setElement(0, 2, stack)
|
|
226
236
|
lines.newRow()
|
|
227
237
|
lines.setElement(0, 1, 'DEBUG')
|
|
228
|
-
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
|
|
238
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') or DEBUG_CALLID="${args.calls.current()}"`)
|
|
229
239
|
lines.newRow()
|
|
230
240
|
lines.setElement(0, 1, 'ERROR')
|
|
231
241
|
lines.setElement(0, 2, errorMessage)
|
|
@@ -240,6 +250,7 @@ class Generators {
|
|
|
240
250
|
const widths = Lines.addRemainder([10, 10])
|
|
241
251
|
const lines = new Lines(widths)
|
|
242
252
|
lines.setElement(0, 0, 'Generator')
|
|
253
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
243
254
|
if (generator.index > -1 && generator.km) {
|
|
244
255
|
// lines.setElement(0, 2, `KM '${generator.km}' ordinal: ${generator.index}`)
|
|
245
256
|
lines.setElement(0, 2, generator.toLabel())
|
|
@@ -251,7 +262,7 @@ class Generators {
|
|
|
251
262
|
lines.setElement(0, 2, generator.toString())
|
|
252
263
|
lines.newRow()
|
|
253
264
|
lines.setElement(0, 1, 'RESULT')
|
|
254
|
-
lines.setElement(0, 2, generated)
|
|
265
|
+
lines.setElement(0, 2, generated + " " + pOrRTag)
|
|
255
266
|
lines.newRow()
|
|
256
267
|
lines.setElement(0, 1, 'STACK')
|
|
257
268
|
lines.setElement(0, 2, stack)
|
|
@@ -268,11 +279,15 @@ class Generators {
|
|
|
268
279
|
break
|
|
269
280
|
}
|
|
270
281
|
}
|
|
282
|
+
for (const f of finallyList) {
|
|
283
|
+
await f()
|
|
284
|
+
}
|
|
271
285
|
args.calls.pop()
|
|
272
286
|
if (!applied && config.getDebug()) {
|
|
273
287
|
const widths = Lines.addRemainder([10, 10])
|
|
274
288
|
const lines = new Lines(widths)
|
|
275
289
|
lines.setElement(0, 0, 'Generator')
|
|
290
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
276
291
|
lines.setElement(0, 2, 'No generator applied')
|
|
277
292
|
lines.newRow()
|
|
278
293
|
lines.setElement(0, 1, 'STACK')
|
package/src/helpers.js
CHANGED
|
@@ -544,52 +544,77 @@ const stableId = (tag) => {
|
|
|
544
544
|
}
|
|
545
545
|
|
|
546
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
|
+
|
|
547
556
|
let current = obj;
|
|
548
|
-
for (const key of
|
|
557
|
+
for (const key of keys) {
|
|
549
558
|
if (current === null || current === undefined) return defaultValue;
|
|
550
|
-
if (typeof current !==
|
|
559
|
+
if (typeof current !== "object") return defaultValue;
|
|
551
560
|
current = current[key];
|
|
552
561
|
}
|
|
553
562
|
return current === undefined ? defaultValue : current;
|
|
554
563
|
}
|
|
555
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
|
+
|
|
556
581
|
/**
|
|
557
|
-
* Set a value in an object by path array.
|
|
582
|
+
* Set a value in an object by path (string or array).
|
|
558
583
|
* Automatically creates missing objects {} or arrays [] as needed.
|
|
559
584
|
*
|
|
560
585
|
* @param {Object} obj - The root object to modify
|
|
561
|
-
* @param {Array<string|number>} path -
|
|
586
|
+
* @param {string|Array<string|number>} path - Path keys/indices
|
|
562
587
|
* @param {*} value - Value to set
|
|
563
588
|
* @returns {*} The set value (for chaining)
|
|
564
589
|
*/
|
|
565
590
|
function setByPath(obj, path, value) {
|
|
566
|
-
|
|
567
|
-
|
|
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");
|
|
568
599
|
}
|
|
569
600
|
|
|
570
601
|
let current = obj;
|
|
571
602
|
|
|
572
|
-
for (let i = 0; i <
|
|
573
|
-
const key =
|
|
574
|
-
const isLast = i ===
|
|
603
|
+
for (let i = 0; i < keys.length; i++) {
|
|
604
|
+
const key = keys[i];
|
|
605
|
+
const isLast = i === keys.length - 1;
|
|
575
606
|
|
|
576
607
|
if (isLast) {
|
|
577
|
-
// Final step — just assign
|
|
578
608
|
current[key] = value;
|
|
579
609
|
} else {
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
if (current[key] == null) {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
? []
|
|
587
|
-
: {};
|
|
588
|
-
} else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
|
|
589
|
-
// 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) {
|
|
590
616
|
current[key] = { ...current[key] };
|
|
591
|
-
} else if (!Array.isArray(current[key]) &&
|
|
592
|
-
// If next expects array but current is object → convert
|
|
617
|
+
} else if (!Array.isArray(current[key]) && nextIsIndex) {
|
|
593
618
|
current[key] = Object.values(current[key]);
|
|
594
619
|
}
|
|
595
620
|
|
|
@@ -602,7 +627,60 @@ function setByPath(obj, path, value) {
|
|
|
602
627
|
|
|
603
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"]\''
|
|
604
629
|
|
|
630
|
+
// removeProp.js
|
|
631
|
+
function removeProp(obj, testFn, { maxDepth = Infinity, seen = new WeakSet() } = {}) {
|
|
632
|
+
if (!obj || typeof obj !== 'object' || maxDepth <= 0) return obj;
|
|
633
|
+
if (seen.has(obj)) return obj;
|
|
634
|
+
seen.add(obj);
|
|
635
|
+
|
|
636
|
+
if (Array.isArray(obj)) {
|
|
637
|
+
// ---- ARRAY: process each element (but don't remove elements unless testFn says so)
|
|
638
|
+
let writeIdx = 0;
|
|
639
|
+
for (let i = 0; i < obj.length; i++) {
|
|
640
|
+
const element = obj[i];
|
|
641
|
+
const shouldRemoveElement = testFn(element, i, obj);
|
|
642
|
+
|
|
643
|
+
if (shouldRemoveElement) {
|
|
644
|
+
// Remove the whole array element
|
|
645
|
+
if (element && typeof element === 'object') {
|
|
646
|
+
// Still walk inside it in case testFn wants side effects
|
|
647
|
+
removeProp(element, testFn, { maxDepth: maxDepth - 1, seen });
|
|
648
|
+
}
|
|
649
|
+
// Skip writing it back
|
|
650
|
+
} else {
|
|
651
|
+
// Keep element, but walk into it to remove inner props
|
|
652
|
+
removeProp(element, testFn, { maxDepth: maxDepth - 1, seen });
|
|
653
|
+
if (writeIdx !== i) {
|
|
654
|
+
obj[writeIdx] = element;
|
|
655
|
+
}
|
|
656
|
+
writeIdx++;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
obj.length = writeIdx;
|
|
660
|
+
return obj;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// ---- OBJECT: iterate over own keys
|
|
664
|
+
const keys = Reflect.ownKeys(obj);
|
|
665
|
+
for (const key of keys) {
|
|
666
|
+
const val = obj[key];
|
|
667
|
+
const shouldRemove = testFn(val, key, obj);
|
|
668
|
+
|
|
669
|
+
if (shouldRemove) {
|
|
670
|
+
delete obj[key];
|
|
671
|
+
if (val && typeof val === 'object') {
|
|
672
|
+
removeProp(val, testFn, { maxDepth: maxDepth - 1, seen });
|
|
673
|
+
}
|
|
674
|
+
} else {
|
|
675
|
+
removeProp(val, testFn, { maxDepth: maxDepth - 1, seen });
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return obj;
|
|
680
|
+
}
|
|
681
|
+
|
|
605
682
|
module.exports = {
|
|
683
|
+
removeProp,
|
|
606
684
|
helpDebugHierarchy,
|
|
607
685
|
|
|
608
686
|
stableId,
|
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
|
@@ -77,10 +77,11 @@ class Semantic {
|
|
|
77
77
|
this.fixUpArgs(args, context)
|
|
78
78
|
return await debug.hitScoped(args.callId, async () => {
|
|
79
79
|
const matches = await this.matcher(args)
|
|
80
|
-
if (matches
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
+
}
|
|
84
85
|
}
|
|
85
86
|
return matches
|
|
86
87
|
})
|
|
@@ -100,8 +101,8 @@ class Semantic {
|
|
|
100
101
|
this.fixUpArgs(args, contextPrime)
|
|
101
102
|
|
|
102
103
|
return await debug.hitScoped(args.callId, async () => {
|
|
103
|
-
if ((options.debug || {}).apply || args.callId === this.callId) {
|
|
104
|
-
debugger // eslint-disable-line no-debugger
|
|
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
|
|
105
106
|
}
|
|
106
107
|
if (args.breakOnSemantics) {
|
|
107
108
|
debugger // eslint-disable-line no-debugger
|
|
@@ -109,7 +110,7 @@ class Semantic {
|
|
|
109
110
|
|
|
110
111
|
try {
|
|
111
112
|
args.stack.push(this)
|
|
112
|
-
await this._apply(args)
|
|
113
|
+
await this._apply(args) // DEBUG: This is the line you want to step into
|
|
113
114
|
args.stack.pop()
|
|
114
115
|
} catch( e ) {
|
|
115
116
|
args.stack.pop()
|
|
@@ -192,6 +193,8 @@ class Semantics {
|
|
|
192
193
|
let seenQuestion = false
|
|
193
194
|
const deferred = []
|
|
194
195
|
args.log = (message) => { this.logs.push(message) }
|
|
196
|
+
const finallyList = []; // called after the semantic is processed
|
|
197
|
+
args._finally = (call) => finallyList.unshift(call)
|
|
195
198
|
for (const isemantic in this.semantics) {
|
|
196
199
|
const semantic = this.semantics[isemantic]
|
|
197
200
|
// only one question at a time
|
|
@@ -252,13 +255,14 @@ class Semantics {
|
|
|
252
255
|
const widths = Lines.addRemainder([10, 10])
|
|
253
256
|
const lines = new Lines(widths)
|
|
254
257
|
lines.setElement(0, 0, 'Semantic')
|
|
258
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
255
259
|
const source = `${semantic.km}/#${semantic.index}`
|
|
256
260
|
lines.setElement(0, 2, `ERROR while applying (${source}) ${semantic.toLabel()}`)
|
|
257
261
|
lines.newRow()
|
|
258
262
|
lines.setElement(0, 2, semantic.toString())
|
|
259
263
|
lines.newRow()
|
|
260
264
|
lines.setElement(0, 1, 'DEBUG')
|
|
261
|
-
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
|
|
265
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
|
|
262
266
|
lines.newRow()
|
|
263
267
|
lines.setElement(0, 1, 'TO')
|
|
264
268
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
|
@@ -282,6 +286,7 @@ class Semantics {
|
|
|
282
286
|
const widths = Lines.addRemainder([10, 10])
|
|
283
287
|
const lines = new Lines(widths)
|
|
284
288
|
lines.setElement(0, 0, 'Semantic')
|
|
289
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
285
290
|
if (semantic.index > -1 && semantic.km) {
|
|
286
291
|
// lines.setElement(0, 2, `KM '${semantic.km}' ordinal: ${semantic.index} ${ semantic.notes ? semantic.nodes : '' }`)
|
|
287
292
|
lines.setElement(0, 2, semantic.toLabel())
|
|
@@ -293,7 +298,7 @@ class Semantics {
|
|
|
293
298
|
lines.setElement(0, 2, semantic.toString())
|
|
294
299
|
lines.newRow()
|
|
295
300
|
lines.setElement(0, 1, 'DEBUG')
|
|
296
|
-
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}')`)
|
|
301
|
+
lines.setElement(0, 2, `To debug this use debug.breakAt('${args.calls.current()}') in the code or DEBUG_CALLID="${args.calls.current()}"`)
|
|
297
302
|
lines.newRow()
|
|
298
303
|
lines.setElement(0, 1, 'TO')
|
|
299
304
|
lines.setElement(0, 2, `context_id: ${context.context_id}`)
|
|
@@ -324,11 +329,15 @@ class Semantics {
|
|
|
324
329
|
}
|
|
325
330
|
counter += 1
|
|
326
331
|
}
|
|
332
|
+
for (const f of finallyList) {
|
|
333
|
+
await f()
|
|
334
|
+
}
|
|
327
335
|
args.calls.pop()
|
|
328
336
|
if (!applied && debug) {
|
|
329
337
|
const widths = Lines.addRemainder([10, 10])
|
|
330
338
|
const lines = new Lines(widths)
|
|
331
339
|
lines.setElement(0, 0, 'Semantic')
|
|
340
|
+
lines.setElement(0, 1, `#${context.context_id || "?"}`)
|
|
332
341
|
lines.setElement(0, 2, 'No semantic applied')
|
|
333
342
|
lines.newRow()
|
|
334
343
|
lines.setElement(0, 1, 'STACK')
|