Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

[package-json-lint] Add new rule require-dependencies-declared-at-appropriate-level #710

Merged
merged 15 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from 12 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
3 changes: 3 additions & 0 deletions packages/package-json-lint-config-terra/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added new rule `require-dependencies-declared-at-appropriate-level`.

## 1.1.0 - (September 28, 2021)

* Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ module.exports = {
'require-no-hard-coded-dependency-versions': { severityType: 'error' },
'require-no-terra-base-peer-dependency-versions': { severityType: 'warn' },
'require-theme-context-versions': { severityType: 'warn' },
'require-dependencies-declared-at-appropriate-level': { severityType: 'warn' },
},
};
3 changes: 3 additions & 0 deletions packages/package-json-lint/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added new rule `require-dependencies-declared-at-appropriate-level`.

## 1.2.1 - (September 30, 2021)

* Changed
Expand Down
26 changes: 26 additions & 0 deletions packages/package-json-lint/src/rules/dev-dependency-set.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"devDependencySet": [
"@babel/cli",
"@babel/core",
"@babel/helpers",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-syntax-async-generators",
"@babel/plugin-transform-object-assign",
"@babel/plugin-transform-regenerator",
"@babel/plugin-transform-runtime",
"@babel/preset-env",
"@babel/preset-react",
"@babel/register",
"@cerner/browserslist-config-terra",
"@cerner/eslint-config-terra",
"@cerner/jest-config-terra",
"@cerner/stylelint-config-terra",
"@cerner/terra-aggregate-translations",
"@cerner/terra-cli",
"@cerner/terra-dev-site",
"@cerner/terra-functional-testing",
"@cerner/terra-open-source-scripts",
"@cerner/webpack-config-terra",
"jest"
]
}
4 changes: 3 additions & 1 deletion packages/package-json-lint/src/rules/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const requireThemeContextVersions = require('./require-theme-context-versions');
const requireNoTerraBasePeerDependencyVersions = require('./require-no-terra-base-peer-dependency-versions');
const requireDependenciesDeclaredAtAppropriateLevel = require('./require-dependencies-declared-at-appropriate-level');
const requireNoHardCodedDependencyVersions = require('./require-no-hard-coded-dependency-versions');

