Skip to content

Commit

Permalink
Manifest reference instead of the data itself (#14)
Browse files Browse the repository at this point in the history
* Implementation draft (issue with mocking in tests).

* The funny way to mock in the tests.

* Adjusting integration test.

* rm redundant import int test.

* Moving the sample file into a nested dir.

* rm empty options.

* Customizing it() instead of beforeEach.

* Using customized test runner.

* Minor ref.

* Fix int test command.

* Using custom it() with lookup to custom scenarios on before().

* Better class Runner.

* Ref: naming and shortening.

* Fix usage of title.

* REF: using ctx.cwd as the default package dir.

* Ref: extracting for neatness.

* mv runner to tools.

* Ref: shortening.

* Ref: extracting types and helpers.

* mv test-runner dir.

* Fix restore usage of helpers and types.

* Minor naming.

* Readme: updating documentation.

* Note on dir.

* notice on excluding tests.

* rm intro, redundant now.

* rm redundant beforeAll.

* Apply suggestions from code review

* rm redundant type.

* Ref: simpler isInvalid implementation.

* Ref: simpler type for isInvalid.

* even more.

* toCases().

* Changelog: 0.4.0.

* 0.4.0-beta.1

* Instructions on absolute path.

* add prefixes.
  • Loading branch information
Anna Bocharova authored Aug 10, 2024
1 parent ce41777 commit 0b21e34
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 192 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ jobs:
run: yarn
- name: Test
working-directory: integration-test
run: yarn eslint sample.ts --debug
run: yarn eslint src/sample.ts --debug
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Version 0

### v0.4.0

- Breaking changes:
- The `manifest` option replaced with `packageDir` (string, optional);
- The default value is the ESLint `process.cwd()`;
- The plugin can now read the `package.json` itself;
- The plugin can now operate without options.

### v0.3.1

- Integration test and this changelog added;
Expand Down
85 changes: 54 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,12 @@ yarn add --dev eslint-plugin-allowed-dependencies

## Setup

Example of plugin setup and different ways to provide `package.json` data to it:

```javascript
// eslint.config.js or .mjs if you're developing in CommonJS environment
import jsPlugin from "@eslint/js";
import tsPlugin from "typescript-eslint";
import allowedDepsPlugin from "eslint-plugin-allowed-dependencies";

// For Node 18 and 20:
import manifest from "./package.json" assert { type: "json" };

// For Node 22:
// import manifest from "./package.json" with { type: "json" };

// For all those versions and the environments having no JSON import support:
// import { readFileSync } from "node:fs";
// const manifest = JSON.parse(readFileSync("./package.json", "utf8"));

export default [
{
plugins: {
Expand All @@ -59,36 +47,50 @@ export default [
{
files: ["src/**/*.ts"], // implies that "src" only contains the sources
rules: {
"allowed/dependencies": [
"error",
{
manifest, // these are defaults:
/*
production: true,
requiredPeers: true,
optionalPeers: "typeOnly",
typeOnly: [],
ignore: ["^\\.", "^node:"]
*/
},
],
"allowed/dependencies": "error",
},
},
// In case "src" also contains tests:
// {
// files: ["src/**/*.spec.ts"], // exclude test files
// rules: { "allowed/dependencies": "off" },
// },
];
```

# Configuration

## Options

By default, the plugin is configured to check source code: production dependencies and mandatory peers are allowed to
import, but optional peers are allowed to be imported only as types.
Supply the options this way:

```json5
{
rules: {
"allowed/dependencies": [
"error", // these are defaults:
{
packageDir: ".",
production: true,
requiredPeers: true,
optionalPeers: "typeOnly",
typeOnly: [],
ignore: ["^\\.", "^node:"],
},
],
},
}
```

By default, the plugin is configured for checking the source code based on the `package.json` located in the current
working directory of the ESLint process. Production dependencies and mandatory peers are allowed to import,
but optional peers are allowed to be imported only as types.

```yaml
manifest:
description: Your package.json data, required
type: object
required: true
packageDir:
description: The path having your package.json
type: string
default: ctx.cwd # ESLint process.cwd()

production:
description: Allow importing the packages listed in manifest.dependencies
Expand Down Expand Up @@ -123,3 +125,24 @@ ignore:
- "^\\." # relative paths (starts with a dot)
- "^node:" # built-in modules (prefixed with "node:")
```
## packageDir option
If you're using workspaces or somehow running ESLint from different locations, you'd need an absolute path:
```javascript
// for CommonJS:
const options = {
packageDir: __dirname,
};
```

```javascript
// for ESM:
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";

const options = {
packageDir: dirname(fileURLToPath(import.meta.url)),
};
```
11 changes: 2 additions & 9 deletions integration-test/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { readFileSync } from "node:fs";
import jsPlugin from "@eslint/js";
import allowedDepsPlugin from "eslint-plugin-allowed-dependencies";
import tsPlugin from "typescript-eslint";
Expand All @@ -13,15 +12,9 @@ export default [
...tsPlugin.configs.recommended,
// For the sources:
{
files: ["*.ts"], // implies that "src" only contains the sources
files: ["src/*.ts"],
rules: {
"allowed/dependencies": [
"error",
{
manifest: JSON.parse(readFileSync("package.json", "utf8")),
typeOnly: ["typescript"],
},
],
"allowed/dependencies": ["error", { typeOnly: ["typescript"] }],
},
},
];
File renamed without changes.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "eslint-plugin-allowed-dependencies",
"description": "ESLint plugin Allowed Dependencies",
"version": "0.3.1",
"version": "0.4.0-beta.1",
"module": "src/index.ts",
"type": "module",
"main": "dist/index.cjs",
Expand Down
20 changes: 3 additions & 17 deletions src/__snapshots__/schema.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@ exports[`Schema options has the required props 1`] = `
},
"type": "array",
},
"manifest": {
"properties": {
"dependencies": {
"type": "object",
},
"peerDependencies": {
"type": "object",
},
"peerDependenciesMeta": {
"type": "object",
},
},
"type": "object",
},
"optionalPeers": {
"oneOf": [
{
Expand All @@ -38,6 +24,9 @@ exports[`Schema options has the required props 1`] = `
},
],
},
"packageDir": {
"type": "string",
},
"production": {
"oneOf": [
{
Expand Down Expand Up @@ -71,9 +60,6 @@ exports[`Schema options has the required props 1`] = `
"type": "array",
},
},
"required": [
"manifest",
],
"type": "object",
}
`;
5 changes: 5 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { readFileSync } from "node:fs";
import { join as joinPath } from "node:path";
import { flow, join, split, startsWith, take } from "ramda";

/** is scoped import: starts with "at" */
Expand All @@ -6,3 +8,6 @@ const hasScope = startsWith("@");
/** gets the dependency name even when importing its internal path */
export const getName = (imp: string) =>
flow(imp, [split("/"), take(hasScope(imp) ? 2 : 1), join("/")]);

export const getManifest = (path: string) =>
JSON.parse(readFileSync(joinPath(path, "package.json"), "utf8"));
Loading

0 comments on commit 0b21e34

Please sign in to comment.