@jsreport/jsreport-core 3.0.0 → 3.1.2-test.1

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 (80) 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/profiler.js +2 -1
  29. package/lib/main/reporter.js +575 -578
  30. package/lib/main/schemaValidator.js +252 -252
  31. package/lib/main/settings.js +154 -154
  32. package/lib/main/store/checkDuplicatedId.js +27 -27
  33. package/lib/main/store/collection.js +329 -329
  34. package/lib/main/store/documentStore.js +469 -469
  35. package/lib/main/store/mainActions.js +28 -28
  36. package/lib/main/store/memoryStoreProvider.js +99 -99
  37. package/lib/main/store/queue.js +48 -48
  38. package/lib/main/store/referenceUtils.js +251 -251
  39. package/lib/main/store/setupValidateId.js +43 -43
  40. package/lib/main/store/setupValidateShortid.js +71 -71
  41. package/lib/main/store/transaction.js +69 -69
  42. package/lib/main/store/typeUtils.js +180 -180
  43. package/lib/main/templates.js +34 -34
  44. package/lib/main/validateEntityName.js +62 -62
  45. package/lib/shared/createError.js +36 -36
  46. package/lib/shared/encryption.js +114 -114
  47. package/lib/shared/folders/index.js +11 -11
  48. package/lib/shared/folders/normalizeEntityPath.js +15 -15
  49. package/lib/shared/folders/resolveEntityFromPath.js +88 -88
  50. package/lib/shared/folders/resolveEntityPath.js +46 -46
  51. package/lib/shared/folders/resolveFolderFromPath.js +38 -38
  52. package/lib/shared/generateRequestId.js +4 -4
  53. package/lib/shared/listenerCollection.js +169 -0
  54. package/lib/shared/normalizeMetaFromLogs.js +30 -30
  55. package/lib/shared/reporter.js +128 -123
  56. package/lib/shared/request.js +64 -64
  57. package/lib/shared/tempFilesHandler.js +81 -81
  58. package/lib/shared/templates.js +82 -82
  59. package/lib/static/helpers.js +33 -33
  60. package/lib/worker/blobStorage.js +34 -34
  61. package/lib/worker/defaultProxyExtend.js +46 -46
  62. package/lib/worker/documentStore.js +49 -49
  63. package/lib/worker/extensionsManager.js +17 -17
  64. package/lib/worker/logger.js +48 -48
  65. package/lib/worker/render/diff.js +138 -138
  66. package/lib/worker/render/executeEngine.js +227 -190
  67. package/lib/worker/render/htmlRecipe.js +10 -10
  68. package/lib/worker/render/moduleHelper.js +45 -43
  69. package/lib/worker/render/noneEngine.js +12 -12
  70. package/lib/worker/render/profiler.js +158 -158
  71. package/lib/worker/render/render.js +213 -209
  72. package/lib/worker/render/resolveReferences.js +60 -60
  73. package/lib/worker/reporter.js +192 -187
  74. package/lib/worker/sandbox/runInSandbox.js +13 -4
  75. package/lib/worker/sandbox/safeSandbox.js +828 -822
  76. package/lib/worker/templates.js +78 -78
  77. package/lib/worker/workerHandler.js +54 -54
  78. package/package.json +92 -92
  79. package/test/blobStorage/common.js +21 -21
  80. package/test/store/common.js +1449 -1449
