portapack 0.3.1 → 0.3.3

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/.releaserc.js +25 -27
  3. package/CHANGELOG.md +14 -22
  4. package/LICENSE.md +21 -0
  5. package/README.md +22 -53
  6. package/commitlint.config.js +30 -34
  7. package/dist/cli/cli-entry.cjs +183 -98
  8. package/dist/cli/cli-entry.cjs.map +1 -1
  9. package/dist/index.d.ts +0 -3
  10. package/dist/index.js +178 -97
  11. package/dist/index.js.map +1 -1
  12. package/docs/.vitepress/config.ts +38 -33
  13. package/docs/.vitepress/sidebar-generator.ts +89 -38
  14. package/docs/architecture.md +186 -0
  15. package/docs/cli.md +23 -23
  16. package/docs/code-of-conduct.md +7 -1
  17. package/docs/configuration.md +12 -11
  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 +13 -13
  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/roadmap.md +233 -0
  30. package/docs/site.webmanifest +1 -0
  31. package/docs/troubleshooting.md +12 -1
  32. package/examples/main.ts +5 -30
  33. package/examples/sample-project/script.js +1 -1
  34. package/jest.config.ts +8 -13
  35. package/nodemon.json +5 -10
  36. package/package.json +2 -5
  37. package/src/cli/cli-entry.ts +2 -2
  38. package/src/cli/cli.ts +21 -16
  39. package/src/cli/options.ts +127 -113
  40. package/src/core/bundler.ts +253 -222
  41. package/src/core/extractor.ts +632 -565
  42. package/src/core/minifier.ts +173 -162
  43. package/src/core/packer.ts +141 -137
  44. package/src/core/parser.ts +74 -73
  45. package/src/core/web-fetcher.ts +270 -258
  46. package/src/index.ts +18 -17
  47. package/src/types.ts +9 -11
  48. package/src/utils/font.ts +12 -6
  49. package/src/utils/logger.ts +110 -105
  50. package/src/utils/meta.ts +75 -76
  51. package/src/utils/mime.ts +50 -50
  52. package/src/utils/slugify.ts +33 -34
  53. package/tests/unit/cli/cli-entry.test.ts +72 -70
  54. package/tests/unit/cli/cli.test.ts +314 -278
  55. package/tests/unit/cli/options.test.ts +294 -301
  56. package/tests/unit/core/bundler.test.ts +426 -329
  57. package/tests/unit/core/extractor.test.ts +793 -549
  58. package/tests/unit/core/minifier.test.ts +374 -274
  59. package/tests/unit/core/packer.test.ts +298 -264
  60. package/tests/unit/core/parser.test.ts +538 -150
  61. package/tests/unit/core/web-fetcher.test.ts +389 -359
  62. package/tests/unit/index.test.ts +238 -197
  63. package/tests/unit/utils/font.test.ts +26 -21
  64. package/tests/unit/utils/logger.test.ts +267 -260
  65. package/tests/unit/utils/meta.test.ts +29 -28
  66. package/tests/unit/utils/mime.test.ts +73 -74
  67. package/tests/unit/utils/slugify.test.ts +14 -12
  68. package/tsconfig.build.json +9 -10
  69. package/tsconfig.jest.json +1 -1
  70. package/tsconfig.json +2 -2
  71. package/tsup.config.ts +8 -9
  72. package/typedoc.json +5 -9
  73. /package/docs/{portapack-transparent.png → public/portapack-transparent.png} +0 -0
  74. /package/docs/{portapack.jpg → public/portapack.jpg} +0 -0
@@ -8,89 +8,88 @@ import { describe, it, expect } from '@jest/globals';
8
8
  import type { Asset } from '../../../src/types'; // Import Asset type
9
9
 
