theprogrammablemind_4wp 7.6.0 → 7.7.0-beta.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -14,4 +14,5 @@ module.exports = {
14
14
  jsonDiff: "Should not be called in the browser",
15
15
  sortJson: "Should not be called in the browser",
16
16
  util: "Should not be called in the browser",
17
+ performance: "Should not be called in the browser",
17
18
  }
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
  }