diff --git a/.github/workflows/deno-ci.yml b/.github/workflows/deno-ci.yml index 5af8eac..cf145ad 100644 --- a/.github/workflows/deno-ci.yml +++ b/.github/workflows/deno-ci.yml @@ -50,6 +50,9 @@ jobs: - name: Check entrypoint run: time deno cache server.ts + - name: Run any tests + run: time deno test + # Push image to GitHub Packages. # See also https://docs.docker.com/docker-hub/builds/ push: diff --git a/lib/module-map.ts b/lib/module-map.ts index 7e0fb7e..4ecaecc 100644 --- a/lib/module-map.ts +++ b/lib/module-map.ts @@ -5,21 +5,28 @@ import * as registries from "./module-registries.ts"; export class ModuleMap { modules = new Map(); - mainModule: CodeModule | null = null; - mainFile: string | null = null; + mainModule: CodeModule; + registryOpts: registries.RegistryOpts; constructor( public args: URLSearchParams, public redirects: Record, + public rootNode: DenoModule, ) { - this.isolateStd = this.args.get('std') === 'isolate'; + this.registryOpts = { + mainModule: rootNode.specifier, + isolateStd: this.args.get('std') === 'isolate', + } + + this.mainModule = this.grabModFor( + rootNode.specifier, + rootNode.error ? '#error' : undefined); } - isolateStd: boolean; grabModFor(url: string, fragment: string = '') { const wireUrl = url.split('#')[0]; const actualUrl = this.redirects[wireUrl] || wireUrl; - const base = registries.determineModuleBase(actualUrl, this.isolateStd); + const base = registries.determineModuleBase(actualUrl, this.registryOpts); let moduleInfo = this.modules.get(base + fragment); if (!moduleInfo) { moduleInfo = { @@ -79,7 +86,7 @@ export class ModuleMap { for (const module of this.modules.values()) { modules[module.base+module.fragment] = { moduleDeps: Array.from(module.deps).map(x => x.base+x.fragment), - labelText: registries.determineModuleLabel(module, this.isolateStd), + labelText: registries.determineModuleLabel(module, this.registryOpts), totalSize: module.totalSize, fileCount: module.files.length, errors: module.errors, @@ -96,7 +103,7 @@ export class ModuleMap { for (const module of this.modules.values()) { // console.log(module.base, Array.from(module.deps.values()).map(x => x.base)); - const labels = registries.determineModuleLabel(module, this.isolateStd); + const labels = registries.determineModuleLabel(module, this.registryOpts); if (module.errors) { labels.unshift(`${module.errors.length} FAILED IMPORTS FROM:`); for (const err of module.errors) { @@ -171,17 +178,13 @@ export class ModuleMap { } export function processDenoInfo(data: DenoInfo, args?: URLSearchParams) { - const map = new ModuleMap(args ?? new URLSearchParams, data.redirects); - // TODO: when are there multiple roots? const roots = data.roots.map(x => data.redirects[x] || x); const rootNode = data.modules.find(x => roots.includes(x.specifier)); if (!rootNode) throw new Error( `I didn't find a root node in the Deno graph! This is a module-visualizer bug.`); - map.mainModule = map.grabModFor(rootNode.specifier, rootNode.error ? '#error' : undefined); - map.mainFile = rootNode.specifier; - + const map = new ModuleMap(args ?? new URLSearchParams, data.redirects, rootNode); for (const info of data.modules) { map.addFile(info.specifier, info, data); } diff --git a/lib/module-registries.ts b/lib/module-registries.ts index 7561d80..ef30b94 100644 --- a/lib/module-registries.ts +++ b/lib/module-registries.ts @@ -1,16 +1,21 @@ import type { CodeModule } from "./types.ts"; -export function determineModuleBase(fullUrl: string, isolateStd: boolean): string { +export interface RegistryOpts { + mainModule: string; + isolateStd?: boolean; +}; + +export function determineModuleBase(fullUrl: string, opts: RegistryOpts): string { const url = new URL(fullUrl); const parts = fullUrl.split('/'); if (url.protocol === 'file:') return 'file://'; if (url.protocol !== 'https:') return fullUrl; switch (url.host) { case 'deno.land': - if (parts[3].startsWith('std') && !isolateStd) return parts.slice(0, 4).join('/'); + if (parts[3].startsWith('std') && !opts.isolateStd) return parts.slice(0, 4).join('/'); return parts.slice(0, 5).join('/'); case 'cdn.deno.land': - if (parts[3] === 'std' && isolateStd) return parts.slice(0, 8).join('/'); + if (parts[3] === 'std' && opts.isolateStd) return parts.slice(0, 8).join('/'); return parts.slice(0, 6).join('/'); case 'crux.land': if (parts.length == 4) return `${url.origin}/${parts[3]}`; @@ -75,14 +80,14 @@ export function determineModuleBase(fullUrl: string, isolateStd: boolean): strin return fullUrl; } -export function determineModuleLabel(module: CodeModule, isolateStd: boolean): string[] { +export function determineModuleLabel(module: CodeModule, opts: RegistryOpts): string[] { const url = new URL(module.base); const parts = module.base.split('/'); if (url.protocol !== 'https:') return [module.base]; switch (url.host) { case 'deno.land': { let extra = new Array(); - if (parts[3].startsWith('std') && !isolateStd) { + if (parts[3].startsWith('std') && !opts.isolateStd) { const folders = new Set(module.files.map(x => x.url.split('/')[4])); extra = Array.from(folders).map(x => ` • /${x}`); } @@ -90,7 +95,7 @@ export function determineModuleLabel(module: CodeModule, isolateStd: boolean): s } case 'cdn.deno.land': { let extra = new Array(); - if (parts[3] === 'std' && !isolateStd) { + if (parts[3] === 'std' && !opts.isolateStd) { const folders = new Set(module.files.map(x => x.url.split('/')[7])); extra = Array.from(folders).map(x => ` • /${x}`); } diff --git a/lib/module-registries_test.ts b/lib/module-registries_test.ts index 3de98a1..b1a510b 100644 --- a/lib/module-registries_test.ts +++ b/lib/module-registries_test.ts @@ -3,14 +3,15 @@ import { assertEquals } from "https://deno.land/std@0.115.0/testing/asserts.ts"; Deno.test('gist', () => { const gistBase = 'https://gist.githubusercontent.com/danopia/d8b92fdbaa146133dac74a248e62d761/raw/bf5074703f24fee4c2f08577908115f2a6ffff6a'; - const gistUrl = `${gistBase}/repro.ts`; + const mainModule = `${gistBase}/repro.ts`; + + assertEquals(determineModuleBase(mainModule, { mainModule }), gistBase); - assertEquals(determineModuleBase(gistUrl, false), gistBase); assertEquals(determineModuleLabel({ base: gistBase, fragment: '', deps: new Set(), depsUnversioned: new Set(), files: [], totalSize: 0, - }, false), [ + }, { mainModule }), [ "gist: danopia/d8b92fdbaa146133dac74a248e62d761", " @ bf5074703f24fee4c2f08577908115f2a6ffff6a", ]);