10
10
  describe('🧪 MIME Utilities', () => {
11
+ describe('guessMimeType()', () => {
12
+ const defaultResult = { mime: 'application/octet-stream', assetType: 'other' as Asset['type'] };
11
13
 
12
- describe('guessMimeType()', () => {
13
- const defaultResult = { mime: 'application/octet-stream', assetType: 'other' as Asset['type'] };
14
+ // Test cases: [input, expectedMime, expectedAssetType]
15
+ const testCases: [string, string, Asset['type']][] = [
16
+ // CSS
17
+ ['style.css', 'text/css', 'css'],
18
+ ['path/to/style.CSS', 'text/css', 'css'], // Case-insensitive extension
19
+ ['style.css?v=1.0', 'text/css', 'css'], // With query string
20
+ ['/path/style.css#id', 'text/css', 'css'], // With fragment
21
+ ['https://example.com/a/b/c/style.css?q=1', 'text/css', 'css'], // Remote URL
14
22
 
15
- // Test cases: [input, expectedMime, expectedAssetType]
16
- const testCases: [string, string, Asset['type']][] = [
17
- // CSS
18
- ['style.css', 'text/css', 'css'],
19
- ['path/to/style.CSS', 'text/css', 'css'], // Case-insensitive extension
20
- ['style.css?v=1.0', 'text/css', 'css'], // With query string
21
- ['/path/style.css#id', 'text/css', 'css'], // With fragment
22
- ['https://example.com/a/b/c/style.css?q=1', 'text/css', 'css'], // Remote URL
23
+ // JS
24
+ ['script.js', 'application/javascript', 'js'],
25
+ ['script.mjs', 'application/javascript', 'js'],
26
+ ['https://cdn.com/lib.js', 'application/javascript', 'js'],
23
27
 
24
- // JS
25
- ['script.js', 'application/javascript', 'js'],
26
- ['script.mjs', 'application/javascript', 'js'],
27
- ['https://cdn.com/lib.js', 'application/javascript', 'js'],
28
+ // Images
29
+ ['logo.png', 'image/png', 'image'],
30
+ ['photo.jpg', 'image/jpeg', 'image'],
31
+ ['image.jpeg', 'image/jpeg', 'image'],
32
+ ['anim.gif', 'image/gif', 'image'],
33
+ ['icon.svg', 'image/svg+xml', 'image'],
34
+ ['image.webp', 'image/webp', 'image'],
35
+ ['favicon.ico', 'image/x-icon', 'image'],
36
+ ['image.avif', 'image/avif', 'image'],
28
37
 
29
- // Images
30
- ['logo.png', 'image/png', 'image'],
31
- ['photo.jpg', 'image/jpeg', 'image'],
32
- ['image.jpeg', 'image/jpeg', 'image'],
33
- ['anim.gif', 'image/gif', 'image'],
34
- ['icon.svg', 'image/svg+xml', 'image'],
35
- ['image.webp', 'image/webp', 'image'],
36
- ['favicon.ico', 'image/x-icon', 'image'],
37
- ['image.avif', 'image/avif', 'image'],
38
+ // Fonts
39
+ ['font.woff', 'font/woff', 'font'],
40
+ ['font.woff2', 'font/woff2', 'font'],
41
+ ['font.ttf', 'font/ttf', 'font'],
42
+ ['font.otf', 'font/otf', 'font'],
43
+ ['font.eot', 'application/vnd.ms-fontobject', 'font'],
38
44
 
39
- // Fonts
40
- ['font.woff', 'font/woff', 'font'],
41
- ['font.woff2', 'font/woff2', 'font'],
42
- ['font.ttf', 'font/ttf', 'font'],
43
- ['font.otf', 'font/otf', 'font'],
44
- ['font.eot', 'application/vnd.ms-fontobject', 'font'],
45
+ // Audio/Video ('other')
46
+ ['audio.mp3', 'audio/mpeg', 'other'],
47
+ ['audio.ogg', 'audio/ogg', 'other'],
48
+ ['audio.wav', 'audio/wav', 'other'],
49
+ ['video.mp4', 'video/mp4', 'other'],
50
+ ['video.webm', 'video/webm', 'other'],
45
51
 
46
- // Audio/Video ('other')
47
- ['audio.mp3', 'audio/mpeg', 'other'],
48
- ['audio.ogg', 'audio/ogg', 'other'],
49
- ['audio.wav', 'audio/wav', 'other'],
50
- ['video.mp4', 'video/mp4', 'other'],
51
- ['video.webm', 'video/webm', 'other'],
52
+ // Other ('other')
53
+ ['data.json', 'application/json', 'other'],
54
+ ['manifest.webmanifest', 'application/manifest+json', 'other'],
55
+ ['document.xml', 'application/xml', 'other'],
56
+ ['page.html', 'text/html', 'other'],
57
+ ['notes.txt', 'text/plain', 'other'],
52
58
 
53
- // Other ('other')
54
- ['data.json', 'application/json', 'other'],
55
- ['manifest.webmanifest', 'application/manifest+json', 'other'],
56
- ['document.xml', 'application/xml', 'other'],
57
- ['page.html', 'text/html', 'other'],
58
- ['notes.txt', 'text/plain', 'other'],
59
+ // Edge cases
60
+ ['file_without_extension', defaultResult.mime, defaultResult.assetType],
61
+ ['file.unknown', defaultResult.mime, defaultResult.assetType],
62
+ ['.', defaultResult.mime, defaultResult.assetType], // Just a dot
63
+ ['image.', defaultResult.mime, defaultResult.assetType], // Dot at the end
64
+ // URLs with complex paths/queries but known extensions
65
+ ['https://example.com/complex/path.with.dots/image.png?a=1&b=2#frag', 'image/png', 'image'],
66
+ ['file:///C:/Users/Test/Documents/my%20font.ttf', 'font/ttf', 'font'], // File URI
67
+ ];
59
68
 
60
- // Edge cases
61
- ['file_without_extension', defaultResult.mime, defaultResult.assetType],
62
- ['file.unknown', defaultResult.mime, defaultResult.assetType],
63
- ['.', defaultResult.mime, defaultResult.assetType], // Just a dot
64
- ['image.', defaultResult.mime, defaultResult.assetType], // Dot at the end
65
- // URLs with complex paths/queries but known extensions
66
- ['https://example.com/complex/path.with.dots/image.png?a=1&b=2#frag', 'image/png', 'image'],
67
- ['file:///C:/Users/Test/Documents/my%20font.ttf', 'font/ttf', 'font'], // File URI
68
- ];
69
+ // it.each(testCases)('should return correct type for "%s"', (input, expectedMime, expectedAssetType) => {
70
+ // const result = guessMimeType(input);
71
+ // expect(result.mime).toBe(expectedMime);
72
+ // expect(result.assetType).toBe(expectedAssetType);
73
+ // });
69
74
 
70
- // it.each(testCases)('should return correct type for "%s"', (input, expectedMime, expectedAssetType) => {
71
- // const result = guessMimeType(input);
72
- // expect(result.mime).toBe(expectedMime);
73
- // expect(result.assetType).toBe(expectedAssetType);
74
- // });
75
-
76
- it('should return default for null or empty input', () => {
77
- // @ts-expect-error Testing invalid input
78
- expect(guessMimeType(null)).toEqual(defaultResult);
79
- expect(guessMimeType('')).toEqual(defaultResult);
80
- expect(guessMimeType(undefined as any)).toEqual(defaultResult); // Test undefined
81
- });
75
+ it('should return default for null or empty input', () => {
76
+ // @ts-expect-error Testing invalid input
77
+ expect(guessMimeType(null)).toEqual(defaultResult);
78
+ expect(guessMimeType('')).toEqual(defaultResult);
79
+ expect(guessMimeType(undefined as any)).toEqual(defaultResult); // Test undefined
82
80
  });
81
+ });
83
82
 
84
- // Test deprecated getFontMimeType (should just delegate)
85
- describe('getFontMimeType() [Deprecated]', () => {
86
- it('should return correct font MIME type', () => {
87
- expect(getFontMimeType('font.woff2')).toBe('font/woff2');
88
- expect(getFontMimeType('font.ttf')).toBe('font/ttf');
89
- });
83
+ // Test deprecated getFontMimeType (should just delegate)
84
+ describe('getFontMimeType() [Deprecated]', () => {
85
+ it('should return correct font MIME type', () => {
86
+ expect(getFontMimeType('font.woff2')).toBe('font/woff2');
87
+ expect(getFontMimeType('font.ttf')).toBe('font/ttf');
88
+ });
90
89
 
91
- it('should delegate to guessMimeType and return default for non-fonts', () => {
92
- expect(getFontMimeType('style.css')).toBe('text/css'); // Returns CSS mime
93
- expect(getFontMimeType('unknown.ext')).toBe('application/octet-stream'); // Returns default
94
- });
95
- });
96
- });
90
+ it('should delegate to guessMimeType and return default for non-fonts', () => {
91
+ expect(getFontMimeType('style.css')).toBe('text/css'); // Returns CSS mime
92
+ expect(getFontMimeType('unknown.ext')).toBe('application/octet-stream'); // Returns default
93
+ });
94
+ });
95
+ });
@@ -1,21 +1,23 @@
1
+ /**
2
+ * @file tests/unit/utils/slugify.test.ts
3
+ * @description Unit tests for the slugify util.
4
+ */
5
+
1
6
  import { slugify } from '../../../src/utils/slugify'; // Adjust path if needed
