theprogrammablemind 7.12.8 → 8.0.0-beta.1

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 CHANGED
@@ -47,7 +47,13 @@ const getConfig_getObjectsCheck = (config, testConfig) => {
47
47
  }
48
48
  const checks = (testConfig.checks && testConfig.checks.objects) || []
49
49
  if (Array.isArray(checks)) {
50
- return { [testConfigName]: checks }
50
+ const kmToChecks = { [testConfigName]: checks.filter( (check) => !check.km ) }
51
+ for (const check of checks) {
52
+ if (check.km) {
53
+ kmToChecks[check.km] = config.km(check.km).testConfig.checks.objects
54
+ }
55
+ }
56
+ return kmToChecks
51
57
  } else {
52
58
  return checks
53
59
  }
@@ -81,104 +87,6 @@ const pickObjects = (config, testConfig, getObjects) => {
81
87
  return projection
82
88
  }
83
89
 
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
90
  const sameJSON = (json1, json2) => {
183
91
  const sjson1 = sortJson(json1, { depth: 25 })
184
92
  const sjson2 = sortJson(json2, { depth: 25 })
@@ -300,7 +208,6 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
300
208
  }
301
209
  // for semantics
302
210
  args.addAssumedScoped(args, {})
303
- config.getAddedArgs(args)
304
211
 
305
212
  const getAPI = (uuid) => {
306
213
  if (config && config.getAPI) {
@@ -312,14 +219,14 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
312
219
  return config.getAPIs(uuid)
313
220
  }
314
221
  }
315
- const scopedAsk = getAsk(config)
316
222
  args.getUUIDScoped = (uuid) => {
317
223
  return {
318
- ask: scopedAsk(uuid),
319
224
  api: getAPI(uuid),
320
225
  apis: getAPIs(uuid)
321
226
  }
322
227
  }
228
+ config.getAddedArgs(args)
229
+
323
230
  Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
