theprogrammablemind_4wp 8.0.0-beta.8 → 8.0.0-beta.80

Sign up to get free protection for your applications and to get access to all the features.
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 {