2
7
  import { describe, it, expect } from '@jest/globals';
3
8
 
4
9
  describe('slugify()', () => {
5
- it('should handle typical URLs', () => {
6
- // --- Expectations matching the corrected slugify logic ---
7
- expect(slugify('https://site.com/path/page.html')).toBe('path-page');
8
- expect(slugify('products/item-1.html')).toBe('products-item-1');
9
- expect(slugify(' search?q=test page 2 ')).toBe('search-q-test-page-2');
10
- expect(slugify('/path/with/slashes/')).toBe('path-with-slashes');
11
- // ----------------------------------------------------------
12
- expect(slugify('')).toBe('index');
13
- });
14
-
10
+ it('should handle typical URLs', () => {
11
+ // --- Expectations matching the corrected slugify logic ---
12
+ expect(slugify('https://site.com/path/page.html')).toBe('path-page');
13
+ expect(slugify('products/item-1.html')).toBe('products-item-1');
14
+ expect(slugify(' search?q=test page 2 ')).toBe('search-q-test-page-2');
15
+ expect(slugify('/path/with/slashes/')).toBe('path-with-slashes');
16
+ // ----------------------------------------------------------
17
+ expect(slugify('')).toBe('index');
18
+ });
15
19
  });
16
20
 
17
-
18
-
19
21
  // describe('🔧 sanitizeSlug()', () => {
