theprogrammablemind 7.6.0 → 7.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -173,22 +173,32 @@ const setupArgs = (args, config, logs, hierarchy) => {
173
173
  args.theDebugger = {
174
174
  breakOnSemantics: (value) => args.breakOnSemantics = value
175
175
  }
176
- args.s = (c) => config.getSemantics(logs).apply(args, c)
177
- args.g = (c) => config.getGenerators(logs).apply(args, c)
178
- args.gp = (c) => config.getGenerators(logs).apply(args, { ...c, paraphrase: true, isResponse: false, response: false})
179
- args.gr = (c) => config.getGenerators(logs).apply(args, { ...c, paraphrase: false, isResponse: true })
180
176
  if (!logs) {
181
177
  debugger
182
178
  }
183
- args.e = (c) => config.getEvaluator(args.s, args.calls, logs, c)
184
179
  args.log = (message) => logs.push(message)
185
- args.gs = gs(args.g)
186
- args.gsp = gs(args.gp)
187
- args.gsr = gs(args.gr)
180
+
181
+ args.addAssumedScoped = (args, assumed) => {
182
+ args.s = (c) => config.getSemantics(logs).apply(args, c)
183
+ args.g = (c) => config.getGenerators(logs).apply(args, c)
184
+ args.gp = (c) => config.getGenerators(logs).apply({...args, assumed: {paraphrase: true, isResponse: false, response: false}}, c, {paraphrase: true, isResponse: false, response: false})
185
+ args.gr = (c) => config.getGenerators(logs).apply({...args, assumed: {paraphrase: false, isResponse: true}}, { ...c, paraphrase: false, isResponse: true })
186
+ args.e = (c) => config.getEvaluator(args.s, args.calls, logs, c)
187
+ args.gs = gs(args.g)
188
+ args.gsp = gs(args.gp)
189
+ args.gsr = gs(args.gr)
190
+ }
191
+ // for semantics
192
+ args.addAssumedScoped(args, {})
188
193
  config.getAddedArgs(args)
189
194
  }
190
195
 
191
196
  const gs = (g) => (contexts, separator, lastSeparator) => {
197
+ if (!Array.isArray(contexts)) {
198
+ debugger
199
+ throw new Error("Expected a list")
200
+ }
201
+
192
202
  let s = ''
193
203
  if (!separator) {
194
204
  separator = ' '
@@ -276,8 +286,9 @@ const processContext = (context, { objects = {}, config, logs = [] }) => {
276
286
  setupArgs(args, config, logs, hierarchy)
277
287
 
278
288
  context = semantics.apply(args, context)
279
- const generated = generators.apply(args, context)[0]
280
- const paraphrases = generators.apply(args, context, { paraphrase: true, response: false, isResponse: false })[0]
289
+ const generated = generators.apply(args, context)
290
+ const assumed = { paraphrase: true, response: false, isResponse: false }
291
+ const paraphrases = generators.apply({...args, assumed}, context, { paraphrase: true, response: false, isResponse: false })
281
292
  let responses = []
282
293
  if (context.isResponse) {
283
294
  responses = generated
@@ -447,37 +458,29 @@ const processContextsB = ({ config, hierarchy, semantics, generators, json, isTe
447
458
  continue
448
459
  }
449
460
  let assumed = { isResponse: true };
450
- const generated = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
461
+ const generated = contextPrime.isResponse ? config.getGenerators(json.logs).apply({...args, assumed}, contextPrime, assumed) : ''
451
462
  let generatedParenthesized = []
452
463
  if (generateParenthesized) {
453
464
  config.parenthesized = true
454
- generatedParenthesized = contextPrime.isResponse ? config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0] : ''
465
+ generatedParenthesized = contextPrime.isResponse ? config.getGenerators(json.logs).apply({...args, assumed}, contextPrime, assumed) : ''
455
466
  config.parenthesized = false
456
467
  }
457
468
  // assumed = { paraphrase: true, response: false };
458
- assumed = { paraphrase: true };
459
- args.g = (c) => config.getGenerators(json.logs).apply(args, c, assumed)
460
- args.gp = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: true, isResponse: false, response: false }, assumed)
461
- args.gr = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: false }, assumed)
462
- args.gs = gs(args.g)
463
- args.gsp = gs(args.gsp)
464
- args.gsr = gs(args.gr)
469
+ assumed = { paraphrase: true, isResponse: false, response: false };
470
+ // args.g = (c) => config.getGenerators(json.logs).apply({...args, assumed}, c, assumed)
471
+ // args.gs = gs(args.g)
465
472
  if (generateParenthesized) {
466
473
  config.parenthesized = false
467
474
  }
468
- const paraphrases = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
475
+ const paraphrases = config.getGenerators(json.logs).apply({...args, assumed}, contextPrime, assumed)
469
476
  let paraphrasesParenthesized = []
470
477
  if (generateParenthesized) {
471
478
  config.parenthesized = true
472
- paraphrasesParenthesized = config.getGenerators(json.logs).apply(args, contextPrime, assumed)[0]
479
+ paraphrasesParenthesized = config.getGenerators(json.logs).apply({...args, assumed}, contextPrime, assumed)
473
480
  config.parenthesized = false
474
481
  }
