theprogrammablemind 7.1.4-beta.3

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/src/helpers.js ADDED
@@ -0,0 +1,216 @@
1
+ const deepEqual = require('deep-equal')
2
+ const stringify = require('json-stable-stringify')
3
+
4
+ // properties - the properties that correspond to types
5
+ // types - the expected types of the properties
6
+ // returns list of properties found matching order of types
7
+
8
+ const args = (context, hierarchy) => ({ types, properties }) => {
9
+ const orderedByType = []
10
+
11
+ for (const type of types) {
12
+ let found = false
13
+ for (let index = 0; index < properties.length; ++index) {
14
+ const value = context[properties[index]]
15
+ if (!value) {
16
+ return false
17
+ }
18
+ if (hierarchy.isA(value.marker, type)) {
19
+ orderedByType.push(properties[index])
20
+ properties.splice(index, 1)
21
+ found = true
22
+ break
23
+ }
24
+ }
25
+ if (!found) {
26
+ return
27
+ }
28
+ }
29
+
30
+ if (orderedByType.length === 0) {
31
+ return
32
+ }
33
+
34
+ return orderedByType
35
+ }
36
+
37
+ const appendNoDups = (l1, l2) => {
38
+ for (const x of l2) {
39
+ if (l1.includes(x)) {
40
+ continue
41
+ }
42
+ l1.push(x)
43
+ }
44
+ }
45
+
46
+ const safeEquals = (v1, v2) => {
47
+ if (!deepEqual(stringify(v1), stringify(v2))) {
48
+ return false
49
+ }
50
+ return true
51
+ }
52
+
53
+ /*
54
+ const semanticsGenerate = (from, known) => {
55
+ const marker = from.marker
56
+
57
+ const sources = []
58
+ for (let key in Object.keys(from)) {
59
+ if (from[key].marker) {
60
+ sources.push(from[key])
61
+ }
62
+ }
63
+ const mappings = []
64
+ for (let key in Object.keys(to)) {
65
+ const source
66
+ if (to[keys].marker ==
67
+ }
68
+
69
+ return {
70
+ match: ({context}) => marker == marker,
71
+ apply: ({context}) => {
72
+ },
73
+ }
74
+ }
75
+ */
76
+
77
+ const hashIndexesGet = (hash, indexes) => {
78
+ let value = hash
79
+ for (const i of indexes) {
80
+ value = value[i]
81
+ }
82
+ return value
83
+ }
84
+
85
+ const hashIndexesSet = (hash, indexes, value) => {
86
+ let currentValue = hash
87
+ for (const i of indexes.slice(0, -1)) {
88
+ if (!currentValue[i]) {
89
+ currentValue[i] = {}
90
+ }
91
+ currentValue = currentValue[i]
92
+ }
93
+ currentValue[indexes[indexes.length - 1]] = value
94
+ }
95
+
96
+ const translationMapping = (from, to) => {
97
+ const mappings = []
98
+ for (const fkey of Object.keys(from)) {
99
+ if (from[fkey].value) {
100
+ let found = false
101
+ const todo = Object.keys(to).map((key) => [key])
102
+ while (!found) {
103
+ const tkey = todo.shift()
104
+ const tvalue = hashIndexesGet(to, tkey)
105
+ const fvalue = hashIndexesGet(from, [fkey])
106
+ if (fvalue.value === tvalue.value) {
107
+ mappings.push({ from: [fkey], to: tkey })
108
+ found = true
109
+ break
110
+ } else {
111
+ if (typeof tvalue !== 'string' && typeof tvalue !== 'number') {
112
+ for (const key of Object.keys(tvalue)) {
113
+ todo.push(tkey.concat(key))
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ return mappings
121
+ }
122
+
123
+ const normalizeGenerator = (generator) => {
124
+ if (Array.isArray(generator)) {
125
+ if (generator.length === 2) {
126
+ return { match: generator[0], apply: generator[1] }
127
+ } else {
128
+ return { match: generator[0], apply: generator[1], uuid: generator[2] }
129
+ }
130
+ }
131
+ return generator
132
+ }
133
+
134
+ const normalizeSemantic = (semantic) => {
135
+ if (Array.isArray(semantic)) {
136
+ if (semantic.length === 2) {
137
+ return { match: semantic[0], apply: semantic[1] }
138
+ } else {
139
+ return { match: semantic[0], apply: semantic[1], uuid: semantic[2] }
140
+ }
141
+ }
142
+ return semantic
143
+ }
144
+
145
+ const isArray = (value) => {
146
+ return (!!value) && (value.constructor === Array)
147
+ }
148
+
149
+ const isObject = (value) => {
150
+ return (!!value) && (value.constructor === Object)
151
+ }
152
+
153
+ const isCompound = (value) => {
154
+ return isArray(value) || isObject(value)
155
+ }
156
+
157
+ nextCallId = 0
158
+ nextContextId = 0
159
+
160
+ class InitCalls {
161
+
162
+ constructor() {
163
+ this.nextCallId = 0
164
+ this.nextContextId = 0
165
+ this.stack = []
166
+ }
167
+
168
+ start() {
169
+ return this.nextCallId
170
+ }
171
+
172
+ next() {
173
+ // this.nextContextId += 1
174
+ this.nextContextId += 1
175
+ }
176
+
177
+ push() {
178
+ this.nextCallId += 1
179
+ // this.nextCallId += 1
180
+ // this.stack.push(this.nextCallId)
181
+ this.stack.push(this.nextCallId)
182
+ const calls = this.stack.map( (call) => `call${call}` )
183
+ // return `Context#${this.nextContextId}: ${calls}`
184
+ return `Context#${nextContextId}: ${calls}`
185
+ }
186
+
187
+ current() {
188
+ return `call${this.stack[this.stack.length-1]}`
189
+ }
190
+
191
+ touch(context) {
192
+ if (!context.touchedBy) {
193
+ context.touchedBy = []
194
+ }
195
+ if (!context.touchedBy.includes( this.current() )) {
196
+ context.touchedBy.push( this.current() )
197
+ }
198
+ }
199
+
200
+ pop() {
201
+ this.stack.pop()
202
+ }
203
+ }
204
+
205
+ const hashCode = (str) => {
206
+ var hash = 0, i, ch;
207
+ if (str.length === 0) return hash;
208
+ for (i = 0; i < str.length; i++) {
209
+ ch = str.charCodeAt(i);
210
+ hash = ((hash << 5) - hash) + ch;
211
+ hash |= 0; // Convert to 32bit integer
212
+ }
213
+ return hash;
214
+ };
215
+
216
+ module.exports = { args, safeEquals, appendNoDups, hashIndexesGet, hashIndexesSet, translationMapping, normalizeGenerator, normalizeSemantic, isArray, isObject, isCompound, InitCalls, hashCode }
@@ -0,0 +1,293 @@
1
+ const { args: contextArgs, normalizeGenerator, normalizeSemantic } = require('./helpers')
2
+ const Lines = require('../lines')
3
+ const sortJson = require('sort-json')
4
+ const helpers = require('./helpers')
5
+
6
+ class Semantic {
7
+ // constructor ({match, apply, uuid, index, km, notes}) {
8
+ constructor (semantic) {
9
+ semantic = normalizeSemantic(semantic)
10
+ const { match, apply, uuid, index, km, notes, priority, debug, where } = semantic
11
+ this.matcher = match
12
+ this._apply = apply
13
+ this.uuid = uuid
14
+ this.index = index
15
+ this.km = km
16
+ this.priority = priority || 0
17
+ this.notes = notes
18
+ this.callId = debug
19
+ this.where = where
20
+ }
21
+
22
+ toLabel () {
23
+ const where = (this.where) ? `where: "${this.where}"` : ''
24
+ if (!this.km) {
25
+ return where;
26
+ }
27
+ return `KM '${this.km}' ordinal: ${this.index} ${where}`
28
+ }
29
+
30
+ toString () {
31
+ return `Semantic(${this.matcher}, ${this._apply})`
32
+ }
33
+
34
+ getAPI (config) {
35
+ if (config && config.getAPI) {
36
+ return config.getAPI(this.uuid)
37
+ }
38
+ }
39
+
40
+ getAPIs (config) {
41
+ if (config && config._api && config._api.multiApi) {
42
+ return config._api.apis
43
+ }
44
+ }
45
+
46
+ matches (baseArgs, context, options = {}) {
47
+ const hierarchy = baseArgs.hierarchy
48
+ const config = baseArgs.config
49
+ const objects = baseArgs.getObjects(this.uuid)
50
+ // return this.matcher(Object.assign({}, argsBase, {args: contextArgs(context, hierarchy), objects: objects, global: objects, context: context, hierarchy: hierarchy, api: this.getAPI(config)})
51
+ const callId = baseArgs.calls.current()
52
+ const moreArgs = {
53
+ uuid: this.uuid,
54
+ args: contextArgs(context, hierarchy),
55
+ objects: objects,
56
+ global: objects,
57
+ context: context,
58
+ // hierarchy: hierarchy,
59
+ callId,
60
+ api: this.getAPI(config),
61
+ apis: this.getAPIs(config)
62
+ }
63
+ const args = Object.assign({}, baseArgs, moreArgs)
64
+
65
+ const matches = this.matcher(args)
66
+ if (matches && (options.debug || {}).match
67
+ ||
68
+ callId == this.callId) {
69
+ debugger; // next line is the matcher
70
+ this.matcher(args)
71
+ }
72
+ return matches
73
+ }
74
+
75
+ apply (baseArgs, context, s, log, options = {}) {
76
+ const { hierarchy, config, response } = baseArgs
77
+ const objects = baseArgs.getObjects(this.uuid)
78
+ if (!log) {
79
+ console.trace()
80
+ throw 'log is a required argument'
81
+ }
82
+ const contextPrime = Object.assign({}, context)
83
+ let n = (id) => id
84
+ if (config && 'nsToString' in config) {
85
+ n = (id) => config.nsToString(id)
86
+ }
87
+ const callId = baseArgs.calls.current()
88
+ const moreArgs = {
89
+ uuid: this.uuid,
90
+ callId,
91
+ args: contextArgs(context, hierarchy),
92
+ objects,
93
+ log,
94
+ global: objects,
95
+ n,
96
+ context: contextPrime,
97
+ uuid: this.uuid,
98
+ // config,
99
+ response,
100
+ api: this.getAPI(config),
101
+ apis: this.getAPIs(config)
102
+ }
103
+ const args = Object.assign({}, baseArgs, moreArgs)
104
+ if ((options.debug || {}).apply
105
+ ||
106
+ callId == this.callId) {
107
+ debugger;
108
+ }
109
+ this._apply(args)
110
+ return contextPrime
111
+ }
112
+ }
113
+
114
+ class Semantics {
115
+ constructor (semantics, logs = []) {
116
+ semantics = semantics.map((semantic) => {
117
+ if (semantic instanceof Semantic) {
118
+ return semantic
119
+ } else {
120
+ return new Semantic(semantic)
121
+ }
122
+ })
123
+
124
+ const priorityToSemantics = {}
125
+ const add = (priority, value) => {
126
+ if (!priorityToSemantics[priority]) {
127
+ priorityToSemantics[priority] = []
128
+ }
129
+ priorityToSemantics[priority].push(value)
130
+ }
131
+ for (const semantic of semantics) {
132
+ const priority = semantic.priority
133
+ add(priority, semantic)
134
+ }
135
+ this.semantics = []
136
+ for (const key of Object.keys(priorityToSemantics).sort()) {
137
+ this.semantics = this.semantics.concat(priorityToSemantics[key])
138
+ }
139
+
140
+ this.logs = logs
141
+ // map ordinal to number of calls
142
+ this.calls = {}
143
+ };
144
+
145
+ getMostCalled() {
146
+ let maxOrdinal = 0
147
+ let maxCounter = 0
148
+ for (let ordinal in this.calls) {
149
+ const counter = this.calls[ordinal]
150
+ if (counter > maxCounter) {
151
+ maxOrdinal = ordinal
152
+ maxCounter = counter
153
+ }
154
+ }
155
+
156
+ return this.semantics[maxOrdinal]
157
+ }
158
+
159
+ applyToContext (args, context, options) {
160
+ // let context_prime = {}
161
+ if (!(context instanceof Array || context instanceof Object)) {
162
+ return context
163
+ }
164
+
165
+ const config = args.config
166
+ let contextPrime = Object.assign({}, context)
167
+ const s = (context, options) => this.apply(args, context, options)
168
+ let applied = false
169
+ const stack = args.calls.push()
170
+ let counter = 0;
171
+ for (const isemantic in this.semantics) {
172
+ const semantic = this.semantics[isemantic]
173
+ if (semantic.matches(args, context, options)) {
174
+ if (!this.calls[counter]) {
175
+ this.calls[counter] = 0;
176
+ }
177
+ this.calls[counter] += 1;
178
+ const log = (message) => { this.logs.push(message) }
179
+ try {
180
+ contextPrime = semantic.apply(args, context, s, log, options)
181
+ } catch( e ) {
182
+ contextPrime = null
183
+ let errorMessage
184
+ if (e.stack && e.message) {
185
+ errorMessage = `Error applying semantics '${semantic.notes}'. Error is ${e.toString()} stack is ${e.stack}. Semantic is ${semantic.toString()}`
186
+ } else if (e.error) {
187
+ errorMessage = `Error applying semantics '${semantic.notes}'. Error is ${e.error.join()}. Semantic is ${semantic.toString()}`
188
+ } else {
189
+ errorMessage = e.toString();
190
+ }
191
+
192
+ const widths = [10, 10, 90]
193
+ const lines = new Lines(widths)
194
+ lines.setElement(0, 0, 'Semantic')
195
+ const source = `${semantic.km}/#${semantic.index}`
196
+ lines.setElement(0, 2, `ERROR while applying (${source}) ${semantic.toLabel()}`)
197
+ lines.newRow()
198
+ lines.setElement(0, 2, semantic.toString())
199
+ lines.newRow()
200
+ lines.setElement(0, 1, 'TO')
201
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(sortJson(context, { depth: 25 })))})`)
202
+ lines.setElement(1, 2, JSON.stringify(sortJson(context, { depth: 25 }), null, 2))
203
+ lines.newRow()
204
+ lines.setElement(0, 1, 'STACK')
205
+ lines.setElement(0, 2, stack)
206
+ lines.newRow()
207
+ lines.setElement(0, 1, 'DEBUG')
208
+ lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
209
+ lines.newRow()
210
+ lines.setElement(0, 1, 'ERROR')
211
+ lines.setElement(0, 2, errorMessage)
212
+ this.logs.push(lines.toString())
213
+ const message = `ERROR while applying (${source}) ${semantic.toLabel()}\n to\n ${JSON.stringify(context, null, 2)}.\n${errorMessage}'`
214
+ // this.logs.push(message)
215
+ // return [message]
216
+ args.calls.pop()
217
+ throw { error: [message], logs: this.logs }
218
+ }
219
+ args.calls.touch(contextPrime)
220
+ // this.logs.push(`Semantics: applied ${semantic.toString()}\n to\n ${JSON.stringify(context)}\n the result was ${JSON.stringify(contextPrime)}\n`)
221
+ if (((config || {}).config || {}).debug) {
222
+ const widths = [10, 10, 90]
223
+ const lines = new Lines(widths)
224
+ lines.setElement(0, 0, 'Semantic')
225
+ if (semantic.index > -1 && semantic.km) {
226
+ // lines.setElement(0, 2, `KM '${semantic.km}' ordinal: ${semantic.index} ${ semantic.notes ? semantic.nodes : '' }`)
227
+ lines.setElement(0, 2, semantic.toLabel())
228
+ }
229
+ lines.newRow()
230
+ lines.setElement(0, 1, 'APPLIED')
231
+ lines.setElement(0, 2, semantic.toLabel())
232
+ lines.newRow()
233
+ lines.setElement(0, 2, semantic.toString())
234
+ lines.newRow()
235
+ lines.setElement(0, 1, 'TO')
236
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(sortJson(context, { depth: 25 })))})`)
237
+ lines.setElement(1, 2, JSON.stringify(sortJson(context, { depth: 25 }), null, 2))
238
+ lines.newRow()
239
+ lines.setElement(0, 1, 'STACK')
240
+ lines.setElement(0, 2, stack)
241
+ lines.newRow()
242
+ lines.setElement(0, 1, 'DEBUG')
243
+ lines.setElement(0, 2, `To debug this use args.callId == '${args.calls.current()}'`)
244
+ lines.newRow()
245
+ lines.setElement(0, 1, 'RESULT')
246
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(sortJson(contextPrime, { depth: 25 })))})`)
247
+ lines.setElement(1, 2, JSON.stringify(contextPrime, null, 2))
248
+ this.logs.push(lines.toString())
249
+ }
250
+ applied = true
251
+ if (contextPrime.cascade) {
252
+ contextPrime.cascade = false
253
+ } else {
254
+ break
255
+ }
256
+ }
257
+ counter += 1
258
+ }
259
+ args.calls.pop()
260
+ if (!applied && ((config || {}).config || {}).debug) {
261
+ const widths = [10, 10, 90]
262
+ const lines = new Lines(widths)
263
+ lines.setElement(0, 0, 'Semantic')
264
+ lines.setElement(0, 2, 'No semantic applied')
265
+ lines.newRow()
266
+ lines.setElement(0, 1, 'TO')
267
+ lines.setElement(0, 2, `(HASHCODE ${helpers.hashCode(JSON.stringify(sortJson(context, { depth: 25 })))})`)
268
+ lines.setElement(1, 2, JSON.stringify(sortJson(context, { depth: 25 }), null, 2))
269
+ this.logs.push(lines.toString())
270
+ }
271
+ return contextPrime
272
+ }
273
+
274
+ applyToContexts (args, contexts, options) {
275
+ const contextsPrime = []
276
+ contexts.forEach((context) => {
277
+ contextsPrime.push(this.applyToContext(args, context, options))
278
+ })
279
+ return contextsPrime
280
+ }
281
+
282
+ apply (args, context, options) {
283
+ if (Array.isArray(context)) {
284
+ return this.applyToContexts(args, context, options)
285
+ } else if (context instanceof Object) {
286
+ return this.applyToContext(args, context, options)
287
+ } else {
288
+ return context
289
+ }
290
+ }
291
+ }
292
+
293
+ module.exports = { Semantic, Semantics, normalizeGenerator }
@@ -0,0 +1,128 @@
1
+ const _ = require('lodash')
2
+ const deepEqual = require('deep-equal')
3
+
4
+ const groupBy = (property, list) => {
5
+ const groups = {}
6
+ for (const element of list) {
7
+ if (!groups[element[property]]) {
8
+ groups[element[property]] = []
9
+ }
10
+ groups[element[property]].push(element)
11
+ }
12
+ return groups
13
+ }
14
+
15
+ const toList = (value) => {
16
+ if (value.marker === 'list') {
17
+ return value
18
+ } else {
19
+ return {
20
+ marker: 'list',
21
+ types: Array.from(new Set((value.types || []).concat(['list', value.marker]))),
22
+ value: [value]
23
+ }
24
+ }
25
+ }
26
+
27
+ const concatLists = (l1, l2) => {
28
+ l1 = toList(l1)
29
+ l2 = toList(l2)
30
+ return {
31
+ marker: 'list',
32
+ types: Array.from(new Set(l1.types.concat(l2.types))),
33
+ value: Array.from(new Set(l1.value.concat(l2.value)))
34
+ }
35
+ }
36
+
37
+ const findPropertyWithManyValues = (contexts, properties) => {
38
+ for (const property of properties) {
39
+ if (new Set(contexts.map( (context) => context[property] )).size == 1) {
40
+ return property
41
+ }
42
+ }
43
+ }
44
+
45
+ /*
46
+ class JSONSet {
47
+ constructor(list = []) {
48
+ this.members = []
49
+ for (const element of list) {
50
+ this.add(element)
51
+ }
52
+ }
53
+
54
+ toList(element) {
55
+ return this.list
56
+ }
57
+
58
+ add(element) {
59
+ if (!this.has(element)) {
60
+ this.list.push(element)
61
+ }
62
+ }
63
+
64
+ has(searchFor) {
65
+ for (const element of this.list) {
66
+ if (!deepEqual(searchFor, element) {
67
+ return true
68
+ }
69
+ }
70
+ return false
71
+ }
72
+ }
73
+ */
74
+
75
+ // x want y and z OR A
76
+ // x and y want z B
77
+ // x wants and likes y C
78
+
79
+ const canonicalDefault = (value) => {
80
+ if (!value?.marker) {
81
+ return value;
82
+ }
83
+ return { marker: value.marker, value: value.value, word: value.wordi, types: value.types }
84
+ }
85
+
86
+ // if properties null then check the contexts for unflatten property
87
+ const unflatten = (contexts, properties, canonical = canonicalDefault) => {
88
+ const grouped = {}
89
+ for (let context of contexts) {
90
+ if (!grouped[context.marker]) {
91
+ grouped[context.marker] = []
92
+ }
93
+ grouped[context.marker].push(context)
94
+ }
95
+ let results = []
96
+ for (let key in grouped) {
97
+ results = results.concat(unflattenHelper(grouped[key], properties || grouped[key][0].unflatten, canonical))
98
+ }
99
+ return results
100
+ }
101
+
102
+ // properties -> order of preference for grouping values, for example B,A,c
103
+ const unflattenHelper = (contexts, properties, canonical) => {
104
+ if (contexts.length < 2) {
105
+ return contexts
106
+ }
107
+ if (!properties) {
108
+ return contexts
109
+ }
110
+ const groupedByMarker = groupBy('marker', contexts)
111
+ const unflats = []
112
+ for (const key in groupedByMarker) {
113
+ const grouping = groupedByMarker[key]
114
+ const groupingProp = findPropertyWithManyValues(contexts, properties)
115
+ const first = _.cloneDeep(grouping[0])
116
+ for (const next of grouping.slice(1)) {
117
+ for (const prop in next) {
118
+ if (!deepEqual(canonical(next[prop]), canonical(first[prop]))) {
119
+ first[prop] = concatLists(first[prop], next[prop])
120
+ }
121
+ }
122
+ }
123
+ unflats.push(first)
124
+ }
125
+ return unflats
126
+ }
127
+
128
+ module.exports = { groupBy, unflatten }