mirror of
https://github.com/jlengrand/open-wc.git
synced 2026-03-10 08:31:19 +00:00
278 lines
10 KiB
JavaScript
278 lines
10 KiB
JavaScript
import chai from 'chai';
|
|
import { URL } from 'url';
|
|
import { parseFromString } from '../src/parser.js';
|
|
import { resolve } from '../src/resolver.js';
|
|
|
|
const { expect } = chai;
|
|
|
|
const mapBaseURL = 'https://example.com/app/index.html';
|
|
|
|
function makeResolveUnderTest(mapString) {
|
|
const map = parseFromString(mapString, mapBaseURL);
|
|
return (specifier, baseURL) => resolve(specifier, map, baseURL);
|
|
}
|
|
|
|
describe('Mapped using scope instead of "imports"', () => {
|
|
const jsNonDirURL = 'https://example.com/js';
|
|
const jsPrefixedURL = 'https://example.com/jsiscool';
|
|
const inJSDirURL = 'https://example.com/js/app.mjs';
|
|
const topLevelURL = 'https://example.com/app.mjs';
|
|
|
|
it('should fail when the mapping is to an empty array', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"scopes": {
|
|
"/js/": {
|
|
"moment": null,
|
|
"lodash": []
|
|
}
|
|
}
|
|
}`);
|
|
|
|
expect(() => resolveUnderTest('moment', inJSDirURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('lodash', inJSDirURL)).to.throw(TypeError);
|
|
});
|
|
|
|
describe('Exact vs. prefix based matching', () => {
|
|
it('should match correctly when both are in the map', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"scopes": {
|
|
"/js": {
|
|
"moment": "/only-triggered-by-exact/moment",
|
|
"moment/": "/only-triggered-by-exact/moment/"
|
|
},
|
|
"/js/": {
|
|
"moment": "/triggered-by-any-subpath/moment",
|
|
"moment/": "/triggered-by-any-subpath/moment/"
|
|
}
|
|
}
|
|
}`);
|
|
|
|
expect(resolveUnderTest('moment', jsNonDirURL)).to.equal(
|
|
'https://example.com/only-triggered-by-exact/moment',
|
|
);
|
|
expect(resolveUnderTest('moment/foo', jsNonDirURL)).to.equal(
|
|
'https://example.com/only-triggered-by-exact/moment/foo',
|
|
);
|
|
|
|
expect(resolveUnderTest('moment', inJSDirURL)).to.equal(
|
|
'https://example.com/triggered-by-any-subpath/moment',
|
|
);
|
|
expect(resolveUnderTest('moment/foo', inJSDirURL)).to.equal(
|
|
'https://example.com/triggered-by-any-subpath/moment/foo',
|
|
);
|
|
|
|
expect(() => resolveUnderTest('moment', jsPrefixedURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).to.throw(TypeError);
|
|
});
|
|
|
|
it('should match correctly when only an exact match is in the map', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"scopes": {
|
|
"/js": {
|
|
"moment": "/only-triggered-by-exact/moment",
|
|
"moment/": "/only-triggered-by-exact/moment/"
|
|
}
|
|
}
|
|
}`);
|
|
|
|
expect(resolveUnderTest('moment', jsNonDirURL)).to.equal(
|
|
'https://example.com/only-triggered-by-exact/moment',
|
|
);
|
|
expect(resolveUnderTest('moment/foo', jsNonDirURL)).to.equal(
|
|
'https://example.com/only-triggered-by-exact/moment/foo',
|
|
);
|
|
|
|
expect(() => resolveUnderTest('moment', inJSDirURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('moment/foo', inJSDirURL)).to.throw(TypeError);
|
|
|
|
expect(() => resolveUnderTest('moment', jsPrefixedURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).to.throw(TypeError);
|
|
});
|
|
|
|
it('should match correctly when only a prefix match is in the map', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"scopes": {
|
|
"/js/": {
|
|
"moment": "/triggered-by-any-subpath/moment",
|
|
"moment/": "/triggered-by-any-subpath/moment/"
|
|
}
|
|
}
|
|
}`);
|
|
|
|
expect(() => resolveUnderTest('moment', jsNonDirURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('moment/foo', jsNonDirURL)).to.throw(TypeError);
|
|
|
|
expect(resolveUnderTest('moment', inJSDirURL)).to.equal(
|
|
'https://example.com/triggered-by-any-subpath/moment',
|
|
);
|
|
expect(resolveUnderTest('moment/foo', inJSDirURL)).to.equal(
|
|
'https://example.com/triggered-by-any-subpath/moment/foo',
|
|
);
|
|
|
|
expect(() => resolveUnderTest('moment', jsPrefixedURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).to.throw(TypeError);
|
|
});
|
|
});
|
|
|
|
describe('Package-like scenarios', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"imports": {
|
|
"moment": "/node_modules/moment/src/moment.js",
|
|
"moment/": "/node_modules/moment/src/",
|
|
"lodash-dot": "./node_modules/lodash-es/lodash.js",
|
|
"lodash-dot/": "./node_modules/lodash-es/",
|
|
"lodash-dotdot": "../node_modules/lodash-es/lodash.js",
|
|
"lodash-dotdot/": "../node_modules/lodash-es/"
|
|
},
|
|
"scopes": {
|
|
"/": {
|
|
"moment": "/node_modules_3/moment/src/moment.js",
|
|
"vue": "/node_modules_3/vue/dist/vue.runtime.esm.js"
|
|
},
|
|
"/js/": {
|
|
"lodash-dot": "./node_modules_2/lodash-es/lodash.js",
|
|
"lodash-dot/": "./node_modules_2/lodash-es/",
|
|
"lodash-dotdot": "../node_modules_2/lodash-es/lodash.js",
|
|
"lodash-dotdot/": "../node_modules_2/lodash-es/"
|
|
}
|
|
}
|
|
}`);
|
|
|
|
it('should resolve scoped', () => {
|
|
expect(resolveUnderTest('lodash-dot', inJSDirURL)).to.equal(
|
|
'https://example.com/app/node_modules_2/lodash-es/lodash.js',
|
|
);
|
|
expect(resolveUnderTest('lodash-dotdot', inJSDirURL)).to.equal(
|
|
'https://example.com/node_modules_2/lodash-es/lodash.js',
|
|
);
|
|
expect(resolveUnderTest('lodash-dot/foo', inJSDirURL)).to.equal(
|
|
'https://example.com/app/node_modules_2/lodash-es/foo',
|
|
);
|
|
expect(resolveUnderTest('lodash-dotdot/foo', inJSDirURL)).to.equal(
|
|
'https://example.com/node_modules_2/lodash-es/foo',
|
|
);
|
|
});
|
|
|
|
it('should apply best scope match', () => {
|
|
expect(resolveUnderTest('moment', topLevelURL)).to.equal(
|
|
'https://example.com/node_modules_3/moment/src/moment.js',
|
|
);
|
|
expect(resolveUnderTest('moment', inJSDirURL)).to.equal(
|
|
'https://example.com/node_modules_3/moment/src/moment.js',
|
|
);
|
|
expect(resolveUnderTest('vue', inJSDirURL)).to.equal(
|
|
'https://example.com/node_modules_3/vue/dist/vue.runtime.esm.js',
|
|
);
|
|
});
|
|
|
|
it('should fallback to "imports"', () => {
|
|
expect(resolveUnderTest('moment/foo', topLevelURL)).to.equal(
|
|
'https://example.com/node_modules/moment/src/foo',
|
|
);
|
|
expect(resolveUnderTest('moment/foo', inJSDirURL)).to.equal(
|
|
'https://example.com/node_modules/moment/src/foo',
|
|
);
|
|
expect(resolveUnderTest('lodash-dot', topLevelURL)).to.equal(
|
|
'https://example.com/app/node_modules/lodash-es/lodash.js',
|
|
);
|
|
expect(resolveUnderTest('lodash-dotdot', topLevelURL)).to.equal(
|
|
'https://example.com/node_modules/lodash-es/lodash.js',
|
|
);
|
|
expect(resolveUnderTest('lodash-dot/foo', topLevelURL)).to.equal(
|
|
'https://example.com/app/node_modules/lodash-es/foo',
|
|
);
|
|
expect(resolveUnderTest('lodash-dotdot/foo', topLevelURL)).to.equal(
|
|
'https://example.com/node_modules/lodash-es/foo',
|
|
);
|
|
});
|
|
|
|
it('should still fail for package-like specifiers that are not declared', () => {
|
|
expect(() => resolveUnderTest('underscore/', inJSDirURL)).to.throw(TypeError);
|
|
expect(() => resolveUnderTest('underscore/foo', inJSDirURL)).to.throw(TypeError);
|
|
});
|
|
});
|
|
|
|
describe('The scope inheritance example from the README', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"imports": {
|
|
"a": "/a-1.mjs",
|
|
"b": "/b-1.mjs",
|
|
"c": "/c-1.mjs"
|
|
},
|
|
"scopes": {
|
|
"/scope2/": {
|
|
"a": "/a-2.mjs"
|
|
},
|
|
"/scope2/scope3/": {
|
|
"b": "/b-3.mjs"
|
|
}
|
|
}
|
|
}`);
|
|
|
|
const scope1URL = 'https://example.com/scope1/foo.mjs';
|
|
const scope2URL = 'https://example.com/scope2/foo.mjs';
|
|
const scope3URL = 'https://example.com/scope2/scope3/foo.mjs';
|
|
|
|
it('should fall back to "imports" when none match', () => {
|
|
expect(resolveUnderTest('a', scope1URL)).to.equal('https://example.com/a-1.mjs');
|
|
expect(resolveUnderTest('b', scope1URL)).to.equal('https://example.com/b-1.mjs');
|
|
expect(resolveUnderTest('c', scope1URL)).to.equal('https://example.com/c-1.mjs');
|
|
});
|
|
|
|
it('should use a direct scope override', () => {
|
|
expect(resolveUnderTest('a', scope2URL)).to.equal('https://example.com/a-2.mjs');
|
|
expect(resolveUnderTest('b', scope2URL)).to.equal('https://example.com/b-1.mjs');
|
|
expect(resolveUnderTest('c', scope2URL)).to.equal('https://example.com/c-1.mjs');
|
|
});
|
|
|
|
it('should use an indirect scope override', () => {
|
|
expect(resolveUnderTest('a', scope3URL)).to.equal('https://example.com/a-2.mjs');
|
|
expect(resolveUnderTest('b', scope3URL)).to.equal('https://example.com/b-3.mjs');
|
|
expect(resolveUnderTest('c', scope3URL)).to.equal('https://example.com/c-1.mjs');
|
|
});
|
|
});
|
|
|
|
describe('Relative URL scope keys', () => {
|
|
const resolveUnderTest = makeResolveUnderTest(`{
|
|
"imports": {
|
|
"a": "/a-1.mjs",
|
|
"b": "/b-1.mjs",
|
|
"c": "/c-1.mjs"
|
|
},
|
|
"scopes": {
|
|
"": {
|
|
"a": "/a-empty-string.mjs"
|
|
},
|
|
"./": {
|
|
"b": "/b-dot-slash.mjs"
|
|
},
|
|
"../": {
|
|
"c": "/c-dot-dot-slash.mjs"
|
|
}
|
|
}
|
|
}`);
|
|
const inSameDirAsMap = new URL('./foo.mjs', mapBaseURL).href;
|
|
const inDirAboveMap = new URL('../foo.mjs', mapBaseURL).href;
|
|
|
|
it('should resolve an empty string scope using the import map URL', () => {
|
|
expect(resolveUnderTest('a', mapBaseURL)).to.equal('https://example.com/a-empty-string.mjs');
|
|
expect(resolveUnderTest('a', inSameDirAsMap)).to.equal('https://example.com/a-1.mjs');
|
|
});
|
|
|
|
it("should resolve a ./ scope using the import map URL's directory", () => {
|
|
expect(resolveUnderTest('b', mapBaseURL)).to.equal('https://example.com/b-dot-slash.mjs');
|
|
expect(resolveUnderTest('b', inSameDirAsMap)).to.equal('https://example.com/b-dot-slash.mjs');
|
|
});
|
|
|
|
it("should resolve a ../ scope using the import map URL's directory", () => {
|
|
expect(resolveUnderTest('c', mapBaseURL)).to.equal('https://example.com/c-dot-dot-slash.mjs');
|
|
expect(resolveUnderTest('c', inSameDirAsMap)).to.equal(
|
|
'https://example.com/c-dot-dot-slash.mjs',
|
|
);
|
|
expect(resolveUnderTest('c', inDirAboveMap)).to.equal(
|
|
'https://example.com/c-dot-dot-slash.mjs',
|
|
);
|
|
});
|
|
});
|
|
});
|