itty-packager 1.0.0 → 1.0.2
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/README.md +219 -0
- package/bin/itty.js +8 -1
- package/eslint.config.mjs +26 -0
- package/lib/builder.js +2 -2
- package/lib/commands/build.js +9 -10
- package/lib/commands/lint.js +174 -0
- package/lib/commands/publish.js +368 -0
- package/lib/configs/createConfig.mjs +101 -0
- package/lib/configs/eslint.config.mjs +3 -0
- package/lib/configs/eslint.config.template.mjs +30 -0
- package/package.json +25 -4
package/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
<br />
|
|
2
|
+
|
|
3
|
+
<p>
|
|
4
|
+
<a href="https://itty.dev/itty-packager" target="_blank">
|
|
5
|
+
<img src="https://github.com/user-attachments/assets/placeholder-image" alt="itty-packager" height="120" />
|
|
6
|
+
</a>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
[](https://npmjs.com/package/itty-packager)
|
|
10
|
+
[](https://deno.bundlejs.com/?q=itty-packager)
|
|
11
|
+
[](https://coveralls.io/github/kwhitley/itty-packager)
|
|
12
|
+
[](https://github.com/kwhitley/itty-packager/issues)
|
|
13
|
+
[](https://discord.gg/53vyrZAu9u)
|
|
14
|
+
|
|
15
|
+
### [Documentation](https://itty.dev) | [Discord](https://discord.gg/53vyrZAu9u)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Universal toolkit for itty libraries
|
|
20
|
+
|
|
21
|
+
Zero-config build, lint, and publish workflows for TypeScript libraries.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **🔨 Build** - TypeScript compilation with Rollup, minification, and snippet generation
|
|
26
|
+
- **🔍 Lint** - Built-in ESLint configuration with TypeScript support and smart extending
|
|
27
|
+
- **📦 Publish** - Automated version bumping, clean package extraction, and npm publishing
|
|
28
|
+
- **⚡ Zero Config** - Works out of the box, customize only what you need
|
|
29
|
+
- **🎯 Consistent** - Unified tooling across all itty projects
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install --save-dev itty-packager
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
Add to your `package.json` scripts:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "itty build",
|
|
45
|
+
"lint": "itty lint",
|
|
46
|
+
"publish": "itty publish"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
### `itty build`
|
|
54
|
+
|
|
55
|
+
Build your TypeScript library with Rollup, TypeScript compilation, and optional minification.
|
|
56
|
+
|
|
57
|
+
**Usage:** `itty build [options]`
|
|
58
|
+
|
|
59
|
+
**Options:**
|
|
60
|
+
- `-f, --from <dir>` - Source directory (default: `src`)
|
|
61
|
+
- `-o, --out <dir>` - Output directory (default: `dist`)
|
|
62
|
+
- `-c, --copy <files>` - Files to copy to output (comma-separated)
|
|
63
|
+
- `--sourcemap` - Generate source maps (default: `false`)
|
|
64
|
+
- `--hybrid` - Build both ESM and CJS (default: ESM only)
|
|
65
|
+
- `--minify` - Minify output with terser (default: `true`)
|
|
66
|
+
- `--no-minify` - Skip minification
|
|
67
|
+
- `-s, --snippet <name>` - Generate snippet file for README injection
|
|
68
|
+
- `-h, --help` - Show help
|
|
69
|
+
|
|
70
|
+
**Default Behavior:**
|
|
71
|
+
- Compiles all TypeScript files from `src/` to `dist/`
|
|
72
|
+
- Generates ESM (`.mjs`) output only
|
|
73
|
+
- Minifies output by default
|
|
74
|
+
- Updates `package.json` exports with correct paths
|
|
75
|
+
- Single file exports map to root export, multiple files get individual exports
|
|
76
|
+
|
|
77
|
+
**Examples:**
|
|
78
|
+
```bash
|
|
79
|
+
itty build # Basic ESM build, minified
|
|
80
|
+
itty build --hybrid --sourcemap # Build both ESM/CJS with sourcemaps
|
|
81
|
+
itty build --snippet=connect # Build with snippet generation for README
|
|
82
|
+
itty build --from=lib --out=build # Build from lib/ to build/
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `itty lint`
|
|
86
|
+
|
|
87
|
+
Lint your code with ESLint using built-in TypeScript configuration or your local config.
|
|
88
|
+
|
|
89
|
+
**Usage:** `itty lint [files/directories] [options]`
|
|
90
|
+
|
|
91
|
+
**Options:**
|
|
92
|
+
- `--fix` - Automatically fix problems
|
|
93
|
+
- `--max-warnings <n>` - Number of warnings to trigger nonzero exit code
|
|
94
|
+
- `-q, --quiet` - Report errors only
|
|
95
|
+
- `-f, --format <format>` - Output format (stylish, compact, json, etc.)
|
|
96
|
+
- `-h, --help` - Show help
|
|
97
|
+
|
|
98
|
+
**Default Behavior:**
|
|
99
|
+
- Uses built-in TypeScript ESLint config if no local config found
|
|
100
|
+
- Lints entire project excluding `node_modules/`, `dist/`, `build/`, `coverage/`
|
|
101
|
+
- Local configs (`.eslintrc.*`, `eslint.config.*`) override built-in config
|
|
102
|
+
- All ESLint dependencies provided by itty-packager
|
|
103
|
+
|
|
104
|
+
**Config Extension:**
|
|
105
|
+
Create `eslint.config.mjs` to extend the built-in config:
|
|
106
|
+
```javascript
|
|
107
|
+
import { createConfig } from 'itty-packager/lib/configs/createConfig.mjs'
|
|
108
|
+
|
|
109
|
+
export default createConfig({
|
|
110
|
+
rules: {
|
|
111
|
+
'no-console': 'off', // Project-specific overrides
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Examples:**
|
|
117
|
+
```bash
|
|
118
|
+
itty lint # Lint entire project with smart exclusions
|
|
119
|
+
itty lint src # Lint only src directory
|
|
120
|
+
itty lint --fix # Lint and auto-fix issues
|
|
121
|
+
itty lint --format=json # Output results in JSON format
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `itty publish`
|
|
125
|
+
|
|
126
|
+
Version bump and publish your package to npm with clean, flat package structure.
|
|
127
|
+
|
|
128
|
+
**Usage:** `itty publish [options]`
|
|
129
|
+
|
|
130
|
+
**Version Options (default: patch):**
|
|
131
|
+
- `--major` - Major release X.#.# for breaking changes
|
|
132
|
+
- `--minor` - Minor release #.X.# for feature additions
|
|
133
|
+
- `--patch` - Patch release #.#.X for bug fixes (default)
|
|
134
|
+
- `--type <type>` - Custom release type (alpha, beta, rc, etc.)
|
|
135
|
+
|
|
136
|
+
**Publish Options:**
|
|
137
|
+
- `--src <dir>` - Source directory to publish from (default: `dist`)
|
|
138
|
+
- `--dest <dir>` - Temporary directory for publishing (default: `.dist`)
|
|
139
|
+
- `--dry-run` - Build and prepare but do not publish
|
|
140
|
+
- `--no-cleanup` - Leave temporary directory after publishing
|
|
141
|
+
- `--public` - Publish as public package (`--access=public`)
|
|
142
|
+
- `--no-license` - Do not copy LICENSE file to published package
|
|
143
|
+
- `--no-changelog` - Do not copy CHANGELOG.md file to published package
|
|
144
|
+
|
|
145
|
+
**Git Options:**
|
|
146
|
+
- `--tag` - Create git tag for release
|
|
147
|
+
- `--push` - Push changes and tags to git remote
|
|
148
|
+
- `--no-git` - Skip all git operations
|
|
149
|
+
|
|
150
|
+
**Default Behavior:**
|
|
151
|
+
- Defaults to patch version bump if no type specified
|
|
152
|
+
- Extracts build artifacts to temporary directory
|
|
153
|
+
- Copies root files: `README.md`, `LICENSE`, `CHANGELOG.md`, `.npmrc` (if they exist)
|
|
154
|
+
- Transforms package.json paths (e.g., `./dist/file.mjs` → `./file.mjs`)
|
|
155
|
+
- Creates clean, flat package structure in node_modules
|
|
156
|
+
|
|
157
|
+
**Examples:**
|
|
158
|
+
```bash
|
|
159
|
+
itty publish # Patch bump and publish from dist/ (default)
|
|
160
|
+
itty publish --minor --tag # Minor bump, publish, and create git tag
|
|
161
|
+
itty publish --type=alpha # Pre-release alpha version
|
|
162
|
+
itty publish --dry-run # Test the publish process
|
|
163
|
+
itty publish --no-license # Publish without copying LICENSE file
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Package Structure
|
|
167
|
+
|
|
168
|
+
The publish command creates a clean package structure by:
|
|
169
|
+
|
|
170
|
+
1. **Extracting build artifacts** from your `dist/` directory to package root
|
|
171
|
+
2. **Copying essential files** like README, LICENSE, CHANGELOG
|
|
172
|
+
3. **Transforming paths** in package.json to point to root-level files
|
|
173
|
+
4. **Publishing the clean structure** so users get flat imports
|
|
174
|
+
|
|
175
|
+
**Before (in your project):**
|
|
176
|
+
```
|
|
177
|
+
package.json exports: "./dist/connect.mjs"
|
|
178
|
+
dist/connect.mjs
|
|
179
|
+
README.md
|
|
180
|
+
LICENSE
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**After (in node_modules):**
|
|
184
|
+
```
|
|
185
|
+
package.json exports: "./connect.mjs"
|
|
186
|
+
connect.mjs
|
|
187
|
+
README.md
|
|
188
|
+
LICENSE
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Configuration
|
|
192
|
+
|
|
193
|
+
### ESLint
|
|
194
|
+
|
|
195
|
+
The built-in ESLint config includes:
|
|
196
|
+
- TypeScript support with `@typescript-eslint`
|
|
197
|
+
- Sensible defaults for itty projects
|
|
198
|
+
- Unix line endings, single quotes, no semicolons
|
|
199
|
+
- Disabled rules: `no-empty-function`, `no-explicit-any`, `ban-types`, `ban-ts-comment`
|
|
200
|
+
|
|
201
|
+
Override by creating `eslint.config.mjs` in your project root.
|
|
202
|
+
|
|
203
|
+
### Package.json
|
|
204
|
+
|
|
205
|
+
Add itty-packager to your scripts for easy access:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"scripts": {
|
|
210
|
+
"build": "itty build --snippet=mylib --hybrid",
|
|
211
|
+
"lint": "itty lint",
|
|
212
|
+
"publish": "itty publish --tag --push"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
package/bin/itty.js
CHANGED
|
@@ -4,8 +4,9 @@ import { parseArgs } from 'node:util'
|
|
|
4
4
|
|
|
5
5
|
const subcommands = {
|
|
6
6
|
build: () => import('../lib/commands/build.js').then(m => m.buildCommand),
|
|
7
|
+
lint: () => import('../lib/commands/lint.js').then(m => m.lintCommand),
|
|
8
|
+
publish: () => import('../lib/commands/publish.js').then(m => m.publishCommand),
|
|
7
9
|
// Future subcommands can be added here:
|
|
8
|
-
// release: () => import('../lib/commands/release.js').then(m => m.releaseCommand),
|
|
9
10
|
// deploy: () => import('../lib/commands/deploy.js').then(m => m.deployCommand),
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -71,6 +72,8 @@ Usage: itty <subcommand> [options]
|
|
|
71
72
|
|
|
72
73
|
Subcommands:
|
|
73
74
|
build Build your library with rollup and typescript
|
|
75
|
+
lint Lint your code with ESLint
|
|
76
|
+
publish Version and publish your package to npm
|
|
74
77
|
|
|
75
78
|
Global Options:
|
|
76
79
|
-h, --help Show help
|
|
@@ -79,6 +82,10 @@ Global Options:
|
|
|
79
82
|
Examples:
|
|
80
83
|
itty build --snippet=connect --hybrid # Build with snippet and CJS support
|
|
81
84
|
itty build --sourcemap --no-minify # Build with sourcemaps, no minification
|
|
85
|
+
itty lint # Lint entire project (smart exclusions)
|
|
86
|
+
itty lint src # Lint only the src directory
|
|
87
|
+
itty lint --fix # Lint and fix issues automatically
|
|
88
|
+
itty publish --patch # Version bump and publish from dist/
|
|
82
89
|
itty build --help # Show build-specific help
|
|
83
90
|
|
|
84
91
|
Run 'itty <subcommand> --help' for subcommand-specific options.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createConfig } from './lib/configs/createConfig.mjs'
|
|
2
|
+
|
|
3
|
+
export default createConfig({
|
|
4
|
+
rules: {
|
|
5
|
+
// Allow console statements in CLI tools
|
|
6
|
+
'no-console': 'off',
|
|
7
|
+
|
|
8
|
+
// Allow process global in Node.js CLI
|
|
9
|
+
'no-undef': 'off',
|
|
10
|
+
|
|
11
|
+
// Allow useless escapes in regex patterns
|
|
12
|
+
'no-useless-escape': 'off',
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
languageOptions: {
|
|
16
|
+
globals: {
|
|
17
|
+
// Node.js globals
|
|
18
|
+
process: 'readonly',
|
|
19
|
+
console: 'readonly',
|
|
20
|
+
Buffer: 'readonly',
|
|
21
|
+
__dirname: 'readonly',
|
|
22
|
+
__filename: 'readonly',
|
|
23
|
+
global: 'readonly',
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
package/lib/builder.js
CHANGED
|
@@ -14,7 +14,7 @@ export async function build(options = {}) {
|
|
|
14
14
|
const {
|
|
15
15
|
from = 'src',
|
|
16
16
|
out = 'dist',
|
|
17
|
-
copy: copyFiles
|
|
17
|
+
copy: copyFiles,
|
|
18
18
|
snippet,
|
|
19
19
|
sourcemap = false,
|
|
20
20
|
hybrid = false,
|
|
@@ -207,7 +207,7 @@ async function injectSnippet(snippetName, outDir) {
|
|
|
207
207
|
if (await fs.pathExists(readmePath)) {
|
|
208
208
|
const readme = await fs.readFile(readmePath, 'utf-8')
|
|
209
209
|
const newReadme = readme.replace(
|
|
210
|
-
/(<!-- BEGIN SNIPPET -->[\r\n]+```(?:js|ts)[\r\n]).*?([\r\n]
|
|
210
|
+
/(<!-- BEGIN SNIPPET -->[\r\n]+```(?:js|ts)[\r\n]?).*?([\r\n]?```[\r\n]+<!-- END SNIPPET -->)/s,
|
|
211
211
|
`$1${transformed}$2`
|
|
212
212
|
)
|
|
213
213
|
|
package/lib/commands/build.js
CHANGED
|
@@ -5,11 +5,6 @@ export async function buildCommand(args) {
|
|
|
5
5
|
const { values: buildArgs } = parseArgs({
|
|
6
6
|
args,
|
|
7
7
|
options: {
|
|
8
|
-
snippet: {
|
|
9
|
-
type: 'string',
|
|
10
|
-
short: 's',
|
|
11
|
-
description: 'Generate snippet file for README injection'
|
|
12
|
-
},
|
|
13
8
|
from: {
|
|
14
9
|
type: 'string',
|
|
15
10
|
short: 'f',
|
|
@@ -25,8 +20,7 @@ export async function buildCommand(args) {
|
|
|
25
20
|
copy: {
|
|
26
21
|
type: 'string',
|
|
27
22
|
short: 'c',
|
|
28
|
-
|
|
29
|
-
description: 'Files to copy to output (default: LICENSE)'
|
|
23
|
+
description: 'Files to copy to output (comma-separated)'
|
|
30
24
|
},
|
|
31
25
|
sourcemap: {
|
|
32
26
|
type: 'boolean',
|
|
@@ -44,6 +38,11 @@ export async function buildCommand(args) {
|
|
|
44
38
|
type: 'boolean',
|
|
45
39
|
description: 'Skip minification'
|
|
46
40
|
},
|
|
41
|
+
snippet: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
short: 's',
|
|
44
|
+
description: 'Generate snippet file for README injection'
|
|
45
|
+
},
|
|
47
46
|
help: {
|
|
48
47
|
type: 'boolean',
|
|
49
48
|
short: 'h',
|
|
@@ -60,22 +59,22 @@ itty build - Build your library with rollup and typescript
|
|
|
60
59
|
Usage: itty build [options]
|
|
61
60
|
|
|
62
61
|
Options:
|
|
63
|
-
-s, --snippet <name> Generate snippet file for README injection
|
|
64
62
|
-f, --from <dir> Source directory (default: src)
|
|
65
63
|
-o, --out <dir> Output directory (default: dist)
|
|
66
|
-
-c, --copy <files> Files to copy to output (
|
|
64
|
+
-c, --copy <files> Files to copy to output (comma-separated)
|
|
67
65
|
--sourcemap Generate source maps (default: false)
|
|
68
66
|
--hybrid Build both ESM and CJS (default: ESM only)
|
|
69
67
|
--minify Minify output with terser (default: true)
|
|
70
68
|
--no-minify Skip minification
|
|
69
|
+
-s, --snippet <name> Generate snippet file for README injection
|
|
71
70
|
-h, --help Show help
|
|
72
71
|
|
|
73
72
|
Examples:
|
|
74
73
|
itty build # Build ESM only, minified, no sourcemaps
|
|
75
|
-
itty build --snippet=connect # Build with connect snippet generation
|
|
76
74
|
itty build --hybrid --sourcemap # Build both ESM/CJS with sourcemaps
|
|
77
75
|
itty build --no-minify # Build without minification
|
|
78
76
|
itty build --from=lib --out=build # Build from lib/ to build/
|
|
77
|
+
itty build --snippet=connect # Build with connect snippet generation
|
|
79
78
|
`)
|
|
80
79
|
return
|
|
81
80
|
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
8
|
+
const __dirname = path.dirname(__filename)
|
|
9
|
+
|
|
10
|
+
export async function lintCommand(args) {
|
|
11
|
+
const { values: lintArgs, positionals } = parseArgs({
|
|
12
|
+
args,
|
|
13
|
+
options: {
|
|
14
|
+
fix: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
description: 'Automatically fix problems'
|
|
17
|
+
},
|
|
18
|
+
'max-warnings': {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Number of warnings to trigger nonzero exit code'
|
|
21
|
+
},
|
|
22
|
+
quiet: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
short: 'q',
|
|
25
|
+
description: 'Report errors only'
|
|
26
|
+
},
|
|
27
|
+
format: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
short: 'f',
|
|
30
|
+
description: 'Output format (stylish, compact, json, etc.)'
|
|
31
|
+
},
|
|
32
|
+
help: {
|
|
33
|
+
type: 'boolean',
|
|
34
|
+
short: 'h',
|
|
35
|
+
description: 'Show help'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
allowPositionals: true,
|
|
39
|
+
strict: false
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
if (lintArgs.help) {
|
|
43
|
+
console.log(`
|
|
44
|
+
itty lint - Lint your code with ESLint
|
|
45
|
+
|
|
46
|
+
Usage: itty lint [files/directories] [options]
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
--fix Automatically fix problems
|
|
50
|
+
--max-warnings <n> Number of warnings to trigger nonzero exit code
|
|
51
|
+
-q, --quiet Report errors only
|
|
52
|
+
-f, --format <format> Output format (stylish, compact, json, etc.)
|
|
53
|
+
-h, --help Show help
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
itty lint # Lint entire project (excludes node_modules, dist, build, etc.)
|
|
57
|
+
itty lint src # Lint only src directory
|
|
58
|
+
itty lint --fix # Lint entire project and auto-fix issues
|
|
59
|
+
itty lint src --quiet # Lint src directory, show errors only
|
|
60
|
+
itty lint --format=json # Lint entire project, output in JSON format
|
|
61
|
+
|
|
62
|
+
Note:
|
|
63
|
+
- When no paths are specified, lints entire project excluding common build directories
|
|
64
|
+
- Uses built-in TypeScript ESLint config if no local config found
|
|
65
|
+
- Local configs (eslint.config.mjs, .eslintrc.*, etc.) will override built-in config
|
|
66
|
+
- To extend built-in config: import { createConfig } from 'itty-packager/lib/configs/createConfig.mjs'
|
|
67
|
+
- Use specific paths to override the default exclusions
|
|
68
|
+
`)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check for local ESLint configs
|
|
73
|
+
const cwd = process.cwd()
|
|
74
|
+
const localConfigFiles = [
|
|
75
|
+
'eslint.config.mjs',
|
|
76
|
+
'eslint.config.js',
|
|
77
|
+
'.eslintrc.mjs',
|
|
78
|
+
'.eslintrc.js',
|
|
79
|
+
'.eslintrc.json',
|
|
80
|
+
'.eslintrc'
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
const hasLocalConfig = localConfigFiles.some(file =>
|
|
84
|
+
fs.existsSync(path.join(cwd, file))
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
// Find itty-packager's path and config
|
|
88
|
+
const packagerPath = path.resolve(__dirname, '../../')
|
|
89
|
+
const builtinConfig = path.join(packagerPath, 'lib', 'configs', 'eslint.config.mjs')
|
|
90
|
+
|
|
91
|
+
// Check if we're in development (has node_modules) or published (use npx)
|
|
92
|
+
const isDevMode = await fs.pathExists(path.join(packagerPath, 'node_modules'))
|
|
93
|
+
const eslintBinary = isDevMode
|
|
94
|
+
? path.join(packagerPath, 'node_modules', '.bin', 'eslint')
|
|
95
|
+
: 'eslint' // Use npx approach for published version
|
|
96
|
+
|
|
97
|
+
const eslintArgs = []
|
|
98
|
+
|
|
99
|
+
// Use built-in config if no local config exists
|
|
100
|
+
if (!hasLocalConfig) {
|
|
101
|
+
console.log(`🔧 Using built-in ESLint config (no local config found)`)
|
|
102
|
+
eslintArgs.push('--config', builtinConfig)
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`🔧 Using local ESLint config`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Add positional arguments (files/directories to lint)
|
|
108
|
+
if (positionals.length > 0) {
|
|
109
|
+
eslintArgs.push(...positionals)
|
|
110
|
+
} else {
|
|
111
|
+
// Default to all JS/TS files, excluding common build directories
|
|
112
|
+
eslintArgs.push(
|
|
113
|
+
'.',
|
|
114
|
+
'--ignore-pattern', 'node_modules/',
|
|
115
|
+
'--ignore-pattern', 'dist/',
|
|
116
|
+
'--ignore-pattern', 'build/',
|
|
117
|
+
'--ignore-pattern', 'coverage/',
|
|
118
|
+
'--ignore-pattern', '*.min.js',
|
|
119
|
+
'--ignore-pattern', '*.bundle.js'
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Add flags
|
|
124
|
+
if (lintArgs.fix) {
|
|
125
|
+
eslintArgs.push('--fix')
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (lintArgs['max-warnings']) {
|
|
129
|
+
eslintArgs.push('--max-warnings', lintArgs['max-warnings'])
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (lintArgs.quiet) {
|
|
133
|
+
eslintArgs.push('--quiet')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (lintArgs.format) {
|
|
137
|
+
eslintArgs.push('--format', lintArgs.format)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(`🔍 Linting with ESLint...`)
|
|
141
|
+
|
|
142
|
+
// Run ESLint
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const useNpx = !isDevMode
|
|
145
|
+
const command = useNpx ? 'npx' : eslintBinary
|
|
146
|
+
const args = useNpx ? ['eslint', ...eslintArgs] : eslintArgs
|
|
147
|
+
|
|
148
|
+
// Set up environment with access to itty-packager's node_modules for ESLint plugins
|
|
149
|
+
const env = {
|
|
150
|
+
...process.env,
|
|
151
|
+
NODE_PATH: `${path.join(packagerPath, 'node_modules')}:${process.env.NODE_PATH || ''}`
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const eslint = spawn(command, args, {
|
|
155
|
+
stdio: 'inherit',
|
|
156
|
+
cwd: process.cwd(),
|
|
157
|
+
shell: true,
|
|
158
|
+
env
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
eslint.on('close', (code) => {
|
|
162
|
+
if (code === 0) {
|
|
163
|
+
console.log('✅ Linting completed successfully')
|
|
164
|
+
resolve()
|
|
165
|
+
} else {
|
|
166
|
+
reject(new Error(`ESLint exited with code ${code}`))
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
eslint.on('error', (error) => {
|
|
171
|
+
reject(new Error(`Failed to run ESLint: ${error.message}`))
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { spawn } from 'node:child_process'
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
|
|
6
|
+
const SEMVER_TYPES = ['major', 'minor', 'patch']
|
|
7
|
+
|
|
8
|
+
function transformPackageExports(pkg, srcDir) {
|
|
9
|
+
// Transform package.json exports to remove srcDir prefix from paths
|
|
10
|
+
if (pkg.exports) {
|
|
11
|
+
const transformPath = (exportPath) => {
|
|
12
|
+
if (typeof exportPath === 'string' && exportPath.startsWith(`./${srcDir}/`)) {
|
|
13
|
+
return exportPath.replace(`./${srcDir}/`, './')
|
|
14
|
+
}
|
|
15
|
+
return exportPath
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const transformExportObj = (exportObj) => {
|
|
19
|
+
if (typeof exportObj === 'string') {
|
|
20
|
+
return transformPath(exportObj)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof exportObj === 'object' && exportObj !== null) {
|
|
24
|
+
const transformed = {}
|
|
25
|
+
for (const [key, value] of Object.entries(exportObj)) {
|
|
26
|
+
if (typeof value === 'string') {
|
|
27
|
+
transformed[key] = transformPath(value)
|
|
28
|
+
} else if (typeof value === 'object') {
|
|
29
|
+
transformed[key] = transformExportObj(value)
|
|
30
|
+
} else {
|
|
31
|
+
transformed[key] = value
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return transformed
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return exportObj
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const transformedExports = {}
|
|
41
|
+
for (const [key, value] of Object.entries(pkg.exports)) {
|
|
42
|
+
transformedExports[key] = transformExportObj(value)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return { ...pkg, exports: transformedExports }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return pkg
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function versionBump(currentVersion, type) {
|
|
52
|
+
const parts = currentVersion.split('.').map(Number)
|
|
53
|
+
|
|
54
|
+
switch (type) {
|
|
55
|
+
case 'major':
|
|
56
|
+
return `${parts[0] + 1}.0.0`
|
|
57
|
+
case 'minor':
|
|
58
|
+
return `${parts[0]}.${parts[1] + 1}.0`
|
|
59
|
+
case 'patch':
|
|
60
|
+
return `${parts[0]}.${parts[1]}.${parts[2] + 1}`
|
|
61
|
+
default:
|
|
62
|
+
// For pre-release versions like alpha, beta, rc
|
|
63
|
+
if (currentVersion.includes(`-${type}`)) {
|
|
64
|
+
// Increment the pre-release number
|
|
65
|
+
const [base, prerelease] = currentVersion.split(`-${type}.`)
|
|
66
|
+
const prereleaseNum = parseInt(prerelease) || 0
|
|
67
|
+
return `${base}-${type}.${prereleaseNum + 1}`
|
|
68
|
+
} else {
|
|
69
|
+
// Add pre-release to current version
|
|
70
|
+
return `${currentVersion}-${type}.0`
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function runCommand(command, cwd = process.cwd()) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const [cmd, ...args] = command.split(' ')
|
|
78
|
+
const proc = spawn(cmd, args, {
|
|
79
|
+
stdio: 'inherit',
|
|
80
|
+
cwd,
|
|
81
|
+
shell: true
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
proc.on('close', (code) => {
|
|
85
|
+
if (code === 0) {
|
|
86
|
+
resolve()
|
|
87
|
+
} else {
|
|
88
|
+
reject(new Error(`Command failed with exit code ${code}: ${command}`))
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
proc.on('error', (error) => {
|
|
93
|
+
reject(new Error(`Failed to run command: ${error.message}`))
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function publishCommand(args) {
|
|
99
|
+
const { values: publishArgs } = parseArgs({
|
|
100
|
+
args,
|
|
101
|
+
options: {
|
|
102
|
+
major: {
|
|
103
|
+
type: 'boolean',
|
|
104
|
+
description: 'Major release X.#.# for breaking changes'
|
|
105
|
+
},
|
|
106
|
+
minor: {
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
description: 'Minor release #.X.# for feature additions'
|
|
109
|
+
},
|
|
110
|
+
patch: {
|
|
111
|
+
type: 'boolean',
|
|
112
|
+
description: 'Patch release #.#.X for bug fixes'
|
|
113
|
+
},
|
|
114
|
+
type: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Custom release type (alpha, beta, rc, etc.)'
|
|
117
|
+
},
|
|
118
|
+
src: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
default: 'dist',
|
|
121
|
+
description: 'Source directory to publish from (default: dist)'
|
|
122
|
+
},
|
|
123
|
+
dest: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
default: '.dist',
|
|
126
|
+
description: 'Temporary directory for publishing (default: .dist)'
|
|
127
|
+
},
|
|
128
|
+
'dry-run': {
|
|
129
|
+
type: 'boolean',
|
|
130
|
+
description: 'Build and prepare but do not publish'
|
|
131
|
+
},
|
|
132
|
+
'no-cleanup': {
|
|
133
|
+
type: 'boolean',
|
|
134
|
+
description: 'Leave temporary directory after publishing'
|
|
135
|
+
},
|
|
136
|
+
public: {
|
|
137
|
+
type: 'boolean',
|
|
138
|
+
description: 'Publish as public package (--access=public)'
|
|
139
|
+
},
|
|
140
|
+
tag: {
|
|
141
|
+
type: 'boolean',
|
|
142
|
+
description: 'Create git tag for release'
|
|
143
|
+
},
|
|
144
|
+
push: {
|
|
145
|
+
type: 'boolean',
|
|
146
|
+
description: 'Push changes and tags to git remote'
|
|
147
|
+
},
|
|
148
|
+
'no-git': {
|
|
149
|
+
type: 'boolean',
|
|
150
|
+
description: 'Skip all git operations'
|
|
151
|
+
},
|
|
152
|
+
'no-license': {
|
|
153
|
+
type: 'boolean',
|
|
154
|
+
description: 'Do not copy LICENSE file to published package'
|
|
155
|
+
},
|
|
156
|
+
'no-changelog': {
|
|
157
|
+
type: 'boolean',
|
|
158
|
+
description: 'Do not copy CHANGELOG.md file to published package'
|
|
159
|
+
},
|
|
160
|
+
help: {
|
|
161
|
+
type: 'boolean',
|
|
162
|
+
short: 'h',
|
|
163
|
+
description: 'Show help'
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
allowPositionals: false
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
if (publishArgs.help) {
|
|
170
|
+
console.log(`
|
|
171
|
+
itty publish - Version and publish your package to npm
|
|
172
|
+
|
|
173
|
+
Usage: itty publish [options]
|
|
174
|
+
|
|
175
|
+
Version Options (default: patch):
|
|
176
|
+
--major Major release X.#.# for breaking changes
|
|
177
|
+
--minor Minor release #.X.# for feature additions
|
|
178
|
+
--patch Patch release #.#.X for bug fixes (default)
|
|
179
|
+
--type <type> Custom release type (alpha, beta, rc, etc.)
|
|
180
|
+
|
|
181
|
+
Publish Options:
|
|
182
|
+
--src <dir> Source directory to publish from (default: dist)
|
|
183
|
+
--dest <dir> Temporary directory for publishing (default: .dist)
|
|
184
|
+
--dry-run Build and prepare but do not publish
|
|
185
|
+
--no-cleanup Leave temporary directory after publishing
|
|
186
|
+
--public Publish as public package (--access=public)
|
|
187
|
+
--no-license Do not copy LICENSE file to published package
|
|
188
|
+
--no-changelog Do not copy CHANGELOG.md file to published package
|
|
189
|
+
|
|
190
|
+
Git Options:
|
|
191
|
+
--tag Create git tag for release
|
|
192
|
+
--push Push changes and tags to git remote
|
|
193
|
+
--no-git Skip all git operations
|
|
194
|
+
-h, --help Show help
|
|
195
|
+
|
|
196
|
+
Examples:
|
|
197
|
+
itty publish # Patch version bump and publish from dist/ (default)
|
|
198
|
+
itty publish --minor --tag # Minor bump, publish, and create git tag
|
|
199
|
+
itty publish --type=alpha # Pre-release alpha version
|
|
200
|
+
itty publish --src=lib # Publish from lib/ instead of dist/
|
|
201
|
+
itty publish --dry-run # Test the publish process
|
|
202
|
+
|
|
203
|
+
Note: This command extracts your build artifacts to a temporary directory,
|
|
204
|
+
adds root files (README.md, LICENSE, etc.), and publishes from there.
|
|
205
|
+
This creates a clean, flat package structure in node_modules.
|
|
206
|
+
`)
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Determine release type (default to patch)
|
|
211
|
+
const releaseType = publishArgs.major ? 'major'
|
|
212
|
+
: publishArgs.minor ? 'minor'
|
|
213
|
+
: publishArgs.patch ? 'patch'
|
|
214
|
+
: publishArgs.type ? publishArgs.type
|
|
215
|
+
: 'patch' // Default to patch
|
|
216
|
+
|
|
217
|
+
const rootPath = process.cwd()
|
|
218
|
+
const srcDir = path.join(rootPath, publishArgs.src)
|
|
219
|
+
|
|
220
|
+
// Handle root publishing (src=.) by using a different temp directory structure
|
|
221
|
+
const isRootPublish = publishArgs.src === '.'
|
|
222
|
+
const tempDir = isRootPublish
|
|
223
|
+
? path.join(path.dirname(rootPath), `.${path.basename(rootPath)}-dist`)
|
|
224
|
+
: path.join(rootPath, publishArgs.dest)
|
|
225
|
+
const dryRun = publishArgs['dry-run']
|
|
226
|
+
const noCleanup = publishArgs['no-cleanup']
|
|
227
|
+
const publicAccess = publishArgs.public
|
|
228
|
+
const shouldTag = publishArgs.tag
|
|
229
|
+
const shouldPush = publishArgs.push
|
|
230
|
+
const noGit = publishArgs['no-git']
|
|
231
|
+
const noLicense = publishArgs['no-license']
|
|
232
|
+
const noChangelog = publishArgs['no-changelog']
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// Read package.json
|
|
236
|
+
const pkgPath = path.join(rootPath, 'package.json')
|
|
237
|
+
const pkg = await fs.readJSON(pkgPath)
|
|
238
|
+
const newVersion = versionBump(pkg.version, releaseType)
|
|
239
|
+
|
|
240
|
+
console.log(`📦 Publishing ${pkg.name} v${pkg.version} → v${newVersion}`)
|
|
241
|
+
console.log(`📁 Source: ${publishArgs.src}/`)
|
|
242
|
+
|
|
243
|
+
// Check if source directory exists
|
|
244
|
+
if (!await fs.pathExists(srcDir)) {
|
|
245
|
+
throw new Error(`Source directory "${publishArgs.src}" does not exist. Run "itty build" first.`)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Clean and create temp directory
|
|
249
|
+
console.log(`🧹 Preparing ${publishArgs.dest}/`)
|
|
250
|
+
await fs.emptyDir(tempDir)
|
|
251
|
+
await fs.ensureDir(tempDir)
|
|
252
|
+
|
|
253
|
+
// Copy source files to temp directory
|
|
254
|
+
console.log(`📋 Copying ${publishArgs.src}/ to ${path.relative(rootPath, tempDir)}/`)
|
|
255
|
+
|
|
256
|
+
const filter = (src) => {
|
|
257
|
+
// Always exclude node_modules
|
|
258
|
+
if (src.includes('node_modules')) return false
|
|
259
|
+
|
|
260
|
+
// For root publishing, exclude additional files
|
|
261
|
+
if (isRootPublish) {
|
|
262
|
+
const relativePath = path.relative(srcDir, src)
|
|
263
|
+
return !relativePath.startsWith('.git') &&
|
|
264
|
+
!relativePath.includes('.DS_Store') &&
|
|
265
|
+
!relativePath.includes('coverage/') &&
|
|
266
|
+
!relativePath.includes('.nyc_output/')
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return true
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await fs.copy(srcDir, tempDir, { filter })
|
|
273
|
+
|
|
274
|
+
// Copy root files that should be included in the package (only for non-root publishing)
|
|
275
|
+
if (!isRootPublish) {
|
|
276
|
+
const rootFiles = [
|
|
277
|
+
'README.md', // Always copy README
|
|
278
|
+
'.npmrc' // Always copy .npmrc if it exists
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
// Add optional files based on flags
|
|
282
|
+
if (!noLicense) rootFiles.push('LICENSE')
|
|
283
|
+
if (!noChangelog) rootFiles.push('CHANGELOG.md')
|
|
284
|
+
|
|
285
|
+
for (const file of rootFiles) {
|
|
286
|
+
const srcFile = path.join(rootPath, file)
|
|
287
|
+
const destFile = path.join(tempDir, file)
|
|
288
|
+
|
|
289
|
+
if (await fs.pathExists(srcFile)) {
|
|
290
|
+
console.log(`📄 Copying ${file}`)
|
|
291
|
+
await fs.copy(srcFile, destFile)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Update package.json in temp directory with transformed paths
|
|
297
|
+
const updatedPkg = isRootPublish
|
|
298
|
+
? { ...pkg, version: newVersion } // No path transformation for root publishing
|
|
299
|
+
: transformPackageExports({ ...pkg, version: newVersion }, publishArgs.src)
|
|
300
|
+
const tempPkgPath = path.join(tempDir, 'package.json')
|
|
301
|
+
|
|
302
|
+
const transformMessage = isRootPublish ? '' : ' (transforming paths)'
|
|
303
|
+
console.log(`📝 Updating package.json to v${newVersion}${transformMessage}`)
|
|
304
|
+
await fs.writeJSON(tempPkgPath, updatedPkg, { spaces: 2 })
|
|
305
|
+
|
|
306
|
+
if (dryRun) {
|
|
307
|
+
console.log('🧪 Dry run - skipping publish')
|
|
308
|
+
} else {
|
|
309
|
+
// Publish from temp directory
|
|
310
|
+
console.log(`🚀 Publishing to npm...`)
|
|
311
|
+
|
|
312
|
+
const publishCmd = [
|
|
313
|
+
'npm publish',
|
|
314
|
+
publicAccess ? '--access=public' : '',
|
|
315
|
+
SEMVER_TYPES.includes(releaseType) ? '' : `--tag=${releaseType}`
|
|
316
|
+
].filter(Boolean).join(' ')
|
|
317
|
+
|
|
318
|
+
console.log(`Running: ${publishCmd}`)
|
|
319
|
+
await runCommand(publishCmd, tempDir)
|
|
320
|
+
|
|
321
|
+
// Update root package.json
|
|
322
|
+
console.log(`📝 Updating root package.json`)
|
|
323
|
+
await fs.writeJSON(pkgPath, updatedPkg, { spaces: 2 })
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Git operations
|
|
327
|
+
if (!noGit && !dryRun) {
|
|
328
|
+
if (shouldPush || shouldTag) {
|
|
329
|
+
console.log(`📋 Committing changes...`)
|
|
330
|
+
await runCommand('git add .', rootPath)
|
|
331
|
+
await runCommand(`git commit -m "released v${newVersion}"`, rootPath)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (shouldTag) {
|
|
335
|
+
console.log(`🏷️ Creating git tag v${newVersion}`)
|
|
336
|
+
await runCommand(`git tag -a v${newVersion} -m "Release v${newVersion}"`, rootPath)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (shouldPush) {
|
|
340
|
+
console.log(`📤 Pushing to remote...`)
|
|
341
|
+
await runCommand('git push', rootPath)
|
|
342
|
+
|
|
343
|
+
if (shouldTag) {
|
|
344
|
+
console.log(`📤 Pushing tags...`)
|
|
345
|
+
await runCommand('git push --tags', rootPath)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Cleanup
|
|
351
|
+
if (!noCleanup) {
|
|
352
|
+
console.log(`🧹 Cleaning up ${publishArgs.dest}/`)
|
|
353
|
+
await fs.remove(tempDir)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
console.log(`✅ Successfully published ${pkg.name}@${newVersion}`)
|
|
357
|
+
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error(`❌ Publish failed: ${error.message}`)
|
|
360
|
+
|
|
361
|
+
// Cleanup on error
|
|
362
|
+
if (await fs.pathExists(tempDir) && !noCleanup) {
|
|
363
|
+
await fs.remove(tempDir)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
throw error
|
|
367
|
+
}
|
|
368
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import typescriptEslint from '@typescript-eslint/eslint-plugin'
|
|
2
|
+
import tsParser from '@typescript-eslint/parser'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import js from '@eslint/js'
|
|
6
|
+
import { FlatCompat } from '@eslint/eslintrc'
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = path.dirname(__filename)
|
|
10
|
+
const compat = new FlatCompat({
|
|
11
|
+
baseDirectory: __dirname,
|
|
12
|
+
recommendedConfig: js.configs.recommended,
|
|
13
|
+
allConfig: js.configs.all
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
// Base configuration that all itty projects should use
|
|
17
|
+
const baseConfig = [...compat.extends(
|
|
18
|
+
'eslint:recommended',
|
|
19
|
+
'plugin:@typescript-eslint/eslint-recommended',
|
|
20
|
+
'plugin:@typescript-eslint/recommended',
|
|
21
|
+
), {
|
|
22
|
+
plugins: {
|
|
23
|
+
'@typescript-eslint': typescriptEslint,
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
languageOptions: {
|
|
27
|
+
parser: tsParser,
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
rules: {
|
|
31
|
+
'@typescript-eslint/no-empty-function': 'off',
|
|
32
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
33
|
+
'@typescript-eslint/ban-types': 'off',
|
|
34
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
35
|
+
'linebreak-style': ['error', 'unix'],
|
|
36
|
+
'prefer-const': 'off',
|
|
37
|
+
|
|
38
|
+
quotes: ['error', 'single', {
|
|
39
|
+
allowTemplateLiterals: true,
|
|
40
|
+
}],
|
|
41
|
+
|
|
42
|
+
semi: ['error', 'never'],
|
|
43
|
+
},
|
|
44
|
+
}]
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Create an ESLint config by extending the base itty configuration
|
|
48
|
+
* @param {Object} overrides - Configuration overrides
|
|
49
|
+
* @param {Object} overrides.rules - Additional or modified rules
|
|
50
|
+
* @param {Object} overrides.languageOptions - Language options to merge
|
|
51
|
+
* @param {Array} overrides.plugins - Additional plugins
|
|
52
|
+
* @param {Array} overrides.ignores - Files/patterns to ignore
|
|
53
|
+
* @returns {Array} ESLint flat config
|
|
54
|
+
*/
|
|
55
|
+
export function createConfig(overrides = {}) {
|
|
56
|
+
const config = [...baseConfig]
|
|
57
|
+
|
|
58
|
+
if (overrides.rules || overrides.languageOptions || overrides.plugins || overrides.ignores) {
|
|
59
|
+
// Create a new config object that extends the base
|
|
60
|
+
const extendedConfig = {
|
|
61
|
+
...config[config.length - 1], // Take the last config object from base
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Merge rules
|
|
65
|
+
if (overrides.rules) {
|
|
66
|
+
extendedConfig.rules = {
|
|
67
|
+
...extendedConfig.rules,
|
|
68
|
+
...overrides.rules
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Merge language options
|
|
73
|
+
if (overrides.languageOptions) {
|
|
74
|
+
extendedConfig.languageOptions = {
|
|
75
|
+
...extendedConfig.languageOptions,
|
|
76
|
+
...overrides.languageOptions
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Merge plugins
|
|
81
|
+
if (overrides.plugins) {
|
|
82
|
+
extendedConfig.plugins = {
|
|
83
|
+
...extendedConfig.plugins,
|
|
84
|
+
...overrides.plugins
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Add ignores
|
|
89
|
+
if (overrides.ignores) {
|
|
90
|
+
extendedConfig.ignores = overrides.ignores
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Replace the last config in the array
|
|
94
|
+
config[config.length - 1] = extendedConfig
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return config
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Export the base config as default for direct use
|
|
101
|
+
export default baseConfig
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Template for extending the built-in itty-packager ESLint config
|
|
2
|
+
// Copy this to your project root as 'eslint.config.mjs' and customize as needed
|
|
3
|
+
|
|
4
|
+
import { createConfig } from 'itty-packager/lib/configs/createConfig.mjs'
|
|
5
|
+
|
|
6
|
+
export default createConfig({
|
|
7
|
+
// Add custom rules specific to your project
|
|
8
|
+
rules: {
|
|
9
|
+
// Example: Allow console statements
|
|
10
|
+
// 'no-console': 'off',
|
|
11
|
+
|
|
12
|
+
// Example: Require spaces around object braces
|
|
13
|
+
// 'object-curly-spacing': ['error', 'always'],
|
|
14
|
+
|
|
15
|
+
// Example: Prefer template literals over string concatenation
|
|
16
|
+
// 'prefer-template': 'error',
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
// Add project-specific ignores (in addition to defaults)
|
|
20
|
+
ignores: [
|
|
21
|
+
// 'test-fixtures/**',
|
|
22
|
+
// 'docs/**',
|
|
23
|
+
]
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Available options for createConfig():
|
|
27
|
+
// - rules: Object with ESLint rule overrides
|
|
28
|
+
// - languageOptions: Parser and environment settings
|
|
29
|
+
// - plugins: Additional ESLint plugins
|
|
30
|
+
// - ignores: Array of file patterns to ignore
|
package/package.json
CHANGED
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "itty-packager",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Universal build tool for itty libraries",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"itty": "./bin/itty.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"test": "echo 'No tests yet'"
|
|
10
|
+
"lint": "bun bin/itty.js lint",
|
|
11
|
+
"test": "echo 'No tests yet'",
|
|
12
|
+
"release:dry": "bun bin/itty.js publish --patch --tag --dry-run --src=. --no-license --no-changelog",
|
|
13
|
+
"release": "bun bin/itty.js publish --patch --tag --push --src=. --no-license --no-changelog",
|
|
14
|
+
"release:minor": "bun bin/itty.js publish --minor --tag --push --src=. --no-license --no-changelog",
|
|
15
|
+
"release:major": "bun bin/itty.js publish --major --tag --push --src=. --no-license --no-changelog"
|
|
12
16
|
},
|
|
13
17
|
"keywords": [
|
|
14
18
|
"build",
|
|
15
19
|
"rollup",
|
|
16
20
|
"typescript",
|
|
21
|
+
"eslint",
|
|
22
|
+
"publish",
|
|
23
|
+
"cli",
|
|
24
|
+
"tool",
|
|
17
25
|
"itty"
|
|
18
26
|
],
|
|
19
27
|
"author": "Kevin R. Whitley <krwhitley@gmail.com>",
|
|
20
28
|
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/kwhitley/itty-packager.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/kwhitley/itty-packager/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/kwhitley/itty-packager#readme",
|
|
21
37
|
"dependencies": {
|
|
38
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
39
|
+
"@eslint/js": "^9.17.0",
|
|
22
40
|
"@rollup/plugin-terser": "^0.4.4",
|
|
23
41
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
44
|
+
"eslint": "^9.17.0",
|
|
24
45
|
"fs-extra": "^11.2.0",
|
|
25
46
|
"globby": "^14.1.0",
|
|
26
47
|
"rimraf": "^6.0.1",
|
|
@@ -30,4 +51,4 @@
|
|
|
30
51
|
"tslib": "^2.8.1",
|
|
31
52
|
"typescript": "^5.7.2"
|
|
32
53
|
}
|
|
33
|
-
}
|
|
54
|
+
}
|