theprogrammablemind_4wp 7.12.4 → 7.12.5

Sign up to get free protection for your applications and to get access to all the features.
package/client.js CHANGED
@@ -10,12 +10,47 @@ const _ = require('lodash')
10
10
  const stringify = require('json-stable-stringify')
11
11
  const Lines = require('./lines')
12
12
  const flattens = require('./src/flatten')
13
- const { appendNoDups, InitCalls, updateQueries, safeNoDups } = require('./src/helpers')
13
+ const { appendNoDups, InitCalls, updateQueries, safeNoDups, stableId } = require('./src/helpers')
14
14
  const runtime = require('./runtime')
15
15
  const sortJson = runtime.sortJson
16
16
 
17
- const getConfig_getObjectsCheck = (testConfig) => {
18
- return (testConfig.checks && testConfig.checks.objects) || []
17
+ function where (goUp = 2) {
18
+ const e = new Error()
19
+ const regexForm1 = /\((.*):(\d+):(\d+)\)$/
20
+ const regexForm2 = /at (.*):(\d+):(\d+)$/
21
+ const lines = e.stack.split('\n')
22
+ let line
23
+ let match
24
+ for (line of lines.slice(1)) {
25
+ // if (!(line.includes('config.js:') || line.includes('client.js:') || line.includes('<anonymous>'))) {
26
+ if (!(line.includes('config.js:') || line.includes('client.js:'))) {
27
+ match = regexForm1.exec(line) || regexForm2.exec(line)
28
+ if (!match) {
29
+ continue
30
+ }
31
+ break
32
+ }
33
+ }
34
+ // const line = e.stack.split("\n")[goUp];
35
+ // const match = regexForm1.exec(line) || regexForm2.exec(line)
36
+ if (match) {
37
+ return `${match[1]}:${match[2]}`
38
+ } else {
39
+ return 'running in browser'
40
+ }
41
+ }
42
+
43
+ const getConfig_getObjectsCheck = (config, testConfig) => {
44
+ let testConfigName = config.name
45
+ if (testConfig.testModuleName) {
46
+ testConfigName = testConfig.testModuleName
47
+ }
48
+ const checks = (testConfig.checks && testConfig.checks.objects) || []
49
+ if (Array.isArray(checks)) {
50
+ return { [testConfigName]: checks }
51
+ } else {
52
+ return checks
53
+ }
19
54
  }
20
55
 
21
56
  const getConfig_getContextCheck = (testConfig) => {
@@ -26,61 +61,122 @@ const pickContext = (testConfig) => (context) => {
26
61
  return project(context, getConfig_getContextCheck(testConfig))
27
62
  }
28
63
 
29
- const pickObjects = (testConfig, objects) => {
30
- return project(objects, getConfig_getObjectsCheck(testConfig))
64
+ const pickObjects = (config, testConfig, getObjects) => {
65
+ /*
66
+ let testConfigName = config.name
67
+ if (testConfig.testModuleName) {
68
+ objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
69
+ testConfigName = testConfig.testModuleName
70
+ }
71
+ */
72
+ const checks = getConfig_getObjectsCheck(config, testConfig)
73
+ const projection = {}
74
+ for (let km in checks) {
75
+ const objects = getObjects(km)
76
+ if (!objects) {
77
+ throw new Error(`In the checks for ${config.name} the KM ${km} does not exist`)
78
+ }
79
+ projection[km] = project(objects, checks[km])
80
+ }
81
+ return projection
31
82
  }
32
83
 
33
- // move ask to the KM's since verbatim is called
34
- const getAsk = (config) => (uuid) => (asks) => {
35
- for (const ask of asks) {
36
- let oneShot = true // default
37
- if (ask.oneShot === false) {
38
- oneShot = false
39
- }
40
- config.addSemantic({
41
- uuid,
42
- oneShot,
43
- match: (args) => ask.matchr(args),
44
- apply: (args) => ask.applyr(args)
45
- })
46
- }
47
- let oneShot = true
48
- for (const ask of asks) {
49
- if (ask.oneShot === false) {
50
- oneShot = false
51
- }
52
- }
53
- config.addSemantic({
54
- uuid,
55
- oneShot,
56
- match: ({ context }) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
57
- apply: (args) => {
58
- for (const ask of asks) {
59
- let matchq = ask.matchq
60
- let applyq = ask.applyq
61
- if (!matchq) {
62
- let wasAsked = false
63
- matchq = () => !wasAsked,
64
- applyq = (args) => {
65
- wasAsked = true
66
- applyq(args)
84
+ // move ask to the KM's since verbatim is called probably in dialogues?
85
+ const getAsk = (config) => (uuid) => {
86
+ // if (!uuid) {
87
+ // debugger
88
+ //}
89
+ return (asks) => {
90
+ const ask = (ask) => {
91
+ let oneShot = true // default
92
+ if (ask.oneShot === false) {
93
+ oneShot = false
94
+ }
95
+
96
+ const id_q = stableId('semantic')
97
+ const id_rs = []
98
+ let wasAsked = false
99
+ let wasApplied = false
100
+ const getWasAsked = () => {
101
+ return wasAsked
102
+ }
103
+ const setWasAsked = (value) => {
104
+ wasAsked = value
105
+ }
106
+ const getWasApplied = () => {
107
+ return wasApplied
108
+ }
109
+ const setWasApplied = (value) => {
110
+ wasApplied = value
111
+ }
112
+
113
+ const semanticsr = ask.semanticsr || []
114
+ if (semanticsr.length == 0) {
115
+ semanticsr.push({ match: ask.matchr, apply: ask.applyr })
116
+ }
117
+ for (const semantic of semanticsr) {
118
+ const id_r = stableId('semantic')
119
+ id_rs.push(id_r)
120
+ config.addSemantic({
121
+ uuid,
122
+ id: id_r,
123
+ tied_ids: [id_q],
124
+ oneShot,
125
+ where: semantic.where || ask.where || where(2),
126
+ source: 'response',
127
+ match: (args) => semantic.match(args),
128
+ apply: (args) => {
129
+ setWasApplied(true)
130
+ semantic.apply(args)
131
+ },
132
+ })
133
+ }
134
+
135
+ config.addSemantic({
136
+ uuid,
137
+ oneShot,
138
+ id: id_q,
139
+ tied_ids: id_rs,
140
+ where: ask.where,
141
+ isQuestion: true, // do one question at a time
142
+ getWasAsked,
143
+ getWasApplied,
144
+ onNevermind: ask.onNevermind,
145
+ source: 'question',
146
+ match: ({ context }) => context.marker == 'controlEnd' || context.marker == 'controlBetween',
147
+ apply: (args) => {
148
+ let matchq = ask.matchq
149
+ let applyq = ask.applyq
150
+ if (!matchq) {
151
+ let wasAsked = false
152
+ matchq = () => !wasAsked,
153
+ applyq = (args) => {
154
+ wasAsked = true
155
+ return ask.applyq(args)
156
+ }
67
157
  }
158
+ if (matchq(args)) {
159
+ setWasAsked(true)
160
+ setWasApplied(false)
161
+ // args.context.motivationKeep = true
162
+ args.verbatim(applyq(args))
163
+ /*
164
+ args.context.verbatim = applyq(args)
165
+ args.context.isResponse = true;
166
+ delete args.context.controlRemove;
167
+ */
168
+ args.context.controlKeepMotivation = true
169
+ }
170
+ args.context.cascade = true
68
171
  }
69
- if (matchq(args)) {
70
- // args.context.motivationKeep = true
71
- args.verbatim(applyq(args))
72
- /*
73
- args.context.verbatim = applyq(args)
74
- args.context.isResponse = true;
75
- delete args.context.controlRemove;
76
- */
77
- args.context.controlKeepMotivation = true
78
- break
79
- }
80
- }
81
- args.context.cascade = true
172
+ })
82
173
  }
83
- })
174
+ if (!Array.isArray(asks)) {
175
+ asks = [asks]
176
+ }
177
+
178
+ [...asks].reverse().forEach( (a) => ask(a) )
179
+ }
84
180
  }
85
181
 
86
182
  const sameJSON = (json1, json2) => {
@@ -105,6 +201,9 @@ const vimdiff = (actualJSON, expectedJSON, title) => {
105
201
  }
106
202
 
107
203
  const listable = (hierarchy) => (c, type) => {
204
+ if (!c) {
205
+ return false
206
+ }
108
207
  if (hierarchy.isA(c.marker, type)) {
109
208
  return true
110
209
  }
@@ -119,6 +218,9 @@ const listable = (hierarchy) => (c, type) => {
119
218
  }
120
219
 
121
220
  const isA = (hierarchy) => (child, parent) => {
221
+ if (!child || !parent) {
222
+ return false
223
+ }
122
224
  if (child.marker) {
123
225
  child = child.marker
124
226
  }
@@ -147,7 +249,8 @@ class ErrorReason extends Error {
147
249
  }
148
250
 
149
251
  const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
150
- config.setArgs(args)
252
+
253
+ // callId
151
254
  args.calls = new InitCalls(args.isInstance ? `${args.isInstance}#${config.name}` : config.name)
152
255
  if (global.theprogrammablemind && global.theprogrammablemind.loadForTesting) {
153
256
  args.calls = new InitCalls(Object.keys(global.theprogrammablemind.loadForTesting)[0])
@@ -165,32 +268,11 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
165
268
  args.asList = asList
166
269
  args.retry = () => { throw new RetryError() }
167
270
  args.fragments = (query) => config.fragment(query)
168
- const scopedAsk = getAsk(config)
169
-
170
- const getAPI = (uuid) => {
171
- if (config && config.getAPI) {
172
- return config.getAPI(uuid)
173
- }
174
- }
175
- const getAPIs = (uuid) => {
176
- if (config && config.getAPIs) {
177
- return config.getAPIs(uuid)
178
- }
179
- }
180
- args.getUUIDScoped = (uuid) => {
181
- return {
182
- ask: scopedAsk(uuid),
183
- api: getAPI(uuid),
184
- apis: getAPIs(uuid)
185
- }
186
- }
187
- Object.assign(args, args.getUUIDScoped(uuidForScoping))
188
271
  args.breakOnSemantics = false
189
272
  args.theDebugger = {
190
273
  breakOnSemantics: (value) => args.breakOnSemantics = value
191
274
  }
192
275
  if (!logs) {
193
- debugger
194
276
  }
195
277
  args.log = (message) => logs.push(message)
196
278
 
@@ -219,6 +301,33 @@ const setupArgs = (args, config, logs, hierarchy, uuidForScoping) => {
219
301
  // for semantics
220
302
  args.addAssumedScoped(args, {})
221
303
  config.getAddedArgs(args)
304
+
305
+ const getAPI = (uuid) => {
306
+ if (config && config.getAPI) {
307
+ return config.getAPI(uuid)
308
+ }
309
+ }
310
+ const getAPIs = (uuid) => {
311
+ if (config && config.getAPIs) {
312
+ return config.getAPIs(uuid)
313
+ }
314
+ }
315
+ const scopedAsk = getAsk(config)
316
+ args.getUUIDScoped = (uuid) => {
317
+ return {
318
+ ask: scopedAsk(uuid),
319
+ api: getAPI(uuid),
320
+ apis: getAPIs(uuid)
321
+ }
322
+ }
323
+ Object.assign(args, args.getUUIDScoped(uuidForScoping || config.uuid))
324
+ /*
325
+ if (uuidForScoping) {
326
+ Object.assign(args, args.getUUIDScoped(uuidForScoping))
327
+ }
328
+ */
329
+ // sets args for all the API. that make a copy so the args must be fully setup by here except for scoped
330
+ config.setArgs(args)
222
331
  }
223
332
 
224
333
  const gs = (g) => (contexts, separator, lastSeparator) => {
@@ -657,10 +766,8 @@ const loadInstance = (config, instance) => {
657
766
  config.config.skipSemantics = results.skipSemantics
658
767
  }
659
768
  const args = { config, hierarchy, json: results, commandLineArgs: {} }
660
- if (instance.queries) {
661
- args.isInstance = `instance${i}`
662
- args.instance = instance.queries[i]
663
- }
769
+ args.isInstance = `instance${i}`
770
+ args.instance = ''
664
771
  processContextsB(args)
665
772
  if (results.skipSemantics) {
666
773
  config.config.skipSemantics = null
@@ -777,6 +884,7 @@ const _process = async (config, query, { initializer, commandLineArgs, credentia
777
884
  response.trace = response.trace.concat(json.trace)
778
885
  response.version = json.version
779
886
  response.explain_priorities = json.explain_priorities
887
+ response.contextual_priorities_ambiguities = json.contextual_priorities_ambiguities
780
888
 
781
889
  response.contexts = response.contexts.concat(contextsPrime)
782
890
  response.generated = response.generated.concat(generatedPrime)
@@ -851,11 +959,6 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
851
959
  }
852
960
 
853
961
  let objects = getObjects(config.config.objects)(config.uuid)
854
- let testConfigName = config.name
855
- if (testConfig.testModuleName) {
856
- objects = getObjects(config.config.objects)(config.getConfigs()[testConfig.testModuleName].uuid)
857
- testConfigName = testConfig.testModuleName
858
- }
859
962
  try {
860
963
  const result = await _process(config, test, { errorHandler, isTest: true })
861
964
  result.query = test
@@ -895,7 +998,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
895
998
  }
896
999
  return expected.objects.namespaced[expected.objects.nameToUUID[name]] || {}
897
1000
  }
898
- const expected_checked = sortJson(pickObjects(testConfig, expectedGetObjects(testConfigName)), { depth: 25 })
1001
+ const expected_checked = sortJson(pickObjects(config, testConfig, expectedGetObjects), { depth: 25 })
899
1002
  const actualGetObjects = (name) => {
900
1003
  if (!name) {
901
1004
  name = config.name
@@ -903,7 +1006,7 @@ const runTest = async (config, expected, { args, verbose, testConfig, debug }) =
903
1006
  const km = config.configs.find((km) => km.name == name)
904
1007
  return config.config.objects.namespaced[km.uuid] || {}
905
1008
  }
906
- const actual_checked = sortJson(pickObjects(testConfig, actualGetObjects(testConfigName)), { depth: 25 })
1009
+ const actual_checked = sortJson(pickObjects(config, testConfig, actualGetObjects), { depth: 25 })
907
1010
  const failed_checked = !matching(actual_objects, expected_objects)
908
1011
 
909
1012
  const failed_checks = !matching(actual_objects, expected_objects)
@@ -1155,6 +1258,24 @@ const defaultErrorHandler = async (error) => {
1155
1258
  throw error
1156
1259
  }
1157
1260
 
1261
+ const printContextualPrioritiesAmbiguities = (cpa) => {
1262
+ console.log('Contextual Priorities Ambiguities')
1263
+ for (const counter in cpa) {
1264
+ console.log(` Counter ${counter}`)
1265
+ for (const choices of cpa[counter]) {
1266
+ console.log(' [')
1267
+ for (const choice of choices) {
1268
+ console.log(' [')
1269
+ for (const element of choice) {
1270
+ console.log(` ${JSON.stringify(element)},`)
1271
+ }
1272
+ console.log(' ],')
1273
+ }
1274
+ console.log(' ],')
1275
+ }
1276
+ }
1277
+ }
1278
+
1158
1279
  const defaultInnerProcess = (config, errorHandler, responses) => {
1159
1280
  if (responses.errors) {
1160
1281
  console.log('Errors')
@@ -1173,6 +1294,9 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1173
1294
  console.log('Logs')
1174
1295
  responses.logs.forEach((log) => console.log(` ${log}`))
1175
1296
  }
1297
+ if (responses.contextual_priorities_ambiguities) {
1298
+ printContextualPrioritiesAmbiguities(responses.contextual_priorities_ambiguities)
1299
+ }
1176
1300
  console.log(responses.trace)
1177
1301
 
1178
1302
  if (global.beforeObjects) {
@@ -1211,8 +1335,15 @@ const defaultInnerProcess = (config, errorHandler, responses) => {
1211
1335
  console.log(` inputs: ${JSON.stringify(inputs)} output: ${JSON.stringify(output)} reason: ${reason}`)
1212
1336
  }
1213
1337
  }
1214
- const objects = config.get('objects').namespaced[config.uuid]
1215
- const picked = sortJson(pickObjects(config.testConfig, objects), { depth: 25 })
1338
+ // const objects = config.get('objects').namespaced[config.uuid]
1339
+ const actualGetObjects = (name) => {
1340
+ if (!name) {
1341
+ name = config.name
1342
+ }
1343
+ const km = config.configs.find((km) => km.name == name)
1344
+ return config.config.objects.namespaced[km.uuid] || {}
1345
+ }
1346
+ const picked = sortJson(pickObjects(config, config.testConfig, actualGetObjects), { depth: 25 })
1216
1347
  if (!_.isEmpty(picked)) {
1217
1348
  console.log('--- Object showing only the checked values ---')
1218
1349
  console.log(JSON.stringify(picked, null, 2))
@@ -2024,6 +2155,13 @@ const knowledgeModuleImpl = async ({
2024
2155
  })
2025
2156
  f()
2026
2157
  } else if (args.query) {
2158
+ let useTestConfig = testConfig
2159
+ if (args.testModuleName) {
2160
+ config.testConfig.testModuleName = args.testModuleName
2161
+ config.testConfig.checks = config.getConfigs()[args.testModuleName].getTestConfig().checks
2162
+ // useTestConfig = config.getConfigs()[args.testModuleName].getTestConfig()
2163
+ // useTestConfig.testModuleName = args.testModuleName
2164
+ }
2027
2165
  const objects = getObjects(config.config.objects)(config.uuid)
2028
2166
  // for the compare
2029
2167
  if (args.objectDiff) {
@@ -2118,26 +2256,6 @@ const ensureTestFile = (module, name, type) => {
2118
2256
  }
2119
2257
  }
2120
2258
 
2121
- function where (goUp = 2) {
2122
- const e = new Error()
2123
- const regexForm1 = /\((.*):(\d+):(\d+)\)$/
2124
- const regexForm2 = /at (.*):(\d+):(\d+)$/
2125
- const lines = e.stack.split('\n')
2126
- let line
2127
- for (line of lines.slice(1)) {
2128
- if (!(line.includes('config.js:') || line.includes('client.js:'))) {
2129
- break
2130
- }
2131
- }
2132
- // const line = e.stack.split("\n")[goUp];
2133
- const match = regexForm1.exec(line) || regexForm2.exec(line)
2134
- if (match) {
2135
- return `${match[1]}:${match[2]}`
2136
- } else {
2137
- return 'running in browser'
2138
- }
2139
- }
2140
-
2141
2259
  function w (func) {
2142
2260
  func.where = where(3)
2143
2261
  return func
package/package.json CHANGED
@@ -65,6 +65,6 @@
65
65
  "json-stable-stringify": "^1.0.1",
66
66
  "node-fetch": "^2.6.1"
67
67
  },
68
- "version": "7.12.4",
68
+ "version": "7.12.5",
69
69
  "license": "UNLICENSED"
70
70
  }
package/src/config.js CHANGED
@@ -199,7 +199,7 @@ const priority_valid = (cp) => {
199
199
  )
200
200
  }
201
201
 
202
- const handleBridgeProps = (config, bridge, addFirst) => {
202
+ const handleBridgeProps = (config, bridge, { addFirst, uuid } = {}) => {
203
203
  ecatch(`While processing the bridge for ${bridge.id}#${bridge.level}`,
204
204
  () => {
205
205
  if (!bridge.bridge) {
@@ -260,7 +260,8 @@ const handleBridgeProps = (config, bridge, addFirst) => {
260
260
  }
261
261
  */
262
262
 
263
- const addUUID = (obj) => { return { ...obj, uuid: config.uuid } }
263
+ const addUUID = (obj) => { return { ...obj, uuid: uuid || config.uuid } }
264
+
264
265
  if (bridge.generators) {
265
266
  const generators = [...bridge.generators]
266
267
  generators.reverse()
@@ -343,14 +344,14 @@ const handleBridgeProps = (config, bridge, addFirst) => {
343
344
  )
344
345
  }
345
346
 
346
- const handleCalculatedProps = (baseConfig, moreConfig, addFirst) => {
347
+ const handleCalculatedProps = (baseConfig, moreConfig, { addFirst, uuid } = {}) => {
347
348
  if (moreConfig.bridges) {
348
349
  moreConfig.bridges = moreConfig.bridges.map((bridge) => {
349
350
  bridge = { ...bridge }
350
351
  const valid = ['after', 'before', 'bridge', 'development', 'evaluator', 'generatorp', 'generatorr', 'generatorpr', 'generators', 'id', 'convolution', 'inverted', 'isA', 'children', 'parents',
351
352
  'level', 'optional', 'selector', 'semantic', 'words', /Bridge$/, 'localHierarchy', 'levelSpecificHierarchy', 'where', 'uuid']
352
353
  helpers.validProps(valid, bridge, 'bridge')
353
- handleBridgeProps(baseConfig, bridge, addFirst)
354
+ handleBridgeProps(baseConfig, bridge, { addFirst, uuid })
354
355
  return bridge
355
356
  })
356
357
  }
@@ -466,7 +467,7 @@ const normalizeConfig = (config) => {
466
467
  if (config.semantics) {
467
468
  for (const semantic of config.semantics) {
468
469
  if (semantic.oneShot) {
469
- semantic.id = uuid()
470
+ semantic.id = semantic.id || helpers.stableId('semantic')
470
471
  }
471
472
  }
472
473
  }
@@ -901,6 +902,10 @@ class Config {
901
902
  }
902
903
  }
903
904
 
905
+ get semantics() {
906
+ return [...this.config.semantics]
907
+ }
908
+
904
909
  getSemantics (logs = []) {
905
910
  return new Semantics(this.config.semantics, logs, { km: this.name })
906
911
  }
@@ -1314,7 +1319,7 @@ class Config {
1314
1319
  if (global.transitoryMode) {
1315
1320
  def.transitoryMode = true
1316
1321
  }
1317
- handleBridgeProps(this, def)
1322
+ handleBridgeProps(this, def, { uuid })
1318
1323
  bridges.push(def)
1319
1324
  this.checkBridges()
1320
1325
  this._delta.json.bridges.push({ action: 'add', bridge: def })
@@ -1365,9 +1370,28 @@ class Config {
1365
1370
  }
1366
1371
 
1367
1372
  removeSemantic (deleteSemantic) {
1368
- const index = this.config.semantics.findIndex((semantic) => semantic.id === deleteSemantic.id)
1369
- if (index >= 0) {
1370
- this.config.semantics.splice(index, 1)
1373
+ const id = deleteSemantic.id || deleteSemantic
1374
+ const todo = [id]
1375
+ const seen = new Set()
1376
+
1377
+ while (todo.length > 0) {
1378
+ const id = todo.pop()
1379
+ if (seen.has(id)) {
1380
+ continue
1381
+ }
1382
+ seen.add(id)
1383
+ const index = this.config.semantics.findIndex((semantic) => semantic.id === id)
1384
+ if (index == -1) {
1385
+ continue
1386
+ }
1387
+ for (const tied_id of this.config.semantics[index].tied_ids || []) {
1388
+ if (!seen.has(tied_id)) {
1389
+ todo.push(tied_id)
1390
+ }
1391
+ }
1392
+ if (index >= 0) {
1393
+ this.config.semantics.splice(index, 1)
1394
+ }
1371
1395
  }
1372
1396
  }
1373
1397
 
@@ -1555,7 +1579,7 @@ class Config {
1555
1579
  config._api.multiApi[api].args = args
1556
1580
  }
1557
1581
  } else {
1558
- config._api.args = args
1582
+ config._api.args = { ...args, ...args.getUUIDScoped(config.uuid) }
1559
1583
  }
1560
1584
  }
1561
1585
 
@@ -2842,7 +2866,7 @@ class Config {
2842
2866
  debugConfigProps(more)
2843
2867
 
2844
2868
  if (hcps) {
2845
- handleCalculatedProps(this, more, addFirst)
2869
+ handleCalculatedProps(this, more, { addFirst, uuid })
2846
2870
  applyUUID(more, uuid || this._uuid)
2847
2871
  }
2848
2872
  for (const key of Object.keys(more)) {
@@ -3078,5 +3102,5 @@ module.exports = {
3078
3102
  Config,
3079
3103
  config_toServer,
3080
3104
  operatorKey_valid,
3081
- handleBridgeProps
3105
+ handleBridgeProps,
3082
3106
  }
package/src/helpers.js CHANGED
@@ -374,7 +374,15 @@ const subPriority = (sub, sup) => {
374
374
  return true
375
375
  }
376
376
 
377
+ const stableIds = {}
378
+ const stableId = (tag) => {
379
+ const id = stableIds[tag] || 1
380
+ stableIds[tag] = id + 1
381
+ return id
382
+ }
383
+
377
384
  module.exports = {
385
+ stableId,
378
386
  ecatch,
379
387
  functionsToStrings,
380
388
  updateQueries,
package/src/semantics.js CHANGED
@@ -6,7 +6,7 @@ class Semantic {
6
6
  // constructor ({match, apply, uuid, index, km, notes}) {
7
7
  constructor (semantic) {
8
8
  semantic = normalizeSemantic(semantic)
9
- const { match, apply, uuid, index, km, notes, priority, debug, where, applyWrapped, property, oneShot, id } = semantic
9
+ const { match, apply, uuid, index, km, notes, priority, debug, where, source, applyWrapped, property, oneShot, id, tied_ids, isQuestion } = semantic
10
10
  this.matcher = match
11
11
  this._apply = apply
12
12
  this._applyWrapped = applyWrapped
@@ -18,8 +18,11 @@ class Semantic {
18
18
  this.notes = notes
19
19
  this.callId = debug
20
20
  this.where = where
21
+ this.source = source
21
22
  this.oneShot = oneShot
23
+ this.isQuestion = isQuestion
22
24
  this.id = id
25
+ this.tied_ids = tied_ids || []
23
26
  }
24
27
 
25
28
  toLabel () {
@@ -184,11 +187,16 @@ class Semantics {
184
187
  let applied = false
185
188
  const stack = args.calls.push()
186
189
  let counter = 0
190
+ let seenQuestion = false
187
191
  for (const isemantic in this.semantics) {
188
192
  const semantic = this.semantics[isemantic]
189
193
  if (!semantic) {
190
194
  debugger
191
195
  }
196
+ // only one question at a time
197
+ if (semantic.isQuestion && seenQuestion) {
198
+ continue
199
+ }
192
200
  if (semantic.matches(args, context, options)) {
193
201
  if (!this.calls[counter]) {
194
202
  this.calls[counter] = 0
@@ -198,6 +206,7 @@ class Semantics {
198
206
  try {
199
207
  contextPrime = semantic.apply(args, context, s, log, options)
200
208
  if (!contextPrime.controlKeepMotivation && semantic.oneShot) {
209
+ // semantic.tied_ids.forEach((tied_id) => args.config.removeSemantic(tied_id))
201
210
  args.config.removeSemantic(semantic)
202
211
  }
203
212
  } catch (e) {
@@ -274,6 +283,7 @@ class Semantics {
274
283
  this.logs.push(lines.toString())
275
284
  }
276
285
  applied = true
286
+ seenQuestion = seenQuestion || semantic.isQuestion
277
287
  if (contextPrime.cascade) {
278
288
  contextPrime.cascade = false
279
289
  } else {