@pryv/boiler 1.0.8

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/.licenser.yml ADDED
@@ -0,0 +1,72 @@
1
+ files:
2
+ "**/*.js":
3
+ header:
4
+ startBlock: |
5
+ /**
6
+ * @license
7
+ linePrefix: " * "
8
+ endBlock: " */"
9
+ license: |
10
+ [{SPDX}]({LICENSE_URL})
11
+
12
+ package.json:
13
+ json:
14
+ force:
15
+ author: "{AUTHOR_NAME} <{AUTHOR_EMAIL}> ({AUTHOR_WEB})"
16
+ license: "{SPDX}"
17
+ sortPackage: true
18
+
19
+ siblingLicenseFile:
20
+ name: "LICENSE"
21
+
22
+ README.md:
23
+ footer:
24
+ startBlock: "\n\n## License\n\n"
25
+ linePrefix: ""
26
+ endBlock: ""
27
+ license: "[{SPDX}]({LICENSE_URL})"
28
+
29
+ ignore:
30
+ - .git
31
+ - .vscode
32
+ - node_modules
33
+
34
+ license: |
35
+ Copyright (c) {YEARS} {AUTHOR_NAME} {AUTHOR_WEB}
36
+
37
+ Redistribution and use in source and binary forms, with or without
38
+ modification, are permitted provided that the following conditions are met:
39
+
40
+ 1. Redistributions of source code must retain the above copyright notice,
41
+ this list of conditions and the following disclaimer.
42
+
43
+ 2. Redistributions in binary form must reproduce the above copyright notice,
44
+ this list of conditions and the following disclaimer in the documentation
45
+ and/or other materials provided with the distribution.
46
+
47
+ 3. Neither the name of the copyright holder nor the names of its contributors
48
+ may be used to endorse or promote products derived from this software
49
+ without specific prior written permission.
50
+
51
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
52
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
54
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
55
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
57
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
58
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
59
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61
+
62
+ SPDX-License-Identifier: {SPDX}
63
+
64
+ substitutions:
65
+ YEARS:
66
+ start: 2020
67
+ end: CURRENT_YEAR
68
+ AUTHOR_NAME: "Pryv S.A"
69
+ AUTHOR_EMAIL: info@pryv.com
70
+ AUTHOR_WEB: https://pryv.com
71
+ LICENSE_URL: https://github.com/pryv/pryv-boiler/blob/master/LICENSE
72
+ SPDX: BSD-3-Clause
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (c) 2020–2022 Pryv S.A https://pryv.com
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice,
7
+ this list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ 3. Neither the name of the copyright holder nor the names of its contributors
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ SPDX-License-Identifier: BSD-3-Clause
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # Pryv config and logging boilerplate for Node.js
2
+
3
+
4
+ ## Usage
5
+
6
+
7
+ ### Initialization
8
+
9
+ The "boiler" must be initialized with the application name and configuration files settings, before invoking `getConfig()` or `getLogger()`:
10
+
11
+ ```js
12
+ require('@pryv/boiler').init({
13
+ appName: 'my-app', // This will will be prefixed to any log messages
14
+ baseConfigDir: path.resolve(__dirname, '../config'),
15
+ extraConfigs: [{
16
+ scope: 'extra-config',
17
+ file: path.resolve(__dirname, '../config/extras.js')
18
+ }]
19
+ });
20
+ ```
21
+
22
+
23
+ ### Configuration
24
+
25
+ We use [nconf](https://www.npmjs.com/package/nconf).
26
+
27
+ #### Base config directory structure
28
+
29
+ During initialization `default-config.yml` and `${NODE_ENV}-config.yml` will be loaded if present in `baseConfigDir`.
30
+
31
+ #### Loading order and precedence
32
+
33
+ The order configuration sources are loaded is important. Each source is loaded with a "scope" name, which can be used to replace the source's contents at any point of time.
34
+
35
+ The configuration sources are loaded in the following order, the first taking precedence:
36
+
37
+ 1. **'test'**: Empty slot reserved for tests to override any other config parameter
38
+ 2. **'argv'**: Command line arguments
39
+ 3. **'env'**: Environment variables
40
+ 4. **'base'**: File `${NODE_ENV}-config.yml` (if present) or specified by the `--config` command line argument
41
+ 5. **'extra-config'**: Additional source(s) as specified by the `extraConfigs` option (see below)
42
+ 6. Defaults:
43
+ - **'default-file'**: `${baseConfigDir}/default-config.yml`
44
+ - **'defaults'**: Hard-coded defaults for logger
45
+
46
+ #### Extra configurations
47
+
48
+ Additional configuration sources can be set or reserved at initialization with the `extraConfigs` option, which expects an array of objects with one of the following structures:
49
+
50
+ - File: `{scope: <name>, file: <path to file> }`. Accepts `.yml`, `.json` and `.js` files. Note `.js` content is loaded with `require(<path to file>)`.
51
+ - Data: `{scope: <name>, key: <optional key>, data: <object> }`. If `key` is provided, the content of `data` will be accessible by this key, otherwise it is loaded at the root of the configuration.
52
+ - Remote URL: `{scope: <name>, key: <optional key>, url: <URL to json content> }`. The JSON contents of this URL will be loaded asynchronously.
53
+ - URL from key: `{scope: <name>, key: <optional key>, urlFromKey: <key> }`. Similar to remove URL, with the URL obtained from an existing configuration key.
54
+
55
+ #### Working with the configuration
56
+
57
+ Retrieving the configuration object:
58
+
59
+ ```javascript
60
+ // synchronous loading
61
+ const { getConfigUnsafe } = require('@pryv/boiler'); // Until all asynchronous sources such as URL are loaded, items might not be available
62
+ const config = await getConfigUnsafe();
63
+
64
+ // asynchronous loading
65
+ const { getConfig } = require('@pryv/boiler');
66
+ const config = await getConfig(); // Here we can be sure all items are fully loaded
67
+ ```
68
+
69
+ Retrieving settings:
70
+
71
+ ```javascript
72
+ // configuration content is {foo: { bar: 'hello'}};
73
+ const foo = config.get('foo'); // {bar: 'hello'}
74
+ const bar = config.get('foo:bar'); // 'hello'
75
+
76
+ const barExists = config.has('bar'); // true
77
+ ```
78
+
79
+ Assigning settings:
80
+
81
+ ```javascript
82
+ // configuration content is {foo: { bar: 'hello'}};
83
+ config.set('foo', 'bye bye'); // {bar: 'hello'}
84
+ const foo = config.get('foo'); // 'bye bye'
85
+ ```
86
+
87
+ Changing a scope's contents:
88
+
89
+ ```javascript
90
+ // configuration content is {foo: { bar: 'hello'}};
91
+ config.get('foo'); // {bar: 'hello'}
92
+ // replace 'test' existing content (test is always present as the topmost configuration source)
93
+ config.replaceScopeConfig('test', {foo: 'test'});
94
+ config.get('foo'); // 'test'
95
+ // reset content of 'test' scope
96
+ config.replaceScopeConfig('test', {});
97
+ config.get('foo'); // {bar: 'hello'}
98
+
99
+ // Note: for 'test' scope there is a "sugar" function with config.injectTestConfig(object)
100
+ ```
101
+
102
+ #### "Learn" mode
103
+
104
+ To help detect unused configuration settings, a "learn" mode can be activated to track all calls to `config.get()` in files.
105
+
106
+ Example when running tests:
107
+ ```
108
+ export CONFIG_LEARN_DIR="{absolute path}/service-core/learn-config"
109
+ yarn test
110
+ ```
111
+
112
+
113
+ ### Logging
114
+
115
+ All messages are prefixed by the `appName` value provided at initialization (see above)). `appName` can be postfixed with a string by setting the environment variable `PRYV_BOILER_SUFFIX`, which is useful when spawning several concurrent processes of the same application.
116
+
117
+ #### Using the logger
118
+
119
+ ```javascript
120
+ const {getLogger} = require('@pryv/boiler');
121
+
122
+ logger.info('Message', item); // standard log
123
+ logger.warn('Message', item); // warning
124
+ logger.error('Message', item); // warning
125
+ logger.debug('Message', item); // debug
126
+
127
+ logger.getLogger('sub'); // new logger name spaced with parent, here '{appName}:sub'
128
+ ```
129
+
130
+ `logger.info()`, `logger.warn()` and `logger.error()` use [Winston](https://www.npmjs.com/package/winston) `logger.debug()` is based on [debug](https://www.npmjs.com/package/debug).
131
+
132
+ #### Outputting debug messages
133
+
134
+ Set the `DEBUG` environment variable. For example: `DEBUG="*" node app.js` will output all debug messages.
135
+
136
+ As "debug" is a widely used package, you might get way more debug lines than expected, so you can use the `appName` property to only output messages from your application code: `DEBUG="<appName>*" node app.js`
137
+
138
+ #### Log configuration sample
139
+
140
+ ```javascript
141
+ logs: {
142
+ console: {
143
+ active: true,
144
+ level: 'info',
145
+ format: {
146
+ color: true,
147
+ time: true,
148
+ aligned: true
149
+ }
150
+ },
151
+ file: {
152
+ active: true,
153
+ path: 'application.log'
154
+ }
155
+ }
156
+ ```
157
+
158
+
159
+ ## Contributing
160
+
161
+ `npm run lint` lints the code with [Semi-Standard](https://github.com/standard/semistandard).
162
+
163
+ `npm run license` updates license information.
164
+
165
+
166
+ ## License
167
+
168
+ [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
@@ -0,0 +1,7 @@
1
+ ---
2
+ foo:
3
+ bar: 'Hello Bar'
4
+ foo: 'Hello Foo'
5
+ service:
6
+ name: 'To be overriden by Async Service load'
7
+ default-yaml: 'default-yaml loaded'
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+
6
+ module.exports = {
7
+ 'extra-js': 'extra-js loaded'
8
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "extra-json": "extra-config json loaded"
3
+ }
@@ -0,0 +1,2 @@
1
+ ---
2
+ extra-yaml: 'Extra YAML loaded'
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+
6
+ module.exports = async function () {
7
+ await new Promise(resolve => setTimeout(resolve, 100));
8
+ return {
9
+ 'extra-js-async': 'extra-js-async loaded'
10
+ };
11
+ };
@@ -0,0 +1,16 @@
1
+ ---
2
+ logs:
3
+ console:
4
+ active: true
5
+ level: debug
6
+ format:
7
+ color: true
8
+ time: false
9
+ aligned: true
10
+
11
+ file:
12
+ active: true
13
+ path: test-application.log
14
+
15
+ foo:
16
+ bar: 'Hello Test'
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+ /* eslint-disable */
6
+ const boiler = require('../src');
7
+ const config = boiler.init({ appName: 'sample-double-init' });
8
+
9
+ boiler.init({ appName: 'sample-double-init2' });
File without changes
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+ const path = require('path');
6
+ const boiler = require('../src');
7
+ const { getConfigUnsafe, getLogger, getConfig } = require('../src').init({
8
+ appName: 'sample',
9
+ baseConfigDir: path.resolve(__dirname, './configs'),
10
+ extraConfigs: [{
11
+ scope: 'airbrake',
12
+ key: 'logs',
13
+ data: {
14
+ airbrake: {
15
+ active: false,
16
+ projectId: 319858,
17
+ key: '44ca9a107f4546505c7e24c8c598b0c7'
18
+ }
19
+ }
20
+ }, {
21
+ scope: 'extra1',
22
+ file: path.resolve(__dirname, './configs/extra-config.yml')
23
+ }, {
24
+ scope: 'extra2',
25
+ file: path.resolve(__dirname, './configs/extra-config.json')
26
+ }, {
27
+ scope: 'extra3',
28
+ file: path.resolve(__dirname, './configs/extra-config.js')
29
+ }, {
30
+ scope: 'extra4',
31
+ data: {
32
+ 'extra-4-data': 'extra 4 object loaded'
33
+ }
34
+ }, {
35
+ scope: 'extra5',
36
+ key: 'extra-5-data',
37
+ data: 'extra 5 object loaded'
38
+ },
39
+ {
40
+ scope: 'extra-js-async',
41
+ fileAsync: path.resolve(__dirname, './configs/extra-js-async.js')
42
+ }, {
43
+ scope: 'pryv.li',
44
+ url: 'https://reg.pryv.li/service/info'
45
+ }, {
46
+ scope: 'pryv.me',
47
+ key: 'service',
48
+ url: 'https://reg.pryv.me/service/info'
49
+ }, {
50
+ scope: 'pryv.me-def',
51
+ key: 'definitions',
52
+ urlFromKey: 'service:assets:definitions'
53
+ }, {
54
+ scope: 'ondisk-scope',
55
+ key: 'ondisk',
56
+ url: 'file://' + path.resolve(__dirname, './remotes/ondisk.json')
57
+ }, {
58
+ plugin: require('./plugins/plugin-sync')
59
+ }, {
60
+ pluginAsync: require('./plugins/plugin-async')
61
+ }]
62
+ }, function () {
63
+ console.log('Ready');
64
+ });
65
+
66
+ const config = getConfigUnsafe(true);
67
+
68
+ const rootLogger = getLogger();
69
+ rootLogger.debug('hello root');
70
+
71
+ const indexLogger = getLogger('index');
72
+ indexLogger.debug('hello index');
73
+ indexLogger.info('extra Yaml', config.get('extra-yaml'));
74
+ indexLogger.info('extra Json', config.get('extra-json'));
75
+ indexLogger.info('extra Js', config.get('extra-js'));
76
+ indexLogger.info('extra 4 data', config.get('extra-4-data'));
77
+ indexLogger.info('extra 5 data', config.get('extra-5-data'));
78
+ indexLogger.info('default yaml', config.get('default-yaml'));
79
+ indexLogger.info('Default Service Name', config.get('service:name'));
80
+
81
+ config.replaceScopeConfig('extra5', { 'extra-5-data': 'new Extra 5 data' });
82
+ indexLogger.info('extra 5 data', config.get('extra-5-data'));
83
+
84
+ const subLogger = indexLogger.getLogger('sub');
85
+ subLogger.debug('hello sub');
86
+ indexLogger.info('plugin sync', config.get('plugin-sync'));
87
+ indexLogger.info('hide stuff auth=c08r0xs95xlb1xgssmp6tr7c0000gp', { password: 'toto' });
88
+
89
+ (async () => {
90
+ await getConfig();
91
+ await boiler.notifyAirbrake('Hello');
92
+ indexLogger.info('pryv.li serial: ', config.get('serial'));
93
+ indexLogger.info('pryv.me name: ', config.get('service:name'));
94
+ indexLogger.info('Favicon: ', config.get('definitions:favicon:default:url'));
95
+ indexLogger.info('OnDisk: ', config.get('ondisk'));
96
+ indexLogger.info('Plugin async: ', config.get('plugin-async'));
97
+ indexLogger.info('Service Name', config.get('service:name'));
98
+
99
+ indexLogger.info('Scope of foo', config.getScopeAndValue('foo'));
100
+ })();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+ module.exports = {
6
+ load: async function (store) {
7
+ store.set('plugin-async', 'plugin async loaded');
8
+ return 'plugin-async'; // my name
9
+ }
10
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+ module.exports = {
6
+ load: function (store) {
7
+ store.set('plugin-sync', 'plugin sync loaded');
8
+ return 'plugin-sync'; // my name
9
+ }
10
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "tom": "bob"
3
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@pryv/boiler",
3
+ "version": "1.0.8",
4
+ "private": false,
5
+ "description": "Logging and config boilerplate library for Node.js apps and services at Pryv",
6
+ "keywords": [
7
+ "Pryv",
8
+ "Config",
9
+ "Logging"
10
+ ],
11
+ "homepage": "https://github.com/pryv/pryv-boiler#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/pryv/pryv-boiler/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/pryv/pryv-boiler.git"
18
+ },
19
+ "license": "BSD-3-Clause",
20
+ "author": "Pryv S.A <info@pryv.com> (https://pryv.com)",
21
+ "main": "src/index",
22
+ "scripts": {
23
+ "license": "source-licenser -c .licenser.yml .",
24
+ "lint": "semistandard"
25
+ },
26
+ "dependencies": {
27
+ "@airbrake/node": "^1.4.2",
28
+ "debug": "^4.3.4",
29
+ "js-yaml": "^4.0.0",
30
+ "nconf": "^0.12.0",
31
+ "semistandard": "^16.0.1",
32
+ "source-licenser": "^2.0.4",
33
+ "superagent": "^7.1.2",
34
+ "winston": "^3.7.2",
35
+ "winston-daily-rotate-file": "^4.6.1"
36
+ }
37
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+
6
+ const { Notifier } = require('@airbrake/node');
7
+
8
+ let airbrake;
9
+ let logger;
10
+
11
+ function setUpAirbrakeIfNeeded (config, rootLogger) {
12
+ if (airbrake) {
13
+ rootLogger.debug('Skipping airBrake setup (already done)');
14
+ return;
15
+ }
16
+ logger = rootLogger;
17
+
18
+ const airBrakeSettings = config.get('logs:airbrake');
19
+ if (airBrakeSettings.active) {
20
+ airbrake = new Notifier({
21
+ projectId: airBrakeSettings.projectId,
22
+ projectKey: airBrakeSettings.key,
23
+ environment: 'production'
24
+ });
25
+ logger.debug('Airbrake active with projectId: ', airBrakeSettings);
26
+ }
27
+
28
+ // Catch uncaught Promise rejections
29
+ process.on('unhandledRejection', (reason) => {
30
+ throw reason;
31
+ });
32
+
33
+ // Catch uncaught Exceptions
34
+ process.on('uncaughtException', async (error) => {
35
+ logger.error('uncaughtException', error);
36
+ await notifyAirbrake(error);
37
+ if (process.env.NODE_ENV !== 'test') process.exit(1);
38
+ });
39
+ }
40
+
41
+ async function notifyAirbrake () {
42
+ if (airbrake != null && typeof airbrake.notify === 'function') {
43
+ await airbrake.notify(...arguments);
44
+ } else {
45
+ logger.debug('Skipping notifyAirbake', ...arguments);
46
+ }
47
+ }
48
+
49
+ module.exports = {
50
+ setUpAirbrakeIfNeeded: setUpAirbrakeIfNeeded,
51
+ notifyAirbrake: notifyAirbrake
52
+ };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @license
3
+ * [BSD-3-Clause](https://github.com/pryv/pryv-boiler/blob/master/LICENSE)
4
+ */
5
+ /**
6
+ * read all files in CONFIG_LEARN_DIR and output a readable result
7
+ */
8
+
9
+ const path = require('path');
10
+ const learnDir = process.env.CONFIG_LEARN_DIR || path.resolve(__dirname, '../../../learn-config');
11
+ console.log('Looking for learning files in: ' + learnDir);
12
+ const fs = require('fs');
13
+
14
+ const apps = {};
15
+
16
+ // get all files
17
+ const files = fs.readdirSync(learnDir);
18
+
19
+ for (const file of files) {
20
+ if (file.endsWith('-calls.csv')) {
21
+ handleCSV(path.join(learnDir, file));
22
+ }
23
+ }
24
+
25
+ for (const file of files) {
26
+ if (file.endsWith('-config.json')) {
27
+ handleConfig(path.join(learnDir, file));
28
+ }
29
+ }
30
+
31
+ function handleConfig (file) {
32
+ /* eslint-disable-next-line no-useless-escape */
33
+ const appNameSearch = /.*\/([a-zA-Z\-]*)[0-9]{1,2}-config.json/;
34
+ const appName = file.match(appNameSearch)[1];
35
+ const config = require(file).config;
36
+ const calls = apps[appName].calls;
37
+
38
+ checkExistsAndFlag(config, calls);
39
+
40
+ function checkExistsAndFlag (configItem, callsItem) {
41
+ if (typeof configItem !== 'object' || Array.isArray(configItem)) return;
42
+ for (const key of Object.keys(configItem)) {
43
+ if (key !== 'calls') {
44
+ if (typeof callsItem[key] === 'undefined') {
45
+ callsItem[key] = 'UNUSED';
46
+ // console.log(callsItem)
47
+ } else {
48
+ checkExistsAndFlag(configItem[key], callsItem[key]);
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ function handleCSV (file) {
56
+ /* eslint-disable-next-line no-useless-escape */
57
+ const appNameSearch = /.*\/([a-zA-Z\-]*)[0-9]{1,2}-calls.csv/;
58
+ const appName = file.match(appNameSearch)[1];
59
+
60
+ // initialize apps.appname if needed
61
+ if (!apps[appName]) {
62
+ apps[appName] = {
63
+ calls: {},
64
+ rank: {}
65
+ };
66
+ }
67
+
68
+ const filelines = fs.readFileSync(file, 'utf-8').split('\n');
69
+ for (const line of filelines) {
70
+ // -- calls count
71
+ const [path, call] = line.split(';');
72
+ const key = deepFind(apps[appName].calls, path + ':calls');
73
+ if (!key[call]) key[call] = 0;
74
+ key[call]++;
75
+ // -- ranking
76
+ apps[appName].rank[line] = key[call];
77
+ }
78
+ }
79
+
80
+ function deepFind (obj, path) {
81
+ const paths = path.split(':');
82
+ let current = obj;
83
+ let i;
84
+
85
+ for (i = 0; i < paths.length; ++i) {
86
+ if (current[paths[i]] === undefined) {
87
+ current[paths[i]] = {}; // initialize path while searching
88
+ }
89
+ current = current[paths[i]];
90
+ }
91
+ return current;
92
+ }
93
+
94
+ // sort and filter ranking
95
+ const KEEP_HIGHER_N = 10;
96
+
97
+ for (const appName of Object.keys(apps)) {
98
+ const app = apps[appName];
99
+ const arrayOfCalls = [];
100
+ for (const callLine of Object.keys(app.rank)) {
101
+ arrayOfCalls.push({ count: app.rank[callLine], line: callLine });
102
+ }
103
+ const arrayOfCallsSorted = arrayOfCalls.sort((a, b) => { return b.count - a.count; });
104
+ // replace rank info
105
+ app.rank = arrayOfCallsSorted.slice(0, KEEP_HIGHER_N);
106
+ }
107
+
108
+ fs.writeFileSync(path.join(learnDir, 'compute.json'), JSON.stringify(apps, null, 2));
109
+ // console.log(apps);