portapack 0.2.1 → 0.3.0
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/CHANGELOG.md +12 -0
- package/README.md +83 -216
- package/dist/cli/{cli-entry.js → cli-entry.cjs} +626 -498
- package/dist/cli/cli-entry.cjs.map +1 -0
- package/dist/index.d.ts +51 -56
- package/dist/index.js +523 -443
- package/dist/index.js.map +1 -1
- package/docs/cli.md +158 -42
- package/jest.config.ts +18 -8
- package/jest.setup.cjs +66 -146
- package/package.json +5 -5
- package/src/cli/cli-entry.ts +15 -15
- package/src/cli/cli.ts +130 -119
- package/src/core/bundler.ts +174 -63
- package/src/core/extractor.ts +243 -203
- package/src/core/web-fetcher.ts +205 -141
- package/src/index.ts +161 -224
- package/tests/unit/cli/cli-entry.test.ts +66 -77
- package/tests/unit/cli/cli.test.ts +243 -145
- package/tests/unit/core/bundler.test.ts +334 -258
- package/tests/unit/core/extractor.test.ts +391 -1051
- package/tests/unit/core/minifier.test.ts +130 -221
- package/tests/unit/core/packer.test.ts +255 -106
- package/tests/unit/core/parser.test.ts +89 -458
- package/tests/unit/core/web-fetcher.test.ts +330 -285
- package/tests/unit/index.test.ts +206 -300
- package/tests/unit/utils/logger.test.ts +32 -28
- package/tsconfig.jest.json +7 -7
- package/tsup.config.ts +34 -29
- package/dist/cli/cli-entry.js.map +0 -1
- package/output.html +0 -1
- package/site-packed.html +0 -1
- package/test-output.html +0 -0
package/docs/cli.md
CHANGED
@@ -1,117 +1,233 @@
|
|
1
|
-
# ⚙️ CLI Reference
|
1
|
+
# ⚙️ PortaPack CLI Reference
|
2
2
|
|
3
|
-
PortaPack provides a powerful command-line interface for bundling HTML files and websites.
|
3
|
+
PortaPack provides a powerful command-line interface (CLI) for bundling local HTML files and remote websites into single, portable HTML files.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
To use the CLI, install PortaPack globally:
|
7
|
+
To use the CLI, install PortaPack globally using npm (or your preferred package manager):
|
8
8
|
|
9
9
|
```bash
|
10
10
|
npm install -g portapack
|
11
|
+
# or
|
12
|
+
# yarn global add portapack
|
13
|
+
# or
|
14
|
+
# pnpm add -g portapack
|
11
15
|
```
|
12
16
|
|
13
17
|
## Command Syntax
|
14
18
|
|
15
|
-
|
19
|
+
PortaPack supports two command styles for specifying input:
|
16
20
|
|
17
21
|
```bash
|
18
|
-
|
22
|
+
# Positional argument style (recommended)
|
23
|
+
portapack <path_or_url> [options]
|
24
|
+
|
25
|
+
# Named argument style
|
26
|
+
portapack --input <path_or_url> [options]
|
27
|
+
# or using shorthand
|
28
|
+
portapack -i <path_or_url> [options]
|
19
29
|
```
|
20
30
|
|
31
|
+
Both methods work identically - choose whichever you prefer.
|
32
|
+
|
21
33
|
## Options
|
22
34
|
|
23
35
|
| Option | Shorthand | Description | Default |
|
24
|
-
|
25
|
-
| `--input <
|
26
|
-
| `--output <file>` | `-o` | Output file path | `{input}.packed.html` |
|
27
|
-
| `--minify
|
28
|
-
| `--no-minify` |
|
29
|
-
| `--
|
30
|
-
| `--
|
31
|
-
| `--
|
32
|
-
| `--
|
33
|
-
| `--
|
34
|
-
| `--
|
36
|
+
|--------|-----------|-------------|---------|
|
37
|
+
| `<path_or_url>` or `--input <path_or_url>` | `-i` | Required. Input local file path or remote URL (http/https) to process. | - |
|
38
|
+
| `--output <file>` | `-o` | Output file path for the bundled HTML. | `{input}.packed.html` |
|
39
|
+
| `--minify` | `-m` | Enable all minification (HTML, CSS, JS). | - |
|
40
|
+
| `--no-minify` | | Disable all asset minification (HTML, CSS, JS). | `false` |
|
41
|
+
| `--no-minify-html` | | Disable only HTML minification. | `false` |
|
42
|
+
| `--no-minify-css` | | Disable only CSS minification. | `false` |
|
43
|
+
| `--no-minify-js` | | Disable only JavaScript minification. | `false` |
|
44
|
+
| `--recursive [depth]` | `-r` | Recursively bundle links up to depth. If depth omitted, defaults to 1. Only applies to remote URLs. | - (disabled) |
|
45
|
+
| `--max-depth <n>` | | Set maximum depth for recursive crawling (alternative to `-r <n>`). | - |
|
46
|
+
| `--base-url <url>` | `-b` | Base URL for resolving relative URLs found in the input HTML. | Input path/URL |
|
47
|
+
| `--embed-assets` | `-e` | Embed external assets (CSS, JS, images, fonts) as data URIs or inline content. | `true` |
|
48
|
+
| `--no-embed-assets` | | Keep external assets as links (requires network access when viewing). | `false` |
|
49
|
+
| `--timeout <ms>` | `-t` | Network timeout in milliseconds for fetching remote resources. | `30000` (30 seconds) |
|
50
|
+
| `--user-agent <string>` | `-U` | Custom User-Agent string for network requests. | Default Node.js agent |
|
51
|
+
| `--include <glob>` | | Glob pattern for URLs to include during recursion (can be specified multiple times). | `**` (all) |
|
52
|
+
| `--exclude <glob>` | | Glob pattern for URLs to exclude during recursion (can be specified multiple times). | - |
|
53
|
+
| `--log-level <level>` | `-l` | Set logging level (debug, info, warn, error, silent). | `info` |
|
54
|
+
| `--verbose` | `-v` | Enable verbose logging (shortcut for `--log-level debug`). | `false` |
|
55
|
+
| `--config <path>` | `-c` | Path to a configuration file (e.g., `.portapackrc.json`) to load options from. | - |
|
56
|
+
| `--dry-run` | `-d` | Perform all steps except writing the output file. Logs intended actions. | `false` |
|
57
|
+
| `--help` | `-h` | Show help information and exit. | - |
|
58
|
+
| `--version` | | Show PortaPack CLI version number and exit. | - |
|
35
59
|
|
36
60
|
## Examples
|
37
61
|
|
38
|
-
### Basic
|
62
|
+
### Basic Local File Bundling
|
39
63
|
|
40
|
-
Bundle
|
64
|
+
Bundle `index.html` into `bundle.html`:
|
41
65
|
|
42
66
|
```bash
|
67
|
+
# Using positional argument style
|
68
|
+
portapack ./index.html -o bundle.html
|
69
|
+
|
70
|
+
# Using named argument style
|
43
71
|
portapack -i ./index.html -o bundle.html
|
44
72
|
```
|
45
73
|
|
74
|
+
Use default output name (`index.html.packed.html`):
|
75
|
+
|
76
|
+
```bash
|
77
|
+
# Using positional argument style
|
78
|
+
portapack ./index.html
|
79
|
+
|
80
|
+
# Using named argument style
|
81
|
+
portapack -i ./index.html
|
82
|
+
```
|
83
|
+
|
46
84
|
### Web Page Bundling
|
47
85
|
|
48
|
-
Bundle a remote
|
86
|
+
Bundle a single remote webpage:
|
49
87
|
|
50
88
|
```bash
|
89
|
+
# Using positional argument style
|
90
|
+
portapack https://example.com -o example-bundle.html
|
91
|
+
|
92
|
+
# Using named argument style
|
51
93
|
portapack -i https://example.com -o example-bundle.html
|
52
94
|
```
|
53
95
|
|
54
96
|
### Recursive Bundling
|
55
97
|
|
56
|
-
Bundle a website
|
98
|
+
Bundle a website, following links 1 level deep:
|
99
|
+
|
100
|
+
```bash
|
101
|
+
portapack https://example.com -r -o site-bundle-depth1.html
|
102
|
+
```
|
103
|
+
|
104
|
+
Bundle a website, following links up to 2 levels deep:
|
105
|
+
|
106
|
+
```bash
|
107
|
+
portapack https://example.com -r 2 -o site-bundle-depth2.html
|
108
|
+
```
|
109
|
+
|
110
|
+
Alternative using `--max-depth` option:
|
111
|
+
|
112
|
+
```bash
|
113
|
+
portapack https://example.com --max-depth 2 -o site-bundle-depth2.html
|
114
|
+
```
|
115
|
+
|
116
|
+
Recursively bundle only blog posts, excluding images:
|
57
117
|
|
58
118
|
```bash
|
59
|
-
portapack
|
119
|
+
portapack https://example.com -r \
|
120
|
+
--include "/blog/**" \
|
121
|
+
--exclude "**/*.{jpg,png,gif}" \
|
122
|
+
-o blog-bundle.html
|
123
|
+
```
|
124
|
+
|
125
|
+
### Asset Handling
|
126
|
+
|
127
|
+
Bundle without embedding assets (keep external links):
|
128
|
+
|
129
|
+
```bash
|
130
|
+
portapack ./index.html --no-embed-assets -o linked-assets.html
|
131
|
+
```
|
132
|
+
|
133
|
+
Default behavior is to embed assets (which you can make explicit):
|
134
|
+
|
135
|
+
```bash
|
136
|
+
portapack ./index.html --embed-assets -o embedded-assets.html
|
60
137
|
```
|
61
138
|
|
62
139
|
### Minification Control
|
63
140
|
|
64
|
-
Apply
|
141
|
+
Apply all minification:
|
142
|
+
|
143
|
+
```bash
|
144
|
+
portapack ./index.html -m -o min-bundle.html
|
145
|
+
```
|
146
|
+
|
147
|
+
Disable minification completely:
|
148
|
+
|
149
|
+
```bash
|
150
|
+
portapack ./index.html --no-minify -o unmin-bundle.html
|
151
|
+
```
|
152
|
+
|
153
|
+
Selectively control minification:
|
65
154
|
|
66
155
|
```bash
|
67
|
-
|
156
|
+
# Minify CSS and JS but not HTML
|
157
|
+
portapack ./index.html --no-minify-html -o selective-min.html
|
158
|
+
|
159
|
+
# Minify HTML and CSS but not JS
|
160
|
+
portapack ./index.html --no-minify-js -o no-js-min.html
|
68
161
|
```
|
69
162
|
|
70
|
-
|
163
|
+
### Advanced Network Options
|
164
|
+
|
165
|
+
Bundle a remote page with a longer timeout and custom user agent:
|
71
166
|
|
72
167
|
```bash
|
73
|
-
portapack -
|
168
|
+
portapack https://example.com -t 60000 -U "MyCustomBot/1.0" -o example-custom.html
|
74
169
|
```
|
75
170
|
|
76
171
|
### Base URL for Relative Links
|
77
172
|
|
78
|
-
|
173
|
+
Process a local file as if it were hosted at https://example.com:
|
79
174
|
|
80
175
|
```bash
|
81
|
-
portapack
|
176
|
+
portapack ./docs/index.html -b https://example.com/docs/ -o bundle.html
|
177
|
+
```
|
178
|
+
|
179
|
+
### Logging and Debugging
|
180
|
+
|
181
|
+
Enable detailed debug logs:
|
182
|
+
|
183
|
+
```bash
|
184
|
+
portapack ./index.html -v -o bundle-debug.html
|
185
|
+
```
|
186
|
+
|
187
|
+
Only show errors:
|
188
|
+
|
189
|
+
```bash
|
190
|
+
portapack ./index.html --log-level error -o bundle-errors-only.html
|
82
191
|
```
|
83
192
|
|
84
193
|
### Dry Run
|
85
194
|
|
86
|
-
|
195
|
+
See what files and assets would be processed without saving:
|
87
196
|
|
88
197
|
```bash
|
89
|
-
portapack
|
198
|
+
portapack ./index.html --dry-run
|
90
199
|
```
|
91
200
|
|
92
|
-
###
|
201
|
+
### Using a Configuration File
|
93
202
|
|
94
|
-
|
203
|
+
Load options from a config file:
|
95
204
|
|
96
205
|
```bash
|
97
|
-
portapack -
|
206
|
+
portapack -c ./.portapackrc.json
|
207
|
+
```
|
208
|
+
|
209
|
+
### NPX Usage
|
210
|
+
|
211
|
+
Use PortaPack without installing globally:
|
212
|
+
|
213
|
+
```bash
|
214
|
+
npx portapack ./index.html -o bundle.html
|
98
215
|
```
|
99
216
|
|
100
217
|
## Exit Codes
|
101
218
|
|
102
219
|
| Code | Description |
|
103
220
|
|------|-------------|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
107
|
-
|
221
|
+
| 0 | Success |
|
222
|
+
| 1 | General Error (e.g., invalid options, file IO) |
|
223
|
+
| 2 | Input Error (e.g., missing input, invalid URL) |
|
224
|
+
| 3 | Network Error (e.g., fetch failed, timeout) |
|
225
|
+
| 4 | Processing Error (e.g., parsing failed) |
|
108
226
|
|
109
|
-
|
110
|
-
|----------|-------------|
|
111
|
-
| `NODE_ENV` | Set to `test` during testing to suppress console output |
|
227
|
+
(Note: Specific error codes might vary)
|
112
228
|
|
113
229
|
## Related Resources
|
114
230
|
|
115
|
-
-
|
116
|
-
-
|
117
|
-
-
|
231
|
+
- Getting Started (Link needs validation)
|
232
|
+
- API Reference (Link needs validation)
|
233
|
+
- Configuration Guide (Link needs validation)
|
package/jest.config.ts
CHANGED
@@ -5,7 +5,8 @@ const config: Config = {
|
|
5
5
|
/**
|
6
6
|
* Use ts-jest with ESM support.
|
7
7
|
*/
|
8
|
-
preset: 'ts-jest/presets/default-esm',
|
8
|
+
// preset: 'ts-jest/presets/default-esm',
|
9
|
+
preset: 'ts-jest',
|
9
10
|
|
10
11
|
/**
|
11
12
|
* Node test environment
|
@@ -20,16 +21,25 @@ const config: Config = {
|
|
20
21
|
/**
|
21
22
|
* Tell ts-jest to use ESM transformation
|
22
23
|
*/
|
24
|
+
// transform: {
|
25
|
+
// '^.+\\.tsx?$': [
|
26
|
+
// 'ts-jest',
|
27
|
+
// {
|
28
|
+
// useESM: true,
|
29
|
+
// tsconfig: './tsconfig.jest.json'
|
30
|
+
// }
|
31
|
+
// ]
|
32
|
+
// },
|
33
|
+
|
23
34
|
transform: {
|
24
35
|
'^.+\\.tsx?$': [
|
25
36
|
'ts-jest',
|
26
37
|
{
|
27
|
-
useESM:
|
28
|
-
tsconfig: './tsconfig.jest.json'
|
38
|
+
// useESM: false, // Explicitly false or remove this line entirely
|
39
|
+
tsconfig: './tsconfig.jest.json' // Ensure this tsconfig targets CommonJS
|
29
40
|
}
|
30
41
|
]
|
31
42
|
},
|
32
|
-
|
33
43
|
/**
|
34
44
|
* Treat `.ts` files as ESM modules.
|
35
45
|
*/
|
@@ -68,10 +78,10 @@ const config: Config = {
|
|
68
78
|
*/
|
69
79
|
coverageThreshold: {
|
70
80
|
global: {
|
71
|
-
branches:
|
72
|
-
functions:
|
73
|
-
lines:
|
74
|
-
statements:
|
81
|
+
branches: 70,
|
82
|
+
functions: 70,
|
83
|
+
lines: 70,
|
84
|
+
statements: 70,
|
75
85
|
},
|
76
86
|
},
|
77
87
|
|
package/jest.setup.cjs
CHANGED
@@ -1,211 +1,131 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* @description Jest global setup script executed before test suites run (per file).
|
4
|
-
* Responsible for creating temporary directories for test outputs and fixtures,
|
5
|
-
* setting up mock data (like the sample project), and cleaning up afterwards.
|
6
|
-
* Uses CommonJS syntax as Jest setup files often run in a CJS context.
|
7
|
-
*/
|
8
|
-
|
9
|
-
// Node.js core modules required for setup
|
10
|
-
const fs = require('fs/promises'); // Using promises API for async operations
|
1
|
+
// jest.setup.cjs
|
2
|
+
const fs = require('fs/promises');
|
11
3
|
const path = require('path');
|
12
4
|
const crypto = require('crypto');
|
13
5
|
const os = require('os');
|
6
|
+
// const jest = require('@jest/globals'); // REMOVE THIS LINE
|
14
7
|
|
15
|
-
// Generate a unique ID for each test execution session.
|
16
|
-
// This helps isolate test runs if running concurrently or prevents conflicts
|
17
|
-
// if cleanup fails on a previous run.
|
18
8
|
const TEST_RUN_ID = crypto.randomBytes(4).toString('hex');
|
19
|
-
|
20
|
-
// Helper function for resolving paths relative to this setup file's directory
|
21
|
-
// (usually the project root or a specific test config directory)
|
22
9
|
const resolve = (...args) => path.resolve(__dirname, ...args);
|
23
10
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
* Ignores 'EEXIST' error if the directory is already present.
|
28
|
-
* @param {string} dir - The absolute path of the directory to ensure.
|
29
|
-
* @returns {Promise<void>}
|
30
|
-
* @throws {Error} Throws errors other than 'EEXIST' during directory creation.
|
31
|
-
*/
|
11
|
+
// Use the *original* console.log temporarily for setup debugging
|
12
|
+
const originalSetupLog = console.log;
|
13
|
+
|
32
14
|
const ensureDir = async (dir) => {
|
33
15
|
try {
|
34
16
|
await fs.mkdir(dir, { recursive: true });
|
35
17
|
} catch (e) {
|
36
|
-
// If the error is simply that the directory already exists, ignore it.
|
37
18
|
if (e.code !== 'EEXIST') {
|
38
|
-
|
39
|
-
throw e;
|
19
|
+
originalSetupLog(`[SETUP-ERROR] Failed to ensure directory ${dir}:`, e);
|
20
|
+
throw e;
|
40
21
|
}
|
41
22
|
}
|
42
23
|
};
|
43
24
|
|
44
|
-
// Define the base temporary directory using the OS's temp location and the unique run ID.
|
45
|
-
// Using os.tmpdir() is generally safer regarding permissions and OS conventions.
|
46
25
|
const tempDir = path.join(os.tmpdir(), 'portapack-tests', TEST_RUN_ID);
|
47
|
-
|
48
|
-
|
49
|
-
* Object containing base paths for various test-related directories.
|
50
|
-
* These are constructed relative to the main temporary directory.
|
51
|
-
*/
|
26
|
+
// *** Make sure baseDirs is defined ***
|
27
|
+
// (Assuming it was defined correctly before the placeholder comment)
|
52
28
|
const baseDirs = {
|
53
|
-
root: resolve(), // Project root
|
54
|
-
output: path.join(tempDir, 'test-output'), // General output
|
55
|
-
fixtures: path.join(tempDir, '__fixtures__'), // Base for
|
56
|
-
fixturesOutput: path.join(tempDir, '__fixtures__/output'), //
|
57
|
-
sampleProject: path.join(tempDir, 'sample-project') //
|
29
|
+
root: resolve(), // Project root
|
30
|
+
output: path.join(tempDir, 'test-output'), // General output
|
31
|
+
fixtures: path.join(tempDir, '__fixtures__'), // Base for fixtures
|
32
|
+
fixturesOutput: path.join(tempDir, '__fixtures__/output'), // Fixture output
|
33
|
+
sampleProject: path.join(tempDir, 'sample-project') // Mock project dir
|
58
34
|
};
|
35
|
+
// **********************************
|
59
36
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
*/
|
37
|
+
|
38
|
+
// --- Use Jest's GLOBAL beforeAll/afterAll/jest ---
|
39
|
+
// These are available globally in setup files
|
64
40
|
beforeAll(async () => {
|
65
|
-
|
41
|
+
originalSetupLog(`[SETUP] Starting setup in: ${tempDir}`);
|
66
42
|
|
67
|
-
|
68
|
-
//
|
43
|
+
originalSetupLog('[SETUP] Ensuring baseDirs...');
|
44
|
+
// Make sure baseDirs is defined before using it
|
45
|
+
if (!baseDirs || !baseDirs.output || !baseDirs.fixturesOutput) {
|
46
|
+
throw new Error("baseDirs is not properly defined!");
|
47
|
+
}
|
69
48
|
await Promise.all([
|
70
49
|
ensureDir(baseDirs.output),
|
71
50
|
ensureDir(baseDirs.fixturesOutput)
|
72
51
|
]);
|
52
|
+
originalSetupLog('[SETUP] BaseDirs ensured.');
|
73
53
|
|
74
|
-
|
54
|
+
originalSetupLog('[SETUP] Creating runDirs...');
|
75
55
|
const runDirs = {
|
76
56
|
uniqueOutput: path.join(baseDirs.output, TEST_RUN_ID),
|
77
57
|
uniqueFixturesOutput: path.join(baseDirs.fixturesOutput, TEST_RUN_ID)
|
78
58
|
};
|
79
|
-
|
80
|
-
// Create the run-specific directories.
|
81
59
|
await Promise.all([
|
82
60
|
fs.mkdir(runDirs.uniqueOutput, { recursive: true }),
|
83
61
|
fs.mkdir(runDirs.uniqueFixturesOutput, { recursive: true })
|
84
62
|
]);
|
63
|
+
originalSetupLog('[SETUP] RunDirs created.');
|
85
64
|
|
86
|
-
|
87
|
-
|
88
|
-
global.
|
89
|
-
|
90
|
-
|
91
|
-
};
|
92
|
-
|
93
|
-
// Helper function for tests to get a path within the unique test output directory.
|
94
|
-
global.getTestFilePath = (relPath) =>
|
95
|
-
path.join(global.__TEST_DIRECTORIES__.uniqueOutput, relPath);
|
96
|
-
|
97
|
-
// Helper function for tests to get a path within the unique fixture output directory.
|
98
|
-
global.getTestFixturePath = (relPath) =>
|
99
|
-
path.join(global.__TEST_DIRECTORIES__.uniqueFixturesOutput, relPath);
|
65
|
+
originalSetupLog('[SETUP] Setting globals...');
|
66
|
+
global.__TEST_DIRECTORIES__ = { ...baseDirs, ...runDirs };
|
67
|
+
global.getTestFilePath = (relPath) => path.join(global.__TEST_DIRECTORIES__.uniqueOutput, relPath);
|
68
|
+
global.getTestFixturePath = (relPath) => path.join(global.__TEST_DIRECTORIES__.uniqueFixturesOutput, relPath);
|
69
|
+
originalSetupLog('[SETUP] Globals set.');
|
100
70
|
|
101
|
-
|
102
|
-
|
103
|
-
await ensureDir(path.dirname(path.join(tempDir, 'font.woff2')));
|
71
|
+
originalSetupLog('[SETUP] Ensuring mock font dirs...');
|
72
|
+
if (!tempDir) throw new Error("tempDir is not defined before font dir creation!");
|
73
|
+
await ensureDir(path.dirname(path.join(tempDir, 'font.woff2')));
|
104
74
|
await ensureDir(path.dirname(path.join(tempDir, 'font.ttf')));
|
105
|
-
|
75
|
+
originalSetupLog('[SETUP] Mock font dirs ensured.');
|
106
76
|
|
107
|
-
|
77
|
+
originalSetupLog('[SETUP] Writing mock font files...');
|
108
78
|
await fs.writeFile(path.join(tempDir, 'font.woff2'), 'mock woff2 data');
|
109
79
|
await fs.writeFile(path.join(tempDir, 'font.ttf'), 'mock ttf data');
|
110
|
-
|
111
|
-
// Set up a global variable pointing to the temp directory for potential use in mocks.
|
112
80
|
global.__MOCK_FILE_PATH__ = tempDir;
|
81
|
+
originalSetupLog('[SETUP] Mock font files written.');
|
113
82
|
|
114
|
-
|
115
|
-
|
116
|
-
// to prevent ENOENT race conditions.
|
117
|
-
|
118
|
-
console.log(`Ensuring sample project directory exists: ${baseDirs.sampleProject}`);
|
119
|
-
// 1. Ensure the sample project directory exists FIRST
|
83
|
+
originalSetupLog('[SETUP] Ensuring sample project dir...');
|
84
|
+
if (!baseDirs || !baseDirs.sampleProject) throw new Error("baseDirs.sampleProject is not defined!");
|
120
85
|
await ensureDir(baseDirs.sampleProject);
|
86
|
+
originalSetupLog('[SETUP] Sample project dir ensured.');
|
121
87
|
|
122
|
-
|
88
|
+
originalSetupLog('[SETUP] Writing sample project files...');
|
123
89
|
try {
|
124
|
-
console.log(`Writing sample project files to ${baseDirs.sampleProject}...`);
|
125
90
|
await Promise.all([
|
126
|
-
fs.writeFile(
|
127
|
-
|
128
|
-
|
129
|
-
),
|
130
|
-
fs.writeFile(path.join(baseDirs.sampleProject, 'styles.css'), 'body { margin: 0; }'),
|
131
|
-
fs.writeFile(path.join(baseDirs.sampleProject, 'script.js'), `console.log('hello');`),
|
132
|
-
fs.writeFile(path.join(baseDirs.sampleProject, 'logo.png'), 'fake image data') // Using string for simplicity
|
91
|
+
fs.writeFile(path.join(baseDirs.sampleProject, 'index.html'), ``),
|
92
|
+
fs.writeFile(path.join(baseDirs.sampleProject, 'styles.css'), '/* Mock CSS */'),
|
93
|
+
fs.writeFile(path.join(baseDirs.sampleProject, 'script.js'), '// Mock JS'),
|
94
|
+
fs.writeFile(path.join(baseDirs.sampleProject, 'logo.png'), 'fake image data')
|
133
95
|
]);
|
134
|
-
|
96
|
+
originalSetupLog('[SETUP] Sample project files written.');
|
135
97
|
} catch (writeError) {
|
136
|
-
|
137
|
-
|
138
|
-
throw writeError; // Re-throw to potentially fail the setup.
|
98
|
+
originalSetupLog('[SETUP-ERROR] Failed to write sample project files:', writeError);
|
99
|
+
throw writeError;
|
139
100
|
}
|
140
|
-
// --- End Fix ---
|
141
101
|
|
142
|
-
|
143
|
-
// This helps keep test output clean and allows assertions on console messages.
|
102
|
+
originalSetupLog('[SETUP] Mocking console...');
|
144
103
|
const originalLog = console.log;
|
145
104
|
const originalWarn = console.warn;
|
146
105
|
const originalError = console.error;
|
106
|
+
// Use the GLOBAL `jest` object to access `fn`
|
107
|
+
global.console.log = jest.fn((...args) => { if (process.env.DEBUG) originalLog(...args); });
|
108
|
+
global.console.warn = jest.fn((...args) => { /* ... filtering logic ... */ if (process.env.DEBUG) originalWarn(...args); });
|
109
|
+
global.console.error = jest.fn((...args) => { if (process.env.DEBUG) originalError(...args); });
|
110
|
+
originalSetupLog('[SETUP] Console mocked.');
|
147
111
|
|
148
|
-
|
149
|
-
global.console.log = jest.fn((...args) => {
|
150
|
-
// Only log to actual console if DEBUG environment variable is set.
|
151
|
-
if (process.env.DEBUG) {
|
152
|
-
originalLog(...args);
|
153
|
-
}
|
154
|
-
});
|
155
|
-
|
156
|
-
global.console.warn = jest.fn((...args) => {
|
157
|
-
// Optionally filter specific warnings you expect and don't want cluttering output.
|
158
|
-
const msg = args.join(' ');
|
159
|
-
if (
|
160
|
-
msg.includes('Could not fetch asset') ||
|
161
|
-
msg.includes('Error minifying')
|
162
|
-
// Add other expected warning patterns here if needed
|
163
|
-
) {
|
164
|
-
return; // Suppress specific known warnings
|
165
|
-
}
|
166
|
-
// Log other warnings, potentially only in debug mode.
|
167
|
-
if (process.env.DEBUG) {
|
168
|
-
originalWarn(...args);
|
169
|
-
}
|
170
|
-
});
|
171
|
-
|
172
|
-
global.console.error = jest.fn((...args) => {
|
173
|
-
// Always show errors, especially in debug mode.
|
174
|
-
// Could add filtering if there are known, non-critical errors to ignore.
|
175
|
-
if (process.env.DEBUG) {
|
176
|
-
originalError(...args);
|
177
|
-
}
|
178
|
-
// Potentially log even without DEBUG for visibility during tests
|
179
|
-
// originalError(...args);
|
180
|
-
});
|
181
|
-
|
182
|
-
console.log("Test setup complete."); // Log setup finish
|
112
|
+
originalSetupLog("[SETUP] Test setup complete.");
|
183
113
|
});
|
184
114
|
|
185
|
-
/**
|
186
|
-
* Jest's global afterAll hook. Runs once after all tests in a suite file have completed.
|
187
|
-
* Cleans up the temporary directory created for the test run.
|
188
|
-
*/
|
189
115
|
afterAll(async () => {
|
190
|
-
|
191
|
-
const dirs = global.__TEST_DIRECTORIES__; // Retrieve paths from global scope
|
192
|
-
if (!dirs) {
|
193
|
-
console.warn("Global test directories not found during cleanup.");
|
194
|
-
return;
|
195
|
-
}
|
196
|
-
|
116
|
+
originalSetupLog(`[SETUP] Cleaning up test environment in: ${tempDir}`);
|
197
117
|
try {
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
118
|
+
if (tempDir) {
|
119
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
120
|
+
originalSetupLog(`[SETUP] Successfully cleaned up: ${tempDir}`);
|
121
|
+
} else {
|
122
|
+
originalSetupLog(`[SETUP-WARN] tempDir variable was not defined during cleanup.`);
|
123
|
+
}
|
202
124
|
} catch (e) {
|
203
|
-
// Log errors during cleanup but don't fail the tests typically.
|
204
|
-
// ENOENT means the directory was already gone, which is fine.
|
205
125
|
if (e.code !== 'ENOENT') {
|
206
|
-
|
126
|
+
originalSetupLog(`[SETUP-WARN] Could not fully clean test directory ${tempDir}:`, e.message);
|
207
127
|
} else {
|
208
|
-
|
128
|
+
originalSetupLog(`[SETUP] Test directory already removed: ${tempDir}`);
|
209
129
|
}
|
210
130
|
}
|
211
131
|
});
|
package/package.json
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
{
|
2
2
|
"name": "portapack",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.0",
|
4
4
|
"description": "📦 A tool to bundle and minify HTML and all its dependencies into a single portable file.",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.js",
|
7
7
|
"types": "dist/index.d.ts",
|
8
8
|
"type": "module",
|
9
9
|
"bin": {
|
10
|
-
"portapack": "./dist/cli/cli-entry.
|
10
|
+
"portapack": "./dist/cli/cli-entry.cjs"
|
11
11
|
},
|
12
12
|
"scripts": {
|
13
13
|
"dev": "concurrently --success=all -n BUILD,DOCS,TEST -c green,blue,magenta \"npm run dev:build\" \"npm run dev:docs\" \"npm run dev:test\"",
|
14
14
|
"dev:build": "tsup --watch",
|
15
15
|
"dev:docs": "concurrently \"npm run docs:api:watch\" \"npm run docs:dev\"",
|
16
16
|
"dev:test": "cross-env FORCE_COLOR=1 jest --watch --clearCache --passWithNoTests --watchPathIgnorePatterns=\"<rootDir>/tests/__fixtures__/output\"",
|
17
|
-
"dev:test:debug": "cross-env
|
17
|
+
"dev:test:debug": "cross-env FORCE_COLOR=1 jest --watch --runTestsByPath",
|
18
18
|
"build": "npm run build:code && npm run docs:api && npm run docs:build",
|
19
19
|
"build:code": "tsup",
|
20
20
|
"example": "npx tsx examples/main.ts",
|
21
|
-
"test": "cross-env
|
22
|
-
"test:ci": "cross-env
|
21
|
+
"test": "cross-env jest --coverage",
|
22
|
+
"test:ci": "cross-env jest --coverage --ci",
|
23
23
|
"test:clear": "jest --clearCache",
|
24
24
|
"coverage": "jest --coverage && open coverage/lcov-report/index.html",
|
25
25
|
"docs:coverage": "npm run test && mkdir -p docs/test-coverage && cp -r coverage/lcov-report/* docs/test-coverage/",
|