@appland/scanner 1.57.0 → 1.58.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [@appland/scanner-v1.58.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.57.0...@appland/scanner-v1.58.0) (2022-06-07)
2
+
3
+
4
+ ### Features
5
+
6
+ * Watch the scan config file ([1fde76e](https://github.com/applandinc/appmap-js/commit/1fde76ec626eecb5a9ba300bcc3c636ac6e056f6))
7
+
1
8
  # [@appland/scanner-v1.57.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.56.1...@appland/scanner-v1.57.0) (2022-05-23)
2
9
 
3
10
 
@@ -19,7 +19,7 @@ class AppMapIndex {
19
19
  let ast = ASTBySQLString.get(sql);
20
20
  if (!ast) {
21
21
  ast = (0, models_1.parseSQL)(sql, sqlWarning_1.default);
22
- ast ? ASTBySQLString.set(sql, ast) : ASTBySQLString.set(sql, []);
22
+ ast ? ASTBySQLString.set(sql, ast) : ASTBySQLString.set(sql, null);
23
23
  }
24
24
  return ast;
25
25
  }
package/built/check.js CHANGED
@@ -32,13 +32,11 @@ class Check {
32
32
  }
33
33
  toString() {
34
34
  const tokens = [`[${this.rule.id}]`];
35
- // eslint-disable-next-line @typescript-eslint/no-this-alias
36
- const self = this;
37
- ['includeScope', 'excludeScope', 'includeEvent', 'excludeEvent'].forEach((key) => {
38
- if (self[key].length > 0) {
39
- tokens.push(`(${key} ${self[key].join(' && ')})`);
35
+ for (const key of ['includeScope', 'excludeScope', 'includeEvent', 'excludeEvent']) {
36
+ if (this[key].length > 0) {
37
+ tokens.push(`(${key} ${this[key].join(' && ')})`);
40
38
  }
41
- });
39
+ }
42
40
  return tokens.join(' ');
43
41
  }
44
42
  }
@@ -12,7 +12,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const configurationProvider_1 = require("../../configuration/configurationProvider");
16
15
  const errors_1 = require("../../errors");
17
16
  const util_1 = require("../../rules/lib/util");
18
17
  const validateFile_1 = __importDefault(require("../validateFile"));
@@ -20,6 +19,7 @@ const scanArgs_1 = __importDefault(require("../scanArgs"));
20
19
  const resolveAppId_1 = __importDefault(require("../resolveAppId"));
21
20
  const singleScan_1 = __importDefault(require("./singleScan"));
22
21
  const watchScan_1 = __importDefault(require("./watchScan"));
22
+ const configurationProvider_1 = require("../../configuration/configurationProvider");
23
23
  exports.default = {
24
24
  command: 'scan',
25
25
  describe: 'Scan AppMaps for code behavior findings',
@@ -69,16 +69,16 @@ exports.default = {
69
69
  }
70
70
  if (appmapDir)
71
71
  yield (0, validateFile_1.default)('directory', appmapDir);
72
- const configData = yield (0, configurationProvider_1.parseConfigFile)(config);
73
72
  if (watch) {
74
73
  const watchAppMapDir = appmapDir;
75
- return (0, watchScan_1.default)({ appmapDir: watchAppMapDir, configData });
74
+ return (0, watchScan_1.default)({ appmapDir: watchAppMapDir, configFile: config });
76
75
  }
77
76
  else {
78
77
  let appId = appIdArg;
79
78
  if (!reportAllFindings) {
80
79
  appId = yield (0, resolveAppId_1.default)(appIdArg, appmapDir);
81
80
  }
81
+ const configData = yield (0, configurationProvider_1.parseConfigFile)(config);
82
82
  return (0, singleScan_1.default)({
83
83
  appmapFile,
84
84
  appmapDir,
@@ -42,38 +42,56 @@ const formatReport_1 = require("./formatReport");
42
42
  const scanner_1 = __importDefault(require("./scanner"));
43
43
  const fs_1 = require("fs");
44
44
  const util_1 = require("util");
45
+ const configurationProvider_1 = require("../../configuration/configurationProvider");
46
+ const assert_1 = __importDefault(require("assert"));
45
47
  class Watcher {
46
48
  constructor(options) {
47
49
  this.options = options;
48
50
  }
49
51
  watch() {
50
52
  return __awaiter(this, void 0, void 0, function* () {
51
- this.watcher = chokidar.watch(`${this.options.appmapDir}/**/mtime`, {
53
+ yield this.reloadConfig();
54
+ this.configWatcher = chokidar.watch(this.options.configFile, {
52
55
  ignoreInitial: true,
53
56
  });
54
- this.watcher.on('add', this.scan.bind(this)).on('change', this.scan.bind(this));
57
+ this.configWatcher
58
+ .on('add', this.reloadConfig.bind(this))
59
+ .on('change', this.reloadConfig.bind(this));
60
+ this.appmapWatcher = chokidar.watch(`${this.options.appmapDir}/**/mtime`, {
61
+ ignoreInitial: true,
62
+ });
63
+ this.appmapWatcher.on('add', this.scan.bind(this)).on('change', this.scan.bind(this));
55
64
  });
56
65
  }
57
- abort() {
58
- if (!this.watcher)
66
+ close() {
67
+ if (!this.appmapWatcher)
59
68
  return;
60
- this.watcher.close();
61
- this.watcher = undefined;
69
+ (0, assert_1.default)(this.configWatcher, `configWatcher should always be defined if appmapWatcher is defined`);
70
+ this.appmapWatcher.close();
71
+ this.configWatcher.close();
72
+ this.appmapWatcher = undefined;
73
+ this.configWatcher = undefined;
62
74
  }
63
75
  scan(fileName) {
64
76
  return __awaiter(this, void 0, void 0, function* () {
77
+ (0, assert_1.default)(this.config, `config should always be loaded before appmapWatcher triggers a scan`);
65
78
  const pathTokens = fileName.split('/');
66
79
  const appmapDir = pathTokens.slice(0, pathTokens.length - 1).join('/');
67
80
  const appmapFile = [appmapDir, 'appmap.json'].join('.');
68
81
  const reportFile = [appmapDir, 'appmap-findings.json'].join('/');
69
82
  if (!(yield (0, util_1.promisify)(fs_1.exists)(appmapFile)))
70
83
  return;
71
- const scanner = yield (0, scanner_1.default)(true, this.options.configData, [appmapFile]);
84
+ const scanner = yield (0, scanner_1.default)(true, this.config, [appmapFile]);
72
85
  const rawScanResults = yield scanner.scan();
73
86
  // Always report the raw data
74
87
  yield (0, promises_1.writeFile)(reportFile, (0, formatReport_1.formatReport)(rawScanResults));
75
88
  });
76
89
  }
90
+ reloadConfig() {
91
+ return __awaiter(this, void 0, void 0, function* () {
92
+ this.config = yield (0, configurationProvider_1.parseConfigFile)(this.options.configFile);
93
+ });
94
+ }
77
95
  }
78
96
  exports.Watcher = Watcher;
79
97
  function watchScan(options) {
@@ -178,6 +178,9 @@ function loadRule(ruleName) {
178
178
  });
179
179
  }
180
180
  exports.loadRule = loadRule;
181
+ function hasDefinition(key) {
182
+ return key in options_json_1.default.definitions;
183
+ }
181
184
  function loadConfig(config) {
182
185
  return __awaiter(this, void 0, void 0, function* () {
183
186
  config.checks
@@ -188,10 +191,10 @@ function loadConfig(config) {
188
191
  if ((0, util_1.verbose)()) {
189
192
  console.warn(schemaKey);
190
193
  }
191
- const propertiesSchema = options_json_1.default.definitions[schemaKey];
192
- if (!propertiesSchema) {
194
+ if (!hasDefinition(schemaKey)) {
193
195
  return;
194
196
  }
197
+ const propertiesSchema = options_json_1.default.definitions[schemaKey];
195
198
  if ((0, util_1.verbose)()) {
196
199
  console.warn(propertiesSchema);
197
200
  console.warn(check.properties);
@@ -132,7 +132,8 @@ function countJoins(ast) {
132
132
  let joins = 0;
133
133
  (0, visit_1.visit)(ast, {
134
134
  'map.join': (node) => {
135
- joins += node.map.length;
135
+ var _a;
136
+ joins += ((_a = node.map) !== null && _a !== void 0 ? _a : []).length;
136
137
  },
137
138
  });
138
139
  return joins;
@@ -6,8 +6,10 @@ function visit(node, callbacks) {
6
6
  return;
7
7
  const { type, variant } = node;
8
8
  const key = [type, variant].filter(Boolean).join('.');
9
- if (callbacks !== undefined && key in callbacks)
10
- callbacks[key](node, callbacks);
9
+ if (key in callbacks) {
10
+ const callback = callbacks[key];
11
+ callback(node);
12
+ }
11
13
  visitNode(node, callbacks);
12
14
  }
13
15
  exports.visit = visit;
@@ -1,49 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ScanResults = void 0;
4
- function collectMetadata(metadata) {
5
- const uniqueApps = new Set();
6
- const uniqueLabels = new Set();
7
- const uniqueClients = new Set();
8
- const uniqueFrameworks = new Set();
9
- const uniqueGit = new Set();
10
- const uniqueLanguages = new Set();
11
- const uniqueRecorders = new Set();
12
- const uniqueExceptions = new Set();
13
- function pushDistinctItem(unique, members, item) {
14
- if (item === undefined) {
15
- return;
16
- }
17
- const key = JSON.stringify(item);
18
- if (!unique.has(key)) {
19
- unique.add(key);
20
- members.push(item);
4
+ class DistinctItems {
5
+ constructor() {
6
+ this.members = {};
7
+ }
8
+ push(...items) {
9
+ for (const item of items) {
10
+ if (item === undefined)
11
+ continue;
12
+ const key = JSON.stringify(item);
13
+ if (!(key in this.members))
14
+ this.members[key] = item;
21
15
  }
22
16
  }
23
- function pushDistinctItems(unique, members, items) {
24
- (items || []).forEach((item) => pushDistinctItem(unique, members, item));
17
+ [Symbol.iterator]() {
18
+ return Object.values(this.members)[Symbol.iterator]();
19
+ }
20
+ }
21
+ function collectMetadata(metadata) {
22
+ var _a, _b;
23
+ const uniqueApps = new DistinctItems();
24
+ const uniqueLabels = new DistinctItems();
25
+ const uniqueClients = new DistinctItems();
26
+ const uniqueFrameworks = new DistinctItems();
27
+ const uniqueGit = new DistinctItems();
28
+ const uniqueLanguages = new DistinctItems();
29
+ const uniqueRecorders = new DistinctItems();
30
+ const uniqueExceptions = new DistinctItems();
31
+ for (const item of metadata) {
32
+ uniqueApps.push(item.app);
33
+ uniqueLabels.push(...((_a = item.labels) !== null && _a !== void 0 ? _a : []));
34
+ uniqueClients.push(item.client);
35
+ uniqueFrameworks.push(...((_b = item.frameworks) !== null && _b !== void 0 ? _b : []));
36
+ uniqueGit.push(item.git);
37
+ uniqueLanguages.push(item.language);
38
+ uniqueRecorders.push(item.recorder);
39
+ uniqueExceptions.push(item.exception);
25
40
  }
26
- return metadata.reduce((memo, appMapMetadata) => {
27
- pushDistinctItem(uniqueApps, memo.apps, appMapMetadata.app);
28
- pushDistinctItems(uniqueLabels, memo.labels, appMapMetadata.labels);
29
- pushDistinctItem(uniqueClients, memo.clients, appMapMetadata.client);
30
- pushDistinctItems(uniqueFrameworks, memo.frameworks, appMapMetadata.frameworks);
31
- pushDistinctItem(uniqueGit, memo.git, appMapMetadata.git);
32
- pushDistinctItem(uniqueLanguages, memo.languages, appMapMetadata.language);
33
- pushDistinctItem(uniqueRecorders, memo.recorders, appMapMetadata.recorder);
34
- pushDistinctItem(uniqueExceptions, memo.recorders, appMapMetadata.exception);
35
- return memo;
36
- }, {
37
- labels: [],
38
- apps: [],
39
- clients: [],
40
- frameworks: [],
41
- git: [],
42
- languages: [],
43
- recorders: [],
41
+ return {
42
+ labels: [...uniqueLabels],
43
+ apps: [...uniqueApps],
44
+ clients: [...uniqueClients],
45
+ frameworks: [...uniqueFrameworks],
46
+ git: [...uniqueGit],
47
+ languages: [...uniqueLanguages],
48
+ recorders: [...uniqueRecorders],
44
49
  testStatuses: [],
45
- exceptions: [],
46
- });
50
+ exceptions: [...uniqueExceptions],
51
+ };
47
52
  }
48
53
  /**
49
54
  * ScannerSummary summarizes the results of the entire scan.
@@ -21,7 +21,8 @@ function appmapDirFromConfig() {
21
21
  if (appMapConfigExists) {
22
22
  const appMapConfigData = (0, js_yaml_1.load)((yield (0, promises_1.readFile)('appmap.yml')).toString());
23
23
  if (appMapConfigData && typeof appMapConfigData === 'object') {
24
- return appMapConfigData['appmap_dir'];
24
+ const configData = appMapConfigData;
25
+ return configData['appmap_dir'];
25
26
  }
26
27
  }
27
28
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appland/scanner",
3
- "version": "1.57.0",
3
+ "version": "1.58.0",
4
4
  "description": "",
5
5
  "bin": "built/cli.js",
6
6
  "files": [