Skip to content

Commit

Permalink
feat: add integrity flag support (#2571)
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford authored Jul 14, 2024
1 parent b938c17 commit 2e373b2
Show file tree
Hide file tree
Showing 13 changed files with 2,526 additions and 2,337 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [14.x, 16.x, 18.x]
node: [16.x, 18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v2
with:
Expand Down
8 changes: 4 additions & 4 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ If no modules are given, all "imports" in the initial map are relinked.
* `--cache` _<mode>_ Cache mode for fetches (online, offline, no-cache) (default: online)
* `--root` _<url>_ URL to treat as server root, i.e. rebase import maps against
* `--preload` _[mode]_ Add module preloads to HTML output (default: static, dynamic)
* `--integrity` Add module preloads with integrity attributes to HTML output (default: false)
* `--integrity` Add module integrity attributes to the import map (default: false)
* `--compact` Output a compact import map (default: false)
* `--stdout` Output the import map to stdout (default: false)
* `--silent` Silence all output (default: false)
Expand Down Expand Up @@ -87,7 +87,7 @@ If no packages are provided, all "imports" in the initial map are reinstalled.
* `--cache` _<mode>_ Cache mode for fetches (online, offline, no-cache) (default: online)
* `--root` _<url>_ URL to treat as server root, i.e. rebase import maps against
* `--preload` _[mode]_ Add module preloads to HTML output (default: static, dynamic)
* `--integrity` Add module preloads with integrity attributes to HTML output (default: false)
* `--integrity` Add module integrity attributes to the import map (default: false)
* `--compact` Output a compact import map (default: false)
* `--stdout` Output the import map to stdout (default: false)
* `--silent` Silence all output (default: false)
Expand Down Expand Up @@ -137,7 +137,7 @@ Uninstalls packages from an import map. The given packages must be valid package
* `--cache` _<mode>_ Cache mode for fetches (online, offline, no-cache) (default: online)
* `--root` _<url>_ URL to treat as server root, i.e. rebase import maps against
* `--preload` _[mode]_ Add module preloads to HTML output (default: static, dynamic)
* `--integrity` Add module preloads with integrity attributes to HTML output (default: false)
* `--integrity` Add module integrity attributes to the import map (default: false)
* `--compact` Output a compact import map (default: false)
* `--stdout` Output the import map to stdout (default: false)
* `--silent` Silence all output (default: false)
Expand Down Expand Up @@ -169,7 +169,7 @@ Updates packages in an import map to the latest versions that are compatible wit
* `--cache` _<mode>_ Cache mode for fetches (online, offline, no-cache) (default: online)
* `--root` _<url>_ URL to treat as server root, i.e. rebase import maps against
* `--preload` _[mode]_ Add module preloads to HTML output (default: static, dynamic)
* `--integrity` Add module preloads with integrity attributes to HTML output (default: false)
* `--integrity` Add module integrity attributes to the import map (default: false)
* `--compact` Output a compact import map (default: false)
* `--stdout` Output the import map to stdout (default: false)
* `--silent` Silence all output (default: false)
Expand Down
4,720 changes: 2,417 additions & 2,303 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@
"jspm.js"
],
"dependencies": {
"@jspm/generator": "^2.0.0",
"@jspm/generator": "^2.1.2",
"cac": "^6.7.14",
"ora": "^6.3.0",
"picocolors": "^1.0.0",
"rollup": "^3.29.2"
},
"devDependencies": {
"@antfu/eslint-config": "^0.34.2",
"@babel/core": "^7.21.4",
"@babel/core": "^7.24.7",
"@types/node": "^18.15.11",
"esbuild": "^0.16.17",
"eslint": "^8.38.0",
"eslint-config-prettier": "^8.8.0",
"prettier": "^2.8.7",
"tinyspy": "^1.1.1",
"tsx": "^3.12.6",
"tsx": "^4.16.2",
"typescript": "^4.9.5"
}
}
3 changes: 2 additions & 1 deletion src/build/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from "node:path";
import process from "node:process";
import { pathToFileURL } from "node:url";
import { type RollupOptions, rollup } from "rollup";