module.exports = {
'require-dependencies-declared-at-appropriate-level': requireDependenciesDeclaredAtAppropriateLevel,
'require-no-hard-coded-dependency-versions': requireNoHardCodedDependencyVersions,
'require-no-terra-base-peer-dependency-versions': requireNoTerraBasePeerDependencyVersions,
'require-theme-context-versions': requireThemeContextVersions,
'require-no-hard-coded-dependency-versions': requireNoHardCodedDependencyVersions,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const { devDependencySet } = require('./dev-dependency-set.json');

function findUnnecessaryDependency(rule, dependencies, dependencyType) {
const { ruleConfig, projectType, report } = rule;
const messageString = 'require-dependencies-declared-at-appropriate-level';
if (projectType !== 'devModule') {
const currentProblems = Object.keys(dependencies).map((dependency) => {
const dependencyVersion = dependencies[dependency];
if (devDependencySet.includes(dependency) && !(ruleConfig.severity.allowList && ruleConfig.severity.allowList.includes(dependency))) {
return `${dependency}@${dependencyVersion} does not satisfy requirement for ${messageString} rule.`;
}
return undefined;
}).filter(problem => !!problem);

if (currentProblems.length) {
let lintMessage;
if (dependencyType === 'dependency') {
lintMessage = `This project has unnecessary dependencies that violates the ${messageString} rule:\n ${currentProblems.join('\n ')}`;
} else if (dependencyType === 'peer') {
lintMessage = `This project has unnecessary peerDependencies that violates the ${messageString} rule:\n ${currentProblems.join('\n ')}`;
}
report({
lintId: messageString,
severity: ruleConfig.severity,
lintMessage,
projectType,
});
}
}
}

module.exports = {
create: ({
ruleConfig,
projectType,
report,
}) => ({
dependencies: (dependencies) => {
findUnnecessaryDependency({ ruleConfig, projectType, report }, dependencies, 'dependency');
},
peerDependencies: (peerDependencies) => {
findUnnecessaryDependency({ ruleConfig, projectType, report }, peerDependencies, 'peer');
},
}),
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = {
if (currentProblems.length) {
const lintMessage = `The dependencies for this project have hard-coded versions that violates the ${messageString} rule:\n ${currentProblems.join('\n ')}`;
report({
lintId: messageString, severity: ruleConfig.severity.severityType, lintMessage, projectType,
lintId: messageString, severity: ruleConfig.severity, lintMessage, projectType,
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`require-dependencies-declared-at-appropriate-level when projectType is application fails as a warning when there unnecessary dependencies/peerDependencies 1`] = `
Array [
Object {
"lintId": "require-dependencies-declared-at-appropriate-level",
"lintMessage": "This project has unnecessary dependencies that violates the require-dependencies-declared-at-appropriate-level rule:
@cerner/webpack-config-terra@^2.0.0 does not satisfy requirement for require-dependencies-declared-at-appropriate-level rule.",
"projectType": "application",
"severity": Object {
"severityType": "warn",
},
},
Object {
"lintId": "require-dependencies-declared-at-appropriate-level",
"lintMessage": "This project has unnecessary peerDependencies that violates the require-dependencies-declared-at-appropriate-level rule:
jest@^26.6.2 does not satisfy requirement for require-dependencies-declared-at-appropriate-level rule.",
"projectType": "application",
"severity": Object {
"severityType": "warn",
},
},
]
`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is application succeeds when there are no unnecessary dependencies/peerDependencies 1`] = `Array []`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is application succeeds when unnecessary dependencies/peerDependencies are passed in the allowList 1`] = `Array []`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is devModule succeeds when there no unnecessary dependencies/peerDependencies 1`] = `Array []`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is devModule succeeds when there unnecessary dependencies/peerDependencies 1`] = `Array []`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is module fails as a warning when there unnecessary dependencies/peerDependencies 1`] = `
Array [
Object {
"lintId": "require-dependencies-declared-at-appropriate-level",
"lintMessage": "This project has unnecessary peerDependencies that violates the require-dependencies-declared-at-appropriate-level rule:
jest@^26.6.2 does not satisfy requirement for require-dependencies-declared-at-appropriate-level rule.",
"projectType": "module",
"severity": Object {
"severityType": "warn",
},
},
]
`;

exports[`require-dependencies-declared-at-appropriate-level when projectType is module succeeds when there are no unnecessary dependencies/peerDependencies 1`] = `Array []`;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Object {
"lintMessage": "The dependencies for this project have hard-coded versions that violates the require-no-hard-coded-dependency-versions rule:
[email protected] does not satisfy requirement for the require-no-hard-coded-dependency-versions rule.",
"projectType": "devModule",
"severity": "error",
"severity": Object {
"severityType": "error",
},
}
`;

Expand All @@ -24,7 +26,9 @@ Object {
"lintMessage": "The dependencies for this project have hard-coded versions that violates the require-no-hard-coded-dependency-versions rule:
[email protected] does not satisfy requirement for the require-no-hard-coded-dependency-versions rule.",
"projectType": "module",
"severity": "error",
"severity": Object {
"severityType": "error",
},
}
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Object {
terra-action-footer@^1.0.0 does not satisfy range requirement for no terra base peer dependencies: terra-action-footer@>2.5.0",
"projectType": "module",
"severity": Object {
"severityType": "warning",
"severityType": "warn",
},
}
`;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
const requireDependenciesDeclaredAtAppropriateLevel = require('../../../src/rules/require-dependencies-declared-at-appropriate-level');

describe('require-dependencies-declared-at-appropriate-level', () => {
describe('when projectType is application', () => {
it('fails as a warning when there unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'application',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
'@cerner/webpack-config-terra': '^2.0.0',
});
rule.peerDependencies({
jest: '^26.6.2',
});
expect(results).toMatchSnapshot();
});
it('succeeds when there are no unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'application',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
classnames: '^2.2.5',
});
rule.peerDependencies({
react: '^16.8.5',
});
expect(results).toMatchSnapshot();
});
it('succeeds when unnecessary dependencies/peerDependencies are passed in the allowList', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
allowList: ['@cerner/webpack-config-terra', 'jest'],
},
},
projectType: 'application',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
'@cerner/webpack-config-terra': '^2.0.0',
});
rule.peerDependencies({
jest: '^26.6.2',
});
expect(results).toMatchSnapshot();
});
});

describe('when projectType is module', () => {
it('fails as a warning when there unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'module',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
webpack: '^4.30.0',
});
rule.peerDependencies({
jest: '^26.6.2',
});
expect(results).toMatchSnapshot();
});
it('succeeds when there are no unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'module',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
classnames: '^2.2.5',
});
rule.peerDependencies({
react: '^16.8.5',
});
expect(results).toMatchSnapshot();
});
});

describe('when projectType is devModule', () => {
it('succeeds when there unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'devModule',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
'@cerner/webpack-config-terra': '^2.0.0',
});
rule.peerDependencies({
jest: '^26.6.2',
});
expect(results).toMatchSnapshot();
});
it('succeeds when there no unnecessary dependencies/peerDependencies', () => {
const results = [];
const rule = requireDependenciesDeclaredAtAppropriateLevel.create({
ruleConfig: {
severity: {
severityType: 'warn',
},
},
projectType: 'devModule',
report: (issues) => {
results.push(issues);
},
});
rule.dependencies({
classnames: '^2.2.5',
});
rule.peerDependencies({
react: '^16.8.5',
});
expect(results).toMatchSnapshot();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('require-no-terra-base-peer-dependency-versions', () => {
requireNoTerraBasePeerDependencyVersions.create({
ruleConfig: {
severity: {
severityType: 'warning',
severityType: 'warn',
},
},
projectType: 'module',
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-toolkit-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added documentation for new rule `require-dependencies-declared-at-appropriate-level`.

## 2.5.2 - (September 30, 2021)

* Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Badge } from '@cerner/package-json-lint/package.json?dev-site-package';

| Rule Name | Severity Type | Description |
| --- | --- |--- |
| __require-dependencies-declared-at-appropriate-level__ | warn| Notifies when there are unnecessary dependencies and peerDependencies being passed in the package.json. Doesn't apply for devModule. |
pranav300 marked this conversation as resolved.
Show resolved Hide resolved
| __require-no-hard-coded-dependency-versions__ | error | Prevents hard-coded dependencies from being specified in the package.json. Only applies for module and devModule. |
| __require-no-terra-base-peer-dependency-versions__ | warn| Notifies when using terra packages that require terra-base as a peerDependency. |
| __require-theme-context-versions__ | warn| Notifies when using terra packages that don't use terra-theme-context as a dependency. |
| __require-theme-context-versions__ | warn| Notifies when using terra packages that don't use terra-theme-context as a dependency. |