From 71684968f4a7e904ea95e4cae15a4d629825a00e Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Fri, 28 Feb 2025 13:23:17 -0500 Subject: [PATCH] misc edits --- import_map_resolver.js | 83 ++++++++++++++++++++++++++++++++++++++++++ mod.ts | 2 +- what/entry.ts | 5 ++- what/include.ts | 5 --- what/include_a.ts | 6 +++ what/include_b.ts | 1 + what/index.ts | 5 ++- 7 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 import_map_resolver.js delete mode 100644 what/include.ts create mode 100644 what/include_a.ts create mode 100644 what/include_b.ts diff --git a/import_map_resolver.js b/import_map_resolver.js new file mode 100644 index 0000000..d5aea4e --- /dev/null +++ b/import_map_resolver.js @@ -0,0 +1,83 @@ +/** + * Resolves a module specifier against an import map + * @param {string} specifier - The module specifier to resolve (bare specifier or absolute URL) + * @param {Object} importMap - The import map object containing imports and scopes + * @param {string} baseURL - The base URL for context (especially for scopes) + * @returns {string} The resolved URL + */ +export default function resolveImportMap(specifier, importMap, baseURL) { + + // Check for exact matches first (most common case for bare specifiers) + const lookup = importMap.imports[specifier]; + if (lookup) { return lookup; } + + const Scanner =(obj)=> + { + // Check for path prefix matches (longest first) + const keys = Object.keys(obj) + .filter(key => key.endsWith('/')) + .sort((a, b) => b.length - a.length); + for (const key of keys) + { + if (specifier.startsWith(key)) + { + const remainder = specifier.slice(key.length); + return obj[key] + remainder; + } + } + } + + const scan = Scanner(importMap.imports); + if (scan) {return scan} + + // Handle scopes if available + if (importMap.scopes) { + const scopeKeys = Object.keys(importMap.scopes).sort((a, b) => b.length - a.length); + for (const scopeKey of scopeKeys) + { + if (specifier.startsWith(scopeKey)) + { + const scopeImports = importMap.scopes[scopeKey]; + const scan = Scanner(scopeImports); + if (scan) {return scan} + } + } + } + + return specifier; + } + + // Example usage for bare specifiers: + function demonstrateOptimizedResolver() { + const importMap = { + "imports": { + "lodash": "https://cdn.skypack.dev/lodash", + "react": "https://cdn.skypack.dev/react", + "lib/": "/node_modules/lib/", + "components/": "/components/" + }, + "scopes": { + "/admin/": { + "components/": "/admin-components/", + "admin-utils": "scoped!/js/admin-utils.js" + } + } + }; + + // Examples with bare specifiers + console.log("Resolving 'lodash':", resolveImportMap("lodash", importMap, "https://example.com/admin/dashboard/")); + console.log("Resolving 'components/button':", resolveImportMap("components/button", importMap, "https://example.com/admin/dashboard/")); + + // Example with scope + console.log("Resolving 'admin-utils':", + resolveImportMap("admin-utils", importMap, "https://example.com/admin/dashboard/")); + + console.log("Resolving '/admin/admin-utils':", + resolveImportMap("admin-utils", importMap, "https://example.com/admin/dashboard/")); + + // Example with URL + console.log("Resolving 'https://example.com/external.js':", + resolveImportMap("https://example.com/external.js", importMap, "https://example.com/admin/dashboard/")); + } + + demonstrateOptimizedResolver(); diff --git a/mod.ts b/mod.ts index 7efe48d..629de59 100644 --- a/mod.ts +++ b/mod.ts @@ -61,8 +61,8 @@ export default async function(directory, buildOptions={}, importMap) jsxImportSource: "react", ...buildOptions, plugins: [ - resolvePlugin(directory), Mapper.importmapPlugin(importMap) as ESBuild.Plugin, + resolvePlugin(directory), ...buildOptions.plugins||[] ] }; diff --git a/what/entry.ts b/what/entry.ts index d7c60d4..6ac258d 100644 --- a/what/entry.ts +++ b/what/entry.ts @@ -1,9 +1,10 @@ -import Message from "./include.ts"; +import React from "react"; +import Message from "./include_a.ts"; type Person = {name:string, age:number}; const me:Person = {name:"seth", age:41}; -console.log(Message); +console.log(Message, React); export default me; \ No newline at end of file diff --git a/what/include.ts b/what/include.ts deleted file mode 100644 index 79dff95..0000000 --- a/what/include.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as React from "react"; - -console.log(React); - -export default "HELLO"; \ No newline at end of file diff --git a/what/include_a.ts b/what/include_a.ts new file mode 100644 index 0000000..8e9c0a9 --- /dev/null +++ b/what/include_a.ts @@ -0,0 +1,6 @@ +import * as B from "./include_b.ts"; +import * as React from "react"; + +console.log(React, B); + +export default "HELLO"; \ No newline at end of file diff --git a/what/include_b.ts b/what/include_b.ts new file mode 100644 index 0000000..7c645e4 --- /dev/null +++ b/what/include_b.ts @@ -0,0 +1 @@ +export default {}; \ No newline at end of file diff --git a/what/index.ts b/what/index.ts index 6c66f88..77b200b 100644 --- a/what/index.ts +++ b/what/index.ts @@ -4,10 +4,11 @@ const {outputFiles} = await Bundle( import.meta.resolve('./'), // ESBuild configuration (entry points are relative to "directory"): - {entryPoints:["./entry.ts"]}, + {entryPoints:["entry"]}, // import map (if omitted, will scan for a deno configuration within "directory" and use that) {"imports": { + "entry": "./entry.ts", "react": "https://esm.sh/preact@10.22.0/compat", "react/": "https://esm.sh/preact@10.22.0/compat/" }} @@ -15,5 +16,5 @@ const {outputFiles} = await Bundle( for(const item of outputFiles){ // do something with the output... - console.log(item.text); + console.log(item.text.substring(0, 200)); }