20
22
  // const tests: Array<[string, string]> = [
21
23
  // // Basic pages
@@ -1,11 +1,10 @@
1
1
  {
2
- "extends": "./tsconfig.json", // Inherit from tsconfig.json
3
- "compilerOptions": {
4
- "noEmit": false, // Ensure files are emitted
5
- "declaration": true, // Generate type declaration files
6
- "emitDeclarationOnly": true, // Only generate .d.ts files
7
- "outDir": "dist/types" // Output directory for declaration files
8
- },
9
- "include": ["src/**/*"] // Include all TypeScript files in src
10
- }
11
-
2
+ "extends": "./tsconfig.json", // Inherit from tsconfig.json
3
+ "compilerOptions": {
4
+ "noEmit": false, // Ensure files are emitted
5
+ "declaration": true, // Generate type declaration files
6
+ "emitDeclarationOnly": true, // Only generate .d.ts files
7
+ "outDir": "dist/types" // Output directory for declaration files
8
+ },
9
+ "include": ["src/**/*"] // Include all TypeScript files in src
10
+ }
@@ -15,4 +15,4 @@
15
15
  },
16
16
  "include": ["src/**/*", "tests/**/*"],
17
17
  "exclude": ["node_modules", "dist"]
18
- }
18
+ }
package/tsconfig.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "ES2022",
4
- "module": "ESNext", // ✅ ESM output
5
- "moduleResolution": "Bundler", // ✅ lets TS handle extensions properly
4
+ "module": "ESNext", // ✅ ESM output
5
+ "moduleResolution": "Bundler", // ✅ lets TS handle extensions properly
6
6
  "declaration": true,
