@jsreport/jsreport-core 3.0.1 → 3.1.2-test.2

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.
Files changed (79) hide show
  1. package/LICENSE +166 -166
  2. package/README.md +298 -284
  3. package/index.js +29 -27
  4. package/lib/main/blobStorage/blobStorage.js +52 -47
  5. package/lib/main/blobStorage/inMemoryProvider.js +27 -27
  6. package/lib/main/blobStorage/mainActions.js +24 -24
  7. package/lib/main/createDefaultLoggerFormat.js +17 -17
  8. package/lib/main/defaults.js +14 -14
  9. package/lib/main/extensions/discover.js +20 -20
  10. package/lib/main/extensions/extensionsManager.js +264 -265
  11. package/lib/main/extensions/fileUtils.js +56 -55
  12. package/lib/main/extensions/findVersion.js +49 -53
  13. package/lib/main/extensions/locationCache.js +103 -97
  14. package/lib/main/extensions/sorter.js +10 -10
  15. package/lib/main/extensions/validateMinimalVersion.js +50 -50
  16. package/lib/main/folders/cascadeFolderRemove.js +25 -25
  17. package/lib/main/folders/getEntitiesInFolder.js +53 -53
  18. package/lib/main/folders/index.js +42 -42
  19. package/lib/main/folders/moveBetweenFolders.js +354 -354
  20. package/lib/main/folders/validateDuplicatedName.js +107 -107
  21. package/lib/main/folders/validateReservedName.js +53 -53
  22. package/lib/main/logger.js +244 -244
  23. package/lib/main/migration/resourcesToAssets.js +230 -210
  24. package/lib/main/migration/xlsxTemplatesToAssets.js +128 -118
  25. package/lib/main/monitoring.js +91 -91
  26. package/lib/main/optionsLoad.js +237 -237
  27. package/lib/main/optionsSchema.js +237 -237
  28. package/lib/main/reporter.js +579 -578
  29. package/lib/main/schemaValidator.js +252 -252
  30. package/lib/main/settings.js +154 -154
  31. package/lib/main/store/checkDuplicatedId.js +27 -27
  32. package/lib/main/store/collection.js +329 -329
  33. package/lib/main/store/documentStore.js +469 -469
  34. package/lib/main/store/mainActions.js +28 -28
  35. package/lib/main/store/memoryStoreProvider.js +99 -99
  36. package/lib/main/store/queue.js +48 -48
  37. package/lib/main/store/referenceUtils.js +251 -251
  38. package/lib/main/store/setupValidateId.js +43 -43
  39. package/lib/main/store/setupValidateShortid.js +71 -71
  40. package/lib/main/store/transaction.js +69 -69
  41. package/lib/main/store/typeUtils.js +180 -180
  42. package/lib/main/templates.js +34 -34
  43. package/lib/main/validateEntityName.js +62 -62
  44. package/lib/shared/createError.js +36 -36
  45. package/lib/shared/encryption.js +114 -114
  46. package/lib/shared/folders/index.js +11 -11
  47. package/lib/shared/folders/normalizeEntityPath.js +15 -15
  48. package/lib/shared/folders/resolveEntityFromPath.js +88 -88
  49. package/lib/shared/folders/resolveEntityPath.js +46 -46
  50. package/lib/shared/folders/resolveFolderFromPath.js +38 -38
  51. package/lib/shared/generateRequestId.js +4 -4
  52. package/lib/shared/listenerCollection.js +169 -0
  53. package/lib/shared/normalizeMetaFromLogs.js +30 -30
  54. package/lib/shared/reporter.js +123 -123
  55. package/lib/shared/request.js +64 -64
  56. package/lib/shared/tempFilesHandler.js +81 -81
  57. package/lib/shared/templates.js +82 -82
  58. package/lib/static/helpers.js +33 -33
  59. package/lib/worker/blobStorage.js +34 -34
  60. package/lib/worker/defaultProxyExtend.js +46 -46
  61. package/lib/worker/documentStore.js +49 -49
  62. package/lib/worker/extensionsManager.js +17 -17
  63. package/lib/worker/logger.js +48 -48
  64. package/lib/worker/render/diff.js +138 -138
  65. package/lib/worker/render/executeEngine.js +207 -200
  66. package/lib/worker/render/htmlRecipe.js +10 -10
  67. package/lib/worker/render/moduleHelper.js +43 -43
  68. package/lib/worker/render/noneEngine.js +12 -12
  69. package/lib/worker/render/profiler.js +158 -158
  70. package/lib/worker/render/render.js +205 -209
  71. package/lib/worker/render/resolveReferences.js +60 -60
  72. package/lib/worker/reporter.js +191 -187
  73. package/lib/worker/sandbox/runInSandbox.js +13 -4
  74. package/lib/worker/sandbox/safeSandbox.js +828 -822
  75. package/lib/worker/templates.js +78 -78
  76. package/lib/worker/workerHandler.js +54 -54
  77. package/package.json +92 -92
  78. package/test/blobStorage/common.js +21 -21
  79. package/test/store/common.js +1449 -1449
