Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use deno info to search for imports #100

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ jobs:
- name: Run lint
run: deno lint
- name: Run test
run: deno test --allow-read --allow-write
run: deno test --allow-read --allow-write --allow-net
2 changes: 1 addition & 1 deletion .github/workflows/udd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
id: test
continue-on-error: true
run: |
deno test --allow-read --allow-write
deno test --allow-read --allow-write --allow-net
- name: Set commit status with outcome
uses: Sibz/github-status-action@v1
with:
Expand Down
3 changes: 1 addition & 2 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ export class Udd {
}

async run(): Promise<UddResult[]> {
const content: string = await this.content();
const urls = await importUrls(this.filename);

const urls: string[] = importUrls(content, this.registries);
this.progress.n = urls.length;

// from a url we need to extract the current version
Expand Down
82 changes: 64 additions & 18 deletions search.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
import { RegistryCtor } from "./registry.ts";

// FIXME use deno info once it has json output?

// given a ts/js string we want to find the import urls/
// note: these can span over multiple lines
// import "https?://deno.land/(std|x)@([^/"]?)/.*?"
// import { foo, bar } from "https?://deno.land/(std|x)@([^/"]?)/.*?"

export function importUrls(
tsContent: string,
registries: RegistryCtor[],
): string[] {
// look up all the supported regex matches.
const rs: RegExp[] = registries.map((R) => new R("").regexp).map((re) =>
new RegExp(re, "g")
);
return rs.flatMap((regexp) => tsContent.match(regexp) || []);
import {
createGraph,
ModuleGraph,
} from "https://deno.land/x/[email protected]/mod.ts";
import { ResolvedDependency } from "https://deno.land/x/[email protected]/lib/types.d.ts";

async function getRemoteDependencies(root: string) {
const seen = new Set<string>();
const result: Record<string, ResolvedDependency[]> = {};

function getDeps(
graph: ModuleGraph,
specifier: string,
) {
if (new URL(specifier).protocol !== "file:") {
// It makes things easier to reason about
throw "Searching for dependencies inside of a remote file is not supported";
}

if (seen.has(specifier)) {
// It's already checked.
return undefined;
}

const { dependencies } = graph.get(specifier)!.toJSON();
if (dependencies) {
for (const { code, type } of dependencies) {
if (code?.specifier === undefined) continue;

if (new URL(code.specifier).protocol === "file:") {
// this is a local dependency, so we need to check if it has remote dependencies inside of it
getDeps(
graph,
code?.specifier ?? type?.specifier!,
);
} else {
// This is what we're looking for
// remote dependencies inside of a local file
result[specifier] = result[specifier]
? [...result[specifier], code]
: [code];
}
}
}

seen.add(specifier);
}

getDeps(await createGraph(root), root);
return result;
}

export async function importUrls(
targetFile: string,
) {
const root = `${new URL(targetFile, import.meta.url)}`;
const remoteDeps = await getRemoteDependencies(root);

return remoteDeps[root]
.map((dep) => dep.specifier)
// Note: we're throwing span info out
// In the future we can use it for url replacement
.map((specifier) => specifier ? decodeURI(specifier) : undefined)
.filter((s) => s) as string[]; // ignore empty specifiers
}
9 changes: 5 additions & 4 deletions search_test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { assertEquals } from "./test_deps.ts";
import { REGISTRIES } from "./registry.ts";
import { importUrls } from "./search.ts";

Deno.test("denolandImports", () => {
Deno.test("denolandImports", async () => {
const expected = [
"https://deno.land/[email protected]/foo.ts",
"https://deno.land/x/[email protected]/foo.ts",
"npm:[email protected]",
"npm:[email protected]/",
"npm:[email protected]/hooks",
];
// const ts = `
// import { foo } from "${expected[0]}";
Expand All @@ -20,7 +19,9 @@ export * as preact from "npm:[email protected]";
export * as hooks from "npm:[email protected]/hooks";
`;

const urls = importUrls(ts, REGISTRIES);
const dir = Deno.makeTempDirSync();
Deno.writeTextFileSync(dir + "/a.ts", ts);
const urls = await importUrls(dir + "/a.ts");
urls.sort();
assertEquals(urls, expected);
});
3 changes: 2 additions & 1 deletion test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,12 @@ import { bar } from "https://fakeregistry.com/[email protected]/bar.ts#=";
expected,
[FakeRegistry, FakeDenoLand],
);

assertEquals(4, results.length);
// the ordering is a little weird...
// (it corresponds to the order passed registries)
// FIXME make less fragile by improving search.ts to provide urls in order
assertEquals([true, undefined, true, true], results.map((x) => x.success));
assertEquals([true, true, undefined, true], results.map((x) => x.success));
});

Deno.test("uddFakeregistryFragmentMove", async () => {
Expand Down