portapack 0.3.0 → 0.3.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.
Files changed (74) hide show
  1. package/.eslintrc.json +67 -8
  2. package/.github/workflows/ci.yml +5 -4
  3. package/.releaserc.js +25 -27
  4. package/CHANGELOG.md +12 -19
  5. package/LICENSE.md +21 -0
  6. package/README.md +34 -36
  7. package/commitlint.config.js +30 -34
  8. package/dist/cli/cli-entry.cjs +199 -135
  9. package/dist/cli/cli-entry.cjs.map +1 -1
  10. package/dist/index.d.ts +0 -3
  11. package/dist/index.js +194 -134
  12. package/dist/index.js.map +1 -1
  13. package/docs/.vitepress/config.ts +36 -34
  14. package/docs/.vitepress/sidebar-generator.ts +89 -38
  15. package/docs/cli.md +29 -82
  16. package/docs/code-of-conduct.md +7 -1
  17. package/docs/configuration.md +103 -117
  18. package/docs/contributing.md +6 -2
  19. package/docs/deployment.md +10 -5
  20. package/docs/development.md +8 -5
  21. package/docs/getting-started.md +76 -45
  22. package/docs/index.md +1 -1
  23. package/docs/public/android-chrome-192x192.png +0 -0
  24. package/docs/public/android-chrome-512x512.png +0 -0
  25. package/docs/public/apple-touch-icon.png +0 -0
  26. package/docs/public/favicon-16x16.png +0 -0
  27. package/docs/public/favicon-32x32.png +0 -0
  28. package/docs/public/favicon.ico +0 -0
  29. package/docs/site.webmanifest +1 -0
  30. package/docs/troubleshooting.md +12 -1
  31. package/examples/main.ts +7 -10
  32. package/examples/sample-project/script.js +1 -1
  33. package/jest.config.ts +8 -13
  34. package/nodemon.json +5 -10
  35. package/package.json +2 -5
  36. package/src/cli/cli-entry.ts +2 -2
  37. package/src/cli/cli.ts +21 -16
  38. package/src/cli/options.ts +127 -113
  39. package/src/core/bundler.ts +254 -221
  40. package/src/core/extractor.ts +639 -520
  41. package/src/core/minifier.ts +173 -162
  42. package/src/core/packer.ts +141 -137
  43. package/src/core/parser.ts +74 -73
  44. package/src/core/web-fetcher.ts +270 -258
  45. package/src/index.ts +18 -17
  46. package/src/types.ts +9 -11
  47. package/src/utils/font.ts +12 -6
  48. package/src/utils/logger.ts +110 -105
  49. package/src/utils/meta.ts +75 -76
  50. package/src/utils/mime.ts +50 -50
  51. package/src/utils/slugify.ts +33 -34
  52. package/tests/unit/cli/cli-entry.test.ts +72 -70
  53. package/tests/unit/cli/cli.test.ts +314 -278
  54. package/tests/unit/cli/options.test.ts +294 -301
  55. package/tests/unit/core/bundler.test.ts +426 -329
  56. package/tests/unit/core/extractor.test.ts +828 -380
  57. package/tests/unit/core/minifier.test.ts +374 -274
  58. package/tests/unit/core/packer.test.ts +298 -264
  59. package/tests/unit/core/parser.test.ts +538 -150
  60. package/tests/unit/core/web-fetcher.test.ts +389 -359
  61. package/tests/unit/index.test.ts +238 -197
  62. package/tests/unit/utils/font.test.ts +26 -21
  63. package/tests/unit/utils/logger.test.ts +267 -260
  64. package/tests/unit/utils/meta.test.ts +29 -28
  65. package/tests/unit/utils/mime.test.ts +73 -74
  66. package/tests/unit/utils/slugify.test.ts +14 -12
  67. package/tsconfig.build.json +9 -10
  68. package/tsconfig.jest.json +2 -1
  69. package/tsconfig.json +2 -2
  70. package/tsup.config.ts +8 -8
  71. package/typedoc.json +5 -9
  72. package/docs/demo.md +0 -46
  73. /package/docs/{portapack-transparent.png → public/portapack-transparent.png} +0 -0
  74. /package/docs/{portapack.jpg → public/portapack.jpg} +0 -0
