├── .github └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── chompfile.toml ├── package.json ├── src ├── alphabetize.ts ├── map.ts └── url.ts ├── test └── cases │ ├── combine-subpaths.js │ ├── examples.js │ ├── flattening-roots.js │ ├── flattening.js │ ├── integrity.js │ ├── rebase-map.js │ ├── rebase-url.js │ └── resolve-map.js ├── tsconfig.json └── typedoc.json /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: main 6 | pull_request: 7 | branches: main 8 | 9 | jobs: 10 | test-node: 11 | name: Node.js Tests 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | node: [14.x, 16.x] 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Use Node.js ${{ matrix.node }} 19 | uses: actions/setup-node@v2 20 | with: 21 | node: ${{ matrix.node }} 22 | - name: Setup Chomp 23 | uses: guybedford/chomp-action@v1 24 | env: 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | - run: npm install 27 | - run: chomp test 28 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Setup Node 15 | uses: actions/setup-node@v2 16 | with: 17 | node-version: "16.x" 18 | - name: Setup Chomp 19 | uses: guybedford/chomp-action@v1 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | - name: Installing Dependencies 23 | run: npm install 24 | - name: Build package 25 | run: chomp build 26 | - name: Run tests 27 | run: chomp test 28 | - name: Authenticate with Registry 29 | env: 30 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | run: | 32 | npm logout 33 | echo "@jspm:registry=https://registry.npmjs.org/" > .npmrc 34 | echo "registry=https://registry.npmjs.org/" >> .npmrc 35 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc 36 | npm whoami 37 | 38 | - name: Publish to npm 39 | env: 40 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 41 | run: npm publish --yes 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | lib 4 | dist 5 | docs 6 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | ----------- 3 | 4 | Copyright (C) 2020-2021 Guy Bedford 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Import Map Utility 2 | 3 | Generic ImportMap class utility for the manipulation and resolution of import maps, used by JSPM. 4 | 5 | ## Getting Started 6 | 7 | ### Installation 8 | 9 | Node.js: 10 | ``` 11 | npm install @jspm/import-map 12 | ``` 13 | 14 | ### Usage 15 | 16 | `@jspm/import-map` only ships as an ES module. 17 | 18 | example.mjs 19 | ```js 20 | import { ImportMap } from '@jspm/import-map'; 21 | 22 | const mapUrl = import.meta.url; 23 | 24 | const map = new ImportMap({ 25 | mapUrl, // optional 26 | map: { 27 | imports: { 28 | react: 'https://cdn.com/react.js' 29 | }, 30 | scopes: { 31 | 'https://site.com/': { 32 | react: 'https://cdn.com/react2.js' 33 | } 34 | }, 35 | integrity: { 36 | 'https://cdn.com/react.js': 'sha384-...' 37 | } 38 | } 39 | }); 40 | 41 | // Use the map resolver 42 | map.resolve('react') === 'https://cdn.com/react.js'; 43 | map.resolve('react', 'https://site.com/') === 'https://cdn.com/react2.js'; 44 | 45 | // Supports normal URL resolution behaving a browser-compatible ES module resolver 46 | map.resolve('./hello.js', 'https://site.com/') === 'https://site.com/hello.js'; 47 | 48 | // Mutate the map 49 | map.set('react', './custom-react.js'); 50 | map.resolve('react') === new URL('./custom-react.js', mapUrl).href; 51 | 52 | // Mutate the map inside a custom scope 53 | map.set('react', './custom-react2.js', 'https://another.com/'); 54 | map.resolve('react', 'https://another.com/') === new URL('./custom-react2.js', mapUrl).href; 55 | 56 | // Get the map JSON 57 | console.log(JSON.stringify(map.toJSON(), null, 2)); 58 | // { 59 | // "imports": { 60 | // "react": "./custom-react.js" 61 | // }, 62 | // "scopes": { 63 | // "https://site.com/": { 64 | // "react": "https://cdn.com/react2.js" 65 | // }, 66 | // "https://another.com/": { 67 | // "react": "./custom-react2.js" 68 | // } 69 | // }, 70 | // "integrity": { 71 | // "https://cdn.com/react.js": "sha384-..." 72 | // } 73 | // } 74 | 75 | // Rebase the map 76 | map.rebase('./map/'); 77 | console.log(JSON.stringify(map.toJSON(), null, 2)); 78 | // { 79 | // "imports": { 80 | // "react": "../custom-react.js" 81 | // }, 82 | // "scopes": { 83 | // "https://site.com/": { 84 | // "react": "https://cdn.com/react2.js" 85 | // }, 86 | // "https://another.com/": { 87 | // "react": "../custom-react2.js" 88 | // } 89 | // }, 90 | // "integrity": { 91 | // "https://cdn.com/react.js": "sha384-..." 92 | // } 93 | // } 94 | 95 | // Flatten the import map (removes unnecessary scope redundancy) 96 | map.set('react', '../custom-react.js', 'https://site.com/'); 97 | map.flatten(); 98 | console.log(JSON.stringify(map.toJSON(), null, 2)); 99 | // { 100 | // "imports": { 101 | // "react": "../custom-react.js" 102 | // }, 103 | // "scopes": { 104 | // "https://another.com/": { 105 | // "react": "../custom-react2.js" 106 | // } 107 | // }, 108 | // "integrity": { 109 | // "https://cdn.com/react.js": "sha384-..." 110 | // } 111 | // } 112 | 113 | // Replace URLs in the map 114 | map.replace('https://cdn.com/', 'https://cdn-mirror.com/'); 115 | map.replace('https://another.com/', 'https://another-site.com/'); 116 | console.log(JSON.stringify(map.toJSON(), null, 2)); 117 | // { 118 | // "imports": { 119 | // "react": "../custom-react.js" 120 | // }, 121 | // "scopes": { 122 | // "https://another-site.com/": { 123 | // "react": "../custom-react2.js" 124 | // } 125 | // }, 126 | // "integrity": { 127 | // "https://another.com/react.js": "sha384-..." 128 | // } 129 | // } 130 | 131 | // Combine subpaths in the map 132 | // This is only supported for scopes and not top-level imports, 133 | // to avoid losing dependency information from imports. 134 | // (all non-returning methods support chaining) 135 | console.log(new ImportMap({ 136 | map: { 137 | scopes: { 138 | "/": { 139 | "pkg/a.js": "/pkg/a.js", 140 | "pkg/b.js": "/pkg/b.js" 141 | } 142 | } 143 | } 144 | }).combineSubpaths().toJSON()); 145 | // { 146 | // "imports": {}, 147 | // "scopes": { 148 | // "/": { 149 | // "pkg/": "/pkg/" 150 | // } 151 | // } 152 | // } 153 | ``` 154 | 155 | ## API 156 | 157 | See [src/map.ts](https://github.com/jspm/import-map/blob/main/src/map.ts). 158 | 159 | Support is also provided for conditional maps supporting a way to manage generic maps for multiple environment targets, before serializing or resolving for exact environment targets. 160 | 161 | ### License 162 | 163 | MIT 164 | -------------------------------------------------------------------------------- /chompfile.toml: -------------------------------------------------------------------------------- 1 | version = 0.1 2 | default-task = 'build' 3 | 4 | extensions = ['chomp@0.1:swc', 'chomp@0.1:rollup'] 5 | 6 | [[task]] 7 | target = 'docs' 8 | deps = ['src/*.ts'] 9 | run = 'typedoc src/*.ts' 10 | 11 | [[task]] 12 | dep = 'src/##.ts' 13 | target = 'lib/##.js' 14 | template = 'swc' 15 | 16 | [[task]] 17 | name = 'build' 18 | target = 'dist/map.js' 19 | deps = ['lib/**/*.js', 'build:dec'] 20 | template = 'rollup' 21 | [task.template-options] 22 | entries = ['lib/map.js'] 23 | 24 | [[task]] 25 | name = 'build:dec' 26 | deps = ['lib/**/*.js'] 27 | run = 'npx tsc --emitDeclarationOnly' 28 | 29 | [[task]] 30 | name = 'test' 31 | dep = 'test:' 32 | 33 | [[task]] 34 | name = 'test:#' 35 | deps = ['lib/**/*.js', 'test/cases/#.js'] 36 | run = 'node -C source $DEP' 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jspm/import-map", 3 | "description": "Package Import Map Utility", 4 | "license": "MIT", 5 | "version": "1.1.0", 6 | "types": "lib/map.d.ts", 7 | "type": "module", 8 | "exports": { 9 | ".": { 10 | "types": "./lib/map.d.ts", 11 | "source": "./lib/map.js", 12 | "default": "./dist/map.js" 13 | } 14 | }, 15 | "files": [ 16 | "src", 17 | "lib", 18 | "dist" 19 | ], 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/jspm/import-map.git" 23 | }, 24 | "keywords": [ 25 | "jspm", 26 | "import maps", 27 | "es modules" 28 | ], 29 | "author": "Guy Bedford", 30 | "bugs": { 31 | "url": "https://github.com/jspm/import-map/issues" 32 | }, 33 | "homepage": "https://github.com/jspm/import-map#readme", 34 | "devDependencies": { 35 | "@swc/cli": "^0.1.65", 36 | "@swc/core": "^1.4.8", 37 | "rollup": "^2.79.1", 38 | "typescript": "^4.9.5" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/alphabetize.ts: -------------------------------------------------------------------------------- 1 | export function alphabetize(obj: Record): Record { 2 | const out: Record = {}; 3 | for (const key of Object.keys(obj).sort()) out[key] = obj[key]; 4 | return out; 5 | } 6 | -------------------------------------------------------------------------------- /src/map.ts: -------------------------------------------------------------------------------- 1 | import { 2 | baseUrl, 3 | rebase, 4 | isPlain, 5 | isURL, 6 | getCommonBase, 7 | resolve, 8 | sameOrigin, 9 | } from "./url.js"; 10 | import { alphabetize } from "./alphabetize.js"; 11 | 12 | let crypto; 13 | 14 | export interface IImportMap { 15 | imports?: Record; 16 | scopes?: { 17 | [scope: string]: Record; 18 | }; 19 | integrity?: { 20 | [url: string]: string 21 | } 22 | } 23 | 24 | export class ImportMap implements IImportMap { 25 | imports: Record = Object.create(null); 26 | scopes: Record> = Object.create(null); 27 | integrity: Record = Object.create(null); 28 | 29 | /** 30 | * The absolute URL of the import map, for determining relative resolutions 31 | * When using file:/// URLs this allows relative modules to be co-located 32 | */ 33 | mapUrl: URL; 34 | /** 35 | * The URL to use for root-level resolutions in the import map 36 | * If null, root resolutions are not resolved and instead left as-is 37 | * 38 | * By default, rootUrl is null unless the mapUrl is an http or https URL, 39 | * in which case it is taken to be the root of the mapUrl. 40 | */ 41 | rootUrl: URL | null; 42 | 43 | /** 44 | * Create a new import map instance 45 | * 46 | * @param opts import map options, can be an optional bag of { map?, mapUrl?, rootUrl? } or just a direct mapUrl 47 | */ 48 | constructor( 49 | opts: 50 | | { 51 | map?: IImportMap; 52 | mapUrl?: string | URL; 53 | rootUrl?: string | URL | null; 54 | } 55 | | string 56 | | URL 57 | ) { 58 | let { 59 | map, 60 | mapUrl = baseUrl, 61 | rootUrl, 62 | } = opts instanceof URL || 63 | typeof opts === "string" || 64 | typeof opts === "undefined" 65 | ? { mapUrl: opts, map: undefined, rootUrl: undefined } 66 | : opts; 67 | if (typeof mapUrl === "string") mapUrl = new URL(mapUrl); 68 | this.mapUrl = mapUrl; 69 | if ( 70 | rootUrl === undefined && 71 | (this.mapUrl.protocol === "http:" || this.mapUrl.protocol === "https:") 72 | ) 73 | rootUrl = new URL("/", this.mapUrl); 74 | else if (typeof rootUrl === "string") rootUrl = new URL(rootUrl); 75 | this.rootUrl = rootUrl || null; 76 | if (map) this.extend(map); 77 | } 78 | 79 | /** 80 | * Clones the import map 81 | * @returns Cloned import map 82 | */ 83 | clone() { 84 | return new ImportMap({ mapUrl: this.mapUrl, rootUrl: this.rootUrl }).extend( 85 | this 86 | ); 87 | } 88 | 89 | /** 90 | * Extends the import map mappings 91 | * @param map Import map to extend with 92 | * @param overrideScopes Set to true to have scopes be replacing instead of extending 93 | * @returns ImportMap for chaining 94 | */ 95 | extend(map: IImportMap, overrideScopes = false) { 96 | Object.assign(this.imports, map.imports); 97 | if (overrideScopes) { 98 | Object.assign(this.scopes, map.scopes); 99 | } else if (map.scopes) { 100 | for (const scope of Object.keys(map.scopes)) 101 | Object.assign( 102 | (this.scopes[scope] = this.scopes[scope] || Object.create(null)), 103 | map.scopes[scope] 104 | ); 105 | } 106 | Object.assign(this.integrity, map.integrity); 107 | this.rebase(); 108 | return this; 109 | } 110 | 111 | /** 112 | * Performs an alphanumerical sort on the import map imports and scopes 113 | * @returns ImportMap for chaining 114 | */ 115 | sort() { 116 | this.imports = alphabetize(this.imports); 117 | this.scopes = alphabetize(this.scopes); 118 | for (const scope of Object.keys(this.scopes)) 119 | this.scopes[scope] = alphabetize(this.scopes[scope]); 120 | this.integrity = alphabetize(this.integrity); 121 | return this; 122 | } 123 | 124 | /** 125 | * Set a specific entry in the import map 126 | * 127 | * @param name Specifier to set 128 | * @param target Target of the map 129 | * @param parent Optional parent scope 130 | * @returns ImportMap for chaining 131 | */ 132 | set(name: string, target: string, parent?: string) { 133 | if (!parent) { 134 | this.imports[name] = target; 135 | } else { 136 | this.scopes[parent] = this.scopes[parent] || Object.create(null); 137 | this.scopes[parent][name] = target; 138 | } 139 | return this; 140 | } 141 | /** 142 | * @param target URL target 143 | * @param integrity Integrity 144 | */ 145 | setIntegrity(target: string, integrity: string) { 146 | this.integrity[target] = integrity; 147 | const targetRebased = rebase(target, this.mapUrl, this.rootUrl); 148 | if (targetRebased !== target && this.integrity[targetRebased]) 149 | delete this.integrity[targetRebased]; 150 | if (targetRebased.startsWith('./') && target !== targetRebased.slice(2) && this.integrity[targetRebased.slice(2)]) 151 | delete this.integrity[targetRebased.slice(2)]; 152 | } 153 | /** 154 | * @param target URL target 155 | * @param integrity Integrity 156 | */ 157 | getIntegrity(target: string, integrity: string) { 158 | const targetResolved = resolve(target, this.mapUrl, this.rootUrl); 159 | if (this.integrity[targetResolved]) return this.integrity[targetResolved]; 160 | const targetRebased = rebase(targetResolved, this.mapUrl, this.rootUrl); 161 | if (this.integrity[targetRebased]) return this.integrity[targetRebased]; 162 | if (this.integrity[targetRebased.slice(2)]) return this.integrity[targetRebased.slice(2)]; 163 | } 164 | 165 | /** 166 | * Bulk replace URLs in the import map 167 | * Provide a URL ending in "/" to perform path replacements 168 | * 169 | * @param url {String} The URL to replace 170 | * @param newUrl {String} The URL to replace it with 171 | * @returns ImportMap for chaining 172 | */ 173 | replace(url: string, newUrl: string) { 174 | const replaceSubpaths = url.endsWith("/"); 175 | if (!isURL(url)) throw new Error("URL remapping only supports URLs"); 176 | const newRelPkgUrl = rebase(newUrl, this.mapUrl, this.rootUrl); 177 | if (this.imports[url]) { 178 | this.imports[newRelPkgUrl] = this.imports[url]; 179 | delete this.imports[url]; 180 | } 181 | if (replaceSubpaths) { 182 | for (const impt of Object.keys(this.imports)) { 183 | const target = this.imports[impt]; 184 | if (target.startsWith(url)) { 185 | this.imports[impt] = newRelPkgUrl + target.slice(url.length); 186 | } 187 | } 188 | } 189 | for (const scope of Object.keys(this.scopes)) { 190 | const scopeImports = this.scopes[scope]; 191 | const scopeUrl = resolve(scope, this.mapUrl, this.rootUrl); 192 | if ((replaceSubpaths && scopeUrl.startsWith(url)) || scopeUrl === url) { 193 | const newScope = newRelPkgUrl + scopeUrl.slice(url.length); 194 | delete this.scopes[scope]; 195 | this.scopes[newScope] = scopeImports; 196 | } 197 | for (const impt of Object.keys(scopeImports)) { 198 | const target = scopeImports[impt]; 199 | if ((replaceSubpaths && target.startsWith(url)) || target === url) 200 | scopeImports[impt] = newRelPkgUrl + target.slice(url.length); 201 | } 202 | } 203 | if (this.integrity[url]) { 204 | this.integrity[newRelPkgUrl] = this.integrity[url]; 205 | delete this.integrity[url]; 206 | } 207 | return this; 208 | } 209 | 210 | /** 211 | * Groups subpath mappings into path mappings when multiple exact subpaths 212 | * exist under the same path. 213 | * 214 | * For two mappings like { "base/a.js": "/a.js", "base/b.js": "/b.js" }, 215 | * these will be replaced with a single path mapping { "base/": "/" }. 216 | * Groupings are done throughout all import scopes individually. 217 | * 218 | * @returns ImportMap for chaining 219 | */ 220 | combineSubpaths() { 221 | // iterate possible bases and submappings, grouping bases greedily 222 | const combineSubpathMappings = (mappings: Record) => { 223 | let outMappings: Record = Object.create(null); 224 | for (let impt of Object.keys(mappings)) { 225 | const target = mappings[impt]; 226 | // Check if this import is already handled by an existing path mapping 227 | // If so, either merge with it or continue on 228 | let mapMatch; 229 | if (isPlain(impt)) { 230 | mapMatch = getMapMatch(impt, outMappings); 231 | } else { 232 | mapMatch = 233 | getMapMatch( 234 | (impt = rebase(impt, this.mapUrl, this.rootUrl)), 235 | outMappings 236 | ) || 237 | (this.rootUrl && 238 | getMapMatch( 239 | (impt = rebase(impt, this.mapUrl, null)), 240 | outMappings 241 | )) || 242 | undefined; 243 | } 244 | if ( 245 | mapMatch && 246 | impt.slice(mapMatch.length) === 247 | resolve(target, this.mapUrl, this.rootUrl).slice( 248 | resolve(outMappings[mapMatch], this.mapUrl, this.rootUrl).length 249 | ) 250 | ) { 251 | continue; 252 | } 253 | 254 | let newbase = false; 255 | const targetParts = mappings[impt].split("/"); 256 | const imptParts = impt.split("/"); 257 | for (let j = imptParts.length - 1; j > 0; j--) { 258 | const subpath = imptParts.slice(j).join("/"); 259 | const subpathTarget = targetParts 260 | .slice(targetParts.length - (imptParts.length - j)) 261 | .join("/"); 262 | if (subpath !== subpathTarget) { 263 | outMappings[impt] = mappings[impt]; 264 | break; 265 | } 266 | const base = imptParts.slice(0, j).join("/") + "/"; 267 | if (outMappings[base]) continue; 268 | const baseTarget = 269 | targetParts 270 | .slice(0, targetParts.length - (imptParts.length - j)) 271 | .join("/") + "/"; 272 | 273 | // Dedupe existing mappings against the new base to remove them 274 | // And if we dont dedupe against anything then dont perform this basing 275 | for (let impt of Object.keys(outMappings)) { 276 | const target = outMappings[impt]; 277 | let matches = false; 278 | if (isPlain(impt)) { 279 | matches = impt.startsWith(base); 280 | } else { 281 | matches = 282 | (impt = rebase(impt, this.mapUrl, this.rootUrl)).startsWith( 283 | base 284 | ) || 285 | (impt = rebase(impt, this.mapUrl, this.rootUrl)).startsWith( 286 | base 287 | ); 288 | } 289 | if ( 290 | matches && 291 | impt.slice(base.length) === 292 | resolve(target, this.mapUrl, this.rootUrl).slice( 293 | resolve(baseTarget, this.mapUrl, this.rootUrl).length 294 | ) 295 | ) { 296 | newbase = true; 297 | delete outMappings[impt]; 298 | } 299 | } 300 | 301 | if (newbase) { 302 | outMappings[base] = baseTarget; 303 | break; 304 | } 305 | } 306 | 307 | if (!newbase) outMappings[impt] = target; 308 | } 309 | return outMappings; 310 | }; 311 | 312 | // Only applies for scopes since "imports" are generally treated as 313 | // an authoritative entry point list 314 | for (const scope of Object.keys(this.scopes)) { 315 | this.scopes[scope] = combineSubpathMappings(this.scopes[scope]); 316 | } 317 | 318 | return this; 319 | } 320 | 321 | /** 322 | * Groups the import map scopes to shared URLs to reduce duplicate mappings. 323 | * 324 | * For two given scopes, "https://site.com/x/" and "https://site.com/y/", 325 | * a single scope will be constructed for "https://site.com/" including 326 | * their shared mappings, only retaining the scopes if they have differences. 327 | * 328 | * In the case where the scope is on the same origin as the mapUrl, the grouped 329 | * scope is determined based on determining the common baseline over all local scopes 330 | * 331 | * @returns ImportMap for chaining 332 | */ 333 | flatten() { 334 | // First, determine the common base for the local mappings if any 335 | let localScopemapUrl: string | null = null; 336 | for (const scope of Object.keys(this.scopes)) { 337 | const resolvedScope = resolve(scope, this.mapUrl, this.rootUrl); 338 | if (isURL(resolvedScope)) { 339 | const scopeUrl = new URL(resolvedScope); 340 | if (sameOrigin(scopeUrl, this.mapUrl)) { 341 | if (!localScopemapUrl) localScopemapUrl = scopeUrl.href; 342 | else 343 | localScopemapUrl = getCommonBase(scopeUrl.href, localScopemapUrl); 344 | } 345 | } else { 346 | if (!localScopemapUrl) localScopemapUrl = resolvedScope; 347 | else localScopemapUrl = getCommonBase(resolvedScope, localScopemapUrl); 348 | } 349 | } 350 | 351 | // for each scope, update its mappings to be in the shared base where possible 352 | const relativeLocalScopemapUrl = localScopemapUrl 353 | ? rebase(localScopemapUrl, this.mapUrl, this.rootUrl) 354 | : null; 355 | for (const scope of Object.keys(this.scopes)) { 356 | const scopeImports = this.scopes[scope]; 357 | 358 | let scopemapUrl: string; 359 | const resolvedScope = resolve(scope, this.mapUrl, this.rootUrl); 360 | if (isURL(resolvedScope)) { 361 | const scopeUrl = new URL(resolvedScope); 362 | if (sameOrigin(scopeUrl, this.mapUrl)) { 363 | scopemapUrl = relativeLocalScopemapUrl; 364 | } else { 365 | scopemapUrl = 366 | scopeUrl.protocol + 367 | "//" + 368 | scopeUrl.hostname + 369 | (scopeUrl.port ? ":" + scopeUrl.port : "") + 370 | "/"; 371 | } 372 | } else { 373 | scopemapUrl = relativeLocalScopemapUrl; 374 | } 375 | 376 | let scopeBase: Record | null = 377 | this.scopes[scopemapUrl] || Object.create(null); 378 | if (scopeBase === scopeImports) scopeBase = null; 379 | 380 | let flattenedAll = true; 381 | for (const name of Object.keys(scopeImports)) { 382 | const target = scopeImports[name]; 383 | if ( 384 | this.imports[name] && 385 | resolve(this.imports[name], this.mapUrl, this.rootUrl) === 386 | resolve(target, this.mapUrl, this.rootUrl) 387 | ) { 388 | delete scopeImports[name]; 389 | } else if ( 390 | scopeBase && 391 | (!scopeBase[name] || 392 | resolve(scopeBase[name], this.mapUrl, this.rootUrl) === 393 | resolve(target, this.mapUrl, this.rootUrl)) 394 | ) { 395 | scopeBase[name] = rebase(target, this.mapUrl, this.rootUrl); 396 | delete scopeImports[name]; 397 | this.scopes[scopemapUrl] = alphabetize(scopeBase); 398 | } else { 399 | flattenedAll = false; 400 | } 401 | } 402 | if (flattenedAll) delete this.scopes[scope]; 403 | } 404 | return this; 405 | } 406 | 407 | /** 408 | * Rebase the entire import map to a new mapUrl and rootUrl 409 | * 410 | * If the rootUrl is not provided, it will remain null if it was 411 | * already set to null. 412 | * 413 | * Otherwise, just like the constructor options, the rootUrl 414 | * will default to the mapUrl base if it is an http: or https: 415 | * scheme URL, and null otherwise keeping absolute URLs entirely 416 | * in-tact. 417 | * 418 | * @param mapUrl The new map URL to use 419 | * @param rootUrl The new root URL to use 420 | * @returns ImportMap for chaining 421 | */ 422 | rebase(mapUrl: URL | string = this.mapUrl, rootUrl?: URL | string | null) { 423 | if (typeof mapUrl === "string") mapUrl = new URL(mapUrl); 424 | if (rootUrl === undefined) { 425 | if (mapUrl.href === this.mapUrl.href) rootUrl = this.rootUrl; 426 | else 427 | rootUrl = 428 | this.rootUrl === null || 429 | (mapUrl.protocol !== "https:" && mapUrl.protocol !== "http:") 430 | ? null 431 | : new URL("/", mapUrl); 432 | } else if (typeof rootUrl === "string") rootUrl = new URL(rootUrl); 433 | let changedImportProps = false; 434 | for (const impt of Object.keys(this.imports)) { 435 | const target = this.imports[impt]; 436 | this.imports[impt] = rebase( 437 | resolve(target, this.mapUrl, this.rootUrl), 438 | mapUrl, 439 | rootUrl 440 | ); 441 | if (!isPlain(impt)) { 442 | const newImpt = rebase( 443 | resolve(impt, this.mapUrl, this.rootUrl), 444 | mapUrl, 445 | rootUrl 446 | ); 447 | if (newImpt !== impt) { 448 | changedImportProps = true; 449 | this.imports[newImpt] = this.imports[impt]; 450 | delete this.imports[impt]; 451 | } 452 | } 453 | } 454 | if (changedImportProps) this.imports = alphabetize(this.imports); 455 | let changedScopeProps = false; 456 | for (const scope of Object.keys(this.scopes)) { 457 | const scopeImports = this.scopes[scope]; 458 | let changedScopeImportProps = false; 459 | for (const impt of Object.keys(scopeImports)) { 460 | const target = scopeImports[impt]; 461 | scopeImports[impt] = rebase( 462 | resolve(target, this.mapUrl, this.rootUrl), 463 | mapUrl, 464 | rootUrl 465 | ); 466 | if (!isPlain(impt)) { 467 | const newName = rebase( 468 | resolve(impt, this.mapUrl, this.rootUrl), 469 | mapUrl, 470 | rootUrl 471 | ); 472 | if (newName !== impt) { 473 | changedScopeImportProps = true; 474 | scopeImports[newName] = scopeImports[impt]; 475 | delete scopeImports[impt]; 476 | } 477 | } 478 | } 479 | if (changedScopeImportProps) 480 | this.scopes[scope] = alphabetize(scopeImports); 481 | const newScope = rebase( 482 | resolve(scope, this.mapUrl, this.rootUrl), 483 | mapUrl, 484 | rootUrl 485 | ); 486 | if (scope !== newScope) { 487 | changedScopeProps = true; 488 | delete this.scopes[scope]; 489 | this.scopes[newScope] = scopeImports; 490 | } 491 | } 492 | if (changedScopeProps) this.scopes = alphabetize(this.scopes); 493 | let changedIntegrityProps = false; 494 | for (const target of Object.keys(this.integrity)) { 495 | const newTarget = rebase( 496 | resolve(target, this.mapUrl, this.rootUrl), 497 | mapUrl, 498 | rootUrl 499 | ); 500 | if (target !== newTarget) { 501 | this.integrity[newTarget] = this.integrity[target]; 502 | delete this.integrity[target]; 503 | changedIntegrityProps = true; 504 | } 505 | } 506 | if (changedIntegrityProps) this.integrity = alphabetize(this.integrity); 507 | this.mapUrl = mapUrl; 508 | this.rootUrl = rootUrl; 509 | return this; 510 | } 511 | 512 | /** 513 | * Perform a module resolution against the import map 514 | * 515 | * @param specifier Specifier to resolve 516 | * @param parentUrl Parent URL to resolve against 517 | * @returns Resolved URL string 518 | */ 519 | resolve(specifier: string, parentUrl: string | URL = this.mapUrl): string { 520 | if (typeof parentUrl !== "string") parentUrl = parentUrl.toString(); 521 | parentUrl = resolve(parentUrl, this.mapUrl, this.rootUrl); 522 | let specifierUrl: URL | undefined; 523 | if (!isPlain(specifier)) { 524 | specifierUrl = new URL(specifier, parentUrl); 525 | specifier = specifierUrl.href; 526 | } 527 | const scopeMatches = getScopeMatches( 528 | parentUrl, 529 | this.scopes, 530 | this.mapUrl, 531 | this.rootUrl 532 | ); 533 | for (const [scope] of scopeMatches) { 534 | let mapMatch = getMapMatch(specifier, this.scopes[scope]); 535 | if (!mapMatch && specifierUrl) { 536 | mapMatch = 537 | getMapMatch( 538 | (specifier = rebase(specifier, this.mapUrl, this.rootUrl)), 539 | this.scopes[scope] 540 | ) || 541 | (this.rootUrl && 542 | getMapMatch( 543 | (specifier = rebase(specifier, this.mapUrl, null)), 544 | this.scopes[scope] 545 | )) || 546 | undefined; 547 | } 548 | if (mapMatch) { 549 | const target = this.scopes[scope][mapMatch]; 550 | return resolve( 551 | target + specifier.slice(mapMatch.length), 552 | this.mapUrl, 553 | this.rootUrl 554 | ); 555 | } 556 | } 557 | let mapMatch = getMapMatch(specifier, this.imports); 558 | if (!mapMatch && specifierUrl) { 559 | mapMatch = 560 | getMapMatch( 561 | (specifier = rebase(specifier, this.mapUrl, this.rootUrl)), 562 | this.imports 563 | ) || 564 | (this.rootUrl && 565 | getMapMatch( 566 | (specifier = rebase(specifier, this.mapUrl, null)), 567 | this.imports 568 | )) || 569 | undefined; 570 | } 571 | if (mapMatch) { 572 | const target = this.imports[mapMatch]; 573 | return resolve( 574 | target + specifier.slice(mapMatch.length), 575 | this.mapUrl, 576 | this.rootUrl 577 | ); 578 | } 579 | if (specifierUrl) return specifierUrl.href; 580 | throw new Error(`Unable to resolve ${specifier} in ${parentUrl}`); 581 | } 582 | 583 | /** 584 | * Get the import map JSON data 585 | * 586 | * @returns Import map data 587 | */ 588 | toJSON(): IImportMap { 589 | const obj: any = {}; 590 | if (Object.keys(this.imports).length) obj.imports = this.imports; 591 | if (Object.keys(this.scopes).length) obj.scopes = this.scopes; 592 | if (Object.keys(this.integrity).length) obj.integrity = this.integrity; 593 | return JSON.parse(JSON.stringify(obj)); 594 | } 595 | } 596 | 597 | export function getScopeMatches( 598 | parentUrl: string, 599 | scopes: Record>, 600 | mapUrl: URL, 601 | rootUrl?: URL 602 | ): [string, string][] { 603 | let scopeCandidates = Object.keys(scopes).map((scope) => [ 604 | scope, 605 | resolve(scope, mapUrl, rootUrl), 606 | ]); 607 | scopeCandidates = scopeCandidates.sort(([, matchA], [, matchB]) => 608 | matchA.length < matchB.length ? 1 : -1 609 | ); 610 | 611 | return scopeCandidates.filter(([, scopeUrl]) => { 612 | return ( 613 | scopeUrl === parentUrl || 614 | (scopeUrl.endsWith("/") && parentUrl.startsWith(scopeUrl)) 615 | ); 616 | }) as [string, string][]; 617 | } 618 | 619 | export function getMapMatch( 620 | specifier: string, 621 | map: Record 622 | ): string | undefined { 623 | if (specifier in map) return specifier; 624 | let curMatch; 625 | for (const match of Object.keys(map)) { 626 | const wildcard = match.endsWith("*"); 627 | if (!match.endsWith("/") && !wildcard) continue; 628 | if (specifier.startsWith(wildcard ? match.slice(0, -1) : match)) { 629 | if (!curMatch || match.length > curMatch.length) curMatch = match; 630 | } 631 | } 632 | return curMatch; 633 | } 634 | -------------------------------------------------------------------------------- /src/url.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | // @ts-ignore 3 | var document: any; 4 | // @ts-ignore 5 | var location: any; 6 | // @ts-ignore 7 | var process: NodeJS.Process; 8 | } 9 | 10 | export let baseUrl: URL; 11 | // @ts-ignore 12 | if (typeof Deno !== "undefined") { 13 | // @ts-ignore 14 | baseUrl = new URL("file://" + Deno.cwd() + "/"); 15 | } else if (typeof process !== "undefined" && process.versions?.node) { 16 | baseUrl = new URL("file://" + process.cwd() + "/"); 17 | } else if ((typeof document as any) !== "undefined") { 18 | const baseEl: any | null = document.querySelector("base[href]"); 19 | if (baseEl) 20 | baseUrl = new URL(baseEl.href + (baseEl.href.endsWith("/") ? "" : "/")); 21 | else if (typeof location !== "undefined") 22 | baseUrl = new URL("../", new URL(location.href)); 23 | } 24 | 25 | export function getCommonBase(a: string, b: string): string { 26 | if (a.startsWith(b)) return b; 27 | if (b.startsWith(a)) return a; 28 | const aSegments = a.split("/"); 29 | const bSegments = b.split("/"); 30 | let i = 0; 31 | while (aSegments[i] === bSegments[i]) i++; 32 | return aSegments.slice(0, i).join("/") + "/"; 33 | } 34 | 35 | export function sameOrigin(url: URL, baseUrl: URL) { 36 | return ( 37 | url.protocol === baseUrl.protocol && 38 | url.host === baseUrl.host && 39 | url.port === baseUrl.port && 40 | url.username === baseUrl.username && 41 | url.password === baseUrl.password 42 | ); 43 | } 44 | 45 | export function resolve(url: string, mapUrl: URL, rootUrl: URL | null): string { 46 | if (url.startsWith("/")) 47 | return rootUrl 48 | ? new URL("." + url.slice(url[1] === "/" ? 1 : 0), rootUrl).href 49 | : url; 50 | return new URL(url, mapUrl).href; 51 | } 52 | 53 | /** 54 | * Rebase the given URL to the baseURL and rootURL 55 | * 56 | * @param url URL to rebase 57 | * @param baseUrl Import map baseUrl 58 | * URLs will be based relative to this path if the same origin as the URL. 59 | * @param rootUrl Optional URL ending in / of the root HTML URL. 60 | * When provided and possible, will be used as the base of the form '/...' 61 | * @returns relative URL string 62 | */ 63 | export function rebase(url: string, baseUrl: URL, rootUrl: URL | null = null) { 64 | let resolved; 65 | if (url.startsWith("/") || url.startsWith("//")) { 66 | if (rootUrl === null) return url; 67 | resolved = new URL(url, rootUrl); 68 | } else { 69 | resolved = new URL(url, baseUrl); 70 | } 71 | if (rootUrl && resolved.href.startsWith(rootUrl.href)) 72 | return resolved.href.slice(rootUrl.href.length - 1); 73 | if (rootUrl && rootUrl.href.startsWith(resolved.href)) { 74 | // edge-case 75 | return "/" + relative(resolved, rootUrl); 76 | } 77 | if (sameOrigin(resolved, baseUrl)) return relative(resolved, baseUrl); 78 | return resolved.href; 79 | } 80 | 81 | export function relative(url: URL, baseUrl: URL) { 82 | const baseUrlPath = baseUrl.pathname; 83 | const urlPath = url.pathname; 84 | const minLen = Math.min(baseUrlPath.length, urlPath.length); 85 | let sharedBaseIndex = -1; 86 | for (let i = 0; i < minLen; i++) { 87 | if (baseUrlPath[i] !== urlPath[i]) break; 88 | if (urlPath[i] === "/") sharedBaseIndex = i; 89 | } 90 | const backtracks = 91 | baseUrlPath.slice(sharedBaseIndex + 1).split("/").length - 1; 92 | return ( 93 | (backtracks ? "../".repeat(backtracks) : "./") + 94 | urlPath.slice(sharedBaseIndex + 1) + 95 | url.search + 96 | url.hash 97 | ); 98 | } 99 | 100 | export function isURL(specifier: string) { 101 | try { 102 | if (specifier[0] === "#") return false; 103 | new URL(specifier); 104 | } catch { 105 | return false; 106 | } 107 | return true; 108 | } 109 | 110 | export function isPlain(specifier: string) { 111 | return !isRelative(specifier) && !isURL(specifier); 112 | } 113 | 114 | export function isRelative(specifier: string) { 115 | return ( 116 | specifier.startsWith("./") || 117 | specifier.startsWith("../") || 118 | specifier.startsWith("/") 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /test/cases/combine-subpaths.js: -------------------------------------------------------------------------------- 1 | import { deepStrictEqual } from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | const map = { 5 | imports: { 6 | 'base/another/': '/another/', 7 | 'base/a.js': '/a.js', 8 | 'base/b.js': '/b.js', 9 | 'base/another/a.js': '/another/a.js', 10 | 'base/another/b.js': '/another/b.js', 11 | 'base/another/c': '/another/c.js', 12 | 'base/another/d': '/another/b.js', 13 | '/url/sub/': '/another/x/', 14 | '/url/sub/x.js': '/another/sub/x.js', 15 | '/url/sub/y.js': '/another/sub/y.js', 16 | '/url/z.js': '/another/z.js', 17 | 'only/mapping.js': './only/mapping.js' 18 | } 19 | }; 20 | 21 | { 22 | const importMap = new ImportMap({ map }); 23 | 24 | importMap.combineSubpaths(); 25 | 26 | deepStrictEqual(importMap.toJSON(), map); 27 | } 28 | 29 | { 30 | const importMap = new ImportMap({ map: { scopes: { '/': map.imports } } }); 31 | 32 | importMap.sort(); 33 | importMap.combineSubpaths(); 34 | 35 | deepStrictEqual(importMap.toJSON(), { 36 | scopes: { 37 | '/': { 38 | '/url/': '/another/', 39 | '/url/sub/': '/another/x/', 40 | 'base/': '/', 41 | 'base/another/c': '/another/c.js', 42 | 'base/another/d': '/another/b.js', 43 | 'only/mapping.js': './only/mapping.js' 44 | } 45 | } 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /test/cases/examples.js: -------------------------------------------------------------------------------- 1 | import { strictEqual, deepStrictEqual } from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | const mapBase = new URL('.', import.meta.url); 5 | 6 | const map = new ImportMap({ 7 | mapUrl: mapBase, 8 | map: { 9 | imports: { 10 | react: 'https://cdn.com/react.js' 11 | }, 12 | scopes: { 13 | 'https://site.com/': { 14 | react: 'https://cdn.com/react2.js' 15 | } 16 | } 17 | } 18 | }); 19 | 20 | strictEqual(map.resolve('react', mapBase), 'https://cdn.com/react.js'); 21 | strictEqual(map.resolve('react', 'https://site.com/'), 'https://cdn.com/react2.js'); 22 | 23 | strictEqual(map.resolve('./hello.js', 'https://site.com/'), 'https://site.com/hello.js'); 24 | 25 | map.set('react', './custom-react.js'); 26 | strictEqual(map.resolve('react'), new URL('./custom-react.js', mapBase).href); 27 | 28 | map.set('react', './custom-react2.js', 'https://another.com/'); 29 | strictEqual(map.resolve('react', 'https://another.com/'), new URL('./custom-react2.js', mapBase).href); 30 | 31 | deepStrictEqual(map.toJSON(), { 32 | "imports": { 33 | "react": "./custom-react.js" 34 | }, 35 | "scopes": { 36 | "https://site.com/": { 37 | "react": "https://cdn.com/react2.js" 38 | }, 39 | "https://another.com/": { 40 | "react": "./custom-react2.js" 41 | } 42 | } 43 | }); 44 | 45 | // Rebase the map 46 | map.rebase(new URL('./map/', mapBase)); 47 | 48 | deepStrictEqual(map.toJSON(), { 49 | "imports": { 50 | "react": "../custom-react.js" 51 | }, 52 | "scopes": { 53 | "https://site.com/": { 54 | "react": "https://cdn.com/react2.js" 55 | }, 56 | "https://another.com/": { 57 | "react": "../custom-react2.js" 58 | } 59 | } 60 | }); 61 | 62 | // Flatten the import map (removes unnecessary scope redundancy) 63 | map.set('react', '../custom-react.js', 'https://site.com/'); 64 | map.flatten(); 65 | deepStrictEqual(map.toJSON(), { 66 | "imports": { 67 | "react": "../custom-react.js" 68 | }, 69 | "scopes": { 70 | "https://another.com/": { 71 | "react": "../custom-react2.js" 72 | } 73 | } 74 | }); 75 | 76 | // Replace URLs in the map 77 | map.replace('https://cdn.com/', 'https://cdn-mirror.com/'); 78 | map.replace('https://another.com/', 'https://another-site.com/'); 79 | deepStrictEqual(map.toJSON(), { 80 | "imports": { 81 | "react": "../custom-react.js" 82 | }, 83 | "scopes": { 84 | "https://another-site.com/": { 85 | "react": "../custom-react2.js" 86 | } 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /test/cases/flattening-roots.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | { 5 | const map = new ImportMap({ 6 | mapUrl: new URL("file:///test/map/"), 7 | rootUrl: new URL("file:///test/"), 8 | map: { 9 | scopes: { 10 | '/': { 11 | 'react': 'https://ga.jspm.io/npm:react@18.2.0/index.js', 12 | } 13 | } 14 | } 15 | }); 16 | 17 | map.flatten(); 18 | assert(map.scopes && map.scopes["/"]); 19 | } 20 | 21 | { 22 | const map = new ImportMap({ 23 | mapUrl: new URL(import.meta.url), 24 | map: { 25 | imports: { 26 | '@patternfly/pfe-core': '/assets/packages/@patternfly/pfe-core/core.js', 27 | '@rhds/tokens': '/assets/packages/@rhds/tokens/js/tokens.js', 28 | '@lit/reactive-element': '/assets/packages/@lit/reactive-element/reactive-element.js', 29 | lit: '/assets/packages/lit/index.js', 30 | '@patternfly/elements/pf-tooltip/pf-tooltip.js': '/assets/packages/@patternfly/elements/pf-tooltip/pf-tooltip.js', 31 | '@patternfly/pfe-core/controllers/roving-tabindex-controller.js': '/assets/packages/@patternfly/pfe-core/controllers/roving-tabindex-controller.js' 32 | }, 33 | scopes: { 34 | '/assets/packages/@patternfly/elements/': { 35 | 'lit/directives/class-map.js': '/assets/packages/lit/directives/class-map.js', 36 | '@floating-ui/dom': '/assets/packages/@floating-ui/dom/dist/floating-ui.dom.browser.min.mjs', 37 | '@patternfly/pfe-core/controllers/floating-dom-controller.js': '/assets/packages/@patternfly/pfe-core/controllers/floating-dom-controller.js', 38 | }, 39 | '/assets/packages/lit/': { 40 | 'lit-element/lit-element.js': '/assets/packages/lit-element/lit-element.js', 41 | '@lit/reactive-element/decorators/state.js': '/assets/packages/@lit/reactive-element/decorators/state.js', 42 | }, 43 | } 44 | } 45 | }); 46 | map.flatten(); 47 | assert.deepStrictEqual( 48 | map.toJSON(), 49 | { 50 | imports: { 51 | '@patternfly/pfe-core': '/assets/packages/@patternfly/pfe-core/core.js', 52 | '@rhds/tokens': '/assets/packages/@rhds/tokens/js/tokens.js', 53 | '@lit/reactive-element': '/assets/packages/@lit/reactive-element/reactive-element.js', 54 | lit: '/assets/packages/lit/index.js', 55 | '@patternfly/elements/pf-tooltip/pf-tooltip.js': '/assets/packages/@patternfly/elements/pf-tooltip/pf-tooltip.js', 56 | '@patternfly/pfe-core/controllers/roving-tabindex-controller.js': '/assets/packages/@patternfly/pfe-core/controllers/roving-tabindex-controller.js' 57 | }, 58 | scopes: { 59 | '/assets/packages/': { 60 | 'lit/directives/class-map.js': '/assets/packages/lit/directives/class-map.js', 61 | '@floating-ui/dom': '/assets/packages/@floating-ui/dom/dist/floating-ui.dom.browser.min.mjs', 62 | '@patternfly/pfe-core/controllers/floating-dom-controller.js': '/assets/packages/@patternfly/pfe-core/controllers/floating-dom-controller.js', 63 | 'lit-element/lit-element.js': '/assets/packages/lit-element/lit-element.js', 64 | '@lit/reactive-element/decorators/state.js': '/assets/packages/@lit/reactive-element/decorators/state.js', 65 | }, 66 | } 67 | } 68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /test/cases/flattening.js: -------------------------------------------------------------------------------- 1 | import { ImportMap } from '@jspm/import-map'; 2 | import { deepStrictEqual } from 'assert'; 3 | 4 | { 5 | const map = new ImportMap({ 6 | mapUrl: new URL('.', import.meta.url), 7 | map: { 8 | scopes: { 9 | './packages/bio/bio-design-system/': { 10 | '@roundforest/react-feature-flags-context': './packages/commons/react-feature-flags-context/lib/src/react-feature-flags-context.js', 11 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 12 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 13 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js', 14 | '@roundforest/react-localization-commons': './packages/commons/react-localization-commons/lib/src/localization-commons.js', 15 | '@roundforest/react-ripple-effect': './packages/commons/react-ripple-effect/lib/src/ripple-effect.js', 16 | '@roundforest/react-full-screen-state': './packages/commons/react-full-screen-state/lib/src/react-full-screen-state.js', 17 | 'react-toastify': 'https://ga.jspm.io/npm:react-toastify@8.0.3/dist/index.js', 18 | '@tippyjs/react/headless': 'https://ga.jspm.io/npm:@tippyjs/react@4.2.6/headless/dist/dev.tippy-react-headless.umd.js', 19 | 'tippy.js/headless': 'https://ga.jspm.io/npm:tippy.js@6.3.3/headless/dist/dev.tippy-headless.cjs.js', 20 | '@roundforest/react-map-slots': './packages/commons/react-map-slots/src/map-slots.js', 21 | '@roundforest/react-tooltip': './packages/commons/react-tooltip/lib/src/tooltip.js', 22 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js', 23 | 'react-copy-to-clipboard': 'https://ga.jspm.io/npm:react-copy-to-clipboard@5.0.4/lib/index.js' 24 | }, 25 | './packages/bio/bio-home-page/': { 26 | '@roundforest/react-localization-commons': './packages/commons/react-localization-commons/lib/src/localization-commons.js', 27 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 28 | '@roundforest/bio-design-system': './packages/bio/bio-design-system/lib/exports.js', 29 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js', 30 | '@roundforest/bio-product-category-search': './packages/bio/bio-product-category-search/lib/src/exports.js', 31 | '@roundforest/react-environment-context': './packages/commons/react-environment-context/lib/src/react-environment-context.js', 32 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 33 | 'react-helmet': 'https://ga.jspm.io/npm:react-helmet@6.1.0/lib/dev.Helmet.js', 34 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js', 35 | '@roundforest/bio-home-page': './packages/bio/bio-home-page/lib/src/bio-home-page.js' 36 | }, 37 | './packages/bio/bio-product-category-search/': { 38 | '@roundforest/react-localization-commons': './packages/commons/react-localization-commons/lib/src/localization-commons.js', 39 | '@roundforest/react-environment-context': './packages/commons/react-environment-context/lib/src/react-environment-context.js', 40 | 'react-query': 'https://ga.jspm.io/npm:react-query@3.31.0/lib/dev.index.js', 41 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 42 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 43 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js', 44 | '@roundforest/bio-design-system': './packages/bio/bio-design-system/lib/exports.js', 45 | '@roundforest/react-full-screen-state': './packages/commons/react-full-screen-state/lib/src/react-full-screen-state.js' 46 | }, 47 | './packages/commons/emotion-styled/': { 48 | '@roundforest/frontend-commons': './packages/commons/frontend-commons/lib/src/frontend-commons.js', 49 | '@emotion/styled': 'https://ga.jspm.io/npm:@emotion/styled@11.3.0/dist/dev.emotion-styled.browser.cjs.js' 50 | }, 51 | './packages/commons/react-environment-context/': { react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js' }, 52 | './packages/commons/react-feature-flags-context/': { react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js' }, 53 | './packages/commons/react-full-screen-state/': { react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js' }, 54 | './packages/commons/react-localization-commons/': { react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js' }, 55 | './packages/commons/react-map-slots/': { 56 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 57 | 'react-is': 'https://ga.jspm.io/npm:react-is@17.0.2/dev.index.js' 58 | }, 59 | './packages/commons/react-portal/': { 60 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 61 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js' 62 | }, 63 | './packages/commons/react-ripple-effect/': { 64 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 65 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 66 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js' 67 | }, 68 | './packages/commons/react-tooltip/': { 69 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 70 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js', 71 | '@roundforest/react-portal': './packages/commons/react-portal/lib/src/portal.js' 72 | }, 73 | 'https://ga.jspm.io/npm:react-dom@16.14.0/': { react: 'https://ga.jspm.io/npm:react@16.14.0/dev.index.js' }, 74 | 'https://ga.jspm.io/npm:react-dom@17.0.2/': { 75 | 'scheduler/tracing': 'https://ga.jspm.io/npm:scheduler@0.20.2/dev.tracing.js', 76 | scheduler: 'https://ga.jspm.io/npm:scheduler@0.20.2/dev.index.js' 77 | }, 78 | 'https://ga.jspm.io/npm:react-query@3.31.0/': { 79 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@16.14.0/dev.index.js' 80 | }, 81 | 'https://ga.jspm.io/': { 82 | '@babel/runtime/helpers/extends': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/extends.js', 83 | '@babel/runtime/helpers/inheritsLoose': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/inheritsLoose.js', 84 | '@babel/runtime/helpers/interopRequireDefault': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/interopRequireDefault.js', 85 | '@emotion/cache': 'https://ga.jspm.io/npm:@emotion/cache@11.5.0/dist/dev.emotion-cache.browser.cjs.js', 86 | '@emotion/hash': 'https://ga.jspm.io/npm:@emotion/hash@0.8.0/dist/hash.browser.cjs.js', 87 | '@emotion/is-prop-valid': 'https://ga.jspm.io/npm:@emotion/is-prop-valid@1.1.0/dist/emotion-is-prop-valid.browser.cjs.js', 88 | '@emotion/memoize': 'https://ga.jspm.io/npm:@emotion/memoize@0.7.5/dist/emotion-memoize.browser.cjs.js', 89 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 90 | '@emotion/serialize': 'https://ga.jspm.io/npm:@emotion/serialize@1.0.2/dist/dev.emotion-serialize.browser.cjs.js', 91 | '@emotion/sheet': 'https://ga.jspm.io/npm:@emotion/sheet@1.0.3/dist/dev.emotion-sheet.browser.cjs.js', 92 | '@emotion/unitless': 'https://ga.jspm.io/npm:@emotion/unitless@0.7.5/dist/unitless.browser.cjs.js', 93 | '@emotion/utils': 'https://ga.jspm.io/npm:@emotion/utils@1.0.0/dist/emotion-utils.browser.cjs.js', 94 | '@emotion/weak-memoize': 'https://ga.jspm.io/npm:@emotion/weak-memoize@0.2.5/dist/weak-memoize.browser.cjs.js', 95 | '@popperjs/core': 'https://ga.jspm.io/npm:@popperjs/core@2.10.2/dist/cjs/dev.popper.js', clsx: 'https://ga.jspm.io/npm:clsx@1.1.1/dist/clsx.js', 96 | 'copy-to-clipboard': 'https://ga.jspm.io/npm:copy-to-clipboard@3.3.1/index.js', 97 | 'hoist-non-react-statics': 'https://ga.jspm.io/npm:hoist-non-react-statics@3.3.2/dist/hoist-non-react-statics.cjs.js', 98 | 'object-assign': 'https://ga.jspm.io/npm:object-assign@4.1.1/index.js', 99 | 'prop-types': 'https://ga.jspm.io/npm:prop-types@15.7.2/dev.index.js', 100 | 'prop-types/checkPropTypes': 'https://ga.jspm.io/npm:prop-types@15.7.2/dev.checkPropTypes.js', 101 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 102 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js', 103 | 'react-fast-compare': 'https://ga.jspm.io/npm:react-fast-compare@3.2.0/index.js', 104 | 'react-is': 'https://ga.jspm.io/npm:react-is@16.13.1/dev.index.js', 105 | 'react-side-effect': 'https://ga.jspm.io/npm:react-side-effect@2.1.1/lib/index.js', 106 | scheduler: 'https://ga.jspm.io/npm:scheduler@0.19.1/dev.index.js', 107 | 'scheduler/tracing': 'https://ga.jspm.io/npm:scheduler@0.19.1/dev.tracing.js', 108 | stylis: 'https://ga.jspm.io/npm:stylis@4.0.10/dist/umd/stylis.js', 109 | 'tippy.js/headless': 'https://ga.jspm.io/npm:tippy.js@6.3.3/headless/dist/dev.tippy-headless.cjs.js', 110 | 'toggle-selection': 'https://ga.jspm.io/npm:toggle-selection@1.0.6/index.js' 111 | } 112 | } 113 | } 114 | }); 115 | map.flatten(); 116 | deepStrictEqual(map.toJSON(), { 117 | scopes: { 118 | 'https://ga.jspm.io/npm:react-dom@16.14.0/': { react: 'https://ga.jspm.io/npm:react@16.14.0/dev.index.js' }, 119 | 'https://ga.jspm.io/npm:react-dom@17.0.2/': { 120 | 'scheduler/tracing': 'https://ga.jspm.io/npm:scheduler@0.20.2/dev.tracing.js', 121 | scheduler: 'https://ga.jspm.io/npm:scheduler@0.20.2/dev.index.js' 122 | }, 123 | 'https://ga.jspm.io/npm:react-query@3.31.0/': { 124 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@16.14.0/dev.index.js' 125 | }, 126 | 'https://ga.jspm.io/': { 127 | '@babel/runtime/helpers/extends': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/extends.js', 128 | '@babel/runtime/helpers/inheritsLoose': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/inheritsLoose.js', 129 | '@babel/runtime/helpers/interopRequireDefault': 'https://ga.jspm.io/npm:@babel/runtime@7.16.0/helpers/interopRequireDefault.js', 130 | '@emotion/cache': 'https://ga.jspm.io/npm:@emotion/cache@11.5.0/dist/dev.emotion-cache.browser.cjs.js', 131 | '@emotion/hash': 'https://ga.jspm.io/npm:@emotion/hash@0.8.0/dist/hash.browser.cjs.js', 132 | '@emotion/is-prop-valid': 'https://ga.jspm.io/npm:@emotion/is-prop-valid@1.1.0/dist/emotion-is-prop-valid.browser.cjs.js', 133 | '@emotion/memoize': 'https://ga.jspm.io/npm:@emotion/memoize@0.7.5/dist/emotion-memoize.browser.cjs.js', 134 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 135 | '@emotion/serialize': 'https://ga.jspm.io/npm:@emotion/serialize@1.0.2/dist/dev.emotion-serialize.browser.cjs.js', 136 | '@emotion/sheet': 'https://ga.jspm.io/npm:@emotion/sheet@1.0.3/dist/dev.emotion-sheet.browser.cjs.js', '@emotion/unitless': 'https://ga.jspm.io/npm:@emotion/unitless@0.7.5/dist/unitless.browser.cjs.js', 137 | '@emotion/utils': 'https://ga.jspm.io/npm:@emotion/utils@1.0.0/dist/emotion-utils.browser.cjs.js', 138 | '@emotion/weak-memoize': 'https://ga.jspm.io/npm:@emotion/weak-memoize@0.2.5/dist/weak-memoize.browser.cjs.js', 139 | '@popperjs/core': 'https://ga.jspm.io/npm:@popperjs/core@2.10.2/dist/cjs/dev.popper.js', 140 | clsx: 'https://ga.jspm.io/npm:clsx@1.1.1/dist/clsx.js', 141 | 'copy-to-clipboard': 'https://ga.jspm.io/npm:copy-to-clipboard@3.3.1/index.js', 142 | 'hoist-non-react-statics': 'https://ga.jspm.io/npm:hoist-non-react-statics@3.3.2/dist/hoist-non-react-statics.cjs.js', 143 | 'object-assign': 'https://ga.jspm.io/npm:object-assign@4.1.1/index.js', 144 | 'prop-types': 'https://ga.jspm.io/npm:prop-types@15.7.2/dev.index.js', 145 | 'prop-types/checkPropTypes': 'https://ga.jspm.io/npm:prop-types@15.7.2/dev.checkPropTypes.js', 146 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 147 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js', 148 | 'react-fast-compare': 'https://ga.jspm.io/npm:react-fast-compare@3.2.0/index.js', 149 | 'react-is': 'https://ga.jspm.io/npm:react-is@16.13.1/dev.index.js', 150 | 'react-side-effect': 'https://ga.jspm.io/npm:react-side-effect@2.1.1/lib/index.js', 151 | scheduler: 'https://ga.jspm.io/npm:scheduler@0.19.1/dev.index.js', 152 | 'scheduler/tracing': 'https://ga.jspm.io/npm:scheduler@0.19.1/dev.tracing.js', 153 | stylis: 'https://ga.jspm.io/npm:stylis@4.0.10/dist/umd/stylis.js', 154 | 'tippy.js/headless': 'https://ga.jspm.io/npm:tippy.js@6.3.3/headless/dist/dev.tippy-headless.cjs.js', 155 | 'toggle-selection': 'https://ga.jspm.io/npm:toggle-selection@1.0.6/index.js' 156 | }, 157 | './packages/': { 158 | '@emotion/react': 'https://ga.jspm.io/npm:@emotion/react@11.5.0/dist/dev.emotion-react.browser.cjs.js', 159 | '@emotion/styled': 'https://ga.jspm.io/npm:@emotion/styled@11.3.0/dist/dev.emotion-styled.browser.cjs.js', 160 | '@roundforest/bio-design-system': './packages/bio/bio-design-system/lib/exports.js', 161 | '@roundforest/bio-home-page': './packages/bio/bio-home-page/lib/src/bio-home-page.js', 162 | '@roundforest/bio-product-category-search': './packages/bio/bio-product-category-search/lib/src/exports.js', 163 | '@roundforest/emotion-styled': './packages/commons/emotion-styled/src/emotion-styled.js', 164 | '@roundforest/frontend-commons': './packages/commons/frontend-commons/lib/src/frontend-commons.js', 165 | '@roundforest/react-environment-context': './packages/commons/react-environment-context/lib/src/react-environment-context.js', 166 | '@roundforest/react-feature-flags-context': './packages/commons/react-feature-flags-context/lib/src/react-feature-flags-context.js', 167 | '@roundforest/react-full-screen-state': './packages/commons/react-full-screen-state/lib/src/react-full-screen-state.js', 168 | '@roundforest/react-localization-commons': './packages/commons/react-localization-commons/lib/src/localization-commons.js', 169 | '@roundforest/react-map-slots': './packages/commons/react-map-slots/src/map-slots.js', 170 | '@roundforest/react-portal': './packages/commons/react-portal/lib/src/portal.js', 171 | '@roundforest/react-ripple-effect': './packages/commons/react-ripple-effect/lib/src/ripple-effect.js', 172 | '@roundforest/react-tooltip': './packages/commons/react-tooltip/lib/src/tooltip.js', 173 | '@tippyjs/react/headless': 'https://ga.jspm.io/npm:@tippyjs/react@4.2.6/headless/dist/dev.tippy-react-headless.umd.js', 174 | react: 'https://ga.jspm.io/npm:react@17.0.2/dev.index.js', 175 | 'react-copy-to-clipboard': 'https://ga.jspm.io/npm:react-copy-to-clipboard@5.0.4/lib/index.js', 176 | 'react-dom': 'https://ga.jspm.io/npm:react-dom@17.0.2/dev.index.js', 177 | 'react-helmet': 'https://ga.jspm.io/npm:react-helmet@6.1.0/lib/dev.Helmet.js', 178 | 'react-is': 'https://ga.jspm.io/npm:react-is@17.0.2/dev.index.js', 179 | 'react-query': 'https://ga.jspm.io/npm:react-query@3.31.0/lib/dev.index.js', 180 | 'react-toastify': 'https://ga.jspm.io/npm:react-toastify@8.0.3/dist/index.js', 181 | 'tippy.js/headless': 'https://ga.jspm.io/npm:tippy.js@6.3.3/headless/dist/dev.tippy-headless.cjs.js' 182 | } 183 | } 184 | }); 185 | } 186 | 187 | { 188 | const map = new ImportMap({ 189 | mapUrl: new URL('.', import.meta.url), 190 | map: { 191 | imports: { '@jspm/generator': '../../dist/generator.js' }, 192 | scopes: { 193 | '../../': { 194 | url: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/url.js', 195 | fs: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/fs.js', 196 | '@babel/preset-typescript': 'https://ga.jspm.io/npm:@babel/preset-typescript@7.16.0/lib/index.js', 197 | '@babel/core': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/dev.index.js', 198 | '#fetch': '../../dist/fetch-native.js', 199 | 'es-module-lexer': 'https://ga.jspm.io/npm:es-module-lexer@0.9.3/dist/lexer.js', 200 | sver: 'https://ga.jspm.io/npm:sver@1.8.3/sver.js', 201 | '@jspm/import-map': 'https://ga.jspm.io/npm:@jspm/import-map@0.1.5/dist/map.js', 202 | 'sver/convert-range.js': 'https://ga.jspm.io/npm:sver@1.8.3/convert-range.js' 203 | }, 204 | 'https://ga.jspm.io/npm:@babel/code-frame@7.16.0/': { 205 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 206 | '@babel/highlight': 'https://ga.jspm.io/npm:@babel/highlight@7.16.0/lib/index.js' 207 | }, 208 | 'https://ga.jspm.io/npm:@babel/core@7.16.0/': { 209 | '@babel/helper-compilation-targets': 'https://ga.jspm.io/npm:@babel/helper-compilation-targets@7.16.0/lib/index.js', 210 | semver: 'https://ga.jspm.io/npm:semver@6.3.0/semver.js', 211 | '@babel/helpers': 'https://ga.jspm.io/npm:@babel/helpers@7.16.0/lib/index.js', 212 | '@babel/helper-module-transforms': 'https://ga.jspm.io/npm:@babel/helper-module-transforms@7.16.0/lib/index.js', 213 | '@babel/generator': 'https://ga.jspm.io/npm:@babel/generator@7.16.0/lib/index.js', 214 | '@babel/template': 'https://ga.jspm.io/npm:@babel/template@7.16.0/lib/index.js', 215 | '@babel/code-frame': 'https://ga.jspm.io/npm:@babel/code-frame@7.16.0/lib/index.js', 216 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 217 | '@babel/traverse': 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/lib/index.js', 218 | gensync: 'https://ga.jspm.io/npm:gensync@1.0.0-beta.2/index.js', 219 | '#lib/config/files/index.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/config/files/index-browser.js', 220 | '#lib/config/resolve-targets.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/config/resolve-targets-browser.js', 221 | '#lib/transformation/util/clone-deep.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/transformation/util/clone-deep-browser.js', 222 | '#lib/transform-file.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/transform-file-browser.js', 223 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 224 | path: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/path.js', 225 | fs: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/fs.js', 226 | debug: 'https://ga.jspm.io/npm:debug@4.3.2/src/browser.js', 227 | 'convert-source-map': 'https://ga.jspm.io/npm:convert-source-map@1.8.0/index.js', 228 | 'source-map': 'https://ga.jspm.io/npm:source-map@0.5.7/source-map.js', 229 | '@babel/parser': 'https://ga.jspm.io/npm:@babel/parser@7.16.2/lib/index.js' 230 | }, 231 | 'https://ga.jspm.io/npm:@babel/generator@7.16.0/': { 232 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 233 | jsesc: 'https://ga.jspm.io/npm:jsesc@2.5.2/jsesc.js', 234 | 'source-map': 'https://ga.jspm.io/npm:source-map@0.5.7/source-map.js' 235 | }, 236 | 'https://ga.jspm.io/npm:@babel/helper-annotate-as-pure@7.16.0/': { 237 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 238 | }, 239 | 'https://ga.jspm.io/npm:@babel/helper-compilation-targets@7.16.0/': { 240 | '@babel/helper-validator-option': 'https://ga.jspm.io/npm:@babel/helper-validator-option@7.14.5/lib/index.js', 241 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 242 | semver: 'https://ga.jspm.io/npm:semver@6.3.0/semver.js', 243 | '@babel/compat-data/native-modules': 'https://ga.jspm.io/npm:@babel/compat-data@7.16.0/native-modules.js', 244 | '@babel/compat-data/plugins': 'https://ga.jspm.io/npm:@babel/compat-data@7.16.0/plugins.js', 245 | browserslist: 'https://ga.jspm.io/npm:browserslist@4.17.4/index.js' 246 | }, 247 | 'https://ga.jspm.io/npm:@babel/helper-create-class-features-plugin@7.16.0/': { 248 | '@babel/helper-function-name': 'https://ga.jspm.io/npm:@babel/helper-function-name@7.16.0/lib/index.js', '@babel/helper-split-export-declaration': 'https://ga.jspm.io/npm:@babel/helper-split-export-declaration@7.16.0/lib/index.js', 249 | '@babel/core': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/dev.index.js', 250 | '@babel/helper-replace-supers': 'https://ga.jspm.io/npm:@babel/helper-replace-supers@7.16.0/lib/index.js', 251 | '@babel/helper-member-expression-to-functions': 'https://ga.jspm.io/npm:@babel/helper-member-expression-to-functions@7.16.0/lib/index.js', 252 | '@babel/helper-optimise-call-expression': 'https://ga.jspm.io/npm:@babel/helper-optimise-call-expression@7.16.0/lib/index.js', 253 | '@babel/helper-annotate-as-pure': 'https://ga.jspm.io/npm:@babel/helper-annotate-as-pure@7.16.0/lib/index.js' 254 | }, 255 | 'https://ga.jspm.io/npm:@babel/helper-function-name@7.16.0/': { 256 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 257 | '@babel/template': 'https://ga.jspm.io/npm:@babel/template@7.16.0/lib/index.js', 258 | '@babel/helper-get-function-arity': 'https://ga.jspm.io/npm:@babel/helper-get-function-arity@7.16.0/lib/index.js' 259 | }, 260 | 'https://ga.jspm.io/npm:@babel/helper-get-function-arity@7.16.0/': { 261 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 262 | }, 263 | 'https://ga.jspm.io/npm:@babel/helper-hoist-variables@7.16.0/': { 264 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 265 | }, 266 | 'https://ga.jspm.io/npm:@babel/helper-member-expression-to-functions@7.16.0/': { 267 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 268 | }, 269 | 'https://ga.jspm.io/npm:@babel/helper-module-imports@7.16.0/': { 270 | assert: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/assert.js', 271 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 272 | }, 273 | 'https://ga.jspm.io/npm:@babel/helper-module-transforms@7.16.0/': { 274 | path: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/path.js', 275 | '@babel/helper-validator-identifier': 'https://ga.jspm.io/npm:@babel/helper-validator-identifier@7.15.7/lib/index.js', 276 | '@babel/helper-split-export-declaration': 'https://ga.jspm.io/npm:@babel/helper-split-export-declaration@7.16.0/lib/index.js', 277 | assert: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/assert.js', 278 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 279 | '@babel/template': 'https://ga.jspm.io/npm:@babel/template@7.16.0/lib/index.js', 280 | '@babel/traverse': 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/lib/index.js', 281 | '@babel/helper-simple-access': 'https://ga.jspm.io/npm:@babel/helper-simple-access@7.16.0/lib/index.js', '@babel/helper-module-imports': 'https://ga.jspm.io/npm:@babel/helper-module-imports@7.16.0/lib/index.js', 282 | '@babel/helper-replace-supers': 'https://ga.jspm.io/npm:@babel/helper-replace-supers@7.16.0/lib/index.js' 283 | }, 284 | 'https://ga.jspm.io/npm:@babel/helper-optimise-call-expression@7.16.0/': { 285 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 286 | }, 287 | 'https://ga.jspm.io/npm:@babel/helper-replace-supers@7.16.0/': { 288 | '@babel/traverse': 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/lib/index.js', 289 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 290 | '@babel/helper-optimise-call-expression': 'https://ga.jspm.io/npm:@babel/helper-optimise-call-expression@7.16.0/lib/index.js', 291 | '@babel/helper-member-expression-to-functions': 'https://ga.jspm.io/npm:@babel/helper-member-expression-to-functions@7.16.0/lib/index.js' 292 | }, 293 | 'https://ga.jspm.io/npm:@babel/helper-simple-access@7.16.0/': { 294 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 295 | }, 296 | 'https://ga.jspm.io/npm:@babel/helper-split-export-declaration@7.16.0/': { 297 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 298 | }, 299 | 'https://ga.jspm.io/npm:@babel/helpers@7.16.0/': { 300 | '@babel/template': 'https://ga.jspm.io/npm:@babel/template@7.16.0/lib/index.js', 301 | '@babel/traverse': 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/lib/index.js', 302 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js' 303 | }, 304 | 'https://ga.jspm.io/npm:@babel/highlight@7.16.0/': { 305 | '@babel/helper-validator-identifier': 'https://ga.jspm.io/npm:@babel/helper-validator-identifier@7.15.7/lib/index.js', 306 | 'js-tokens': 'https://ga.jspm.io/npm:js-tokens@4.0.0/index.js', 307 | chalk: 'https://ga.jspm.io/npm:chalk@2.4.2/index.js' 308 | }, 309 | 'https://ga.jspm.io/npm:@babel/plugin-syntax-typescript@7.16.0/': { 310 | '@babel/helper-plugin-utils': 'https://ga.jspm.io/npm:@babel/helper-plugin-utils@7.14.5/lib/index.js' 311 | }, 312 | 'https://ga.jspm.io/npm:@babel/plugin-transform-typescript@7.16.0/': { 313 | '@babel/helper-plugin-utils': 'https://ga.jspm.io/npm:@babel/helper-plugin-utils@7.14.5/lib/index.js', 314 | assert: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/assert.js', 315 | '@babel/core': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/dev.index.js', 316 | '@babel/plugin-syntax-typescript': 'https://ga.jspm.io/npm:@babel/plugin-syntax-typescript@7.16.0/lib/index.js', 317 | '@babel/helper-create-class-features-plugin': 'https://ga.jspm.io/npm:@babel/helper-create-class-features-plugin@7.16.0/lib/index.js' 318 | }, 319 | 'https://ga.jspm.io/npm:@babel/preset-typescript@7.16.0/': { 320 | '@babel/helper-plugin-utils': 'https://ga.jspm.io/npm:@babel/helper-plugin-utils@7.14.5/lib/index.js', 321 | '@babel/helper-validator-option': 'https://ga.jspm.io/npm:@babel/helper-validator-option@7.14.5/lib/index.js', 322 | '@babel/plugin-transform-typescript': 'https://ga.jspm.io/npm:@babel/plugin-transform-typescript@7.16.0/lib/index.js' 323 | }, 324 | 'https://ga.jspm.io/npm:@babel/template@7.16.0/': { 325 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 326 | '@babel/parser': 'https://ga.jspm.io/npm:@babel/parser@7.16.2/lib/index.js', 327 | '@babel/code-frame': 'https://ga.jspm.io/npm:@babel/code-frame@7.16.0/lib/index.js' 328 | }, 329 | 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/': { 330 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 331 | debug: 'https://ga.jspm.io/npm:debug@4.3.2/src/browser.js', 332 | '@babel/code-frame': 'https://ga.jspm.io/npm:@babel/code-frame@7.16.0/lib/index.js', 333 | '@babel/generator': 'https://ga.jspm.io/npm:@babel/generator@7.16.0/lib/index.js', 334 | '@babel/parser': 'https://ga.jspm.io/npm:@babel/parser@7.16.2/lib/index.js', 335 | '@babel/helper-split-export-declaration': 'https://ga.jspm.io/npm:@babel/helper-split-export-declaration@7.16.0/lib/index.js', 336 | globals: 'https://ga.jspm.io/npm:globals@11.12.0/index.js', 337 | '@babel/helper-hoist-variables': 'https://ga.jspm.io/npm:@babel/helper-hoist-variables@7.16.0/lib/index.js', 338 | '@babel/helper-function-name': 'https://ga.jspm.io/npm:@babel/helper-function-name@7.16.0/lib/index.js' 339 | }, 340 | 'https://ga.jspm.io/npm:@babel/types@7.16.0/': { 341 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 342 | '@babel/helper-validator-identifier': 'https://ga.jspm.io/npm:@babel/helper-validator-identifier@7.15.7/lib/index.js', 343 | 'to-fast-properties': 'https://ga.jspm.io/npm:to-fast-properties@2.0.0/index.js' 344 | }, 345 | 'https://ga.jspm.io/npm:ansi-styles@3.2.1/': { 346 | 'color-convert': 'https://ga.jspm.io/npm:color-convert@1.9.3/index.js' 347 | }, 348 | 'https://ga.jspm.io/npm:browserslist@4.17.4/': { 349 | path: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/path.js', 350 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 351 | '#node.js': 'https://ga.jspm.io/npm:browserslist@4.17.4/browser.js', 352 | 'node-releases/data/processed/envs.json': 'https://ga.jspm.io/npm:node-releases@2.0.1/data/processed/envs.json.js', 353 | 'node-releases/data/release-schedule/release-schedule.json': 'https://ga.jspm.io/npm:node-releases@2.0.1/data/release-schedule/release-schedule.json.js', 354 | 'electron-to-chromium/versions': 'https://ga.jspm.io/npm:electron-to-chromium@1.3.886/versions.js', 355 | 'caniuse-lite/dist/unpacker/agents': 'https://ga.jspm.io/npm:caniuse-lite@1.0.30001274/dist/unpacker/agents.js' 356 | }, 357 | 'https://ga.jspm.io/npm:chalk@2.4.2/': { 358 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 359 | 'escape-string-regexp': 'https://ga.jspm.io/npm:escape-string-regexp@1.0.5/index.js', 360 | 'supports-color': 'https://ga.jspm.io/npm:supports-color@5.5.0/browser.js', 361 | 'ansi-styles': 'https://ga.jspm.io/npm:ansi-styles@3.2.1/index.js' 362 | }, 363 | 'https://ga.jspm.io/npm:color-convert@1.9.3/': { 364 | 'color-name': 'https://ga.jspm.io/npm:color-name@1.1.3/index.js' 365 | }, 366 | 'https://ga.jspm.io/npm:convert-source-map@1.8.0/': { 367 | fs: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/fs.js', 368 | path: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/path.js', 369 | 'safe-buffer': 'https://ga.jspm.io/npm:safe-buffer@5.1.2/index.js' 370 | }, 371 | 'https://ga.jspm.io/npm:debug@4.3.2/': { 372 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 373 | ms: 'https://ga.jspm.io/npm:ms@2.1.2/index.js' 374 | }, 375 | 'https://ga.jspm.io/npm:jsesc@2.5.2/': { 376 | buffer: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/buffer.js' 377 | }, 378 | 'https://ga.jspm.io/npm:safe-buffer@5.1.2/': { 379 | buffer: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/buffer.js' 380 | }, 381 | 'https://ga.jspm.io/npm:semver@6.3.0/': { 382 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js' 383 | }, 384 | 'https://ga.jspm.io/npm:sver@1.8.3/': { semver: 'https://ga.jspm.io/npm:semver@6.3.0/semver.js' } 385 | } 386 | } 387 | }); 388 | map.flatten(); 389 | deepStrictEqual(map.toJSON(), { 390 | imports: { '@jspm/generator': '../../dist/generator.js' }, 391 | scopes: { 392 | '../../': { 393 | '#fetch': '../../dist/fetch-native.js', 394 | '@babel/core': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/dev.index.js', 395 | '@babel/preset-typescript': 'https://ga.jspm.io/npm:@babel/preset-typescript@7.16.0/lib/index.js', 396 | '@jspm/import-map': 'https://ga.jspm.io/npm:@jspm/import-map@0.1.5/dist/map.js', 397 | 'es-module-lexer': 'https://ga.jspm.io/npm:es-module-lexer@0.9.3/dist/lexer.js', 398 | fs: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/fs.js', 399 | sver: 'https://ga.jspm.io/npm:sver@1.8.3/sver.js', 400 | 'sver/convert-range.js': 'https://ga.jspm.io/npm:sver@1.8.3/convert-range.js', 401 | url: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/url.js' 402 | }, 403 | 'https://ga.jspm.io/': { 404 | '#lib/config/files/index.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/config/files/index-browser.js', 405 | '#lib/config/resolve-targets.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/config/resolve-targets-browser.js', 406 | '#lib/transform-file.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/transform-file-browser.js', 407 | '#lib/transformation/util/clone-deep.js': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/transformation/util/clone-deep-browser.js', 408 | '#node.js': 'https://ga.jspm.io/npm:browserslist@4.17.4/browser.js', 409 | '@babel/code-frame': 'https://ga.jspm.io/npm:@babel/code-frame@7.16.0/lib/index.js', 410 | '@babel/compat-data/native-modules': 'https://ga.jspm.io/npm:@babel/compat-data@7.16.0/native-modules.js', 411 | '@babel/compat-data/plugins': 'https://ga.jspm.io/npm:@babel/compat-data@7.16.0/plugins.js', 412 | '@babel/core': 'https://ga.jspm.io/npm:@babel/core@7.16.0/lib/dev.index.js', 413 | '@babel/generator': 'https://ga.jspm.io/npm:@babel/generator@7.16.0/lib/index.js', 414 | '@babel/helper-annotate-as-pure': 'https://ga.jspm.io/npm:@babel/helper-annotate-as-pure@7.16.0/lib/index.js', 415 | '@babel/helper-compilation-targets': 'https://ga.jspm.io/npm:@babel/helper-compilation-targets@7.16.0/lib/index.js', 416 | '@babel/helper-create-class-features-plugin': 'https://ga.jspm.io/npm:@babel/helper-create-class-features-plugin@7.16.0/lib/index.js', 417 | '@babel/helper-function-name': 'https://ga.jspm.io/npm:@babel/helper-function-name@7.16.0/lib/index.js', '@babel/helper-get-function-arity': 'https://ga.jspm.io/npm:@babel/helper-get-function-arity@7.16.0/lib/index.js', 418 | '@babel/helper-hoist-variables': 'https://ga.jspm.io/npm:@babel/helper-hoist-variables@7.16.0/lib/index.js', 419 | '@babel/helper-member-expression-to-functions': 'https://ga.jspm.io/npm:@babel/helper-member-expression-to-functions@7.16.0/lib/index.js', 420 | '@babel/helper-module-imports': 'https://ga.jspm.io/npm:@babel/helper-module-imports@7.16.0/lib/index.js', 421 | '@babel/helper-module-transforms': 'https://ga.jspm.io/npm:@babel/helper-module-transforms@7.16.0/lib/index.js', 422 | '@babel/helper-optimise-call-expression': 'https://ga.jspm.io/npm:@babel/helper-optimise-call-expression@7.16.0/lib/index.js', 423 | '@babel/helper-plugin-utils': 'https://ga.jspm.io/npm:@babel/helper-plugin-utils@7.14.5/lib/index.js', 424 | '@babel/helper-replace-supers': 'https://ga.jspm.io/npm:@babel/helper-replace-supers@7.16.0/lib/index.js', 425 | '@babel/helper-simple-access': 'https://ga.jspm.io/npm:@babel/helper-simple-access@7.16.0/lib/index.js', 426 | '@babel/helper-split-export-declaration': 'https://ga.jspm.io/npm:@babel/helper-split-export-declaration@7.16.0/lib/index.js', 427 | '@babel/helper-validator-identifier': 'https://ga.jspm.io/npm:@babel/helper-validator-identifier@7.15.7/lib/index.js', 428 | '@babel/helper-validator-option': 'https://ga.jspm.io/npm:@babel/helper-validator-option@7.14.5/lib/index.js', 429 | '@babel/helpers': 'https://ga.jspm.io/npm:@babel/helpers@7.16.0/lib/index.js', 430 | '@babel/highlight': 'https://ga.jspm.io/npm:@babel/highlight@7.16.0/lib/index.js', 431 | '@babel/parser': 'https://ga.jspm.io/npm:@babel/parser@7.16.2/lib/index.js', 432 | '@babel/plugin-syntax-typescript': 'https://ga.jspm.io/npm:@babel/plugin-syntax-typescript@7.16.0/lib/index.js', 433 | '@babel/plugin-transform-typescript': 'https://ga.jspm.io/npm:@babel/plugin-transform-typescript@7.16.0/lib/index.js', 434 | '@babel/template': 'https://ga.jspm.io/npm:@babel/template@7.16.0/lib/index.js', 435 | '@babel/traverse': 'https://ga.jspm.io/npm:@babel/traverse@7.16.0/lib/index.js', 436 | '@babel/types': 'https://ga.jspm.io/npm:@babel/types@7.16.0/lib/index.js', 437 | 'ansi-styles': 'https://ga.jspm.io/npm:ansi-styles@3.2.1/index.js', 438 | assert: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/assert.js', 439 | browserslist: 'https://ga.jspm.io/npm:browserslist@4.17.4/index.js', 440 | buffer: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/buffer.js', 441 | 'caniuse-lite/dist/unpacker/agents': 'https://ga.jspm.io/npm:caniuse-lite@1.0.30001274/dist/unpacker/agents.js', 442 | chalk: 'https://ga.jspm.io/npm:chalk@2.4.2/index.js', 443 | 'color-convert': 'https://ga.jspm.io/npm:color-convert@1.9.3/index.js', 444 | 'color-name': 'https://ga.jspm.io/npm:color-name@1.1.3/index.js', 445 | 'convert-source-map': 'https://ga.jspm.io/npm:convert-source-map@1.8.0/index.js', 446 | debug: 'https://ga.jspm.io/npm:debug@4.3.2/src/browser.js', 447 | 'electron-to-chromium/versions': 'https://ga.jspm.io/npm:electron-to-chromium@1.3.886/versions.js', 448 | 'escape-string-regexp': 'https://ga.jspm.io/npm:escape-string-regexp@1.0.5/index.js', 449 | fs: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/fs.js', 450 | gensync: 'https://ga.jspm.io/npm:gensync@1.0.0-beta.2/index.js', 451 | globals: 'https://ga.jspm.io/npm:globals@11.12.0/index.js', 452 | 'js-tokens': 'https://ga.jspm.io/npm:js-tokens@4.0.0/index.js', 453 | jsesc: 'https://ga.jspm.io/npm:jsesc@2.5.2/jsesc.js', 454 | ms: 'https://ga.jspm.io/npm:ms@2.1.2/index.js', 455 | 'node-releases/data/processed/envs.json': 'https://ga.jspm.io/npm:node-releases@2.0.1/data/processed/envs.json.js', 456 | 'node-releases/data/release-schedule/release-schedule.json': 'https://ga.jspm.io/npm:node-releases@2.0.1/data/release-schedule/release-schedule.json.js', 457 | path: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/path.js', 458 | process: 'https://ga.jspm.io/npm:@jspm/core@2.0.0-beta.12/nodelibs/browser/process.js', 459 | 'safe-buffer': 'https://ga.jspm.io/npm:safe-buffer@5.1.2/index.js', 460 | semver: 'https://ga.jspm.io/npm:semver@6.3.0/semver.js', 461 | 'source-map': 'https://ga.jspm.io/npm:source-map@0.5.7/source-map.js', 462 | 'supports-color': 'https://ga.jspm.io/npm:supports-color@5.5.0/browser.js', 463 | 'to-fast-properties': 'https://ga.jspm.io/npm:to-fast-properties@2.0.0/index.js' 464 | } 465 | } 466 | }); 467 | } 468 | -------------------------------------------------------------------------------- /test/cases/integrity.js: -------------------------------------------------------------------------------- 1 | import assert, { strictEqual, deepStrictEqual } from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | { 5 | const map = new ImportMap({ 6 | map: { 7 | integrity: { 8 | 'a': 'a integrity', 9 | 'b': 'b integrity' 10 | } 11 | } 12 | }); 13 | 14 | map.setIntegrity('./c', 'c integrity'); 15 | 16 | strictEqual(map.getIntegrity('c'), 'c integrity'); 17 | strictEqual(map.getIntegrity('./c'), 'c integrity'); 18 | 19 | map.setIntegrity('c', 'new c integrity'); 20 | strictEqual(map.getIntegrity('./c'), 'new c integrity'); 21 | 22 | map.rebase(); 23 | deepStrictEqual(map.toJSON(), { 24 | integrity: { 25 | './a': 'a integrity', 26 | './b': 'b integrity', 27 | './c': 'new c integrity' 28 | } 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /test/cases/rebase-map.js: -------------------------------------------------------------------------------- 1 | import { deepStrictEqual } from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | const map = new ImportMap({ 5 | mapUrl: 'https://site.com/', 6 | rootUrl: null, 7 | map: { 8 | imports: { 9 | './some': './another', 10 | 'https://another.com/x': './y' 11 | }, 12 | scopes: { 13 | 'https://another.com/': { 14 | './url.js': './scoped-map.js', 15 | } 16 | }, 17 | integrity: { 18 | "./another": 'some-integrity', 19 | 'https://another.com/x': 'another-integrity' 20 | } 21 | } 22 | }); 23 | 24 | map.rebase('https://another.com/'); 25 | 26 | deepStrictEqual(map.toJSON(), { 27 | imports: { 28 | './x': 'https://site.com/y', 29 | 'https://site.com/some': 'https://site.com/another' 30 | }, 31 | scopes: { 32 | './': { 33 | 'https://site.com/url.js': 'https://site.com/scoped-map.js', 34 | } 35 | }, 36 | integrity: { 37 | './x': 'another-integrity', 38 | 'https://site.com/another': 'some-integrity' 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /test/cases/rebase-url.js: -------------------------------------------------------------------------------- 1 | import { rebase } from '../../lib/url.js'; 2 | import assert from 'assert'; 3 | 4 | let url = 'file:///test/'; 5 | let mapUrl = new URL('file:///test/a/'); 6 | let rootUrl = new URL('file:///test/a/'); 7 | assert.equal(rebase(url, mapUrl, rootUrl), '/../'); 8 | 9 | url = 'file:///test/'; 10 | mapUrl = new URL('file:///test/a/'); 11 | rootUrl = new URL('file:///test/a/b/'); 12 | assert.equal(rebase(url, mapUrl, rootUrl), '/../../'); 13 | -------------------------------------------------------------------------------- /test/cases/resolve-map.js: -------------------------------------------------------------------------------- 1 | import { strictEqual } from 'assert'; 2 | import { ImportMap } from '@jspm/import-map'; 3 | 4 | const baseUrl = 'https://site.com/'; 5 | const map = new ImportMap({ 6 | mapUrl: baseUrl, 7 | map: { 8 | imports: { 9 | test: '/test-map.js', 10 | 'https://another.com/url.js': '/url-map.js' 11 | }, 12 | scopes: { 13 | 'https://another.com/': { 14 | '/url.js': '/scoped-map.js', 15 | } 16 | } 17 | } 18 | }); 19 | 20 | strictEqual(map.resolve('test', baseUrl), 'https://site.com/test-map.js'); 21 | strictEqual(map.resolve('/url.js', 'https://another.com/'), 'https://site.com/url-map.js'); 22 | strictEqual(map.resolve('https://site.com/url.js', 'https://another.com/x'), 'https://site.com/scoped-map.js'); 23 | strictEqual(map.resolve('https://another.com/url.js', baseUrl), 'https://site.com/url-map.js'); 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "typeRoots": ["node_modules/@types"], 4 | "allowSyntheticDefaultImports": true, 5 | "moduleResolution": "node", 6 | "module": "esnext", 7 | "target": "es2019", 8 | "sourceMap": true, 9 | "outDir": "lib", 10 | "declaration": true, 11 | "declarationDir": "lib", 12 | "removeComments": false 13 | }, 14 | "include": [ 15 | "src/*.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": ["src/map.ts"] 3 | } 4 | --------------------------------------------------------------------------------