diff --git a/README.md b/README.md index 7dc772e0..9fc392c9 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,49 @@ module.exports = { }; ``` +If the tag name is not specified it will process all the tags. + +> You can use your custom filter to specify html elements to be processed. + +For example: + +**webpack.config.js** + +```js +module.exports = { + module: { + rules: [ + { + test: /\.html$/i, + loader: 'html-loader', + options: { + attributes: { + list: [ + { + // Attribute name + attribute: 'src', + // Type of processing, can be `src` or `scrset` + type: 'src', + // Allow to filter some attributes (optional) + filter: (tag, attribute, attributes, resourcePath) => { + // The `tag` argument contains a name of the HTML tag. + // The `attribute` argument contains a name of the HTML attribute. + // The `attributes` argument contains all attributes of the tag. + // The `resourcePath` argument contains a path to the loaded HTML file. + + // choose all HTML tags except img tag + return tag.toLowerCase() !== 'img'; + }, + }, + ], + }, + }, + }, + ], + }, +}; +``` + #### `urlFilter` Type: `Function` diff --git a/src/options.json b/src/options.json index d4ce35df..8291e308 100644 --- a/src/options.json +++ b/src/options.json @@ -19,7 +19,7 @@ "instanceof": "Function" } }, - "required": ["tag", "attribute", "type"], + "required": ["attribute", "type"], "additionalProperties": false }, "AttributeList": { diff --git a/src/plugins/source-plugin.js b/src/plugins/source-plugin.js index 0ca0955a..78e66dc2 100644 --- a/src/plugins/source-plugin.js +++ b/src/plugins/source-plugin.js @@ -495,7 +495,9 @@ export default (options) => const getAttribute = (tag, attribute, attributes, resourcePath) => { return attributeList.find( (element) => - element.tag.toLowerCase() === tag.toLowerCase() && + (typeof element.tag === 'undefined' || + (typeof element.tag !== 'undefined' && + element.tag.toLowerCase() === tag.toLowerCase())) && element.attribute.toLowerCase() === attribute.toLowerCase() && (element.filter ? element.filter(tag, attribute, attributes, resourcePath) diff --git a/test/__snapshots__/attributes-option.test.js.snap b/test/__snapshots__/attributes-option.test.js.snap index 06471f2b..bf491a98 100644 --- a/test/__snapshots__/attributes-option.test.js.snap +++ b/test/__snapshots__/attributes-option.test.js.snap @@ -738,6 +738,638 @@ exports[`'attributes' option should handle "src" and "srcset" tags correctly: re exports[`'attributes' option should handle "src" and "srcset" tags correctly: warnings 1`] = `Array []`; +exports[`'attributes' option should handle all src attributes in all HTML tags except img (testing filter option) tag is undefined: errors 1`] = `Array []`; + +exports[`'attributes' option should handle all src attributes in all HTML tags except img (testing filter option) tag is undefined: module 1`] = ` +"// Imports +var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\"); +var ___HTML_LOADER_IMPORT_0___ = require(\\"./script.file.js\\"); +var ___HTML_LOADER_IMPORT_1___ = require(\\"./example.ogg\\"); +var ___HTML_LOADER_IMPORT_2___ = require(\\"./example.pdf\\"); +var ___HTML_LOADER_IMPORT_3___ = require(\\"./template.html\\"); +var ___HTML_LOADER_IMPORT_4___ = require(\\"./image.png\\"); +var ___HTML_LOADER_IMPORT_5___ = require(\\"./example.vtt\\"); +var ___HTML_LOADER_IMPORT_6___ = require(\\"./module.file.js\\"); +var ___HTML_LOADER_IMPORT_7___ = require(\\"./fallback.file.js\\"); +// Module +var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___); +var ___HTML_LOADER_REPLACER_1___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_1___); +var ___HTML_LOADER_REPLACER_2___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_2___); +var ___HTML_LOADER_REPLACER_3___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_3___); +var ___HTML_LOADER_REPLACER_4___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_4___); +var ___HTML_LOADER_REPLACER_5___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_5___); +var ___HTML_LOADER_REPLACER_6___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_6___); +var ___HTML_LOADER_REPLACER_7___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_7___); +var code = \\"\\\\n\\\\n

My First Heading

\\\\n

My first paragraph.

\\\\n

An Unordered HTML List

\\\\n\\\\n\\\\n\\\\n

An Ordered HTML List

\\\\n\\\\n
    \\\\n
  1. Coffee
  2. \\\\n
  3. Tea
  4. \\\\n
  5. Milk
  6. \\\\n
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n
Foo
\\\\n\\\\n\\\\n
BAR
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\n\\\\n \\\\n \\\\n \\\\\\"Flowers\\\\\\"\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Smiley\\\\n\\\\n
\\\\n First name:
\\\\n \\\\n
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\nT ex t \\\\n\\\\n
\\\\n\\\\n\\\\n\\\\n]]>\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\nlink text\\\\n\\\\nCall me\\\\n\\\\n-->\\\\n-->\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n
\\\\n
\\\\n\\\\n<div id = "character">\\\\n© 2007\\\\nor\\\\n© 2007\\\\n\\\\n
\\\\n\\\\n\\\\\\"Red\\\\n
\\\\n Written by Jon Doe.
\\\\n Visit us at:
\\\\n Example.com
\\\\n Box 564, Disneyland
\\\\n USA\\\\n
\\\\nlink\\\\nStart Chat\\\\nStart Chat\\\\nStart Chat\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Test\\\\\\"\\\\n\\\\n\\\\n\\\\n Test \\\\n\\\\ntest\\\\ntest\\\\ntest\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n

Text

\\\\n

Text

\\\\n

Text

\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\\\"test\\\\\\"\\\\n\\\\\\"test\\\\\\"\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\"; +// Exports +module.exports = code;" +`; + +exports[`'attributes' option should handle all src attributes in all HTML tags except img (testing filter option) tag is undefined: result 1`] = ` +" + +

My First Heading

+

My first paragraph.

+

An Unordered HTML List

+ +
    +
  • Coffee
  • +
  • Tea
  • +
  • Milk
  • +
+ +

An Ordered HTML List

+ +
    +
  1. Coffee
  2. +
  3. Tea
  4. +
  5. Milk
  6. +
+ + + + + +
Foo
+ + +
BAR
+ + + + + + + + + + + + + + + + + + + + + + + + + +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva + + + + + \\"Flowers\\" + + + + + + + + +\\"Smiley + +
+ First name:
+ +
+ + + + + + + + + + + + + +T ex t + +
+ + + +]]> + + + + + + + + + + + + + + + + + + + + +link text + +Call me + +--> +--> + + + + + +
+
+ +<div id = "character"> +© 2007 +or +© 2007 + +
+ +\\"Red +
+ Written by Jon Doe.
+ Visit us at:
+ Example.com
+ Box 564, Disneyland
+ USA +
+link +Start Chat +Start Chat +Start Chat + + + +\\"Elva +\\"Elva + +\\"Elva +\\"Test\\" + + + + Test + +test +test +test + + + + + +

Text

+

Text

+

Text

+ + + + + + + + + + + + + + + + +\\"Elva + + + + + + + + + + + +\\"Elva +\\"test\\"/ +\\"test\\" +\\"test\\" +\\"test\\"/ +\\"test\\"/ + + +\\"Elva +" +`; + +exports[`'attributes' option should handle all src attributes in all HTML tags except img (testing filter option) tag is undefined: warnings 1`] = `Array []`; + +exports[`'attributes' option should handle all src attributes in all HTML tags when tag is undefined: errors 1`] = `Array []`; + +exports[`'attributes' option should handle all src attributes in all HTML tags when tag is undefined: module 1`] = ` +"// Imports +var ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\\"../../src/runtime/getUrl.js\\"); +var ___HTML_LOADER_IMPORT_0___ = require(\\"./image.png\\"); +var ___HTML_LOADER_IMPORT_1___ = require(\\"aliasImg\\"); +var ___HTML_LOADER_IMPORT_2___ = require(\\"./script.file.js\\"); +var ___HTML_LOADER_IMPORT_3___ = require(\\"./icons.svg\\"); +var ___HTML_LOADER_IMPORT_4___ = require(\\"./example.ogg\\"); +var ___HTML_LOADER_IMPORT_5___ = require(\\"./example.pdf\\"); +var ___HTML_LOADER_IMPORT_6___ = require(\\"./template.html\\"); +var ___HTML_LOADER_IMPORT_7___ = require(\\"./example.vtt\\"); +var ___HTML_LOADER_IMPORT_8___ = require(\\"./image image.png\\"); +var ___HTML_LOADER_IMPORT_9___ = require(\\"./module.file.js\\"); +var ___HTML_LOADER_IMPORT_10___ = require(\\"./fallback.file.js\\"); +var ___HTML_LOADER_IMPORT_11___ = require(\\"aliasImageWithSpace\\"); +// Module +var ___HTML_LOADER_REPLACER_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___); +var ___HTML_LOADER_REPLACER_1___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___, true); +var ___HTML_LOADER_REPLACER_2___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_1___); +var ___HTML_LOADER_REPLACER_3___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_2___); +var ___HTML_LOADER_REPLACER_4___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_3___); +var ___HTML_LOADER_REPLACER_5___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_4___); +var ___HTML_LOADER_REPLACER_6___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_5___); +var ___HTML_LOADER_REPLACER_7___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_6___); +var ___HTML_LOADER_REPLACER_8___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_7___); +var ___HTML_LOADER_REPLACER_9___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_8___); +var ___HTML_LOADER_REPLACER_10___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_9___); +var ___HTML_LOADER_REPLACER_11___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_10___); +var ___HTML_LOADER_REPLACER_12___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_11___, true); +var ___HTML_LOADER_REPLACER_13___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_11___); +var code = \\"\\\\n\\\\n

My First Heading

\\\\n

My first paragraph.

\\\\n

An Unordered HTML List

\\\\n\\\\n
    \\\\n
  • Coffee
  • \\\\n
  • Tea
  • \\\\n
  • Milk
  • \\\\n
\\\\n\\\\n

An Ordered HTML List

\\\\n\\\\n
    \\\\n
  1. Coffee
  2. \\\\n
  3. Tea
  4. \\\\n
  5. Milk
  6. \\\\n
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n
Foo
\\\\n\\\\n\\\\n
BAR
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\n\\\\n \\\\n \\\\n \\\\\\"Flowers\\\\\\"\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Smiley\\\\n\\\\n
\\\\n First name:
\\\\n \\\\n
\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\nT ex t \\\\n\\\\n
\\\\n\\\\n\\\\n\\\\n]]>\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\nlink text\\\\n\\\\nCall me\\\\n\\\\n-->\\\\n-->\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n
\\\\n
\\\\n\\\\n<div id = "character">\\\\n© 2007\\\\nor\\\\n© 2007\\\\n\\\\n
\\\\n\\\\n\\\\\\"Red\\\\n
\\\\n Written by Jon Doe.
\\\\n Visit us at:
\\\\n Example.com
\\\\n Box 564, Disneyland
\\\\n USA\\\\n
\\\\nlink\\\\nStart Chat\\\\nStart Chat\\\\nStart Chat\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Elva\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"Test\\\\\\"\\\\n\\\\n\\\\n\\\\n Test \\\\n\\\\ntest\\\\ntest\\\\ntest\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n

Text

\\\\n

Text

\\\\n

Text

\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\\\"test\\\\\\"\\\\n\\\\\\"test\\\\\\"\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\\\"test\\\\\\"/\\\\n\\\\n\\\\n\\\\\\"Elva\\\\n\\"; +// Exports +module.exports = code;" +`; + +exports[`'attributes' option should handle all src attributes in all HTML tags when tag is undefined: result 1`] = ` +" + +

My First Heading

+

My first paragraph.

+

An Unordered HTML List

+ +
    +
  • Coffee
  • +
  • Tea
  • +
  • Milk
  • +
+ +

An Ordered HTML List

+ +
    +
  1. Coffee
  2. +
  3. Tea
  4. +
  5. Milk
  6. +
+ + + + + +
Foo
+ + +
BAR
+ + + + + + + + + + + + + + + + + + + + + + + + + +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva +\\"Elva + + + + + \\"Flowers\\" + + + + + + + + +\\"Smiley + +
+ First name:
+ +
+ + + + + + + + + + + + + +T ex t + +
+ + + +]]> + + + + + + + + + + + + + + + + + + + + +link text + +Call me + +--> +--> + + + + + +
+
+ +<div id = "character"> +© 2007 +or +© 2007 + +
+ +\\"Red +
+ Written by Jon Doe.
+ Visit us at:
+ Example.com
+ Box 564, Disneyland
+ USA +
+link +Start Chat +Start Chat +Start Chat + + + +\\"Elva +\\"Elva + +\\"Elva +\\"Test\\" + + + + Test + +test +test +test + + + + + +

