theprogrammablemind 8.0.0-beta.8 → 8.0.0-beta.80

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/src/config.js CHANGED
@@ -2,9 +2,10 @@
2
2
  const { Semantics, normalizeGenerator } = require('./semantics')
3
3
  const { Generators } = require('./generators')
4
4
  const { v4: uuidv4 } = require('uuid')
5
- const client = require('../client')
5
+ const configHelpers = require('./configHelpers')
6
6
  const DigraphInternal = require('./digraph_internal')
7
7
  const helpers = require('./helpers')
8
+ const { InitCalls } = require('./helpers')
8
9
  const { ecatch } = require('./helpers')
9
10
  const runtime = require('../runtime')
10
11
  const _ = require('lodash')
@@ -254,6 +255,9 @@ const priority_valid = (cp) => {
254
255
  const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
255
256
  ecatch(`While processing the bridge for ${bridge.id}#${bridge.level}`,
256
257
  () => {
258
+ if (bridge.development && config.isModule) {
259
+ return
260
+ }
257
261
  if (!bridge.bridge) {
258
262
  bridge.bridge = '{ ...next(operator) }'
259
263
  }
@@ -262,7 +266,12 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
262
266
  }
263
267
  if (bridge.children) {
264
268
  for (const child of bridge.children) {
265
- config.addHierarchy(child, bridge.id)
269
+ // config.addHierarchy(child, bridge.id)
270
+ if (child.child) {
271
+ config.addHierarchy(child.child, bridge.id, child.instance)
272
+ } else {
273
+ config.addHierarchy(child, bridge.id)
274
+ }
266
275
  }
267
276
  }
268
277
  if (bridge.operator) {
@@ -270,12 +279,20 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
270
279
  }
271
280
  if (bridge.parents) {
272
281
  for (const parent of bridge.parents) {
273
- config.addHierarchy(bridge.id, parent)
282
+ if (parent.parent) {
283
+ config.addHierarchy(bridge.id, parent.parent, parent.instance)
284
+ } else {
285
+ config.addHierarchy(bridge.id, parent)
286
+ }
274
287
  }
275
288
  }
276
289
  if (bridge.isA) {
277
290
  for (const parent of bridge.isA) {
278
- config.addHierarchy(bridge.id, parent)
291
+ if (parent.parent) {
292
+ config.addHierarchy(bridge.id, parent.parent, parent.instance)
293
+ } else {
294
+ config.addHierarchy(bridge.id, parent)
295
+ }
279
296
  }
280
297
  }
281
298
  if (bridge.before) {
@@ -338,8 +355,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
338
355
  const level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
339
356
 
340
357
  const generator = {
341
- where: bridge.generatorp.where || bridge.where || client.where(4),
342
- match: (args) => bridge.id == args.context.marker && args.context.level == level && args.context.paraphrase && match(args),
358
+ where: bridge.generatorp.where || bridge.where || helpers.where(4),
359
+ match: async (args) => bridge.id == args.context.marker && args.context.level == level && args.context.paraphrase && await match(args),
343
360
  apply: (args) => apply(args),
344
361
  applyWrapped: apply,
345
362
  property: 'generatorp'
@@ -355,8 +372,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
355
372
  const apply = typeof bridge.generatorr === 'function' ? bridge.generatorr : bridge.generatorr.apply || bridge.generatorr
356
373
  const level = bridge.generatorr.level >= 0 ? bridge.generatorr.level : bridge.level + 1
357
374
  const generator = {
358
- where: bridge.generatorr.where || bridge.where || client.where(4),
359
- match: (args) => bridge.id == args.context.marker && args.context.level == level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && match(args),
375
+ where: bridge.generatorr.where || bridge.where || helpers.where(4),
376
+ match: async (args) => bridge.id == args.context.marker && args.context.level == level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
360
377
  apply: (args) => apply(args),
361
378
  applyWrapped: apply,
362
379
  property: 'generatorr'
@@ -369,7 +386,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
369
386
  }
370
387
  if (bridge.evaluator) {
371
388
  const semantic = {
372
- where: bridge.evaluator.where || bridge.where || client.where(3),
389
+ where: bridge.evaluator.where || bridge.where || helpers.where(3),
373
390
  match: ({ context }) => bridge.id == context.marker && context.evaluate,
374
391
  apply: (args) => bridge.evaluator(args),
375
392
  applyWrapped: bridge.evaluator,
@@ -383,7 +400,7 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
383
400
  }
384
401
  if (bridge.semantic) {
385
402
  const semantic = {
386
- where: bridge.semantic.where || bridge.where || client.where(3),
403
+ where: bridge.semantic.where || bridge.where || helpers.where(3),
387
404
  match: ({ context }) => bridge.id == context.marker && !context.evaluate,
388
405
  apply: (args) => bridge.semantic(args),
389
406
  applyWrapped: bridge.semantic,
@@ -551,7 +568,7 @@ function isLetter (char) {
551
568
  }
552
569
  */
553
570
 
554
- function configDup (config, options) {
571
+ async function configDup (config, options) {
555
572
  if (config instanceof Config) {
556
573
  return config.copy(options)
557
574
  }
@@ -691,9 +708,9 @@ class KM {
691
708
  return true
692
709
  }
693
710
 
694
- copy2 (options) {
711
+ async copy2 (options) {
695
712
  // greg -> add a flag to say don't init the api's
696
- const config = configDup(this._config, options)
713
+ const config = await configDup(this._config, options)
697
714
  const km = new KM({
698
715
  config,
699
716
  getCounter: options.getCounter,
@@ -705,10 +722,10 @@ class KM {
705
722
  return km // copy2()
706
723
  }
707
724
 
708
- copy () {
725
+ async copy () {
709
726
  const km = new KM({
710
727
  name: this._name,
711
- config: configDup(this._config),
728
+ config: await configDup(this._config),
712
729
  // _uuid: uuidv4(),
713
730
  _uuid: this._config.getCounter(this._config._name),
714
731
  getCounter: (name) => this._config.getCounter(name),
@@ -760,12 +777,11 @@ const multiApiImpl = (initializer) => {
760
777
  multiApi: true,
761
778
 
762
779
  // multi functions
763
- add: (config, multiApi, api) => {
780
+ add: async (config, multiApi, api, apiConstructor) => {
764
781
  initializer(config, api)
765
782
  const name = api.getName()
766
783
  multiApi.apis[name] = api
767
- // api.objects = config.get('objects')
768
- // api.config = () => config
784
+ multiApi.apiConstructors[name] = apiConstructor
769
785
  multiApi.current = name
770
786
  },
771
787
 
@@ -788,6 +804,9 @@ const multiApiImpl = (initializer) => {
788
804
  apis: {
789
805
  },
790
806
 
807
+ apiConstructors: {
808
+ },
809
+
791
810
  // api functions
792
811
  api: (multiApi) => multiApi.apis[multiApi.current]
793
812
  })
@@ -798,17 +817,6 @@ class Config {
798
817
  return config_toServer(config)
799
818
  }
800
819
 
801
- base () {
802
- const base = new Config()
803
- for (const km of this.configs.reverse()) {
804
- if (km.isSelf) {
805
- continue
806
- }
807
- base.add(km.config)
808
- }
809
- return base
810
- }
811
-
812
820
  getInfo () {
813
821
  const name = this.name
814
822
  const includes = this.configs.slice(1).map((km) => km.config.name)
@@ -852,6 +860,7 @@ class Config {
852
860
  addArgs: (...args) => this.addArgs(...args),
853
861
  getBridge: (...args) => this.getBridge(...args),
854
862
  fragment: (...args) => this.fragment(...args),
863
+ server: (...args) => this.server(...args),
855
864
  exists: (...args) => this.exists(...args),
856
865
  addAPI: (...args) => this.addAPI(...args)
857
866
  }
@@ -988,23 +997,8 @@ class Config {
988
997
 
989
998
  // value is in response field
990
999
  // TODO maybe generalize out query+evaluate along the lines of set value and set reference
991
- /*
992
- getEvaluator (s, log, context) {
993
- const instance = s({ ...context, evaluate: true })
994
- if (!instance.evalue && !instance.verbatim && !instance.value) {
995
- this.warningNotEvaluated(log, context);
996
- }
997
- if (!instance.evalue) {
998
- instance.evalue = instance.value
999
- instance.edefault = true
1000
- }
1001
- delete instance.evaluate
1002
- instance.instance = true;
1003
- return instance
1004
- }
1005
- */
1006
- getEvaluator (s, calls, log, context) {
1007
- const instance = s({ ...context, evaluate: true })
1000
+ async getEvaluator (s, calls, log, context) {
1001
+ const instance = await s({ ...context, evaluate: true })
1008
1002
  calls.touch(instance)
1009
1003
  if (!instance.evalue && !instance.verbatim && !instance.value) {
1010
1004
  this.warningNotEvaluated(log, context)
@@ -1018,19 +1012,21 @@ class Config {
1018
1012
  return instance
1019
1013
  }
1020
1014
 
1021
- fragmentInstantiator (contexts) {
1015
+ fragmentInstantiator (args, contexts) {
1022
1016
  return new Object({
1023
1017
  contexts: () => contexts,
1024
- instantiate: (mappings) => {
1018
+ instantiate: async (mappings) => {
1025
1019
  const instantiated = _.cloneDeep(contexts)
1026
1020
  // const todo = [...instantiated]
1027
1021
  // const todo = [...instantiated]
1028
1022
  const todo = _.clone(instantiated)
1023
+ args = {...args}
1029
1024
  while (todo.length > 0) {
1030
1025
  const context = todo.pop()
1026
+ args.context = context
1031
1027
  for (const mapping of mappings) {
1032
- if (mapping.match({ context })) {
1033
- mapping.apply({ context })
1028
+ if (await mapping.match(args)) {
1029
+ await mapping.apply(args)
1034
1030
  }
1035
1031
  }
1036
1032
  for (const key of Object.keys(context)) {
@@ -1049,11 +1045,21 @@ class Config {
1049
1045
  })
1050
1046
  }
1051
1047
 
1052
- fragment (query) {
1048
+ fragment (args, query) {
1053
1049
  for (const instance of (this.instances || [])) {
1054
1050
  for (const fragment of (instance.fragments || [])) {
1055
1051
  if (fragment.query === query) {
1056
- return this.fragmentInstantiator(fragment.contexts)
1052
+ return this.fragmentInstantiator(args, fragment.contexts)
1053
+ }
1054
+ }
1055
+ for (const fragment of (instance.resultss || [])) {
1056
+ if (fragment.isFragment && fragment.query === query) {
1057
+ return this.fragmentInstantiator(args, fragment.contexts)
1058
+ }
1059
+ }
1060
+ for (const fragment of (this.fragmentsBeingBuilt || [])) {
1061
+ if (fragment.query === query) {
1062
+ return this.fragmentInstantiator(args, fragment.contexts)
1057
1063
  }
1058
1064
  }
1059
1065
  }
@@ -1093,6 +1099,27 @@ class Config {
1093
1099
  } else {
1094
1100
  const config = { ...queryOrConfig }
1095
1101
  delete config.where
1102
+
1103
+ if (config.words && config.words.hierarchy) {
1104
+ config.words.hierarchy = config.words.hierarchy.map( (value) => {
1105
+ value = {...value}
1106
+ delete value.uuid
1107
+ return value
1108
+ })
1109
+ }
1110
+
1111
+ if (config.words && config.words.patterns) {
1112
+ config.words.patterns = config.words.patterns.map( (value) => {
1113
+ value = {...value}
1114
+ value.defs = value.defs.map( (value) => {
1115
+ value = {...value}
1116
+ delete value.uuid
1117
+ return value
1118
+ })
1119
+ return value
1120
+ })
1121
+ }
1122
+
1096
1123
  config.operators = (config.operators || []).map((operator) => {
1097
1124
  if (typeof operator === 'string') {
1098
1125
  return { pattern: operator }
@@ -1120,6 +1147,9 @@ class Config {
1120
1147
  delete bridge.generatorpr
1121
1148
  delete bridge.evaluator
1122
1149
  delete bridge.semantic
1150
+ if (!bridge.bridge) {
1151
+ bridge.bridge = "{ ...next(operator) }"
1152
+ }
1123
1153
  return bridge
1124
1154
  })
1125
1155
  } else {
@@ -1171,8 +1201,24 @@ class Config {
1171
1201
  let startOfChanges
1172
1202
  for (let iq = 0; iq < templateQueries.length; ++iq) {
1173
1203
  if (!helpers.safeEquals(templateQueries[iq], instanceQueries[iq])) {
1174
- sameQueries = false
1175
- startOfChanges = iq
1204
+ // if the current and rest are not queries or fragments then treat as not needing rebuild
1205
+ if (templateQueries.length != instanceQueries.length) {
1206
+ sameQueries = false
1207
+ startOfChanges = iq
1208
+ } else {
1209
+ let hasQueryOrFragment = false
1210
+ for (let rest = iq; rest < templateQueries.length; ++rest) {
1211
+ const value = templateQueries[rest]
1212
+ if (typeof value == 'string' || (value.query && value.isFragment)) {
1213
+ hasQueryOrFragment = true
1214
+ break
1215
+ }
1216
+ }
1217
+ if (hasQueryOrFragment) {
1218
+ sameQueries = false
1219
+ startOfChanges = iq
1220
+ }
1221
+ }
1176
1222
  break;
1177
1223
  }
1178
1224
  }
@@ -1197,7 +1243,9 @@ class Config {
1197
1243
  // console.log("instanceFragments", instanceFragments)
1198
1244
  }
1199
1245
  }
1200
- if (startOfChanges || instance.resultss) {
1246
+ if (startOfChanges) {
1247
+ return { needsRebuild: true, startOfChanges, previousResultss: instance.resultss }
1248
+ } else if (startOfChanges || instance.resultss) {
1201
1249
  return { needsRebuild: !(instance && sameQueries && sameFragments), startOfChanges, previousResultss: instance.resultss }
1202
1250
  } else {
1203
1251
  return { needsRebuild: !(instance && sameQueries && sameFragments) }
@@ -1222,7 +1270,7 @@ class Config {
1222
1270
  }
1223
1271
 
1224
1272
  // loadTemplate
1225
- load (template, instance, options = { rebuild: false, previousResultss: undefined, startOfChanges: undefined }) {
1273
+ async load (rebuildTemplate, template, instance, options = { rebuild: false, previousResultss: undefined, startOfChanges: undefined }) {
1226
1274
  this.validifyTemplate(template)
1227
1275
  instance.template = template
1228
1276
  this.logs.push(`loading template for ${this.name}`)
@@ -1230,7 +1278,7 @@ class Config {
1230
1278
  // TODO fix beforeQuery
1231
1279
  template = { fragments: [], configs: [], ...template }
1232
1280
  template.fragments = template.fragments.concat(this.dynamicFragments)
1233
- client.rebuildTemplate({ config: this, target: this.name, previousResultss: options.previousResultss, startOfChanges: options.startOfChanges, beforeQuery: () => {}, template, ...options })
1281
+ rebuildTemplate({ config: this, target: this.name, previousResultss: options.previousResultss, startOfChanges: options.startOfChanges, beforeQuery: () => {}, template, ...options })
1234
1282
  } else {
1235
1283
  // no change
1236
1284
  // this.initInstances.push({ ...instance, name: config.name })
@@ -1255,7 +1303,7 @@ class Config {
1255
1303
  instance.name = this.name
1256
1304
  this.initInstances.push(instance)
1257
1305
  this.instances.push(instance)
1258
- client.loadInstance(this, instance)
1306
+ await configHelpers.loadInstance(this, instance)
1259
1307
  }
1260
1308
  }
1261
1309
  }
@@ -1309,9 +1357,9 @@ class Config {
1309
1357
  }
1310
1358
  }
1311
1359
 
1312
- addHierarchy (child, parent) {
1360
+ addHierarchy (child, parent, instance) {
1313
1361
  if (child && parent || !child || Array.isArray(child) || (typeof child === 'string' && !parent)) {
1314
- this.addHierarchyChildParent(child, parent)
1362
+ this.addHierarchyChildParent(child, parent, instance)
1315
1363
  // this.addHierarchyProperties ({ child, parent })
1316
1364
  } else {
1317
1365
  this.addHierarchyProperties(child)
@@ -1319,26 +1367,32 @@ class Config {
1319
1367
  }
1320
1368
 
1321
1369
  addHierarchyProperties (edge) {
1322
- const { child, parent } = edge
1370
+ const { child, parent, instance } = edge
1323
1371
  if (typeof child !== 'string') {
1324
1372
  throw new Error(`addHierarchy expected child property to be a string. got ${JSON.stringify(child)}`)
1325
1373
  }
1326
1374
  if (typeof parent !== 'string') {
1327
1375
  throw new Error(`addHierarchy expected parent property to be a string. got ${JSON.stringify(parent)}`)
1328
1376
  }
1377
+ if (instance && typeof instance !== 'boolean') {
1378
+ throw new Error(`addHierarchy expected instance property to be a boolean or undefined. got ${JSON.stringify(instance)}`)
1379
+ }
1329
1380
  debugHierarchy([child, parent])
1330
1381
  this.config.hierarchy.push(edge)
1331
1382
  // TODO greg11 this.hierarchy.addEdge(edge)
1332
- this._delta.json.hierarchy.push([child, parent])
1383
+ this._delta.json.hierarchy.push([child, parent, instance || false])
1333
1384
  }
1334
1385
 
1335
- addHierarchyChildParent (child, parent) {
1386
+ addHierarchyChildParent (child, parent, instance) {
1336
1387
  if (typeof child !== 'string') {
1337
1388
  throw new Error(`addHierarchy expected child to be a string. got ${JSON.stringify(child)}`)
1338
1389
  }
1339
1390
  if (typeof parent !== 'string') {
1340
1391
  throw new Error(`addHierarchy expected parent to be a string. got ${JSON.stringify(parent)}`)
1341
1392
  }
1393
+ if (instance && typeof instance !== 'boolean') {
1394
+ throw new Error(`addHierarchy expected instance property to be a boolean or undefined. got ${JSON.stringify(instance)}`)
1395
+ }
1342
1396
  debugHierarchy([child, parent])
1343
1397
  if (this.config.hierarchy.find((element) => {
1344
1398
  const hc = hierarchyCanonical(element)
@@ -1349,9 +1403,9 @@ class Config {
1349
1403
  return
1350
1404
  }
1351
1405
 
1352
- this.config.hierarchy.push([child, parent])
1406
+ this.config.hierarchy.push([child, parent, instance || false])
1353
1407
  // this.hierarchy.addEdge([child, parent])
1354
- this._delta.json.hierarchy.push([child, parent])
1408
+ this._delta.json.hierarchy.push([child, parent, instance || false])
1355
1409
  }
1356
1410
 
1357
1411
  getBridge (id, level) {
@@ -1398,7 +1452,7 @@ class Config {
1398
1452
  }
1399
1453
 
1400
1454
  if (!generator.where) {
1401
- generator.where = client.where(3)
1455
+ generator.where = helpers.where(3)
1402
1456
  }
1403
1457
 
1404
1458
  const generators = this.config.generators
@@ -1421,7 +1475,7 @@ class Config {
1421
1475
  }
1422
1476
 
1423
1477
  if (!semantic.where) {
1424
- semantic.where = client.where(3)
1478
+ semantic.where = helpers.where(3)
1425
1479
  }
1426
1480
 
1427
1481
  const semantics = this.config.semantics
@@ -1608,16 +1662,12 @@ class Config {
1608
1662
  return params
1609
1663
  }
1610
1664
 
1611
- processContexts (contexts, params) {
1612
- client.processContexts(contexts, this.getParams())
1613
- }
1614
-
1615
- processContext (context) {
1616
- return client.processContext(context, this.getParams())
1665
+ async processContext (context) {
1666
+ return await configHelpers.processContext(context, this.getParams())
1617
1667
  }
1618
1668
 
1619
1669
  process (query, options) {
1620
- return client.process(this, query, options)
1670
+ return this.clientProcess(this, query, options)
1621
1671
  }
1622
1672
 
1623
1673
  query (query, options) {
@@ -1757,8 +1807,25 @@ class Config {
1757
1807
  config.words.hierarchy = hierarchyPrime
1758
1808
  }
1759
1809
 
1810
+ terminate() {
1811
+ this.configs.forEach((km) => {
1812
+ const config = km.config
1813
+ if (!config.terminatorFn) {
1814
+ this.terminatorFn(this)
1815
+ } else {
1816
+ config.terminatorFn(this)
1817
+ }
1818
+ })
1819
+ }
1820
+
1821
+ setTerminator(terminatorFn) {
1822
+ if (terminatorFn) {
1823
+ this.terminatorFn = terminatorFn
1824
+ }
1825
+ }
1826
+
1760
1827
  // configs = [ { config, namespace } ... ]
1761
- constructor (config, module) {
1828
+ constructor (config, module, clientProcess) {
1762
1829
  if (config instanceof Config) {
1763
1830
  throw new Error('Excepted the config argument to be a hash not a Config object')
1764
1831
  }
@@ -1776,6 +1843,7 @@ class Config {
1776
1843
  config.priorities = config.priorities || []
1777
1844
  }
1778
1845
 
1846
+ this.clientProcess = clientProcess
1779
1847
  this.maxDepth = 20 // for generators and semantics
1780
1848
  this.debugLoops = false // for generators and semantics
1781
1849
 
@@ -1801,24 +1869,6 @@ class Config {
1801
1869
  // when running configs any bridges added are marked as transitory so that the associated will ignore those op's
1802
1870
  this.transitoryMode = false
1803
1871
 
1804
- // check for duplicate bridges
1805
- if (config && config.bridges) {
1806
- let duplicated = new Set()
1807
- const seen = new Set()
1808
- for (const bridge of config.bridges) {
1809
- const id = `${bridge.id}/${bridge.level}`
1810
- if (seen.has(id)) {
1811
- duplicated.add(id)
1812
- } else {
1813
- seen.add(id)
1814
- }
1815
- }
1816
- duplicated = Array.from(duplicated)
1817
- if (duplicated.length > 0) {
1818
- throw new Error(`In the KM ${config.name}, the following operators are duplicated in the bridges: ${duplicated}`)
1819
- }
1820
- }
1821
-
1822
1872
  if (config && config.words) {
1823
1873
  initWords(config.words)
1824
1874
  isValidWordDef(config.words)
@@ -1840,6 +1890,7 @@ class Config {
1840
1890
  currentConfig.wasInitialized = true
1841
1891
  }
1842
1892
  }
1893
+ this.terminatorFn = () => {}
1843
1894
  if (config) {
1844
1895
  this.name = config.name
1845
1896
  }
@@ -1867,6 +1918,7 @@ class Config {
1867
1918
  }
1868
1919
  this.get('objects').namespaced[this._uuid] = {}
1869
1920
  this.valid()
1921
+ this.checks()
1870
1922
  debugConfigProps(this.config)
1871
1923
  }
1872
1924
 
@@ -1878,9 +1930,9 @@ class Config {
1878
1930
  this._stop_auto_rebuild = true
1879
1931
  }
1880
1932
 
1881
- restart_auto_rebuild() {
1933
+ async restart_auto_rebuild() {
1882
1934
  this._stop_auto_rebuild = false
1883
- this.rebuild()
1935
+ await this.rebuild()
1884
1936
  }
1885
1937
 
1886
1938
  getAddedArgs (args) {
@@ -1899,8 +1951,8 @@ class Config {
1899
1951
  }
1900
1952
  }
1901
1953
 
1902
- set multiApi (initializer) {
1903
- this.api = multiApiImpl(initializer)
1954
+ async setMultiApi (initializer) {
1955
+ await this.setApi(() => multiApiImpl(initializer))
1904
1956
  }
1905
1957
 
1906
1958
  get multiApi () {
@@ -1948,31 +2000,38 @@ class Config {
1948
2000
  }
1949
2001
  }
1950
2002
 
1951
- addAPI (api) {
2003
+ async addAPI (api) {
2004
+ // console.trace()
2005
+ // throw "addAPI"
1952
2006
  if (this._api && this._api.multiApi) {
1953
- this._api.add(this, this._api, api)
2007
+ await this._api.add(this, this._api, api)
1954
2008
  } else {
1955
2009
  throw new Error('Can only add apis to a multi-api')
1956
2010
  }
1957
2011
  }
1958
2012
 
1959
- set api (value) {
2013
+ async setApi (constructor) {
2014
+ if (typeof constructor !== 'function') {
2015
+ throw new Error(`Expected the argument to be an API constructor for ${this.name}.`)
2016
+ }
2017
+ const value = constructor()
1960
2018
  if (!value.initialize) {
1961
2019
  throw new Error(`Expected the API to have an initialize function for ${this.name}.`)
1962
2020
  }
1963
2021
 
1964
2022
  if (this._api && this._api.multiApi) {
1965
- this._api.add(this, this._api, value)
1966
- } else {
1967
- this._api = _.cloneDeep(value)
1968
- /*
1969
- if (this._api) {
1970
- // this._api.objects = this.config.objects
1971
- // this._api.config = () => this
1972
- // this._api.uuid = this._uuid
2023
+ await this._api.add(this, this._api, value, constructor)
2024
+ const previousApiConstructor = this._apiConstructor
2025
+ this._apiConstructor = (config) => {
2026
+ const api = previousApiConstructor(config)
2027
+ // does this need await?
2028
+ api.add(config, api, constructor(config), constructor)
2029
+ return api
1973
2030
  }
1974
- */
1975
- this.rebuild()
2031
+ } else {
2032
+ this._api = value
2033
+ this._apiConstructor = constructor
2034
+ await this.rebuild()
1976
2035
  }
1977
2036
  }
1978
2037
 
@@ -1992,7 +2051,7 @@ class Config {
1992
2051
  }
1993
2052
 
1994
2053
  // remove all added modules and initialize with the init config
1995
- resetToOne () {
2054
+ async resetToOne () {
1996
2055
  /*
1997
2056
  this.config = _.cloneDeep(this.initConfig)
1998
2057
  this.configs = [this.configs[0]]
@@ -2001,11 +2060,8 @@ class Config {
2001
2060
  */
2002
2061
  this.configs = [this.configs[0]]
2003
2062
  this.defaultConfig()
2004
- if (!this.initializeFn) {
2005
- // TODO move this to the default initializer
2006
- Object.assign(this.config.objects, _.cloneDeep(this.initConfig.objects || {}))
2007
- }
2008
- this.initializeConfigFromConfigs({ others: [], objects: this.config.objects.namespaced, moreNames: [], callInitializers: false })
2063
+ Object.assign(this.config.objects, _.cloneDeep(this.initConfig.objects || {}))
2064
+ await this.initializeConfigFromConfigs({ others: [], objects: this.config.objects.namespaced, moreNames: [], callInitializers: false })
2009
2065
  const map = {}
2010
2066
  for (let i = 0; i < this.configs.length; ++i) {
2011
2067
  map[this.configs[i].uuid] = this.configs[i].uuid
@@ -2027,21 +2083,27 @@ class Config {
2027
2083
  runtime.fs.writeFileSync(fn, JSON.stringify(this.config, 0, 2))
2028
2084
  }
2029
2085
 
2030
- copy (options = { callInitializers: true }) {
2031
- }
2032
-
2033
- copy (options = { callInitializers: true }) {
2086
+ async copy (options = { callInitializers: true }) {
2034
2087
  this.valid()
2035
2088
  const cp = new Config()
2036
2089
  cp.logs = []
2037
2090
  cp.maxDepth = this.maxDepth
2038
2091
  cp.debugLoops = this.debugLoops
2039
2092
  cp.transitoryMode = this.transitoryMode
2040
- cp.configs = this.configs.map((km) => km.copy2(Object.assign({}, options, { getCounter: (name) => cp.getCounter(name), callInitializers: false })))
2093
+ // cp.configs = this.configs.map((km) => await km.copy2(Object.assign({}, options, { getCounter: (name) => cp.getCounter(name), callInitializers: false })))
2094
+ cp.configs = []
2095
+ for (const km of this.configs) {
2096
+ cp.configs.push(await km.copy2(Object.assign({}, options, { getCounter: (name) => cp.getCounter(name), callInitializers: false })))
2097
+ }
2041
2098
  cp._uuid = cp.configs[0]._uuid
2042
2099
  // update uuid here set the uuid in the objects and add error checking
2043
2100
  cp.initializerFn = this.initializerFn
2044
- cp._api = _.cloneDeep(this._api)
2101
+ cp.terminatorFn = this.terminatorFn
2102
+ // cp._api = _.cloneDeep(this._api)
2103
+ if (this._apiConstructor) {
2104
+ cp._api = this._apiConstructor(cp)
2105
+ cp._apiConstructor = this._apiConstructor
2106
+ }
2045
2107
  cp._namespace = this._namespace
2046
2108
  cp._eqClasses = this._eqClasses
2047
2109
  cp.name = this.name
@@ -2053,18 +2115,14 @@ class Config {
2053
2115
  cp.instances = this.instances.slice()
2054
2116
  cp.configCounter = this.configCounter
2055
2117
  cp.testConfig = this.testConfig
2118
+ cp._server = this._server
2056
2119
 
2057
2120
  cp.initConfig = _.cloneDeep(this.initConfig)
2058
2121
  cp.defaultConfig()
2059
2122
  // cp.wasInitialized = false; // since default config GREG
2060
2123
  cp.resetWasInitialized()
2061
- if (!this.initializeFn) {
2062
- // TODO move this to the default initializer
2063
- Object.assign(cp.config.objects, _.cloneDeep(this.initConfig.objects || {}))
2064
- }
2065
- // cp.initializeConfigFromConfigs({ others: [], objects: cp.config.objects.namespaced, moreNames: [], ...options })
2066
- // cp.initializeConfigFromConfigs(Object.assign({ others: [], objects: cp.config.objects.namespaced, moreNames: [] }, { callInitializers: false }))
2067
- cp.initializeConfigFromConfigs(Object.assign({ others: [], objects: cp.config.objects.namespaced, moreNames: [] }, options))
2124
+ Object.assign(cp.config.objects, _.cloneDeep(this.initConfig.objects || {}))
2125
+ await cp.initializeConfigFromConfigs(Object.assign({ others: [], objects: cp.config.objects.namespaced, moreNames: [] }, options))
2068
2126
  const map = {}
2069
2127
  for (let i = 0; i < this.configs.length; ++i) {
2070
2128
  map[this.configs[i].uuid] = cp.configs[i].uuid
@@ -2075,33 +2133,16 @@ class Config {
2075
2133
  // debugger
2076
2134
  }
2077
2135
  if (options.callInitializers) {
2078
- cp.rebuild(options)
2136
+ await cp.rebuild(options) // in copy
2079
2137
  } else {
2080
- // this mess is for duplicate into a KM after resetToOne was called
2081
- /*
2082
- if (cp._api) {
2083
- // cp._api.objects = cp.config.objects
2084
- // cp._api.config = () => (cp instanceof Config) ? cp : cp.config
2085
- // cp._api.uuid = cp._uuid
2086
- }
2087
- */
2088
-
2089
2138
  if (!cp.config.objects) {
2090
2139
  cp.config.objects = { namespaced: {} }
2091
2140
  } else if (!cp.config.objects.namespaced) {
2092
2141
  cp.config.objects.namespaced = {}
2093
2142
  }
2094
2143
  cp.configs.forEach((km) => {
2095
- // const namespace = km.namespace
2096
2144
  cp.config.objects.namespaced[km._uuid] = {}
2097
2145
  })
2098
- /*
2099
- if (cp._uuid == 'concept2') {
2100
- if (!cp.api.objects.defaultTypesForHierarchy) {
2101
- debugger
2102
- }
2103
- }
2104
- */
2105
2146
  }
2106
2147
  cp.valid()
2107
2148
  return cp
@@ -2225,41 +2266,7 @@ class Config {
2225
2266
  }
2226
2267
  }
2227
2268
 
2228
- initializeFromConfigs () {
2229
- // [...this.configs].reverse().forEach(({ config, namespace, uuid }) => {
2230
- [...this.configs].reverse().forEach(({ config, namespace, uuid }) => {
2231
- /*
2232
- let objects = this.get('objects')
2233
- if (namespace) {
2234
- objects = {}
2235
- this.get('objects')['namespaced'][namespace] = objects
2236
- }
2237
- */
2238
- const objects = {}
2239
- if (config instanceof Config) {
2240
- this.get('objects').namespaced[config._uuid] = objects
2241
- /*
2242
- if (config._api) {
2243
- // config._api.objects = objects
2244
- // config._api.config = () => this
2245
- }
2246
- */
2247
- config.initializerFn(setupInitializerFNArgs(this, { testConfig: config, currentConfig: config, objects, namespace, uuid }))
2248
- } else {
2249
- this.get('objects').namespaced[this._uuid] = objects
2250
- /*
2251
- if (config._api) {
2252
- // config._api.objects = objects
2253
- // config._api.config = () => this
2254
- }
2255
- */
2256
- this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, namespace, uuid }))
2257
- }
2258
- })
2259
- this.instances.forEach((instance) => client.loadInstance(this, instance))
2260
- }
2261
-
2262
- initialize ({ force = true } = {}) {
2269
+ initialize23 ({ force = true } = {}) {
2263
2270
  if (force || !this.wasInitialized) {
2264
2271
  const objects = this.config.objects.namespaced[this._uuid]
2265
2272
  this.initializerFn(setupInitializerFNArgs(this, { testConfig: this, currentConfig: this, objects, uuid: this._uuid, namespace: '' }))
@@ -2267,7 +2274,7 @@ class Config {
2267
2274
  }
2268
2275
  }
2269
2276
 
2270
- initializer (fn, options = {}) {
2277
+ async initializer (fn, options = {}) {
2271
2278
  if (options) {
2272
2279
  for (const option of Object.keys(options)) {
2273
2280
  const validOptions = []
@@ -2289,8 +2296,7 @@ class Config {
2289
2296
  currentConfig.wasInitialized = true
2290
2297
  global.transitoryMode = transitoryMode
2291
2298
  }
2292
- // this.initializeFromConfigs()
2293
- this.rebuild()
2299
+ await this.rebuild()
2294
2300
  }
2295
2301
 
2296
2302
  nsToString (id) {
@@ -2436,7 +2442,7 @@ class Config {
2436
2442
  }
2437
2443
 
2438
2444
  // rebuild ({ isModule: mainIsModule = false } = {}) {
2439
- rebuild ({ isModule: mainIsModule } = {}) {
2445
+ async rebuild ({ isModule: mainIsModule } = {}) {
2440
2446
  if (this._stop_auto_rebuild) {
2441
2447
  return
2442
2448
  }
@@ -2604,7 +2610,7 @@ class Config {
2604
2610
  }
2605
2611
  const instance = this.instances.find((instance) => instance.name == name)
2606
2612
  if (instance) {
2607
- client.loadInstance(this, instance)
2613
+ await configHelpers.loadInstance(this, instance)
2608
2614
  }
2609
2615
  this.hierarchy.edges = this.config.hierarchy
2610
2616
  }
@@ -2612,7 +2618,7 @@ class Config {
2612
2618
 
2613
2619
  this.hierarchy.edges = this.config.hierarchy
2614
2620
  this.valid()
2615
- this.checkBridges()
2621
+ this.checks()
2616
2622
  }
2617
2623
 
2618
2624
  nameToUUID (name) {
@@ -2624,6 +2630,7 @@ class Config {
2624
2630
  // if undefined namespace applies to first loaded config
2625
2631
  // if list of name then namespace applied only to those configs
2626
2632
  // if true then namespace applies to all loaded configs
2633
+ /*
2627
2634
  namespace (moreNames, others) {
2628
2635
  const config = this.copy()
2629
2636
  if (!Array.isArray(moreNames)) {
@@ -2659,6 +2666,7 @@ class Config {
2659
2666
  config.rebuild()
2660
2667
  return config
2661
2668
  }
2669
+ */
2662
2670
 
2663
2671
  setupNamespace (km) {
2664
2672
  let config = km.config
@@ -2677,7 +2685,7 @@ class Config {
2677
2685
 
2678
2686
  // config.initializerFn({ config: this, objects, namespace })
2679
2687
  // this goes through all the configs and sets up this.config
2680
- initializeConfigFromConfigs ({ others, objects, moreNames, callInitializers = true }) {
2688
+ async initializeConfigFromConfigs ({ others, objects, moreNames, callInitializers = true }) {
2681
2689
  // setup the namespace in the configs
2682
2690
  let first = true
2683
2691
  this.configs.forEach((km) => {
@@ -2826,6 +2834,11 @@ class Config {
2826
2834
  }
2827
2835
  }
2828
2836
 
2837
+ checks () {
2838
+ this.checkOperators()
2839
+ this.checkBridges()
2840
+ }
2841
+
2829
2842
  checkOperators () {
2830
2843
  if (!this.config.operators) {
2831
2844
  return
@@ -2846,53 +2859,19 @@ class Config {
2846
2859
  return
2847
2860
  }
2848
2861
 
2849
- /*
2850
- "namespaces": {
2851
- "634a678b-8d92-4464-bf65-943a82f404d8": {
2852
- "ids": [ "tankConcept" ],
2853
- "namespace": [ "ns1" ]
2854
- },
2855
- console.log('before check', JSON.stringify(this._eqClasses, null, 2))
2856
- */
2857
-
2858
- const errors = []
2859
- /*
2860
- const namespaces = this.config.namespaces
2861
- const nsToIds = {}
2862
- for (const uuid in namespaces) {
2863
- const namespace = namespaces[uuid].namespace
2864
- const ns = namespace.join('#')
2865
- if (!nsToIds[ns]) {
2866
- nsToIds[ns] = new Set()
2867
- }
2868
- const ids = nsToIds[ns]
2869
- for (const id of namespaces[uuid].ids) {
2870
- if (ids.has(id)) {
2871
- if (ns === '') {
2872
- const dups = this.config.bridges.filter( (bridge) => bridge.id == id )
2873
- errors.push(`Id '${id}' is defined more than once in the bridges of the base namespace of the KM ${this.name}, Dups are ${JSON.stringify(dups)}`)
2874
- } else {
2875
- errors.push(`Id '${id}' is defined more than once in the bridges of the ${ns} namespace of the KM ${this.name}`)
2876
- }
2877
- } else {
2878
- ids.add(id)
2879
- }
2880
- }
2881
- }
2882
- */
2883
-
2884
- const keyIsPresent = {}
2862
+ let duplicated = new Set()
2863
+ const seen = new Set()
2885
2864
  for (const bridge of this.config.bridges) {
2886
- const key = `${bridge.id}/${bridge.level} (namespace: ${bridge.uuid})`
2887
- if (keyIsPresent[key]) {
2888
- errors.push(new Error(`Id '${key}' is defined more than once in bridges of the base namespace of the KM ${this.name}`))
2865
+ const id = `${bridge.id}/${bridge.level} (namespace: ${bridge.uuid || this.uuid})`
2866
+ if (seen.has(id)) {
2867
+ duplicated.add(id)
2889
2868
  } else {
2890
- keyIsPresent[key] = key
2869
+ seen.add(id)
2891
2870
  }
2892
2871
  }
2893
-
2894
- if (errors.length > 0) {
2895
- throw errors
2872
+ duplicated = Array.from(duplicated)
2873
+ if (duplicated.length > 0) {
2874
+ throw new Error(`In the KM ${this.name}, the following operators are duplicated in the bridges: ${duplicated}`)
2896
2875
  }
2897
2876
  };
2898
2877
 
@@ -2949,25 +2928,29 @@ class Config {
2949
2928
  }
2950
2929
  }
2951
2930
 
2952
- add (...mores) {
2953
- mores.forEach((km) => {
2954
- if (km === this) {
2955
- throw new Error('Cannot add an object to itself.')
2931
+ async add (...createConfigs) {
2932
+ createConfigs.forEach((createConfig, index) => {
2933
+ if (typeof createConfig !== 'function') {
2934
+ throw new Error(`Expected add argument number ${index+1} to be a function that constructs the config.`)
2956
2935
  }
2957
2936
  })
2958
2937
 
2959
- mores = mores.map((km) => {
2960
- if (!(km instanceof Config)) {
2961
- km = new Config(km)
2938
+ const mores = []
2939
+ for (const createConfig of createConfigs) {
2940
+ const more = await createConfig()
2941
+ if (this.name && this.name == more.name) {
2942
+ throw new Error('Cannot add an object to itself for argument number ${index+1}.')
2962
2943
  }
2963
- return km
2964
- })
2965
-
2966
- mores.forEach((more) => {
2944
+ if (this === more) {
2945
+ throw new Error('Cannot add an object to itself.')
2946
+ }
2947
+ mores.push(more)
2948
+ }
2949
+ for (let more of mores) {
2967
2950
  this.valid()
2968
2951
  more.valid()
2969
2952
  // copy so i don't have to copy later
2970
- more = more.copy()
2953
+ more = await more.copy()
2971
2954
  more.server(this._server, this._key, this._queryParams)
2972
2955
 
2973
2956
  const moreConfigs = more.configs.map((km) => km.name || km.uuid)
@@ -2982,9 +2965,6 @@ class Config {
2982
2965
  const moreKMs1 = [new KM({ config: more, getCounter: (name) => this.getCounter(name), uuid: more.uuid, namespace })]
2983
2966
  const moreKMs2 = more.configs.slice(1).map((km) => {
2984
2967
  return km
2985
- // const cp = km.copy()
2986
- // cp.namespace = namespace
2987
- // return cp;
2988
2968
  })
2989
2969
  const moreKMs = moreKMs1.concat(moreKMs2)
2990
2970
  const eqClass = moreKMs.map((km) => km.uuid)
@@ -2998,7 +2978,7 @@ class Config {
2998
2978
  this.configs.push(moreKM)
2999
2979
  }
3000
2980
  }
3001
- more.resetToOne()
2981
+ await more.resetToOne()
3002
2982
  this.config.eqClasses = this._eqClasses
3003
2983
  // greg
3004
2984
  // setup instances
@@ -3013,8 +2993,8 @@ class Config {
3013
2993
  }
3014
2994
  }
3015
2995
  this.instances = noDups
3016
- })
3017
- this.rebuild()
2996
+ }
2997
+ await this.rebuild() // in add(
3018
2998
  this.valid()
3019
2999
  return this
3020
3000
  }
@@ -3170,7 +3150,7 @@ class Config {
3170
3150
  // assumes this is called in reverse order
3171
3151
  addInternalR (more, useOldVersion = true, skipObjects = false, includeNamespaces = true, allowNameToBeNull = false) {
3172
3152
  if (more instanceof Config) {
3173
- more.initialize({ force: false })
3153
+ more.initialize23({ force: false })
3174
3154
  if (useOldVersion) {
3175
3155
  more = more.config
3176
3156
  } else {