7
7
  "sourceMap": true,
8
8
  "outDir": "./dist",
package/tsup.config.ts CHANGED
@@ -7,7 +7,6 @@
7
7
  * - CommonJS format (`cjs`) for CLI compatibility with Node/npx
8
8
  * - .cjs file extension to avoid ESM interpretation issues
9
9
  * - Shebang (`#!/usr/bin/env node`) for executability
10
- * - No type declarations
11
10
  *
12
11
  * 🔹 API Build:
13
12
  * - ESModule format (`esm`) for modern module usage
@@ -24,19 +23,19 @@ export default defineConfig([
24
23
  'cli-entry': 'src/cli/cli-entry.ts',
25
24
  },
26
25
  outDir: 'dist/cli',
27
- format: ['cjs'], // ✅ Required for CLI to work with npx
26
+ format: ['cjs'], // ✅ Required for CLI to work with npx
28
27
  platform: 'node',
29
28
  target: 'node18',
30
29
  splitting: false,
31
- clean: true, // Wipe dist/cli clean on each build
32
- dts: false, // No types for CLI
30
+ clean: true, // Wipe dist/cli clean on each build
31
+ dts: false, // No types for CLI
33
32
  sourcemap: true,
34
33
  banner: {
35
- js: '#!/usr/bin/env node', // ✅ Required for CLI shebang
34
+ js: '#!/usr/bin/env node', // ✅ Required for CLI shebang
36
35
  },
37
36
  outExtension() {
38
37
  return {
39
- js: '.cjs', // ✅ Required: prevents ESM misinterpretation
38
+ js: '.cjs', // ✅ Required: prevents ESM misinterpretation
40
39
  };
41
40
  },
42
41
  esbuildOptions(options) {
@@ -54,12 +53,12 @@ export default defineConfig([
54
53
  index: 'src/index.ts',
55
54
  },
56
55
  outDir: 'dist',
57
- format: ['esm'], // ✅ Modern ESM output for consumers
56
+ format: ['esm'], // ✅ Modern ESM output for consumers
58
57
  platform: 'node',
59
58
  target: 'node18',
60
59
  splitting: false,
61
- clean: false, // Don't wipe CLI build!
62
- dts: true, // ✅ Generate TypeScript declarations
60
+ clean: false, // Don't wipe CLI build!
61
+ dts: true, // ✅ Generate TypeScript declarations
63
62
  sourcemap: true,
64
63
  outExtension() {
65
64
  return {
package/typedoc.json CHANGED
@@ -1,9 +1,5 @@
1
1
  {
2
- "entryPoints": [
3
- "src/index.ts",
4
- "src/types.ts",
5
- "src/cli/cli.ts"
6
- ],
2
+ "entryPoints": ["src/index.ts", "src/types.ts", "src/cli/cli.ts"],
7
3
  "out": "docs/api",
8
4
  "plugin": ["typedoc-plugin-markdown"],
9
5
  "tsconfig": "tsconfig.json",
@@ -15,9 +11,9 @@
15
11
  "theme": "markdown",
16
12
  "entryPointStrategy": "expand",
17
13
  "exclude": [
18
- "**/node_modules/**",
19
- "**/test/**",
20
- "**/tests/**",
14
+ "**/node_modules/**",
15
+ "**/test/**",
16
+ "**/tests/**",
21
17
  "**/dist/**",
22
18
  "**/*.spec.ts",
23
19
  "**/*.test.ts"
@@ -25,4 +21,4 @@
25
21
  "sort": ["alphabetical"],
26
22
  "categorizeByGroup": true,
27
23
  "sourceLinkTemplate": "https://github.com/manicinc/portapack/blob/master/{path}#L{line}"
28
- }
24
+ }
File without changes