@appland/scanner 1.71.2 → 1.71.3

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,11 @@
1
+ # [@appland/scanner-v1.71.3](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.71.2...@appland/scanner-v1.71.3) (2022-10-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Handle appmap paths in an OS-agnostic manner in scan --watch ([cc473a8](https://github.com/getappmap/appmap-js/commit/cc473a89c60130b4b518a56b7e50f8617d88dd59))
7
+ * scan --watch works even if the appmap dir doesn't initially exist ([938bb76](https://github.com/getappmap/appmap-js/commit/938bb76d8fd827874731f4cd3258c4b9e0988a35))
8
+
1
9
  # [@appland/scanner-v1.71.2](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.71.1...@appland/scanner-v1.71.2) (2022-10-04)
2
10
 
3
11
 
@@ -69,11 +69,11 @@ exports.default = {
69
69
  if (reportAllFindings && watch) {
70
70
  throw new errors_1.ValidationError(`Don't use --all with --watch, because in watch mode all findings are reported`);
71
71
  }
72
+ if (appmapDir)
73
+ yield (0, validateFile_1.default)('directory', appmapDir);
72
74
  if (!appmapFile && !appmapDir) {
73
75
  appmapDir = (yield (0, appmapDirFromConfig_1.appmapDirFromConfig)()) || '.';
74
76
  }
75
- if (appmapDir)
76
- yield (0, validateFile_1.default)('directory', appmapDir);
77
77
  let appId = appIdArg;
78
78
  if (!watch && !reportAllFindings)
79
79
  appId = yield (0, resolveAppId_1.default)(appIdArg, appmapDir);
@@ -44,6 +44,29 @@ const configurationProvider_1 = require("../../configuration/configurationProvid
44
44
  const assert_1 = __importDefault(require("assert"));
45
45
  const path_1 = __importDefault(require("path"));
46
46
  const async_1 = require("async");
47
+ function isDir(targetPath) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ try {
50
+ return (yield (0, promises_1.stat)(targetPath)).isDirectory();
51
+ }
52
+ catch (_a) {
53
+ return false;
54
+ }
55
+ });
56
+ }
57
+ function existingParent(targetPath) {
58
+ return __awaiter(this, void 0, void 0, function* () {
59
+ while (targetPath.length > 1) {
60
+ if (yield isDir(targetPath))
61
+ break;
62
+ targetPath = path_1.default.dirname(targetPath);
63
+ }
64
+ return targetPath;
65
+ });
66
+ }
67
+ function isAncestorPath(ancestor, descendant) {
68
+ return !path_1.default.relative(ancestor, descendant).startsWith('..');
69
+ }
47
70
  class Watcher {
48
71
  constructor(options) {
49
72
  this.options = options;
@@ -58,20 +81,34 @@ class Watcher {
58
81
  this.configWatcher
59
82
  .on('add', this.reloadConfig.bind(this))
60
83
  .on('change', this.reloadConfig.bind(this));
61
- // Chokidar struggles with relative paths. Make sure the watch pattern is absolute.
62
- const watchPattern = path_1.default.resolve(this.options.appmapDir, '**', 'mtime');
63
- this.appmapWatcher = chokidar.watch(watchPattern, {
84
+ const appmapDir = path_1.default.resolve(this.options.appmapDir);
85
+ // If the appmap directory is a descendant of cwd, watch cwd (presumably project directory).
86
+ // This ensures the watch will survive even if the appmap dir is removed and recreated.
87
+ // Otherwise, make sure to use an existing directory. Chokidar struggles with missing directories.
88
+ const watchDir = isAncestorPath(process.cwd(), appmapDir)
89
+ ? process.cwd()
90
+ : yield existingParent(appmapDir);
91
+ // Custom ignore function needed to cut down the watch tree to just what we need.
92
+ const ignored = (targetPath) => {
93
+ // Ignore anything that isn't an ancestor or descendant of the appmap dir.
94
+ if (!(isAncestorPath(targetPath, appmapDir) || isAncestorPath(appmapDir, targetPath)))
95
+ return true;
96
+ // Also make sure to not try to recurse down node_modules or .git
97
+ const basename = path_1.default.basename(targetPath);
98
+ return basename === 'node_modules' || basename === '.git';
99
+ };
100
+ this.appmapWatcher = chokidar.watch(watchDir, {
64
101
  ignoreInitial: true,
65
- ignored: ['**/node_modules/**', '**/.git/**'],
102
+ ignored,
66
103
  });
67
- this.appmapPoller = chokidar.watch(watchPattern, {
104
+ this.appmapPoller = chokidar.watch(watchDir, {
68
105
  ignoreInitial: false,
69
- ignored: ['**/node_modules/**', '**/.git/**'],
106
+ ignored,
70
107
  usePolling: true,
71
108
  interval: 1000,
72
109
  persistent: false,
73
110
  });
74
- const enqueue = this.enqueue.bind(this);
111
+ const enqueue = (filePath) => path_1.default.basename(filePath) === 'mtime' && this.enqueue(filePath);
75
112
  for (const ch of [this.appmapWatcher, this.appmapPoller])
76
113
  ch.on('add', enqueue).on('change', enqueue);
77
114
  });
@@ -94,7 +131,7 @@ class Watcher {
94
131
  scan(mtimePath) {
95
132
  return __awaiter(this, void 0, void 0, function* () {
96
133
  (0, assert_1.default)(this.config, `config should always be loaded before appmapWatcher triggers a scan`);
97
- const appmapFile = mtimePath.replace(/\/mtime$/, '.appmap.json');
134
+ const appmapFile = [path_1.default.dirname(mtimePath), 'appmap.json'].join('.');
98
135
  const reportFile = mtimePath.replace(/mtime$/, 'appmap-findings.json');
99
136
  const [appmapStats, reportStats] = yield Promise.all([appmapFile, reportFile].map((f) => (0, promises_1.stat)(f).catch(() => null)));
100
137
  if (!appmapStats)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appland/scanner",
3
- "version": "1.71.2",
3
+ "version": "1.71.3",
4
4
  "description": "",
5
5
  "bin": "built/cli.js",
6
6
  "files": [