@@ -1,5 +1,3 @@
1
- // tests/unit/cli/options.test.ts
2
-
3
1
  import { describe, it, expect, afterEach } from '@jest/globals';
4
2
  // Import the function to test and necessary types
5
3
  import { parseOptions } from '../../../src/cli/options'; // Adjust path if needed
@@ -7,8 +5,8 @@ import { LogLevel, type CLIOptions } from '../../../src/types'; // Adjust path i
7
5
 
8
6
  // Helper function to simulate process.argv structure
9
7
  const runParseOptions = (args: string[]): CLIOptions => {
10
- // Prepend standard node/script path expected by commander
11
- return parseOptions(['node', 'script.js', ...args]);
8
+ // Prepend standard node/script path expected by commander
9
+ return parseOptions(['node', 'script.js', ...args]);
12
10
  };
13
11
 
14
12
  // Extract the helper function for direct testing if needed (though it's private)
@@ -16,301 +14,296 @@ const runParseOptions = (args: string[]): CLIOptions => {
16
14
  // const { parseRecursiveValue } = require('../../../src/cli/options'); // Or use import { parseRecursiveValue } from '...' if exported
17
15
 
18
16
  describe('🔧 CLI Options Parser (options.ts)', () => {
17
+ // Define expected defaults for easier comparison
18
+ const defaultOptions: Partial<CLIOptions> = {
19
+ baseUrl: undefined,
20
+ dryRun: false,
21
+ output: undefined,
22
+ verbose: false,
23
+ input: undefined,
24
+ logLevel: LogLevel.INFO,
25
+ recursive: undefined, // No flag means undefined
26
+ embedAssets: true, // Default is true
27
+ minifyHtml: true, // Default is true
28
+ minifyCss: true, // Default is true
29
+ minifyJs: true, // Default is true
30
+ };
31
+
32
+ afterEach(() => {
33
+ // Commander potentially maintains state between parses if not careful,
34
+ // although creating a new Command instance each time in parseOptions mitigates this.
35
+ // No specific cleanup usually needed here unless mocking process.argv directly.
36
+ });
37
+
38
+ describe('Basic Options', () => {
39
+ it('should parse input argument', () => {
40
+ const input = 'input.html';
41
+ const opts = runParseOptions([input]);
42
+ expect(opts.input).toBe(input);
43
+ });
44
+
45
+ it('should parse input argument with other flags', () => {
46
+ const input = 'https://example.com';
47
+ const output = 'out.html';
48
+ const opts = runParseOptions([input, '-o', output]);
49
+ expect(opts.input).toBe(input);
50
+ expect(opts.output).toBe(output);
51
+ });
52
+
53
+ it('should parse --output/-o', () => {
54
+ const output = 'dist/bundle.html';
55
+ expect(runParseOptions(['-o', output]).output).toBe(output);
56
+ expect(runParseOptions(['--output', output]).output).toBe(output);
57
+ });
58
+
59
+ it('should parse --base-url/-b', () => {
60
+ const url = 'https://example.com/base/';
61
+ expect(runParseOptions(['-b', url]).baseUrl).toBe(url);
62
+ expect(runParseOptions(['--base-url', url]).baseUrl).toBe(url);
63
+ });
64
+
65
+ it('should parse --dry-run/-d', () => {
66
+ expect(runParseOptions(['-d']).dryRun).toBe(true);
67
+ expect(runParseOptions(['--dry-run']).dryRun).toBe(true);
68
+ });
69
+
70
+ it('should have correct default values when no flags are provided', () => {
71
+ const opts = runParseOptions([]);
72
+ // Check against defined defaults
73
+ expect(opts).toMatchObject(defaultOptions);
74
+ // Explicitly check potentially tricky defaults
75
+ expect(opts.logLevel).toBe(LogLevel.INFO);
76
+ expect(opts.embedAssets).toBe(true);
77
+ expect(opts.minifyHtml).toBe(true);
78
+ expect(opts.minifyCss).toBe(true);
79
+ expect(opts.minifyJs).toBe(true);
80
+ expect(opts.dryRun).toBe(false);
81
+ expect(opts.verbose).toBe(false);
82
+ expect(opts.recursive).toBeUndefined();
83
+ });
84
+ });
85
+
86
+ describe('Logging Options', () => {
87
+ it('should default logLevel to INFO', () => {
88
+ const opts = runParseOptions([]);
89
+ expect(opts.logLevel).toBe(LogLevel.INFO);
90
+ expect(opts.verbose).toBe(false);
91
+ });
92
+
93
+ it('should set verbose flag', () => {
94
+ const opts = runParseOptions(['-v']);
95
+ expect(opts.verbose).toBe(true);
96
+ });
97
+
98
+ it('should set logLevel to DEBUG with --verbose/-v', () => {
99
+ expect(runParseOptions(['-v']).logLevel).toBe(LogLevel.DEBUG);
100
+ expect(runParseOptions(['--verbose']).logLevel).toBe(LogLevel.DEBUG);
101
+ });
102
+
103
+ it('should set logLevel with --log-level', () => {
104
+ expect(runParseOptions(['--log-level', 'debug']).logLevel).toBe(LogLevel.DEBUG);
105
+ expect(runParseOptions(['--log-level', 'info']).logLevel).toBe(LogLevel.INFO);
106
+ expect(runParseOptions(['--log-level', 'warn']).logLevel).toBe(LogLevel.WARN);
107
+ expect(runParseOptions(['--log-level', 'error']).logLevel).toBe(LogLevel.ERROR);
108
+ expect(runParseOptions(['--log-level', 'silent']).logLevel).toBe(LogLevel.NONE);
109
+ expect(runParseOptions(['--log-level', 'none']).logLevel).toBe(LogLevel.NONE);
110
+ });
111
+
112
+ it('should prioritize --log-level over --verbose', () => {
113
+ // Both present, --log-level wins
114
+ expect(runParseOptions(['-v', '--log-level', 'warn']).logLevel).toBe(LogLevel.WARN);
115
+ expect(runParseOptions(['--log-level', 'error', '--verbose']).logLevel).toBe(LogLevel.ERROR);
116
+ });
117
+
118
+ // Commander handles choice validation, but we could test invalid if needed (it would exit/error)
119
+ // it('should throw error for invalid --log-level choice', () => { ... });
120
+ });
121
+
122
+ describe('Embedding Options', () => {
123
+ it('should default embedAssets to true', () => {
124
+ const opts = runParseOptions([]);
125
+ expect(opts.embedAssets).toBe(true);
126
+ });
127
+
128
+ it('should respect -e/--embed-assets (should still be true)', () => {
129
+ // This flag confirms the default, doesn't change behavior unless --no is used
130
+ expect(runParseOptions(['-e']).embedAssets).toBe(true);
131
+ expect(runParseOptions(['--embed-assets']).embedAssets).toBe(true);
132
+ });
133
+
134
+ it('should set embedAssets to false with --no-embed-assets', () => {
135
+ const opts = runParseOptions(['--no-embed-assets']);
136
+ expect(opts.embedAssets).toBe(false);
137
+ });
138
+
139
+ it('should prioritize --no-embed-assets over -e', () => {
140
+ // If both somehow passed, the negation should win
141
+ expect(runParseOptions(['-e', '--no-embed-assets']).embedAssets).toBe(false);
142
+ expect(runParseOptions(['--no-embed-assets', '-e']).embedAssets).toBe(false);
143
+ });
144
+ });
145
+
146
+ describe('Minification Options', () => {
147
+ it('should default all minify flags to true', () => {
148
+ const opts = runParseOptions([]);
149
+ expect(opts.minifyHtml).toBe(true);
150
+ expect(opts.minifyCss).toBe(true);
151
+ expect(opts.minifyJs).toBe(true);
152
+ });
153
+
154
+ it('should respect -m/--minify (all still true)', () => {
155
+ // This flag confirms the default behavior based on current logic
156
+ const optsM = runParseOptions(['-m']);
157
+ expect(optsM.minifyHtml).toBe(true);
158
+ expect(optsM.minifyCss).toBe(true);
159
+ expect(optsM.minifyJs).toBe(true);
160
+ const optsMinify = runParseOptions(['--minify']);
161
+ expect(optsMinify.minifyHtml).toBe(true);
162
+ expect(optsMinify.minifyCss).toBe(true);
163
+ expect(optsMinify.minifyJs).toBe(true);
164
+ });
165
+
166
+ it('should set all minify flags to false with --no-minify', () => {
167
+ const opts = runParseOptions(['--no-minify']);
168
+ expect(opts.minifyHtml).toBe(false);
169
+ expect(opts.minifyCss).toBe(false);
170
+ expect(opts.minifyJs).toBe(false);
171
+ });
172
+
173
+ it('should set only minifyHtml to false with --no-minify-html', () => {
174
+ const opts = runParseOptions(['--no-minify-html']);
175
+ expect(opts.minifyHtml).toBe(false);
176
+ expect(opts.minifyCss).toBe(true);
177
+ expect(opts.minifyJs).toBe(true);
178
+ });
179
+
180
+ it('should set only minifyCss to false with --no-minify-css', () => {
181
+ const opts = runParseOptions(['--no-minify-css']);
182
+ expect(opts.minifyHtml).toBe(true);
183
+ expect(opts.minifyCss).toBe(false);
184
+ expect(opts.minifyJs).toBe(true);
185
+ });
186
+
187
+ it('should set only minifyJs to false with --no-minify-js', () => {
188
+ const opts = runParseOptions(['--no-minify-js']);
189
+ expect(opts.minifyHtml).toBe(true);
190
+ expect(opts.minifyCss).toBe(true);
191
+ expect(opts.minifyJs).toBe(false);
192
+ });
193
+
194
+ it('should prioritize --no-minify over individual --no-minify-<type> flags', () => {
195
+ // Commander processes flags in order, but our logic checks opts.minify first
196
+ const opts = runParseOptions(['--no-minify-html', '--no-minify']);
197
+ expect(opts.minifyHtml).toBe(false);
198
+ expect(opts.minifyCss).toBe(false); // Should also be false due to --no-minify
199
+ expect(opts.minifyJs).toBe(false); // Should also be false due to --no-minify
200
+ });
201
+
202
+ it('should prioritize individual --no-minify-<type> flags over --minify', () => {
203
+ // If both --minify and --no-minify-html are present, html should be false
204
+ const opts = runParseOptions(['--minify', '--no-minify-html']);
205
+ expect(opts.minifyHtml).toBe(false); // Disabled specifically
206
+ expect(opts.minifyCss).toBe(true); // Stays enabled (default)
207
+ expect(opts.minifyJs).toBe(true); // Stays enabled (default)
208
+ });
209
+
210
+ it('should handle combinations of --no-minify-<type>', () => {
211
+ const opts = runParseOptions(['--no-minify-html', '--no-minify-js']);
212
+ expect(opts.minifyHtml).toBe(false);
213
+ expect(opts.minifyCss).toBe(true);
214
+ expect(opts.minifyJs).toBe(false);
215
+ });
216
+ });
217
+
218
+ describe('Recursive/MaxDepth Options', () => {
219
+ it('should have recursive undefined by default', () => {
220
+ const opts = runParseOptions([]);
221
+ expect(opts.recursive).toBeUndefined();
222
+ });
223
+
224
+ it('should set recursive to true with -r', () => {
225
+ const opts = runParseOptions(['-r']);
226
+ expect(opts.recursive).toBe(true);
227
+ });
228
+
229
+ it('should set recursive to true with --recursive', () => {
230
+ const opts = runParseOptions(['--recursive']);
231
+ expect(opts.recursive).toBe(true);
232
+ });
233
+
234
+ it('should set recursive to a number with -r <depth>', () => {
235
+ const opts = runParseOptions(['-r', '3']);
236
+ expect(opts.recursive).toBe(3);
237
+ });
19
238
 
20
- // Define expected defaults for easier comparison
21
- const defaultOptions: Partial<CLIOptions> = {
22
- baseUrl: undefined,
23
- dryRun: false,
24
- output: undefined,
25
- verbose: false,
26
- input: undefined,
27
- logLevel: LogLevel.INFO,
28
- recursive: undefined, // No flag means undefined
29
- embedAssets: true, // Default is true
30
- minifyHtml: true, // Default is true
31
- minifyCss: true, // Default is true
32
- minifyJs: true, // Default is true
33
- };
34
-
35
- afterEach(() => {
36
- // Commander potentially maintains state between parses if not careful,
37
- // although creating a new Command instance each time in parseOptions mitigates this.
38
- // No specific cleanup usually needed here unless mocking process.argv directly.
39
- });
40
-
41
- describe('Basic Options', () => {
42
- it('should parse input argument', () => {
43
- const input = 'input.html';
44
- const opts = runParseOptions([input]);
45
- expect(opts.input).toBe(input);
46
- });
47
-
48
- it('should parse input argument with other flags', () => {
49
- const input = 'https://example.com';
50
- const output = 'out.html';
51
- const opts = runParseOptions([input, '-o', output]);
52
- expect(opts.input).toBe(input);
53
- expect(opts.output).toBe(output);
54
- });
55
-
56
- it('should parse --output/-o', () => {
57
- const output = 'dist/bundle.html';
58
- expect(runParseOptions(['-o', output]).output).toBe(output);
59
- expect(runParseOptions(['--output', output]).output).toBe(output);
60
- });
61
-
62
- it('should parse --base-url/-b', () => {
63
- const url = 'https://example.com/base/';
64
- expect(runParseOptions(['-b', url]).baseUrl).toBe(url);
65
- expect(runParseOptions(['--base-url', url]).baseUrl).toBe(url);
66
- });
67
-
68
- it('should parse --dry-run/-d', () => {
69
- expect(runParseOptions(['-d']).dryRun).toBe(true);
70
- expect(runParseOptions(['--dry-run']).dryRun).toBe(true);
71
- });
72
-
73
- it('should have correct default values when no flags are provided', () => {
74
- const opts = runParseOptions([]);
75
- // Check against defined defaults
76
- expect(opts).toMatchObject(defaultOptions);
77
- // Explicitly check potentially tricky defaults
78
- expect(opts.logLevel).toBe(LogLevel.INFO);
79
- expect(opts.embedAssets).toBe(true);
80
- expect(opts.minifyHtml).toBe(true);
81
- expect(opts.minifyCss).toBe(true);
82
- expect(opts.minifyJs).toBe(true);
83
- expect(opts.dryRun).toBe(false);
84
- expect(opts.verbose).toBe(false);
85
- expect(opts.recursive).toBeUndefined();
86
- });
87
- });
88
-
89
- describe('Logging Options', () => {
90
- it('should default logLevel to INFO', () => {
91
- const opts = runParseOptions([]);
92
- expect(opts.logLevel).toBe(LogLevel.INFO);
93
- expect(opts.verbose).toBe(false);
94
- });
95
-
96
- it('should set verbose flag', () => {
97
- const opts = runParseOptions(['-v']);
98
- expect(opts.verbose).toBe(true);
99
- });
100
-
101
- it('should set logLevel to DEBUG with --verbose/-v', () => {
102
- expect(runParseOptions(['-v']).logLevel).toBe(LogLevel.DEBUG);
103
- expect(runParseOptions(['--verbose']).logLevel).toBe(LogLevel.DEBUG);
104
- });
105
-
106
- it('should set logLevel with --log-level', () => {
107
- expect(runParseOptions(['--log-level', 'debug']).logLevel).toBe(LogLevel.DEBUG);
108
- expect(runParseOptions(['--log-level', 'info']).logLevel).toBe(LogLevel.INFO);
109
- expect(runParseOptions(['--log-level', 'warn']).logLevel).toBe(LogLevel.WARN);
110
- expect(runParseOptions(['--log-level', 'error']).logLevel).toBe(LogLevel.ERROR);
111
- expect(runParseOptions(['--log-level', 'silent']).logLevel).toBe(LogLevel.NONE);
112
- expect(runParseOptions(['--log-level', 'none']).logLevel).toBe(LogLevel.NONE);
113
- });
114
-
115
- it('should prioritize --log-level over --verbose', () => {
116
- // Both present, --log-level wins
117
- expect(runParseOptions(['-v', '--log-level', 'warn']).logLevel).toBe(LogLevel.WARN);
118
- expect(runParseOptions(['--log-level', 'error', '--verbose']).logLevel).toBe(LogLevel.ERROR);
119
- });
120
-
121
- // Commander handles choice validation, but we could test invalid if needed (it would exit/error)
122
- // it('should throw error for invalid --log-level choice', () => { ... });
123
- });
124
-
125
- describe('Embedding Options', () => {
126
- it('should default embedAssets to true', () => {
127
- const opts = runParseOptions([]);
128
- expect(opts.embedAssets).toBe(true);
129
- });
130
-
131
- it('should respect -e/--embed-assets (should still be true)', () => {
132
- // This flag confirms the default, doesn't change behavior unless --no is used
133
- expect(runParseOptions(['-e']).embedAssets).toBe(true);
134
- expect(runParseOptions(['--embed-assets']).embedAssets).toBe(true);
135
- });
136
-
137
- it('should set embedAssets to false with --no-embed-assets', () => {
138
- const opts = runParseOptions(['--no-embed-assets']);
139
- expect(opts.embedAssets).toBe(false);
140
- });
141
-
142
- it('should prioritize --no-embed-assets over -e', () => {
143
- // If both somehow passed, the negation should win
144
- expect(runParseOptions(['-e', '--no-embed-assets']).embedAssets).toBe(false);
145
- expect(runParseOptions(['--no-embed-assets', '-e']).embedAssets).toBe(false);
146
- });
147
- });
148
-
149
- describe('Minification Options', () => {
150
- it('should default all minify flags to true', () => {
151
- const opts = runParseOptions([]);
152
- expect(opts.minifyHtml).toBe(true);
153
- expect(opts.minifyCss).toBe(true);
154
- expect(opts.minifyJs).toBe(true);
155
- });
156
-
157
- it('should respect -m/--minify (all still true)', () => {
158
- // This flag confirms the default behavior based on current logic
159
- const optsM = runParseOptions(['-m']);
160
- expect(optsM.minifyHtml).toBe(true);
161
- expect(optsM.minifyCss).toBe(true);
162
- expect(optsM.minifyJs).toBe(true);
163
- const optsMinify = runParseOptions(['--minify']);
164
- expect(optsMinify.minifyHtml).toBe(true);
165
- expect(optsMinify.minifyCss).toBe(true);
166
- expect(optsMinify.minifyJs).toBe(true);
167
- });
168
-
169
- it('should set all minify flags to false with --no-minify', () => {
170
- const opts = runParseOptions(['--no-minify']);
171
- expect(opts.minifyHtml).toBe(false);
172
- expect(opts.minifyCss).toBe(false);
173
- expect(opts.minifyJs).toBe(false);
174
- });
175
-
176
- it('should set only minifyHtml to false with --no-minify-html', () => {
177
- const opts = runParseOptions(['--no-minify-html']);
178
- expect(opts.minifyHtml).toBe(false);
179
- expect(opts.minifyCss).toBe(true);
180
- expect(opts.minifyJs).toBe(true);
181
- });
182
-
183
- it('should set only minifyCss to false with --no-minify-css', () => {
184
- const opts = runParseOptions(['--no-minify-css']);
185
- expect(opts.minifyHtml).toBe(true);
186
- expect(opts.minifyCss).toBe(false);
187
- expect(opts.minifyJs).toBe(true);
188
- });
189
-
190
- it('should set only minifyJs to false with --no-minify-js', () => {
191
- const opts = runParseOptions(['--no-minify-js']);
192
- expect(opts.minifyHtml).toBe(true);
193
- expect(opts.minifyCss).toBe(true);
194
- expect(opts.minifyJs).toBe(false);
195
- });
196
-
197
- it('should prioritize --no-minify over individual --no-minify-<type> flags', () => {
198
- // Commander processes flags in order, but our logic checks opts.minify first
199
- const opts = runParseOptions(['--no-minify-html', '--no-minify']);
200
- expect(opts.minifyHtml).toBe(false);
201
- expect(opts.minifyCss).toBe(false); // Should also be false due to --no-minify
202
- expect(opts.minifyJs).toBe(false); // Should also be false due to --no-minify
203
- });
204
-
205
- it('should prioritize individual --no-minify-<type> flags over --minify', () => {
206
- // If both --minify and --no-minify-html are present, html should be false
207
- const opts = runParseOptions(['--minify', '--no-minify-html']);
208
- expect(opts.minifyHtml).toBe(false); // Disabled specifically
209
- expect(opts.minifyCss).toBe(true); // Stays enabled (default)
210
- expect(opts.minifyJs).toBe(true); // Stays enabled (default)
211
- });
212
-
213
- it('should handle combinations of --no-minify-<type>', () => {
214
- const opts = runParseOptions(['--no-minify-html', '--no-minify-js']);
215
- expect(opts.minifyHtml).toBe(false);
216
- expect(opts.minifyCss).toBe(true);
217
- expect(opts.minifyJs).toBe(false);
218
- });
219
- });
220
-
221
- describe('Recursive/MaxDepth Options', () => {
222
- it('should have recursive undefined by default', () => {
223
- const opts = runParseOptions([]);
224
- expect(opts.recursive).toBeUndefined();
225
- });
226
-
227
- it('should set recursive to true with -r', () => {
228
- const opts = runParseOptions(['-r']);
229
- expect(opts.recursive).toBe(true);
230
- });
231
-
232
- it('should set recursive to true with --recursive', () => {
233
- const opts = runParseOptions(['--recursive']);
234
- expect(opts.recursive).toBe(true);
235
- });
236
-
237
- it('should set recursive to a number with -r <depth>', () => {
238
- const opts = runParseOptions(['-r', '3']);
239
- expect(opts.recursive).toBe(3);
240
- });
241
-
242
- it('should set recursive to a number with --recursive <depth>', () => {
243
- const opts = runParseOptions(['--recursive', '5']);
244
- expect(opts.recursive).toBe(5);
245
- });
246
-
247
- it('should parse -r value correctly (helper function effect)', () => {
248
- expect(runParseOptions(['-r', '0']).recursive).toBe(0);
249
- expect(runParseOptions(['-r', '10']).recursive).toBe(10);
250
- expect(runParseOptions(['-r', 'abc']).recursive).toBe(true);
251
-
252
- // --- FIX: Remove this line ---
253
- // expect(runParseOptions(['-r', '-5']).recursive).toBe(true);
254
- // ---------------------------
255
-
256
- // Add this line to ensure the flag-only case is tested:
257
- expect(runParseOptions(['-r']).recursive).toBe(true);
258
- });
259
-
260
- it('should set recursive to a number with --max-depth <depth>', () => {
261
- const opts = runParseOptions(['--max-depth', '2']);
262
- expect(opts.recursive).toBe(2);
263
- });
264
-
265
- it('should handle invalid --max-depth (NaN becomes undefined, logic handles it)', () => {
266
- // Commander's parseInt will return NaN for 'abc', which our logic ignores
267
- const opts = runParseOptions(['--max-depth', 'abc']);
268
- expect(opts.recursive).toBeUndefined(); // maxDepth is ignored, recursive wasn't set
269
- });
270
-
271
- it('should handle negative --max-depth (ignored)', () => {
272
- // Our logic ignores maxDepth < 0
273
- const opts = runParseOptions(['--max-depth', '-1']);
274
- expect(opts.recursive).toBeUndefined(); // maxDepth is ignored, recursive wasn't set
275
- });
276
-
277
- it('should prioritize --max-depth over -r (flag only)', () => {
278
- const opts = runParseOptions(['-r', '--max-depth', '4']);
279
- expect(opts.recursive).toBe(4);
280
- });
281
-
282
- it('should prioritize --max-depth over -r <depth>', () => {
283
- const opts = runParseOptions(['-r', '1', '--max-depth', '5']);
284
- expect(opts.recursive).toBe(5);
285
- });
286
-
287
- it('should prioritize --max-depth over --recursive (flag only)', () => {
288
- const opts = runParseOptions(['--recursive', '--max-depth', '2']);
289
- expect(opts.recursive).toBe(2);
290
- });
291
-
292
- it('should prioritize --max-depth over --recursive <depth>', () => {
293
- const opts = runParseOptions(['--recursive', '3', '--max-depth', '1']);
294
- expect(opts.recursive).toBe(1);
295
- });
296
- });
297
-
298
- // Optional: Direct tests for the helper if it were exported
299
- // describe('parseRecursiveValue() Helper', () => {
300
- // it('should return true for undefined', () => {
301
- // expect(parseRecursiveValue(undefined)).toBe(true);
302
- // });
303
- // it('should return number for valid string', () => {
304
- // expect(parseRecursiveValue('0')).toBe(0);
305
- // expect(parseRecursiveValue('5')).toBe(5);
306
- // });
307
- // it('should return true for invalid number string', () => {
308
- // expect(parseRecursiveValue('abc')).toBe(true);
309
- // expect(parseRecursiveValue('')).toBe(true); // isNaN('') is false, but parseInt('') is NaN
310
- // });
311
- // it('should return true for negative number string', () => {
312
- // expect(parseRecursiveValue('-1')).toBe(true);
313
- // expect(parseRecursiveValue('-10')).toBe(true);
314
- // });
315
- // });
316
- });
239
+ it('should set recursive to a number with --recursive <depth>', () => {
240
+ const opts = runParseOptions(['--recursive', '5']);
241
+ expect(opts.recursive).toBe(5);
242
+ });
243
+
244
+ it('should parse -r value correctly (helper function effect)', () => {
245
+ expect(runParseOptions(['-r', '0']).recursive).toBe(0);
246
+ expect(runParseOptions(['-r', '10']).recursive).toBe(10);
247
+ expect(runParseOptions(['-r', 'abc']).recursive).toBe(true);
248
+
249
+ // Add this line to ensure the flag-only case is tested:
250
+ expect(runParseOptions(['-r']).recursive).toBe(true);
251
+ });
252
+
253
+ it('should set recursive to a number with --max-depth <depth>', () => {
254
+ const opts = runParseOptions(['--max-depth', '2']);
255
+ expect(opts.recursive).toBe(2);
256
+ });
257
+
258
+ it('should handle invalid --max-depth (NaN becomes undefined, logic handles it)', () => {
259
+ // Commander's parseInt will return NaN for 'abc', which our logic ignores
260
+ const opts = runParseOptions(['--max-depth', 'abc']);
261
+ expect(opts.recursive).toBeUndefined(); // maxDepth is ignored, recursive wasn't set
262
+ });
263
+
264
+ it('should handle negative --max-depth (ignored)', () => {
265
+ // Our logic ignores maxDepth < 0
266
+ const opts = runParseOptions(['--max-depth', '-1']);
267
+ expect(opts.recursive).toBeUndefined(); // maxDepth is ignored, recursive wasn't set
268
+ });
269
+
270
+ it('should prioritize --max-depth over -r (flag only)', () => {
271
+ const opts = runParseOptions(['-r', '--max-depth', '4']);
272
+ expect(opts.recursive).toBe(4);
273
+ });
274
+
275
+ it('should prioritize --max-depth over -r <depth>', () => {
276
+ const opts = runParseOptions(['-r', '1', '--max-depth', '5']);
277
+ expect(opts.recursive).toBe(5);
278
+ });
279
+
280
+ it('should prioritize --max-depth over --recursive (flag only)', () => {
281
+ const opts = runParseOptions(['--recursive', '--max-depth', '2']);
282
+ expect(opts.recursive).toBe(2);
283
+ });
284
+
285
+ it('should prioritize --max-depth over --recursive <depth>', () => {
286
+ const opts = runParseOptions(['--recursive', '3', '--max-depth', '1']);
287
+ expect(opts.recursive).toBe(1);
288
+ });
289
+ });
290
+
291
+ // Optional: Direct tests for the helper if it were exported
292
+ // describe('parseRecursiveValue() Helper', () => {
293
+ // it('should return true for undefined', () => {
294
+ // expect(parseRecursiveValue(undefined)).toBe(true);
295
+ // });
296
+ // it('should return number for valid string', () => {
297
+ // expect(parseRecursiveValue('0')).toBe(0);
298
+ // expect(parseRecursiveValue('5')).toBe(5);
299
+ // });
300
+ // it('should return true for invalid number string', () => {
301
+ // expect(parseRecursiveValue('abc')).toBe(true);
302
+ // expect(parseRecursiveValue('')).toBe(true); // isNaN('') is false, but parseInt('') is NaN
303
+ // });
304
+ // it('should return true for negative number string', () => {
305
+ // expect(parseRecursiveValue('-1')).toBe(true);
306
+ // expect(parseRecursiveValue('-10')).toBe(true);
307
+ // });
308
+ // });
309
+ });