Skip to content

Commit 368aa42

Browse files
authored
V1.4.0 (#500)
* handle jsr pkgs from npm * correctly hash jsr pkgs * feat: hash all path segments in jsrPkgToFlatpakData and bump version to 1.4.0
1 parent db39dc0 commit 368aa42

File tree

7 files changed

+455
-33
lines changed

7 files changed

+455
-33
lines changed

deno/deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@flatpak-contrib/flatpak-deno-generator",
3-
"version": "1.3.5",
3+
"version": "1.4.0",
44
"exports": "./src/main.ts",
55
"license": "MIT"
66
}

deno/deno.lock

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deno/src/main.ts

Lines changed: 177 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,16 @@ export async function jsrPkgToFlatpakData(pkg: Pkg): Promise<FlatpakData[]> {
116116
const [checksumType, checksumValue] = splitOnce(fileMeta.checksum, "-");
117117

118118
const url = `https://jsr.io/${pkg.module}/${pkg.version}${fileUrl}`;
119-
let [fileDir, fileName] = splitOnce(fileUrl, "/", "right");
120-
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${fileDir}`;
121-
122-
if (shouldHash(fileName)) {
123-
fileName = await shortHash(fileName);
124-
}
119+
const segments = fileUrl.split("/").filter(Boolean);
120+
const hashedSegments = await Promise.all(
121+
segments.map(async (part) =>
122+
shouldHash(part) ? await shortHash(part) : part
123+
),
124+
);
125+
const fileName = hashedSegments.pop();
126+
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${
127+
hashedSegments.length > 0 ? "/" + hashedSegments.join("/") : ""
128+
}`;
125129

126130
flatpkData.push({
127131
type: "file",
@@ -143,8 +147,17 @@ export async function jsrPkgToFlatpakData(pkg: Pkg): Promise<FlatpakData[]> {
143147
"-",
144148
);
145149
const url = `https://jsr.io/${pkg.module}/${pkg.version}${fileUrl}`;
146-
const [fileDir, fileName] = splitOnce(fileUrl, "/", "right");
147-
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${fileDir}`;
150+
const segments = fileUrl.split("/").filter(Boolean);
151+
const hashedSegments = await Promise.all(
152+
segments.map(async (part) =>
153+
shouldHash(part) ? await shortHash(part) : part
154+
),
155+
);
156+
const fileName = hashedSegments.pop();
157+
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${
158+
hashedSegments.length > 0 ? "/" + hashedSegments.join("/") : ""
159+
}`;
160+
148161
flatpkData.push({
149162
type: "file",
150163
url,
@@ -158,6 +171,106 @@ export async function jsrPkgToFlatpakData(pkg: Pkg): Promise<FlatpakData[]> {
158171
return flatpkData;
159172
}
160173

174+
/**
175+
* Checks if a package is a JSR package accessed via npm.jsr.io
176+
* @param module The module identifier (e.g., "@jsr/sigma__deno-compat")
177+
* @returns true if this is a JSR package via npm compatibility layer
178+
*/
179+
function isJsrNpmPackage(module: string): boolean {
180+
return module.startsWith("@jsr/");
181+
}
182+
183+
/**
184+
* Converts JSR package (accessed via npm.jsr.io) into FlatpakData objects.
185+
* JSR packages via npm have tarball URLs and integrity in the lock file,
186+
* so we don't need to fetch from a registry.
187+
* @param pkg The JSR-via-npm package information.
188+
* @param lockData The lock file data for this specific package.
189+
* @returns A promise that resolves to an array of FlatpakData objects.
190+
*/
191+
export function jsrNpmPkgToFlatpakData(
192+
pkg: Pkg,
193+
// deno-lint-ignore no-explicit-any
194+
lockData: any,
195+
): FlatpakData[] {
196+
const tarballUrl = lockData.tarball;
197+
const integrity = lockData.integrity;
198+
199+
if (!tarballUrl || !integrity) {
200+
throw new Error(
201+
`Missing tarball or integrity for JSR package ${pkg.module}@${pkg.version}`,
202+
);
203+
}
204+
205+
const [checksumType, checksumValue] = splitOnce(integrity, "-");
206+
207+
const registryContents = JSON.stringify({
208+
name: pkg.module,
209+
"dist-tags": {},
210+
versions: {
211+
[pkg.version]: {
212+
dist: {
213+
integrity: integrity,
214+
tarball: tarballUrl,
215+
},
216+
},
217+
},
218+
});
219+
220+
// Deno's npm cache resolution for JSR packages can be inconsistent
221+
// Sometimes it looks under npm.jsr.io, sometimes under registry.npmjs.org
222+
// We generate entries for both paths to ensure compatibility
223+
const results: FlatpakData[] = [];
224+
225+
// Create inline registry.json for npm.jsr.io path
226+
results.push({
227+
type: "inline",
228+
contents: registryContents,
229+
dest: `deno_dir/npm/npm.jsr.io/${pkg.module}`,
230+
"dest-filename": "registry.json",
231+
});
232+
233+
// Create inline registry.json for registry.npmjs.org path
234+
results.push({
235+
type: "inline",
236+
contents: registryContents,
237+
dest: `deno_dir/npm/registry.npmjs.org/${pkg.module}`,
238+
"dest-filename": "registry.json",
239+
});
240+
241+
// Archive for npm.jsr.io path
242+
const pkgDataJsr: FlatpakData = {
243+
type: "archive",
244+
"archive-type": "tar-gzip",
245+
url: tarballUrl,
246+
[checksumType]: base64ToHex(checksumValue),
247+
dest: `deno_dir/npm/npm.jsr.io/${pkg.module}/${pkg.version}`,
248+
};
249+
250+
if (pkg.cpu) {
251+
pkgDataJsr["only-arches"] = [pkg.cpu];
252+
}
253+
254+
results.push(pkgDataJsr);
255+
256+
// Archive for registry.npmjs.org path
257+
const pkgDataNpm: FlatpakData = {
258+
type: "archive",
259+
"archive-type": "tar-gzip",
260+
url: tarballUrl,
261+
[checksumType]: base64ToHex(checksumValue),
262+
dest: `deno_dir/npm/registry.npmjs.org/${pkg.module}/${pkg.version}`,
263+
};
264+
265+
if (pkg.cpu) {
266+
pkgDataNpm["only-arches"] = [pkg.cpu];
267+
}
268+
269+
results.push(pkgDataNpm);
270+
271+
return results;
272+
}
273+
161274
/**
162275
* Converts NPM package information into an array of FlatpakData objects.
163276
* It fetches metadata for the package and creates entries for the package's
@@ -229,25 +342,60 @@ export async function main(
229342
return { module: r[0], version: r[1], name };
230343
});
231344
jsrPkgs;
232-
const npmPkgs: Pkg[] = !lock.npm ? [] : Object.entries(lock.npm)
233-
.filter((
234-
// deno-lint-ignore no-explicit-any
235-
[_key, val]: any,
236-
) => (val.os === undefined || val.os?.at(0) === "linux"))
345+
346+
// Process npm packages, separating JSR packages from regular npm packages
347+
// deno-lint-ignore no-explicit-any
348+
const npmEntries: Array<[string, any]> = !lock.npm
349+
? []
350+
: Object.entries(lock.npm)
351+
.filter((
352+
// deno-lint-ignore no-explicit-any
353+
[_key, val]: any,
354+
) => (val.os === undefined || val.os?.at(0) === "linux"));
355+
356+
// deno-lint-ignore no-explicit-any
357+
const npmPkgs: Array<[Pkg, any]> = npmEntries
358+
.filter(([key, _val]) => {
359+
const r = key.match(/(^@?.+?)@([^_]+?)(?=_|$)/)!;
360+
return !isJsrNpmPackage(r[1]);
361+
})
237362
// deno-lint-ignore no-explicit-any
238363
.map(([key, val]: [string, any]) => {
239364
const r = key.match(/(^@?.+?)@([^_]+?)(?=_|$)/)!;
240365
const name = r[1].includes("/") ? r[1].split("/")[1] : r[1];
241366
const cpu = val.cpu?.at(0);
242-
return {
243-
module: r[1],
244-
version: r[2],
245-
name,
246-
cpu: cpu === "x64" ? "x86_64" : cpu === "arm64" ? "aarch64" : cpu,
247-
};
367+
return [
368+
{
369+
module: r[1],
370+
version: r[2],
371+
name,
372+
cpu: cpu === "x64" ? "x86_64" : cpu === "arm64" ? "aarch64" : cpu,
373+
},
374+
val,
375+
];
376+
});
377+
378+
// deno-lint-ignore no-explicit-any
379+
const jsrNpmPkgs: Array<[Pkg, any]> = npmEntries
380+
.filter(([key, _val]) => {
381+
const r = key.match(/(^@?.+?)@([^_]+?)(?=_|$)/)!;
382+
return isJsrNpmPackage(r[1]);
383+
})
384+
// deno-lint-ignore no-explicit-any
385+
.map(([key, val]: [string, any]) => {
386+
const r = key.match(/(^@?.+?)@([^_]+?)(?=_|$)/)!;
387+
const name = r[1].includes("/") ? r[1].split("/")[1] : r[1];
388+
const cpu = val.cpu?.at(0);
389+
return [
390+
{
391+
module: r[1],
392+
version: r[2],
393+
name,
394+
cpu: cpu === "x64" ? "x86_64" : cpu === "arm64" ? "aarch64" : cpu,
395+
},
396+
val,
397+
];
248398
});
249-
//url: https://registry.npmjs.org/@napi-rs/cli/-/cli-2.18.4.tgz
250-
npmPkgs;
251399
const httpPkgsData = !lock.remote
252400
? []
253401
: Object.entries(lock.remote).map(async ([urlStr, checksum]) => {
@@ -270,9 +418,14 @@ export async function main(
270418
await Promise.all(
271419
jsrPkgs.map((pkg) => jsrPkgToFlatpakData(pkg)),
272420
).then((r) => r.flat()),
273-
await Promise.all(npmPkgs.map((pkg) => npmPkgToFlatpakData(pkg))).then(
274-
(r) => r.flat(),
275-
),
421+
await Promise.all(
422+
npmPkgs.map(([pkg, _lockData]) => npmPkgToFlatpakData(pkg)),
423+
).then((r) => r.flat()),
424+
await Promise.all(
425+
jsrNpmPkgs.map(([pkg, lockData]) =>
426+
jsrNpmPkgToFlatpakData(pkg, lockData)
427+
),
428+
).then((r) => r.flat()),
276429
await Promise.all(httpPkgsData),
277430
].flat();
278431
// console.log(flatpakData);

deno/src/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// LICENSE = MIT
2+
// deno-lint-ignore-file no-import-prefix
23

34
import { encodeHex } from "jsr:@std/encoding@1/hex";
45
import { decodeBase64 } from "jsr:@std/encoding@1/base64";

0 commit comments

Comments
 (0)