theprogrammablemind 7.12.8 → 8.0.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 +31 -132
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/config.js +247 -94
- package/src/digraph.js +29 -10
- package/src/digraph_internal.js +29 -10
package/client.js
CHANGED
@@ -81,104 +81,6 @@ const pickObjects = (config, testConfig, getObjects) => {
|
|
81
81
|
return projection
|
82
82
|
}
|
83
83
|
|
84
|
-
// move ask to the KM's since verbatim is called probably in dialogues?
|
85
|
-
const getAsk = (config) => (uuid) => {
|
86
|
-
// if (!uuid) {
|
87
|
-
// debugger
|
88
|
-
//}
|
89
|
-
return (asks) => {
|
90
|
-
const ask = (ask) => {
|
91
|
-
let oneShot = true // default
|
92
|
-
if (ask.oneShot === false) {
|
93
|
-
oneShot = false
|
94
|
-
}
|
95
|
-
|
96
|
-
const id_q = stableId('semantic')
|
97
|
-
const id_rs = []
|
98
|
-
let wasAsked = false
|
99
|
-
let wasApplied = false
|
100
|
-
const getWasAsked = () => {
|
101
|
-
return wasAsked
|
102
|
-
}
|
103
|
-
const setWasAsked = (value) => {
|
104
|
-
wasAsked = value
|
105
|
-
}
|
106
|
-
const getWasApplied = () => {
|
107
|
-
return wasApplied
|
108
|
-
}
|
109
|
-
const setWasApplied = (value) => {
|
110
|
-
wasApplied = value
|
111
|
-
}
|
112
|
-
|
113
|
-
const semanticsr = ask.semanticsr || []
|
114
|
-
if (semanticsr.length == 0) {
|
115
|
-
semanticsr.push({ match: ask.matchr, apply: ask.applyr })
|
116
|
-
}
|
117
|
-
for (const semantic of semanticsr) {
|
118
|
-
const id_r = stableId('semantic')
|
119
|
-
id_rs.push(id_r)
|
120
|
-
config.addSemantic({
|
121
|
-
uuid,
|
122
|
-
id: id_r,
|
123
|
-
tied_ids: [id_q],
|
124
|
-
oneShot,
|
125
|
-
where: semantic.where || ask.where || where(2),
|
126
|
-
source: 'response',
|
127
|
-
match: (args) => semantic.match(args),
|
128
|
-
apply: (args) => {
|
129
|
-
setWasApplied(true)
|
130
|
-
semantic.apply(args)
|
131
|
-
},
|
132
|
-
})
|
133
|
-
}
|
134
|
-
|
135
|
-
config.addSemantic({
|
136
|
-
uuid,
|
137
|
-
oneShot,
|
138
|
-
id: id_q,
|
139
|
-
tied_ids: id_rs,
|
140
|
-
where: ask.where,
|
141
|
-
isQuestion: true, // do one question at a time
|
142
|
-
getWasAsked,
|
143
|
-
getWasApplied,
|
144
|
-
onNevermind: ask.onNevermind,
|
145
|
-
source: 'question',
|
146
|
-
match: ({ context }) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
|
147
|
-
apply: (args) => {
|
148
|
-
let matchq = ask.matchq
|
149
|
-
let applyq = ask.applyq
|
150
|
-
if (!matchq) {
|
151
|
-
let wasAsked = false
|
152
|
-
matchq = () => !wasAsked,
|
153
|
-
applyq = (args) => {
|
154
|
-
wasAsked = true
|
155
|
-
return ask.applyq(args)
|
156
|
-
}
|
157
|
-
}
|
158
|
-
if (matchq(args)) {
|
159
|
-
setWasAsked(true)
|
160
|
-
setWasApplied(false)
|
161
|
-
// args.context.motivationKeep = true
|
162
|
-
args.verbatim(applyq(args))
|
163
|
-
/*
|
164
|
-
args.context.verbatim = applyq(args)
|
165
|
-
args.context.isResponse = true;
|
166
|
-
delete args.context.controlRemove;
|
167
|
-
*/
|
168
|
-
args.context.controlKeepMotivation = true
|
169
|
-
}
|
170
|
-
args.context.cascade = true
|
171
|
-
}
|
172
|
-
})
|
173
|
-
}
|
174
|
-
if (!Array.isArray(asks)) {
|
175
|
-
asks = [asks]
|
176
|
-
}
|
177
|
-
|
178
|
-
[...asks].reverse().forEach( (a) => ask(a) )
|
179
|
-
}
|
180
|
-
}
|
181
|
-
|
182
84
|
const sameJSON = (json1, json2) => {
|
183
85
|
const sjson1 = sortJson(json1, { depth: 25 })
|
184
86
|
const sjson2 = sortJson(json2, { depth: 25 })
|
@@ -300,7 +202,6 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
300
202
|
}
|
301
203
|
// for semantics
|
302
204
|
args.addAssumedScoped(args, {})
|
303
|
-
config.getAddedArgs(args)
|
304
205
|
|
305
206
|
const getAPI = (uuid) => {
|
306
207
|
if (config && config.getAPI) {
|
@@ -312,14 +213,14 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
|
|
312
213
|
return config.getAPIs(uuid)
|
313
214
|
}
|
314
215
|
}
|
315
|
-
const scopedAsk = getAsk(config)
|
316
216
|
args.getUUIDScoped = (uuid) => {
|
317
217
|
return {
|
318
|
-
ask: scopedAsk(uuid),
|
319
218
|
api: getAPI(uuid),
|
320
219
|
apis: getAPIs(uuid)
|
321
220
|
}
|
322
221
|
}
|
222
|
+
config.getAddedArgs(args)
|
223
|
+
|
323
224
|
Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
|
324
225
|
/*
|
325
226
|
if (uuidForScoping) {
|
@@ -745,17 +646,15 @@ const loadInstance = (config, instance) => {
|
|
745
646
|
const results = instance.resultss[i]
|
746
647
|
if (results.extraConfig) {
|
747
648
|
// config.addInternal(results, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false)
|
748
|
-
// config.addInternal(config.template.queries[i], { handleCalculatedProps: true } )
|
749
649
|
const uuid = config.nameToUUID(instance.name)
|
750
650
|
// used to do a CLONE
|
751
|
-
|
752
|
-
config.addInternal(instance.template.queries[i], { uuid, addFirst: true, handleCalculatedProps: true })
|
651
|
+
config.addInternal(instance.template.configs[i], { uuid, addFirst: true, handleCalculatedProps: true })
|
753
652
|
} else if (results.apply) {
|
754
653
|
const objects = config.get('objects')
|
755
654
|
const args = { objects, getObjects: getObjects(objects) }
|
756
|
-
if (instance.
|
655
|
+
if (instance.configs) {
|
757
656
|
args.isInstance = `instance${i}`
|
758
|
-
args.instance = instance.
|
657
|
+
args.instance = instance.configs[i]
|
759
658
|
}
|
760
659
|
|
761
660
|
const uuid = config.nameToUUID(instance.name)
|
@@ -923,15 +822,27 @@ const getConfigForTest = (config, testConfig) => {
|
|
923
822
|
// configForTest[key] = config.config[key]
|
924
823
|
if (key === 'words') {
|
925
824
|
const words = config.config.words
|
926
|
-
configForTest.words = {
|
927
|
-
|
825
|
+
configForTest.words = {
|
826
|
+
literals: {},
|
827
|
+
patterns: [],
|
828
|
+
hierarchy: [],
|
829
|
+
}
|
830
|
+
|
831
|
+
const literals = config.config.words.literals
|
832
|
+
for (const key in literals) {
|
928
833
|
const defs = []
|
929
|
-
for (const def of
|
834
|
+
for (const def of literals[key]) {
|
930
835
|
// TODO handle thie uuids the right way
|
931
836
|
defs.push(Object.assign({}, def, { uuid: undefined }))
|
932
837
|
}
|
933
|
-
configForTest.words[key] = defs
|
838
|
+
configForTest.words.literals[key] = defs
|
934
839
|
}
|
840
|
+
|
841
|
+
const patterns = config.config.words.patterns
|
842
|
+
configForTest.words.patterns = patterns.map((pattern) => Object.assign({}, pattern, { uuid: undefined }))
|
843
|
+
|
844
|
+
const hierarchy = config.config.words.hierarchy
|
845
|
+
configForTest.words.hierarchy = hierarchy.map((hierarchy) => Object.assign({}, hierarchy, { uuid: undefined }))
|
935
846
|
} else if (key === 'operators') {
|
936
847
|
configForTest.operators = config.config.operators.map((operator) => Object.assign({}, operator, { uuid: undefined }))
|
937
848
|
} else if (key === 'bridges') {
|
@@ -1281,7 +1192,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
|
|
1281
1192
|
console.log('Errors')
|
1282
1193
|
responses.errors.forEach((error) => console.log(` ${error}`))
|
1283
1194
|
}
|
1284
|
-
console.log("KM's loaded", config.configs.map((c) => c.name))
|
1195
|
+
console.log("KM's loaded (ordered)", config.configs.map((c) => c.name))
|
1285
1196
|
console.log('This is the global objects from running semantics:\n', config.objects)
|
1286
1197
|
if (!_.isEmpty(responses.learned_contextual_priorities)) {
|
1287
1198
|
console.log('\nThe learned contextual priorties are :\n')
|
@@ -1404,12 +1315,12 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1404
1315
|
associations: [],
|
1405
1316
|
learned_contextual_priorities: []
|
1406
1317
|
}
|
1407
|
-
const looper = async (
|
1408
|
-
if (
|
1318
|
+
const looper = async (configs) => {
|
1319
|
+
if (configs.length === 0) {
|
1409
1320
|
finish()
|
1410
1321
|
return
|
1411
1322
|
}
|
1412
|
-
const { property, hierarchy, query: queryOrExtraConfig, previousResults, initializer, skipSemantics } =
|
1323
|
+
const { property, hierarchy, query: queryOrExtraConfig, previousResults, initializer, skipSemantics } = configs.shift()
|
1413
1324
|
// queries are strings or { query: "blah", development: true/false }
|
1414
1325
|
if (typeof queryOrExtraConfig === 'string' || queryOrExtraConfig.query) {
|
1415
1326
|
let query = queryOrExtraConfig
|
@@ -1461,7 +1372,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1461
1372
|
accumulators[property].push(results)
|
1462
1373
|
accumulators.associations = accumulators.associations.concat(results.associations)
|
1463
1374
|
accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
|
1464
|
-
await looper(
|
1375
|
+
await looper(configs)
|
1465
1376
|
} catch (e) {
|
1466
1377
|
const error = { errors: [e], query: query.query }
|
1467
1378
|
config.config.skipSemantics = null
|
@@ -1475,7 +1386,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1475
1386
|
setupArgs(args, config, config.logs, hierarchy)
|
1476
1387
|
initFunction(args)
|
1477
1388
|
accumulators[property].push({ apply: queryOrExtraConfig })
|
1478
|
-
await looper(
|
1389
|
+
await looper(configs)
|
1479
1390
|
} else {
|
1480
1391
|
// extra config is def from a time like operators or bridges or words etc
|
1481
1392
|
// it will just get added to the config
|
@@ -1491,7 +1402,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1491
1402
|
throw new Error(`Error processing extra config${where}: ${e.stack}}`)
|
1492
1403
|
}
|
1493
1404
|
accumulators[property].push({ extraConfig: true, ...extraConfig })
|
1494
|
-
await looper(
|
1405
|
+
await looper(configs)
|
1495
1406
|
}
|
1496
1407
|
}
|
1497
1408
|
}
|
@@ -1531,7 +1442,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1531
1442
|
return template
|
1532
1443
|
}
|
1533
1444
|
stabilizeOutput(accumulators)
|
1534
|
-
runtime.fs.writeFileSync(instanceName, JSON.stringify(Object.assign({
|
1445
|
+
runtime.fs.writeFileSync(instanceName, JSON.stringify(Object.assign({ configs: template.configs.map(updateQueries) }, accumulators), 0, 2))
|
1535
1446
|
|
1536
1447
|
// km tests file
|
1537
1448
|
const testsName = `./${target}.test.json`
|
@@ -1550,7 +1461,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
|
|
1550
1461
|
}
|
1551
1462
|
let todo = []
|
1552
1463
|
todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false || query.skipSemantics } }))
|
1553
|
-
todo = todo.concat((template.
|
1464
|
+
todo = todo.concat((template.configs || []).map((query, index) => {
|
1554
1465
|
let pr
|
1555
1466
|
if (index < startOfChanges) {
|
1556
1467
|
pr = previousResultss[index]
|
@@ -1600,19 +1511,6 @@ const knowledgeModuleImpl = async ({
|
|
1600
1511
|
acceptsAdditionalConfig = false,
|
1601
1512
|
...rest
|
1602
1513
|
} = {}) => {
|
1603
|
-
/*
|
1604
|
-
if (description == 'fastfood related concepts') {
|
1605
|
-
debugger
|
1606
|
-
global.old = template.template.queries[91].bridges[0]
|
1607
|
-
}
|
1608
|
-
let old
|
1609
|
-
if (template && template.template && template.template.queries) {
|
1610
|
-
old = template.template.queries
|
1611
|
-
template.template.queries = _.cloneDeep(template.template.queries)
|
1612
|
-
template.wasCopied = true
|
1613
|
-
}
|
1614
|
-
*/
|
1615
|
-
|
1616
1514
|
const unknownArgs = Object.keys(rest)
|
1617
1515
|
if (unknownArgs.length > 0) {
|
1618
1516
|
throw new Error(`Unknown arguments to knowledgeModule: ${unknownArgs.join()}`)
|
@@ -2270,6 +2168,7 @@ const knowledgeModule = async (...args) => {
|
|
2270
2168
|
|
2271
2169
|
module.exports = {
|
2272
2170
|
process: _process,
|
2171
|
+
stableId,
|
2273
2172
|
where,
|
2274
2173
|
w,
|
2275
2174
|
// submitBug,
|
package/index.js
CHANGED
package/package.json
CHANGED
package/src/config.js
CHANGED
@@ -26,6 +26,19 @@ const config_toServer = (config) => {
|
|
26
26
|
// cant change things because copy breaks something
|
27
27
|
}
|
28
28
|
|
29
|
+
const initWords = (words) => {
|
30
|
+
if (!words.literals) {
|
31
|
+
words.literals = {}
|
32
|
+
}
|
33
|
+
if (!words.patterns) {
|
34
|
+
words.patterns = []
|
35
|
+
}
|
36
|
+
if (!words.hierarchy) {
|
37
|
+
words.hierarchy = []
|
38
|
+
}
|
39
|
+
return words
|
40
|
+
}
|
41
|
+
|
29
42
|
const debugPriority = (priority) => {
|
30
43
|
if (global.entodictonDebugPriority) {
|
31
44
|
if (helpers.subPriority(entodictonDebugPriority, priority)) {
|
@@ -123,6 +136,7 @@ const validConfigProps = (config) => {
|
|
123
136
|
|
124
137
|
const setupInitializerFNArgs = (config, args) => {
|
125
138
|
const aw = (word, def) => config.addWord(word, def, args.uuid)
|
139
|
+
const ap = (pattern, def) => config.addPattern(pattern, def, args.uuid)
|
126
140
|
const ag = (generator) => config.addGenerator(generator, args.uuid, config.name)
|
127
141
|
const km = (name) => config.getConfig(name)
|
128
142
|
const apis = (name) => config.getConfig(name).api
|
@@ -130,6 +144,7 @@ const setupInitializerFNArgs = (config, args) => {
|
|
130
144
|
return {
|
131
145
|
...args,
|
132
146
|
addWord: aw,
|
147
|
+
addPattern: ap,
|
133
148
|
addGenerator: ag,
|
134
149
|
config: config.getPseudoConfig(args.uuid, args.currentConfig),
|
135
150
|
km,
|
@@ -213,6 +228,9 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
213
228
|
config.addHierarchy(child, bridge.id)
|
214
229
|
}
|
215
230
|
}
|
231
|
+
if (bridge.operator) {
|
232
|
+
config.addOperator(bridge.operator, uuid || config.uuid)
|
233
|
+
}
|
216
234
|
if (bridge.parents) {
|
217
235
|
for (const parent of bridge.parents) {
|
218
236
|
config.addHierarchy(bridge.id, parent)
|
@@ -329,7 +347,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
|
|
329
347
|
if (bridge.semantic) {
|
330
348
|
const semantic = {
|
331
349
|
where: bridge.semantic.where || bridge.where || client.where(3),
|
332
|
-
match: ({ context }) => bridge.id == context.marker,
|
350
|
+
match: ({ context }) => bridge.id == context.marker && !context.evaluate,
|
333
351
|
apply: (args) => bridge.semantic(args),
|
334
352
|
applyWrapped: bridge.semantic,
|
335
353
|
property: 'semantic'
|
@@ -348,7 +366,7 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
|
|
348
366
|
if (moreConfig.bridges) {
|
349
367
|
moreConfig.bridges = moreConfig.bridges.map((bridge) => {
|
350
368
|
bridge = { ...bridge }
|
351
|
-
const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
|
369
|
+
const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'operator', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
|
352
370
|
'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid']
|
353
371
|
helpers.validProps(valid, bridge, 'bridge')
|
354
372
|
handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
|
@@ -409,10 +427,13 @@ const hierarchyCanonical = (element) => {
|
|
409
427
|
}
|
410
428
|
}
|
411
429
|
|
412
|
-
const
|
430
|
+
const isValidWordDef = (word, def, config) => {
|
431
|
+
// TODO trie
|
432
|
+
/*
|
413
433
|
if (!def.id) {
|
414
434
|
throw new Error(`In the KM "${config.name}", for the word ${word} the following definition is missing the "id" property: ${JSON.stringify(def)}`)
|
415
435
|
}
|
436
|
+
*/
|
416
437
|
/*
|
417
438
|
if (!def.initial) {
|
418
439
|
throw `In the KM "${config.name}", for the word ${word} the following definition is missing the "initial" property: ${JSON.stringify(def)}`
|
@@ -429,16 +450,20 @@ const hierarchyToCanonical = (edge) => {
|
|
429
450
|
|
430
451
|
const addWord = (config, uuid) => ({ word, id, initial }) => {
|
431
452
|
if (!config.words) {
|
432
|
-
config.words = {
|
453
|
+
config.words = {
|
454
|
+
literals: {},
|
455
|
+
patterns: [],
|
456
|
+
hierarchy: [],
|
457
|
+
}
|
433
458
|
}
|
434
|
-
const
|
459
|
+
const literals = config.words.literals
|
435
460
|
const def = { id, initial, uuid }
|
436
|
-
if (
|
437
|
-
if (!
|
438
|
-
|
461
|
+
if (literals[word]) {
|
462
|
+
if (!literals[word].some((e) => helpers.safeEquals(e, def))) {
|
463
|
+
literals[word].unshift(def)
|
439
464
|
}
|
440
465
|
} else {
|
441
|
-
|
466
|
+
literals[word] = [def]
|
442
467
|
}
|
443
468
|
}
|
444
469
|
|
@@ -453,6 +478,7 @@ const normalizeConfig = (config) => {
|
|
453
478
|
}
|
454
479
|
}
|
455
480
|
}
|
481
|
+
|
456
482
|
if (config.bridges) {
|
457
483
|
for (const bridge of config.bridges) {
|
458
484
|
if (!bridge.level) {
|
@@ -471,6 +497,14 @@ const normalizeConfig = (config) => {
|
|
471
497
|
}
|
472
498
|
}
|
473
499
|
}
|
500
|
+
|
501
|
+
if (config.operators) {
|
502
|
+
for (let i = 0; i < config.operators.length; ++i) {
|
503
|
+
if (typeof config.operators[i] === 'string') {
|
504
|
+
config.operators[i] = { pattern: config.operators[i] }
|
505
|
+
}
|
506
|
+
}
|
507
|
+
}
|
474
508
|
}
|
475
509
|
}
|
476
510
|
|
@@ -488,8 +522,17 @@ function configDup (config, options) {
|
|
488
522
|
}
|
489
523
|
|
490
524
|
function setWordsUUIDs (words, uuid) {
|
491
|
-
|
492
|
-
|
525
|
+
const literals = words.literals
|
526
|
+
for (const key in literals) {
|
527
|
+
literals[key] = literals[key].map((o) => Object.assign(o, { uuid }))
|
528
|
+
}
|
529
|
+
const patterns = words.patterns
|
530
|
+
for (const pattern of patterns) {
|
531
|
+
pattern.defs.map((def) => Object.assign(def, { uuid }))
|
532
|
+
}
|
533
|
+
const hierarchy = words.hierarchy
|
534
|
+
for (const pair of hierarchy) {
|
535
|
+
pair.uuid = uuid
|
493
536
|
}
|
494
537
|
}
|
495
538
|
|
@@ -740,7 +783,7 @@ class Config {
|
|
740
783
|
}
|
741
784
|
const templateQueries = []
|
742
785
|
if (this.instances && this.instances.length > 0) {
|
743
|
-
for (const query of this.instances.slice(-1)[0].
|
786
|
+
for (const query of this.instances.slice(-1)[0].configs) {
|
744
787
|
if (typeof query === 'string') {
|
745
788
|
templateQueries.push(query)
|
746
789
|
}
|
@@ -764,6 +807,7 @@ class Config {
|
|
764
807
|
addSemantic: (...args) => this.addSemantic(...args, uuid, config.name),
|
765
808
|
removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
|
766
809
|
addWord: (...args) => this.addWord(...args, uuid),
|
810
|
+
addPattern: (...args) => this.addPattern(...args, uuid),
|
767
811
|
|
768
812
|
getHierarchy: (...args) => this.config.hierarchy,
|
769
813
|
getBridges: (...args) => this.config.bridges,
|
@@ -785,28 +829,6 @@ class Config {
|
|
785
829
|
}
|
786
830
|
}
|
787
831
|
|
788
|
-
// return the config with just the elements from the included KM's
|
789
|
-
baseConfig () {
|
790
|
-
const operators = this.config.operators.filter((operator) => {
|
791
|
-
return operator.uuid !== this.uuid
|
792
|
-
})
|
793
|
-
const bridges = this.config.bridges.filter((bridge) => {
|
794
|
-
return bridge.uuid !== this.uuid
|
795
|
-
})
|
796
|
-
const words = {}
|
797
|
-
for (const word in this.config.words) {
|
798
|
-
const defs = this.config.words[word].filter((def) => def.uuid !== this.uuid)
|
799
|
-
if (defs.length > 0) {
|
800
|
-
words[word] = defs
|
801
|
-
}
|
802
|
-
}
|
803
|
-
return {
|
804
|
-
operators,
|
805
|
-
bridges,
|
806
|
-
words
|
807
|
-
}
|
808
|
-
}
|
809
|
-
|
810
832
|
getCounter (maybeName = '') {
|
811
833
|
const counter = this.configCounter
|
812
834
|
this.configCounter += 1
|
@@ -843,7 +865,11 @@ class Config {
|
|
843
865
|
namespaced: {}
|
844
866
|
},
|
845
867
|
description: '',
|
846
|
-
words: {
|
868
|
+
words: {
|
869
|
+
literals: {},
|
870
|
+
patterns: [],
|
871
|
+
hierarchy: [],
|
872
|
+
}, // Done
|
847
873
|
floaters: [],
|
848
874
|
implicits: [],
|
849
875
|
flatten: [],
|
@@ -1102,8 +1128,8 @@ class Config {
|
|
1102
1128
|
return elements.map(toCanonicalQuery)
|
1103
1129
|
}
|
1104
1130
|
|
1105
|
-
const templateQueries = toCanonicalQueries(template.
|
1106
|
-
const instanceQueries = toCanonicalQueries(instance.
|
1131
|
+
const templateQueries = toCanonicalQueries(template.configs || []).map(helpers.updateQueries)
|
1132
|
+
const instanceQueries = toCanonicalQueries(instance.configs || [])
|
1107
1133
|
let sameQueries = true
|
1108
1134
|
let startOfChanges
|
1109
1135
|
for (let iq = 0; iq < templateQueries.length; ++iq) {
|
@@ -1124,7 +1150,6 @@ class Config {
|
|
1124
1150
|
if (templateQueries.length < instanceQueries.length) {
|
1125
1151
|
startOfChanges = instanceQueries.length
|
1126
1152
|
}
|
1127
|
-
// const sameQueries = helpers.safeEquals(toCanonicalQueries(template.queries || []).map(helpers.updateQueries), toCanonicalQueries(instance.queries || []))
|
1128
1153
|
|
1129
1154
|
if (debug) {
|
1130
1155
|
if (!(instance && sameQueries && sameFragments)) {
|
@@ -1133,8 +1158,6 @@ class Config {
|
|
1133
1158
|
console.log('sameFragments', sameFragments)
|
1134
1159
|
// console.log("templateFragments", templateFragments)
|
1135
1160
|
// console.log("instanceFragments", instanceFragments)
|
1136
|
-
// console.log('template.queries', JSON.stringify(toCanonicalQueries(template.queries || []).map(helpers.updateQueries), null, 2))
|
1137
|
-
// console.log("instance.queries", JSON.stringify(toCanonicalQueries(instance.queries || []), null, 2))
|
1138
1161
|
}
|
1139
1162
|
}
|
1140
1163
|
if (startOfChanges || instance.resultss) {
|
@@ -1145,13 +1168,13 @@ class Config {
|
|
1145
1168
|
}
|
1146
1169
|
|
1147
1170
|
validifyTemplate (template) {
|
1148
|
-
if (!template.
|
1149
|
-
throw new Error(`Expected the template for ${this.name} to be an object that can have the properties:
|
1171
|
+
if (!template.configs && !template.fragments) {
|
1172
|
+
throw new Error(`Expected the template for ${this.name} to be an object that can have the properties: configs and fragments`)
|
1150
1173
|
}
|
1151
|
-
for (const query of template.
|
1174
|
+
for (const query of template.configs || []) {
|
1152
1175
|
if (typeof query === 'string') {
|
1153
1176
|
} else if (query instanceof Config) {
|
1154
|
-
throw new Error(`For the template for ${this.name}, each element in
|
1177
|
+
throw new Error(`For the template for ${this.name}, each element in configs should be either a string or a structure with a config (not a Config object).`)
|
1155
1178
|
}
|
1156
1179
|
}
|
1157
1180
|
}
|
@@ -1168,7 +1191,7 @@ class Config {
|
|
1168
1191
|
this.logs.push(`loading template for ${this.name}`)
|
1169
1192
|
if (options.rebuild) {
|
1170
1193
|
// TODO fix beforeQuery
|
1171
|
-
template = { fragments: [],
|
1194
|
+
template = { fragments: [], configs: [], ...template }
|
1172
1195
|
template.fragments = template.fragments.concat(this.dynamicFragments)
|
1173
1196
|
client.rebuildTemplate({ config: this, target: this.name, previousResultss: options.previousResultss, startOfChanges: options.startOfChanges, beforeQuery: () => {}, template, ...options })
|
1174
1197
|
} else {
|
@@ -1176,7 +1199,7 @@ class Config {
|
|
1176
1199
|
// this.initInstances.push({ ...instance, name: config.name })
|
1177
1200
|
const isEmpty = (instance) => {
|
1178
1201
|
const properties = [
|
1179
|
-
'
|
1202
|
+
'configs',
|
1180
1203
|
'resultss',
|
1181
1204
|
'fragments',
|
1182
1205
|
'semantics',
|
@@ -1189,7 +1212,7 @@ class Config {
|
|
1189
1212
|
for (let i = 0; i < instance.resultss.length; ++i) {
|
1190
1213
|
const result = instance.resultss[i]
|
1191
1214
|
if (result.apply) {
|
1192
|
-
result.apply = template.
|
1215
|
+
result.apply = template.configs[i]
|
1193
1216
|
}
|
1194
1217
|
}
|
1195
1218
|
instance.name = this.name
|
@@ -1429,21 +1452,41 @@ class Config {
|
|
1429
1452
|
|
1430
1453
|
addWordInternal (word, def, uuid) {
|
1431
1454
|
if (!this.config.words) {
|
1432
|
-
this.config.words = {
|
1455
|
+
this.config.words = {
|
1456
|
+
literals: {},
|
1457
|
+
patterns: [],
|
1458
|
+
hierarchy: [],
|
1459
|
+
}
|
1433
1460
|
}
|
1434
|
-
|
1461
|
+
|
1462
|
+
const literals = this.config.words.literals
|
1435
1463
|
def = Object.assign({}, def, { uuid: uuid || this._uuid })
|
1436
|
-
if (
|
1437
|
-
if (!
|
1438
|
-
|
1464
|
+
if (literals[word]) {
|
1465
|
+
if (!literals[word].some((e) => helpers.safeEquals(e, def))) {
|
1466
|
+
literals[word].unshift(def)
|
1439
1467
|
}
|
1440
1468
|
} else {
|
1441
|
-
|
1469
|
+
literals[word] = [def]
|
1442
1470
|
}
|
1443
1471
|
|
1444
1472
|
this._delta.json.words.push({ action: 'add', word, def })
|
1445
1473
|
}
|
1446
1474
|
|
1475
|
+
addPattern (pattern, def, uuid) {
|
1476
|
+
if (!this.config.words) {
|
1477
|
+
this.config.words = {
|
1478
|
+
literals: {},
|
1479
|
+
patterns: [],
|
1480
|
+
hierarchy: [],
|
1481
|
+
}
|
1482
|
+
}
|
1483
|
+
|
1484
|
+
const patterns = this.config.words.patterns
|
1485
|
+
def = Object.assign({}, def, { uuid: uuid || this._uuid })
|
1486
|
+
patterns.unshift({ pattern, defs: [def] })
|
1487
|
+
this._delta.json.words.push({ action: 'add', pattern, defs: [def] })
|
1488
|
+
}
|
1489
|
+
|
1447
1490
|
getAPI (uuid) {
|
1448
1491
|
if (this._uuid === uuid) {
|
1449
1492
|
return this.api
|
@@ -1637,13 +1680,35 @@ class Config {
|
|
1637
1680
|
config.generators = config.generators.filter((element) => !element.development)
|
1638
1681
|
config.semantics = config.semantics.filter((element) => !element.development)
|
1639
1682
|
config.hierarchy = (config.hierarchy).filter((element) => !element.development)
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1683
|
+
|
1684
|
+
const literals = config.words.literals
|
1685
|
+
for (const word in literals) {
|
1686
|
+
const defs = literals[word] || []
|
1687
|
+
literals[word] = defs.filter((def) => !def.development)
|
1688
|
+
if (literals[word].length == 0) {
|
1689
|
+
delete literals[word]
|
1690
|
+
}
|
1691
|
+
}
|
1692
|
+
|
1693
|
+
const patterns = config.words.patterns || []
|
1694
|
+
const patternsPrime = []
|
1695
|
+
for (const pattern of patterns) {
|
1696
|
+
let defs = pattern.defs || []
|
1697
|
+
defs = defs.filter((def) => !def.development)
|
1698
|
+
if (defs.length !== 0) {
|
1699
|
+
patternsPrime.push({...pattern, defs})
|
1645
1700
|
}
|
1646
1701
|
}
|
1702
|
+
config.words.patterns = patternsPrime
|
1703
|
+
|
1704
|
+
const hierarchy = config.words.hierarchy || []
|
1705
|
+
const hierarchyPrime = []
|
1706
|
+
for (const pair of hierarchy) {
|
1707
|
+
if (!pair.development) {
|
1708
|
+
hierarchyPrime.push(pair)
|
1709
|
+
}
|
1710
|
+
}
|
1711
|
+
config.words.hierarchy = hierarchyPrime
|
1647
1712
|
}
|
1648
1713
|
|
1649
1714
|
// configs = [ { config, namespace } ... ]
|
@@ -1657,7 +1722,7 @@ class Config {
|
|
1657
1722
|
|
1658
1723
|
config.operators = config.operators || []
|
1659
1724
|
config.bridges = config.bridges || []
|
1660
|
-
config.words = config.words || {}
|
1725
|
+
config.words = config.words || { literals: {}, patterns: [], hierarchy: [] }
|
1661
1726
|
config.generators = config.generators || []
|
1662
1727
|
config.semantics = config.semantics || []
|
1663
1728
|
config.hierarchy = config.hierarchy || []
|
@@ -1687,7 +1752,7 @@ class Config {
|
|
1687
1752
|
this.instances = []
|
1688
1753
|
this.logs = []
|
1689
1754
|
this.dynamicFragments = []
|
1690
|
-
// when running
|
1755
|
+
// when running configs any bridges added are marked as transitory so that the associated will ignore those op's
|
1691
1756
|
this.transitoryMode = false
|
1692
1757
|
|
1693
1758
|
// check for duplicate bridges
|
@@ -1709,11 +1774,8 @@ class Config {
|
|
1709
1774
|
}
|
1710
1775
|
|
1711
1776
|
if (config && config.words) {
|
1712
|
-
|
1713
|
-
|
1714
|
-
isValidDef(word, def, config)
|
1715
|
-
}
|
1716
|
-
}
|
1777
|
+
initWords(config.words)
|
1778
|
+
isValidWordDef(config.words)
|
1717
1779
|
}
|
1718
1780
|
|
1719
1781
|
if (config && config.priorities) {
|
@@ -1778,7 +1840,16 @@ class Config {
|
|
1778
1840
|
getAddedArgs (args) {
|
1779
1841
|
for (let addedArgs of this.addedArgss) {
|
1780
1842
|
addedArgs = addedArgs(args)
|
1843
|
+
const getUUIDScoped = addedArgs.getUUIDScoped
|
1844
|
+
delete addedArgs.getUUIDScoped
|
1781
1845
|
Object.assign(args, addedArgs)
|
1846
|
+
if (getUUIDScoped) {
|
1847
|
+
const currentGetUUIDScoped = args.getUUIDScoped
|
1848
|
+
if (!currentGetUUIDScoped) {
|
1849
|
+
debugger
|
1850
|
+
}
|
1851
|
+
args.getUUIDScoped = (uuid) => Object.assign(currentGetUUIDScoped(uuid), getUUIDScoped(uuid))
|
1852
|
+
}
|
1782
1853
|
}
|
1783
1854
|
}
|
1784
1855
|
|
@@ -2020,10 +2091,28 @@ class Config {
|
|
2020
2091
|
this.config.namespaces = ns
|
2021
2092
|
}
|
2022
2093
|
|
2023
|
-
if (this.config.words) {
|
2024
|
-
|
2025
|
-
|
2026
|
-
|
2094
|
+
if (!this.config.words) {
|
2095
|
+
this.config.words = {}
|
2096
|
+
}
|
2097
|
+
|
2098
|
+
if (this.config.words.literals) {
|
2099
|
+
const literals = this.config.words.literals
|
2100
|
+
for (const key in literals) {
|
2101
|
+
literals[key].forEach((o) => {
|
2102
|
+
if (o.uuid) {
|
2103
|
+
if (map[o.uuid]) {
|
2104
|
+
o.uuid = map[o.uuid]
|
2105
|
+
}
|
2106
|
+
} else {
|
2107
|
+
o.uuid = this._uuid
|
2108
|
+
}
|
2109
|
+
})
|
2110
|
+
}
|
2111
|
+
}
|
2112
|
+
|
2113
|
+
const mapDefList = (list) => {
|
2114
|
+
for (const element of list) {
|
2115
|
+
element.defs.forEach((o) => {
|
2027
2116
|
if (o.uuid) {
|
2028
2117
|
if (map[o.uuid]) {
|
2029
2118
|
o.uuid = map[o.uuid]
|
@@ -2035,6 +2124,22 @@ class Config {
|
|
2035
2124
|
}
|
2036
2125
|
}
|
2037
2126
|
|
2127
|
+
if (this.config.words.patterns) {
|
2128
|
+
mapDefList(this.config.words.patterns)
|
2129
|
+
}
|
2130
|
+
|
2131
|
+
if (this.config.words.hierarchy) {
|
2132
|
+
for (const o of this.config.words.hierarchy) {
|
2133
|
+
if (o.uuid) {
|
2134
|
+
if (map[o.uuid]) {
|
2135
|
+
o.uuid = map[o.uuid]
|
2136
|
+
}
|
2137
|
+
} else {
|
2138
|
+
o.uuid = this._uuid
|
2139
|
+
}
|
2140
|
+
}
|
2141
|
+
}
|
2142
|
+
|
2038
2143
|
if (this.config.bridges) {
|
2039
2144
|
this.config.bridges.forEach((bridge) => {
|
2040
2145
|
if (bridge.uuid) {
|
@@ -2207,11 +2312,14 @@ class Config {
|
|
2207
2312
|
}
|
2208
2313
|
*/
|
2209
2314
|
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
|
2214
|
-
|
2315
|
+
const literals = this.config.words.literals
|
2316
|
+
if (literals) {
|
2317
|
+
for (const key in literals) {
|
2318
|
+
const values = literals[key]
|
2319
|
+
if (values.some((word) => (Object.keys(word).includes('uuid') && !word.uuid))) {
|
2320
|
+
debugBreak()
|
2321
|
+
return false
|
2322
|
+
}
|
2215
2323
|
}
|
2216
2324
|
}
|
2217
2325
|
|
@@ -2425,7 +2533,7 @@ class Config {
|
|
2425
2533
|
this.config.hierarchy = []
|
2426
2534
|
this.config.priorities = []
|
2427
2535
|
this.config.associations = { positive: [], negative: [] }
|
2428
|
-
this.config.words = {}
|
2536
|
+
this.config.words = initWords({})
|
2429
2537
|
|
2430
2538
|
for (let i = 0; i < addInternals.length; ++i) {
|
2431
2539
|
let name
|
@@ -2612,13 +2720,25 @@ class Config {
|
|
2612
2720
|
}
|
2613
2721
|
|
2614
2722
|
if (config.words) {
|
2615
|
-
const
|
2616
|
-
for (const word in config.words) {
|
2617
|
-
|
2723
|
+
const literals = {}
|
2724
|
+
for (const word in config.words.literals) {
|
2725
|
+
literals[word] = config.words.literals[word].map((word) => {
|
2618
2726
|
return Object.assign({}, word, { id: toNS(word.id), uuid })
|
2619
2727
|
})
|
2620
2728
|
}
|
2621
|
-
config.words =
|
2729
|
+
config.words.literals = literals
|
2730
|
+
|
2731
|
+
for (const pattern of config.words.patterns) {
|
2732
|
+
pattern.defs.forEach((def) => {
|
2733
|
+
def.id = toNS(def.id)
|
2734
|
+
def.uuid = uuid
|
2735
|
+
})
|
2736
|
+
}
|
2737
|
+
|
2738
|
+
for (const pair of config.words.hierarchy) {
|
2739
|
+
pair.child = toNS(pair.child)
|
2740
|
+
pair.parent = toNS(pair.parent)
|
2741
|
+
}
|
2622
2742
|
}
|
2623
2743
|
|
2624
2744
|
if (config.hierarchy) {
|
@@ -2739,6 +2859,7 @@ class Config {
|
|
2739
2859
|
throw new Error(`Setting invalid property ${property}`)
|
2740
2860
|
}
|
2741
2861
|
|
2862
|
+
// TODO trie
|
2742
2863
|
if (property == 'words') {
|
2743
2864
|
for (const word in value) {
|
2744
2865
|
for (const def of value[word]) {
|
@@ -2803,7 +2924,8 @@ class Config {
|
|
2803
2924
|
more = more.copy()
|
2804
2925
|
more.server(this._server, this._key, this._queryParams)
|
2805
2926
|
|
2806
|
-
|
2927
|
+
const moreConfigs = more.configs.map((km) => km.name || km.uuid)
|
2928
|
+
this.loadOrder.addList(moreConfigs)
|
2807
2929
|
|
2808
2930
|
// get the new ones
|
2809
2931
|
// remove the dups
|
@@ -2885,16 +3007,36 @@ class Config {
|
|
2885
3007
|
continue
|
2886
3008
|
}
|
2887
3009
|
if (key === 'words') {
|
2888
|
-
|
2889
|
-
|
2890
|
-
|
2891
|
-
|
2892
|
-
|
3010
|
+
if (more.words.literals) {
|
3011
|
+
const literals = this.config.words.literals
|
3012
|
+
const moreLiterals = more.words.literals
|
3013
|
+
for (const word of Object.keys(moreLiterals)) {
|
3014
|
+
if (!literals[word]) {
|
3015
|
+
literals[word] = []
|
3016
|
+
}
|
3017
|
+
if (addFirst) {
|
3018
|
+
literals[word] = moreLiterals[word].concat(literals[word])
|
3019
|
+
} else {
|
3020
|
+
literals[word] = literals[word].concat(moreLiterals[word])
|
3021
|
+
}
|
2893
3022
|
}
|
3023
|
+
}
|
3024
|
+
if (more.words.patterns) {
|
3025
|
+
const patterns = this.config.words.patterns
|
3026
|
+
const morePatterns = more.words.patterns
|
2894
3027
|
if (addFirst) {
|
2895
|
-
|
3028
|
+
this.config.words.patterns = morePatterns.concat(patterns)
|
2896
3029
|
} else {
|
2897
|
-
|
3030
|
+
this.config.words.patterns = patterns.concat(morePatterns)
|
3031
|
+
}
|
3032
|
+
}
|
3033
|
+
if (more.words.hierarchy) {
|
3034
|
+
const hierarchy = this.config.words.hierarchy
|
3035
|
+
const moreHierarchy = more.words.hierarchy
|
3036
|
+
if (addFirst) {
|
3037
|
+
this.config.words.hierarchy = moreHierarchy.concat(hierarchy)
|
3038
|
+
} else {
|
3039
|
+
this.config.words.hierarchy = hierarchy.concat(moreHierarchy)
|
2898
3040
|
}
|
2899
3041
|
}
|
2900
3042
|
} else if (key === 'name') {
|
@@ -3006,14 +3148,25 @@ class Config {
|
|
3006
3148
|
continue
|
3007
3149
|
}
|
3008
3150
|
if (key === 'words') {
|
3009
|
-
|
3010
|
-
|
3011
|
-
|
3012
|
-
|
3013
|
-
|
3151
|
+
if (this.config.words.literals) {
|
3152
|
+
const literals = this.config.words.literals
|
3153
|
+
const moreLiterals = more.words.literals
|
3154
|
+
for (const word of Object.keys(moreLiterals)) {
|
3155
|
+
if (!literals[word]) {
|
3156
|
+
literals[word] = []
|
3157
|
+
}
|
3158
|
+
literals[word] = moreLiterals[word].concat(literals[word])
|
3014
3159
|
}
|
3015
|
-
|
3016
|
-
|
3160
|
+
}
|
3161
|
+
if (this.config.words.patterns) {
|
3162
|
+
const patterns = this.config.words.patterns
|
3163
|
+
const morePatterns = more.words.patterns
|
3164
|
+
this.config.words.patterns = morePatterns.concat(patterns)
|
3165
|
+
}
|
3166
|
+
if (this.config.words.hierarchy) {
|
3167
|
+
const hierarchy = this.config.words.hierarchy
|
3168
|
+
const moreHierarchy = more.words.hierarchy
|
3169
|
+
this.config.words.hierarchy = moreHierarchy.concat(hierarchy)
|
3017
3170
|
}
|
3018
3171
|
} else if (key === 'name') {
|
3019
3172
|
/*
|
package/src/digraph.js
CHANGED
@@ -113,19 +113,31 @@ class Digraph {
|
|
113
113
|
}
|
114
114
|
|
115
115
|
minima (nodes) {
|
116
|
-
|
117
|
-
const
|
118
|
-
|
119
|
-
|
120
|
-
}
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
116
|
+
nodes = new Set(nodes)
|
117
|
+
const nodeToDescendants = {}
|
118
|
+
for (const node of nodes) {
|
119
|
+
nodeToDescendants[node] = this.descendants(node)
|
120
|
+
}
|
121
|
+
let minima = new Set()
|
122
|
+
for (const node of nodes) {
|
123
|
+
let okay = true
|
124
|
+
for (const key of nodeToDescendants[node]) {
|
125
|
+
if (nodes.has(key)) {
|
126
|
+
if (key in nodeToDescendants && nodeToDescendants[key].has(node)) {
|
127
|
+
continue
|
128
|
+
}
|
129
|
+
okay = false
|
130
|
+
break
|
131
|
+
}
|
132
|
+
}
|
133
|
+
if (okay) {
|
134
|
+
minima.add(node)
|
135
|
+
}
|
125
136
|
}
|
126
137
|
return minima
|
127
138
|
}
|
128
139
|
|
140
|
+
/*
|
129
141
|
maxima (nodes) {
|
130
142
|
const maxima = new Set(nodes)
|
131
143
|
const descendants = new Set([])
|
@@ -135,14 +147,21 @@ class Digraph {
|
|
135
147
|
descendants.forEach((n) => maxima.delete(n))
|
136
148
|
return maxima
|
137
149
|
}
|
150
|
+
*/
|
138
151
|
|
139
152
|
add (child, parent) {
|
140
153
|
this._edges.push([child, parent])
|
141
154
|
}
|
142
155
|
|
156
|
+
exists(child, parent) {
|
157
|
+
return this._edges.find((edge) => edge[0] == child && edge[1] == parent)
|
158
|
+
}
|
159
|
+
|
143
160
|
addList (l) {
|
144
161
|
for (let i = 1; i < l.length; ++i) {
|
145
|
-
this.
|
162
|
+
if (!this.exists(l[i-1], l[i])) {
|
163
|
+
this._edges.push([l[i - 1], l[i]])
|
164
|
+
}
|
146
165
|
}
|
147
166
|
}
|
148
167
|
|
package/src/digraph_internal.js
CHANGED
@@ -81,19 +81,31 @@ class DigraphInternal {
|
|
81
81
|
}
|
82
82
|
|
83
83
|
minima (nodes) {
|
84
|
-
|
85
|
-
const
|
86
|
-
|
87
|
-
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
nodes = new Set(nodes)
|
85
|
+
const nodeToDescendants = {}
|
86
|
+
for (const node of nodes) {
|
87
|
+
nodeToDescendants[node] = this.descendants(node)
|
88
|
+
}
|
89
|
+
let minima = new Set()
|
90
|
+
for (const node of nodes) {
|
91
|
+
let okay = true
|
92
|
+
for (const key of nodeToDescendants[node]) {
|
93
|
+
if (nodes.has(key)) {
|
94
|
+
if (key in nodeToDescendants && nodeToDescendants[key].has(node)) {
|
95
|
+
continue
|
96
|
+
}
|
97
|
+
okay = false
|
98
|
+
break
|
99
|
+
}
|
100
|
+
}
|
101
|
+
if (okay) {
|
102
|
+
minima.add(node)
|
103
|
+
}
|
93
104
|
}
|
94
105
|
return minima
|
95
106
|
}
|
96
107
|
|
108
|
+
/*
|
97
109
|
maxima (nodes) {
|
98
110
|
const maxima = new Set(nodes)
|
99
111
|
const descendants = new Set([])
|
@@ -103,14 +115,21 @@ class DigraphInternal {
|
|
103
115
|
descendants.forEach((n) => maxima.delete(n))
|
104
116
|
return maxima
|
105
117
|
}
|
118
|
+
*/
|
106
119
|
|
107
120
|
add (child, parent) {
|
108
121
|
this._edges.push([child, parent])
|
109
122
|
}
|
110
123
|
|
124
|
+
exists(child, parent) {
|
125
|
+
return this._edges.findIndex((edge) => edge[0] == child && edge[1] == parent) != -1
|
126
|
+
}
|
127
|
+
|
111
128
|
addList (l) {
|
112
129
|
for (let i = 1; i < l.length; ++i) {
|
113
|
-
this.
|
130
|
+
if (!this.exists(l[i-1], l[i])) {
|
131
|
+
this._edges.push([l[i - 1], l[i]])
|
132
|
+
}
|
114
133
|
}
|
115
134
|
}
|
116
135
|
|