475
- args.g = (c) => config.getGenerators(json.logs).apply(args, c)
476
- args.gp = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: true, isResponse: false, response: false })
477
- args.gr = (c) => config.getGenerators(json.logs).apply(args, {...c, paraphrase: false })
478
- args.gs = gs(args.g)
479
- args.gsp = gs(args.gp)
480
- args.gsr = gs(args.gr)
482
+ // args.g = (c) => config.getGenerators(json.logs).apply(args, c)
483
+ // args.gs = gs(args.g)
481
484
  contextsPrime.push(contextPrime)
482
485
  generatedPrime.push(generated)
483
486
  paraphrasesPrime.push(paraphrases)
@@ -660,6 +663,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
660
663
  opChoices: []
661
664
  },
662
665
  times: 0.0,
666
+ clientSideTimes: 0.0,
663
667
  trace: '',
664
668
  contexts: [],
665
669
  generated: [],
@@ -701,8 +705,16 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
701
705
  if (json.status !== 200) {
702
706
  throw json
703
707
  } else {
708
+ let clientSideTime
709
+ if (isTest) {
710
+ start = runtime.performance.performance.now()
711
+ }
704
712
  const { contextsPrime, generatedPrime, paraphrasesPrime, paraphrasesParenthesizedPrime, generatedParenthesizedPrime, responsesPrime } =
705
713
  processContextsB({ isTest, config, hierarchy, json, commandLineArgs /*, generators, semantics */ })
714
+ if (isTest) {
715
+ end = runtime.performance.performance.now()
716
+ clientSideTime = end - start
717
+ }
706
718
  response.associations = json.associations
707
719
  response.learned_contextual_priorities = json.learned_contextual_priorities
708
720
  response.hierarchy = json.hierarchy
@@ -713,6 +725,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
713
725
  // appendNoDups(response.metadata.priorities, json.metadata.priorities)
714
726
  appendNoDups(response.metadata.opChoices, json.metadata.opChoices)
715
727
  response.times += json.times
728
+ response.clientSideTimes += clientSideTime
716
729
  response.trace = response.trace.concat(json.trace)
717
730
  response.version = json.version
718
731
  response.explain_priorities = json.explain_priorities
@@ -778,10 +791,6 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
778
791
  const test = expected.query
779
792
  // initialize in between test so state is not preserved since the test was adding without state
780
793
  config.rebuild()
781
- if (!args.dontAddAssociations) {
782
- config.addAssociationsFromTests(config.tests)
783
- }
784
- // config.addAssocationsFromTests(
785
794
  const errorHandler = (error) => {
786
795
  if (error.metadata) {
787
796
  const priorities = analyzeMetaData(expected.metadata, error.metadata)
@@ -806,10 +815,10 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
806
815
  defaultInnerProcess(config, errorHandler, result)
807
816
  }
808
817
  if (verbose) {
809
- const widths = [100, 20]
818
+ const widths = [100, 60]
810
819
  const lines = new Lines(widths)
811
820
  lines.setElement(0, 0, test)
812
- lines.setElement(0, 1, `time on server ${result.times.toFixed(2)}`)
821
+ lines.setElement(0, 1, `time on server: ${result.times.toFixed(2)} client: ${(result.clientSideTimes/1000).toFixed(2)}`)
813
822
  lines.log()
814
823
  }
815
824
  const expected_objects = sortJson(convertToStable(expected.objects), { depth: 25 })
@@ -1173,7 +1182,7 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1173
1182
  }
1174
1183
 
1175
1184
  if (responses.explain_priorities) {
1176
- console.log("Explain Priorities")
1185
+ console.log("Explain Priorities (listed from lower priority to higher priority)")
1177
1186
  for ([inputss, outpus, reason] of responses.explain_priorities) {
1178
1187
  console.log(` ${JSON.stringify(inputss)} reason: ${reason}`)
1179
1188
  }
@@ -1274,6 +1283,7 @@ const rebuildTemplate = async ({ config, target, template, errorHandler = defaul
1274
1283
  }
1275
1284
  if (results.contexts.length > 1) {
1276
1285
  console.log(`query "${query.query}". There is ${results.contexts.length} contexts in the results. Make sure its producing the results that you expect.`)
1286
+ throw new Error(`query "${query.query}". There is ${results.contexts.length} contexts in the results. Make sure its producing the results that you expect.`)
1277
1287
  } else if (results.paraphrases[0] != query.query) {
1278
1288
  console.log(`query "${query.query}". The paraphrase is different from the query "${results.paraphrases[0]}".`)
1279
1289
  } else {
@@ -1299,14 +1309,18 @@ const rebuildTemplate = async ({ config, target, template, errorHandler = defaul
1299
1309
  // it will just get added to the config
1300
1310
  const extraConfig = queryOrExtraConfig
1301
1311
  console.log('config', extraConfig)
1302
- try {
1303
- config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true } )
1304
- } catch ( e ) {
1305
- const where = extraConfig.where ? ` ${extraConfig.where}` : ''
1306
- throw new Error(`Error processing extra config${where}: ${e.stack}}`)
1312
+ if (extraConfig.stop) {
1313
+ await looper([])
1314
+ } else {
1315
+ try {
1316
+ config.addInternal(_.cloneDeep(extraConfig), { handleCalculatedProps: true } )
1317
+ } catch ( e ) {
1318
+ const where = extraConfig.where ? ` ${extraConfig.where}` : ''
1319
+ throw new Error(`Error processing extra config${where}: ${e.stack}}`)
1320
+ }
1321
+ accumulators[property].push({ extraConfig: true, ...extraConfig })
1322
+ await looper(queries)
1307
1323
  }
1308
- accumulators[property].push({ extraConfig: true, ...extraConfig })
1309
- await looper(queries)
1310
1324
  }
1311
1325
  }
1312
1326
 
@@ -1327,6 +1341,7 @@ const rebuildTemplate = async ({ config, target, template, errorHandler = defaul
1327
1341
  } else {
1328
1342
  delete result.load_cache_time
1329
1343
  delete result.times
1344
+ delete result.clientSideTimes
1330
1345
  delete result.memory_free_percent
1331
1346
  delete result.logs
1332
1347
  delete result.version
@@ -1366,7 +1381,29 @@ const rebuildTemplate = async ({ config, target, template, errorHandler = defaul
1366
1381
  await looper(Object.assign([], todo))
1367
1382
  }
1368
1383
 
1369
- const knowledgeModule = async ({
1384
+ const checkTemplate = (template) => {
1385
+ return
1386
+ if (!template) {
1387
+ return
1388
+ }
1389
+ if (template.checks) {
1390
+ throw new Error("The 'checks' property should be in the 'test' property not the 'template' property")
1391
+ }
1392
+ }
1393
+
1394
+ const checkTest = (testConfig) => {
1395
+ if (!testConfig) {
1396
+ return
1397
+ }
1398
+ if (!testConfig.name) {
1399
+ throw new Error("The 'test' property is missing the 'name' property that contains the name of the '<km>.test.json' file")
1400
+ }
1401
+ if (!testConfig.contents) {
1402
+ throw new Error("The 'test' property is missing the 'contents' property that contains contents of the '<km>.test.json' file")
1403
+ }
1404
+ }
1405
+
1406
+ const knowledgeModuleImpl = async ({
1370
1407
  module: moduleFromJSFile,
1371
1408
  description,
1372
1409
  section,
@@ -1399,9 +1436,10 @@ const knowledgeModule = async ({
1399
1436
  if (!description) {
1400
1437
  throw new Error("'description' is a required parameter. The value should the description of the knowledge module.")
1401
1438
  }
1402
- if (!test) {
1439
+ if (!testConfig) {
1403
1440
  throw new Error("'test' is a required parameter. The value should the path to the file used to store the tests of the knowledge module and the contents of the file in the form { name: <filePath>, contexts: <json> }.")
1404
1441
  }
1442
+ checkTest(testConfig)
1405
1443
 
1406
1444
  const isProcess = require.main === moduleFromJSFile
1407
1445
 
@@ -1466,7 +1504,6 @@ const knowledgeModule = async ({
1466
1504
  parser.add_argument('--parenthesized', { action: 'store_true', help: 'Show the generated phrases with parenthesis.' })
1467
1505
  parser.add_argument('-c', '--clean', { help: 'Remove data from the test files. a === association' })
1468
1506
  parser.add_argument('-od', '--objectDiff', { action: 'store_true', help: 'When showing the objects use a colour diff' })
1469
- parser.add_argument('-daa', '--dontAddAssociations', { action: 'store_true', help: 'Do not add associations from the tests.' })
1470
1507
  parser.add_argument('-p', '--print', { help: 'Print the specified elements c === config, w === words, b === bridges, o === operators d === objects (d for data), h === hierarchy, g === generators, s === semantics, l === load t=tests ordering p === priorities a == associations j == JSON sent to server. for example --print wb' })
1471
1508
  parser.add_argument('-s', '--save', { action: 'store_true', help: 'When running with the --query flag this will save the current run to the test file. When running without the --query flag all tests will be run and resaved.' })
1472
1509
  parser.add_argument('-sd', '--saveDeveloper', { action: 'store_true', help: 'Same as -s but the query will not show up in the info command.' })
@@ -1671,6 +1708,8 @@ const knowledgeModule = async ({
1671
1708
  }
1672
1709
  }
1673
1710
 
1711
+ checkTemplate(template)
1712
+
1674
1713
  if (template) {
1675
1714
  const needsRebuild = config.needsRebuild(template.template, template.instance, options)
1676
1715
  if (needsRebuild) {
@@ -1678,17 +1717,21 @@ const knowledgeModule = async ({
1678
1717
  options.rebuild = true
1679
1718
  config.config.rebuild = true
1680
1719
  }
1681
- config.load(template.template, template.instance, { rebuild: needsRebuild })
1682
- printConfig()
1720
+ try {
1721
+ config.load(template.template, template.instance, { rebuild: needsRebuild })
1722
+ } catch( e ) {
1723
+ debugger
1724
+ console.error(`Error loading template for ${config.name}. ${e.error ? e.error : e}`)
1725
+ runtime.process.exit(-1)
1726
+ }
1727
+ if (!args.query) {
1728
+ printConfig()
1729
+ }
1683
1730
  if (needsRebuild) {
1684
1731
  return
1685
1732
  }
1686
1733
  }
1687
1734
 
1688
- if (!args.save && !args.rebuildTemplate && !args.dontAddAssociations) {
1689
- config.addAssociationsFromTests(config.tests);
1690
- }
1691
-
1692
1735
  if (args.retrain) {
1693
1736
  config.config.retrain = true
1694
1737
  }
@@ -1696,7 +1739,6 @@ const knowledgeModule = async ({
1696
1739
  if (args.test || args.testVerbose || args.testAllVerbose || args.save) {
1697
1740
  global.transitoryMode = true
1698
1741
  }
1699
-
1700
1742
  if (!args.query && !args.test && !args.info && (args.save || args.saveDeveloper)) {
1701
1743
  global.transitoryMode = true
1702
1744
  saveTests(config, test, testConfig, args.saveDeveloper)
@@ -1718,7 +1760,6 @@ const knowledgeModule = async ({
1718
1760
  useTestConfig = config.getConfigs()[args.testModuleName].getTestConfig()
1719
1761
  useTestConfig.testModuleName = args.testModuleName
1720
1762
  test = useTestConfig.name
1721
-
1722
1763
  }
1723
1764
  runTests(config, test, { args, debug: args.debug, testConfig: useTestConfig, verbose: args.testVerbose || args.testAllVerbose, stopAtFirstError: !args.testAllVerbose }).then((results) => {
1724
1765
  let newError = false
@@ -1762,17 +1803,21 @@ const knowledgeModule = async ({
1762
1803
  console.log(` actual ${label} `, actual)
1763
1804
  newError = true
1764
1805
  headerShown = true
1806
+ if (args.vimdiff) {
1807
+ vimdiff(result.actual.paraphrasesParenthesized, result.expected.paraphrasesParenthesized)
1808
+ }
1765
1809
  }
1766
1810
  }
1767
1811
  show('paraphrases', result.expected.paraphrases, result.actual.paraphrases)
1768
1812
  if (!args.testNoParenthesized) {
1769
1813
  show('paraphrases parenthesized', result.expected.paraphrasesParenthesized, result.actual.paraphrasesParenthesized)
1770
1814
  }
1815
+ /*
1816
+ }
1771
1817
  show('responses', result.expected.responses, result.actual.responses)
1772
1818
  if (!args.testNoParenthesized) {
1773
1819
  show('responses parenthesized', result.expected.generatedParenthesized, result.actual.generatedParenthesized)
1774
1820
  }
1775
- /*
1776
1821
  if (JSON.stringify(result.expected.paraphrases) !== JSON.stringify(result.actual.paraphrases)) {
1777
1822
  if (!headerShown) {
1778
1823
  console.log(' Failure')
@@ -1798,10 +1843,10 @@ const knowledgeModule = async ({
1798
1843
  }
1799
1844
  const widths = [4, 18, 72]
1800
1845
  const lines = new Lines(widths)
1801
- lines.setElement(1, 1, 'expected checked')
1846
+ lines.setElement(1, 1, 'expected checked objects')
1802
1847
  lines.setElement(2, 2, JSON.stringify(result.expected.checked, null, 2))
1803
1848
  lines.log()
1804
- lines.setElement(1, 1, 'actual checked')
1849
+ lines.setElement(1, 1, 'actual checked objects')
1805
1850
  lines.setElement(2, 2, JSON.stringify(result.actual.checked, null, 2))
1806
1851
  lines.log()
1807
1852
  if (args.vimdiff) {
@@ -1816,10 +1861,10 @@ const knowledgeModule = async ({
1816
1861
  }
1817
1862
  const widths = [4, 18, 72]
1818
1863
  const lines = new Lines(widths)
1819
- lines.setElement(1, 1, 'expected checkedContexts', true)
1864
+ lines.setElement(1, 1, 'expected checked contexts', true)
1820
1865
  lines.setElement(2, 2, JSON.stringify(result.expected.checkedContexts, null, 2))
1821
1866
  lines.log()
1822
- lines.setElement(1, 1, 'actual checkedContexts', true)
1867
+ lines.setElement(1, 1, 'actual checked contexts', true)
1823
1868
  lines.setElement(2, 2, JSON.stringify(result.actual.checkedContexts, null, 2))
1824
1869
  lines.log()
1825
1870
  if (args.vimdiff) {
@@ -1836,16 +1881,18 @@ const knowledgeModule = async ({
1836
1881
  }
1837
1882
  }
1838
1883
  }
1839
- if (!headerShown) {
1884
+ if (hasError) {
1885
+ if (!headerShown) {
1886
+ if (!(useTestConfig.check && useTestConfig.check.length > 0)) {
1887
+ console.log('There are failures due to things other than paraphrases, responses and checked properties being different. They are not shown because you ran -tv or -tva which only shows difference in paraphrase and results. Usually what I do is -s and do a diff to make sure there are no other problems. If the paraphrases or results were different they would have shown here.')
1888
+ }
1889
+ }
1840
1890
  if (!(useTestConfig.check && useTestConfig.check.length > 0)) {
1841
- console.log('There are failures due to things other than paraphrases, responses and checked properties being different. They are not shown because you ran -tv or -tva which only shows difference in paraphrase and results. Usually what I do is -s and do a diff to make sure there are no other problems. If the paraphrases or results were different they would have shown here.')
1891
+ console.log('use -v arg to write files expected.json and actual.json in the current directory for detailed comparison. Or do -s and then git diff the changes.')
1892
+ // console.log(JSON.stringify(contexts))
1893
+ console.log('**************************** ERRORS ************************')
1842
1894
  }
1843
1895
  }
1844
- if (!(useTestConfig.check && useTestConfig.check.length > 0)) {
1845
- console.log('use -v arg to write files expected.json and actual.json in the current directory for detailed comparison. Or do -s and then git diff the changes.')
1846
- // console.log(JSON.stringify(contexts))
1847
- console.log('**************************** ERRORS ************************')
1848
- }
1849
1896
  }
1850
1897
  // const contexts = { failures: results }
1851
1898
  l(n - 1, hasError || newError)
@@ -1939,8 +1986,6 @@ const knowledgeModule = async ({
1939
1986
  errorHandler(e)
1940
1987
  }
1941
1988
  }
1942
-
1943
- config.addAssociationsFromTests(config.tests);
1944
1989
  }
1945
1990
 
1946
1991
  createConfigExport = () => {
@@ -1951,7 +1996,6 @@ const knowledgeModule = async ({
1951
1996
  }
1952
1997
  moduleFromJSFile.exports = createConfigExport
1953
1998
  }
1954
-
1955
1999
  }
1956
2000
 
1957
2001
  /*
@@ -1999,6 +2043,10 @@ function w(func) {
1999
2043
  return func
2000
2044
  }
2001
2045
 
2046
+ const knowledgeModule = async (...args) => {
2047
+ await knowledgeModuleImpl(...args).catch((e) => console.error(e))
2048
+ }
2049
+
2002
2050
  module.exports = {
2003
2051
  process: _process,
2004
2052
  where,
package/package.json CHANGED
@@ -64,6 +64,6 @@
64
64
  "json-stable-stringify": "^1.0.1",
65
65
  "node-fetch": "^2.6.1"
66
66
  },
67
- "version": "7.6.0",
67
+ "version": "7.7.0-beta.0",
68
68
  "license": "ISC"
69
69
  }
package/runtime.js CHANGED
@@ -15,4 +15,5 @@ module.exports = {
15
15
  jsonDiff: require('json-diff'),
16
16
  sortJson: require('sort-json'),
17
17
  util: require('util'),
18
+ performance: require('perf_hooks'),
18
19
  }
package/src/config.js CHANGED
@@ -27,7 +27,7 @@ const config_toServer = (config) => {
27
27
 
28
28
  const debugPriority = (priority) => {
29
29
  if (global.entodictonDebugPriority) {
30
- if (helpers.safeEquals(entodictonDebugPriority, priority)) {
30
+ if (helpers.subPriority(entodictonDebugPriority, priority)) {
31
31
  debugger; // debug hierarchy hit
32
32
  }
33
33
  }
@@ -1137,12 +1137,6 @@ class Config {
1137
1137
  return this.config.objects.namespaced[this._uuid]
1138
1138
  }
1139
1139
 
1140
- addAssociationsFromTests(tests = []) {
1141
- for (let test of tests) {
1142
- this.addAssociations(test.associations || []);
1143
- }
1144
- }
1145
-
1146
1140
  addAssociations (associations) {
1147
1141
  for (let association of associations) {
1148
1142
  this.addAssociation(association)
package/src/flatten.js CHANGED
@@ -81,6 +81,9 @@ const flatten = (markers, value) => {
81
81
  return flattenListHelper(markers, value)
82
82
  }
83
83
 
84
+ if (value.flatten === false) {
85
+ return [[value], false]
86
+ }
84
87
  const marker = value.marker
85
88
  let properties = value
86
89
 
package/src/generators.js CHANGED
@@ -73,7 +73,8 @@ class Generator {
73
73
  return matches
74
74
  }
75
75
 
76
- apply (baseArgs, objects, g, gs, context, hierarchy, config, response, log, options = {}) {
76
+ // apply (baseArgs, objects, g, gs, context, hierarchy, config, response, log, options = {}) {
77
+ apply (baseArgs, objects, context, hierarchy, config, response, log, options = {}) {
77
78
  if (!log) {
78
79
  throw new Error('generators.apply argument log is required')
79
80
  }
@@ -103,12 +104,12 @@ class Generator {
103
104
  log,
104
105
  global:
105
106
  objects,
106
- g,
107
+ // g,
107
108
  n,
108
109
  hierarchy,
109
110
  context,
110
111
  uuid: this.uuid,
111
- gs,
112
+ // gs,
112
113
  config,
113
114
  response,
114
115
  api: this.getAPI(config),
@@ -165,136 +166,125 @@ class Generators {
165
166
  this.logs = logs
166
167
  };
167
168
 
168
- // assumed - properties added to contexts before the generators are called. For setting paraphrase property
169
- apply (args, contexts, assumed = {}, options = {}) {
169
+ // assumed - properties added to context before the generators are called. For setting paraphrase property
170
+ apply (args, context, assumed = {}, options = {}) {
171
+ if (Array.isArray(context)) {
172
+ throw new Error("Expected a context not an array")
173
+ }
174
+ if (typeof context !== 'object') {
175
+ return String(context)
176
+ }
177
+
170
178
  const config = args.config
171
179
  const objects = args.objects
172
180
  const hierarchy = args.hierarchy
173
181
  const response = args.response
174
- if (Array.isArray(contexts)) {
175
- // no-op
176
- } else if (typeof contexts === 'object') {
177
- contexts = [contexts]
178
- } else {
179
- return String(contexts)
180
- }
181
182
 
182
- const contextsPrime = []
183
- for (const icontext in contexts) {
184
- let context = contexts[icontext]
185
- context = Object.assign({}, context, assumed)
186
- // let context_prime = JSON.stringify(context);
187
- let generated = context
188
- let applied = false
189
- const stack = args.calls.push()
190
- for (let igenerator = 0; igenerator < this.generators.length; ++igenerator) {
191
- const generator = this.generators[igenerator]
192
- if (generator.matches(args, objects, context, hierarchy, config, options)) {
193
- const g = (context, options) => {
194
- const r = this.apply(args, context, Object.assign({}, ((options||{}).assumed || {}), assumed), options)
195
- if (Array.isArray(r)) {
196
- return r.join(' ')
197
- } else {
198
- return r
199
- }
200
- }
201
- const log = (message) => { this.logs.push(message) }
202
- // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${JSON.stringify(context)}`)
203
- let errorMessage = 'The apply function did not return a value'
204
- try {
205
- generated= generator.apply(args, objects, g, args.gs, context, hierarchy, config, response, log)
206
- } catch( e ) {
207
- // the next if handle this
208
- generated = null
209
- e.retryCall = () => generator.apply(args, objects, g, args.gs, context, hierarchy, config, response, log)
210
- const help = 'The error has a retryCall property that will recall the function that failed.'
211
- if (e.stack && e.message) {
212
- const info = `${generator.notes ? generator.notes : ''}${generator.where ? generator.where : ''}`
213
- errorMessage = `Error applying generator '${info}. Error is ${e.toString()} stack is ${e.stack}. Generator is ${generator.toString()}. ${help}`
214
- } else if (e.error) {
215
- const info = `${generator.notes ? generator.notes : ''}${generator.where ? generator.where : ''}`
216
- errorMessage = `Error applying generator '${info}. Error is ${e.error.join()}. Generator is ${generator.toString()}. ${help}`
217
- } else {
218
- errorMessage = e.toString()
219
- }
183
+
184
+ // args = { ...args, ...args.getAssumedScoped(assumed) }
185
+ args.addAssumedScoped(args, assumed)
186
+ context = Object.assign({}, context, args.assumed)
187
+ let generated = ''
188
+ let applied = false
189
+ const stack = args.calls.push()
190
+ for (let igenerator = 0; igenerator < this.generators.length; ++igenerator) {
191
+ const generator = this.generators[igenerator]
192
+ if (generator.matches(args, objects, context, hierarchy, config, options)) {
193
+ const log = (message) => { this.logs.push(message) }
194
+ // this.logs.push(`Generators: applied ${generator.toString()}\n to\n ${JSON.stringify(context)}`)
195
+ let errorMessage = 'The apply function did not return a value'
196
+ try {
197
+ generated= generator.apply(args, objects, context, hierarchy, config, response, log)
198
+ } catch( e ) {
199
+ // the next if handle this
200
+ generated = null
201
+ e.retryCall = () => generator.apply(args, objects, context, hierarchy, config, response, log)
202
+ const help = 'The error has a retryCall property that will recall the function that failed.'
203
+ if (e.stack && e.message) {
204
+ const info = `${generator.notes ? generator.notes : ''}${generator.where ? generator.where : ''}`
205
+ errorMessage = `Error applying generator '${info}. Error is ${e.toString()} stack is ${e.stack}. Generator is ${generator.toString()}. ${help}`
206
+ } else if (e.error) {
207
+ const info = `${generator.notes ? generator.notes : ''}${generator.where ? generator.where : ''}`
208
+ errorMessage = `Error applying generator '${info}. Error is ${e.error.join()}. Generator is ${generator.toString()}. ${help}`
209
+ } else {
210
+ errorMessage = e.toString()
220
211
  }
221
- if (!generated && generated !== '') {
222
- const widths = [10, 10, 90]
223
- const lines = new Lines(widths)
224
- lines.setElement(0, 0, 'Generator')
225
- const source = `${generator.km}/#${generator.index}`
226
- lines.setElement(0, 2, `ERROR while applying (${source}) ${generator.toLabel()}`)
227
- lines.newRow()
228
- lines.setElement(0, 2, generator.toString())
229
- lines.newRow()
230
- lines.setElement(0, 1, 'TO')
231
- lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(helpers.sortJson(context, { depth: 25 })))})`)
232
- lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
233
- lines.newRow()
234
- lines.setElement(0, 1, 'STACK')
235
- lines.setElement(0, 2, stack)
236
- lines.newRow()
237
- lines.setElement(0, 1, 'DEBUG')
238
- lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
239
- lines.newRow()
240
- lines.setElement(0, 1, 'ERROR')
241
- lines.setElement(0, 2, errorMessage)
242
- this.logs.push(lines.toString())
243
- const message = `ERROR while applying (${source}) ${generator.toLabel()}\n to\n ${JSON.stringify(context, null, 2)}.\n${errorMessage}'`
244
- // this.logs.push(message)
245
- // return [message]
246
- args.calls.pop()
247
- throw { error: [message], logs: this.logs }
248
- }
249
- if (((config || {}).config || {}).debug) {
250
- const widths = [10, 10, 90]
251
- const lines = new Lines(widths)
252
- lines.setElement(0, 0, 'Generator')
253
- if (generator.index > -1 && generator.km) {
254
- // lines.setElement(0, 2, `KM '${generator.km}' ordinal: ${generator.index}`)
255
- lines.setElement(0, 2, generator.toLabel())
256
- }
257
- lines.newRow()
258
- lines.setElement(0, 1, 'APPLIED')
212
+ }
213
+ if (!generated && generated !== '') {
214
+ const widths = [10, 10, 90]
215
+ const lines = new Lines(widths)
216
+ lines.setElement(0, 0, 'Generator')
217
+ const source = `${generator.km}/#${generator.index}`
218
+ lines.setElement(0, 2, `ERROR while applying (${source}) ${generator.toLabel()}`)
219
+ lines.newRow()
220
+ lines.setElement(0, 2, generator.toString())
221
+ lines.newRow()
222
+ lines.setElement(0, 1, 'TO')
223
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(helpers.sortJson(context, { depth: 25 })))})`)
224
+ lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
225
+ lines.newRow()
226
+ lines.setElement(0, 1, 'STACK')
227
+ lines.setElement(0, 2, stack)
228
+ lines.newRow()
229
+ lines.setElement(0, 1, 'DEBUG')
230
+ lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
231
+ lines.newRow()
232
+ lines.setElement(0, 1, 'ERROR')
233
+ lines.setElement(0, 2, errorMessage)
234
+ this.logs.push(lines.toString())
235
+ const message = `ERROR while applying (${source}) ${generator.toLabel()}\n to\n ${JSON.stringify(context, null, 2)}.\n${errorMessage}'`
236
+ // this.logs.push(message)
237
+ // return [message]
238
+ args.calls.pop()
239
+ throw { error: [message], logs: this.logs }
240
+ }
241
+ if (((config || {}).config || {}).debug) {
242
+ const widths = [10, 10, 90]
243
+ const lines = new Lines(widths)
244
+ lines.setElement(0, 0, 'Generator')
245
+ if (generator.index > -1 && generator.km) {
246
+ // lines.setElement(0, 2, `KM '${generator.km}' ordinal: ${generator.index}`)
259
247
  lines.setElement(0, 2, generator.toLabel())
260
- lines.newRow()
261
- lines.setElement(0, 2, generator.toString())
262
- lines.newRow()
263
- lines.setElement(0, 1, 'RESULT')
264
- lines.setElement(0, 2, generated)
265
- lines.newRow()
266
- lines.setElement(0, 1, 'STACK')
267
- lines.setElement(0, 2, stack)
268
- lines.newRow()
269
- lines.setElement(0, 1, 'DEBUG')
270
- lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
271
- lines.newRow()
272
- lines.setElement(0, 1, 'TO')
273
- lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(helpers.sortJson(context, { depth: 25 })))})`)
274
- lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
275
- this.logs.push(lines.toString())
276
248
  }
277
- applied = true
278
- break
249
+ lines.newRow()
250
+ lines.setElement(0, 1, 'APPLIED')
251
+ lines.setElement(0, 2, generator.toLabel())
252
+ lines.newRow()
253
+ lines.setElement(0, 2, generator.toString())
254
+ lines.newRow()
255
+ lines.setElement(0, 1, 'RESULT')
256
+ lines.setElement(0, 2, generated)
257
+ lines.newRow()
258
+ lines.setElement(0, 1, 'STACK')
259
+ lines.setElement(0, 2, stack)
260
+ lines.newRow()
261
+ lines.setElement(0, 1, 'DEBUG')
262
+ lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
263
+ lines.newRow()
264
+ lines.setElement(0, 1, 'TO')
265
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(helpers.sortJson(context, { depth: 25 })))})`)
266
+ lines.setElement(1, 2, JSON.stringify(helpers.sortJson(context, { depth: 25 }), null, 2))
267
+ this.logs.push(lines.toString())
279
268
  }
269
+ applied = true
270
+ break
280
271
  }
281
- args.calls.pop()
282
- if (!applied && ((config || {}).config || {}).debug) {
283
- const widths = [10, 10, 90]
284
- const lines = new Lines(widths)
285
- lines.setElement(0, 0, 'Generator')
286
- lines.setElement(0, 2, 'No generator applied')
287
- lines.newRow()
288
- lines.setElement(0, 1, 'STACK')
289
- lines.setElement(0, 2, stack)
290
- lines.newRow()
291
- lines.setElement(0, 1, 'TO')
292
- lines.setElement(0, 2, JSON.stringify(context, null, 2))
293
- this.logs.push(lines.toString())
294
- }
295
- contextsPrime.push((config || {}).parenthesized ? "(" + generated + ")" : generated)
296
272
  }
297
- return contextsPrime
273
+ args.calls.pop()
274
+ if (!applied && ((config || {}).config || {}).debug) {
275
+ const widths = [10, 10, 90]
276
+ const lines = new Lines(widths)
277
+ lines.setElement(0, 0, 'Generator')
278
+ lines.setElement(0, 2, 'No generator applied')
279
+ lines.newRow()
280
+ lines.setElement(0, 1, 'STACK')
281
+ lines.setElement(0, 2, stack)
282
+ lines.newRow()
283
+ lines.setElement(0, 1, 'TO')
284
+ lines.setElement(0, 2, JSON.stringify(context, null, 2))
285
+ this.logs.push(lines.toString())
286
+ }
287
+ return ((config || {}).parenthesized ? "(" + generated + ")" : generated)
298
288
  }
299
289
  }
300
290
 
package/src/helpers.js CHANGED
@@ -334,6 +334,45 @@ const ecatch = (where, call) => {
334
334
  }
335
335
  }
336
336
 
337
+ const equalKey = (key1, key2) => {
338
+ return key1[0] == key2[0] && key1[1] == key2[1]
339
+ }
340
+
341
+ // matches for { context: ..., [ordered], choose: ... } exactely OR
342
+ // [ <id1>, <id2> ] - where id1 is chosen
343
+ const subPriority = (sub, sup) => {
344
+ if (Array.isArray(sub)) {
345
+ const subChoosen = sub[0]
346
+ const subOther = sub[1]
347
+ const hasChoosen = sup.choose.find( (index) => equalKey(sup.context[index], subChoosen)) != undefined
348
+ const hasOtherChosen = sup.choose.find( (index) => equalKey(sup.context[index], subOther)) != undefined
349
+ const hasOther = sup.context.find( (other) => equalKey(other, subOther) ) !== undefined
350
+ return !!(hasChoosen && hasOther) && !hasOtherChosen
351
+ }
352
+
353
+ if (!safeEquals([...sub.choose].sort(), [...sup.choose].sort())) {
354
+ return false
355
+ }
356
+
357
+ const choose = (priority) => {
358
+ const chosen = []
359
+ for (const i of priority.choose) {
360
+ chosen.push(priority.context[i])
361
+ }
362
+ return chosen
363
+ }
364
+ const chosen1 = choose(sub)
365
+ const chosen2 = choose(sup)
366
+ const sameId = (id1, id2) => id1[0] == id2[0] && id1[1] == id2[1]
367
+ // same length so only need one way
368
+ const missing1 = chosen1.find( (id1) => !chosen2.find( (id2) => sameId(id1, id2)) )
369
+ if (missing1) {
370
+ return false
371
+ }
372
+
373
+ return true
374
+ }
375
+
337
376
  module.exports = {
338
377
  ecatch,
339
378
  functionsToStrings,
@@ -354,5 +393,6 @@ module.exports = {
354
393
  isCompound,
355
394
  InitCalls,
356
395
  hashCode,
357
- sortJson
396
+ sortJson,
397
+ subPriority,
358
398
  }
package/src/project.js CHANGED
@@ -16,6 +16,9 @@ const project = (object, filter) => {
16
16
  return object.map( element => project(element, filter) )
17
17
  } else {
18
18
  for (let properties of filter) {
19
+ if (typeof properties == 'function') {
20
+ properties = properties(object)
21
+ }
19
22
  if (typeof properties == 'object') {
20
23
  if (properties.propertyLists) {
21
24
  for (const propertyList in properties.propertyLists) {
@@ -45,7 +48,6 @@ const project = (object, filter) => {
45
48
  if (properties.property) {
46
49
  const property = properties.property
47
50
  if (properties.isPropertyList) {
48
- debugger
49
51
  if (!Array.isArray(object[property])) {
50
52
  return projection
51
53
  }