Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lay out foundation for this project #16

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,20 @@ module.exports = {
overrides: [
{
files: ['*.ts'],
extends: ['@metamask/eslint-config-typescript'],
extends: [
'@metamask/eslint-config-typescript',
'@metamask/eslint-config-nodejs',
],
},

{
files: ['src/cli.ts'],
parserOptions: {
sourceType: 'script',
},
rules: {
'n/shebang': 'off',
},
},

{
Expand All @@ -32,5 +45,6 @@ module.exports = {
'dist/',
'docs/',
'.yarn/',
'tmp/',
],
};
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,6 @@ node_modules/
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# This project
tmp
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ npx @metamask/module-lint
- Install [Yarn v3](https://yarnpkg.com/getting-started/install)
- Run `yarn install` to install dependencies and run any required post-install scripts

### Running Locally

To run the tool locally, say:

```
yarn run-tool [OPTIONS] [ARGUMENTS...]
```

### Testing and Linting

Run `yarn test` to run the tests once. To run tests on file changes, run `yarn test:watch`.
Expand Down
14 changes: 7 additions & 7 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ module.exports = {
collectCoverage: true,

// An array of glob patterns indicating a set of files for which coverage information should be collected
collectCoverageFrom: ['./src/**/*.ts'],
collectCoverageFrom: [
'./src/**/*.ts',
'!./src/cli.ts',
'!./src/logging-utils.ts',
],

// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',

// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
coveragePathIgnorePatterns: ['/node_modules/', '/tmp'],

// Indicates which provider should be used to instrument code for coverage
coverageProvider: 'babel',
Expand Down Expand Up @@ -159,9 +161,7 @@ module.exports = {
// ],

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
testPathIgnorePatterns: ['/node_modules/', '/tmp'],

// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
Expand Down
20 changes: 19 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"types": "./dist/types/index.d.ts",
"bin": "./dist/cli.js",
"files": [
"dist/cjs/**",
"dist/esm/**",
Expand All @@ -44,9 +45,21 @@
"lint:fix": "yarn lint:eslint --fix && yarn lint:constraints --fix && yarn lint:misc --write && yarn lint:dependencies && yarn lint:changelog",
"lint:misc": "prettier '**/*.json' '**/*.md' '!CHANGELOG.md' '**/*.yml' '!.yarnrc.yml' --ignore-path .gitignore --no-error-on-unmatched-pattern",
"prepack": "./scripts/prepack.sh",
"run-tool": "ts-node --swc src/cli.ts",
"test": "jest && jest-it-up",
"test:watch": "jest --watch"
},
"resolutions": {
"@jridgewell/gen-mapping": "0.3.3"
},
"dependencies": {
"@metamask/utils": "^8.2.0",
"axios": "^1.5.1",
"chalk": "^4.1.2",
"dependency-graph": "^0.11.0",
"execa": "^5.1.1",
"yargs": "^17.7.2"
},
"devDependencies": {
"@lavamoat/allow-scripts": "^2.3.1",
"@lavamoat/preinstall-always-fail": "^1.0.0",
Expand All @@ -58,6 +71,7 @@
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.66",
"@types/jest": "^28.1.6",
"@types/jest-when": "^3.5.3",
"@types/node": "^16",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
Expand All @@ -72,9 +86,13 @@
"eslint-plugin-promise": "^6.1.1",
"jest": "^28.1.3",
"jest-it-up": "^2.0.2",
"jest-mock-extended": "^3.0.5",
"nock": "^13.3.4",
"prettier": "^2.7.1",
"prettier-plugin-packagejson": "^2.3.0",
"rimraf": "^3.0.2",
"rimraf": "^5.0.5",
"stdio-mock": "^1.2.0",
"strip-ansi": "^6.0.0",
"ts-jest": "^28.0.7",
"ts-node": "^10.7.0",
"typedoc": "^0.23.15",
Expand Down
136 changes: 136 additions & 0 deletions src/build-rule-tree.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import * as dependencyGraphModule from 'dependency-graph';

import { buildRuleTree } from './build-rule-tree';
import type { Rule } from './execute-rules';

jest.mock('dependency-graph', () => {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
__esModule: true,
...jest.requireActual('dependency-graph'),
};
});

describe('buildRuleTree', () => {
it('builds a nested data structure that starts with the rules that have no dependencies and navigates through their dependents recursively', () => {
const rule1: Rule = {
name: 'rule-1',
description: 'Description for rule 1',
dependencies: ['rule-2'],
execute: async () => {
return {
passed: true,
};
},
};
const rule2: Rule = {
name: 'rule-2',
description: 'Description for rule 2',
dependencies: ['rule-3'],
execute: async () => {
return {
passed: true,
};
},
};
const rule3: Rule = {
name: 'rule-3',
description: 'Description for rule 3',
dependencies: [],
execute: async () => {
return {
passed: true,
};
},
};
const rules = [rule1, rule2, rule3];

const ruleTree = buildRuleTree(rules);

expect(ruleTree).toStrictEqual({
children: [
{
rule: rule3,
children: [
{
rule: rule2,
children: [
{
rule: rule1,
children: [],
},
],
},
],
},
],
});
});

it('reinterprets a dependency cycle error from dep-graph if given a set of rules where a dependency cycle is present', () => {
const rule1: Rule = {
name: 'rule-1',
description: 'Description for rule 1',
dependencies: ['rule-2'],
execute: async () => {
return {
passed: false,
failures: [{ message: 'Oops' }],
};
},
};
const rule2: Rule = {
name: 'rule-2',
description: 'Description for rule 2',
dependencies: ['rule-3'],
execute: async () => {
return {
passed: true,
};
},
};
const rule3: Rule = {
name: 'rule-3',
description: 'Description for rule 3',
dependencies: ['rule-1'],
execute: async () => {
return {
passed: true,
};
},
};
const rules = [rule1, rule2, rule3];

expect(() => buildRuleTree(rules)).toThrow(
new Error(
`
Could not build rule tree as some rules depend on each other circularly:

- Rule "rule-1" depends on...
- Rule "rule-2", which depends on...
- Rule "rule-3", which depends on...
- Rule "rule-1" again (creating the cycle)
`.trim(),
),
);
});

it('re-throws any unknown if given a set of rules where a dependency cycle is present', () => {
const error = new Error('oops');
const depGraph = new dependencyGraphModule.DepGraph();
jest.spyOn(depGraph, 'overallOrder').mockImplementation(() => {
throw error;
});
jest.spyOn(dependencyGraphModule, 'DepGraph').mockReturnValue(depGraph);

expect(() => buildRuleTree([])).toThrow(error);
});

it('returns an empty root node if given no rules', () => {
const ruleTree = buildRuleTree([]);

expect(ruleTree).toStrictEqual({
children: [],
});
});
});
Loading