@appland/scanner 1.65.0 → 1.68.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 +38 -0
- package/built/cli/scan/breakpoint.js +65 -0
- package/built/cli/scan/command.js +28 -18
- package/built/cli/scan/interactiveScan.js +34 -0
- package/built/cli/scan/singleScan.js +6 -14
- package/built/cli/scan/ui/interactiveProgess.js +147 -0
- package/built/cli/scan/ui/scanContext.js +67 -0
- package/built/cli/scan/ui/state/addBreakpoint.js +120 -0
- package/built/cli/scan/ui/state/eval.js +41 -0
- package/built/cli/scan/ui/state/hint.js +23 -0
- package/built/cli/scan/ui/state/hitBreakpoint.js +68 -0
- package/built/cli/scan/ui/state/initial.js +58 -0
- package/built/cli/scan/ui/state/scan.js +33 -0
- package/built/cli/scan/ui/state.js +2 -0
- package/built/cli/scan/ui/userInteraction.js +97 -0
- package/built/configuration/configurationProvider.js +1 -1
- package/built/database/index.js +15 -2
- package/built/progressReporter.js +2 -0
- package/built/ruleChecker.js +22 -10
- package/built/rules/deprecated-crypto-algorithm/metadata.js +14 -0
- package/built/rules/deprecated-crypto-algorithm/rule.js +44 -0
- package/built/rules/lib/parseRuleDescription.js +4 -1
- package/built/rules/lib/util.js +31 -1
- package/built/rules/too-many-joins/metadata.js +10 -0
- package/built/rules/too-many-joins/options.js +12 -0
- package/built/rules/{tooManyJoins.js → too-many-joins/rule.js} +14 -24
- package/built/sampleConfig/default.yml +1 -0
- package/doc/labels/crypto.decrypt.md +7 -0
- package/doc/labels/crypto.digest.md +7 -0
- package/doc/labels/crypto.encrypt.md +1 -0
- package/doc/rules/deprecated-crypto-algorithm.md +15 -0
- package/doc/rules/http-500.md +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
# [@appland/scanner-v1.68.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.67.0...@appland/scanner-v1.68.0) (2022-08-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Allow rule doc to be missing ([85a22fc](https://github.com/applandinc/appmap-js/commit/85a22fcaf777ab3794300d3ad52057be6ace4a87))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Enhanced breakpoints ([b338bc9](https://github.com/applandinc/appmap-js/commit/b338bc9c1beebf3fbc78fb57bb72e4738c0ed5e6))
|
|
12
|
+
* Interactive rule evaluator ([d0a0846](https://github.com/applandinc/appmap-js/commit/d0a08466ed0e92484a4c195c74cbb737a2cb40d6))
|
|
13
|
+
|
|
14
|
+
# [@appland/scanner-v1.67.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.66.0...@appland/scanner-v1.67.0) (2022-08-10)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* Fix Options loading from dir-based rules ([f58ce49](https://github.com/applandinc/appmap-js/commit/f58ce49f22ba4d649e8886d76373cf23d6614b37))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* Ignore schema info tables in too-many-joins ([0cb387d](https://github.com/applandinc/appmap-js/commit/0cb387d74aa7e6edda5e24a88d07fa65b3900966))
|
|
25
|
+
|
|
26
|
+
# [@appland/scanner-v1.66.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.65.0...@appland/scanner-v1.66.0) (2022-08-08)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* Fix rule doc ([b99b6ae](https://github.com/applandinc/appmap-js/commit/b99b6aec90186bef312d04fb4f4c95f9b1ee62d5))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* Add deprecated-crypto-algorithm to default rule set ([3034489](https://github.com/applandinc/appmap-js/commit/303448974a73637493a72bea7ab8cfb28ccc8b10))
|
|
37
|
+
* Detect deprecated crypto algorithm ([a17a537](https://github.com/applandinc/appmap-js/commit/a17a537334771a9f2cd64fa73c2396e517ff82ea))
|
|
38
|
+
|
|
1
39
|
# [@appland/scanner-v1.65.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.64.0...@appland/scanner-v1.65.0) (2022-08-08)
|
|
2
40
|
|
|
3
41
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BreakOnCodeObject = exports.BreakOnLabel = exports.BreakOnEvent = exports.BreakOnCounter = void 0;
|
|
4
|
+
class BreakOnCounter {
|
|
5
|
+
constructor(counter) {
|
|
6
|
+
this.counter = counter;
|
|
7
|
+
}
|
|
8
|
+
condition(context) {
|
|
9
|
+
return this.counter === context.counter;
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return `(${this.counter})`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.BreakOnCounter = BreakOnCounter;
|
|
16
|
+
class BreakOnEvent {
|
|
17
|
+
constructor(eventName) {
|
|
18
|
+
this.eventName = makeRegularExpression(eventName);
|
|
19
|
+
}
|
|
20
|
+
condition(context) {
|
|
21
|
+
return this.eventName.test(context.eventName);
|
|
22
|
+
}
|
|
23
|
+
toString() {
|
|
24
|
+
return this.eventName.toString();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.BreakOnEvent = BreakOnEvent;
|
|
28
|
+
class BreakOnLabel {
|
|
29
|
+
constructor(label) {
|
|
30
|
+
this.label = makeRegularExpression(label);
|
|
31
|
+
}
|
|
32
|
+
condition(context) {
|
|
33
|
+
if (!context.event)
|
|
34
|
+
return false;
|
|
35
|
+
return !![...context.event.codeObject.labels].find((label) => this.label.test(label));
|
|
36
|
+
}
|
|
37
|
+
toString() {
|
|
38
|
+
return this.label.toString();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.BreakOnLabel = BreakOnLabel;
|
|
42
|
+
class BreakOnCodeObject {
|
|
43
|
+
constructor(codeObject) {
|
|
44
|
+
this.codeObject = makeRegularExpression(codeObject);
|
|
45
|
+
}
|
|
46
|
+
condition(context) {
|
|
47
|
+
if (!context.event)
|
|
48
|
+
return false;
|
|
49
|
+
return this.codeObject.test(context.event.codeObject.fqid);
|
|
50
|
+
}
|
|
51
|
+
toString() {
|
|
52
|
+
return this.codeObject.toString();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.BreakOnCodeObject = BreakOnCodeObject;
|
|
56
|
+
function escapeRegexp(expr) {
|
|
57
|
+
return new RegExp(expr.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'));
|
|
58
|
+
}
|
|
59
|
+
function makeRegularExpression(expr) {
|
|
60
|
+
if (expr.length < 2)
|
|
61
|
+
return escapeRegexp(expr);
|
|
62
|
+
if (expr.startsWith('/') && expr.endsWith('/'))
|
|
63
|
+
return new RegExp(expr);
|
|
64
|
+
return escapeRegexp(expr);
|
|
65
|
+
}
|
|
@@ -22,11 +22,16 @@ const singleScan_1 = __importDefault(require("./singleScan"));
|
|
|
22
22
|
const watchScan_1 = __importDefault(require("./watchScan"));
|
|
23
23
|
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
24
24
|
const handleWorkingDirectory_1 = require("../handleWorkingDirectory");
|
|
25
|
+
const interactiveScan_1 = __importDefault(require("./interactiveScan"));
|
|
25
26
|
exports.default = {
|
|
26
27
|
command: 'scan',
|
|
27
28
|
describe: 'Scan AppMaps for code behavior findings',
|
|
28
29
|
builder(args) {
|
|
29
30
|
(0, scanArgs_1.default)(args);
|
|
31
|
+
args.option('interactive', {
|
|
32
|
+
describe: 'scan in interactive mode',
|
|
33
|
+
alias: 'i',
|
|
34
|
+
});
|
|
30
35
|
args.option('appmap-file', {
|
|
31
36
|
describe: 'single file to scan, or repeat this option to scan multiple specific files',
|
|
32
37
|
alias: 'f',
|
|
@@ -50,7 +55,7 @@ exports.default = {
|
|
|
50
55
|
handler(options) {
|
|
51
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
57
|
let { appmapDir } = options;
|
|
53
|
-
const { appmapFile,
|
|
58
|
+
const { appmapFile, directory, interactive, config: configFile, verbose: isVerbose, all: reportAllFindings, watch, app: appIdArg, apiKey, ide, reportFile, } = options;
|
|
54
59
|
if (isVerbose) {
|
|
55
60
|
(0, util_1.verbose)(true);
|
|
56
61
|
}
|
|
@@ -64,33 +69,38 @@ exports.default = {
|
|
|
64
69
|
if (reportAllFindings && watch) {
|
|
65
70
|
throw new errors_1.ValidationError(`Don't use --all with --watch, because in watch mode all findings are reported`);
|
|
66
71
|
}
|
|
67
|
-
if (appIdArg && watch) {
|
|
68
|
-
throw new errors_1.ValidationError(`Don't use --app with --watch, because in watch mode all findings are reported`);
|
|
69
|
-
}
|
|
70
72
|
if (!appmapFile && !appmapDir) {
|
|
71
73
|
appmapDir = (yield (0, appmapDirFromConfig_1.appmapDirFromConfig)()) || '.';
|
|
72
74
|
}
|
|
73
75
|
if (appmapDir)
|
|
74
76
|
yield (0, validateFile_1.default)('directory', appmapDir);
|
|
77
|
+
let appId = appIdArg;
|
|
78
|
+
if (!reportAllFindings)
|
|
79
|
+
appId = yield (0, resolveAppId_1.default)(appIdArg, appmapDir);
|
|
75
80
|
if (watch) {
|
|
76
81
|
const watchAppMapDir = appmapDir;
|
|
77
|
-
return (0, watchScan_1.default)({ appmapDir: watchAppMapDir, configFile
|
|
82
|
+
return (0, watchScan_1.default)({ appId, appmapDir: watchAppMapDir, configFile });
|
|
78
83
|
}
|
|
79
84
|
else {
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
85
|
+
const configuration = yield (0, configurationProvider_1.parseConfigFile)(configFile);
|
|
86
|
+
if (interactive) {
|
|
87
|
+
return (0, interactiveScan_1.default)({
|
|
88
|
+
appmapFile,
|
|
89
|
+
appmapDir,
|
|
90
|
+
configuration,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
return (0, singleScan_1.default)({
|
|
95
|
+
appmapFile,
|
|
96
|
+
appmapDir,
|
|
97
|
+
configuration,
|
|
98
|
+
reportAllFindings,
|
|
99
|
+
appId,
|
|
100
|
+
ide,
|
|
101
|
+
reportFile,
|
|
102
|
+
});
|
|
83
103
|
}
|
|
84
|
-
const configData = yield (0, configurationProvider_1.parseConfigFile)(config);
|
|
85
|
-
return (0, singleScan_1.default)({
|
|
86
|
-
appmapFile,
|
|
87
|
-
appmapDir,
|
|
88
|
-
configData,
|
|
89
|
-
reportAllFindings,
|
|
90
|
-
appId,
|
|
91
|
-
ide,
|
|
92
|
-
reportFile,
|
|
93
|
-
});
|
|
94
104
|
}
|
|
95
105
|
});
|
|
96
106
|
},
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
16
|
+
const util_1 = require("../../rules/lib/util");
|
|
17
|
+
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
18
|
+
const scanContext_1 = __importDefault(require("./ui/scanContext"));
|
|
19
|
+
const initial_1 = __importDefault(require("./ui/state/initial"));
|
|
20
|
+
function interactiveScan(options) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const { appmapFile, appmapDir, configuration } = options;
|
|
23
|
+
const checks = yield (0, configurationProvider_1.loadConfig)(configuration);
|
|
24
|
+
const files = yield (0, util_1.collectAppMapFiles)(appmapFile, appmapDir);
|
|
25
|
+
yield Promise.all(files.map((file) => __awaiter(this, void 0, void 0, function* () { return (0, validateFile_1.default)('file', file); })));
|
|
26
|
+
const context = new scanContext_1.default(checks, files);
|
|
27
|
+
let state = initial_1.default;
|
|
28
|
+
while (state) {
|
|
29
|
+
const newState = yield state(context);
|
|
30
|
+
state = newState;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
exports.default = interactiveScan;
|
|
@@ -12,10 +12,7 @@ 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 util_1 = require("util");
|
|
16
15
|
const promises_1 = require("fs/promises");
|
|
17
|
-
const glob_1 = require("glob");
|
|
18
|
-
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
19
16
|
const scanner_1 = __importDefault(require("./scanner"));
|
|
20
17
|
const errors_1 = require("../../errors");
|
|
21
18
|
const findings_1 = require("../../findings");
|
|
@@ -23,19 +20,14 @@ const findingsReport_1 = __importDefault(require("../../report/findingsReport"))
|
|
|
23
20
|
const summaryReport_1 = __importDefault(require("../../report/summaryReport"));
|
|
24
21
|
const formatReport_1 = require("./formatReport");
|
|
25
22
|
const telemetry_1 = __importDefault(require("../../telemetry"));
|
|
23
|
+
const util_1 = require("../../rules/lib/util");
|
|
24
|
+
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
26
25
|
function singleScan(options) {
|
|
27
26
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
-
const { appmapFile, appmapDir,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
files = yield glob(`${appmapDir}/**/*.appmap.json`);
|
|
33
|
-
}
|
|
34
|
-
if (appmapFile) {
|
|
35
|
-
files = typeof appmapFile === 'string' ? [appmapFile] : appmapFile;
|
|
36
|
-
yield Promise.all(files.map((file) => __awaiter(this, void 0, void 0, function* () { return (0, validateFile_1.default)('file', file); })));
|
|
37
|
-
}
|
|
38
|
-
const scanner = yield (0, scanner_1.default)(reportAllFindings, configData, files).catch((error) => {
|
|
27
|
+
const { appmapFile, appmapDir, configuration, reportAllFindings, appId, ide, reportFile } = options;
|
|
28
|
+
const files = yield (0, util_1.collectAppMapFiles)(appmapFile, appmapDir);
|
|
29
|
+
yield Promise.all(files.map((file) => __awaiter(this, void 0, void 0, function* () { return (0, validateFile_1.default)('file', file); })));
|
|
30
|
+
const scanner = yield (0, scanner_1.default)(reportAllFindings, configuration, files).catch((error) => {
|
|
39
31
|
throw new errors_1.ValidationError(error.message + '\nUse --all to perform an offline scan.');
|
|
40
32
|
});
|
|
41
33
|
const startTime = Date.now();
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const events_1 = __importDefault(require("events"));
|
|
16
|
+
class InteractiveProgress extends events_1.default {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.breakpoints = [];
|
|
20
|
+
this.depth = 0;
|
|
21
|
+
this.counter = 0;
|
|
22
|
+
this.initialize();
|
|
23
|
+
}
|
|
24
|
+
initialize() {
|
|
25
|
+
this.depth = 0;
|
|
26
|
+
this.counter = 0;
|
|
27
|
+
}
|
|
28
|
+
addBreakpoint(breakpoint) {
|
|
29
|
+
this.breakpoints.push(breakpoint);
|
|
30
|
+
}
|
|
31
|
+
removeBreakpoint(breakpoint) {
|
|
32
|
+
this.breakpoints = this.breakpoints.filter((b) => b !== breakpoint);
|
|
33
|
+
}
|
|
34
|
+
get prefix() {
|
|
35
|
+
const counterStr = `(${this.counter}) `;
|
|
36
|
+
return (counterStr + ' '.repeat(this.depth).padStart(10 + this.depth * 2 - counterStr.length, ' '));
|
|
37
|
+
}
|
|
38
|
+
resume() {
|
|
39
|
+
if (!this.breakpointResolver)
|
|
40
|
+
return;
|
|
41
|
+
this.breakpointResolver();
|
|
42
|
+
this.breakpointResolver = undefined;
|
|
43
|
+
}
|
|
44
|
+
breakOn(eventName, variables) {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const context = Object.assign({ eventName, appMap: this.appMap, appMapFileName: this.appMapFileName, check: this.check, scope: this.scope, counter: this.counter, depth: this.depth }, variables);
|
|
47
|
+
const hitBreakpoint = this.breakpoints.find((b) => b.condition(context));
|
|
48
|
+
if (!hitBreakpoint)
|
|
49
|
+
return;
|
|
50
|
+
this.emit('breakpoint', hitBreakpoint, context);
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
this.breakpointResolver = resolve;
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
beginAppMap(appMapFileName, appMap) {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
console.log(`${this.prefix}beginAppMap: ${appMapFileName}`);
|
|
59
|
+
this.depth += 1;
|
|
60
|
+
this.appMapFileName = appMapFileName;
|
|
61
|
+
this.appMap = appMap;
|
|
62
|
+
yield this.breakOn('beginAppMap', {});
|
|
63
|
+
this.counter += 1;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
beginCheck(check) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
console.log(`${this.prefix}beginCheck: ${check}`);
|
|
69
|
+
this.depth += 1;
|
|
70
|
+
this.check = check;
|
|
71
|
+
yield this.breakOn('beginCheck', {});
|
|
72
|
+
this.counter += 1;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
filterScope(scopeName, scope) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
console.log(`${this.prefix}filterScope: ${scopeName} ${scope}`);
|
|
78
|
+
yield this.breakOn('filterScope', {});
|
|
79
|
+
this.counter += 1;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
enterScope(scope) {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
console.log(`${this.prefix}enterScope: ${scope}`);
|
|
85
|
+
this.depth += 1;
|
|
86
|
+
this.scope = scope;
|
|
87
|
+
yield this.breakOn('enterScope', {});
|
|
88
|
+
this.counter += 1;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
filterEvent(event) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
console.log(`${this.prefix}filterEvent: ${event}`);
|
|
94
|
+
this.event = event;
|
|
95
|
+
yield this.breakOn('filterEvent', { event });
|
|
96
|
+
this.event = undefined;
|
|
97
|
+
this.counter += 1;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
matchResult(event, matchResult) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
console.log(`${this.prefix}matchResult: ${matchResult}`);
|
|
103
|
+
this.event = event;
|
|
104
|
+
yield this.breakOn('matchResult', { matchResult });
|
|
105
|
+
this.event = undefined;
|
|
106
|
+
this.counter += 1;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
matchEvent(event, _appMapIndex) {
|
|
110
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
111
|
+
console.log(`${this.prefix}matchEvent: ${event}`);
|
|
112
|
+
this.event = event;
|
|
113
|
+
yield this.breakOn('matchEvent', {});
|
|
114
|
+
this.event = undefined;
|
|
115
|
+
this.counter += 1;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
leaveScope() {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
this.depth -= 1;
|
|
121
|
+
console.log(`${this.prefix}leaveScope`);
|
|
122
|
+
yield this.breakOn('leaveScope', {});
|
|
123
|
+
this.scope = undefined;
|
|
124
|
+
this.counter += 1;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
endCheck() {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
this.depth -= 1;
|
|
130
|
+
console.log(`${this.prefix}endCheck`);
|
|
131
|
+
yield this.breakOn('endCheck', {});
|
|
132
|
+
this.check = undefined;
|
|
133
|
+
this.counter += 1;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
endAppMap() {
|
|
137
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
138
|
+
this.depth -= 1;
|
|
139
|
+
console.log(`${this.prefix}endAppMap`);
|
|
140
|
+
yield this.breakOn('endAppMap', {});
|
|
141
|
+
this.appMap = undefined;
|
|
142
|
+
this.appMapFileName = undefined;
|
|
143
|
+
this.counter += 1;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.default = InteractiveProgress;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const models_1 = require("@appland/models");
|
|
16
|
+
const console_1 = require("console");
|
|
17
|
+
const events_1 = __importDefault(require("events"));
|
|
18
|
+
const promises_1 = require("fs/promises");
|
|
19
|
+
const appMapIndex_1 = __importDefault(require("../../../appMapIndex"));
|
|
20
|
+
const ruleChecker_1 = __importDefault(require("../../../ruleChecker"));
|
|
21
|
+
const interactiveProgess_1 = __importDefault(require("./interactiveProgess"));
|
|
22
|
+
class ScanContext extends events_1.default {
|
|
23
|
+
constructor(checks, files) {
|
|
24
|
+
super();
|
|
25
|
+
this.checks = checks;
|
|
26
|
+
this.files = files;
|
|
27
|
+
this.isScanning = false;
|
|
28
|
+
this.progress = new interactiveProgess_1.default();
|
|
29
|
+
this.checker = new ruleChecker_1.default(this.progress);
|
|
30
|
+
this.progress.on('breakpoint', (breakpoint) => {
|
|
31
|
+
this.emit('breakpoint', breakpoint);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
scan() {
|
|
35
|
+
if (this.isScanning) {
|
|
36
|
+
this.progress.resume();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.progress.initialize();
|
|
40
|
+
this.doScan();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
doScan() {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
(0, console_1.assert)(!this.isScanning, 'Scanning already in progress');
|
|
46
|
+
this.isScanning = true;
|
|
47
|
+
const findings = [];
|
|
48
|
+
for (let fileIndex = 0; fileIndex < this.files.length; fileIndex++) {
|
|
49
|
+
const fileName = this.files[fileIndex];
|
|
50
|
+
const appMapData = yield (0, promises_1.readFile)(fileName, 'utf8');
|
|
51
|
+
const appMap = (0, models_1.buildAppMap)(appMapData).normalize().build();
|
|
52
|
+
const appMapIndex = new appMapIndex_1.default(appMap);
|
|
53
|
+
yield this.progress.beginAppMap(fileName, appMap);
|
|
54
|
+
for (let checkIndex = 0; checkIndex < this.checks.length; checkIndex++) {
|
|
55
|
+
const check = this.checks[checkIndex];
|
|
56
|
+
yield this.progress.beginCheck(check);
|
|
57
|
+
yield this.checker.check(fileName, appMapIndex, check, findings);
|
|
58
|
+
yield this.progress.endCheck();
|
|
59
|
+
}
|
|
60
|
+
yield this.progress.endAppMap();
|
|
61
|
+
}
|
|
62
|
+
this.isScanning = false;
|
|
63
|
+
this.emit('complete', findings);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.default = ScanContext;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const readline_1 = require("readline");
|
|
16
|
+
const breakpoint_1 = require("../../breakpoint");
|
|
17
|
+
const userInteraction_1 = __importDefault(require("../userInteraction"));
|
|
18
|
+
const scan_1 = __importDefault(require("./scan"));
|
|
19
|
+
const history = [];
|
|
20
|
+
function addBreakpoint(context) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const onCounter = () => __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
const { sequenceNumber } = yield userInteraction_1.default.prompt({
|
|
24
|
+
name: 'sequenceNumber',
|
|
25
|
+
type: 'number',
|
|
26
|
+
message: 'Sequence number:',
|
|
27
|
+
});
|
|
28
|
+
return new breakpoint_1.BreakOnCounter(Number(sequenceNumber));
|
|
29
|
+
});
|
|
30
|
+
const onEventName = () => __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
const { eventName } = yield userInteraction_1.default.prompt({
|
|
32
|
+
name: 'eventName',
|
|
33
|
+
type: 'input',
|
|
34
|
+
message: 'Event name:',
|
|
35
|
+
});
|
|
36
|
+
return new breakpoint_1.BreakOnEvent(eventName);
|
|
37
|
+
});
|
|
38
|
+
const onLabel = () => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
const { labelName } = yield userInteraction_1.default.prompt({
|
|
40
|
+
name: 'labelName',
|
|
41
|
+
type: 'input',
|
|
42
|
+
message: 'Event label:',
|
|
43
|
+
});
|
|
44
|
+
return new breakpoint_1.BreakOnLabel(labelName);
|
|
45
|
+
});
|
|
46
|
+
const onCodeObject = () => __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
let codeObjectName;
|
|
48
|
+
if (!context.progress.appMap) {
|
|
49
|
+
codeObjectName = (yield userInteraction_1.default.prompt({
|
|
50
|
+
name: 'codeObjectName',
|
|
51
|
+
type: 'input',
|
|
52
|
+
message: 'Code object:',
|
|
53
|
+
}))['codeObjectName'];
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
let codeObjectIds = [];
|
|
57
|
+
const collectCodeObjectNames = (codeObject) => {
|
|
58
|
+
codeObjectIds.push(codeObject.fqid);
|
|
59
|
+
};
|
|
60
|
+
context.progress.appMap.classMap.visit(collectCodeObjectNames);
|
|
61
|
+
codeObjectIds = codeObjectIds.sort();
|
|
62
|
+
const codeObjectCompleter = (line) => {
|
|
63
|
+
let options = codeObjectIds.filter((id) => id.startsWith(line));
|
|
64
|
+
if (options.length === 0)
|
|
65
|
+
options = codeObjectIds
|
|
66
|
+
.filter((id) => id.includes(line))
|
|
67
|
+
.map((id) => id.slice(id.indexOf(line)));
|
|
68
|
+
return [options, line];
|
|
69
|
+
};
|
|
70
|
+
codeObjectName = yield new Promise((resolve, _reject) => {
|
|
71
|
+
const rl = (0, readline_1.createInterface)({
|
|
72
|
+
input: process.stdin,
|
|
73
|
+
output: process.stdout,
|
|
74
|
+
completer: codeObjectCompleter,
|
|
75
|
+
history,
|
|
76
|
+
historySize: 1000,
|
|
77
|
+
removeHistoryDuplicates: true,
|
|
78
|
+
prompt: 'Code object: ',
|
|
79
|
+
tabSize: 4,
|
|
80
|
+
});
|
|
81
|
+
let response = '';
|
|
82
|
+
rl.on('line', (data) => {
|
|
83
|
+
response = data;
|
|
84
|
+
rl.close();
|
|
85
|
+
});
|
|
86
|
+
rl.on('close', () => {
|
|
87
|
+
resolve(response);
|
|
88
|
+
});
|
|
89
|
+
rl.prompt();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (codeObjectName && codeObjectName !== '')
|
|
93
|
+
return new breakpoint_1.BreakOnCodeObject(codeObjectName);
|
|
94
|
+
});
|
|
95
|
+
const choices = {
|
|
96
|
+
'break at sequence number': onCounter,
|
|
97
|
+
'break on label': onLabel,
|
|
98
|
+
'break on code object': onCodeObject,
|
|
99
|
+
'break on event name': onEventName,
|
|
100
|
+
quit: null,
|
|
101
|
+
};
|
|
102
|
+
userInteraction_1.default.progress(`Choose a breakpoint type, and enter the criteria.`);
|
|
103
|
+
userInteraction_1.default.progress(`NOTE: label, code object, and event name breakpoints can be regular expressions.`);
|
|
104
|
+
userInteraction_1.default.progress(` To enter a regular expression, use the syntax: /expr/`);
|
|
105
|
+
const { action: actionName } = yield userInteraction_1.default.prompt({
|
|
106
|
+
name: 'action',
|
|
107
|
+
type: 'list',
|
|
108
|
+
message: 'How would you like to proceed?:',
|
|
109
|
+
choices: Object.keys(choices),
|
|
110
|
+
});
|
|
111
|
+
const action = choices[actionName];
|
|
112
|
+
if (!action)
|
|
113
|
+
return scan_1.default;
|
|
114
|
+
const breakpoint = yield action();
|
|
115
|
+
if (breakpoint)
|
|
116
|
+
context.progress.addBreakpoint(breakpoint);
|
|
117
|
+
return scan_1.default;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
exports.default = addBreakpoint;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
16
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
17
|
+
const userInteraction_1 = __importDefault(require("../userInteraction"));
|
|
18
|
+
const hitBreakpoint_1 = __importDefault(require("./hitBreakpoint"));
|
|
19
|
+
const util_1 = require("util");
|
|
20
|
+
function initial(context) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const { expression } = yield userInteraction_1.default.prompt({
|
|
23
|
+
name: 'expression',
|
|
24
|
+
type: 'input',
|
|
25
|
+
message: 'Enter expression:',
|
|
26
|
+
});
|
|
27
|
+
let result;
|
|
28
|
+
try {
|
|
29
|
+
result = ((check, appMap, scope, event) => {
|
|
30
|
+
return eval(expression);
|
|
31
|
+
})(context.progress.check, context.progress.appMap, context.progress.scope, context.progress.event);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.log(err);
|
|
35
|
+
}
|
|
36
|
+
if (result)
|
|
37
|
+
console.log((0, util_1.inspect)(result));
|
|
38
|
+
return hitBreakpoint_1.default;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
exports.default = initial;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const userInteraction_1 = __importDefault(require("../userInteraction"));
|
|
16
|
+
const hitBreakpoint_1 = __importDefault(require("./hitBreakpoint"));
|
|
17
|
+
function hint(_context) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
userInteraction_1.default.progress([`Some suggested expressions:`, 'appMap', 'check', 'event', 'scope'].join('\n'));
|
|
20
|
+
return hitBreakpoint_1.default;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
exports.default = hint;
|