apotheke 0.0.1 → 0.1.1
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/LICENSE +21 -0
- package/README.md +37 -209
- package/SKILL.md +249 -0
- package/dist/cli.js +96 -90
- package/dist/index.d.ts +6 -5
- package/dist/index.js +160 -147
- package/package.json +65 -46
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marco Raffaello
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<p align="left">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/header/graph.svg?title=apotheke&subtitle=Deterministic%20import%20organization%20for%20JavaScript%20and%20TypeScript&logo=https://raw.githubusercontent.com/mRaffaello/apotheke/main/apps/docs/public/mark-dark.png&align=left&font=geist&mode=dark" />
|
|
4
|
+
<img alt="apotheke — deterministic import organization for JavaScript and TypeScript" src="https://shieldcn.dev/header/graph.svg?title=apotheke&subtitle=Deterministic%20import%20organization%20for%20JavaScript%20and%20TypeScript&logo=https://raw.githubusercontent.com/mRaffaello/apotheke/main/apps/docs/public/mark.png&align=left&font=geist&mode=light" />
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="left">
|
|
9
|
+
<a href="https://www.npmjs.com/package/apotheke">
|
|
10
|
+
<picture>
|
|
11
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/group/npm/apotheke+npm/dm/apotheke+bundlephobia/minzip/apotheke+npm/types/apotheke+github/ci/mRaffaello/apotheke+github/license/mRaffaello/apotheke.svg?variant=secondary&mode=dark" />
|
|
12
|
+
<img alt="npm version, monthly downloads, minzipped size, TypeScript types, CI status, MIT license" src="https://shieldcn.dev/group/npm/apotheke+npm/dm/apotheke+bundlephobia/minzip/apotheke+npm/types/apotheke+github/ci/mRaffaello/apotheke+github/license/mRaffaello/apotheke.svg?variant=secondary&mode=light" />
|
|
13
|
+
</picture>
|
|
14
|
+
</a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
**Prettier for imports.** You describe the groups your codebase actually has —
|
|
18
|
+
apotheke sorts every import into them, the same way, in every file. Run it as a
|
|
19
|
+
Prettier plugin or as a standalone CLI.
|
|
4
20
|
|
|
5
21
|
```ts
|
|
6
22
|
// Before
|
|
@@ -25,224 +41,36 @@ import { useQuery } from '@tanstack/react-query';
|
|
|
25
41
|
import { createRoute } from '@tanstack/react-router';
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
Note where `../api/tsr` and `@tanstack/react-query` landed: grouping is by
|
|
45
|
+
**role in your app**, not by whether a module is local or comes from
|
|
46
|
+
`node_modules`.
|
|
31
47
|
|
|
32
|
-
##
|
|
48
|
+
## Getting started
|
|
33
49
|
|
|
34
50
|
```sh
|
|
35
|
-
npm install -D apotheke
|
|
36
|
-
# or
|
|
37
51
|
pnpm add -D apotheke
|
|
38
52
|
```
|
|
39
53
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
apotheke --write src/**/*.{ts,tsx} # format in place
|
|
44
|
-
apotheke --check src/**/*.{ts,tsx} # CI — exit 1 if anything would change
|
|
45
|
-
apotheke --diff src/**/*.{ts,tsx} # print diff without writing
|
|
46
|
-
apotheke --stdin-filepath src/app.tsx # read from stdin, write to stdout
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Config
|
|
50
|
-
|
|
51
|
-
Create `apotheke.config.mjs` at your project root:
|
|
52
|
-
|
|
53
|
-
```js
|
|
54
|
-
// apotheke.config.mjs
|
|
55
|
-
export default {
|
|
56
|
-
groups: [
|
|
57
|
-
{ name: 'React', match: ['react', 'react-dom', 'react-*'] },
|
|
58
|
-
{ name: 'Hooks', match: ['**/hooks/**'] },
|
|
59
|
-
{ name: 'Api', match: ['**/api/**', '@tanstack/react-query'] },
|
|
60
|
-
{ name: 'Navigation', match: ['@tanstack/react-router'] },
|
|
61
|
-
{ name: 'Assets', match: ['lucide-react'] }
|
|
62
|
-
],
|
|
63
|
-
aliases: {
|
|
64
|
-
'@': './src' // mirrors tsconfig paths — auto-read if omitted
|
|
65
|
-
},
|
|
66
|
-
groupSeparator: true, // blank line between groups
|
|
67
|
-
groupComments: true // // GroupName header above each group
|
|
68
|
-
};
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Apotheke also reads `tsconfig.json` (or `jsconfig.json`) automatically to pick up `paths` aliases and `baseUrl`, so you often don't need to set `aliases` manually.
|
|
72
|
-
|
|
73
|
-
Unmatched imports collect in an **Others** group at the end. Side-effect imports (`import './styles.css'`) always go first.
|
|
74
|
-
|
|
75
|
-
### Monorepo
|
|
76
|
-
|
|
77
|
-
Place a root config and extend it per-package:
|
|
78
|
-
|
|
79
|
-
```js
|
|
80
|
-
// apps/web/apotheke.config.mjs
|
|
81
|
-
export default {
|
|
82
|
-
extends: '../../apotheke.config.mjs',
|
|
83
|
-
groups: [{ name: 'Shared', match: ['@acme/*'] }]
|
|
84
|
-
};
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## Prettier plugin
|
|
90
|
-
|
|
91
|
-
Apotheke ships as a prettier plugin. When loaded, it runs as a `preprocess` step — apotheke organises imports first, then prettier formats the result. One pass, correct order, no conflicts.
|
|
92
|
-
|
|
93
|
-
**Requirements:** Prettier v3 or later (v3 supports async `preprocess`; v2 does not).
|
|
94
|
-
|
|
95
|
-
### Permanent setup
|
|
96
|
-
|
|
97
|
-
**1. Install apotheke**
|
|
98
|
-
|
|
99
|
-
```sh
|
|
100
|
-
pnpm add -D apotheke
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**2. Add the plugin to your prettier config**
|
|
104
|
-
|
|
105
|
-
```js
|
|
106
|
-
// .prettierrc.js
|
|
107
|
-
module.exports = {
|
|
108
|
-
plugins: ['apotheke'],
|
|
109
|
-
};
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
That's it — `prettier --write` will now organise imports automatically.
|
|
113
|
-
|
|
114
|
-
### Quick test (without installing)
|
|
115
|
-
|
|
116
|
-
```sh
|
|
117
|
-
cd /path/to/your-project
|
|
118
|
-
npx prettier@3 \
|
|
119
|
-
--plugin /path/to/apotheke/dist/index.js \
|
|
120
|
-
--write 'src/App.tsx'
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### VS Code on-save
|
|
124
|
-
|
|
125
|
-
Install the [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extension. Because `prettier.format()` calls our plugin's `preprocess` hook directly, no extra config is needed:
|
|
126
|
-
|
|
127
|
-
```json
|
|
128
|
-
{
|
|
129
|
-
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
130
|
-
"editor.formatOnSave": true
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Pre-commit with Husky + lint-staged
|
|
135
|
-
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"lint-staged": {
|
|
139
|
-
"*.{ts,tsx,js,jsx}": ["prettier --write"]
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Prettier v2 fallback
|
|
54
|
+
📖 **[Read the documentation →](https://marcoraffaello.com/apotheke)**
|
|
145
55
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
```json
|
|
149
|
-
{
|
|
150
|
-
"lint-staged": {
|
|
151
|
-
"*.{ts,tsx,js,jsx}": [
|
|
152
|
-
"apotheke --write",
|
|
153
|
-
"prettier --write"
|
|
154
|
-
]
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
## Testing locally without publishing
|
|
162
|
-
|
|
163
|
-
### Option 1 — Direct invocation (no setup)
|
|
164
|
-
|
|
165
|
-
```sh
|
|
166
|
-
node /path/to/apotheke/dist/cli.js --write 'src/**/*.{ts,tsx}'
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
Build first if needed: `cd /path/to/apotheke && pnpm build`
|
|
170
|
-
|
|
171
|
-
### Option 2 — `pnpm link` (recommended)
|
|
172
|
-
|
|
173
|
-
**In the apotheke repo:**
|
|
174
|
-
|
|
175
|
-
```sh
|
|
176
|
-
pnpm build
|
|
177
|
-
pnpm link --global
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**In your target repo:**
|
|
181
|
-
|
|
182
|
-
```sh
|
|
183
|
-
pnpm link --global apotheke
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
Now `apotheke --write src/**/*.tsx` works as if it were installed normally. You'll need to re-run `pnpm build` in the apotheke repo after making source changes.
|
|
187
|
-
|
|
188
|
-
**To unlink when done:**
|
|
189
|
-
|
|
190
|
-
```sh
|
|
191
|
-
# In your target repo
|
|
192
|
-
pnpm unlink --global apotheke
|
|
193
|
-
|
|
194
|
-
# In the apotheke repo
|
|
195
|
-
pnpm unlink --global
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Option 3 — Path dependency in `package.json`
|
|
199
|
-
|
|
200
|
-
```sh
|
|
201
|
-
pnpm add /path/to/apotheke
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
---
|
|
56
|
+
The [quick start](https://marcoraffaello.com/apotheke/docs/quick-start) goes
|
|
57
|
+
from an empty config to organised imports in about two minutes.
|
|
205
58
|
|
|
206
59
|
## Development
|
|
207
60
|
|
|
61
|
+
This repository is a pnpm workspace. The published package lives in
|
|
62
|
+
`packages/apotheke`, the documentation site in `apps/docs`.
|
|
63
|
+
|
|
208
64
|
```sh
|
|
209
65
|
pnpm install
|
|
210
|
-
|
|
211
|
-
#
|
|
212
|
-
pnpm
|
|
213
|
-
|
|
214
|
-
# Run all tests (unit + e2e)
|
|
215
|
-
pnpm test
|
|
216
|
-
|
|
217
|
-
# Unit tests only
|
|
218
|
-
pnpm test:unit
|
|
219
|
-
|
|
220
|
-
# E2E tests against real repos (cloned automatically on first run)
|
|
221
|
-
pnpm test:e2e
|
|
222
|
-
|
|
223
|
-
# Type check
|
|
224
|
-
pnpm typecheck
|
|
66
|
+
pnpm build # build the package (required before format and dogfooding)
|
|
67
|
+
pnpm test # unit + e2e
|
|
68
|
+
pnpm docs:dev # run the documentation site locally
|
|
225
69
|
```
|
|
226
70
|
|
|
227
|
-
|
|
71
|
+
Issues and pull requests are welcome at
|
|
72
|
+
[github.com/mRaffaello/apotheke](https://github.com/mRaffaello/apotheke).
|
|
228
73
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
grouper.ts Glob-based group assignment
|
|
233
|
-
sorter.ts Alphabetical sort, type imports float to top
|
|
234
|
-
deduplicator.ts Merge named/default imports from same specifier
|
|
235
|
-
printer.ts Reconstruct import block with group headers
|
|
236
|
-
config.ts Load apotheke.config.mjs, merge tsconfig aliases
|
|
237
|
-
format.ts Top-level formatImports(source, config)
|
|
238
|
-
types.ts Shared types
|
|
239
|
-
cli.ts CLI source (Node.js)
|
|
240
|
-
index.ts Prettier plugin + programmatic API
|
|
241
|
-
dist/
|
|
242
|
-
cli.js Compiled CLI — run with node or via the apotheke bin
|
|
243
|
-
index.js Compiled prettier plugin
|
|
244
|
-
index.d.ts Types for programmatic use
|
|
245
|
-
tests/
|
|
246
|
-
unit/ 76 unit tests
|
|
247
|
-
e2e/ 20 e2e tests against sonner and tremor
|
|
248
|
-
```
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT © Marco Raffaello
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-apotheke
|
|
3
|
+
description: Set up apotheke import organizer in any JS/TS project. Scans existing imports, proposes group config, writes apotheke.config.mjs, and wires up prettier plugin. Use when user wants to organize imports, set up apotheke, or add import formatting to a project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Setup Apotheke
|
|
7
|
+
|
|
8
|
+
Apotheke is **Prettier for imports** — deterministic, configurable import organization for JavaScript and TypeScript. It is not a replacement for prettier: it runs *inside* prettier as a `preprocess` plugin, so imports get organized and code gets formatted in a single `prettier --write` pass. It also ships a standalone CLI for projects that do not use prettier.
|
|
9
|
+
|
|
10
|
+
This skill installs and configures it by analyzing the project's actual imports, then wiring it up as a prettier plugin.
|
|
11
|
+
|
|
12
|
+
Full documentation: <https://marcoraffaello.com/apotheke>
|
|
13
|
+
|
|
14
|
+
## Step 1 — Detect project structure (monorepo vs single package)
|
|
15
|
+
|
|
16
|
+
Before doing anything else, determine whether this is a monorepo. Check for these signals at the working directory root:
|
|
17
|
+
|
|
18
|
+
| File / field | Tool |
|
|
19
|
+
| ---------------------------------------- | ----------------------- |
|
|
20
|
+
| `pnpm-workspace.yaml` | pnpm workspaces |
|
|
21
|
+
| `turbo.json` | Turborepo |
|
|
22
|
+
| `nx.json` | Nx |
|
|
23
|
+
| `lerna.json` | Lerna |
|
|
24
|
+
| `rush.json` | Rush |
|
|
25
|
+
| `package.json` with `"workspaces"` field | npm/yarn/bun workspaces |
|
|
26
|
+
|
|
27
|
+
If any of these are present, it's a **monorepo**. Follow the monorepo path below. Otherwise follow the single-package path.
|
|
28
|
+
|
|
29
|
+
### Single-package path
|
|
30
|
+
|
|
31
|
+
Proceed to Step 2 with the repo root as the single package root.
|
|
32
|
+
|
|
33
|
+
### Monorepo path
|
|
34
|
+
|
|
35
|
+
1. Identify all package roots by reading the workspaces glob (e.g. `packages/*`, `apps/*`) from whichever workspace config is present. List them to the user.
|
|
36
|
+
2. Ask: "Should I set up a shared root config that all packages inherit from, or configure each package independently?"
|
|
37
|
+
- **Shared root** (recommended): write a root `apotheke.config.mjs` with groups common across all packages; each package gets its own config with `extends: "../../apotheke.config.mjs"` that overrides or adds package-specific groups.
|
|
38
|
+
- **Independent**: each package gets its own self-contained config with no inheritance.
|
|
39
|
+
3. Scan each package separately (Step 2 runs once per package root). Combine the findings to build the shared group set before writing configs.
|
|
40
|
+
4. In Step 6, add scripts to each package's `package.json` scoped to that package's source folder. Optionally add a root-level script that runs prettier across all packages.
|
|
41
|
+
|
|
42
|
+
## Step 2 — Scan the project
|
|
43
|
+
|
|
44
|
+
For each package root (or just the single root), search for all `.ts`, `.tsx`, `.js`, `.jsx` files (excluding `node_modules`, `dist`, `.next`, `build`, `out`). Read a sample of files (up to 20 per package, spread across the directory tree) and extract the unique import specifiers.
|
|
45
|
+
|
|
46
|
+
Pay attention to:
|
|
47
|
+
|
|
48
|
+
- **Package imports**: `react`, `@tanstack/react-query`, `lucide-react`, etc.
|
|
49
|
+
- **Path alias imports**: `@/components/...`, `~/lib/...`, `#utils/...`
|
|
50
|
+
- **Relative path patterns**: which folders appear most — `hooks/`, `api/`, `components/`, `views/`, `pages/`, `utils/`, `lib/`, `stores/`, etc.
|
|
51
|
+
- **tsconfig.json / jsconfig.json**: read `compilerOptions.paths` and `compilerOptions.baseUrl` to understand existing aliases. In a monorepo, check both the root tsconfig and each package's tsconfig.
|
|
52
|
+
|
|
53
|
+
## Step 3 — Check for existing config
|
|
54
|
+
|
|
55
|
+
Look for `apotheke.config.mjs`, `apotheke.config.js`, or `apotheke.config.ts` at each relevant root. If one already exists, read it, tell the user, and ask whether to update it or abort.
|
|
56
|
+
|
|
57
|
+
## Step 4 — Propose groups
|
|
58
|
+
|
|
59
|
+
Based on what you found, propose a `groups` array. Use your judgment to create meaningful groups. Common patterns:
|
|
60
|
+
|
|
61
|
+
- If the project uses React → group `react`, `react-dom`, `react-*`
|
|
62
|
+
> **Warning — `react-*` is greedy**: it will also match `react-hook-form`, `react-i18next`, `react-day-picker`, etc. Groups are matched in order and the first match wins. If you want those libraries in their own groups (Forms, i18n, Date), either list them in those groups _before_ the React group in the array, or narrow the React match to just `['react', 'react-dom']` without the wildcard.
|
|
63
|
+
- If the project has `hooks/` folder → group `**/hooks/**`
|
|
64
|
+
- If the project has `api/`, `services/`, `queries/` → group those paths + data-fetching libraries (react-query, swr, etc.)
|
|
65
|
+
- If the project has `components/`, `ui/` → group those
|
|
66
|
+
- If the project uses a router (react-router, tanstack-router, next/navigation) → group it
|
|
67
|
+
- If the project uses icon libraries (lucide-react, @heroicons, react-icons) → group as Assets
|
|
68
|
+
- If the project has a `store/`, `context/` folder → group it
|
|
69
|
+
- If the project uses a UI kit (@mui, @radix-ui, shadcn) → group it
|
|
70
|
+
- In a monorepo, internal workspace packages (e.g. `@acme/*`) deserve their own group
|
|
71
|
+
|
|
72
|
+
Always propose a sensible **alias map** based on tsconfig `paths`.
|
|
73
|
+
|
|
74
|
+
In a monorepo with a shared root config: put universal groups (React, external libraries) in the root config, and package-specific groups (internal paths, local components) in each package config.
|
|
75
|
+
|
|
76
|
+
Present the proposed config clearly and ask the user:
|
|
77
|
+
|
|
78
|
+
1. Are these groups right? Any to add, remove, or rename?
|
|
79
|
+
2. Is the order right? Groups are matched top-to-bottom and the first match wins.
|
|
80
|
+
3. Should there be blank lines between groups? (`groupSeparator`, default: yes)
|
|
81
|
+
4. Should group comments (`// React`) be added? (`groupComments`, default: yes)
|
|
82
|
+
|
|
83
|
+
Do **not** offer to toggle sorting or deduplication. Imports are always sorted
|
|
84
|
+
alphabetically within a group, named imports are always sorted within the
|
|
85
|
+
braces, and duplicate specifiers are always merged. There are no options for
|
|
86
|
+
these.
|
|
87
|
+
|
|
88
|
+
Wait for confirmation before proceeding.
|
|
89
|
+
|
|
90
|
+
## Step 5 — Write apotheke.config.mjs
|
|
91
|
+
|
|
92
|
+
**Always use `.mjs`** — it works with both the CLI and the Node.js prettier plugin. Never write `.ts` configs: Node.js (where prettier runs) cannot `import()` TypeScript files. Only `apotheke.config.mjs` and `apotheke.config.js` are discovered.
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
// apotheke.config.mjs
|
|
96
|
+
export default {
|
|
97
|
+
groups: [
|
|
98
|
+
// ... confirmed groups
|
|
99
|
+
],
|
|
100
|
+
aliases: {
|
|
101
|
+
// ... from tsconfig paths
|
|
102
|
+
},
|
|
103
|
+
groupSeparator: true,
|
|
104
|
+
groupComments: true
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For a monorepo with a shared root:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
// apps/web/apotheke.config.mjs
|
|
112
|
+
export default {
|
|
113
|
+
extends: '../../apotheke.config.mjs',
|
|
114
|
+
groups: [
|
|
115
|
+
// package-specific groups only — root groups are inherited
|
|
116
|
+
{ name: 'Local Components', match: ['**/components/**'] }
|
|
117
|
+
]
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Step 6 — Install apotheke and wire up prettier
|
|
122
|
+
|
|
123
|
+
### 6a. Install apotheke
|
|
124
|
+
|
|
125
|
+
Check if apotheke is already in `package.json` dependencies. If not, install it:
|
|
126
|
+
|
|
127
|
+
- Bun project (`bun.lock` present) → `bun add -D apotheke`
|
|
128
|
+
- pnpm (`pnpm-lock.yaml`) → `pnpm add -D apotheke`
|
|
129
|
+
- yarn (`yarn.lock`) → `yarn add -D apotheke`
|
|
130
|
+
- npm (`package-lock.json`) → `npm install -D apotheke`
|
|
131
|
+
|
|
132
|
+
In a monorepo, install at the root unless the workspace requires per-package installs.
|
|
133
|
+
|
|
134
|
+
### 6b. Add apotheke to the prettier config
|
|
135
|
+
|
|
136
|
+
Check for `.prettierrc`, `.prettierrc.js`, `.prettierrc.json`, or `prettier.config.js`. Add `"apotheke"` to the `plugins` array (create the file if none exists):
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
// prettier.config.js (or .prettierrc.js)
|
|
140
|
+
module.exports = {
|
|
141
|
+
// ...existing options unchanged...
|
|
142
|
+
plugins: ['apotheke']
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
For JSON prettier configs (`.prettierrc` or `.prettierrc.json`):
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"plugins": ["apotheke"]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> **Ordering is critical**: apotheke must be the **last** entry in `plugins`. It chains to the previous plugin's `preprocess` hook via `getBase()?.preprocess`, so any plugin listed after it will completely override apotheke's preprocess and imports will not be organized. If another prettier plugin (e.g. `prettier-plugin-tailwindcss`) is already present, place `"apotheke"` after it:
|
|
155
|
+
>
|
|
156
|
+
> ```json
|
|
157
|
+
> { "plugins": ["prettier-plugin-tailwindcss", "apotheke"] }
|
|
158
|
+
> ```
|
|
159
|
+
|
|
160
|
+
### 6c. Verify prettier version
|
|
161
|
+
|
|
162
|
+
Check that prettier v3 is installed (`"prettier": "^3"` in devDependencies). If v2 is found, tell the user:
|
|
163
|
+
|
|
164
|
+
> "Apotheke's prettier plugin requires prettier v3 (async `preprocess`). I can upgrade it, or set up the v2 fallback (CLI + prettier in sequence). Which do you prefer?"
|
|
165
|
+
|
|
166
|
+
**v2 fallback** (lint-staged only):
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"lint-staged": {
|
|
171
|
+
"*.{ts,tsx,js,jsx}": ["apotheke --write", "prettier --write"]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Step 7 — Add scripts to package.json
|
|
177
|
+
|
|
178
|
+
With the prettier plugin wired up, a single `prettier --write` does everything. Add:
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"scripts": {
|
|
183
|
+
"format": "prettier --write 'src/**/*.{ts,tsx,js,jsx}'",
|
|
184
|
+
"format:check": "prettier --check 'src/**/*.{ts,tsx,js,jsx}'"
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Adjust the glob to match the project's source folder. In a monorepo, also add a root script:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
{
|
|
193
|
+
"scripts": {
|
|
194
|
+
"format": "prettier --write 'packages/*/src/**/*.{ts,tsx}' 'apps/*/src/**/*.{ts,tsx}'",
|
|
195
|
+
"format:check": "prettier --check 'packages/*/src/**/*.{ts,tsx}' 'apps/*/src/**/*.{ts,tsx}'"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Step 8 — VS Code on-save (optional)
|
|
201
|
+
|
|
202
|
+
Ask the user: "Do you want imports organized automatically on save in VS Code?"
|
|
203
|
+
|
|
204
|
+
If yes, the prettier VS Code extension handles this automatically once the plugin is in the prettier config — no extra config needed. Confirm that the extension is installed and `editor.formatOnSave` is enabled:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
// .vscode/settings.json
|
|
208
|
+
{
|
|
209
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
210
|
+
"editor.formatOnSave": true,
|
|
211
|
+
"editor.codeActionsOnSave": {
|
|
212
|
+
"source.organizeImports": false
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Disable `source.organizeImports` to prevent VS Code's built-in import sorter from conflicting with apotheke.
|
|
218
|
+
|
|
219
|
+
## Step 9 — Run a dry-run
|
|
220
|
+
|
|
221
|
+
Run a true dry-run (no writes) on a small sample (3–5 files, one per package in a monorepo) and show the user what would change:
|
|
222
|
+
|
|
223
|
+
```sh
|
|
224
|
+
prettier --list-different 'src/App.tsx' 'src/main.tsx'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
> `--write --list-different` together would actually write the files; use `--list-different` alone for a real dry-run.
|
|
228
|
+
|
|
229
|
+
Show the before/after for imports to confirm the groups look right.
|
|
230
|
+
|
|
231
|
+
Ask: "Does this look right? Shall I run `format` on the whole project?"
|
|
232
|
+
|
|
233
|
+
If yes, run the `format` script using the package manager detected in Step 6a
|
|
234
|
+
(`pnpm run format`, `bun run format`, `yarn format` or `npm run format`).
|
|
235
|
+
|
|
236
|
+
## Final summary
|
|
237
|
+
|
|
238
|
+
Report:
|
|
239
|
+
|
|
240
|
+
- Project type: single-package or monorepo (list package roots if monorepo)
|
|
241
|
+
- Config(s) written to: paths
|
|
242
|
+
- Groups configured: list them
|
|
243
|
+
- Prettier plugin: wired up in `prettier.config.js` (or equivalent)
|
|
244
|
+
- Script added: `format` / `format:check`
|
|
245
|
+
- Files that would be changed: N files
|
|
246
|
+
- Whether `--write` was run
|
|
247
|
+
|
|
248
|
+
Point the user at the documentation for anything beyond this setup:
|
|
249
|
+
<https://marcoraffaello.com/apotheke>
|