@jsreport/jsreport-core 3.1.1 → 3.3.0

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 -298
  3. package/index.js +29 -29
  4. package/lib/main/blobStorage/blobStorage.js +52 -52
  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 -264
  11. package/lib/main/extensions/fileUtils.js +56 -56
  12. package/lib/main/extensions/findVersion.js +49 -49
  13. package/lib/main/extensions/locationCache.js +103 -103
  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 +254 -244
  23. package/lib/main/migration/resourcesToAssets.js +230 -230
  24. package/lib/main/migration/xlsxTemplatesToAssets.js +128 -128
  25. package/lib/main/monitoring.js +92 -91
  26. package/lib/main/optionsLoad.js +237 -237
  27. package/lib/main/optionsSchema.js +237 -237
  28. package/lib/main/profiler.js +13 -1
  29. package/lib/main/reporter.js +593 -579
  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 -169
  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 +232 -207
  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 +162 -158
  71. package/lib/worker/render/render.js +202 -201
  72. package/lib/worker/render/resolveReferences.js +60 -60
  73. package/lib/worker/reporter.js +197 -191
  74. package/lib/worker/sandbox/runInSandbox.js +65 -13
  75. package/lib/worker/sandbox/safeSandbox.js +829 -828
  76. package/lib/worker/templates.js +80 -78
  77. package/lib/worker/workerHandler.js +54 -54
  78. package/package.json +91 -92
  79. package/test/blobStorage/common.js +21 -21
  80. package/test/store/common.js +1449 -1449
