theprogrammablemind 9.5.1-beta.3 → 9.5.1-beta.30

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
@@ -12,9 +12,8 @@ const _ = require('lodash')
12
12
  const stringify = require('json-stable-stringify')
13
13
  const Lines = require('./lines')
14
14
  const flattens = require('./src/flatten')
15
- const { appendNoDups, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps } = require('./src/helpers')
15
+ const { sortJson, appendNoDups, updateQueries, safeNoDups, stableId, where, suggestAssociationsFix, suggestAssociationsFixFromSummaries, validProps } = require('./src/helpers')
16
16
  const runtime = require('./runtime')
17
- const sortJson = runtime.sortJson
18
17
  const debug = require('./src/debug')
19
18
 
20
19
  const getConfig_getObjectsCheck = (config, testConfig) => {
@@ -69,6 +68,7 @@ const pickObjects = (config, testConfig, getObjects) => {
69
68
  if (!objects) {
70
69
  throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
71
70
  }
71
+
72
72
  if (checks[km] && checks[km].find((check) => check.match && check.apply)) {
73
73
  projection[km] = project2(objects, checks[km])
74
74
  } else {
@@ -316,6 +316,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
316
316
  }
317
317
 
318
318
  let startCounter = 0
319
+ let contextIdCounter = 0
319
320
  while (true) {
320
321
  if (queries.length === 0) {
321
322
  break
@@ -356,8 +357,9 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
356
357
  }
357
358
  const summary = { summaries: json.summaries, length: json.contexts.length }
358
359
  summaries.push(summary)
359
- const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
360
- await processContextsB({ isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
360
+ const { updatedContextIdCounter, contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
361
+ await processContextsB({ contextIdCounter, isTest, isProcess, isModule, rebuildingTemplate, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
362
+ contextIdCounter = updatedContextIdCounter
361
363
  if (isTest) {
362
364
  const end = runtime.performance.performance.now()
363
365
  clientSideTime = end - start
@@ -475,6 +477,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug, tim
475
477
  return
476
478
  }
477
479
  // initialize in between test so state is not preserved since the test was adding without state
480
+ config.testConfig.testModuleName = testConfig.testModuleName
478
481
  await config.rebuild()
479
482
  const errorHandler = (error) => {
480
483
  if (error.metadata) {
@@ -913,7 +916,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
913
916
  console.log('')
914
917
  const screen_width = process.stdout.columns
915
918
  // || 0 for when running without a console
916
- const widths = [70, 10, Math.max(80, screen_width - 71 || 0)]
919
+ const widths = Lines.addRemainder([70, 10])
917
920
  const lines = new Lines(widths)
918
921
  lines.setElement(0, 0, '--- The paraphrases are ----------')
919
922
  lines.setElement(0, 2, '--- The response strings are ----------')
@@ -970,7 +973,7 @@ const rebuildTemplate = async ({ config, instance, target, previousResultss, reb
970
973
  if (instance.fragments) {
971
974
  pr = instance.fragments[index]
972
975
  }
973
- return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics: false })
976
+ return Object.assign({}, toProperties(query), { property: 'fragments', previousResults: pr, skipSemantics: true })
974
977
  }
975
978
 
976
979
  const looper = async (configs) => {
@@ -2008,9 +2011,15 @@ const ensureTestFile = (module, name, type) => {
2008
2011
  }
2009
2012
 
2010
2013
  const knowledgeModule = async (...args) => {
2011
- await knowledgeModuleImpl(...args).catch((e) => {
2014
+ await knowledgeModuleImpl(...args).catch(async (e) => {
2012
2015
  console.error(e)
2013
- process.exit(-1)
2016
+ function sleep(ms) {
2017
+ return new Promise((resolve) => {
2018
+ setTimeout(resolve, ms);
2019
+ });
2020
+ }
2021
+ await sleep(1) // get the stderr to flush
2022
+ await process.exit(-1); // tiny trick: empty write forces flush of console.error buffer
2014
2023
  })
2015
2024
  }
2016
2025
 
package/lines.js CHANGED
@@ -5,6 +5,13 @@ class Lines {
5
5
  this.rows = []
6
6
  }
7
7
 
8
+ static SCREEN_WIDTH = 164
9
+
10
+ static addRemainder(widths) {
11
+ const sum = widths.reduce((a, b) => a + b)
12
+ return [...widths, Lines.SCREEN_WIDTH - sum]
13
+ }
14
+
8
15
  addLine () {
9
16
  this.lines.push(this.widths.map((width) => ''.padEnd(width)))
10
17
  }
package/package.json CHANGED
@@ -3,14 +3,14 @@
3
3
  "@eslint/js": "^9.21.0",
4
4
  "@typescript-eslint/eslint-plugin": "^4.28.4",
5
5
  "@typescript-eslint/parser": "^4.28.4",
6
+ "argparse": "^2.0.1",
6
7
  "eslint": "^7.32.0",
7
8
  "eslint-config-standard": "^16.0.3",
8
9
  "eslint-plugin-import": "^2.23.4",
9
10
  "eslint-plugin-node": "^11.1.0",
10
11
  "eslint-plugin-promise": "^5.1.0",
11
12
  "globals": "^16.0.0",
12
- "jest": "^29.7.0",
13
- "argparse": "^2.0.1"
13
+ "jest": "^30.2.0"
14
14
  },
15
15
  "scripts": {
16
16
  "to:debug": "node inspect node_modules/.bin/jest --runInBand -t NEO23",
@@ -45,6 +45,7 @@
45
45
  "runtime.js",
46
46
  "src/helpers.js",
47
47
  "src/flatten.js",
48
+ "src/fragments.js",
48
49
  "src/unflatten.js",
49
50
  "src/config.js",
50
51
  "src/configHelpers.js",
@@ -61,6 +62,7 @@
61
62
  "dependencies": {
62
63
  "base-64": "^1.0.0",
63
64
  "deep-equal": "^2.0.4",
65
+ "flatted": "^3.3.3",
64
66
  "fs": "0.0.1-security",
65
67
  "json-diff": "^1.0.3",
66
68
  "json-stable-stringify": "^1.0.1",
@@ -68,9 +70,8 @@
68
70
  "node-fetch": "^2.6.1",
69
71
  "readline": "^1.3.0",
70
72
  "scriptjs": "^2.5.9",
71
- "sort-json": "^2.0.0",
72
73
  "uuid": "^8.3.2"
73
74
  },
74
- "version": "9.5.1-beta.3",
75
+ "version": "9.5.1-beta.30",
75
76
  "license": "UNLICENSED"
76
77
  }
package/runtime.js CHANGED
@@ -13,7 +13,6 @@ module.exports = {
13
13
  ArgumentParser,
14
14
  readline: require('readline'),
15
15
  jsonDiff: require('json-diff'),
16
- sortJson: require('sort-json'),
17
16
  util: require('util'),
18
17
  performance: require('perf_hooks')
19
18
  }
package/src/config.js CHANGED
@@ -10,6 +10,7 @@ const { ecatch } = require('./helpers')
10
10
  const runtime = require('../runtime')
11
11
  const _ = require('lodash')
12
12
  const db = require('./debug')
13
+ const { fragmentInstantiator, fragmentMapperInstantiator } = require('./fragments')
13
14
 
14
15
  const debugBreak = () => {
15
16
  // debugger
@@ -20,8 +21,6 @@ const bags = [
20
21
  'semantics'
21
22
  ]
22
23
 
23
- global.GORDO = true
24
-
25
24
  const indent = (string, indent) => {
26
25
  return string.replace(/^/gm, ' '.repeat(indent))
27
26
  }
@@ -401,11 +400,15 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
401
400
  if (bridge.generatorp) {
402
401
  const match = bridge.generatorp.match || (() => true)
403
402
  const apply = typeof bridge.generatorp === 'function' ? bridge.generatorp : bridge.generatorp.apply || bridge.generatorp
404
- const level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
403
+ let level = bridge.generatorp.level >= 0 ? bridge.generatorp.level : bridge.level + 1
404
+ if (!bridge.bridge) {
405
+ level = 0
406
+ }
405
407
 
406
408
  const generator = {
407
409
  where: bridge.generatorp.where || bridge.where || helpers.where(4),
408
- match: async (args) => bridge.id === args.context.marker && args.context.level === level && args.context.paraphrase && await match(args),
410
+ // match: async (args) => bridge.id === args.context.marker && args.context.level === level && args.context.paraphrase && await match(args),
411
+ match: async (args) => args.isA(args.context.marker, bridge.id) && args.context.level === level && args.context.paraphrase && await match(args),
409
412
  apply: (args) => apply(args),
410
413
  applyWrapped: apply,
411
414
  property: 'generatorp'
@@ -422,7 +425,8 @@ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
422
425
  const level = bridge.generatorr.level >= 0 ? bridge.generatorr.level : bridge.level + 1
423
426
  const generator = {
424
427
  where: bridge.generatorr.where || bridge.where || helpers.where(4),
425
- match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
428
+ // match: async (args) => bridge.id === args.context.marker && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
429
+ match: async (args) => args.isA(args.context.marker, bridge.id) && args.context.level === level && !args.context.paraphrase && (args.context.response || args.context.isResponse) && await match(args),
426
430
  apply: (args) => apply(args),
427
431
  applyWrapped: apply,
428
432
  property: 'generatorr'
@@ -509,8 +513,43 @@ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {})
509
513
  if (moreConfig.bridges) {
510
514
  moreConfig.bridges = moreConfig.bridges.map((bridge) => {
511
515
  bridge = { ...bridge }
512
- const valid = ['after', 'conditional', 'associations', 'before', 'bridge', 'check', 'disabled', 'scope', 'skipable', 'return_type_selector', 'evaluator', 'evaluators', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'operator', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
513
- 'level', 'optional', 'selector', 'separators', 'semantic', 'semantics', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid']
516
+ const valid = [
517
+ 'after',
518
+ 'associations',
519
+ 'before',
520
+ 'bridge',
521
+ 'check',
522
+ 'children',
523
+ 'conditional',
524
+ 'convolution',
525
+ 'disabled',
526
+ 'enhanced_associations',
527
+ 'evaluator',
528
+ 'evaluators',
529
+ 'generatorp',
530
+ 'generatorpr',
531
+ 'generatorr',
532
+ 'generators',
533
+ 'id',
534
+ 'inverted',
535
+ 'isA',
536
+ 'level',
537
+ 'levelSpecificHierarchy',
538
+ 'localHierarchy',
539
+ 'operator',
540
+ 'optional',
541
+ 'parents',
542
+ 'return_type_selector',
543
+ 'scope',
544
+ 'selector',
545
+ 'semantic',
546
+ 'semantics',
547
+ 'separators',
548
+ 'skipable',
549
+ 'uuid',
550
+ 'where',
551
+ 'words', /Bridge$/,
552
+ ]
514
553
  helpers.validProps(valid, bridge, 'bridge')
515
554
  handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
516
555
  return bridge
@@ -673,7 +712,7 @@ function setWordsUUIDs (words, uuid) {
673
712
  for (const key in literals) {
674
713
  literals[key] = literals[key].map((o) => Object.assign(o, { uuid }))
675
714
  }
676
- const patterns = words.patterns
715
+ const patterns = words.patterns || []
677
716
  for (const pattern of patterns) {
678
717
  pattern.defs.map((def) => Object.assign(def, { uuid }))
679
718
  }
@@ -902,6 +941,10 @@ class Config {
902
941
  return config_toServer(config)
903
942
  }
904
943
 
944
+ async run(handler) {
945
+ return configHelpers.run(this, handler)
946
+ }
947
+
905
948
  async fixtures () {
906
949
  if (this.testConfig?.fixtures) {
907
950
  const args = {}
@@ -935,6 +978,7 @@ class Config {
935
978
 
936
979
  getPseudoConfig (uuid, config) {
937
980
  return {
981
+ pseudo: true,
938
982
  description: 'this is a pseudo config that has limited functionality due to being available in the initializer and fixtures function context',
939
983
  addAssociation: (...args) => this.addAssociation(...args),
940
984
  addAssociations: (...args) => this.addAssociations(...args),
@@ -948,6 +992,14 @@ class Config {
948
992
  removeSemantic: (...args) => this.removeSemantic(...args, uuid, config.name),
949
993
  addWord: (...args) => this.addWord(...args, uuid),
950
994
  addPattern: (...args) => this.addPattern(...args, uuid),
995
+ updateBridge: (...args) => this.updateBridge(...args),
996
+ processContext: (...args) => this.processContext(...args),
997
+
998
+ semantics: () => this.config.semantics,
999
+ getConfigs: () => this.configs,
1000
+ getTests: () => this.getTests(),
1001
+ getName: () => this.getName(),
1002
+ getDescription: () => this.getDescription(),
951
1003
 
952
1004
  getHierarchy: (...args) => this.config.hierarchy,
953
1005
  getBridges: (...args) => this.config.bridges,
@@ -957,10 +1009,33 @@ class Config {
957
1009
  fragment: (...args) => this.fragment(...args),
958
1010
  server: (...args) => this.server(...args),
959
1011
  exists: (...args) => this.exists(...args),
960
- addAPI: (...args) => this.addAPI(...args)
1012
+ addAPI: (...args) => this.addAPI(...args),
1013
+
1014
+ getParenthesized: () => this.getParenthesized(),
1015
+ setParenthesized: (...args) => this.setParenthesized(...args),
961
1016
  }
962
1017
  }
963
1018
 
1019
+ getName() {
1020
+ return this.name
1021
+ }
1022
+
1023
+ getDescription() {
1024
+ return this.description
1025
+ }
1026
+
1027
+ getTests() {
1028
+ return this.tests
1029
+ }
1030
+
1031
+ getParenthesized(value) {
1032
+ return this.parenthesized
1033
+ }
1034
+
1035
+ setParenthesized(value) {
1036
+ this.parenthesized = value
1037
+ }
1038
+
964
1039
  inDevelopmentMode (call) {
965
1040
  config.developmentModeOn += 1
966
1041
  try {
@@ -1107,59 +1182,52 @@ class Config {
1107
1182
  return instance
1108
1183
  }
1109
1184
 
1110
- fragmentInstantiator (args, contexts) {
1111
- return new Object({
1112
- contexts: () => contexts,
1113
- instantiate: async (mappings) => {
1114
- const instantiated = _.cloneDeep(contexts)
1115
- // const todo = [...instantiated]
1116
- // const todo = [...instantiated]
1117
- const todo = _.clone(instantiated)
1118
- args = { ...args }
1119
- while (todo.length > 0) {
1120
- const context = todo.pop()
1121
- args.context = context
1122
- for (const mapping of mappings) {
1123
- if (await mapping.match(args)) {
1124
- await mapping.apply(args)
1125
- }
1126
- }
1127
- for (const key of Object.keys(context)) {
1128
- // if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
1129
- if (!helpers.isCompound(context[key])) {
1130
- continue
1131
- }
1132
- if (context[key].instantiated) {
1133
- continue
1134
- }
1135
- todo.push(context[key])
1136
- }
1137
- }
1138
- return instantiated
1139
- }
1140
- })
1141
- }
1142
-
1143
- fragment (args, query) {
1185
+ getFragment(query) {
1144
1186
  for (const instance of (this.instances || [])) {
1145
1187
  for (const fragment of (instance.fragments || [])) {
1146
1188
  if (fragment.query === query) {
1147
- return this.fragmentInstantiator(args, fragment.contexts)
1189
+ return fragment
1148
1190
  }
1149
1191
  }
1150
1192
  for (const fragment of (instance.resultss || [])) {
1151
1193
  if (fragment.isFragment && fragment.query === query) {
1152
- return this.fragmentInstantiator(args, fragment.contexts)
1194
+ return fragment
1153
1195
  }
1154
1196
  }
1155
1197
  for (const fragment of (this.fragmentsBeingBuilt || [])) {
1156
1198
  if (fragment.query === query) {
1157
- return this.fragmentInstantiator(args, fragment.contexts)
1199
+ return fragment
1158
1200
  }
1159
1201
  }
1160
1202
  }
1161
1203
  }
1162
1204
 
1205
+ // mappings are optional
1206
+ async fragment (args, query, mappings) {
1207
+ const fragment = this.getFragment(query)
1208
+ if (fragment) {
1209
+ let fi = fragmentInstantiator(args, fragment.contexts)
1210
+ if (mappings) {
1211
+ fi = await fi
1212
+ return fi.instantiate([{
1213
+ match: ({context}) => !!mappings[context.value], // is the value in the mappings
1214
+ apply: ({context}) => Object.assign(context, mappings[context.value]),
1215
+ }])
1216
+ } else {
1217
+ return fi
1218
+ }
1219
+ }
1220
+ }
1221
+
1222
+ fragmentMapper (args, values, fromModelQuery, toModelQuery) {
1223
+ const fromModelFragment = this.getFragment(fromModelQuery)
1224
+ console.dir(fromModelFragment)
1225
+ const toModelFragment = this.getFragment(toModelQuery)
1226
+ console.dir(toModelFragment)
1227
+ const mapper = fragmentMapperInstantiator(values, fromModelFragment.contexts, toModelFragment.contexts)
1228
+ return mapper
1229
+ }
1230
+
1163
1231
  // { rebuild: false, isModule: false }
1164
1232
  needsRebuild (template, instance, options) {
1165
1233
  if (options.rebuild) {
@@ -1518,6 +1586,11 @@ class Config {
1518
1586
  }
1519
1587
  }
1520
1588
 
1589
+ updateBridge(id, updater) {
1590
+ const bridge = this.config.bridges.find((b) => b.id === id)
1591
+ updater({ config: this, bridge })
1592
+ }
1593
+
1521
1594
  addBridge (bridge, uuid) {
1522
1595
  if (!this.config.bridges) {
1523
1596
  this.config.bridges = []
@@ -1819,7 +1892,7 @@ class Config {
1819
1892
 
1820
1893
  // set the args in the api's
1821
1894
  setArgs (args) {
1822
- const setArgs = (config) => {
1895
+ const setConfigArgs = (config) => {
1823
1896
  if (!config._api) {
1824
1897
  return
1825
1898
  }
@@ -1832,10 +1905,10 @@ class Config {
1832
1905
  }
1833
1906
  }
1834
1907
 
1835
- setArgs(this)
1908
+ setConfigArgs(this)
1836
1909
  for (const config of this.configs) {
1837
1910
  if (config.config instanceof Config) {
1838
- setArgs(config.config)
1911
+ setConfigArgs(config.config)
1839
1912
  }
1840
1913
  }
1841
1914
  }
@@ -1864,6 +1937,16 @@ class Config {
1864
1937
  }
1865
1938
  }
1866
1939
 
1940
+ getObjects () {
1941
+ const configs = {}
1942
+ const ns = this.config.objects.namespaced
1943
+ configs[this.name] = this
1944
+ for (const config of this.configs) {
1945
+ configs[config._name] = ns[config._uuid]
1946
+ }
1947
+ return configs
1948
+ }
1949
+
1867
1950
  getConfig (name) {
1868
1951
  if (this.name === name) {
1869
1952
  return this
@@ -1911,12 +1994,7 @@ class Config {
1911
1994
  } else if (this.scope == 'development') {
1912
1995
  new_result = !(element.scope === 'testing')
1913
1996
  }
1914
- if (global.GORDO && old_result !== new_result) {
1915
- global.GORDO = false
1916
- console.log("THERE WAS A DIFFERENCE ------------------------------------------------")
1917
- debugger // greg23old
1918
- }
1919
- return old_result
1997
+ return new_result
1920
1998
  }
1921
1999
 
1922
2000
  config.operators = config.operators.filter((element) => keep(element))
@@ -112,14 +112,18 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
112
112
  throw new ErrorReason(context)
113
113
  }
114
114
  args.kms = config.getConfigs()
115
- args.config = config
115
+ args.config = config.getPseudoConfig(uuidForScoping, config)
116
116
  args.hierarchy = hierarchy
117
117
  args.isA = isA(hierarchy)
118
118
  // args.listable = listable(hierarchy)
119
119
  // args.asList = asList
120
120
  args.retry = () => { throw new RetryError() }
121
- args.fragments = (query) => {
122
- return config.fragment(args, query)
121
+ // mappings are optional
122
+ args.fragments = (query, mappings) => {
123
+ return config.fragment(args, query, mappings)
124
+ }
125
+ args.fragmentMapper = (values, fromModelQuery, toModelQuery) => {
126
+ return config.fragmentMapper(args, values, fromModelQuery, toModelQuery)
123
127
  }
124
128
  args.breakOnSemantics = false
125
129
  args.theDebugger = {
@@ -133,20 +137,35 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
133
137
  args.addPattern = (pattern, def) => config.addPattern(pattern, args.uuid)
134
138
  args.addGenerator = (generator) => config.addGenerator(generator, args.uuid, config.name)
135
139
 
140
+ if (config.testConfig?.testModuleName) {
141
+ args.testModuleName = config.testConfig.testModuleName
142
+ }
136
143
  args.addAssumedScoped = (args, assumed) => {
137
144
  const addAssumed = (args, ...moreAssumed) => {
138
145
  return { ...args, assumed: Object.assign({}, assumed, (args.assumed || {}), ...moreAssumed) }
139
146
  }
140
147
 
141
- args.s = (c) => config.getSemantics(logs).apply(args, c)
142
- args.g = (c, a = {}) => {
143
- return config.getGenerators(logs).apply(addAssumed(args, a), c, a)
148
+ args.s = (c, options = {}) => config.getSemantics(logs).apply(args, c, options)
149
+ args.g = (c, rest = {}) => {
150
+ // if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
151
+ // debugger
152
+ // }
153
+ const { assumed = {}, options = {} } = rest
154
+ return config.getGenerators(logs).apply(addAssumed(args, assumed), c, assumed, options)
144
155
  }
145
- args.gp = (c, a = {}) => {
146
- return config.getGenerators(logs).apply(addAssumed(args, a, { paraphrase: true, isResponse: false, response: false }), c, { paraphrase: true, isResponse: false, response: false })
156
+ args.gp = (c, rest = {}) => {
157
+ // if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
158
+ // debugger
159
+ // }
160
+ const { assumed = {}, options = {} } = rest
161
+ return config.getGenerators(logs).apply(addAssumed(args, assumed, { paraphrase: true, isResponse: false, response: false }), c, { paraphrase: true, isResponse: false, response: false }, options)
147
162
  }
148
- args.gr = (c, a = {}) => {
149
- return config.getGenerators(logs).apply(addAssumed(args, a, { paraphrase: false, isResponse: true }), { ...c, paraphrase: false, isResponse: true })
163
+ args.gr = (c, rest = {}) => {
164
+ // if (JSON.stringify(rest) !== '{}' && !(rest.assumed || rest.options)) {
165
+ // debugger
166
+ // }
167
+ const { assumed = {}, options = {} } = rest
168
+ return config.getGenerators(logs).apply(addAssumed(args, assumed, { paraphrase: false, isResponse: true }), { ...c, paraphrase: false, isResponse: true }, options)
150
169
  }
151
170
  args.e = (c) => {
152
171
  if (!c) {
@@ -181,6 +200,7 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
181
200
 
182
201
  Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
183
202
  args.apis = args.apis || ((name) => config.getConfig(name).api)
203
+ // args.apis = (name) => config.getAPIs(name)
184
204
  /*
185
205
  if (uuidForScoping) {
186
206
  Object.assign(args, args.getUUIDScoped(uuidForScoping))
@@ -199,6 +219,22 @@ const getObjects = (objects) => {
199
219
  }
200
220
  }
201
221
 
222
+ const run = async (config, handler) => {
223
+ // map to hash
224
+ config = config || {}
225
+ if (config.config) {
226
+ config = config
227
+ }
228
+
229
+ const hierarchy = new DigraphInternal((config.config || {}).hierarchy || [])
230
+
231
+ const objects = config.config.objects.namespaced[config.uuid]
232
+ const logs = []
233
+ const args = {}
234
+ setupArgs(args, config, logs, hierarchy)
235
+ return handler(args)
236
+ }
237
+
202
238
  const processContext = async (context, { objects = {}, config, logs = [] }) => {
203
239
  const generators = config.getGenerators(logs)
204
240
  const semantics = config.getSemantics(logs)
@@ -291,7 +327,7 @@ const setupContexts = (rawContexts) => {
291
327
  return contexts
292
328
  }
293
329
 
294
- const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate }) => {
330
+ const processContextsB = async ({ config, hierarchy, semantics, generators, json, isTest, isProcess, isModule, rebuildingTemplate, isInstance, instance, query, data, retries, url, commandLineArgs, forTemplate, contextIdCounter }) => {
295
331
  // TODO fix this name to contextsPrime
296
332
  const contextsPrime = []
297
333
  const generatedPrime = []
@@ -311,14 +347,13 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
311
347
  args.insert = (context) => toDo.unshift(context)
312
348
  let overlap, lastRange
313
349
  config.debugLoops = commandLineArgs && commandLineArgs.debugLoops
314
- let context_id_counter = 0
315
350
  while (toDo.length > 0) {
316
351
  const context = toDo.shift()
317
352
  args.calls.next()
318
353
  let contextPrime = context
319
354
  context.topLevel = true
320
- context_id_counter += 1
321
- context.context_id = context_id_counter
355
+ contextIdCounter += 1
356
+ context.context_id = contextIdCounter
322
357
  try {
323
358
  if (json.has_errors) {
324
359
  throw new Error('There are errors in the logs. Run with the -d flag and grep for Error')
@@ -328,6 +363,9 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
328
363
  const semantics = config.getSemantics(json.logs)
329
364
  try {
330
365
  contextPrime = await semantics.apply(args, context)
366
+ // contextPrime.greg = 'yes'
367
+ // console.log("context_id", context.context_id)
368
+ // console.log("semantics.apply", JSON.stringify(contextPrime, null, 2))
331
369
  } catch (e) {
332
370
  if (e.message == 'Maximum call stack size exceeded') {
333
371
  const mostCalled = semantics.getMostCalled()
@@ -368,21 +406,21 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
368
406
  const generated = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
369
407
  let generatedParenthesized = []
370
408
  if (generateParenthesized) {
371
- config.parenthesized = true
409
+ config.setParenthesized(true)
372
410
  generatedParenthesized = contextPrime.isResponse ? await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed) : ''
373
- config.parenthesized = false
411
+ config.setParenthesized(false)
374
412
  }
375
413
  // assumed = { paraphrase: true, response: false };
376
414
  assumed = { paraphrase: true, isResponse: false, response: false }
377
415
  if (generateParenthesized) {
378
- config.parenthesized = false
416
+ config.setParenthesized(false)
379
417
  }
380
418
  const paraphrases = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
381
419
  let paraphrasesParenthesized = []
382
420
  if (generateParenthesized) {
383
- config.parenthesized = true
421
+ config.setParenthesized(true)
384
422
  paraphrasesParenthesized = await config.getGenerators(json.logs).apply({ ...args, assumed }, contextPrime, assumed)
385
- config.parenthesized = false
423
+ config.setParenthesized(false)
386
424
  }
387
425
  contextsPrime.push(contextPrime)
388
426
  generatedPrime.push(generated)
@@ -421,7 +459,7 @@ const processContextsB = async ({ config, hierarchy, semantics, generators, json
421
459
  throw e
422
460
  }
423
461
  }
424
- return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime }
462
+ return { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime, updatedContextIdCounter: contextIdCounter }
425
463
  }
426
464
 
427
465
  // instance template loadTemplate
@@ -479,6 +517,9 @@ const loadInstance = async (config, instance) => {
479
517
  args.isModule = true
480
518
  args.isProcess = false
481
519
  }
520
+ if (instance.name == config.testConfig.testModuleName) {
521
+ args.isTesting = true
522
+ }
482
523
  await results.apply(args)
483
524
  } else if (results.isFragment) {
484
525
  } else {
@@ -490,6 +531,9 @@ const loadInstance = async (config, instance) => {
490
531
  args.instance = ''
491
532
  args.isProcess = !config.isModule
492
533
  args.isModule = !!config.isModule
534
+ if (instance.name == config.testConfig.testModuleName) {
535
+ args.isTesting = true
536
+ }
493
537
  await processContextsB(args)
494
538
  if (results.skipSemantics) {
495
539
  config.config.skipSemantics = null
@@ -505,6 +549,7 @@ module.exports = {
505
549
  // listable,
506
550
  setupArgs,
507
551
  processContext,
552
+ run,
508
553
  getObjects,
509
554
  gs,
510
555
  processContextsB,
@@ -0,0 +1,83 @@
1
+ const _ = require('lodash')
2
+ const helpers = require('./helpers')
3
+
4
+ function fragmentInstantiator (args, contexts) {
5
+ return new Object({
6
+ contexts: () => {
7
+ return _.cloneDeep(contexts)
8
+ },
9
+ instantiate: async (mappings) => {
10
+ const instantiated = _.cloneDeep(contexts)
11
+ const todo = [{ context: instantiated, path: [] }]
12
+ args = { ...args }
13
+ while (todo.length > 0) {
14
+ const { context, path } = todo.pop()
15
+ args.context = context
16
+ args.path = path
17
+ for (const mapping of mappings) {
18
+ if (await mapping.match(args)) {
19
+ await mapping.apply(args)
20
+ }
21
+ }
22
+ for (const key of Object.keys(context)) {
23
+ // if (['number', 'string', 'boolean'].includes(typeof (context[key]))) {
24
+ if (!helpers.isCompound(context[key])) {
25
+ continue
26
+ }
27
+ if (context[key].instantiated) {
28
+ continue
29
+ }
30
+ todo.push({ context: context[key], path: [...path, key] })
31
+ }
32
+ }
33
+ if (contexts.length == 1 && instantiated.length == 1) {
34
+ return instantiated[0]
35
+ } else {
36
+ return instantiated
37
+ }
38
+ }
39
+ })
40
+ }
41
+
42
+ async function fragmentMapperInstantiator(values, modelFrom, modelTo) {
43
+ const paths = {}
44
+ for (const value of values) {
45
+ paths[value] = { value }
46
+ }
47
+
48
+ {
49
+ const fi = fragmentInstantiator({paths}, modelFrom)
50
+ await fi.instantiate([
51
+ {
52
+ match: ({context, path}) => values.includes(context.value),
53
+ apply: ({context, path}) => paths[context.value].from = path
54
+ },
55
+ ])
56
+ }
57
+
58
+ {
59
+ const fi = fragmentInstantiator({paths}, modelTo)
60
+ await fi.instantiate([
61
+ {
62
+ match: ({context, path}) => values.includes(context.value),
63
+ apply: ({context, path}) => paths[context.value].to = path
64
+ },
65
+ ])
66
+ }
67
+ return {
68
+ instantiate: (actualFrom) => {
69
+ const actualTo = structuredClone(modelTo)
70
+ for (const value in paths) {
71
+ const { from, to } = paths[value]
72
+ const actualValue = helpers.getByPath(actualFrom, from, null)
73
+ helpers.setByPath(actualTo, to, actualValue)
74
+ }
75
+ return actualTo
76
+ }
77
+ }
78
+ }
79
+
80
+ module.exports = {
81
+ fragmentInstantiator,
82
+ fragmentMapperInstantiator,
83
+ }
package/src/generators.js CHANGED
@@ -182,10 +182,10 @@ class Generators {
182
182
  const generator = this.generators[igenerator]
183
183
  if (await generator.matches(args, objects, context, hierarchy, config, options)) {
184
184
  const log = (message) => { this.logs.push(message) }
185
- // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${JSON.stringify(context)}`)
185
+ // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${stringify(context)}`)
186
186
  let errorMessage = 'The apply function did not return a value'
187
187
  try {
188
- generated = await generator.apply(args, objects, context, hierarchy, config, response, log)
188
+ generated = await generator.apply(args, objects, context, hierarchy, config, response, log, options)
189
189
  } catch (e) {
190
190
  // the next if handle this
191
191
  generated = null
@@ -202,7 +202,7 @@ class Generators {
202
202
  }
203
203
  }
204
204
  if (!generated && generated !== '') {
205
- const widths = [10, 10, 90]
205
+ const widths = Lines.addRemainder([10, 10])
206
206
  const lines = new Lines(widths)
207
207
  lines.setElement(0, 0, 'Generator')
208
208
  const source = `${generator.km}/#${generator.index}`
@@ -212,7 +212,7 @@ class Generators {
212
212
  lines.newRow()
213
213
  lines.setElement(0, 1, 'TO')
214
214
  lines.setElement(0, 2, `context_id: ${context.context_id}`)
215
- lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
215
+ lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 10 }), null, 2))
216
216
  lines.newRow()
217
217
  lines.setElement(0, 1, 'STACK')
218
218
  lines.setElement(0, 2, stack)
@@ -230,7 +230,7 @@ class Generators {
230
230
  throw { error: [message], logs: this.logs }
231
231
  }
232
232
  if (((config || {}).config || {}).debug) {
233
- const widths = [10, 10, 90]
233
+ const widths = Lines.addRemainder([10, 10])
234
234
  const lines = new Lines(widths)
235
235
  lines.setElement(0, 0, 'Generator')
236
236
  if (generator.index > -1 && generator.km) {
@@ -263,7 +263,7 @@ class Generators {
263
263
  }
264
264
  args.calls.pop()
265
265
  if (!applied && ((config || {}).config || {}).debug) {
266
- const widths = [10, 10, 90]
266
+ const widths = Lines.addRemainder([10, 10])
267
267
  const lines = new Lines(widths)
268
268
  lines.setElement(0, 0, 'Generator')
269
269
  lines.setElement(0, 2, 'No generator applied')
@@ -275,7 +275,11 @@ class Generators {
275
275
  lines.setElement(0, 2, JSON.stringify(context, null, 2))
276
276
  this.logs.push(lines.toString())
277
277
  }
278
- return ((config || {}).parenthesized ? '(' + generated + ')' : generated)
278
+ let parenthesized = false
279
+ if (config && config.getParenthesized()) {
280
+ parenthesized = true
281
+ }
282
+ return parenthesized ? '(' + generated + ')' : generated
279
283
  }
280
284
  }
281
285
 
package/src/helpers.js CHANGED
@@ -292,8 +292,53 @@ const hashCode = (str) => {
292
292
  return hash
293
293
  }
294
294
 
295
- const sortJson = (json) => {
296
- return json
295
+ /**
296
+ * Recursively sorts object keys alphabetically.
297
+ * Fully handles arrays (including objects inside arrays) and preserves Date/other non-plain objects.
298
+ *
299
+ * @param {any} input - The value to sort (object, array, primitive, etc.)
300
+ * @param {Object} [options]
301
+ * - ignoreCase: boolean (default false) – case-insensitive sort
302
+ * - reverse: boolean (default false) – reverse alphabetical order
303
+ * @returns {any} New sorted value
304
+ */
305
+ function sortJson(input, options = {}) {
306
+ const { ignoreCase = false, reverse = false } = options;
307
+
308
+ // Helper: is this a plain object {} (not Array, Date, Map, null, etc.)
309
+ function isPlainObject(value) {
310
+ return value !== null && typeof value === 'object' && value.constructor === Object;
311
+ }
312
+
313
+ // Handle arrays: map over elements and recurse
314
+ if (Array.isArray(input)) {
315
+ return input.map(item => sortJson(item, options));
316
+ }
317
+
318
+ // If not a plain object, return unchanged (preserves Date, Map, Set, primitives, etc.)
319
+ if (!isPlainObject(input)) {
320
+ return input;
321
+ }
322
+
323
+ // Sorter for keys
324
+ const sorter = (a, b) => {
325
+ const A = ignoreCase ? a.toLowerCase() : a;
326
+ const B = ignoreCase ? b.toLowerCase() : b;
327
+ return reverse ? B.localeCompare(A) : A.localeCompare(B);
328
+ };
329
+
330
+ // Build new sorted object
331
+ const sorted = {};
332
+
333
+ Object.keys(input)
334
+ .sort(sorter)
335
+ .forEach(key => {
336
+ const value = input[key];
337
+ // Always recurse: handles nested objects and arrays properly
338
+ sorted[key] = sortJson(value, options);
339
+ });
340
+
341
+ return sorted;
297
342
  }
298
343
 
299
344
  const validProps = (valids, object, type) => {
@@ -436,6 +481,63 @@ const stableId = (tag) => {
436
481
  return id
437
482
  }
438
483
 
484
+ function getByPath(obj, path, defaultValue) {
485
+ let current = obj;
486
+ for (const key of path) {
487
+ if (current === null || current === undefined) return defaultValue;
488
+ if (typeof current !== 'object') return defaultValue;
489
+ current = current[key];
490
+ }
491
+ return current === undefined ? defaultValue : current;
492
+ }
493
+
494
+ /**
495
+ * Set a value in an object by path array.
496
+ * Automatically creates missing objects {} or arrays [] as needed.
497
+ *
498
+ * @param {Object} obj - The root object to modify
499
+ * @param {Array<string|number>} path - Array of keys/indices
500
+ * @param {*} value - Value to set
501
+ * @returns {*} The set value (for chaining)
502
+ */
503
+ function setByPath(obj, path, value) {
504
+ if (!Array.isArray(path) || path.length === 0) {
505
+ throw new Error('Path must be a non-empty array');
506
+ }
507
+
508
+ let current = obj;
509
+
510
+ for (let i = 0; i < path.length; i++) {
511
+ const key = path[i];
512
+ const isLast = i === path.length - 1;
513
+
514
+ if (isLast) {
515
+ // Final step — just assign
516
+ current[key] = value;
517
+ } else {
518
+ // Not last — ensure next level exists
519
+ const nextKey = path[i + 1];
520
+
521
+ if (current[key] == null) {
522
+ // Auto-create: array if next key is number, otherwise object
523
+ current[key] = typeof nextKey === 'number' || String(nextKey >>> 0) === nextKey
524
+ ? []
525
+ : {};
526
+ } else if (Array.isArray(current[key]) && typeof nextKey !== 'number') {
527
+ // Safety: if current is array but next key isn't a valid index → convert to object
528
+ current[key] = { ...current[key] };
529
+ } else if (!Array.isArray(current[key]) && typeof nextKey === 'number') {
530
+ // If next expects array but current is object → convert
531
+ current[key] = Object.values(current[key]);
532
+ }
533
+
534
+ current = current[key];
535
+ }
536
+ }
537
+
538
+ return value;
539
+ }
540
+
439
541
  module.exports = {
440
542
  stableId,
441
543
  ecatch,
@@ -463,4 +565,6 @@ module.exports = {
463
565
  w,
464
566
  suggestAssociationsFix,
465
567
  suggestAssociationsFixFromSummaries,
568
+ getByPath,
569
+ setByPath,
466
570
  }
package/src/project2.js CHANGED
@@ -3,6 +3,13 @@ function project(source, filters) {
3
3
  return source
4
4
  }
5
5
 
6
+ function isPlainObject(obj) {
7
+ return Object.prototype.toString.call(obj) === '[object Object]';
8
+ }
9
+ if (!isPlainObject(source) && !Array.isArray(source)) {
10
+ return source
11
+ }
12
+
6
13
  if (Object.keys(source).length === 0 && filters.length === 0) {
7
14
  return {};
8
15
  }
package/src/semantics.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const { args: contextArgs, normalizeGenerator, normalizeSemantic } = require('./helpers')
2
2
  const Lines = require('../lines')
3
3
  const helpers = require('./helpers')
4
+ const debug = require('./debug')
4
5
 
5
6
  class Semantic {
6
7
  // constructor ({match, apply, uuid, index, km, notes}) {
@@ -70,6 +71,7 @@ class Semantic {
70
71
  }
71
72
 
72
73
  async matches (args, context, options = {}) {
74
+ args = {...args}
73
75
  this.fixUpArgs(args, context)
74
76
  const matches = await this.matcher(args)
75
77
  if (matches && (options.debug || {}).match || args.callId === this.callId) {
@@ -81,6 +83,7 @@ class Semantic {
81
83
  }
82
84
 
83
85
  async apply (args, context, s, options = {}) {
86
+ args = {...args}
84
87
  const { config } = args
85
88
  if (config && config.debugLoops) {
86
89
  console.log('apply', this.toLabel())
@@ -218,7 +221,7 @@ class Semantics {
218
221
  errorMessage = e.toString()
219
222
  }
220
223
 
221
- const widths = [10, 10, 90]
224
+ const widths = Lines.addRemainder([10, 10])
222
225
  const lines = new Lines(widths)
223
226
  lines.setElement(0, 0, 'Semantic')
224
227
  const source = `${semantic.km}/#${semantic.index}`
@@ -248,7 +251,7 @@ class Semantics {
248
251
  args.calls.touch(contextPrime)
249
252
  // this.logs.push(`Semantics: applied ${semantic.toString()}\n to\n ${JSON.stringify(context)}\n the result was ${JSON.stringify(contextPrime)}\n`)
250
253
  if (((config || {}).config || {}).debug) {
251
- const widths = [10, 10, 132]
254
+ const widths = Lines.addRemainder([10, 10])
252
255
  const lines = new Lines(widths)
253
256
  lines.setElement(0, 0, 'Semantic')
254
257
  if (semantic.index > -1 && semantic.km) {
@@ -295,7 +298,7 @@ class Semantics {
295
298
  }
296
299
  args.calls.pop()
297
300
  if (!applied && ((config || {}).config || {}).debug) {
298
- const widths = [10, 10, 90]
301
+ const widths = Lines.addRemainder([10, 10])
299
302
  const lines = new Lines(widths)
300
303
  lines.setElement(0, 0, 'Semantic')
301
304
  lines.setElement(0, 2, 'No semantic applied')