@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,209 +1,205 @@
1
- /*!
2
- * Copyright(c) 2018 Jan Blaha
3
- *
4
- * Orchestration of the rendering process
5
- */
6
- const { Readable } = require('stream')
7
- const extend = require('node.extend.without.arrays')
8
- const ExecuteEngine = require('./executeEngine')
9
- const Request = require('../../shared/request')
10
- const generateRequestId = require('../../shared/generateRequestId')
11
- const resolveReferences = require('./resolveReferences.js')
12
- const moduleHelper = require('./moduleHelper')
13
- let reportCounter = 0
14
- const fs = require('fs').promises
15
- const path = require('path')
16
-
17
- module.exports = (reporter) => {
18
- let helpersScript
19
- reporter.beforeRenderListeners.add('core-helpers', async (req) => {
20
- if (!helpersScript) {
21
- helpersScript = await fs.readFile(path.join(__dirname, '../../static/helpers.js'), 'utf8')
22
- }
23
- req.context.systemHelpers += helpersScript + '\n'
24
- })
25
- moduleHelper(reporter)
26
- reporter.addRequestContextMetaConfig('systemHelpers', { sandboxHidden: true })
27
-
28
- const executeEngine = ExecuteEngine(reporter)
29
- async function beforeRender (reporter, request, response) {
30
- if (!request.template) {
31
- throw reporter.createError('template property must be defined', {
32
- statusCode: 400
33
- })
34
- }
35
-
36
- await reporter.beforeRenderListeners.fire(request, response)
37
- await reporter.validateRenderListeners.fire(request, response)
38
- }
39
-
40
- async function invokeRender (reporter, request, response) {
41
- if (!request.template.engine) {
42
- throw reporter.createError('Engine must be specified', {
43
- statusCode: 400
44
- })
45
- }
46
-
47
- const engine = reporter.extensionsManager.engines.find((e) => e.name === request.template.engine)
48
-
49
- if (!engine) {
50
- throw reporter.createError(`Engine '${request.template.engine}' not found. If this is a custom engine make sure it's properly installed from npm`, {
51
- statusCode: 400
52
- })
53
- }
54
-
55
- if (
56
- request.data != null &&
57
- typeof request.data === 'object' &&
58
- Array.isArray(request.data)
59
- ) {
60
- throw reporter.createError('Request data can not be an array. you should pass an object in request.data input', {
61
- statusCode: 400
62
- })
63
- }
64
-
65
- const engineProfilerEvent = reporter.profiler.emit({
66
- type: 'operationStart',
67
- subtype: 'engine',
68
- name: request.template.engine
69
- }, request, response)
70
-
71
- reporter.logger.debug(`Rendering engine ${engine.name}`, request)
72
-
73
- const engineRes = await executeEngine(engine, request)
74
-
75
- response.content = Buffer.from(engineRes.content != null ? engineRes.content : '')
76
-
77
- reporter.profiler.emit({
78
- type: 'operationEnd',
79
- operationId: engineProfilerEvent.operationId
80
- }, request, response)
81
-
82
- await reporter.afterTemplatingEnginesExecutedListeners.fire(request, response)
83
-
84
- if (!request.template.recipe) {
85
- throw reporter.createError('Recipe must be specified', {
86
- statusCode: 400
87
- })
88
- }
89
-
90
- const recipe = reporter.extensionsManager.recipes.find((r) => r.name === request.template.recipe)
91
-
92
- if (!recipe) {
93
- throw reporter.createError(`Recipe '${request.template.recipe}' not found. If this is a custom recipe make sure it's properly installed from npm.`, {
94
- statusCode: 400
95
- })
96
- }
97
-
98
- const recipeProfilerEvent = reporter.profiler.emit({
99
- type: 'operationStart',
100
- subtype: 'recipe',
101
- name: request.template.recipe
102
- }, request, response)
103
-
104
- reporter.logger.debug('Executing recipe ' + request.template.recipe, request)
105
-
106
- await recipe.execute(request, response)
107
- reporter.profiler.emit({
108
- type: 'operationEnd',
109
- operationId: recipeProfilerEvent.operationId
110
- }, request, response)
111
- }
112
-
113
- async function afterRender (reporter, request, response) {
114
- await reporter.afterRenderListeners.fire(request, response)
115
-
116
- response.stream = Readable.from(response.content)
117
- response.result = response.stream
118
-
119
- return response
120
- }
121
-
122
- return async (req, parentReq) => {
123
- const request = Request(req, parentReq)
124
- request.context.systemHelpers = ''
125
- const response = { meta: {} }
126
- let renderStartProfilerEvent
127
- try {
128
- if (request.context.id == null) {
129
- request.context.id = generateRequestId()
130
- }
131
-
132
- renderStartProfilerEvent = await reporter.profiler.renderStart(request, parentReq, response)
133
- request.data = resolveReferences(request.data) || {}
134
-
135
- if (request.options.reportName) {
136
- response.meta.reportName = String(request.options.reportName)
137
- } else {
138
- response.meta.reportName = 'report'
139
- }
140
-
141
- request.context.reportCounter = ++reportCounter
142
- request.context.startTimestamp = new Date().getTime()
143
-
144
- reporter.requestModulesCache.set(request.context.id, Object.create(null))
145
-
146
- reporter.logger.info(`Starting rendering request ${request.context.reportCounter} (user: ${(request.context.user ? request.context.user.username : 'null')})`, request)
147
-
148
- // TODO
149
- /* if (reporter.entityTypeValidator.getSchema('TemplateType') != null) {
150
- const templateValidationResult = reporter.entityTypeValidator.validate('TemplateType', request.template, { rootPrefix: 'template' })
151
-
152
- if (!templateValidationResult.valid) {
153
- throw reporter.createError(`template input in request contain values that does not match the defined schema. ${templateValidationResult.fullErrorMessage}`, {
154
- statusCode: 400
155
- })
156
- }
157
- } */
158
-
159
- await beforeRender(reporter, request, response)
160
- await invokeRender(reporter, request, response)
161
- await afterRender(reporter, request, response)
162
-
163
- reporter.logger.info(`Rendering request ${request.context.reportCounter} finished in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request)
164
-
165
- response.meta.logs = request.context.logs
166
-
167
- if (parentReq) {
168
- parentReq.context.logs = parentReq.context.logs.concat(request.context.logs)
169
- parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared)
170
- }
171
-
172
- await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response)
173
-
174
- return response
175
- } catch (e) {
176
- await reporter.renderErrorListeners.fire(request, response, e)
177
-
178
- const logFn = e.weak ? reporter.logger.warn : reporter.logger.error
179
-
180
- logFn(`Error when processing render request ${request.context.reportCounter} ${e.message}${e.stack != null ? ' ' + e.stack : ''}`, request)
181
-
182
- logFn(`Rendering request ${request.context.reportCounter} finished with error in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request)
183
-
184
- if (
185
- parentReq &&
186
- parentReq.context &&
187
- parentReq.context.logs &&
188
- request.context &&
189
- request.context.logs
190
- ) {
191
- parentReq.context.logs = parentReq.context.logs.concat(request.context.logs)
192
- }
193
-
194
- if (parentReq) {
195
- parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared)
196
- }
197
-
198
- e.logged = true
199
-
200
- if (renderStartProfilerEvent) {
201
- await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response, e)
202
- }
203
-
204
- throw e
205
- } finally {
206
- reporter.requestModulesCache.delete(request.context.id)
207
- }
208
- }
209
- }
1
+ /*!
2
+ * Copyright(c) 2018 Jan Blaha
3
+ *
4
+ * Orchestration of the rendering process
5
+ */
6
+ const { Readable } = require('stream')
7
+ const extend = require('node.extend.without.arrays')
8
+ const ExecuteEngine = require('./executeEngine')
9
+ const Request = require('../../shared/request')
10
+ const generateRequestId = require('../../shared/generateRequestId')
11
+ const resolveReferences = require('./resolveReferences.js')
12
+ const moduleHelper = require('./moduleHelper')
13
+ let reportCounter = 0
14
+
15
+ module.exports = (reporter) => {
16
+ reporter.addRequestContextMetaConfig('systemHelpers', { sandboxHidden: true })
17
+
18
+ moduleHelper(reporter)
19
+
20
+ const executeEngine = ExecuteEngine(reporter)
21
+ async function beforeRender (reporter, request, response) {
22
+ if (!request.template) {
23
+ throw reporter.createError('template property must be defined', {
24
+ statusCode: 400
25
+ })
26
+ }
27
+
28
+ await reporter.beforeRenderListeners.fire(request, response)
29
+ await reporter.validateRenderListeners.fire(request, response)
30
+ }
31
+
32
+ async function invokeRender (reporter, request, response) {
33
+ if (!request.template.engine) {
34
+ throw reporter.createError('Engine must be specified', {
35
+ statusCode: 400
36
+ })
37
+ }
38
+
39
+ const engine = reporter.extensionsManager.engines.find((e) => e.name === request.template.engine)
40
+
41
+ if (!engine) {
42
+ throw reporter.createError(`Engine '${request.template.engine}' not found. If this is a custom engine make sure it's properly installed from npm`, {
43
+ statusCode: 400
44
+ })
45
+ }
46
+
47
+ if (
48
+ request.data != null &&
49
+ typeof request.data === 'object' &&
50
+ Array.isArray(request.data)
51
+ ) {
52
+ throw reporter.createError('Request data can not be an array. you should pass an object in request.data input', {
53
+ statusCode: 400
54
+ })
55
+ }
56
+
57
+ const engineProfilerEvent = reporter.profiler.emit({
58
+ type: 'operationStart',
59
+ subtype: 'engine',
60
+ name: request.template.engine
61
+ }, request, response)
62
+
63
+ reporter.logger.debug(`Rendering engine ${engine.name}`, request)
64
+
65
+ const engineRes = await executeEngine(engine, request)
66
+
67
+ response.content = Buffer.from(engineRes.content != null ? engineRes.content : '')
68
+
69
+ reporter.profiler.emit({
70
+ type: 'operationEnd',
71
+ operationId: engineProfilerEvent.operationId
72
+ }, request, response)
73
+
74
+ await reporter.afterTemplatingEnginesExecutedListeners.fire(request, response)
75
+
76
+ if (!request.template.recipe) {
77
+ throw reporter.createError('Recipe must be specified', {
78
+ statusCode: 400
79
+ })
80
+ }
81
+
82
+ const recipe = reporter.extensionsManager.recipes.find((r) => r.name === request.template.recipe)
83
+
84
+ if (!recipe) {
85
+ throw reporter.createError(`Recipe '${request.template.recipe}' not found. If this is a custom recipe make sure it's properly installed from npm.`, {
86
+ statusCode: 400
87
+ })
88
+ }
89
+
90
+ const recipeProfilerEvent = reporter.profiler.emit({
91
+ type: 'operationStart',
92
+ subtype: 'recipe',
93
+ name: request.template.recipe
94
+ }, request, response)
95
+
96
+ reporter.logger.debug('Executing recipe ' + request.template.recipe, request)
97
+
98
+ await recipe.execute(request, response)
99
+ reporter.profiler.emit({
100
+ type: 'operationEnd',
101
+ operationId: recipeProfilerEvent.operationId
102
+ }, request, response)
103
+ }
104
+
105
+ async function afterRender (reporter, request, response) {
106
+ await reporter.afterRenderListeners.fire(request, response)
107
+
108
+ response.stream = Readable.from(response.content)
109
+ response.result = response.stream
110
+
111
+ return response
112
+ }
113
+
114
+ return async (req, parentReq) => {
115
+ const request = Request(req, parentReq)
116
+ request.context.systemHelpers = ''
117
+ const response = { meta: {} }
118
+ let renderStartProfilerEvent
119
+ try {
120
+ if (request.context.id == null) {
121
+ request.context.id = generateRequestId()
122
+ }
123
+
124
+ renderStartProfilerEvent = await reporter.profiler.renderStart(request, parentReq, response)
125
+ request.data = resolveReferences(request.data) || {}
126
+
127
+ if (request.options.reportName) {
128
+ response.meta.reportName = String(request.options.reportName)
129
+ } else {
130
+ response.meta.reportName = 'report'
131
+ }
132
+
133
+ request.context.reportCounter = ++reportCounter
134
+ request.context.startTimestamp = new Date().getTime()
135
+
136
+ if (parentReq == null) {
137
+ reporter.requestModulesCache.set(request.context.rootId, Object.create(null))
138
+ }
139
+
140
+ reporter.logger.info(`Starting rendering request ${request.context.reportCounter} (user: ${(request.context.user ? request.context.user.username : 'null')})`, request)
141
+
142
+ // TODO
143
+ /* if (reporter.entityTypeValidator.getSchema('TemplateType') != null) {
144
+ const templateValidationResult = reporter.entityTypeValidator.validate('TemplateType', request.template, { rootPrefix: 'template' })
145
+
146
+ if (!templateValidationResult.valid) {
147
+ throw reporter.createError(`template input in request contain values that does not match the defined schema. ${templateValidationResult.fullErrorMessage}`, {
148
+ statusCode: 400
149
+ })
150
+ }
151
+ } */
152
+
153
+ await beforeRender(reporter, request, response)
154
+ await invokeRender(reporter, request, response)
155
+ await afterRender(reporter, request, response)
156
+
157
+ reporter.logger.info(`Rendering request ${request.context.reportCounter} finished in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request)
158
+
159
+ response.meta.logs = request.context.logs
160
+
161
+ if (parentReq) {
162
+ parentReq.context.logs = parentReq.context.logs.concat(request.context.logs)
163
+ parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared)
164
+ }
165
+
166
+ await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response)
167
+
168
+ return response
169
+ } catch (e) {
170
+ await reporter.renderErrorListeners.fire(request, response, e)
171
+
172
+ const logFn = e.weak ? reporter.logger.warn : reporter.logger.error
173
+
174
+ logFn(`Error when processing render request ${request.context.reportCounter} ${e.message}${e.stack != null ? ' ' + e.stack : ''}`, request)
175
+
176
+ logFn(`Rendering request ${request.context.reportCounter} finished with error in ${(new Date().getTime() - request.context.startTimestamp)} ms`, request)
177
+
178
+ if (
179
+ parentReq &&
180
+ parentReq.context &&
181
+ parentReq.context.logs &&
182
+ request.context &&
183
+ request.context.logs
184
+ ) {
185
+ parentReq.context.logs = parentReq.context.logs.concat(request.context.logs)
186
+ }
187
+
188
+ if (parentReq) {
189
+ parentReq.context.shared = extend(true, parentReq.context.shared, request.context.shared)
190
+ }
191
+
192
+ e.logged = true
193
+
194
+ if (renderStartProfilerEvent) {
195
+ await reporter.profiler.renderEnd(renderStartProfilerEvent.operationId, request, response, e)
196
+ }
197
+
198
+ throw e
199
+ } finally {
200
+ if (parentReq == null) {
201
+ reporter.requestModulesCache.delete(request.context.rootId)
202
+ }
203
+ }
204
+ }
205
+ }
@@ -1,60 +1,60 @@
1
- // resolve references in json specified by $ref and $id attribute, this is handy when user send cycles in json
2
- module.exports = function (json) {
3
- if (typeof json === 'string') {
4
- json = JSON.parse(json)
5
- }
6
-
7
- const byid = {} // all objects by id
8
- const refs = [] // references to objects that could not be resolved
9
- json = (function recurse (obj, prop, parent) {
10
- if (typeof obj !== 'object' || !obj) { // a primitive value
11
- return obj
12
- }
13
- if (Object.prototype.toString.call(obj) === '[object Array]') {
14
- for (let i = 0; i < obj.length; i++) {
15
- if (obj[i] === null) {
16
- continue
17
- }
18
-
19
- if (Object.prototype.hasOwnProperty.call(obj[i], '$ref')) {
20
- obj[i] = recurse(obj[i], i, obj)
21
- } else {
22
- obj[i] = recurse(obj[i], prop, obj)
23
- }
24
- }
25
- return obj
26
- }
27
-
28
- if ('$ref' in obj) { // a reference
29
- const ref = obj.$ref
30
- if (ref in byid) {
31
- return byid[ref]
32
- }
33
- // else we have to make it lazy:
34
- refs.push([parent, prop, ref])
35
- return
36
- } else if ('$id' in obj) {
37
- const id = obj.$id
38
- delete obj.$id
39
- if ('$values' in obj) { // an array
40
- obj = obj.$values.map(recurse)
41
- } else { // a plain object
42
- for (const p in obj) {
43
- if (Object.prototype.hasOwnProperty.call(obj, p)) {
44
- obj[p] = recurse(obj[p], p, obj)
45
- }
46
- }
47
- }
48
- byid[id] = obj
49
- }
50
-
51
- return obj
52
- })(json) // run it!
53
-
54
- for (let i = 0; i < refs.length; i++) { // resolve previously unknown references
55
- const ref = refs[i]
56
- ref[0][ref[1]] = byid[ref[2]]
57
- // Notice that this throws if you put in a reference at top-level
58
- }
59
- return json
60
- }
1
+ // resolve references in json specified by $ref and $id attribute, this is handy when user send cycles in json
2
+ module.exports = function (json) {
3
+ if (typeof json === 'string') {
4
+ json = JSON.parse(json)
5
+ }
6
+
7
+ const byid = {} // all objects by id
8
+ const refs = [] // references to objects that could not be resolved
9
+ json = (function recurse (obj, prop, parent) {
10
+ if (typeof obj !== 'object' || !obj) { // a primitive value
11
+ return obj
12
+ }
13
+ if (Object.prototype.toString.call(obj) === '[object Array]') {
14
+ for (let i = 0; i < obj.length; i++) {
15
+ if (obj[i] === null) {
16
+ continue
17
+ }
18
+
19
+ if (Object.prototype.hasOwnProperty.call(obj[i], '$ref')) {
20
+ obj[i] = recurse(obj[i], i, obj)
21
+ } else {
22
+ obj[i] = recurse(obj[i], prop, obj)
23
+ }
24
+ }
25
+ return obj
26
+ }
27
+
28
+ if ('$ref' in obj) { // a reference
29
+ const ref = obj.$ref
30
+ if (ref in byid) {
31
+ return byid[ref]
32
+ }
33
+ // else we have to make it lazy:
34
+ refs.push([parent, prop, ref])
35
+ return
36
+ } else if ('$id' in obj) {
37
+ const id = obj.$id
38
+ delete obj.$id
39
+ if ('$values' in obj) { // an array
40
+ obj = obj.$values.map(recurse)
41
+ } else { // a plain object
42
+ for (const p in obj) {
43
+ if (Object.prototype.hasOwnProperty.call(obj, p)) {
44
+ obj[p] = recurse(obj[p], p, obj)
45
+ }
46
+ }
47
+ }
48
+ byid[id] = obj
49
+ }
50
+
51
+ return obj
52
+ })(json) // run it!
53
+
54
+ for (let i = 0; i < refs.length; i++) { // resolve previously unknown references
55
+ const ref = refs[i]
56
+ ref[0][ref[1]] = byid[ref[2]]
57
+ // Notice that this throws if you put in a reference at top-level
58
+ }
59
+ return json
60
+ }