@@ -1,237 +1,237 @@
1
- const path = require('path')
2
- const fs = require('fs')
3
- const extend = require('node.extend.without.arrays')
4
- const decamelize = require('decamelize')
5
- const nconf = require('nconf')
6
- const appRoot = require('app-root-path')
7
- const { ignoreInitialSchemaProperties } = require('./optionsSchema')
8
-
9
- const {
10
- getDefaultLoadConfig,
11
- getDefaultTempDirectory,
12
- getDefaultRootDirectory
13
- } = require('./defaults')
14
-
15
- /**
16
- * Initialize configuration options. This includes loading config files or initializing default config values
17
- */
18
- async function optionsLoad ({
19
- defaults,
20
- options,
21
- validator,
22
- onConfigLoaded
23
- }) {
24
- let shouldLoadExternalConfig = defaults.loadConfig
25
-
26
- if (options.loadConfig != null) {
27
- shouldLoadExternalConfig = options.loadConfig
28
- }
29
-
30
- if (shouldLoadExternalConfig == null) {
31
- shouldLoadExternalConfig = getDefaultLoadConfig()
32
- }
33
-
34
- let loadConfigResult
35
-
36
- if (shouldLoadExternalConfig) {
37
- loadConfigResult = await loadConfig(defaults, options)
38
- } else {
39
- loadConfigResult = await loadConfig(defaults, options, false)
40
- }
41
-
42
- const appliedConfigFile = loadConfigResult[1]
43
-
44
- options.loadConfig = shouldLoadExternalConfig
45
-
46
- // validating initial options at very first to ensure basic options are right
47
- // this makes afterConfigLoaded function be able to see sanitized values and let us
48
- // apply defaults later doing checks that expects the right value type
49
- const rootOptionsValidation = validator.validateRoot(options, {
50
- rootPrefix: 'rootOptions',
51
- ignore: ignoreInitialSchemaProperties
52
- })
53
-
54
- if (!rootOptionsValidation.valid) {
55
- throw new Error(`options contain values that does not match the defined base root schema. ${rootOptionsValidation.fullErrorMessage}`)
56
- }
57
-
58
- options.appDirectory = options.appDirectory || appRoot.toString()
59
-
60
- // if parentModuleDirectory is empty or null here we proceed with the fallback value to rootDirectory
61
- if (!options.parentModuleDirectory) {
62
- options.parentModuleDirectory = options.rootDirectory
63
- }
64
-
65
- options.extensions = options.extensions || {}
66
- options.logger = options.logger || {}
67
-
68
- if (onConfigLoaded != null) {
69
- await onConfigLoaded()
70
- }
71
-
72
- if (options.tempDirectory && !path.isAbsolute(options.tempDirectory)) {
73
- options.tempDirectory = path.join(options.rootDirectory, options.tempDirectory)
74
- }
75
-
76
- options.tempDirectory = options.tempDirectory || getDefaultTempDirectory()
77
- options.tempAutoCleanupDirectory = path.join(options.tempDirectory, 'autocleanup')
78
- options.tempCoreDirectory = path.join(options.tempDirectory, 'core')
79
- options.store = options.store || { provider: 'memory' }
80
-
81
- options.sandbox = options.sandbox || {}
82
- if (options.allowLocalFilesAccess === true) {
83
- options.sandbox.allowedModules = '*'
84
- }
85
- options.sandbox.nativeModules = options.sandbox.nativeModules || []
86
- options.sandbox.modules = options.sandbox.modules || []
87
- options.sandbox.allowedModules = options.sandbox.allowedModules || []
88
-
89
- if (!fs.existsSync(options.tempDirectory)) {
90
- fs.mkdirSync(options.tempDirectory, { recursive: true })
91
- }
92
-
93
- if (!fs.existsSync(options.tempAutoCleanupDirectory)) {
94
- fs.mkdirSync(options.tempAutoCleanupDirectory, { recursive: true })
95
- }
96
-
97
- if (!fs.existsSync(options.tempCoreDirectory)) {
98
- fs.mkdirSync(options.tempCoreDirectory, { recursive: true })
99
- }
100
-
101
- return appliedConfigFile
102
- }
103
-
104
- /**
105
- * Merge config values from arguments, environment variables, default passed to the constructor and configuration file
106
- */
107
- async function loadConfig (defaults, options, loadExternal = true) {
108
- let loadedOptions = {}
109
- // using clean instance of nconf, avoids sharing values between multiple instances of jsreport
110
- const nconfInstance = new nconf.Provider()
111
-
112
- let rootDirectory = options.rootDirectory || defaults.rootDirectory || getDefaultRootDirectory()
113
-
114
- if (options.rootDirectory) {
115
- loadedOptions.rootDirectory = options.rootDirectory
116
- }
117
-
118
- // we use `.defaults({ store: <value> }` because nconf has problems reading objects with `store`
119
- // property, nconf always take the value of `.store` instead of whole options object in that case
120
- // so we need to pass our object inside store property in order to be loaded correctly
121
- let nfn = nconfInstance.overrides({ store: options })
122
-
123
- let appliedConfigFile = null
124
-
125
- const makeTransform = ({ normalize, separator }) => (obj) => {
126
- let separators = !Array.isArray(separator) ? [separator] : separator
127
-
128
- separators = separators.join('')
129
-
130
- if (normalize === true && obj.key === 'extensions' && typeof obj.value === 'object') {
131
- Object.keys(obj.value).forEach((extensionKey) => {
132
- const realExtensionName = decamelize(extensionKey, '-')
133
- const currentValue = obj.value[extensionKey]
134
- delete obj.value[extensionKey]
135
-
136
- if (realExtensionName !== extensionKey && obj.value[realExtensionName]) {
137
- obj.value[realExtensionName] = extend(
138
- true,
139
- obj.value[realExtensionName],
140
- currentValue
141
- )
142
- } else {
143
- obj.value[realExtensionName] = currentValue
144
- }
145
- })
146
- } else if (!normalize && obj.key.startsWith('extensions')) {
147
- // the transform ensures that camelCase alias keys of extensions
148
- // are being loaded as decamelized keys, this is needed
149
- // in order to respect the order of configuration loading
150
- // for args and env config values
151
- const match = new RegExp(`extensions[${separators}](.[^${separators}]*)[${separators}]*.*`).exec(obj.key)
152
-
153
- if (!match) {
154
- return obj
155
- }
156
-
157
- if (match.length < 2) {
158
- throw new Error(`Wrong configuration value ${obj.key}`)
159
- }
160
-
161
- const realExtensionName = decamelize(match[1], '-')
162
- obj.key = obj.key.replace(match[1], realExtensionName)
163
- }
164
-
165
- return obj
166
- }
167
-
168
- if (loadExternal) {
169
- const separators = ['_', ':']
170
-
171
- nfn = nfn.argv({
172
- // we make a transform that just normalize keys,
173
- // because the transform for args receives single key "extensions" with
174
- // already parsed values of nested args
175
- // "--extensions.something.value = true", "--extensions.something2.value = true".
176
- // unlike the transform for env store which receives raw keys
177
- transform: makeTransform({ normalize: true })
178
- }).env({
179
- separator: ':',
180
- transform: makeTransform({ separator: separators })
181
- }).env({
182
- separator: '_',
183
- transform: makeTransform({ separator: separators })
184
- })
185
- }
186
-
187
- if (nfn.get('rootDirectory') != null) {
188
- rootDirectory = nfn.get('rootDirectory')
189
- }
190
-
191
- // the highest priority for applied config file has file specified using configFile option
192
- const configFileParam = nfn.get('configFile')
193
-
194
- if (configFileParam) {
195
- const configFilePath = path.isAbsolute(configFileParam) ? configFileParam : path.join(rootDirectory, configFileParam)
196
-
197
- if (!fs.existsSync(configFilePath)) {
198
- throw new Error('Config file ' + configFileParam + ' was not found.')
199
- }
200
-
201
- appliedConfigFile = configFileParam
202
-
203
- nfn.file({ file: configFilePath })
204
-
205
- if (nfn.get('rootDirectory') != null) {
206
- rootDirectory = nfn.get('rootDirectory')
207
- }
208
- }
209
-
210
- if (loadExternal) {
211
- // no config file applied so far, lets try to apply the default jsreport.config.json
212
- if (!appliedConfigFile) {
213
- if (fs.existsSync(path.join(rootDirectory, 'jsreport.config.json'))) {
214
- appliedConfigFile = 'jsreport.config.json'
215
- nfn.file({ file: path.join(rootDirectory, 'jsreport.config.json') })
216
-
217
- if (nfn.get('rootDirectory') != null) {
218
- rootDirectory = nfn.get('rootDirectory')
219
- }
220
- }
221
- }
222
- }
223
-
224
- // we pass a copy of defaults to avoid loosing the original
225
- // object values
226
- nfn.defaults({ store: extend(true, {}, defaults) })
227
-
228
- Object.assign(options, nconfInstance.get())
229
-
230
- loadedOptions = extend(true, {}, options, loadedOptions)
231
-
232
- options.rootDirectory = rootDirectory
233
-
234
- return [loadedOptions, appliedConfigFile]
235
- }
236
-
237
- module.exports = optionsLoad
1
+ const path = require('path')
2
+ const fs = require('fs')
3
+ const extend = require('node.extend.without.arrays')
4
+ const decamelize = require('decamelize')
5
+ const nconf = require('nconf')
6
+ const appRoot = require('app-root-path')
7
+ const { ignoreInitialSchemaProperties } = require('./optionsSchema')
8
+
9
+ const {
10
+ getDefaultLoadConfig,
11
+ getDefaultTempDirectory,
12
+ getDefaultRootDirectory
13
+ } = require('./defaults')
14
+
15
+ /**
16
+ * Initialize configuration options. This includes loading config files or initializing default config values
17
+ */
18
+ async function optionsLoad ({
19
+ defaults,
20
+ options,
21
+ validator,
22
+ onConfigLoaded
23
+ }) {
24
+ let shouldLoadExternalConfig = defaults.loadConfig
25
+
26
+ if (options.loadConfig != null) {
27
+ shouldLoadExternalConfig = options.loadConfig
28
+ }
29
+
30
+ if (shouldLoadExternalConfig == null) {
31
+ shouldLoadExternalConfig = getDefaultLoadConfig()
32
+ }
33
+
34
+ let loadConfigResult
35
+
36
+ if (shouldLoadExternalConfig) {
37
+ loadConfigResult = await loadConfig(defaults, options)
38
+ } else {
39
+ loadConfigResult = await loadConfig(defaults, options, false)
40
+ }
41
+
42
+ const appliedConfigFile = loadConfigResult[1]
43
+
44
+ options.loadConfig = shouldLoadExternalConfig
45
+
46
+ // validating initial options at very first to ensure basic options are right
47
+ // this makes afterConfigLoaded function be able to see sanitized values and let us
48
+ // apply defaults later doing checks that expects the right value type
49
+ const rootOptionsValidation = validator.validateRoot(options, {
50
+ rootPrefix: 'rootOptions',
51
+ ignore: ignoreInitialSchemaProperties
52
+ })
53
+
54
+ if (!rootOptionsValidation.valid) {
55
+ throw new Error(`options contain values that does not match the defined base root schema. ${rootOptionsValidation.fullErrorMessage}`)
56
+ }
57
+
58
+ options.appDirectory = options.appDirectory || appRoot.toString()
59
+
60
+ // if parentModuleDirectory is empty or null here we proceed with the fallback value to rootDirectory
61
+ if (!options.parentModuleDirectory) {
62
+ options.parentModuleDirectory = options.rootDirectory
63
+ }
64
+
65
+ options.extensions = options.extensions || {}
66
+ options.logger = options.logger || {}
67
+
68
+ if (onConfigLoaded != null) {
69
+ await onConfigLoaded()
70
+ }
71
+
72
+ if (options.tempDirectory && !path.isAbsolute(options.tempDirectory)) {
73
+ options.tempDirectory = path.join(options.rootDirectory, options.tempDirectory)
74
+ }
75
+
76
+ options.tempDirectory = options.tempDirectory || getDefaultTempDirectory()
77
+ options.tempAutoCleanupDirectory = path.join(options.tempDirectory, 'autocleanup')
78
+ options.tempCoreDirectory = path.join(options.tempDirectory, 'core')
79
+ options.store = options.store || { provider: 'memory' }
80
+
81
+ options.sandbox = options.sandbox || {}
82
+ if (options.allowLocalFilesAccess === true) {
83
+ options.sandbox.allowedModules = '*'
84
+ }
85
+ options.sandbox.nativeModules = options.sandbox.nativeModules || []
86
+ options.sandbox.modules = options.sandbox.modules || []
87
+ options.sandbox.allowedModules = options.sandbox.allowedModules || []
88
+
89
+ if (!fs.existsSync(options.tempDirectory)) {
90
+ fs.mkdirSync(options.tempDirectory, { recursive: true })
91
+ }
92
+
93
+ if (!fs.existsSync(options.tempAutoCleanupDirectory)) {
94
+ fs.mkdirSync(options.tempAutoCleanupDirectory, { recursive: true })
95
+ }
96
+
97
+ if (!fs.existsSync(options.tempCoreDirectory)) {
98
+ fs.mkdirSync(options.tempCoreDirectory, { recursive: true })
99
+ }
100
+
101
+ return appliedConfigFile
102
+ }
103
+
104
+ /**
105
+ * Merge config values from arguments, environment variables, default passed to the constructor and configuration file
106
+ */
107
+ async function loadConfig (defaults, options, loadExternal = true) {
108
+ let loadedOptions = {}
109
+ // using clean instance of nconf, avoids sharing values between multiple instances of jsreport
110
+ const nconfInstance = new nconf.Provider()
111
+
112
+ let rootDirectory = options.rootDirectory || defaults.rootDirectory || getDefaultRootDirectory()
113
+
114
+ if (options.rootDirectory) {
115
+ loadedOptions.rootDirectory = options.rootDirectory
116
+ }
117
+
118
+ // we use `.defaults({ store: <value> }` because nconf has problems reading objects with `store`
119
+ // property, nconf always take the value of `.store` instead of whole options object in that case
120
+ // so we need to pass our object inside store property in order to be loaded correctly
121
+ let nfn = nconfInstance.overrides({ store: options })
122
+
123
+ let appliedConfigFile = null
124
+
125
+ const makeTransform = ({ normalize, separator }) => (obj) => {
126
+ let separators = !Array.isArray(separator) ? [separator] : separator
127
+
128
+ separators = separators.join('')
129
+
130
+ if (normalize === true && obj.key === 'extensions' && typeof obj.value === 'object') {
131
+ Object.keys(obj.value).forEach((extensionKey) => {
132
+ const realExtensionName = decamelize(extensionKey, '-')
133
+ const currentValue = obj.value[extensionKey]
134
+ delete obj.value[extensionKey]
135
+
136
+ if (realExtensionName !== extensionKey && obj.value[realExtensionName]) {
137
+ obj.value[realExtensionName] = extend(
138
+ true,
139
+ obj.value[realExtensionName],
140
+ currentValue
141
+ )
142
+ } else {
143
+ obj.value[realExtensionName] = currentValue
144
+ }
145
+ })
146
+ } else if (!normalize && obj.key.startsWith('extensions')) {
147
+ // the transform ensures that camelCase alias keys of extensions
148
+ // are being loaded as decamelized keys, this is needed
149
+ // in order to respect the order of configuration loading
150
+ // for args and env config values
151
+ const match = new RegExp(`extensions[${separators}](.[^${separators}]*)[${separators}]*.*`).exec(obj.key)
152
+
153
+ if (!match) {
154
+ return obj
155
+ }
156
+
157
+ if (match.length < 2) {
158
+ throw new Error(`Wrong configuration value ${obj.key}`)
159
+ }
160
+
161
+ const realExtensionName = decamelize(match[1], '-')
162
+ obj.key = obj.key.replace(match[1], realExtensionName)
163
+ }
164
+
165
+ return obj
166
+ }
167
+
168
+ if (loadExternal) {
169
+ const separators = ['_', ':']
170
+
171
+ nfn = nfn.argv({
172
+ // we make a transform that just normalize keys,
173
+ // because the transform for args receives single key "extensions" with
174
+ // already parsed values of nested args
175
+ // "--extensions.something.value = true", "--extensions.something2.value = true".
176
+ // unlike the transform for env store which receives raw keys
177
+ transform: makeTransform({ normalize: true })
178
+ }).env({
179
+ separator: ':',
180
+ transform: makeTransform({ separator: separators })
181
+ }).env({
182
+ separator: '_',
183
+ transform: makeTransform({ separator: separators })
184
+ })
185
+ }
186
+
187
+ if (nfn.get('rootDirectory') != null) {
188
+ rootDirectory = nfn.get('rootDirectory')
189
+ }
190
+
191
+ // the highest priority for applied config file has file specified using configFile option
192
+ const configFileParam = nfn.get('configFile')
193
+
194
+ if (configFileParam) {
195
+ const configFilePath = path.isAbsolute(configFileParam) ? configFileParam : path.join(rootDirectory, configFileParam)
196
+
197
+ if (!fs.existsSync(configFilePath)) {
198
+ throw new Error('Config file ' + configFileParam + ' was not found.')
199
+ }
200
+
201
+ appliedConfigFile = configFileParam
202
+
203
+ nfn.file({ file: configFilePath })
204
+
205
+ if (nfn.get('rootDirectory') != null) {
206
+ rootDirectory = nfn.get('rootDirectory')
207
+ }
208
+ }
209
+
210
+ if (loadExternal) {
211
+ // no config file applied so far, lets try to apply the default jsreport.config.json
212
+ if (!appliedConfigFile) {
213
+ if (fs.existsSync(path.join(rootDirectory, 'jsreport.config.json'))) {
214
+ appliedConfigFile = 'jsreport.config.json'
215
+ nfn.file({ file: path.join(rootDirectory, 'jsreport.config.json') })
216
+
217
+ if (nfn.get('rootDirectory') != null) {
218
+ rootDirectory = nfn.get('rootDirectory')
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ // we pass a copy of defaults to avoid loosing the original
225
+ // object values
226
+ nfn.defaults({ store: extend(true, {}, defaults) })
227
+
228
+ Object.assign(options, nconfInstance.get())
229
+
230
+ loadedOptions = extend(true, {}, options, loadedOptions)
231
+
232
+ options.rootDirectory = rootDirectory
233
+
234
+ return [loadedOptions, appliedConfigFile]
235
+ }
236
+
237
+ module.exports = optionsLoad