324
231
  /*
325
232
  if (uuidForScoping) {
@@ -540,7 +447,7 @@ const setupContexts = (rawContexts) => {
540
447
  return contexts
541
448
  }
542
449
 
543
- const processContextsB = ({ config, hierarchy, semantics, generators, json, isTest, isInstance, instance, query, data, retries, url, commandLineArgs }) => {
450
+ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTest, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs }) => {
544
451
  // TODO fix this name to contextsPrime
545
452
  const contextsPrime = []
546
453
  const generatedPrime = []
@@ -590,6 +497,9 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
590
497
  reason: e.reason,
591
498
  error: e.stack || e.error
592
499
  })
500
+ if (rebuildingTemplate) {
501
+ throw e
502
+ }
593
503
  }
594
504
  }
595
505
  if (contextPrime.controlRemove) {
@@ -745,17 +655,15 @@ const loadInstance = (config, instance) => {
745
655
  const results = instance.resultss[i]
746
656
  if (results.extraConfig) {
747
657
  // config.addInternal(results, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false)
748
- // config.addInternal(config.template.queries[i], { handleCalculatedProps: true } )
749
658
  const uuid = config.nameToUUID(instance.name)
750
659
  // used to do a CLONE
751
- // config.addInternal(_.cloneDeep(instance.template.queries[i]), { uuid, addFirst: true, handleCalculatedProps: true })
752
- config.addInternal(instance.template.queries[i], { uuid, addFirst: true, handleCalculatedProps: true })
660
+ config.addInternal(instance.template.configs[i], { uuid, addFirst: true, handleCalculatedProps: true })
753
661
  } else if (results.apply) {
754
662
  const objects = config.get('objects')
755
663
  const args = { objects, getObjects: getObjects(objects) }
756
- if (instance.queries) {
664
+ if (instance.configs) {
757
665
  args.isInstance = `instance${i}`
758
- args.instance = instance.queries[i]
666
+ args.instance = instance.configs[i]
759
667
  }
760
668
 
761
669
  const uuid = config.nameToUUID(instance.name)
@@ -865,7 +773,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
865
773
  start = runtime.performance.performance.now()
866
774
  }
867
775
  const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
868
- processContextsB({ isTest, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
776
+ processContextsB({ isTest, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
869
777
  if (isTest) {
870
778
  end = runtime.performance.performance.now()
871
779
  clientSideTime = end - start
@@ -923,15 +831,27 @@ const getConfigForTest = (config, testConfig) => {
923
831
  // configForTest[key] = config.config[key]
924
832
  if (key === 'words') {
925
833
  const words = config.config.words
926
- configForTest.words = {}
927
- for (const key of Object.keys(words)) {
834
+ configForTest.words = {
835
+ literals: {},
836
+ patterns: [],
837
+ hierarchy: [],
838
+ }
839
+
840
+ const literals = config.config.words.literals
841
+ for (const key in literals) {
928
842
  const defs = []
929
- for (const def of words[key]) {
843
+ for (const def of literals[key]) {
930
844
  // TODO handle thie uuids the right way
931
845
  defs.push(Object.assign({}, def, { uuid: undefined }))
932
846
  }
933
- configForTest.words[key] = defs
847
+ configForTest.words.literals[key] = defs
934
848
  }
849
+
850
+ const patterns = config.config.words.patterns
851
+ configForTest.words.patterns = patterns.map((pattern) => Object.assign({}, pattern, { uuid: undefined }))
852
+
853
+ const hierarchy = config.config.words.hierarchy
854
+ configForTest.words.hierarchy = hierarchy.map((hierarchy) => Object.assign({}, hierarchy, { uuid: undefined }))
935
855
  } else if (key === 'operators') {
936
856
  configForTest.operators = config.config.operators.map((operator) => Object.assign({}, operator, { uuid: undefined }))
937
857
  } else if (key === 'bridges') {
@@ -1281,7 +1201,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1281
1201
  console.log('Errors')
1282
1202
  responses.errors.forEach((error) => console.log(` ${error}`))
1283
1203
  }
1284
- console.log("KM's loaded", config.configs.map((c) => c.name))
1204
+ console.log("KM's loaded (ordered)", config.configs.map((c) => c.name))
1285
1205
  console.log('This is the global objects from running semantics:\n', config.objects)
1286
1206
  if (!_.isEmpty(responses.learned_contextual_priorities)) {
1287
1207
  console.log('\nThe learned contextual priorties are :\n')
@@ -1404,12 +1324,12 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1404
1324
  associations: [],
1405
1325
  learned_contextual_priorities: []
1406
1326
  }
1407
- const looper = async (queries) => {
1408
- if (queries.length === 0) {
1327
+ const looper = async (configs) => {
1328
+ if (configs.length === 0) {
1409
1329
  finish()
1410
1330
  return
1411
1331
  }
1412
- const { property, hierarchy, query: queryOrExtraConfig, previousResults, initializer, skipSemantics } = queries.shift()
1332
+ const { property, hierarchy, query: queryOrExtraConfig, previousResults, initializer, skipSemantics } = configs.shift()
1413
1333
  // queries are strings or { query: "blah", development: true/false }
1414
1334
  if (typeof queryOrExtraConfig === 'string' || queryOrExtraConfig.query) {
1415
1335
  let query = queryOrExtraConfig
@@ -1461,7 +1381,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1461
1381
  accumulators[property].push(results)
1462
1382
  accumulators.associations = accumulators.associations.concat(results.associations)
1463
1383
  accumulators.learned_contextual_priorities = accumulators.learned_contextual_priorities.concat(results.learned_contextual_priorities)
1464
- await looper(queries)
1384
+ await looper(configs)
1465
1385
  } catch (e) {
1466
1386
  const error = { errors: [e], query: query.query }
1467
1387
  config.config.skipSemantics = null
@@ -1475,7 +1395,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1475
1395
  setupArgs(args, config, config.logs, hierarchy)
1476
1396
  initFunction(args)
1477
1397
  accumulators[property].push({ apply: queryOrExtraConfig })
1478
- await looper(queries)
1398
+ await looper(configs)
1479
1399
  } else {
1480
1400
  // extra config is def from a time like operators or bridges or words etc
1481
1401
  // it will just get added to the config
@@ -1491,7 +1411,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1491
1411
  throw new Error(`Error processing extra config${where}: ${e.stack}}`)
1492
1412
  }
1493
1413
  accumulators[property].push({ extraConfig: true, ...extraConfig })
1494
- await looper(queries)
1414
+ await looper(configs)
1495
1415
  }
1496
1416
  }
1497
1417
  }
@@ -1531,7 +1451,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1531
1451
  return template
1532
1452
  }
1533
1453
  stabilizeOutput(accumulators)
1534
- runtime.fs.writeFileSync(instanceName, JSON.stringify(Object.assign({ queries: template.queries.map(updateQueries) }, accumulators), 0, 2))
1454
+ runtime.fs.writeFileSync(instanceName, JSON.stringify(Object.assign({ configs: template.configs.map(updateQueries) }, accumulators), 0, 2))
1535
1455
 
1536
1456
  // km tests file
1537
1457
  const testsName = `./${target}.test.json`
@@ -1550,7 +1470,7 @@ const rebuildTemplate = async ({ config, target, previousResultss, startOfChange
1550
1470
  }
1551
1471
  let todo = []
1552
1472
  todo = todo.concat((template.initializers || []).map((query) => { return { initializer: true, property: 'resultss', query, skipSemantics: false || query.skipSemantics } }))
1553
- todo = todo.concat((template.queries || []).map((query, index) => {
1473
+ todo = todo.concat((template.configs || []).map((query, index) => {
1554
1474
  let pr
1555
1475
  if (index < startOfChanges) {
1556
1476
  pr = previousResultss[index]
@@ -1600,19 +1520,6 @@ const knowledgeModuleImpl = async ({
1600
1520
  acceptsAdditionalConfig = false,
1601
1521
  ...rest
1602
1522
  } = {}) => {
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
1523
  const unknownArgs = Object.keys(rest)
1617
1524
  if (unknownArgs.length > 0) {
1618
1525
  throw new Error(`Unknown arguments to knowledgeModule: ${unknownArgs.join()}`)
@@ -1659,19 +1566,16 @@ const knowledgeModuleImpl = async ({
1659
1566
  }
1660
1567
 
1661
1568
  if (isProcess) {
1662
- const config = createConfig()
1663
- setupConfig(config)
1664
- processResults = processResults({ config, errorHandler })
1665
- // setup();
1666
1569
  const parser = new runtime.ArgumentParser({
1667
1570
  description: 'Entodicton knowledge module'
1668
1571
  })
1669
1572
 
1573
+ 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"\''
1670
1574
  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]]\''
1671
1575
  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]]\''
1672
1576
  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]]\''
1673
1577
  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}\''
1674
- const helpDebugBridge = 'In order to get a debug break when a specific bridge is created set the DEBUG_BRIDGE environment variable to id/level to break on. For example DEBUG_BRIDGE=\'id#level\''
1578
+ 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\''
1675
1579
  const helpDebugOperator = 'In order to get a debug break when a specific hierarcy is created set the DEBUG_OPERATOR environment variable to debug any config loaded. For example DEBUG_OPERATOR=\'([operator] ([arg]))\''
1676
1580
 
1677
1581
  parser.add_argument('-tmn', '--testModuleName', { help: 'When running tests instead of using the current modules tests use the specified modules tests' })
@@ -1703,6 +1607,7 @@ const knowledgeModuleImpl = async ({
1703
1607
  parser.add_argument('-dl', '--debugLoops', { action: 'store_true', help: 'When running with the --debugLoops flag the logs calls to semantics and generators will be immediately written to the console ' })
1704
1608
  parser.add_argument('-d', '--debug', { action: 'store_true', help: 'When running with the --debug flag this set the debug flag in the config' })
1705
1609
  parser.add_argument('-da', '--debugAssociation', { action: 'store_true', help: helpDebugAssociation })
1610
+ parser.add_argument('-dw', '--debugWord', { action: 'store_true', help: helpDebugWord })
1706
1611
  parser.add_argument('-dh', '--debugHierarchy', { action: 'store_true', help: helpDebugHierarchy })
1707
1612
  parser.add_argument('-dp', '--debugPriority', { action: 'store_true', help: helpDebugPriority })
1708
1613
  parser.add_argument('-dcp', '--debugContextualPriority', { action: 'store_true', help: helpDebugContextualPriority })
@@ -1718,6 +1623,21 @@ const knowledgeModuleImpl = async ({
1718
1623
  args.rebuildTemplate = true
1719
1624
  }
1720
1625
 
1626
+ // dont debug the load of the KM's if rebuild template is on since we want to debug the template rebuild not the load
1627
+ if (args.rebuildTemplate) {
1628
+ global.pauseDebugging = true
1629
+ }
1630
+
1631
+ const config = createConfig()
1632
+ setupConfig(config)
1633
+ processResults = processResults({ config, errorHandler })
1634
+
1635
+ if (args.rebuildTemplate) {
1636
+ global.pauseDebugging = false
1637
+ }
1638
+
1639
+ // setup();
1640
+
1721
1641
  if (args.parenthesized) {
1722
1642
  config.parenthesized = true
1723
1643
  }
@@ -1754,6 +1674,10 @@ const knowledgeModuleImpl = async ({
1754
1674
  console.log(helpDebugAssociation)
1755
1675
  runtime.process.exit(-1)
1756
1676
  }
1677
+ if (args.debugWord) {
1678
+ console.log(helpDebugWord)
1679
+ runtime.process.exit(-1)
1680
+ }
1757
1681
  if (args.debugHierarchy) {
1758
1682
  console.log(helpDebugHierarchy)
1759
1683
  runtime.process.exit(-1)
@@ -1846,8 +1770,14 @@ const knowledgeModuleImpl = async ({
1846
1770
  }
1847
1771
  }
1848
1772
  if (args.print.includes('w')) {
1849
- for (const word in config.config.words) {
1850
- console.log(word.concat(' ', ...config.config.words[word].map((def) => JSON.stringify(def))))
1773
+ // { literals: Object, patterns: Array(2), hierarchy: Array(97) }
1774
+ console.log('literals')
1775
+ for (const word in config.config.words.literals) {
1776
+ console.log(' ' + word.concat(' ', ...config.config.words.literals[word].map((def) => JSON.stringify(def))))
1777
+ }
1778
+ console.log('patterns')
1779
+ for (const pattern of config.config.words.patterns) {
1780
+ console.log(' ' + JSON.stringify(pattern))
1851
1781
  }
1852
1782
  }
1853
1783
  if (args.print.includes('b')) {
@@ -2270,6 +2200,7 @@ const knowledgeModule = async (...args) => {
2270
2200
 
2271
2201
  module.exports = {
2272
2202
  process: _process,
2203
+ stableId,
2273
2204
  where,
2274
2205
  w,
2275
2206
  // submitBug,
package/index.js CHANGED
@@ -15,6 +15,7 @@ module.exports = {
15
15
  knowledgeModule: client.knowledgeModule,
16
16
  ensureTestFile: client.ensureTestFile,
17
17
  where: client.where,
18
+ stableId: client.stableId,
18
19
  w: client.w,
19
20
  Config,
20
21
  Semantics,
package/package.json CHANGED
@@ -65,6 +65,6 @@
65
65
  "json-stable-stringify": "^1.0.1",
66
66
  "node-fetch": "^2.6.1"
67
67
  },
68
- "version": "7.12.8",
68
+ "version": "8.0.0-beta.1",
69
69
  "license": "UNLICENSED"
70
70
  }
package/src/config.js CHANGED
@@ -26,7 +26,23 @@ 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) => {
43
+ if (global.pauseDebugging) {
44
+ return
45
+ }
30
46
  if (global.entodictonDebugPriority) {
31
47
  if (helpers.subPriority(entodictonDebugPriority, priority)) {
32
48
  debugger // debug hierarchy hit
@@ -35,6 +51,9 @@ const debugPriority = (priority) => {
35
51
  }
36
52
 
37
53
  const debugAssociation = (association) => {
54
+ if (global.pauseDebugging) {
55
+ return
56
+ }
38
57
  if (global.entodictonDebugAssociation) {
39
58
  if (helpers.safeEquals(global.entodictonDebugAssociation, association)) {
40
59
  debugger // debug association hit
@@ -42,7 +61,21 @@ const debugAssociation = (association) => {
42
61
  }
43
62
  }
44
63
 
64
+ const debugWord = (word) => {
65
+ if (global.pauseDebugging) {
66
+ return
67
+ }
68
+ if (global.entodictonDebugWord) {
69
+ if (helpers.safeEquals(global.entodictonDebugWord, word)) {
70
+ debugger // debug word hit
71
+ }
72
+ }
73
+ }
74
+
45
75
  const debugHierarchy = (pair) => {
76
+ if (global.pauseDebugging) {
77
+ return
78
+ }
46
79
  if (global.entodictonDebugHierarchy) {
47
80
  if (helpers.safeEquals(global.entodictonDebugHierarchy, pair)) {
48
81
  debugger // debug hierarchy hit
@@ -51,14 +84,20 @@ const debugHierarchy = (pair) => {
51
84
  }
52
85
 
53
86
  const debugBridge = (bridge) => {
87
+ if (global.pauseDebugging) {
88
+ return
89
+ }
54
90
  if (global.entodictonDebugBridge) {
55
- if (global.entodictonDebugBridge[0] == bridge.id && global.entodictonDebugBridge[1] == bridge.level) {
91
+ if (global.entodictonDebugBridge == bridge.id) {
56
92
  debugger // debug hierarchy hit
57
93
  }
58
94
  }
59
95
  }
60
96
 
61
97
  const debugOperator = (operator) => {
98
+ if (global.pauseDebugging) {
99
+ return
100
+ }
62
101
  if (global.entodictonDebugOperator) {
63
102
  if ((operator.pattern || operator) === global.entodictonDebugOperator) {
64
103
  debugger // debug operator hit
@@ -67,18 +106,29 @@ const debugOperator = (operator) => {
67
106
  }
68
107
 
69
108
  const debugConfigProps = (config) => {
109
+ if (global.pauseDebugging) {
110
+ return
111
+ }
70
112
  if (!config) {
71
113
  return
72
114
  }
73
115
  const checkProps = [
74
116
  { property: 'priorities', check: (v) => debugPriority(v) },
75
117
  { property: 'association', check: (v) => debugAssociation(v) },
118
+ { property: 'words', check: (v) => debugAssociation(v) },
76
119
  { property: 'hierarchy', check: (v) => debugHierarchy(v) },
77
120
  { property: 'operators', check: (v) => debugOperator(v) },
78
121
  { property: 'bridges', check: (v) => debugBridge(v) }
79
122
  ]
80
123
  for (const { property, check } of checkProps) {
81
- if (config[property]) {
124
+ if (property == 'words') {
125
+ if (config[property]) {
126
+ for (const value in config[property].literals) {
127
+ check(value)
128
+ }
129
+ }
130
+ }
131
+ else if (config[property]) {
82
132
  for (const value of config[property]) {
83
133
  check(value)
84
134
  }
@@ -123,6 +173,7 @@ const validConfigProps = (config) => {
123
173
 
124
174
  const setupInitializerFNArgs = (config, args) => {
125
175
  const aw = (word, def) => config.addWord(word, def, args.uuid)
176
+ const ap = (pattern, def) => config.addPattern(pattern, def, args.uuid)
126
177
  const ag = (generator) => config.addGenerator(generator, args.uuid, config.name)
127
178
  const km = (name) => config.getConfig(name)
128
179
  const apis = (name) => config.getConfig(name).api
@@ -130,6 +181,7 @@ const setupInitializerFNArgs = (config, args) => {
130
181
  return {
131
182
  ...args,
132
183
  addWord: aw,
184
+ addPattern: ap,
133
185
  addGenerator: ag,
134
186
  config: config.getPseudoConfig(args.uuid, args.currentConfig),
135
187
  km,
@@ -213,6 +265,9 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
213
265
  config.addHierarchy(child, bridge.id)
214
266
  }
215
267
  }
268
+ if (bridge.operator) {
269
+ config.addOperator(bridge.operator, uuid || config.uuid)
270
+ }
216
271
  if (bridge.parents) {
217
272
  for (const parent of bridge.parents) {
218
273
  config.addHierarchy(bridge.id, parent)
@@ -242,7 +297,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
242
297
  if (bridge.words) {
243
298
  for (let def of bridge.words) {
244
299
  if (typeof def === 'string') {
245
- config.addWordInternal(def, { id: bridge.id, initial: `{ value: "${def}"}` })
300
+ config.addWordInternal(def, { id: bridge.id, initial: `{ value: "${bridge.id}"}` })
246
301
  } else {
247
302
  const word = def.word
248
303
  def = { initial: JSON.stringify(def), id: bridge.id, word }
@@ -329,7 +384,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
329
384
  if (bridge.semantic) {
330
385
  const semantic = {
331
386
  where: bridge.semantic.where || bridge.where || client.where(3),
332
- match: ({ context }) => bridge.id == context.marker,
387
+ match: ({ context }) => bridge.id == context.marker && !context.evaluate,
333
388
  apply: (args) => bridge.semantic(args),
334
389
  applyWrapped: bridge.semantic,
335
390
  property: 'semantic'
@@ -348,7 +403,7 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
348
403
  if (moreConfig.bridges) {
349
404
  moreConfig.bridges = moreConfig.bridges.map((bridge) => {
350
405
  bridge = { ...bridge }
351
- const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
406
+ const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'operator', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
352
407
  'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid']
353
408
  helpers.validProps(valid, bridge, 'bridge')
354
409
  handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
@@ -386,13 +441,13 @@ if (runtime.process.env.DEBUG_ASSOCIATION) {
386
441
  global.entodictonDebugAssociation = JSON.parse(runtime.process.env.DEBUG_ASSOCIATION)
387
442
  }
388
443
 
444
+ if (runtime.process.env.DEBUG_WORD) {
445
+ global.entodictonDebugWord = runtime.process.env.DEBUG_WORD
446
+ }
447
+
389
448
  if (runtime.process.env.DEBUG_BRIDGE) {
390
- // id/level
391
- global.entodictonDebugBridge = runtime.process.env.DEBUG_BRIDGE.split('/')
392
- if (global.entodictonDebugBridge.length !== 2) {
393
- console.log('Expected DEBUG_BRIDGE to be of the form "id/level"')
394
- process.exit(-1)
395
- }
449
+ // id
450
+ global.entodictonDebugBridge = runtime.process.env.DEBUG_BRIDGE
396
451
  global.entodictonDebugBridge[1] = parseInt(global.entodictonDebugBridge[1])
397
452
  }
398
453
 
@@ -409,10 +464,13 @@ const hierarchyCanonical = (element) => {
409
464
  }
410
465
  }
411
466
 
412
- const isValidDef = (word, def, config) => {
467
+ const isValidWordDef = (word, def, config) => {
468
+ // TODO trie
469
+ /*
413
470
  if (!def.id) {
414
471
  throw new Error(`In the KM "${config.name}", for the word ${word} the following definition is missing the "id" property: ${JSON.stringify(def)}`)
415
472
  }
473
+ */
416
474
  /*
417
475
  if (!def.initial) {
418
476
  throw `In the KM "${config.name}", for the word ${word} the following definition is missing the "initial" property: ${JSON.stringify(def)}`
@@ -429,16 +487,20 @@ const hierarchyToCanonical = (edge) => {
429
487
 
430
488
  const addWord = (config, uuid) => ({ word, id, initial }) => {
431
489
  if (!config.words) {
432
- config.words = {}
490
+ config.words = {
491
+ literals: {},
492
+ patterns: [],
493
+ hierarchy: [],
494
+ }
433
495
  }
434
- const words = config.words
496
+ const literals = config.words.literals
435
497
  const def = { id, initial, uuid }
436
- if (words[word]) {
437
- if (!words[word].some((e) => helpers.safeEquals(e, def))) {
438
- words[word].unshift(def)
498
+ if (literals[word]) {
499
+ if (!literals[word].some((e) => helpers.safeEquals(e, def))) {
500
+ literals[word].unshift(def)
439
501
  }
440
502
  } else {
441
- words[word] = [def]
503
+ literals[word] = [def]
442
504
  }
443
505
  }
444
506
 
@@ -453,6 +515,7 @@ const normalizeConfig = (config) => {
453
515
  }
454
516
  }
455
517
  }
518
+
456
519
  if (config.bridges) {
457
520
  for (const bridge of config.bridges) {
458
521
  if (!bridge.level) {
@@ -471,6 +534,14 @@ const normalizeConfig = (config) => {
471
534
  }
472
535
  }
473
536
  }
537
+
538
+ if (config.operators) {
539
+ for (let i = 0; i < config.operators.length; ++i) {
540
+ if (typeof config.operators[i] === 'string') {
541
+ config.operators[i] = { pattern: config.operators[i] }
542
+ }
543
+ }
544
+ }
474
545
  }
475
546
  }
476
547
 
@@ -488,8 +559,17 @@ function configDup (config, options) {
488
559
  }
489
560
 
490
561
  function setWordsUUIDs (words, uuid) {
491
- for (const key in words) {
492
- words[key] = words[key].map((o) => Object.assign(o, { uuid }))
562
+ const literals = words.literals
563
+ for (const key in literals) {
564
+ literals[key] = literals[key].map((o) => Object.assign(o, { uuid }))
565
+ }
566
+ const patterns = words.patterns
567
+ for (const pattern of patterns) {
568
+ pattern.defs.map((def) => Object.assign(def, { uuid }))
569
+ }
570
+ const hierarchy = words.hierarchy
571
+ for (const pair of hierarchy) {
572
+ pair.uuid = uuid
493
573
  }
494
574
  }
495
575
 
@@ -740,7 +820,7 @@ class Config {
740
820
  }
741
821
  const templateQueries = []
742
822
  if (this.instances && this.instances.length > 0) {
743
- for (const query of this.instances.slice(-1)[0].queries) {
823
+ for (const query of this.instances.slice(-1)[0].configs) {
744
824
  if (typeof query === 'string') {
745
825
  templateQueries.push(query)
746
826
  }
@@ -764,6 +844,7 @@ class Config {
764
844
  addSemantic: (...args) => this.addSemantic(...args, uuid, config.name),
765
845
  removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
766
846
  addWord: (...args) => this.addWord(...args, uuid),
847
+ addPattern: (...args) => this.addPattern(...args, uuid),
767
848
 
768
849
  getHierarchy: (...args) => this.config.hierarchy,
769
850
  getBridges: (...args) => this.config.bridges,
@@ -785,28 +866,6 @@ class Config {
785
866
  }
786
867
  }
787
868
 
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
869
  getCounter (maybeName = '') {
811
870
  const counter = this.configCounter
812
871
  this.configCounter += 1
@@ -843,7 +902,11 @@ class Config {
843
902
  namespaced: {}
844
903
  },
845
904
  description: '',
846
- words: {}, // Done
905
+ words: {
906
+ literals: {},
907
+ patterns: [],
908
+ hierarchy: [],
909
+ }, // Done
847
910
  floaters: [],
848
911
  implicits: [],
849
912
  flatten: [],
@@ -1102,8 +1165,8 @@ class Config {
1102
1165
  return elements.map(toCanonicalQuery)
1103
1166
  }
1104
1167
 
1105
- const templateQueries = toCanonicalQueries(template.queries || []).map(helpers.updateQueries)
1106
- const instanceQueries = toCanonicalQueries(instance.queries || [])
1168
+ const templateQueries = toCanonicalQueries(template.configs || []).map(helpers.updateQueries)
1169
+ const instanceQueries = toCanonicalQueries(instance.configs || [])
1107
1170
  let sameQueries = true
1108
1171
  let startOfChanges
1109
1172
  for (let iq = 0; iq < templateQueries.length; ++iq) {
@@ -1124,7 +1187,6 @@ class Config {
1124
1187
  if (templateQueries.length < instanceQueries.length) {
1125
1188
  startOfChanges = instanceQueries.length
1126
1189
  }
1127
- // const sameQueries = helpers.safeEquals(toCanonicalQueries(template.queries || []).map(helpers.updateQueries), toCanonicalQueries(instance.queries || []))
1128
1190
 
1129
1191
  if (debug) {
1130
1192
  if (!(instance && sameQueries && sameFragments)) {
@@ -1133,8 +1195,6 @@ class Config {
1133
1195
  console.log('sameFragments', sameFragments)
1134
1196
  // console.log("templateFragments", templateFragments)
1135
1197
  // 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
1198
  }
1139
1199
  }
1140
1200
  if (startOfChanges || instance.resultss) {
@@ -1145,13 +1205,13 @@ class Config {
1145
1205
  }
1146
1206
 
1147
1207
  validifyTemplate (template) {
1148
- if (!template.queries && !template.fragments) {
1149
- throw new Error(`Expected the template for ${this.name} to be an object that can have the properties: queries and fragments`)
1208
+ if (!template.configs && !template.fragments) {
1209
+ throw new Error(`Expected the template for ${this.name} to be an object that can have the properties: configs and fragments`)
1150
1210
  }
1151
- for (const query of template.queries || []) {
1211
+ for (const query of template.configs || []) {
1152
1212
  if (typeof query === 'string') {
1153
1213
  } else if (query instanceof Config) {
1154
- throw new Error(`For the template for ${this.name}, each element in queries should be either a string or a structure with a config (not a Config object).`)
1214
+ 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
1215
  }
1156
1216
  }
1157
1217
  }
@@ -1168,7 +1228,7 @@ class Config {
1168
1228
  this.logs.push(`loading template for ${this.name}`)
1169
1229
  if (options.rebuild) {
1170
1230
  // TODO fix beforeQuery
1171
- template = { fragments: [], queries: [], ...template }
1231
+ template = { fragments: [], configs: [], ...template }
1172
1232
  template.fragments = template.fragments.concat(this.dynamicFragments)
1173
1233
  client.rebuildTemplate({ config: this, target: this.name, previousResultss: options.previousResultss, startOfChanges: options.startOfChanges, beforeQuery: () => {}, template, ...options })
1174
1234
  } else {
@@ -1176,7 +1236,7 @@ class Config {
1176
1236
  // this.initInstances.push({ ...instance, name: config.name })
1177
1237
  const isEmpty = (instance) => {
1178
1238
  const properties = [
1179
- 'queries',
1239
+ 'configs',
1180
1240
  'resultss',
1181
1241
  'fragments',
1182
1242
  'semantics',
@@ -1189,7 +1249,7 @@ class Config {
1189
1249
  for (let i = 0; i < instance.resultss.length; ++i) {
1190
1250
  const result = instance.resultss[i]
1191
1251
  if (result.apply) {
1192
- result.apply = template.queries[i]
1252
+ result.apply = template.configs[i]
1193
1253
  }
1194
1254
  }
1195
1255
  instance.name = this.name
@@ -1429,21 +1489,42 @@ class Config {
1429
1489
 
1430
1490
  addWordInternal (word, def, uuid) {
1431
1491
  if (!this.config.words) {
1432
- this.config.words = {}
1492
+ this.config.words = {
1493
+ literals: {},
1494
+ patterns: [],
1495
+ hierarchy: [],
1496
+ }
1433
1497
  }
1434
- const words = this.config.words
1498
+ debugWord(word)
1499
+
1500
+ const literals = this.config.words.literals
1435
1501
  def = Object.assign({}, def, { uuid: uuid || this._uuid })
1436
- if (words[word]) {
1437
- if (!words[word].some((e) => helpers.safeEquals(e, def))) {
1438
- words[word].unshift(def)
1502
+ if (literals[word]) {
1503
+ if (!literals[word].some((e) => helpers.safeEquals(e, def))) {
1504
+ literals[word].unshift(def)
1439
1505
  }
1440
1506
  } else {
1441
- words[word] = [def]
1507
+ literals[word] = [def]
1442
1508
  }
1443
1509
 
1444
1510
  this._delta.json.words.push({ action: 'add', word, def })
1445
1511
  }
1446
1512
 
1513
+ addPattern (pattern, def, uuid) {
1514
+ if (!this.config.words) {
1515
+ this.config.words = {
1516
+ literals: {},
1517
+ patterns: [],
1518
+ hierarchy: [],
1519
+ }
1520
+ }
1521
+
1522
+ const patterns = this.config.words.patterns
1523
+ def = Object.assign({}, def, { uuid: uuid || this._uuid })
1524
+ patterns.unshift({ pattern, defs: [def] })
1525
+ this._delta.json.words.push({ action: 'add', pattern, defs: [def] })
1526
+ }
1527
+
1447
1528
  getAPI (uuid) {
1448
1529
  if (this._uuid === uuid) {
1449
1530
  return this.api
@@ -1539,6 +1620,10 @@ class Config {
1539
1620
  return client.process(this, query, options)
1540
1621
  }
1541
1622
 
1623
+ processQuery (query, options) {
1624
+ return this.process(query, options)
1625
+ }
1626
+
1542
1627
  initDefaults () {
1543
1628
  const init = (config) => {
1544
1629
  if (!config.objects) {
@@ -1637,13 +1722,35 @@ class Config {
1637
1722
  config.generators = config.generators.filter((element) => !element.development)
1638
1723
  config.semantics = config.semantics.filter((element) => !element.development)
1639
1724
  config.hierarchy = (config.hierarchy).filter((element) => !element.development)
1640
- for (const word in config.words) {
1641
- const defs = config.words[word] || []
1642
- config.words[word] = defs.filter((def) => !def.development)
1643
- if (config.words[word].length == 0) {
1644
- delete config.words[word]
1725
+
1726
+ const literals = config.words.literals
1727
+ for (const word in literals) {
1728
+ const defs = literals[word] || []
1729
+ literals[word] = defs.filter((def) => !def.development)
1730
+ if (literals[word].length == 0) {
1731
+ delete literals[word]
1732
+ }
1733
+ }
1734
+
1735
+ const patterns = config.words.patterns || []
1736
+ const patternsPrime = []
1737
+ for (const pattern of patterns) {
1738
+ let defs = pattern.defs || []
1739
+ defs = defs.filter((def) => !def.development)
1740
+ if (defs.length !== 0) {
1741
+ patternsPrime.push({...pattern, defs})
1645
1742
  }
1646
1743
  }
1744
+ config.words.patterns = patternsPrime
1745
+
1746
+ const hierarchy = config.words.hierarchy || []
1747
+ const hierarchyPrime = []
1748
+ for (const pair of hierarchy) {
1749
+ if (!pair.development) {
1750
+ hierarchyPrime.push(pair)
1751
+ }
1752
+ }
1753
+ config.words.hierarchy = hierarchyPrime
1647
1754
  }
1648
1755
 
1649
1756
  // configs = [ { config, namespace } ... ]
@@ -1657,7 +1764,7 @@ class Config {
1657
1764
 
1658
1765
  config.operators = config.operators || []
1659
1766
  config.bridges = config.bridges || []
1660
- config.words = config.words || {}
1767
+ config.words = config.words || { literals: {}, patterns: [], hierarchy: [] }
1661
1768
  config.generators = config.generators || []
1662
1769
  config.semantics = config.semantics || []
1663
1770
  config.hierarchy = config.hierarchy || []
@@ -1687,7 +1794,7 @@ class Config {
1687
1794
  this.instances = []
1688
1795
  this.logs = []
1689
1796
  this.dynamicFragments = []
1690
- // when running queries any bridges added are marked as transitory so that the associated will ignore those op's
1797
+ // when running configs any bridges added are marked as transitory so that the associated will ignore those op's
1691
1798
  this.transitoryMode = false
1692
1799
 
1693
1800
  // check for duplicate bridges
@@ -1709,11 +1816,8 @@ class Config {
1709
1816
  }
1710
1817
 
1711
1818
  if (config && config.words) {
1712
- for (const word of Object.keys(config.words)) {
1713
- for (const def of config.words[word]) {
1714
- isValidDef(word, def, config)
1715
- }
1716
- }
1819
+ initWords(config.words)
1820
+ isValidWordDef(config.words)
1717
1821
  }
1718
1822
 
1719
1823
  if (config && config.priorities) {
@@ -1778,7 +1882,16 @@ class Config {
1778
1882
  getAddedArgs (args) {
1779
1883
  for (let addedArgs of this.addedArgss) {
1780
1884
  addedArgs = addedArgs(args)
1885
+ const getUUIDScoped = addedArgs.getUUIDScoped
1886
+ delete addedArgs.getUUIDScoped
1781
1887
  Object.assign(args, addedArgs)
1888
+ if (getUUIDScoped) {
1889
+ const currentGetUUIDScoped = args.getUUIDScoped
1890
+ if (!currentGetUUIDScoped) {
1891
+ debugger
1892
+ }
1893
+ args.getUUIDScoped = (uuid) => Object.assign(currentGetUUIDScoped(uuid), getUUIDScoped(uuid))
1894
+ }
1782
1895
  }
1783
1896
  }
1784
1897
 
@@ -2020,10 +2133,14 @@ class Config {
2020
2133
  this.config.namespaces = ns
2021
2134
  }
2022
2135
 
2023
- if (this.config.words) {
2024
- const words = this.config.words
2025
- for (const key in words) {
2026
- words[key].forEach((o) => {
2136
+ if (!this.config.words) {
2137
+ this.config.words = {}
2138
+ }
2139
+
2140
+ if (this.config.words.literals) {
2141
+ const literals = this.config.words.literals
2142
+ for (const key in literals) {
2143
+ literals[key].forEach((o) => {
2027
2144
  if (o.uuid) {
2028
2145
  if (map[o.uuid]) {
2029
2146
  o.uuid = map[o.uuid]
@@ -2035,6 +2152,36 @@ class Config {
2035
2152
  }
2036
2153
  }
2037
2154
 
2155
+ const mapDefList = (list) => {
2156
+ for (const element of list) {
2157
+ element.defs.forEach((o) => {
2158
+ if (o.uuid) {
2159
+ if (map[o.uuid]) {
2160
+ o.uuid = map[o.uuid]
2161
+ }
2162
+ } else {
2163
+ o.uuid = this._uuid
2164
+ }
2165
+ })
2166
+ }
2167
+ }
2168
+
2169
+ if (this.config.words.patterns) {
2170
+ mapDefList(this.config.words.patterns)
2171
+ }
2172
+
2173
+ if (this.config.words.hierarchy) {
2174
+ for (const o of this.config.words.hierarchy) {
2175
+ if (o.uuid) {
2176
+ if (map[o.uuid]) {
2177
+ o.uuid = map[o.uuid]
2178
+ }
2179
+ } else {
2180
+ o.uuid = this._uuid
2181
+ }
2182
+ }
2183
+ }
2184
+
2038
2185
  if (this.config.bridges) {
2039
2186
  this.config.bridges.forEach((bridge) => {
2040
2187
  if (bridge.uuid) {
@@ -2207,11 +2354,14 @@ class Config {
2207
2354
  }
2208
2355
  */
