x-fidelity 1.0.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/.czrc +3 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +28 -0
- package/.github/workflows/release.yml +34 -0
- package/.releaserc +11 -0
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +81 -0
- package/commitlint.config.js +3 -0
- package/dist/core/cli.js +37 -0
- package/dist/core/engine.js +67 -0
- package/dist/core/engine.test.js +79 -0
- package/dist/facts/repoDependencyFacts.js +105 -0
- package/dist/facts/repoDependencyFacts.test.js +149 -0
- package/dist/facts/repoFilesystemFacts.js +91 -0
- package/dist/index.js +35 -0
- package/dist/operators/currentDependencies.js +58 -0
- package/dist/operators/currentDependencies.test.js +43 -0
- package/dist/operators/directoryStructureMatches.js +63 -0
- package/dist/operators/directoryStructureMatches.test.js +61 -0
- package/dist/operators/fileContains.js +17 -0
- package/dist/operators/fileContains.test.js +25 -0
- package/dist/operators/index.js +11 -0
- package/dist/rules/index.js +61 -0
- package/dist/rules/noDatabases-rule.json +21 -0
- package/dist/rules/standardDirectoryStructure-rule.json +25 -0
- package/dist/rules/supportedCoreDependencies-rule.json +29 -0
- package/dist/typeDefs.js +2 -0
- package/dist/utils/logger.js +14 -0
- package/dist/xfidelity +35 -0
- package/jest.config.js +6 -0
- package/package.json +69 -0
- package/src/core/cli.ts +42 -0
- package/src/core/engine.test.ts +82 -0
- package/src/core/engine.ts +68 -0
- package/src/facts/repoDependencyFacts.test.ts +166 -0
- package/src/facts/repoDependencyFacts.ts +88 -0
- package/src/facts/repoFilesystemFacts.ts +80 -0
- package/src/index.ts +25 -0
- package/src/operators/currentDependencies.test.ts +45 -0
- package/src/operators/currentDependencies.ts +40 -0
- package/src/operators/directoryStructureMatches.test.ts +47 -0
- package/src/operators/directoryStructureMatches.ts +43 -0
- package/src/operators/fileContains.test.ts +27 -0
- package/src/operators/fileContains.ts +19 -0
- package/src/operators/index.ts +12 -0
- package/src/rules/index.ts +29 -0
- package/src/rules/noDatabases-rule.json +21 -0
- package/src/rules/standardDirectoryStructure-rule.json +25 -0
- package/src/rules/supportedCoreDependencies-rule.json +29 -0
- package/src/typeDefs.ts +40 -0
- package/src/utils/logger.ts +20 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,91 @@
|
|
|
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
|
+
exports.collectStandardDirectoryStructure = exports.collectRepoFileData = void 0;
|
|
16
|
+
const logger_1 = require("../utils/logger");
|
|
17
|
+
const axios_1 = __importDefault(require("axios"));
|
|
18
|
+
const fs_1 = __importDefault(require("fs"));
|
|
19
|
+
const path_1 = __importDefault(require("path"));
|
|
20
|
+
function parseFile(filePath) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
return Promise.resolve({
|
|
23
|
+
fileName: path_1.default.basename(filePath),
|
|
24
|
+
filePath,
|
|
25
|
+
fileContent: fs_1.default.readFileSync(filePath, 'utf8')
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function collectRepoFileData(repoPath) {
|
|
30
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
const filesData = [];
|
|
32
|
+
logger_1.logger.debug(`collectingRepoFileData from: ${repoPath}`);
|
|
33
|
+
const files = fs_1.default.readdirSync(repoPath);
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
const filePath = path_1.default.join(repoPath, file);
|
|
36
|
+
if (!ignored(filePath)) {
|
|
37
|
+
const stats = yield fs_1.default.promises.lstat(filePath);
|
|
38
|
+
if (stats.isDirectory()) {
|
|
39
|
+
const dirFilesData = yield collectRepoFileData(filePath);
|
|
40
|
+
filesData.push(...dirFilesData);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const fileData = yield parseFile(filePath);
|
|
44
|
+
filesData.push(fileData);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return filesData;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
exports.collectRepoFileData = collectRepoFileData;
|
|
52
|
+
function ignored(file) {
|
|
53
|
+
return file.startsWith('.')
|
|
54
|
+
|| file.includes('node_modules')
|
|
55
|
+
|| file.includes('/.')
|
|
56
|
+
|| file.endsWith('-rule.json')
|
|
57
|
+
|| file.includes('/dist/')
|
|
58
|
+
|| file.includes('/lcov')
|
|
59
|
+
|| file.startsWith('dist')
|
|
60
|
+
|| file.endsWith('md')
|
|
61
|
+
|| file.endsWith('.log')
|
|
62
|
+
|| file.includes('LICENSE');
|
|
63
|
+
}
|
|
64
|
+
const standardStructure = {
|
|
65
|
+
"src": {
|
|
66
|
+
"core": null,
|
|
67
|
+
"utils": null,
|
|
68
|
+
"operators": null,
|
|
69
|
+
"rules": null,
|
|
70
|
+
"facts": null,
|
|
71
|
+
"FAIL": null
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function collectStandardDirectoryStructure(configUrl) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
if (configUrl) {
|
|
77
|
+
try {
|
|
78
|
+
const response = yield axios_1.default.get(configUrl);
|
|
79
|
+
return response.data.standardStructure;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logger_1.logger.error(`Error fetching standard structure from configUrl: ${error}`);
|
|
83
|
+
return standardStructure;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
return standardStructure;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
exports.collectStandardDirectoryStructure = collectStandardDirectoryStructure;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const logger_1 = require("./utils/logger");
|
|
14
|
+
let json = require('format-json');
|
|
15
|
+
const cli_1 = require("./core/cli");
|
|
16
|
+
const engine_1 = require("./core/engine");
|
|
17
|
+
//console.log(`analyzing repo at path: [${options.dir}]`);
|
|
18
|
+
try {
|
|
19
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
let results = yield (0, engine_1.analyzeCodebase)(cli_1.options.dir, cli_1.options.configUrl);
|
|
21
|
+
if (results.length > 0) {
|
|
22
|
+
//console.log('WARNING: lo-fi attributes detected in codebase!');
|
|
23
|
+
//console.log(results);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
//console.log('hi-fi codebase detected!');
|
|
27
|
+
}
|
|
28
|
+
logger_1.logger.info(results);
|
|
29
|
+
console.log(JSON.stringify(results));
|
|
30
|
+
//console.log(`opinionated codebase analysis completed with ${results.length} failed checks.`);
|
|
31
|
+
}))().catch((e) => { console.log(e); });
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
console.log(e);
|
|
35
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.currentDependencies = void 0;
|
|
27
|
+
const logger_1 = require("../utils/logger");
|
|
28
|
+
const semver = __importStar(require("semver"));
|
|
29
|
+
const currentDependencies = {
|
|
30
|
+
'name': 'currentDependencies',
|
|
31
|
+
'fn': (filePath, dependencyData) => {
|
|
32
|
+
let result = false;
|
|
33
|
+
// this is a special rule we only run on the root package.json, however it checks the entire dependency tree.
|
|
34
|
+
if (filePath !== 'package.json') {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
logger_1.logger.debug(`currentDependencies: working..`);
|
|
38
|
+
try {
|
|
39
|
+
logger_1.logger.debug(`currentDependencies: processing ${dependencyData.installedDependencyVersions}`);
|
|
40
|
+
dependencyData.installedDependencyVersions.map((versionData) => {
|
|
41
|
+
logger_1.logger.debug(`currentDependencies: checking ${versionData.dep}`);
|
|
42
|
+
const requiredRange = new semver.Range(versionData.min);
|
|
43
|
+
if (!semver.gtr(versionData.ver, requiredRange)) {
|
|
44
|
+
let msg = `dependency ${versionData.dep} is outdated. Current version: ${versionData.ver}, required: ${versionData.min}`;
|
|
45
|
+
logger_1.logger.error(`currentDependencies: ${msg}`);
|
|
46
|
+
throw new Error(msg);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
result = true;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
result = false;
|
|
53
|
+
}
|
|
54
|
+
logger_1.logger.debug(`currentDependencies: ${result}`);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.currentDependencies = currentDependencies;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const logger_1 = require("../utils/logger");
|
|
4
|
+
const currentDependencies_1 = require("./currentDependencies");
|
|
5
|
+
describe('currentDependencies', () => {
|
|
6
|
+
it('returns true when filePath is not package.json', () => {
|
|
7
|
+
const filePath = 'notPackage.json';
|
|
8
|
+
const dependencyData = {};
|
|
9
|
+
expect(currentDependencies_1.currentDependencies.fn(filePath, JSON.stringify(dependencyData))).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
it('returns true when all dependencies are up-to-date', () => {
|
|
12
|
+
const filePath = 'package.json';
|
|
13
|
+
const dependencyData = {
|
|
14
|
+
installedDependencyVersions: [
|
|
15
|
+
{ dep: 'dep1', ver: '2.0.0', min: '1.0.0' },
|
|
16
|
+
{ dep: 'dep2', ver: '3.0.0', min: '2.0.0' }
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
expect(currentDependencies_1.currentDependencies.fn(filePath, dependencyData)).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('returns false when at least one dependency is outdated', () => {
|
|
22
|
+
const filePath = 'package.json';
|
|
23
|
+
const dependencyData = {
|
|
24
|
+
installedDependencyVersions: [
|
|
25
|
+
{ dep: 'dep1', ver: '.0.0', min: '1.0.0' },
|
|
26
|
+
{ dep: 'dep2', ver: '1.0.0', min: '2.0.0' }
|
|
27
|
+
]
|
|
28
|
+
};
|
|
29
|
+
expect(currentDependencies_1.currentDependencies.fn(filePath, dependencyData)).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
it('logs an error when at least one dependency is outdated', () => {
|
|
32
|
+
const filePath = 'package.json';
|
|
33
|
+
const dependencyData = {
|
|
34
|
+
installedDependencyVersions: [
|
|
35
|
+
{ dep: 'dep1', ver: '1.0.0', min: '1.0.0' },
|
|
36
|
+
{ dep: 'dep2', ver: '1.0.0', min: '2.0.0' }
|
|
37
|
+
]
|
|
38
|
+
};
|
|
39
|
+
const errorSpy = jest.spyOn(logger_1.logger, 'error');
|
|
40
|
+
currentDependencies_1.currentDependencies.fn(filePath, dependencyData);
|
|
41
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.directoryStructureMatches = void 0;
|
|
27
|
+
const logger_1 = require("../utils/logger");
|
|
28
|
+
const path = __importStar(require("path"));
|
|
29
|
+
const fs = __importStar(require("fs"));
|
|
30
|
+
let hasChecked = false;
|
|
31
|
+
const directoryStructureMatches = {
|
|
32
|
+
'name': 'directoryStructureMatches',
|
|
33
|
+
'fn': (filePath, standardStructure) => {
|
|
34
|
+
if (filePath !== 'yarn.lock' || hasChecked) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
const repoPath = path.dirname(filePath);
|
|
38
|
+
let result = true;
|
|
39
|
+
// check the directory structure of the repo against the standard structure
|
|
40
|
+
function checkStructure(currentPath, structure) {
|
|
41
|
+
for (const key in structure) {
|
|
42
|
+
const newPath = path.join(currentPath, key);
|
|
43
|
+
logger_1.logger.debug(`checking ${newPath}`);
|
|
44
|
+
if (!fs.existsSync(newPath) || !fs.lstatSync(newPath).isDirectory()) {
|
|
45
|
+
logger_1.logger.debug(`Missing or invalid directory: ${newPath}`);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
result = checkStructure(newPath, structure[key]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
const checkResult = checkStructure(repoPath, standardStructure);
|
|
55
|
+
//console.log(checkResult)
|
|
56
|
+
if (!checkResult) {
|
|
57
|
+
result = false;
|
|
58
|
+
}
|
|
59
|
+
hasChecked = true;
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
exports.directoryStructureMatches = directoryStructureMatches;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const path = __importStar(require("path"));
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
28
|
+
const directoryStructureMatches_1 = require("./directoryStructureMatches");
|
|
29
|
+
jest.mock('fs');
|
|
30
|
+
jest.mock('path');
|
|
31
|
+
describe('directoryStructureMatches', () => {
|
|
32
|
+
const mockedFs = fs;
|
|
33
|
+
const mockedPath = path;
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
mockedFs.existsSync.mockReset();
|
|
36
|
+
mockedFs.lstatSync.mockReset();
|
|
37
|
+
mockedPath.dirname.mockReset();
|
|
38
|
+
mockedPath.join.mockReset();
|
|
39
|
+
});
|
|
40
|
+
it('should return true if filePath is not "yarn.lock" or hasChecked is true', () => {
|
|
41
|
+
const result = directoryStructureMatches_1.directoryStructureMatches.fn('notYarn.lock', {});
|
|
42
|
+
expect(result).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
// ...
|
|
45
|
+
it('should return true if directory structure matches the standard structure', () => {
|
|
46
|
+
mockedPath.dirname.mockReturnValue('/repo');
|
|
47
|
+
mockedPath.join.mockImplementation((...args) => args.join('/'));
|
|
48
|
+
mockedFs.existsSync.mockReturnValue(true);
|
|
49
|
+
mockedFs.lstatSync.mockReturnValue({ isDirectory: () => true });
|
|
50
|
+
const result = directoryStructureMatches_1.directoryStructureMatches.fn('yarn.lock', { dir1: null, dir2: { subdir1: null } });
|
|
51
|
+
expect(result).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
// it('should return false if directory structure does not match the standard structure', () => {
|
|
54
|
+
// mockedPath.dirname.mockReturnValue('/repo');
|
|
55
|
+
// mockedPath.join.mockImplementation((...args) => args.join('/'));
|
|
56
|
+
// mockedFs.existsSync.mockReturnValue(false);
|
|
57
|
+
// mockedFs.lstatSync.mockReturnValue({ isDirectory: () => false } as Stats);
|
|
58
|
+
// const result = directoryStructureMatches.fn('yarn.lock', { dir1: null, dir2: { subdir1: null } });
|
|
59
|
+
// expect(result).toBe(false);
|
|
60
|
+
// });
|
|
61
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fileContains = void 0;
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
|
+
const fileContains = {
|
|
6
|
+
'name': 'fileContains',
|
|
7
|
+
'fn': (fileContent, checkString) => {
|
|
8
|
+
let result = false;
|
|
9
|
+
const regex = new RegExp(checkString, 'g');
|
|
10
|
+
if (regex.test(fileContent)) {
|
|
11
|
+
result = true;
|
|
12
|
+
}
|
|
13
|
+
logger_1.logger.debug(`fileContains '${checkString}': ${result}`);
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
exports.fileContains = fileContains;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fileContains_1 = require("./fileContains");
|
|
4
|
+
describe('fileContains', () => {
|
|
5
|
+
it('returns true when the checkString is found in the fileContent', () => {
|
|
6
|
+
const fileContent = 'Hello, world!';
|
|
7
|
+
const checkString = 'world';
|
|
8
|
+
expect(fileContains_1.fileContains.fn(fileContent, checkString)).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
it('returns false when the checkString is not found in the fileContent', () => {
|
|
11
|
+
const fileContent = 'Hello, world!';
|
|
12
|
+
const checkString = 'universe';
|
|
13
|
+
expect(fileContains_1.fileContains.fn(fileContent, checkString)).toBe(false);
|
|
14
|
+
});
|
|
15
|
+
it('returns true when the checkString is a regular expression that matches part of the fileContent', () => {
|
|
16
|
+
const fileContent = 'Hello, world!';
|
|
17
|
+
const checkString = '\\bworld\\b';
|
|
18
|
+
expect(fileContains_1.fileContains.fn(fileContent, checkString)).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
it('returns false when the checkString is a regular expression that does not match any part of the fileContent', () => {
|
|
21
|
+
const fileContent = 'Hello, world!';
|
|
22
|
+
const checkString = '\\buniverse\\b';
|
|
23
|
+
expect(fileContains_1.fileContains.fn(fileContent, checkString)).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.operators = void 0;
|
|
4
|
+
const currentDependencies_1 = require("./currentDependencies");
|
|
5
|
+
const fileContains_1 = require("./fileContains");
|
|
6
|
+
const directoryStructureMatches_1 = require("./directoryStructureMatches");
|
|
7
|
+
let operators = [];
|
|
8
|
+
exports.operators = operators;
|
|
9
|
+
operators.push(currentDependencies_1.currentDependencies);
|
|
10
|
+
operators.push(fileContains_1.fileContains);
|
|
11
|
+
operators.push(directoryStructureMatches_1.directoryStructureMatches);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.loadRules = void 0;
|
|
36
|
+
const logger_1 = require("../utils/logger");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
let rules = [];
|
|
40
|
+
// import each json file in local directory and add to rules array as a RuleProperties object
|
|
41
|
+
function loadRules() {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
logger_1.logger.debug(`loading json rules..`);
|
|
44
|
+
const ruleFiles = (yield fs.promises.readdir(__dirname)).filter(file => file.endsWith('.json'));
|
|
45
|
+
logger_1.logger.debug(`found ${ruleFiles.length} rule files to load.`);
|
|
46
|
+
const rules = yield Promise.all(ruleFiles.map((file) => __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
try {
|
|
48
|
+
logger_1.logger.debug(`loading ${file}...`);
|
|
49
|
+
const rule = yield Promise.resolve(`${path.join(__dirname, file)}`).then(s => __importStar(require(s)));
|
|
50
|
+
return rule;
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
logger_1.logger.error(`FATAL: Error loading rule file: ${file}`);
|
|
54
|
+
logger_1.logger.error(e);
|
|
55
|
+
console.error(e);
|
|
56
|
+
}
|
|
57
|
+
})));
|
|
58
|
+
return rules;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
exports.loadRules = loadRules;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "noDatabases",
|
|
3
|
+
"conditions": {
|
|
4
|
+
"not": {
|
|
5
|
+
"any": [
|
|
6
|
+
{
|
|
7
|
+
"fact": "fileData",
|
|
8
|
+
"path": "$.fileContent",
|
|
9
|
+
"operator": "fileContains",
|
|
10
|
+
"value": "oracle"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"event": {
|
|
16
|
+
"type": "violation",
|
|
17
|
+
"params": {
|
|
18
|
+
"message": "noDatabases: code must not directly call databases"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "standardDirectoryStructure",
|
|
3
|
+
"conditions": {
|
|
4
|
+
"all": [
|
|
5
|
+
{
|
|
6
|
+
"fact": "fileData",
|
|
7
|
+
"path": "$.filePath",
|
|
8
|
+
"operator": "directoryStructureMatches",
|
|
9
|
+
"value": {
|
|
10
|
+
"fact": "standardStructure"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"event": {
|
|
16
|
+
"type": "violation",
|
|
17
|
+
"params": {
|
|
18
|
+
"message": "The directory structure does not match the standard.",
|
|
19
|
+
"details": {
|
|
20
|
+
"fact": "fileData",
|
|
21
|
+
"path": "$.filePath"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "supportedCoreDependencies",
|
|
3
|
+
"conditions": {
|
|
4
|
+
"all": [
|
|
5
|
+
{
|
|
6
|
+
"fact": "fileData",
|
|
7
|
+
"path": "$.filePath",
|
|
8
|
+
"operator": "currentDependencies",
|
|
9
|
+
"value": {
|
|
10
|
+
"fact": "dependencyData"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"event": {
|
|
16
|
+
"type": "violation",
|
|
17
|
+
"params": {
|
|
18
|
+
"message": "some important dependencies have expired!",
|
|
19
|
+
"filePath": {
|
|
20
|
+
"fact": "fileData",
|
|
21
|
+
"path": "$.filePath"
|
|
22
|
+
},
|
|
23
|
+
"minimumDependencyVersions": {
|
|
24
|
+
"fact": "dependencyData",
|
|
25
|
+
"path": "$.minimumDependencyVersions"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/typeDefs.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
const winston_1 = require("winston");
|
|
5
|
+
const logger = (0, winston_1.createLogger)({
|
|
6
|
+
level: 'debug',
|
|
7
|
+
format: winston_1.format.combine(winston_1.format.timestamp({
|
|
8
|
+
format: 'YYYY-MM-DD HH:mm:ss.SSS ZZ'
|
|
9
|
+
}), winston_1.format.errors({ stack: true }), winston_1.format.splat(), winston_1.format.json(), winston_1.format.prettyPrint()),
|
|
10
|
+
transports: [
|
|
11
|
+
new winston_1.transports.File({ filename: 'x-fidelity.log' })
|
|
12
|
+
]
|
|
13
|
+
});
|
|
14
|
+
exports.logger = logger;
|
package/dist/xfidelity
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const logger_1 = require("./utils/logger");
|
|
14
|
+
let json = require('format-json');
|
|
15
|
+
const cli_1 = require("./core/cli");
|
|
16
|
+
const engine_1 = require("./core/engine");
|
|
17
|
+
//console.log(`analyzing repo at path: [${options.dir}]`);
|
|
18
|
+
try {
|
|
19
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
let results = yield (0, engine_1.analyzeCodebase)(cli_1.options.dir, cli_1.options.configUrl);
|
|
21
|
+
if (results.length > 0) {
|
|
22
|
+
//console.log('WARNING: lo-fi attributes detected in codebase!');
|
|
23
|
+
//console.log(results);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
//console.log('hi-fi codebase detected!');
|
|
27
|
+
}
|
|
28
|
+
logger_1.logger.info(results);
|
|
29
|
+
console.log(JSON.stringify(results));
|
|
30
|
+
//console.log(`opinionated codebase analysis completed with ${results.length} failed checks.`);
|
|
31
|
+
}))().catch((e) => { console.log(e); });
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
console.log(e);
|
|
35
|
+
}
|