diff --git a/.eslintignore b/.eslintignore index 4a838089..ae409af0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,3 @@ -/node_modules -/src/runtime +/coverage /dist +/node_modules diff --git a/babel.config.js b/babel.config.js index 4c9ccbc8..a76d9af9 100644 --- a/babel.config.js +++ b/babel.config.js @@ -15,5 +15,20 @@ module.exports = (api) => { }, ], ], + overrides: [ + { + test: './src/runtime', + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: '0.12', + }, + }, + ], + ], + }, + ], }; }; diff --git a/src/runtime/api.js b/src/runtime/api.js index e70cba20..117f5263 100644 --- a/src/runtime/api.js +++ b/src/runtime/api.js @@ -3,35 +3,45 @@ Author Tobias Koppers @sokra */ // css base code, injected by the css-loader +// eslint-disable-next-line func-names module.exports = function(useSourceMap) { - var list = []; + const list = []; // return the list of modules as css string list.toString = function toString() { - return this.map(function(item) { - var content = cssWithMappingToString(item, useSourceMap); + return this.map((item) => { + const content = cssWithMappingToString(item, useSourceMap); + if (item[2]) { - return '@media ' + item[2] + '{' + content + '}'; - } else { - return content; + return `@media ${item[2]}{${content}}`; } + + return content; }).join(''); }; // import a list of modules into the list + // eslint-disable-next-line func-names list.i = function(modules, mediaQuery) { if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } - var alreadyImportedModules = {}; - for (var i = 0; i < this.length; i++) { - var id = this[i][0]; + + const alreadyImportedModules = {}; + + for (let i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + const id = this[i][0]; + if (id != null) { alreadyImportedModules[id] = true; } } - for (i = 0; i < modules.length; i++) { - var item = modules[i]; + + for (let i = 0; i < modules.length; i++) { + const item = modules[i]; + // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. @@ -40,27 +50,31 @@ module.exports = function(useSourceMap) { if (mediaQuery && !item[2]) { item[2] = mediaQuery; } else if (mediaQuery) { - item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; + item[2] = `(${item[2]}) and (${mediaQuery})`; } + list.push(item); } } }; + return list; }; function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; + const content = item[1] || ''; + // eslint-disable-next-line prefer-destructuring + const cssMapping = item[3]; + if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function(source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; - }); + const sourceMapping = toComment(cssMapping); + const sourceURLs = cssMapping.sources.map( + (source) => `/*# sourceURL=${cssMapping.sourceRoot}${source} */` + ); return [content] .concat(sourceURLs) @@ -74,9 +88,8 @@ function cssWithMappingToString(item, useSourceMap) { // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef - var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); - var data = - 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + const data = `sourceMappingURL=data:application/json;charset=utf-8;base64,${base64}`; - return '/*# ' + data + ' */'; + return `/*# ${data} */`; } diff --git a/src/runtime/url-escape.js b/src/runtime/url-escape.js index a792c658..e97c94df 100644 --- a/src/runtime/url-escape.js +++ b/src/runtime/url-escape.js @@ -5,13 +5,14 @@ module.exports = function escape(url, needQuotes) { // If url is already wrapped in quotes, remove them if (/^['"].*['"]$/.test(url)) { + // eslint-disable-next-line no-param-reassign url = url.slice(1, -1); } // Should url be wrapped? // See https://drafts.csswg.org/css-values-3/#urls if (/["'() \t\n]/.test(url) || needQuotes) { - return '"' + url.replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"'; + return `"${url.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"`; } return url; diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index 158f1624..a359ece6 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -6,35 +6,45 @@ exports[`loader should compile with \`css\` entry point (with \`modules\` and sc Author Tobias Koppers @sokra */ // css base code, injected by the css-loader +// eslint-disable-next-line func-names module.exports = function(useSourceMap) { - var list = []; + const list = []; // return the list of modules as css string list.toString = function toString() { - return this.map(function(item) { - var content = cssWithMappingToString(item, useSourceMap); + return this.map((item) => { + const content = cssWithMappingToString(item, useSourceMap); + if (item[2]) { - return '@media ' + item[2] + '{' + content + '}'; - } else { - return content; + return \`@media \${item[2]}{\${content}}\`; } + + return content; }).join(''); }; // import a list of modules into the list + // eslint-disable-next-line func-names list.i = function(modules, mediaQuery) { if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } - var alreadyImportedModules = {}; - for (var i = 0; i < this.length; i++) { - var id = this[i][0]; + + const alreadyImportedModules = {}; + + for (let i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + const id = this[i][0]; + if (id != null) { alreadyImportedModules[id] = true; } } - for (i = 0; i < modules.length; i++) { - var item = modules[i]; + + for (let i = 0; i < modules.length; i++) { + const item = modules[i]; + // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. @@ -43,27 +53,31 @@ module.exports = function(useSourceMap) { if (mediaQuery && !item[2]) { item[2] = mediaQuery; } else if (mediaQuery) { - item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; + item[2] = \`(\${item[2]}) and (\${mediaQuery})\`; } + list.push(item); } } }; + return list; }; function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; + const content = item[1] || ''; + // eslint-disable-next-line prefer-destructuring + const cssMapping = item[3]; + if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function(source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; - }); + const sourceMapping = toComment(cssMapping); + const sourceURLs = cssMapping.sources.map( + (source) => \`/*# sourceURL=\${cssMapping.sourceRoot}\${source} */\` + ); return [content] .concat(sourceURLs) @@ -77,11 +91,10 @@ function cssWithMappingToString(item, useSourceMap) { // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef - var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); - var data = - 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + const data = \`sourceMappingURL=data:application/json;charset=utf-8;base64,\${base64}\`; - return '/*# ' + data + ' */'; + return \`/*# \${data} */\`; } " `; @@ -96,13 +109,14 @@ exports[`loader should compile with \`css\` entry point (with \`modules\` and sc // If url is already wrapped in quotes, remove them if (/^['\\"].*['\\"]$/.test(url)) { + // eslint-disable-next-line no-param-reassign url = url.slice(1, -1); } // Should url be wrapped? // See https://drafts.csswg.org/css-values-3/#urls if (/[\\"'() \\\\t\\\\n]/.test(url) || needQuotes) { - return '\\"' + url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n') + '\\"'; + return \`\\"\${url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n')}\\"\`; } return url; @@ -281,35 +295,45 @@ exports[`loader should compile with \`css\` entry point (with \`modules\` and sc Author Tobias Koppers @sokra */ // css base code, injected by the css-loader +// eslint-disable-next-line func-names module.exports = function(useSourceMap) { - var list = []; + const list = []; // return the list of modules as css string list.toString = function toString() { - return this.map(function(item) { - var content = cssWithMappingToString(item, useSourceMap); + return this.map((item) => { + const content = cssWithMappingToString(item, useSourceMap); + if (item[2]) { - return '@media ' + item[2] + '{' + content + '}'; - } else { - return content; + return \`@media \${item[2]}{\${content}}\`; } + + return content; }).join(''); }; // import a list of modules into the list + // eslint-disable-next-line func-names list.i = function(modules, mediaQuery) { if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } - var alreadyImportedModules = {}; - for (var i = 0; i < this.length; i++) { - var id = this[i][0]; + + const alreadyImportedModules = {}; + + for (let i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + const id = this[i][0]; + if (id != null) { alreadyImportedModules[id] = true; } } - for (i = 0; i < modules.length; i++) { - var item = modules[i]; + + for (let i = 0; i < modules.length; i++) { + const item = modules[i]; + // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. @@ -318,27 +342,31 @@ module.exports = function(useSourceMap) { if (mediaQuery && !item[2]) { item[2] = mediaQuery; } else if (mediaQuery) { - item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; + item[2] = \`(\${item[2]}) and (\${mediaQuery})\`; } + list.push(item); } } }; + return list; }; function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; + const content = item[1] || ''; + // eslint-disable-next-line prefer-destructuring + const cssMapping = item[3]; + if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function(source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; - }); + const sourceMapping = toComment(cssMapping); + const sourceURLs = cssMapping.sources.map( + (source) => \`/*# sourceURL=\${cssMapping.sourceRoot}\${source} */\` + ); return [content] .concat(sourceURLs) @@ -352,11 +380,10 @@ function cssWithMappingToString(item, useSourceMap) { // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef - var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); - var data = - 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + const data = \`sourceMappingURL=data:application/json;charset=utf-8;base64,\${base64}\`; - return '/*# ' + data + ' */'; + return \`/*# \${data} */\`; } " `; @@ -371,13 +398,14 @@ exports[`loader should compile with \`css\` entry point (with \`modules\` and sc // If url is already wrapped in quotes, remove them if (/^['\\"].*['\\"]$/.test(url)) { + // eslint-disable-next-line no-param-reassign url = url.slice(1, -1); } // Should url be wrapped? // See https://drafts.csswg.org/css-values-3/#urls if (/[\\"'() \\\\t\\\\n]/.test(url) || needQuotes) { - return '\\"' + url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n') + '\\"'; + return \`\\"\${url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n')}\\"\`; } return url; @@ -580,35 +608,45 @@ exports[`loader should compile with \`css\` entry point: api 1`] = ` Author Tobias Koppers @sokra */ // css base code, injected by the css-loader +// eslint-disable-next-line func-names module.exports = function(useSourceMap) { - var list = []; + const list = []; // return the list of modules as css string list.toString = function toString() { - return this.map(function(item) { - var content = cssWithMappingToString(item, useSourceMap); + return this.map((item) => { + const content = cssWithMappingToString(item, useSourceMap); + if (item[2]) { - return '@media ' + item[2] + '{' + content + '}'; - } else { - return content; + return \`@media \${item[2]}{\${content}}\`; } + + return content; }).join(''); }; // import a list of modules into the list + // eslint-disable-next-line func-names list.i = function(modules, mediaQuery) { if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } - var alreadyImportedModules = {}; - for (var i = 0; i < this.length; i++) { - var id = this[i][0]; + + const alreadyImportedModules = {}; + + for (let i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + const id = this[i][0]; + if (id != null) { alreadyImportedModules[id] = true; } } - for (i = 0; i < modules.length; i++) { - var item = modules[i]; + + for (let i = 0; i < modules.length; i++) { + const item = modules[i]; + // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. @@ -617,27 +655,31 @@ module.exports = function(useSourceMap) { if (mediaQuery && !item[2]) { item[2] = mediaQuery; } else if (mediaQuery) { - item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; + item[2] = \`(\${item[2]}) and (\${mediaQuery})\`; } + list.push(item); } } }; + return list; }; function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; + const content = item[1] || ''; + // eslint-disable-next-line prefer-destructuring + const cssMapping = item[3]; + if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function(source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; - }); + const sourceMapping = toComment(cssMapping); + const sourceURLs = cssMapping.sources.map( + (source) => \`/*# sourceURL=\${cssMapping.sourceRoot}\${source} */\` + ); return [content] .concat(sourceURLs) @@ -651,11 +693,10 @@ function cssWithMappingToString(item, useSourceMap) { // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef - var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); - var data = - 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + const data = \`sourceMappingURL=data:application/json;charset=utf-8;base64,\${base64}\`; - return '/*# ' + data + ' */'; + return \`/*# \${data} */\`; } " `; @@ -670,13 +711,14 @@ exports[`loader should compile with \`css\` entry point: escape 1`] = ` // If url is already wrapped in quotes, remove them if (/^['\\"].*['\\"]$/.test(url)) { + // eslint-disable-next-line no-param-reassign url = url.slice(1, -1); } // Should url be wrapped? // See https://drafts.csswg.org/css-values-3/#urls if (/[\\"'() \\\\t\\\\n]/.test(url) || needQuotes) { - return '\\"' + url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n') + '\\"'; + return \`\\"\${url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n')}\\"\`; } return url; @@ -855,35 +897,45 @@ exports[`loader should compile with \`js\` entry point: api 1`] = ` Author Tobias Koppers @sokra */ // css base code, injected by the css-loader +// eslint-disable-next-line func-names module.exports = function(useSourceMap) { - var list = []; + const list = []; // return the list of modules as css string list.toString = function toString() { - return this.map(function(item) { - var content = cssWithMappingToString(item, useSourceMap); + return this.map((item) => { + const content = cssWithMappingToString(item, useSourceMap); + if (item[2]) { - return '@media ' + item[2] + '{' + content + '}'; - } else { - return content; + return \`@media \${item[2]}{\${content}}\`; } + + return content; }).join(''); }; // import a list of modules into the list + // eslint-disable-next-line func-names list.i = function(modules, mediaQuery) { if (typeof modules === 'string') { + // eslint-disable-next-line no-param-reassign modules = [[null, modules, '']]; } - var alreadyImportedModules = {}; - for (var i = 0; i < this.length; i++) { - var id = this[i][0]; + + const alreadyImportedModules = {}; + + for (let i = 0; i < this.length; i++) { + // eslint-disable-next-line prefer-destructuring + const id = this[i][0]; + if (id != null) { alreadyImportedModules[id] = true; } } - for (i = 0; i < modules.length; i++) { - var item = modules[i]; + + for (let i = 0; i < modules.length; i++) { + const item = modules[i]; + // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. @@ -892,27 +944,31 @@ module.exports = function(useSourceMap) { if (mediaQuery && !item[2]) { item[2] = mediaQuery; } else if (mediaQuery) { - item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; + item[2] = \`(\${item[2]}) and (\${mediaQuery})\`; } + list.push(item); } } }; + return list; }; function cssWithMappingToString(item, useSourceMap) { - var content = item[1] || ''; - var cssMapping = item[3]; + const content = item[1] || ''; + // eslint-disable-next-line prefer-destructuring + const cssMapping = item[3]; + if (!cssMapping) { return content; } if (useSourceMap && typeof btoa === 'function') { - var sourceMapping = toComment(cssMapping); - var sourceURLs = cssMapping.sources.map(function(source) { - return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; - }); + const sourceMapping = toComment(cssMapping); + const sourceURLs = cssMapping.sources.map( + (source) => \`/*# sourceURL=\${cssMapping.sourceRoot}\${source} */\` + ); return [content] .concat(sourceURLs) @@ -926,11 +982,10 @@ function cssWithMappingToString(item, useSourceMap) { // Adapted from convert-source-map (MIT) function toComment(sourceMap) { // eslint-disable-next-line no-undef - var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); - var data = - 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; + const base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); + const data = \`sourceMappingURL=data:application/json;charset=utf-8;base64,\${base64}\`; - return '/*# ' + data + ' */'; + return \`/*# \${data} */\`; } " `; @@ -945,13 +1000,14 @@ exports[`loader should compile with \`js\` entry point: escape 1`] = ` // If url is already wrapped in quotes, remove them if (/^['\\"].*['\\"]$/.test(url)) { + // eslint-disable-next-line no-param-reassign url = url.slice(1, -1); } // Should url be wrapped? // See https://drafts.csswg.org/css-values-3/#urls if (/[\\"'() \\\\t\\\\n]/.test(url) || needQuotes) { - return '\\"' + url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n') + '\\"'; + return \`\\"\${url.replace(/\\"/g, '\\\\\\\\\\"').replace(/\\\\n/g, '\\\\\\\\n')}\\"\`; } return url;