@@ -1,88 +1,88 @@
1
- const normalizeEntityPath = require('./normalizeEntityPath')
2
-
3
- module.exports = (reporter) => async (entityPathParam, targetEntitySet, options, req) => {
4
- if (req == null) {
5
- req = options
6
- options = {}
7
- }
8
-
9
- const entityPath = normalizeEntityPath(entityPathParam, options, req)
10
- const fragments = entityPath.split('/').filter(s => s)
11
- let currentEntity = null
12
- let currentEntitySet = null
13
- let currentFolder = null
14
-
15
- if (targetEntitySet) {
16
- const entitySet = reporter.documentStore.model.entitySets[targetEntitySet]
17
-
18
- if (!entitySet) {
19
- throw new Error(`Target entity set "${targetEntitySet}" does not exists`)
20
- }
21
-
22
- if (!entitySet.entityTypeDef.name) {
23
- throw new Error(`Entity set "${targetEntitySet}" does not have a name attribute`)
24
- }
25
- }
26
-
27
- if (fragments.length === 0) {
28
- return
29
- }
30
-
31
- const lastIndex = fragments.length - 1
32
-
33
- for (const [index, entityName] of fragments.entries()) {
34
- if (lastIndex === index) {
35
- if (!targetEntitySet) {
36
- for (const c of Object.keys(reporter.documentStore.collections)) {
37
- if (!reporter.documentStore.model.entitySets[c].entityTypeDef.name) {
38
- continue
39
- }
40
-
41
- const query = getSearchQuery(entityName, currentFolder)
42
- currentEntitySet = c
43
- currentEntity = await reporter.documentStore.collection(c).findOne(query, req)
44
-
45
- if (currentEntity) {
46
- break
47
- }
48
- }
49
- } else {
50
- const query = getSearchQuery(entityName, currentFolder)
51
- currentEntitySet = targetEntitySet
52
- currentEntity = await reporter.documentStore.collection(targetEntitySet).findOne(query, req)
53
- }
54
- } else {
55
- const query = getSearchQuery(entityName, currentFolder)
56
- const folder = await reporter.documentStore.collection('folders').findOne(query, req)
57
-
58
- if (!folder) {
59
- break
60
- }
61
-
62
- currentFolder = folder
63
- }
64
- }
65
-
66
- if (!currentEntity) {
67
- return
68
- }
69
-
70
- return {
71
- entitySet: currentEntitySet,
72
- entity: currentEntity
73
- }
74
- }
75
-
76
- function getSearchQuery (name, currentFolder) {
77
- const query = {
78
- name
79
- }
80
-
81
- if (currentFolder) {
82
- query.folder = { shortid: currentFolder.shortid }
83
- } else {
84
- query.folder = null
85
- }
86
-
87
- return query
88
- }
1
+ const normalizeEntityPath = require('./normalizeEntityPath')
2
+
3
+ module.exports = (reporter) => async (entityPathParam, targetEntitySet, options, req) => {
4
+ if (req == null) {
5
+ req = options
6
+ options = {}
7
+ }
8
+
9
+ const entityPath = normalizeEntityPath(entityPathParam, options, req)
10
+ const fragments = entityPath.split('/').filter(s => s)
11
+ let currentEntity = null
12
+ let currentEntitySet = null
13
+ let currentFolder = null
14
+
15
+ if (targetEntitySet) {
16
+ const entitySet = reporter.documentStore.model.entitySets[targetEntitySet]
17
+
18
+ if (!entitySet) {
19
+ throw new Error(`Target entity set "${targetEntitySet}" does not exists`)
20
+ }
21
+
22
+ if (!entitySet.entityTypeDef.name) {
23
+ throw new Error(`Entity set "${targetEntitySet}" does not have a name attribute`)
24
+ }
25
+ }
26
+
27
+ if (fragments.length === 0) {
28
+ return
29
+ }
30
+
31
+ const lastIndex = fragments.length - 1
32
+
33
+ for (const [index, entityName] of fragments.entries()) {
34
+ if (lastIndex === index) {
35
+ if (!targetEntitySet) {
36
+ for (const c of Object.keys(reporter.documentStore.collections)) {
37
+ if (!reporter.documentStore.model.entitySets[c].entityTypeDef.name) {
38
+ continue
39
+ }
40
+
41
+ const query = getSearchQuery(entityName, currentFolder)
42
+ currentEntitySet = c
43
+ currentEntity = await reporter.documentStore.collection(c).findOne(query, req)
44
+
45
+ if (currentEntity) {
46
+ break
47
+ }
48
+ }
49
+ } else {
50
+ const query = getSearchQuery(entityName, currentFolder)
51
+ currentEntitySet = targetEntitySet
52
+ currentEntity = await reporter.documentStore.collection(targetEntitySet).findOne(query, req)
53
+ }
54
+ } else {
55
+ const query = getSearchQuery(entityName, currentFolder)
56
+ const folder = await reporter.documentStore.collection('folders').findOne(query, req)
57
+
58
+ if (!folder) {
59
+ break
60
+ }
61
+
62
+ currentFolder = folder
63
+ }
64
+ }
65
+
66
+ if (!currentEntity) {
67
+ return
68
+ }
69
+
70
+ return {
71
+ entitySet: currentEntitySet,
72
+ entity: currentEntity
73
+ }
74
+ }
75
+
76
+ function getSearchQuery (name, currentFolder) {
77
+ const query = {
78
+ name
79
+ }
80
+
81
+ if (currentFolder) {
82
+ query.folder = { shortid: currentFolder.shortid }
83
+ } else {
84
+ query.folder = null
85
+ }
86
+
87
+ return query
88
+ }
@@ -1,46 +1,46 @@
1
-
2
- async function resolveEntityPath (reporter, entity, lookup, req) {
3
- const fullPath = []
4
- let currentEntity = entity
5
-
6
- while (currentEntity != null) {
7
- if (currentEntity.folder != null) {
8
- let folder
9
-
10
- if (lookup) {
11
- folder = await lookup(currentEntity.folder.shortid)
12
- } else {
13
- folder = await reporter.documentStore.collection('folders').findOne({
14
- shortid: currentEntity.folder.shortid
15
- }, req)
16
- }
17
-
18
- if (folder != null) {
19
- fullPath.unshift(folder.name)
20
- currentEntity = folder
21
- } else {
22
- throw new Error(`Folder with shortid "${currentEntity.folder.shortid}" does not exists`)
23
- }
24
- } else {
25
- currentEntity = null
26
- }
27
- }
28
-
29
- fullPath.push(entity.name)
30
-
31
- return `/${fullPath.join('/')}`
32
- }
33
-
34
- module.exports = (reporter) => async (entity, entitySet, req, lookup) => {
35
- const entitySetInfo = reporter.documentStore.model.entitySets[entitySet]
36
-
37
- if (!entitySetInfo) {
38
- throw new Error(`Unknown entitySet "${entitySet}"`)
39
- }
40
-
41
- if (entitySetInfo.entityTypeDef.name == null) {
42
- throw new Error(`Could not find name attribute of entity of type "${entitySet}"`)
43
- }
44
-
45
- return resolveEntityPath(reporter, entity, lookup, req)
46
- }
1
+
2
+ async function resolveEntityPath (reporter, entity, lookup, req) {
3
+ const fullPath = []
4
+ let currentEntity = entity
5
+
6
+ while (currentEntity != null) {
7
+ if (currentEntity.folder != null) {
8
+ let folder
9
+
10
+ if (lookup) {
11
+ folder = await lookup(currentEntity.folder.shortid)
12
+ } else {
13
+ folder = await reporter.documentStore.collection('folders').findOne({
14
+ shortid: currentEntity.folder.shortid
15
+ }, req)
16
+ }
17
+
18
+ if (folder != null) {
19
+ fullPath.unshift(folder.name)
20
+ currentEntity = folder
21
+ } else {
22
+ throw new Error(`Folder with shortid "${currentEntity.folder.shortid}" does not exists`)
23
+ }
24
+ } else {
25
+ currentEntity = null
26
+ }
27
+ }
28
+
29
+ fullPath.push(entity.name)
30
+
31
+ return `/${fullPath.join('/')}`
32
+ }
33
+
34
+ module.exports = (reporter) => async (entity, entitySet, req, lookup) => {
35
+ const entitySetInfo = reporter.documentStore.model.entitySets[entitySet]
36
+
37
+ if (!entitySetInfo) {
38
+ throw new Error(`Unknown entitySet "${entitySet}"`)
39
+ }
40
+
41
+ if (entitySetInfo.entityTypeDef.name == null) {
42
+ throw new Error(`Could not find name attribute of entity of type "${entitySet}"`)
43
+ }
44
+
45
+ return resolveEntityPath(reporter, entity, lookup, req)
46
+ }
@@ -1,38 +1,38 @@
1
- const normalizeEntityPath = require('./normalizeEntityPath')
2
-
3
- module.exports = (reporter) => async (entityPathParam, req) => {
4
- const entityPath = normalizeEntityPath(entityPathParam, {}, req)
5
- const fragments = entityPath.split('/').filter(s => s)
6
- let found = false
7
- let currentFolder = null
8
-
9
- for (const f of fragments) {
10
- if (found) {
11
- currentFolder = null
12
- break
13
- }
14
-
15
- const query = {
16
- name: f
17
- }
18
-
19
- if (currentFolder) {
20
- query.folder = { shortid: currentFolder.shortid }
21
- } else {
22
- query.folder = null
23
- }
24
-
25
- const folder = await reporter.documentStore.collection('folders').findOne(query, req)
26
-
27
- if (!folder) {
28
- found = true
29
- // we don't know from path /a/b if b is template or folder,
30
- // so if folder is not found, we assume it was other entity and continue
31
- continue
32
- }
33
-
34
- currentFolder = folder
35
- }
36
-
37
- return currentFolder
38
- }
1
+ const normalizeEntityPath = require('./normalizeEntityPath')
2
+
3
+ module.exports = (reporter) => async (entityPathParam, req) => {
4
+ const entityPath = normalizeEntityPath(entityPathParam, {}, req)
5
+ const fragments = entityPath.split('/').filter(s => s)
6
+ let found = false
7
+ let currentFolder = null
8
+
9
+ for (const f of fragments) {
10
+ if (found) {
11
+ currentFolder = null
12
+ break
13
+ }
14
+
15
+ const query = {
16
+ name: f
17
+ }
18
+
19
+ if (currentFolder) {
20
+ query.folder = { shortid: currentFolder.shortid }
21
+ } else {
22
+ query.folder = null
23
+ }
24
+
25
+ const folder = await reporter.documentStore.collection('folders').findOne(query, req)
26
+
27
+ if (!folder) {
28
+ found = true
29
+ // we don't know from path /a/b if b is template or folder,
30
+ // so if folder is not found, we assume it was other entity and continue
31
+ continue
32
+ }
33
+
34
+ currentFolder = folder
35
+ }
36
+
37
+ return currentFolder
38
+ }
@@ -1,4 +1,4 @@
1
- const { customAlphabet } = require('nanoid')
2
- const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 15)
3
-
4
- module.exports = () => nanoid()
1
+ const { customAlphabet } = require('nanoid')
2
+ const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 15)
3
+
4
+ module.exports = () => nanoid()
@@ -0,0 +1,169 @@
1
+
2
+ module.exports = function createListenerCollection (_name) {
3
+ const name = _name != null ? `${_name}` : 'Anonymous'
4
+ return new ListenerCollection(name)
5
+ }
6
+
7
+ class ListenerCollection {
8
+ constructor (name) {
9
+ this._name = name
10
+ this._listeners = []
11
+ this._pre = []
12
+ this._post = []
13
+ this._postFail = []
14
+ }
15
+
16
+ /**
17
+ * Add listener cb at the end of the current chain.
18
+ * @param {String} key
19
+ * @param {Object|Function} context
20
+ * @param {Function} listener
21
+ */
22
+ add (key, context, listener) {
23
+ const fn = listener || context
24
+ const _context = listener === null ? this : context
25
+
26
+ this._listeners.push({
27
+ key: key,
28
+ fn,
29
+ context: _context
30
+ })
31
+ }
32
+
33
+ /**
34
+ * Add the listener callback to the particular position in the chain.
35
+ * The position is specified by the index in the array or a condition
36
+ * Example
37
+ * listeners.insert({ pre: "another", post: "another2" }, "foo", this, function() {... });
38
+ *
39
+ * @param {Number|Object} indexOrCondition
40
+ * @param {String} key
41
+ * @param {Object} context
42
+ * @param {Function} listener
43
+ */
44
+ insert (indexOrCondition, key, context, listener) {
45
+ const listenerOpts = {
46
+ key: key,
47
+ fn: listener || context,
48
+ context: listener === null ? this : context
49
+ }
50
+
51
+ if (!isNaN(indexOrCondition)) {
52
+ return this._listeners.splice(indexOrCondition, 0, listenerOpts)
53
+ }
54
+
55
+ let afterInsertIndex = null
56
+ let beforeInsertIndex = null
57
+
58
+ for (let i = 0; i < this._listeners.length; i++) {
59
+ if (this._listeners[i].key === indexOrCondition.after) {
60
+ afterInsertIndex = i + 1
61
+ }
62
+
63
+ if (this._listeners[i].key === indexOrCondition.before) {
64
+ beforeInsertIndex = i
65
+ }
66
+ }
67
+
68
+ const index = afterInsertIndex !== null
69
+ ? afterInsertIndex
70
+ : (beforeInsertIndex !== null ? beforeInsertIndex : this._listeners.length)
71
+
72
+ this._listeners.splice(index, 0, listenerOpts)
73
+ }
74
+
75
+ /**
76
+ * Remove the listener specified by its key from the collection
77
+ * @param {String} key
78
+ */
79
+ remove (key) {
80
+ this._listeners = this._listeners.filter((l) => {
81
+ return l.key !== key
82
+ })
83
+ }
84
+
85
+ /* Add hook that will be executed before actual listener */
86
+ pre (fn) {
87
+ this._pre.push(fn)
88
+ }
89
+
90
+ /* Add hook that will be executed after actual listener */
91
+ post (fn) {
92
+ this._post.push(fn)
93
+ }
94
+
95
+ /* Add hook that will be executed after actual listener when execution will fail */
96
+ postFail (fn) {
97
+ this._postFail.push(fn)
98
+ }
99
+
100
+ /**
101
+ * Fires listeners and returns value composed from all boolean results into the single bool
102
+ * @returns {Promise<Boolean>}
103
+ */
104
+ async fireAndJoinResults (...args) {
105
+ const results = await this.fire(...args)
106
+
107
+ const successes = results.filter((r) => {
108
+ return r === true
109
+ })
110
+
111
+ const failures = results.filter((r) => {
112
+ return r === false
113
+ })
114
+
115
+ const dontCares = results.filter((r) => {
116
+ return r === null || r === undefined
117
+ })
118
+
119
+ if (successes.length && (successes.length + dontCares.length === results.length)) {
120
+ // override pass
121
+ return true
122
+ }
123
+
124
+ if (failures.length && (failures.length + dontCares.length === results.length)) {
125
+ return false
126
+ }
127
+
128
+ if (dontCares.length === results.length) {
129
+ return null
130
+ }
131
+
132
+ return true
133
+ }
134
+
135
+ /**
136
+ * Fire registered listeners in sequence and returns a promise containing wrapping an array of all
137
+ * individual results.
138
+ * The parameters passed to the fire are forwarded in the same order to the listeners.
139
+ * @returns {Promise<U>}
140
+ */
141
+ async fire (...args) {
142
+ const self = this
143
+
144
+ const applyHook = function applyHook (l, hookArrayName, outerArgs) {
145
+ self[hookArrayName].forEach((p) => {
146
+ p.apply(l, outerArgs)
147
+ })
148
+ }
149
+
150
+ const results = []
151
+
152
+ for (const l of this._listeners) {
153
+ const currentArgs = [...args]
154
+ applyHook(l, '_pre', currentArgs)
155
+
156
+ try {
157
+ const val = await l.fn.apply(l.context, currentArgs)
158
+ applyHook(l, '_post', currentArgs)
159
+ results.push(val)
160
+ } catch (e) {
161
+ currentArgs.unshift(e)
162
+ applyHook(l, '_postFail', currentArgs)
163
+ throw e
164
+ }
165
+ }
166
+
167
+ return results
168
+ }
169
+ }
@@ -1,30 +1,30 @@
1
- const omit = require('lodash.omit')
2
-
3
- module.exports = (level, msg, meta) => {
4
- // detecting if meta is jsreport request object
5
- if (meta != null && meta.context) {
6
- meta.context.logs = meta.context.logs || []
7
-
8
- meta.context.logs.push({
9
- level: level,
10
- message: msg,
11
- timestamp: meta.timestamp || new Date().getTime()
12
- })
13
-
14
- // TODO adding cancel looks bad, its before script is adding req.cancel()
15
- // excluding non relevant properties for the log
16
- const newMeta = Object.assign({}, omit(meta, ['template', 'options', 'data', 'context', 'timestamp', 'cancel']))
17
-
18
- if (newMeta.rootId == null && meta.context.rootId != null) {
19
- newMeta.rootId = meta.context.rootId
20
- }
21
-
22
- if (newMeta.id == null && meta.context.id != null) {
23
- newMeta.id = meta.context.id
24
- }
25
-
26
- return newMeta
27
- }
28
-
29
- return meta
30
- }
1
+ const omit = require('lodash.omit')
2
+
3
+ module.exports = (level, msg, meta) => {
4
+ // detecting if meta is jsreport request object
5
+ if (meta != null && meta.context) {
6
+ meta.context.logs = meta.context.logs || []
7
+
8
+ meta.context.logs.push({
9
+ level: level,
10
+ message: msg,
11
+ timestamp: meta.timestamp || new Date().getTime()
12
+ })
13
+
14
+ // TODO adding cancel looks bad, its before script is adding req.cancel()
15
+ // excluding non relevant properties for the log
16
+ const newMeta = Object.assign({}, omit(meta, ['template', 'options', 'data', 'context', 'timestamp', 'cancel']))
17
+
18
+ if (newMeta.rootId == null && meta.context.rootId != null) {
19
+ newMeta.rootId = meta.context.rootId
20
+ }
21
+
22
+ if (newMeta.id == null && meta.context.id != null) {
23
+ newMeta.id = meta.context.id
24
+ }
25
+
26
+ return newMeta
27
+ }
28
+
29
+ return meta
30
+ }