Text

+

Text

+

Text

+ + + + + + + + + + + + + + + + +\\"Elva + + + + + + + + + + + +\\"Elva +\\"test\\"/ +\\"test\\" +\\"test\\" +\\"test\\"/ +\\"test\\"/ + + +\\"Elva +" +`; + +exports[`'attributes' option should handle all src attributes in all HTML tags when tag is undefined: warnings 1`] = `Array []`; + exports[`'attributes' option should handle attributes with a "boolean" notation equals "true": errors 1`] = `Array []`; exports[`'attributes' option should handle attributes with a "boolean" notation equals "true": module 1`] = ` diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap index c5c186b1..be2674c3 100644 --- a/test/__snapshots__/validate-options.test.js.snap +++ b/test/__snapshots__/validate-options.test.js.snap @@ -15,6 +15,11 @@ exports[`validate options should throw an error on the "attributes" option with - options.attributes.list should be an non-empty array." `; +exports[`validate options should throw an error on the "attributes" option with "{"list":[{"tag":"","attribute":"src","type":"src"}]}" value 1`] = ` +"Invalid options object. HTML Loader has been initialized using an options object that does not match the API schema. + - options.attributes.list[0].tag should be an non-empty string." +`; + exports[`validate options should throw an error on the "attributes" option with "{"list":[{"tag":"img","attribute":"src","type":"src","filter":"test"}]}" value 1`] = ` "Invalid options object. HTML Loader has been initialized using an options object that does not match the API schema. - options.attributes.list[0].filter should be an instance of function." diff --git a/test/attributes-option.test.js b/test/attributes-option.test.js index 901c3546..e1e896e9 100644 --- a/test/attributes-option.test.js +++ b/test/attributes-option.test.js @@ -172,6 +172,52 @@ describe("'attributes' option", () => { expect(getErrors(stats)).toMatchSnapshot('errors'); }); + it('should handle all src attributes in all HTML tags when tag is undefined', async () => { + const compiler = getCompiler('simple.js', { + attributes: { + list: [ + { + attribute: 'src', + type: 'src', + }, + ], + }, + }); + const stats = await compile(compiler); + + expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module'); + expect( + execute(readAsset('main.bundle.js', compiler, stats)) + ).toMatchSnapshot('result'); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); + + it('should handle all src attributes in all HTML tags except img (testing filter option) tag is undefined', async () => { + const compiler = getCompiler('simple.js', { + attributes: { + list: [ + { + attribute: 'src', + type: 'src', + // eslint-disable-next-line no-unused-vars + filter: (tag, attribute, attributes) => { + return tag.toLowerCase() !== 'img'; + }, + }, + ], + }, + }); + const stats = await compile(compiler); + + expect(getModuleSource('./simple.html', stats)).toMatchSnapshot('module'); + expect( + execute(readAsset('main.bundle.js', compiler, stats)) + ).toMatchSnapshot('result'); + expect(getWarnings(stats)).toMatchSnapshot('warnings'); + expect(getErrors(stats)).toMatchSnapshot('errors'); + }); + it('should work by default with CommonJS module syntax', async () => { const compiler = getCompiler( 'simple.js', diff --git a/test/validate-options.test.js b/test/validate-options.test.js index dba55de8..0b7e6473 100644 --- a/test/validate-options.test.js +++ b/test/validate-options.test.js @@ -6,6 +6,14 @@ describe('validate options', () => { success: [ true, false, + { + list: [ + { + attribute: 'src', + type: 'src', + }, + ], + }, { list: [ { @@ -72,6 +80,15 @@ describe('validate options', () => { }, ], }, + { + list: [ + { + tag: '', + attribute: 'src', + type: 'src', + }, + ], + }, { list: [ {