Skip to content

Commit

Permalink
Move "script parser" section to dedicated feature page to make entry …
Browse files Browse the repository at this point in the history
…files more accessible
  • Loading branch information
webpro committed Dec 4, 2023
1 parent 302798e commit c2ff2b3
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 69 deletions.
70 changes: 7 additions & 63 deletions packages/docs/src/content/docs/explanations/entry-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,70 +42,14 @@ The values you set override the default values, they are not merged.

## Scripts in package.json

The `main`, `bin`, `exports` and `scripts` fields may contain entry files. Let's
take a look at this example:
The `main`, `bin`, and `exports` fields may contain entry files. The `scripts`
are also parsed to find entry files and dependencies. See [Script Parser][2] for
more details.

```json title="package.json"
{
"name": "knip-example",
"main": "index.js",
"exports": {
"./lib": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"bin": {
"program": "bin/cli.js"
},
"scripts": {
"build": "bundle src/entry.ts",
"start": "node --loader tsx server.ts"
}
}
```

From this example, Knip automatically adds the following files as entry files:

- `index.js`
- `./dist/index.mjs`
- `./dist/index.cjs`
- `bin/cli.js`
- `src/entry.ts`
- `server.ts`

Knip respects `.gitignore` files and `ignore` config options. It would not add
the `exports` if the `dist` folder is matching a pattern in a relevant
`.gitignore` file or `ignore` option.

## Scripts in source code

When Knip is walking the abstract syntax trees (ASTs) of JavaScript and
TypeScript source code files, it looks for imports and exports. But there's a
few more (rather obscure) things that Knip detects in the process. Below are
examples of additional scripts Knip parses to find entry files and dependencies.

### execa

If the `execa` dependency is imported in source code, Knip considers the
contents of `$` template tags to be scripts:

```ts
await $({ stdio: 'inherit' })`c8 node hydrate.js`;
```

Parsing the script results in `hydrate.js` added as an entry file and the `c8`
dependency as referenced.

### zx

If the `zx` dependency is imported in source code, Knip considers the contents
of `$` template tags to be scripts:

```ts
await $`node scripts/parse.js`;
```
## Ignored Files

This will add `scripts/parse.js` as an entry file.
Knip respects `.gitignore` files and the `ignore` config option to prevent
matching files from being added as entry file.

[1]: ../overview/configuration.md#defaults
[2]: ../features/script-parser.md
14 changes: 10 additions & 4 deletions packages/docs/src/content/docs/explanations/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ sidebar:

## Introduction

This page describes why Knip uses plugins and their `config` and `entry`
options.
This page describes why Knip uses plugins and the difference between `config`
and `entry` files.

## Configuration Files

Expand All @@ -18,8 +18,8 @@ source files. However, configuration files often reference external dependencies
in different ways. Knip uses plugins to parse configuration files to find those
dependencies.

In this example we look at [Knip's ESLint plugin][2]. Its default `config`
includes `.eslintrc.json`. Here's a minimal example:
In this example we look at [Knip's ESLint plugin][2]. The default `config` file
patterns include `.eslintrc.json`. Here's a minimal example:

```json title=".eslintrc.json"
{
Expand All @@ -35,6 +35,9 @@ In this case, the plugin will return the `eslint-config-airbnb`,
`eslint-config-prettier` and `@typescript-eslint/eslint-plugin` dependencies, so
Knip knows they should be listed in `package.json`.

Some tools allow configuration to be stored in `package.json`, that's why some
the relevant plugins contain `package.json` in the list of `config` files.

:::tip[Summary]

`config` files are parsed by plugins to find external dependencies. Knip uses
Expand Down Expand Up @@ -154,6 +157,8 @@ jobs:
From these scripts, the `scripts/build.js` and `scripts/deploy.ts` files will be
added as entry files by the GitHub Actions plugin.

You can read more about this in [Script Parser][3].

### webpack

Let's take a look at this example webpack configuration file:
Expand Down Expand Up @@ -237,3 +242,4 @@ Plugins are configured with two distinct types of files:

[1]: ./entry-files.md
[2]: ../reference/plugins/eslint.md
[3]: ../features/script-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ Knip run faster). Example:
knip --workspace packages/my-lib
```

This mode includes ancestor and dependent workspaces, for two reasons:
This will include ancestor and dependent workspaces, for two reasons:

- Ancestor workspaces may contain dependencies the linted workspace uses.
- Ancestor workspaces may list dependencies in `package.json` the linted
workspace uses.
- Dependent workspaces may reference exports from the linted workspace.

To lint the workspace in isolation, you can combine this with [strict production
Expand Down
99 changes: 99 additions & 0 deletions packages/docs/src/content/docs/features/script-parser.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Script Parser
---

## Introduction

Knip parses scripts to find additional dependencies and entry files in various
places:

- In [`package.json`][1]
- In specific [`config` files][2]
- In [source code][3]

Any shell script Knip finds is read and statically analyzed, but not executed.

## package.json

The `main`, `bin`, `exports` and `scripts` fields may contain entry files. Let's
take a look at this example:

```json title="package.json"
{
"name": "my-package",
"main": "index.js",
"exports": {
"./lib": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
}
},
"bin": {
"program": "bin/cli.js"
},
"scripts": {
"build": "bundle src/entry.ts",
"start": "node --loader tsx server.ts"
}
}
```

From this example, Knip automatically adds the following files as entry files:

- `index.js`
- `./dist/index.mjs`
- `./dist/index.cjs`
- `bin/cli.js`
- `src/entry.ts`
- `server.ts`

By the way, Knip would not add the `exports` if the `dist` folder is matching a
pattern in a relevant `.gitignore` file or `ignore` option.

## Plugins

Some plugins also use the script parser to extract entry files and dependencies
from commands. A few examples:

- GitHub Actions: workflow files may contain `run` commands (e.g.
`.github/workflows/ci.yml`)
- Husky & Lefthook: Git hooks such as `.git/hooks/pre-push` contain scripts;
also `lefthook.yml` has `run` commands
- Lint Staged: configuration values are all commands
- Nx: task executors and `nx:run-commands` executors in `project.json` contains
scripts
- Release It: `hooks` contain commands

## Source Code

When Knip is walking the abstract syntax trees (ASTs) of JavaScript and
TypeScript source code files, it looks for imports and exports. But there's a
few more (rather obscure) things that Knip detects in the process. Below are
examples of additional scripts Knip parses to find entry files and dependencies.

### execa

If the `execa` dependency is imported in source code, Knip considers the
contents of `$` template tags to be scripts:

```ts
await $({ stdio: 'inherit' })`c8 node hydrate.js`;
```

Parsing the script results in `hydrate.js` added as an entry file and the `c8`
dependency as referenced.

### zx

If the `zx` dependency is imported in source code, Knip considers the contents
of `$` template tags to be scripts:

```ts
await $`node scripts/parse.js`;
```

This will add `scripts/parse.js` as an entry file.

[1]: #packagejson
[2]: #plugins
[3]: #source-code

0 comments on commit c2ff2b3

Please sign in to comment.