|
3 | 3 | [](https://socket.dev/npm/package/@socketregistry/packageurl-js) |
4 | 4 | [](https://github.com/SocketDev/socket-packageurl-js/actions/workflows/test.yml) |
5 | 5 | [](https://twitter.com/SocketSecurity) |
| 6 | +[](https://bsky.app/profile/socket.dev) |
6 | 7 |
|
7 | | -> An enhanced and tested zero dependency drop-in replacement of |
8 | | -> [`packageurl-js`](https://socket.dev/npm/package/packageurl-js) complete with |
9 | | -> TypeScript types. |
| 8 | +TypeScript-first Package URL parser. Drop-in replacement for [`packageurl-js`](https://socket.dev/npm/package/packageurl-js). |
10 | 9 |
|
11 | | -## Installation |
12 | | - |
13 | | -### Install as a package override |
| 10 | +- TypeScript support |
| 11 | +- Zero dependencies |
| 12 | +- [Package URL spec](https://github.com/package-url/purl-spec) compliant |
| 13 | +- Builder pattern API |
14 | 14 |
|
15 | | -[`socket`](https://socket.dev/npm/package/socket) CLI will automagically ✨ |
16 | | -populate |
17 | | -[overrides](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#overrides) |
18 | | -and [resolutions](https://yarnpkg.com/configuration/manifest#resolutions) of |
19 | | -your `package.json`. |
| 15 | +## Installation |
20 | 16 |
|
21 | 17 | ```sh |
22 | | -npx socket optimize |
| 18 | +pnpm install @socketregistry/packageurl-js |
23 | 19 | ``` |
24 | 20 |
|
25 | | -Prefer to do it yourself? Add `@socketregistry/packageurl-js` to your |
26 | | -`package.json`. |
27 | | - |
| 21 | +**Package override** (recommended): |
28 | 22 | ```json |
29 | 23 | { |
30 | 24 | "overrides": { |
31 | 25 | "packageurl-js": "npm:@socketregistry/packageurl-js@^1" |
32 | | - }, |
33 | | - "resolutions": { |
34 | | - "packageurl-js": "npm:@socketregistry/packageurl-js@^1" |
35 | 26 | } |
36 | 27 | } |
37 | 28 | ``` |
38 | 29 |
|
39 | | -### Install as a plain dependency |
40 | | - |
41 | | -Install with your favorite package manager. |
42 | | - |
43 | | -```sh |
44 | | -npm install @socketregistry/packageurl-js |
45 | | -``` |
46 | | - |
47 | | -## Requirements |
48 | | - |
49 | | -Node >= `18.20.4` |
| 30 | +**Requirements**: Node >= 18.20.4 |
50 | 31 |
|
51 | 32 | ## Usage |
52 | 33 |
|
53 | | -### Basic PackageURL Operations |
54 | | - |
55 | 34 | ```javascript |
56 | | -import { PackageURL } from '@socketregistry/packageurl-js' |
| 35 | +import { PackageURL, PackageURLBuilder } from '@socketregistry/packageurl-js' |
57 | 36 |
|
58 | | -// Parse a Package URL string |
| 37 | +// Parse from string |
59 | 38 | const purl = PackageURL. fromString( 'pkg:npm/[email protected]') |
60 | | -console.log(purl.type) // 'npm' |
61 | 39 | console.log(purl.name) // 'lodash' |
62 | | -console.log(purl.version) // '4.17.21' |
63 | 40 |
|
64 | | -// Create a PackageURL from components |
| 41 | +// Create from components |
65 | 42 | const newPurl = new PackageURL('npm', null, 'express', '4.18.2') |
66 | | -console. log( newPurl. toString()) // 'pkg:npm/[email protected]' |
67 | | - |
68 | | -// With namespace (scope for npm) |
69 | | -const scopedPurl = new PackageURL('npm', '@angular', 'core', '15.0.0') |
70 | | -console. log( scopedPurl. toString()) // 'pkg:npm/%40angular/[email protected]' |
71 | | -``` |
72 | 43 |
|
73 | | -### Using the Builder Pattern |
74 | | - |
75 | | -The `PackageURLBuilder` provides a fluent API for constructing Package URLs: |
76 | | - |
77 | | -```javascript |
78 | | -import { PackageURLBuilder } from '@socketregistry/packageurl-js' |
79 | | - |
80 | | -// Build an npm package URL |
81 | | -const npmPurl = PackageURLBuilder |
| 44 | +// Builder pattern |
| 45 | +const builtPurl = PackageURLBuilder |
82 | 46 | .npm() |
83 | 47 | .name('lodash') |
84 | 48 | .version('4.17.21') |
85 | 49 | .build() |
86 | | - |
87 | | -console. log( npmPurl. toString()) // 'pkg:npm/[email protected]' |
88 | | - |
89 | | -// Build a Maven package URL with qualifiers |
90 | | -const mavenPurl = PackageURLBuilder |
91 | | - .maven() |
92 | | - .namespace('org.apache.commons') |
93 | | - .name('commons-lang3') |
94 | | - .version('3.12.0') |
95 | | - .qualifier('classifier', 'sources') |
96 | | - .build() |
97 | | - |
98 | | -// Build from scratch with all components |
99 | | -const complexPurl = PackageURLBuilder |
100 | | - .create() |
101 | | - .type('cargo') |
102 | | - .name('serde') |
103 | | - .version('1.0.152') |
104 | | - .qualifier('arch', 'x86_64') |
105 | | - .qualifier('os', 'linux') |
106 | | - .build() |
107 | | - |
108 | | -// Copy and modify an existing PackageURL |
109 | | -const modifiedPurl = PackageURLBuilder |
110 | | - .from(npmPurl) |
111 | | - .version('4.17.20') |
112 | | - .build() |
113 | | -``` |
114 | | - |
115 | | -### Available Builder Presets |
116 | | - |
117 | | -The builder includes convenience methods for popular package types: |
118 | | - |
119 | | -```javascript |
120 | | -// Language/ecosystem-specific builders |
121 | | -PackageURLBuilder.cargo() // Rust crates |
122 | | -PackageURLBuilder.composer() // PHP packages |
123 | | -PackageURLBuilder.gem() // Ruby gems |
124 | | -PackageURLBuilder.golang() // Go packages |
125 | | -PackageURLBuilder.maven() // Maven/Java packages |
126 | | -PackageURLBuilder.npm() // npm packages |
127 | | -PackageURLBuilder.nuget() // .NET packages |
128 | | -PackageURLBuilder.pypi() // Python packages |
129 | 50 | ``` |
130 | 51 |
|
131 | | -### URL Conversion |
132 | | - |
133 | | -The `UrlConverter` class can generate repository and download URLs from Package URLs: |
| 52 | +### Builders & URL Conversion |
134 | 53 |
|
135 | 54 | ```javascript |
| 55 | +// Ecosystem-specific builders |
| 56 | +PackageURLBuilder.npm() // npm |
| 57 | +PackageURLBuilder.pypi() // Python |
| 58 | +PackageURLBuilder.maven() // Java/Maven |
| 59 | +PackageURLBuilder.cargo() // Rust |
| 60 | +PackageURLBuilder.gem() // Ruby |
| 61 | + |
| 62 | +// URL conversion |
136 | 63 | import { UrlConverter } from '@socketregistry/packageurl-js' |
137 | | - |
138 | | -const purl = PackageURLBuilder |
139 | | - .npm() |
140 | | - .name('lodash') |
141 | | - .version('4.17.21') |
142 | | - .build() |
143 | | - |
144 | | -// Get repository URL (where source code lives) |
145 | 64 | const repoUrl = UrlConverter.toRepositoryUrl(purl) |
146 | | -console.log(repoUrl) |
147 | | -// { url: 'https://npmjs.com/package/lodash', type: 'web' } |
148 | | - |
149 | | -// Get download URL (where to download the package) |
150 | 65 | const downloadUrl = UrlConverter.toDownloadUrl(purl) |
151 | | -console.log(downloadUrl) |
152 | | -// { url: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz', type: 'tarball' } |
153 | | - |
154 | | -// Get both URLs at once |
155 | | -const allUrls = UrlConverter.getAllUrls(purl) |
156 | | -console.log(allUrls) |
157 | | -// { |
158 | | -// repository: { url: 'https://npmjs.com/package/lodash', type: 'web' }, |
159 | | -// download: { url: 'https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz', type: 'tarball' } |
160 | | -// } |
161 | | - |
162 | | -// Check if a package type supports URL conversion |
163 | | -console.log(UrlConverter.supportsRepositoryUrl('npm')) // true |
164 | | -console.log(UrlConverter.supportsDownloadUrl('npm')) // true |
165 | 66 | ``` |
166 | 67 |
|
167 | | -### Working with Different Package Types |
168 | | - |
169 | | -Examples for various package ecosystems: |
| 68 | +### Advanced |
170 | 69 |
|
171 | 70 | ```javascript |
172 | | -// Rust crate with qualifiers |
173 | | -const rustPurl = PackageURLBuilder |
174 | | - .cargo() |
175 | | - .name('serde') |
176 | | - .version('1.0.152') |
177 | | - .qualifier('feature', 'derive') |
178 | | - .build() |
179 | | - |
180 | | -// Ruby gem |
181 | | -const rubyPurl = PackageURLBuilder |
182 | | - .gem() |
183 | | - .name('rails') |
184 | | - .version('7.0.3') |
185 | | - .build() |
186 | | - |
187 | | -// Go package with namespace (module path) |
188 | | -const goPurl = PackageURLBuilder |
189 | | - .golang() |
190 | | - .namespace('github.com/gin-gonic') |
191 | | - .name('gin') |
192 | | - .version('v1.8.1') |
193 | | - .build() |
194 | | - |
195 | | -// Maven package with namespace (groupId) |
196 | | -const mavenPurl = PackageURLBuilder |
| 71 | +// Namespaces and qualifiers |
| 72 | +const purl = PackageURLBuilder |
197 | 73 | .maven() |
198 | 74 | .namespace('org.springframework') |
199 | 75 | .name('spring-core') |
200 | | - .version('5.3.21') |
| 76 | + .qualifier('classifier', 'sources') |
201 | 77 | .build() |
202 | 78 |
|
203 | | -// Python package |
204 | | -const pythonPurl = PackageURLBuilder |
205 | | - .pypi() |
206 | | - .name('requests') |
207 | | - .version('2.28.1') |
208 | | - .build() |
| 79 | +// Subpaths |
| 80 | +new PackageURL('npm', '@babel', 'runtime', '7.18.6', null, 'helpers/typeof.js') |
209 | 81 | ``` |
210 | 82 |
|
211 | | -### Advanced Features |
| 83 | +## Development |
212 | 84 |
|
213 | | -```javascript |
214 | | -// Package URLs with subpaths |
215 | | -const purlWithSubpath = new PackageURL( |
216 | | - 'npm', |
217 | | - '@babel', |
218 | | - 'runtime', |
219 | | - '7.18.6', |
220 | | - null, |
221 | | - 'helpers/typeof.js' |
222 | | -) |
223 | | - |
224 | | -// Package URLs with qualifiers |
225 | | -const purlWithQualifiers = new PackageURL( |
226 | | - 'maven', |
227 | | - 'org.apache.commons', |
228 | | - 'commons-lang3', |
229 | | - '3.12.0', |
230 | | - { classifier: 'sources', type: 'jar' } |
231 | | -) |
232 | | - |
233 | | -// Validation and normalization |
234 | | -try { |
235 | | - const purl = PackageURL.fromString('invalid-purl') |
236 | | -} catch (error) { |
237 | | - console.log('Invalid Package URL format') |
238 | | -} |
239 | | - |
240 | | -// Working with qualifiers |
241 | | -const purl = PackageURLBuilder |
242 | | - .create() |
243 | | - .type('custom') |
244 | | - .name('mypackage') |
245 | | - .qualifiers({ arch: 'amd64', os: 'linux' }) |
246 | | - .qualifier('extra', 'value') // Add individual qualifier |
247 | | - .build() |
| 85 | +```bash |
| 86 | +pnpm install # Install dependencies |
| 87 | +pnpm build # Build |
| 88 | +pnpm test # Test |
| 89 | +pnpm check # Lint + typecheck |
248 | 90 | ``` |
0 commit comments