mirror of
https://github.com/jlengrand/open-wc.git
synced 2026-03-10 08:31:19 +00:00
fix(resolve): support relative node paths (#521)
This commit is contained in:
committed by
Lars den Bakker
parent
1e019466ae
commit
e4c51b7c66
@@ -17,16 +17,22 @@ import { parseFromString, resolve } from '@import-maps/resolve';
|
||||
|
||||
// you probably want to cache the map processing and not redo it for every resolve
|
||||
// a simple example
|
||||
const mapCache = null;
|
||||
const importMapCache = null;
|
||||
|
||||
function myResolve(specifier) {
|
||||
const currentDir = process.cwd();
|
||||
if (!mapCache) {
|
||||
const mapString = fs.readFileSync(path.join(currentDir, 'import-map.json'), 'utf-8');
|
||||
mapCache = parseFromString(mapString, currentDir);
|
||||
const rootDir = process.cwd();
|
||||
const basePath = importer ? importer.replace(rootDir, `${rootDir}::`) : `${rootDir}::`;
|
||||
if (!importMapCache) {
|
||||
const mapString = fs.readFileSync(path.join(rootDir, 'import-map.json'), 'utf-8');
|
||||
mapCache = parseFromString(mapString, basePath);
|
||||
}
|
||||
|
||||
return specifier => resolve(specifier, mapCache, path.join(`${currentDir}::`, 'index.html');
|
||||
const relativeSource = source.replace(rootDir, '');
|
||||
const resolvedPath = resolve(relativeSource, importMapCache, basePath);
|
||||
|
||||
if (resolvedPath) {
|
||||
return resolvedPath;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export { parseFromString } from './parser.js';
|
||||
export { resolve } from './resolver.js';
|
||||
export { mergeImportMaps } from './utils.js';
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
import { URL } from 'url';
|
||||
import path from 'path';
|
||||
import {
|
||||
tryURLLikeSpecifierParse,
|
||||
BUILT_IN_MODULE_SCHEME,
|
||||
@@ -89,14 +90,25 @@ function resolveImportsMatch(normalizedSpecifier, specifierMap) {
|
||||
export function resolve(specifier, parsedImportMap, scriptURL) {
|
||||
const asURL = tryURLLikeSpecifierParse(specifier, scriptURL);
|
||||
const normalizedSpecifier = asURL ? asURL.href : specifier;
|
||||
const scriptURLString = scriptURL;
|
||||
|
||||
let nodeSpecifier = null;
|
||||
if (scriptURL.includes('::')) {
|
||||
const [rootPath, basePath] = scriptURL.split('::');
|
||||
|
||||
const dirPath = specifier.startsWith('/') ? '' : path.dirname(basePath);
|
||||
nodeSpecifier = path.normalize(path.join(rootPath, dirPath, specifier));
|
||||
}
|
||||
const scriptURLString = scriptURL.split('::').join('');
|
||||
|
||||
for (const [scopePrefix, scopeImports] of Object.entries(parsedImportMap.scopes)) {
|
||||
if (
|
||||
scopePrefix === scriptURLString ||
|
||||
(scopePrefix.endsWith('/') && scriptURLString.startsWith(scopePrefix))
|
||||
) {
|
||||
const scopeImportsMatch = resolveImportsMatch(normalizedSpecifier, scopeImports);
|
||||
const scopeImportsMatch = resolveImportsMatch(
|
||||
nodeSpecifier || normalizedSpecifier,
|
||||
scopeImports,
|
||||
);
|
||||
if (scopeImportsMatch) {
|
||||
return scopeImportsMatch;
|
||||
}
|
||||
@@ -116,5 +128,9 @@ export function resolve(specifier, parsedImportMap, scriptURL) {
|
||||
return asURL.href;
|
||||
}
|
||||
|
||||
if (nodeSpecifier && (specifier.startsWith('/') || specifier.startsWith('.'))) {
|
||||
return nodeSpecifier;
|
||||
}
|
||||
|
||||
throw new TypeError(`Unmapped bare specifier "${specifier}"`);
|
||||
}
|
||||
|
||||
@@ -56,3 +56,21 @@ export function tryURLLikeSpecifierParse(specifier, baseURL) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function mergeImportMaps(mapA, mapB) {
|
||||
const mapAImports = mapA && mapA.imports ? mapA.imports : {};
|
||||
const mapBImports = mapB && mapB.imports ? mapB.imports : {};
|
||||
const mapAScopes = mapA && mapA.scopes ? mapA.scopes : {};
|
||||
const mapBScopes = mapB && mapB.scopes ? mapB.scopes : {};
|
||||
|
||||
return {
|
||||
imports: {
|
||||
...mapAImports,
|
||||
...mapBImports,
|
||||
},
|
||||
scopes: {
|
||||
...mapAScopes,
|
||||
...mapBScopes,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
75
packages/import-maps-resolve/test/mergeImportMaps.test.js
Normal file
75
packages/import-maps-resolve/test/mergeImportMaps.test.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import chai from 'chai';
|
||||
import { mergeImportMaps } from '../src';
|
||||
|
||||
const { expect } = chai;
|
||||
|
||||
describe('mergeImportMaps', () => {
|
||||
it('always has at least imports and scopes', () => {
|
||||
expect(mergeImportMaps({}, null)).to.deep.equal({
|
||||
imports: {},
|
||||
scopes: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('merges imports', () => {
|
||||
const mapA = { imports: { foo: '/to/foo.js' } };
|
||||
const mapB = { imports: { bar: '/to/bar.js' } };
|
||||
|
||||
expect(mergeImportMaps(mapA, mapB)).to.deep.equal({
|
||||
imports: {
|
||||
foo: '/to/foo.js',
|
||||
bar: '/to/bar.js',
|
||||
},
|
||||
scopes: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('merges scopes', () => {
|
||||
const mapA = { scopes: { '/path/to/foo/': { foo: '/to/foo.js' } } };
|
||||
const mapB = { scopes: { '/path/to/bar/': { foo: '/to/bar.js' } } };
|
||||
|
||||
expect(mergeImportMaps(mapA, mapB)).to.deep.equal({
|
||||
imports: {},
|
||||
scopes: {
|
||||
'/path/to/foo/': { foo: '/to/foo.js' },
|
||||
'/path/to/bar/': { foo: '/to/bar.js' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes unknown keys', () => {
|
||||
const mapA = { imports: { foo: '/to/foo.js' } };
|
||||
const mapB = { imp: { bar: '/to/bar.js' } };
|
||||
|
||||
expect(mergeImportMaps(mapA, mapB)).to.deep.equal({
|
||||
imports: {
|
||||
foo: '/to/foo.js',
|
||||
},
|
||||
scopes: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('overrides keys of imports and scopes of first map with second', () => {
|
||||
const mapA = { imports: { foo: '/to/foo.js' } };
|
||||
const mapB = { imports: { foo: '/to/fooOverride.js' } };
|
||||
|
||||
expect(mergeImportMaps(mapA, mapB)).to.deep.equal({
|
||||
imports: {
|
||||
foo: '/to/fooOverride.js',
|
||||
},
|
||||
scopes: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('does not introspect the scopes so with a conflict the last one wins', () => {
|
||||
const mapA = { scopes: { '/path/to/foo/': { foo: '/to/foo.js' } } };
|
||||
const mapB = { scopes: { '/path/to/foo/': { foo: '/to/fooOverride.js' } } };
|
||||
|
||||
expect(mergeImportMaps(mapA, mapB)).to.deep.equal({
|
||||
imports: {},
|
||||
scopes: {
|
||||
'/path/to/foo/': { foo: '/to/fooOverride.js' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { resolve } from '../src/resolver.js';
|
||||
const { expect } = chai;
|
||||
|
||||
const mapBaseURL = '/home/foo/project-a::/app/index.js';
|
||||
const scriptURL = '/home/foo/project-a/app/node_modules/foo/foo.js';
|
||||
const scriptURL = '/home/foo/project-a::/js/app.js';
|
||||
|
||||
function makeResolveUnderTest(mapString) {
|
||||
const map = parseFromString(mapString, mapBaseURL);
|
||||
@@ -77,3 +77,29 @@ describe('Mapped using the "imports" key only (no scopes)', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unmapped', () => {
|
||||
const resolveUnderTest = makeResolveUnderTest(`{}`);
|
||||
|
||||
it('should resolve ./ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('./foo')).to.equal('/home/foo/project-a/js/foo');
|
||||
expect(resolveUnderTest('./foo/bar')).to.equal('/home/foo/project-a/js/foo/bar');
|
||||
expect(resolveUnderTest('./foo/../bar')).to.equal('/home/foo/project-a/js/bar');
|
||||
expect(resolveUnderTest('./foo/../../bar')).to.equal('/home/foo/project-a/bar');
|
||||
});
|
||||
|
||||
it('should resolve ../ specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('../foo')).to.equal('/home/foo/project-a/foo');
|
||||
expect(resolveUnderTest('../foo/bar')).to.equal('/home/foo/project-a/foo/bar');
|
||||
// TODO: do not allow to go up higher then root path
|
||||
// expect(resolveUnderTest('../../../foo/bar')).to.equal('/home/foo/project-a/foo/bar');
|
||||
});
|
||||
|
||||
it('should resolve / specifiers as URLs', () => {
|
||||
expect(resolveUnderTest('/foo')).to.equal('/home/foo/project-a/foo');
|
||||
expect(resolveUnderTest('/foo/bar')).to.equal('/home/foo/project-a/foo/bar');
|
||||
// TODO: do not allow to go up higher then root path
|
||||
// expect(resolveUnderTest('/../../foo/bar')).to.equal('/home/foo/project-a/foo/bar');
|
||||
// expect(resolveUnderTest('/../foo/../bar')).to.equal('/home/foo/project-a/bar');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user