import { JspmError, exists } from "../utils";
Expand Down Expand Up @@ -40,7 +41,7 @@ export default async function build(entry: string, options: Flags) {
`Build config file does not exist: ${buildConfigPath}`
);
}
const rollupConfig = await import(buildConfigPath)
const rollupConfig = await import(pathToFileURL(buildConfigPath).href)
.then((mod) => mod.default)
.catch((err) => {
throw new JspmError(`Failed to load build config: ${err}`);
Expand Down
25 changes: 11 additions & 14 deletions src/build/rollup-importmap-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,25 +44,22 @@ export const RollupImportmapPlugin = async (flags: Flags): Promise<Plugin> => {
}
},
load: async (id: string) => {
let url: URL;
try {
const url = new URL(id);
if (url.protocol === "file:") {
const filePath =
path.extname(url.pathname) === ""
? `${url.pathname}.js`
: url.pathname;

return await fs.readFile(pathToFileURL(filePath), "utf-8");
}
url = new URL(id);
} catch (e) {
throw new JspmError(`Unsupported URL ${id} \n ${e.message}`);
}

if (url.protocol === "https:") {
switch (url.protocol) {
case 'file:':
return await fs.readFile(new URL(id), "utf-8");
case 'https:': {
const response = await fetch(id);
return await response.text();
}
} catch (err) {
throw new JspmError(
`\n Unsupported protocol ${id} \n ${err.message} \n`
);
default:
throw new JspmError(`Unsupported protocol ${url.protocol}`);
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const preloadOpt: opt = [
];
const integrityOpt: opt = [
"--integrity",
"Add module preloads with integrity attributes to HTML output",
"Add module integrity attributes to the import map",
{ default: false },
];
const cacheOpt: opt = [
Expand Down
2 changes: 1 addition & 1 deletion src/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ async function handleLocalFile(
generator: Generator
) {
const source = await fs.readFile(resolvedModule.target, { encoding: "utf8" });
const { default: babel } = await import("@babel/core");
const babel = await import("@babel/core");

try {
babel.parse(source);
Expand Down
1 change: 1 addition & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ export async function getGenerator(
defaultProvider: getProvider(flags),
resolutions: getResolutions(flags),
cache: getCacheMode(flags),
integrity: flags.integrity,
commonJS: true, // TODO: only for --local flag
});
}
Expand Down
73 changes: 73 additions & 0 deletions test/integrity.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import assert from "assert";
import {
type Scenario,
mapDirectory,
mapFile,
runScenarios,
} from "./scenarios";

const importMap = await mapFile("test/fixtures/importmap.json");

const scenarios: Scenario[] = [
// The inline improtmap should be linked and the integrity attribute should be added
{
files: importMap,
commands: ["jspm link react -o index.html --integrity"],
validationFn: async (files: Map<string, string>) => {
const html = files.get("index.html");

assert(html.includes("integrity"));
},
},
// The importmap generated should have integrity attribute
{
files: importMap,
commands: ["jspm link --integrity"],
validationFn: async (files: Map<string, string>) => {
const map = JSON.parse(files.get("importmap.json"));
assert(map.integrity);
},
},
// Scenario should detect the provider and add integrity attribute
{
files: await mapFile("test/fixtures/unpkg.importmap.json"),
commands: [
"jspm link -m unpkg.importmap.json -o importmap.json --integrity",
],
validationFn: async (files: Map<string, string>) => {
const map = JSON.parse(files.get("importmap.json"));
assert(map.integrity);
},
},
// Scenario should detect the provider and add integrity attribute
{
files: await mapDirectory("test/fixtures/scenario_provider_swap"),
commands: ["jspm install --provider nodemodules --integrity"],
validationFn: async (files) => {
const map = JSON.parse(files.get("importmap.json"));
assert(map.integrity);
},
},
// Scenario installs package from denoland along with integrity attribute
{
files: new Map(),
commands: ["jspm install denoland:zod --integrity"],
validationFn: async (files) => {
const map = JSON.parse(files.get("importmap.json"));
assert(map.imports.zod.includes("deno.land"));
assert(map.integrity);
},
},
// Scenario installs package from skypack along with integrity attribute
{
files: new Map(),
commands: ["jspm install lit --provider skypack --integrity"],
validationFn: async (files) => {
const map = JSON.parse(files.get("importmap.json"));
assert(map.imports.lit.includes("cdn.skypack.dev"));
assert(map.integrity);
},
},
];

runScenarios(scenarios);
4 changes: 2 additions & 2 deletions test/ownname.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ const scenarios: Scenario[] = [
commands: ["jspm install app"],
validationFn: async (files: Map<string, string>) => {
// Installing the own-name package "app" should result in the version of
// es-module-lexer in the import map being upgraded to 1.4.1, since it's a
// es-module-lexer in the import map being upgraded to 1.5.4, since it's a
// transitive dependency of "./app.js".
const map = JSON.parse(files.get("importmap.json"));
assert(
map?.imports?.["es-module-lexer"]?.includes("es-module-lexer@1.4.1")
map?.imports?.["es-module-lexer"]?.includes("es-module-lexer@1.5.4")
);
},
},
Expand Down
8 changes: 6 additions & 2 deletions test/providers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ for (const provider of availableProviders) {
let spec = "lit";
let name = "lit";
if (provider.includes("deno")) {
spec = "denoland:oak/body.ts"; // deno doesn't support npm packages
name = "oak/body.ts";
// oak is using jsr. We need to add support for jsr registry and imort protocol
// https://github.com/jspm/generator/issues/366
// spec = "denoland:oak/body.ts"; // deno doesn't support npm packages
// name = "oak/body.ts";
spec = "denoland:zod";
name = "zod";
}
if (provider === "node") {
spec = "@jspm/core/nodelibs/fs"; // node provider is only for polyfills
Expand Down
9 changes: 4 additions & 5 deletions test/scenarios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export async function mapDirectory(dir: string): Promise<Files> {
} else {
const subFiles = await mapDirectory(filePath);
for (const [subFile, subData] of subFiles) {
files.set(path.join(file, subFile).replace(/\\/g, '/'), subData);
files.set(path.join(file, subFile).replace(/\\/g, "/"), subData);
}
}
}
Expand Down Expand Up @@ -103,10 +103,9 @@ async function deleteTmpPkg(dir: string) {
try {
await fs.rm(dir, { recursive: true });
return;
}
catch (err) {
if (err.code === 'EBUSY')
await new Promise(resolve => setTimeout(resolve, 10));
} catch (err) {
if (err.code === "EBUSY")
await new Promise((resolve) => setTimeout(resolve, 10));
}
}
} else {
Expand Down

0 comments on commit 2e373b2

Please sign in to comment.