2209
2356
 
2210
- for (const key in this.config.words) {
2211
- const values = this.config.words[key]
2212
- if (values.some((word) => (Object.keys(word).includes('uuid') && !word.uuid))) {
2213
- debugBreak()
2214
- return false
2357
+ const literals = this.config.words.literals
2358
+ if (literals) {
2359
+ for (const key in literals) {
2360
+ const values = literals[key]
2361
+ if (values.some((word) => (Object.keys(word).includes('uuid') && !word.uuid))) {
2362
+ debugBreak()
2363
+ return false
2364
+ }
2215
2365
  }
2216
2366
  }
2217
2367
 
@@ -2425,7 +2575,7 @@ class Config {
2425
2575
  this.config.hierarchy = []
2426
2576
  this.config.priorities = []
2427
2577
  this.config.associations = { positive: [], negative: [] }
2428
- this.config.words = {}
2578
+ this.config.words = initWords({})
2429
2579
 
2430
2580
  for (let i = 0; i < addInternals.length; ++i) {
2431
2581
  let name
@@ -2612,13 +2762,25 @@ class Config {
2612
2762
  }
2613
2763
 
2614
2764
  if (config.words) {
2615
- const words = {}
2616
- for (const word in config.words) {
2617
- words[word] = config.words[word].map((word) => {
2765
+ const literals = {}
2766
+ for (const word in config.words.literals) {
2767
+ literals[word] = config.words.literals[word].map((word) => {
2618
2768
  return Object.assign({}, word, { id: toNS(word.id), uuid })
2619
2769
  })
2620
2770
  }
2621
- config.words = words
2771
+ config.words.literals = literals
2772
+
2773
+ for (const pattern of config.words.patterns) {
2774
+ pattern.defs.forEach((def) => {
2775
+ def.id = toNS(def.id)
2776
+ def.uuid = uuid
2777
+ })
2778
+ }
2779
+
2780
+ for (const pair of config.words.hierarchy) {
2781
+ pair.child = toNS(pair.child)
2782
+ pair.parent = toNS(pair.parent)
2783
+ }
2622
2784
  }
2623
2785
 
2624
2786
  if (config.hierarchy) {
@@ -2739,6 +2901,7 @@ class Config {
2739
2901
  throw new Error(`Setting invalid property ${property}`)
2740
2902
  }
2741
2903
 
2904
+ // TODO trie
2742
2905
  if (property == 'words') {
2743
2906
  for (const word in value) {
2744
2907
  for (const def of value[word]) {
@@ -2803,7 +2966,8 @@ class Config {
2803
2966
  more = more.copy()
2804
2967
  more.server(this._server, this._key, this._queryParams)
2805
2968
 
2806
- this.loadOrder.addList(more.configs.map((km) => km.name || km.uuid))
2969
+ const moreConfigs = more.configs.map((km) => km.name || km.uuid)
2970
+ this.loadOrder.addList(moreConfigs)
2807
2971
 
2808
2972
  // get the new ones
2809
2973
  // remove the dups
@@ -2885,16 +3049,36 @@ class Config {
2885
3049
  continue
2886
3050
  }
2887
3051
  if (key === 'words') {
2888
- const configWords = this.config.words
2889
- const moreWords = more.words
2890
- for (const word of Object.keys(moreWords)) {
2891
- if (!configWords[word]) {
2892
- configWords[word] = []
3052
+ if (more.words.literals) {
3053
+ const literals = this.config.words.literals
3054
+ const moreLiterals = more.words.literals
3055
+ for (const word of Object.keys(moreLiterals)) {
3056
+ if (!literals[word]) {
3057
+ literals[word] = []
3058
+ }
3059
+ if (addFirst) {
3060
+ literals[word] = moreLiterals[word].concat(literals[word])
3061
+ } else {
3062
+ literals[word] = literals[word].concat(moreLiterals[word])
3063
+ }
3064
+ }
3065
+ }
3066
+ if (more.words.patterns) {
3067
+ const patterns = this.config.words.patterns
3068
+ const morePatterns = more.words.patterns
3069
+ if (addFirst) {
3070
+ this.config.words.patterns = morePatterns.concat(patterns)
3071
+ } else {
3072
+ this.config.words.patterns = patterns.concat(morePatterns)
2893
3073
  }
3074
+ }
3075
+ if (more.words.hierarchy) {
3076
+ const hierarchy = this.config.words.hierarchy
3077
+ const moreHierarchy = more.words.hierarchy
2894
3078
  if (addFirst) {
2895
- configWords[word] = moreWords[word].concat(configWords[word])
3079
+ this.config.words.hierarchy = moreHierarchy.concat(hierarchy)
2896
3080
  } else {
2897
- configWords[word] = configWords[word].concat(moreWords[word])
3081
+ this.config.words.hierarchy = hierarchy.concat(moreHierarchy)
2898
3082
  }
2899
3083
  }
2900
3084
  } else if (key === 'name') {
@@ -3006,14 +3190,25 @@ class Config {
3006
3190
  continue
3007
3191
  }
3008
3192
  if (key === 'words') {
3009
- const configWords = this.config.words
3010
- const moreWords = more.words
3011
- for (const word of Object.keys(moreWords)) {
3012
- if (!configWords[word]) {
3013
- configWords[word] = []
3193
+ if (this.config.words.literals) {
3194
+ const literals = this.config.words.literals
3195
+ const moreLiterals = more.words.literals
3196
+ for (const word of Object.keys(moreLiterals)) {
3197
+ if (!literals[word]) {
3198
+ literals[word] = []
3199
+ }
3200
+ literals[word] = moreLiterals[word].concat(literals[word])
3014
3201
  }
3015
- // configWords[word] = configWords[word].concat(moreWords[word])
3016
- configWords[word] = moreWords[word].concat(configWords[word])
3202
+ }
3203
+ if (this.config.words.patterns) {
3204
+ const patterns = this.config.words.patterns
3205
+ const morePatterns = more.words.patterns
3206
+ this.config.words.patterns = morePatterns.concat(patterns)
3207
+ }
3208
+ if (this.config.words.hierarchy) {
3209
+ const hierarchy = this.config.words.hierarchy
3210
+ const moreHierarchy = more.words.hierarchy
3211
+ this.config.words.hierarchy = moreHierarchy.concat(hierarchy)
3017
3212
  }
3018
3213
  } else if (key === 'name') {
3019
3214
  /*
package/src/digraph.js CHANGED
@@ -113,19 +113,31 @@ class Digraph {
113
113
  }
114
114
 
115
115
  minima (nodes) {
116
- let minima = new Set(nodes)
117
- const ancestors = new Set([])
118
- nodes.forEach((node) => {
119
- this.ancestors(node).forEach((n) => ancestors.add(n))
120
- })
121
- ancestors.forEach((n) => minima.delete(n))
122
- if (minima.size === 0) {
123
- // all unrelated
124
- minima = new Set(nodes)
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._edges.push([l[i - 1], l[i]])
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
 
@@ -81,19 +81,31 @@ class DigraphInternal {
81
81
  }
82
82
 
83
83
  minima (nodes) {
84
- let minima = new Set(nodes)
85
- const ancestors = new Set([])
86
- nodes.forEach((node) => {
87
- this.ancestors(node).forEach((n) => ancestors.add(n))
88
- })
89
- ancestors.forEach((n) => minima.delete(n))
90
- if (minima.size === 0) {
91
- // all unrelated
92
- minima = new Set(nodes)
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._edges.push([l[i - 1], l[i]])
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