Skip to content

Commit 480656f

Browse files
feat: allow to disable default sources (#351)
1 parent 3ddf5dc commit 480656f

File tree

5 files changed

+1550
-534
lines changed

5 files changed

+1550
-534
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ module.exports = {
299299
type: 'src',
300300
filter: (tag, attribute, attributes, resourcePath) => {
301301
if (
302-
attributes.property === 'og:image' ||
302+
attributes.value === 'og:image' ||
303303
attributes.name === 'twitter:image'
304304
) {
305305
return true;

src/plugins/sources-plugin.js

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,25 @@ export default (options) =>
1919
const urlFilter = getFilter(maybeUrlFilter, (value) =>
2020
isUrlRequestable(value)
2121
);
22-
const getAttribute = (tag, attribute, attributes, resourcePath) =>
23-
list.find((element) => {
24-
const foundTag =
25-
typeof element.tag === 'undefined' ||
26-
(typeof element.tag !== 'undefined' &&
27-
element.tag.toLowerCase() === tag.toLowerCase());
28-
29-
if (!foundTag) {
30-
return false;
31-
}
22+
const getAttribute = (tag, attribute, attributes, resourcePath) => {
23+
const foundTag = list.get(tag.toLowerCase()) || list.get('*');
3224

33-
const foundAttribute =
34-
element.attribute.toLowerCase() === attribute.toLowerCase();
25+
if (!foundTag) {
26+
return false;
27+
}
3528

36-
if (!foundAttribute) {
37-
return false;
38-
}
29+
const foundAttribute = foundTag.get(attribute.toLowerCase());
3930

40-
const adaptedAttributes = attributes.reduce((accumulator, item) => {
41-
// eslint-disable-next-line no-param-reassign
42-
accumulator[item.name] = item.value;
43-
return accumulator;
44-
}, {});
31+
if (!foundAttribute) {
32+
return false;
33+
}
4534

46-
return element.filter
47-
? element.filter(tag, attribute, adaptedAttributes, resourcePath)
48-
: true;
49-
});
35+
const result = foundAttribute.filter
36+
? foundAttribute.filter(tag, attribute, attributes, resourcePath)
37+
: true;
38+
39+
return result ? foundAttribute : false;
40+
};
5041

5142
const { resourcePath } = options;
5243
const parser5 = new SAXParser({ sourceCodeLocationInfo: true });

src/utils.js

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -502,14 +502,9 @@ function getMinimizeOption(rawOptions, loaderContext) {
502502
}
503503

504504
function getAttributeValue(attributes, name) {
505-
const lowercasedAttributes = Object.keys(attributes).reduce((keys, k) => {
506-
// eslint-disable-next-line no-param-reassign
507-
keys[k.toLowerCase()] = k;
505+
const [result] = attributes.filter((i) => i.name.toLowerCase() === name);
508506

509-
return keys;
510-
}, {});
511-
512-
return attributes[lowercasedAttributes[name.toLowerCase()]];
507+
return typeof result === 'undefined' ? result : result.value;
513508
}
514509

515510
function scriptSrcFilter(tag, attribute, attributes) {
@@ -737,45 +732,75 @@ const defaultAttributes = [
737732
},
738733
];
739734

740-
function smartMergeSources(array, factory) {
741-
if (typeof array === 'undefined') {
742-
return factory();
735+
function rewriteSourcesList(sourcesList, attribute, source) {
736+
for (const key of sourcesList.keys()) {
737+
const item = sourcesList.get(key);
738+
739+
if (!item.has(attribute)) {
740+
// eslint-disable-next-line no-continue
741+
continue;
742+
}
743+
744+
item.set(attribute, {
745+
...item.get(attribute),
746+
...source,
747+
});
748+
749+
sourcesList.set(key, item);
743750
}
751+
}
744752

745-
const newArray = [];
753+
function createSourcesList(sources, accumulator = new Map()) {
754+
for (const source of sources) {
755+
if (source === '...') {
756+
// eslint-disable-next-line no-continue
757+
continue;
758+
}
746759

747-
for (let i = 0; i < array.length; i++) {
748-
const item = array[i];
760+
let { tag = '*', attribute = '*' } = source;
749761

750-
if (item === '...') {
751-
const items = factory();
762+
tag = tag.toLowerCase();
763+
attribute = attribute.toLowerCase();
752764

753-
if (typeof items !== 'undefined') {
754-
// eslint-disable-next-line no-shadow
755-
for (const item of items) {
756-
newArray.push(item);
757-
}
758-
}
759-
} else if (typeof newArray !== 'undefined') {
760-
newArray.push(item);
765+
if (tag === '*') {
766+
rewriteSourcesList(accumulator, attribute, source);
761767
}
768+
769+
if (!accumulator.has(tag)) {
770+
accumulator.set(tag, new Map());
771+
}
772+
773+
accumulator.get(tag).set(attribute, source);
762774
}
763775

764-
return newArray;
776+
return accumulator;
777+
}
778+
779+
function smartMergeSources(array, factory) {
780+
if (typeof array === 'undefined') {
781+
return factory();
782+
}
783+
784+
const result = array.some((i) => i === '...')
785+
? createSourcesList(array, factory())
786+
: createSourcesList(array);
787+
788+
return result;
765789
}
766790

767791
function getSourcesOption(rawOptions) {
768792
if (typeof rawOptions.sources === 'undefined') {
769-
return { list: defaultAttributes };
793+
return { list: createSourcesList(defaultAttributes) };
770794
}
771795

772796
if (typeof rawOptions.sources === 'boolean') {
773-
return rawOptions.sources === true ? { list: defaultAttributes } : false;
797+
return rawOptions.sources === true
798+
? { list: createSourcesList(defaultAttributes) }
799+
: false;
774800
}
775801

776-
const sources = smartMergeSources(
777-
rawOptions.sources.list,
778-
() => defaultAttributes
802+
const sources = smartMergeSources(rawOptions.sources.list, () =>
803+
createSourcesList(defaultAttributes)
779804
);
780805

781806
return {

test/__snapshots__/sources-option.test.js.snap

Lines changed: 1426 additions & 480 deletions
Large diffs are not rendered by default.

test/sources-option.test.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,60 @@ describe("'sources' option", () => {
5858
expect(getErrors(stats)).toMatchSnapshot('errors');
5959
});
6060

61+
it('should work with "..." syntax and disable source', async () => {
62+
const compiler = getCompiler('simple.js', {
63+
sources: {
64+
list: [
65+
'...',
66+
{
67+
tag: 'img',
68+
attribute: 'src',
69+
type: 'src',
70+
filter: (tag) => tag.toLowerCase() !== 'img',
71+
},
72+
{
73+
tag: 'img',
74+
attribute: 'srcset',
75+
type: 'srcset',
76+
filter: (tag) => tag.toLowerCase() !== 'img',
77+
},
78+
],
79+
},
80+
});
81+
const stats = await compile(compiler);
82+
83+
expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');
84+
expect(
85+
execute(readAsset('main.bundle.js', compiler, stats))
86+
).toMatchSnapshot('result');
87+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
88+
expect(getErrors(stats)).toMatchSnapshot('errors');
89+
});
90+
91+
it('should handle default src sources in all HTML tags except img tag (testing filter option)', async () => {
92+
const compiler = getCompiler('simple.js', {
93+
sources: {
94+
list: [
95+
'...',
96+
{
97+
attribute: 'src',
98+
type: 'src',
99+
// eslint-disable-next-line no-unused-vars
100+
filter: (tag, attribute, sources) => tag.toLowerCase() !== 'img',
101+
},
102+
],
103+
},
104+
});
105+
const stats = await compile(compiler);
106+
107+
expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module');
108+
expect(
109+
execute(readAsset('main.bundle.js', compiler, stats))
110+
).toMatchSnapshot('result');
111+
expect(getWarnings(stats)).toMatchSnapshot('warnings');
112+
expect(getErrors(stats)).toMatchSnapshot('errors');
113+
});
114+
61115
it.skip('should handle the "include" tags', async () => {
62116
const compiler = getCompiler('include.js', {
63117
sources: {

0 commit comments

Comments
 (0)