@@ -1,82 +1,82 @@
1
-
2
- module.exports = (reporter) => {
3
- return {
4
- resolveTemplate: (req) => resolveTemplate(reporter, req)
5
- }
6
- }
7
-
8
- async function resolveTemplate (reporter, req) {
9
- let queryResult
10
-
11
- if (req.template._id) {
12
- queryResult = {
13
- query: { _id: req.template._id },
14
- meta: { field: '_id', value: req.template._id }
15
- }
16
- } else if (req.template.shortid) {
17
- queryResult = {
18
- query: { shortid: req.template.shortid },
19
- meta: { field: 'shortid', value: req.template.shortid }
20
- }
21
- }
22
-
23
- const meta = {}
24
- let templates = []
25
-
26
- if (queryResult) {
27
- meta.field = queryResult.meta.field
28
- meta.value = queryResult.meta.value
29
- templates = await reporter.documentStore.collection('templates').find(queryResult.query, req)
30
- } else if (req.template.name) {
31
- const nameIsPath = req.template.name.indexOf('/') !== -1
32
-
33
- meta.field = 'name'
34
- meta.value = req.template.name
35
-
36
- if (!req.template.name.startsWith('/') && nameIsPath && !req.context.currentFolderPath) {
37
- throw reporter.createError('Invalid template path, path should be absolute and start with "/"', {
38
- statusCode: 400,
39
- weak: true
40
- })
41
- }
42
-
43
- const pathParts = req.template.name.split('/').filter((p) => p)
44
-
45
- if (pathParts.length === 0) {
46
- throw reporter.createError('Invalid template path,', {
47
- statusCode: 400,
48
- weak: true
49
- })
50
- }
51
-
52
- if (!nameIsPath) {
53
- // if name is not path do global search by name (with no folder).
54
- // since template name resolution here does not support relative syntax we should not run
55
- // resolveEntityFromPath if the name is not path
56
- templates = await reporter.documentStore.collection('templates').find({
57
- name: req.template.name
58
- }, req)
59
- } else {
60
- const result = await reporter.folders.resolveEntityFromPath(req.template.name, 'templates', req)
61
-
62
- if (result) {
63
- templates = [result.entity]
64
- }
65
- }
66
- }
67
-
68
- let template
69
-
70
- if (templates.length > 1) {
71
- throw reporter.createError(`Duplicated templates found for query ${meta.field}: ${meta.value}`, {
72
- statusCode: 400,
73
- weak: true
74
- })
75
- }
76
-
77
- if (templates.length === 1) {
78
- template = templates[0]
79
- }
80
-
81
- return template
82
- }
1
+
2
+ module.exports = (reporter) => {
3
+ return {
4
+ resolveTemplate: (req) => resolveTemplate(reporter, req)
5
+ }
6
+ }
7
+
8
+ async function resolveTemplate (reporter, req) {
9
+ let queryResult
10
+
11
+ if (req.template._id) {
12
+ queryResult = {
13
+ query: { _id: req.template._id },
14
+ meta: { field: '_id', value: req.template._id }
15
+ }
16
+ } else if (req.template.shortid) {
17
+ queryResult = {
18
+ query: { shortid: req.template.shortid },
19
+ meta: { field: 'shortid', value: req.template.shortid }
20
+ }
21
+ }
22
+
23
+ const meta = {}
24
+ let templates = []
25
+
26
+ if (queryResult) {
27
+ meta.field = queryResult.meta.field
28
+ meta.value = queryResult.meta.value
29
+ templates = await reporter.documentStore.collection('templates').find(queryResult.query, req)
30
+ } else if (req.template.name) {
31
+ const nameIsPath = req.template.name.indexOf('/') !== -1
32
+
33
+ meta.field = 'name'
34
+ meta.value = req.template.name
35
+
36
+ if (!req.template.name.startsWith('/') && nameIsPath && !req.context.currentFolderPath) {
37
+ throw reporter.createError('Invalid template path, path should be absolute and start with "/"', {
38
+ statusCode: 400,
39
+ weak: true
40
+ })
41
+ }
42
+
43
+ const pathParts = req.template.name.split('/').filter((p) => p)
44
+
45
+ if (pathParts.length === 0) {
46
+ throw reporter.createError('Invalid template path,', {
47
+ statusCode: 400,
48
+ weak: true
49
+ })
50
+ }
51
+
52
+ if (!nameIsPath) {
53
+ // if name is not path do global search by name (with no folder).
54
+ // since template name resolution here does not support relative syntax we should not run
55
+ // resolveEntityFromPath if the name is not path
56
+ templates = await reporter.documentStore.collection('templates').find({
57
+ name: req.template.name
58
+ }, req)
59
+ } else {
60
+ const result = await reporter.folders.resolveEntityFromPath(req.template.name, 'templates', req)
61
+
62
+ if (result) {
63
+ templates = [result.entity]
64
+ }
65
+ }
66
+ }
67
+
68
+ let template
69
+
70
+ if (templates.length > 1) {
71
+ throw reporter.createError(`Duplicated templates found for query ${meta.field}: ${meta.value}`, {
72
+ statusCode: 400,
73
+ weak: true
74
+ })
75
+ }
76
+
77
+ if (templates.length === 1) {
78
+ template = templates[0]
79
+ }
80
+
81
+ return template
82
+ }
@@ -1,33 +1,33 @@
1
- /* eslint-disable no-unused-vars */
2
- async function module (moduleName) {
3
- const jsreport = require('jsreport-proxy')
4
- return jsreport.module(moduleName)
5
- }
6
-
7
- function toJS (data) {
8
- function jsStringEscape (string) {
9
- return ('' + string).replace(/["'\\\n\r\u2028\u2029]/g, function (character) {
10
- // Escape all characters not included in SingleStringCharacters and
11
- // DoubleStringCharacters on
12
- // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
13
- switch (character) {
14
- case '"':
15
- case "'":
16
- case '\\':
17
- return '\\' + character
18
- // Four possible LineTerminator characters need to be escaped:
19
- case '\n':
20
- return '\\n'
21
- case '\r':
22
- return '\\r'
23
- case '\u2028':
24
- return '\\u2028'
25
- case '\u2029':
26
- return '\\u2029'
27
- }
28
- })
29
- }
30
-
31
- const validDataStr = jsStringEscape(JSON.stringify(data))
32
- return `JSON.parse('${validDataStr}')`
33
- }
1
+ /* eslint-disable no-unused-vars */
2
+ async function module (moduleName) {
3
+ const jsreport = require('jsreport-proxy')
4
+ return jsreport.module(moduleName)
5
+ }
6
+
7
+ function toJS (data) {
8
+ function jsStringEscape (string) {
9
+ return ('' + string).replace(/["'\\\n\r\u2028\u2029]/g, function (character) {
10
+ // Escape all characters not included in SingleStringCharacters and
11
+ // DoubleStringCharacters on
12
+ // http://www.ecma-international.org/ecma-262/5.1/#sec-7.8.4
13
+ switch (character) {
14
+ case '"':
15
+ case "'":
16
+ case '\\':
17
+ return '\\' + character
18
+ // Four possible LineTerminator characters need to be escaped:
19
+ case '\n':
20
+ return '\\n'
21
+ case '\r':
22
+ return '\\r'
23
+ case '\u2028':
24
+ return '\\u2028'
25
+ case '\u2029':
26
+ return '\\u2029'
27
+ }
28
+ })
29
+ }
30
+
31
+ const validDataStr = jsStringEscape(JSON.stringify(data))
32
+ return `JSON.parse('${validDataStr}')`
33
+ }
@@ -1,34 +1,34 @@
1
- module.exports = (executeMainAction) => {
2
- return {
3
- async read (blobName, req) {
4
- const r = await executeMainAction('blobStorage.read', {
5
- blobName
6
- }, req)
7
- return Buffer.from(r, 'base64')
8
- },
9
-
10
- write (blobName, content, req) {
11
- return executeMainAction('blobStorage.write', {
12
- blobName,
13
- content: Buffer.from(content).toString('base64')
14
- }, req)
15
- },
16
-
17
- remove (blobName, req) {
18
- return executeMainAction('blobStorage.remove', {
19
- blobName
20
- }, req)
21
- },
22
-
23
- append (blobName, content, req) {
24
- return executeMainAction('blobStorage.append', {
25
- blobName,
26
- content: Buffer.from(content).toString('base64')
27
- }, req)
28
- },
29
-
30
- init () {
31
-
32
- }
33
- }
34
- }
1
+ module.exports = (executeMainAction) => {
2
+ return {
3
+ async read (blobName, req) {
4
+ const r = await executeMainAction('blobStorage.read', {
5
+ blobName
6
+ }, req)
7
+ return Buffer.from(r, 'base64')
8
+ },
9
+
10
+ write (blobName, content, req) {
11
+ return executeMainAction('blobStorage.write', {
12
+ blobName,
13
+ content: Buffer.from(content).toString('base64')
14
+ }, req)
15
+ },
16
+
17
+ remove (blobName, req) {
18
+ return executeMainAction('blobStorage.remove', {
19
+ blobName
20
+ }, req)
21
+ },
22
+
23
+ append (blobName, content, req) {
24
+ return executeMainAction('blobStorage.append', {
25
+ blobName,
26
+ content: Buffer.from(content).toString('base64')
27
+ }, req)
28
+ },
29
+
30
+ init () {
31
+
32
+ }
33
+ }
34
+ }
@@ -1,46 +1,46 @@
1
-
2
- module.exports = (reporter) => (proxy, req) => {
3
- proxy.req = req
4
-
5
- proxy.render = async (renderRequest) => {
6
- const res = await reporter.render({
7
- ...renderRequest,
8
- // new fresh context (user data and cycle control counter is inherit from originalReq during rendering).
9
- // this avoids that user can fake user identity by sending context
10
- // with information of another user and allows the original request to collect logs
11
- // from the render of proxy
12
- context: {}
13
- }, req)
14
-
15
- return {
16
- content: res.content,
17
- meta: res.meta
18
- }
19
- }
20
-
21
- proxy.documentStore = {
22
- collection: (name) => ({
23
- find: async (q) => {
24
- req.context.userFindCall = true
25
- const res = await reporter.documentStore.collection(name).find(q, req)
26
- return res
27
- },
28
- findOne: async (q) => {
29
- req.context.userFindCall = true
30
-
31
- const res = await reporter.documentStore.collection(name).findOne(q, req)
32
-
33
- return res
34
- }
35
- })
36
- }
37
-
38
- proxy.folders = {
39
- resolveEntityFromPath: (path, es, options) => {
40
- return reporter.folders.resolveEntityFromPath(path, es, options || {}, req)
41
- },
42
- resolveEntityPath: (entity, es) => {
43
- return reporter.folders.resolveEntityPath(entity, es, req)
44
- }
45
- }
46
- }
1
+
2
+ module.exports = (reporter) => (proxy, req) => {
3
+ proxy.req = req
4
+
5
+ proxy.render = async (renderRequest) => {
6
+ const res = await reporter.render({
7
+ ...renderRequest,
8
+ // new fresh context (user data and cycle control counter is inherit from originalReq during rendering).
9
+ // this avoids that user can fake user identity by sending context
10
+ // with information of another user and allows the original request to collect logs
11
+ // from the render of proxy
12
+ context: {}
13
+ }, req)
14
+
15
+ return {
16
+ content: res.content,
17
+ meta: res.meta
18
+ }
19
+ }
20
+
21
+ proxy.documentStore = {
22
+ collection: (name) => ({
23
+ find: async (q) => {
24
+ req.context.userFindCall = true
25
+ const res = await reporter.documentStore.collection(name).find(q, req)
26
+ return res
27
+ },
28
+ findOne: async (q) => {
29
+ req.context.userFindCall = true
30
+
31
+ const res = await reporter.documentStore.collection(name).findOne(q, req)
32
+
33
+ return res
34
+ }
35
+ })
36
+ }
37
+
38
+ proxy.folders = {
39
+ resolveEntityFromPath: (path, es, options) => {
40
+ return reporter.folders.resolveEntityFromPath(path, es, options || {}, req)
41
+ },
42
+ resolveEntityPath: (entity, es) => {
43
+ return reporter.folders.resolveEntityPath(entity, es, req)
44
+ }
45
+ }
46
+ }
@@ -1,49 +1,49 @@
1
- module.exports = ({ model, collections }, executeMainAction) => {
2
- const store = {
3
- model,
4
- collection: (name) => ({
5
- find: (q, req) => executeMainAction('documentStore.collection.find', {
6
- query: q,
7
- collection: name
8
- }, req),
9
- findOne: (q, req) => executeMainAction('documentStore.collection.findOne', {
10
- query: q,
11
- collection: name
12
- }, req),
13
- insert: async (doc, req) => {
14
- const entity = await executeMainAction('documentStore.collection.insert', {
15
- doc,
16
- collection: name
17
- }, req)
18
- doc._id = entity._id
19
- return entity
20
- },
21
- update: async (query, update, options, req) => {
22
- if (req == null) {
23
- req = options
24
- options = {}
25
- }
26
-
27
- const r = await executeMainAction('documentStore.collection.update', {
28
- query,
29
- update,
30
- options,
31
- collection: name
32
- }, req)
33
-
34
- return r
35
- }
36
- })
37
- }
38
-
39
- store.collections = {}
40
-
41
- for (const colName of collections) {
42
- store.collections[colName] = {
43
- name: colName,
44
- ...store.collection(colName)
45
- }
46
- }
47
-
48
- return store
49
- }
1
+ module.exports = ({ model, collections }, executeMainAction) => {
2
+ const store = {
3
+ model,
4
+ collection: (name) => ({
5
+ find: (q, req) => executeMainAction('documentStore.collection.find', {
6
+ query: q,
7
+ collection: name
8
+ }, req),
9
+ findOne: (q, req) => executeMainAction('documentStore.collection.findOne', {
10
+ query: q,
11
+ collection: name
12
+ }, req),
13
+ insert: async (doc, req) => {
14
+ const entity = await executeMainAction('documentStore.collection.insert', {
15
+ doc,
16
+ collection: name
17
+ }, req)
18
+ doc._id = entity._id
19
+ return entity
20
+ },
21
+ update: async (query, update, options, req) => {
22
+ if (req == null) {
23
+ req = options
24
+ options = {}
25
+ }
26
+
27
+ const r = await executeMainAction('documentStore.collection.update', {
28
+ query,
29
+ update,
30
+ options,
31
+ collection: name
32
+ }, req)
33
+
34
+ return r
35
+ }
36
+ })
37
+ }
38
+
39
+ store.collections = {}
40
+
41
+ for (const colName of collections) {
42
+ store.collections[colName] = {
43
+ name: colName,
44
+ ...store.collection(colName)
45
+ }
46
+ }
47
+
48
+ return store
49
+ }
@@ -1,17 +1,17 @@
1
- const path = require('path')
2
-
3
- module.exports = (reporter, extensionsDefs) => {
4
- return {
5
- recipes: [],
6
- engines: [],
7
- extensions: extensionsDefs,
8
-
9
- async init () {
10
- for (const extension of this.extensions) {
11
- if (extension.options.enabled !== false) {
12
- await require(path.join(extension.directory, extension.worker))(reporter, extension)
13
- }
14
- }
15
- }
16
- }
17
- }
1
+ const path = require('path')
2
+
3
+ module.exports = (reporter, extensionsDefs) => {
4
+ return {
5
+ recipes: [],
6
+ engines: [],
7
+ extensions: extensionsDefs,
8
+
9
+ async init () {
10
+ for (const extension of this.extensions) {
11
+ if (extension.options.enabled !== false) {
12
+ await require(path.join(extension.directory, extension.worker))(reporter, extension)
13
+ }
14
+ }
15
+ }
16
+ }
17
+ }
@@ -1,48 +1,48 @@
1
- const util = require('util')
2
- const normalizeMetaFromLogs = require('../shared/normalizeMetaFromLogs')
3
-
4
- module.exports = function createLogger (profiler) {
5
- return {
6
- debug: (...args) => logFn('debug', profiler, ...args),
7
- info: (...args) => logFn('info', profiler, ...args),
8
- warn: (...args) => logFn('warn', profiler, ...args),
9
- error: (...args) => logFn('error', profiler, ...args)
10
- }
11
- }
12
-
13
- function logFn (level, profiler, ...args) {
14
- const lastArg = args.slice(-1)[0]
15
- let req
16
-
17
- if (
18
- lastArg != null &&
19
- typeof lastArg === 'object' &&
20
- lastArg.context != null &&
21
- lastArg.context.rootId != null
22
- ) {
23
- req = lastArg
24
- }
25
-
26
- if (req == null) {
27
- return
28
- }
29
-
30
- const msgArgs = args.slice(0, -1)
31
-
32
- const log = {
33
- timestamp: new Date().getTime(),
34
- level: level,
35
- message: util.format.apply(util, msgArgs)
36
- }
37
-
38
- const meta = normalizeMetaFromLogs(level, log.message, lastArg)
39
-
40
- if (meta != null) {
41
- log.meta = meta
42
- }
43
-
44
- return profiler.emit({
45
- type: 'log',
46
- ...log
47
- }, req)
48
- }
1
+ const util = require('util')
2
+ const normalizeMetaFromLogs = require('../shared/normalizeMetaFromLogs')
3
+
4
+ module.exports = function createLogger (profiler) {
5
+ return {
6
+ debug: (...args) => logFn('debug', profiler, ...args),
7
+ info: (...args) => logFn('info', profiler, ...args),
8
+ warn: (...args) => logFn('warn', profiler, ...args),
9
+ error: (...args) => logFn('error', profiler, ...args)
10
+ }
11
+ }
12
+
13
+ function logFn (level, profiler, ...args) {
14
+ const lastArg = args.slice(-1)[0]
15
+ let req
16
+
17
+ if (
18
+ lastArg != null &&
19
+ typeof lastArg === 'object' &&
20
+ lastArg.context != null &&
21
+ lastArg.context.rootId != null
22
+ ) {
23
+ req = lastArg
24
+ }
25
+
26
+ if (req == null) {
27
+ return
28
+ }
29
+
30
+ const msgArgs = args.slice(0, -1)
31
+
32
+ const log = {
33
+ timestamp: new Date().getTime(),
34
+ level: level,
35
+ message: util.format.apply(util, msgArgs)
36
+ }
37
+
38
+ const meta = normalizeMetaFromLogs(level, log.message, lastArg)
39
+
40
+ if (meta != null) {
41
+ log.meta = meta
42
+ }
43
+
44
+ return profiler.emit({
45
+ type: 'log',
46
+ ...log
47
+ }, req)
48
+ }