This commit is contained in:
2022-07-18 02:50:52 +00:00
parent befd344ab0
commit 06181b34d6
8569 changed files with 818704 additions and 352705 deletions
+89
View File
@@ -2,6 +2,95 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [4.3.0](https://github.com/webpack-contrib/css-loader/compare/v4.2.2...v4.3.0) (2020-09-08)
### Features
* the `importLoaders` can be `string` ([#1178](https://github.com/webpack-contrib/css-loader/issues/1178)) ([ec58a7c](https://github.com/webpack-contrib/css-loader/commit/ec58a7cfda46443e35539d66b86685195fa5db03))
### Bug Fixes
* line breaks in `url` function ([88b8ddc](https://github.com/webpack-contrib/css-loader/commit/88b8ddc1d78a2b6a917ed2dfe2f2a37cf6a84190))
### [4.2.2](https://github.com/webpack-contrib/css-loader/compare/v4.2.1...v4.2.2) (2020-08-24)
### Bug Fixes
* source maps generation, source from source maps are now relative to `compiler.context` and use `webpack://` protocol ([#1169](https://github.com/webpack-contrib/css-loader/issues/1169)) ([fb5c53d](https://github.com/webpack-contrib/css-loader/commit/fb5c53d80b10ee698762238bb7b122aec8c5048d))
### [4.2.1](https://github.com/webpack-contrib/css-loader/compare/v4.2.0...v4.2.1) (2020-08-06)
### Bug Fixes
* regression with the `exportOnlyLocals` option, now `locals` are not exported under the `locals` name, it was big regression, we apologize for that ([24c0a12](https://github.com/webpack-contrib/css-loader/commit/24c0a122d1396c08326a24f6184f5da09cf52ccc))
## [4.2.0](https://github.com/webpack-contrib/css-loader/compare/v4.1.1...v4.2.0) (2020-07-31)
### Features
* add `module.type` option, the `icss` option is deprecated ([#1150](https://github.com/webpack-contrib/css-loader/issues/1150)) ([68f72af](https://github.com/webpack-contrib/css-loader/commit/68f72af2a09111f74dcacbf7af019fe7eb40cb6c))
### [4.1.1](https://github.com/webpack-contrib/css-loader/compare/v4.1.0...v4.1.1) (2020-07-30)
### Bug Fixes
* remove unnecessary `console` call ([#1148](https://github.com/webpack-contrib/css-loader/issues/1148)) ([b1b90ca](https://github.com/webpack-contrib/css-loader/commit/b1b90caaea8eb045177749729340c7906454a84b))
## [4.1.0](https://github.com/webpack-contrib/css-loader/compare/v4.0.0...v4.1.0) (2020-07-29)
### Features
* add `icss` option ([#1140](https://github.com/webpack-contrib/css-loader/issues/1140)) ([a8ec7da](https://github.com/webpack-contrib/css-loader/commit/a8ec7da42234e0b2eb061d2a920669940bcbdf05))
* support absolute paths ([f9ba0ce](https://github.com/webpack-contrib/css-loader/commit/f9ba0ce11789770c4c9220478e9c98dbd432a5d6))
### Bug Fixes
* do not crash with `data` URLs ([#1142](https://github.com/webpack-contrib/css-loader/issues/1142)) ([91bc64b](https://github.com/webpack-contrib/css-loader/commit/91bc64b81abfeffd174639a8fdf2366412c11426))
* performance ([#1144](https://github.com/webpack-contrib/css-loader/issues/1144)) ([4f1baa2](https://github.com/webpack-contrib/css-loader/commit/4f1baa211eb27b0b281ba9f262fa12e8aaefc0ba))
## [4.0.0](https://github.com/webpack-contrib/css-loader/compare/v3.6.0...v4.0.0) (2020-07-25)
### ⚠ BREAKING CHANGES
* minimum required `Node.js` version is `10.13.0`
* minimum required `webpack` version is `4.27.0`
* the `esModule` option is `true` by default
* default value of the `sourceMap` option depends on the `devtool` option
* `icss` plugin disable by default, you need to setup the `modules` option to enable it
* the `modules` option is `true` by default for all files matching `/\.module\.\w+$/i.test(filename)` regular expression, `module.auto` is `true` by default
* the `modules.context` option was renamed to the `modules.localIdentContext` option
* default the `modules.localIdentContext` value is `compiler.context` for the `module.getLocalIdent` option
* the `modules.hashPrefix` option was renamed to the `modules.localIdentHashPrefix` option
* the `localsConvention` option was moved and renamed to the `modules.exportLocalsConvention` option
* the `getLocalIndent` option should be always `Function` and should always return `String` value
* the `onlyLocals` option was moved and renamed to the `modules.exportOnlyLocals` option
* function arguments of the `import` option were changed, it is now `function(url, media, resourcePath) {}`
* inline syntax was changed, please write `~` before the file request, i.e. rewrite `url(~!!loader!package/img.png)` to `url(!!loader!~package/img.png)`
### Features
* `@value` supports importing `url()` ([#1126](https://github.com/webpack-contrib/css-loader/issues/1126)) ([7f49a0a](https://github.com/webpack-contrib/css-loader/commit/7f49a0a6047846bb2e432558365e19d4a0dfb366))
* improve `url()` resolving algorithm ([bc19ddd](https://github.com/webpack-contrib/css-loader/commit/bc19ddd8779dafbc2a420870a3cb841041ce9c7c))
* named export for locals ([#1108](https://github.com/webpack-contrib/css-loader/issues/1108)) ([d139ec1](https://github.com/webpack-contrib/css-loader/commit/d139ec1d763f9944550b31f2a75183e488dd1224))
* respected the `style` field from package.json ([#1099](https://github.com/webpack-contrib/css-loader/issues/1099)) ([edf5347](https://github.com/webpack-contrib/css-loader/commit/edf5347e4203a62e50b87248a83da198afdc6eba))
* support `file:` protocol ([5604205](https://github.com/webpack-contrib/css-loader/commit/560420567eb0e1a635648b7f4ff0365db475384c))
* support server relative URLs
### Bug Fixes
* resolution algorithm, you don't need `~` inside packages in `node_modules` ([76f1480](https://github.com/webpack-contrib/css-loader/commit/76f1480b14265369ac5dc8dbbce467cfb8e814c5))
## [3.6.0](https://github.com/webpack-contrib/css-loader/compare/v3.5.3...v3.6.0) (2020-06-13)
+395 -172
View File
@@ -109,16 +109,14 @@ module.exports = {
## Options
| Name | Type | Default | Description |
| :-----------------------------------------: | :-------------------------: | :------: | :--------------------------------------------------------------------- |
| **[`url`](#url)** | `{Boolean\|Function}` | `true` | Enables/Disables `url`/`image-set` functions handling |
| **[`import`](#import)** | `{Boolean\|Function}` | `true` | Enables/Disables `@import` at-rules handling |
| **[`modules`](#modules)** | `{Boolean\|String\|Object}` | `false` | Enables/Disables CSS Modules and their configuration |
| **[`sourceMap`](#sourcemap)** | `{Boolean}` | `false` | Enables/Disables generation of source maps |
| **[`importLoaders`](#importloaders)** | `{Number}` | `0` | Enables/Disables or setups number of loaders applied before CSS loader |
| **[`localsConvention`](#localsconvention)** | `{String}` | `'asIs'` | Style of exported classnames |
| **[`onlyLocals`](#onlylocals)** | `{Boolean}` | `false` | Export only locals |
| **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
| Name | Type | Default | Description |
| :-----------------------------------: | :-------------------------: | :----------------: | :--------------------------------------------------------------------- |
| **[`url`](#url)** | `{Boolean\|Function}` | `true` | Enables/Disables `url`/`image-set` functions handling |
| **[`import`](#import)** | `{Boolean\|Function}` | `true` | Enables/Disables `@import` at-rules handling |
| **[`modules`](#modules)** | `{Boolean\|String\|Object}` | `{auto: true}` | Enables/Disables CSS Modules and their configuration |
| **[`sourceMap`](#sourcemap)** | `{Boolean}` | `compiler.devtool` | Enables/Disables generation of source maps |
| **[`importLoaders`](#importloaders)** | `{Number}` | `0` | Enables/Disables or setups number of loaders applied before CSS loader |
| **[`esModule`](#esmodule)** | `{Boolean}` | `true` | Use ES modules syntax |
### `url`
@@ -126,7 +124,7 @@ Type: `Boolean|Function`
Default: `true`
Enables/Disables `url`/`image-set` functions handling.
Control `url()` resolving. Absolute URLs and root-relative URLs are not resolving.
Control `url()` resolving. Absolute URLs are not resolving.
Examples resolutions:
@@ -264,13 +262,11 @@ module.exports = {
test: /\.css$/i,
loader: 'css-loader',
options: {
import: (parsedImport, resourcePath) => {
// parsedImport.url - url of `@import`
// parsedImport.media - media query of `@import`
import: (url, media, resourcePath) => {
// resourcePath - path to css file
// Don't handle `style.css` import
if (parsedImport.url.includes('style.css')) {
if (url.includes('style.css')) {
return false;
}
@@ -286,7 +282,7 @@ module.exports = {
### `modules`
Type: `Boolean|String|Object`
Default: `false`
Default: based on filename, `true` for all files matching `/\.module\.\w+$/i.test(filename)` regular expression, more information you can read [here](https://github.com/webpack-contrib/css-loader#auto)
Enables/Disables CSS Modules and their configuration.
@@ -415,6 +411,8 @@ exports.locals = {
To import a local classname from another module.
> i We strongly recommend that you specify the extension when importing a file, since it is possible to import a file with any extension and it is not known in advance which file to use.
```css
:local(.continueButton) {
composes: button from 'library/button.css';
@@ -527,11 +525,48 @@ module.exports = {
loader: 'css-loader',
options: {
modules: {
compileType: 'module',
mode: 'local',
auto: true,
exportGlobals: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
context: path.resolve(__dirname, 'src'),
hashPrefix: 'my-custom-hash',
localIdentHashPrefix: 'my-custom-hash',
namedExport: true,
exportLocalsConvention: 'camelCase',
exportOnlyLocals: false,
},
},
},
],
},
};
```
##### `compileType`
Type: `'module' | 'icss'`
Default: `'module'`
Controls the level of compilation applied to the input styles.
The `module` handles `class` and `id` scoping and `@value` values.
The `icss` will only compile the low level `Interoperable CSS` format for declaring `:import` and `:export` dependencies between CSS and other languages.
ICSS underpins CSS Module support, and provides a low level syntax for other tools to implement CSS-module variations of their own.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
compileType: 'icss',
},
},
},
@@ -543,9 +578,9 @@ module.exports = {
##### `auto`
Type: `Boolean|RegExp|Function`
Default: `'undefined'`
Default: `'true'`
Allows auto enable css modules based on filename.
Allows auto enable CSS modules based on filename.
###### `Boolean`
@@ -690,39 +725,12 @@ module.exports = {
};
```
##### `exportGlobals`
Type: `Boolean`
Default: `false`
Allow `css-loader` to export names from global class or id, so you can use that as local name.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
exportGlobals: true,
},
},
},
],
},
};
```
##### `localIdentName`
Type: `String`
Default: `'[hash:base64]'`
You can configure the generated ident with the `localIdentName` query parameter.
Allows to configure the generated local ident name.
See [loader-utils's documentation](https://github.com/webpack/loader-utils#interpolatename) for more information on options.
Recommendations:
@@ -754,13 +762,12 @@ module.exports = {
};
```
##### `context`
##### `localIdentContext`
Type: `String`
Default: `undefined`
Default: `compiler.context`
Allow to redefine basic loader context for local ident name.
By default we use `rootContext` of loader.
Allows to redefine basic loader context for local ident name.
**webpack.config.js**
@@ -782,12 +789,12 @@ module.exports = {
};
```
##### `hashPrefix`
##### `localIdentHashPrefix`
Type: `String`
Default: `undefined`
Allow to add custom hash to generate more unique classes.
Allows to add custom hash to generate more unique classes.
**webpack.config.js**
@@ -800,37 +807,7 @@ module.exports = {
loader: 'css-loader',
options: {
modules: {
hashPrefix: 'hash',
},
},
},
],
},
};
```
##### `getLocalIdent`
Type: `Function`
Default: `undefined`
You can also specify the absolute path to your custom `getLocalIdent` function to generate classname based on a different schema.
By default we use built-in function to generate a classname.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
getLocalIdent: (context, localIdentName, localName, options) => {
return 'whatever_random_class_name';
},
localIdentHashPrefix: 'hash',
},
},
},
@@ -864,16 +841,204 @@ module.exports = {
};
```
### `sourceMap`
##### `getLocalIdent`
Type: `Function`
Default: `undefined`
Allows to specify a function to generate the classname.
By default we use built-in function to generate a classname.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
getLocalIdent: (context, localIdentName, localName, options) => {
return 'whatever_random_class_name';
},
},
},
},
],
},
};
```
##### `namedExport`
Type: `Boolean`
Default: `false`
Enables/Disables generation of source maps.
Enables/disables ES modules named export for locals.
To include source maps set the `sourceMap` option.
> ⚠ Names of locals are converted to camelcase, i.e. the `exportLocalsConvention` option has `camelCaseOnly` value by default.
They are not enabled by default because they expose a runtime overhead and increase in bundle size (JS source maps do not).
> ⚠ It is not allowed to use JavaScript reserved words in css class names.
**styles.css**
```css
.foo-baz {
color: red;
}
.bar {
color: blue;
}
```
**index.js**
```js
import { fooBaz, bar } from './styles.css';
console.log(fooBaz, bar);
```
You can enable a ES module named export using:
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
esModule: true,
modules: {
namedExport: true,
},
},
},
],
},
};
```
##### `exportGlobals`
Type: `Boolean`
Default: `false`
Allow `css-loader` to export names from global class or id, so you can use that as local name.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
exportGlobals: true,
},
},
},
],
},
};
```
##### `exportLocalsConvention`
Type: `String`
Default: based on the `modules.namedExport` option value, if `true` - `camelCaseOnly`, otherwise `asIs`
Style of exported class names.
By default, the exported JSON keys mirror the class names (i.e `asIs` value).
> ⚠ Only `camelCaseOnly` value allowed if you set the `namedExport` value to `true`.
| Name | Type | Description |
| :-------------------: | :--------: | :----------------------------------------------------------------------------------------------- |
| **`'asIs'`** | `{String}` | Class names will be exported as is. |
| **`'camelCase'`** | `{String}` | Class names will be camelized, the original class name will not to be removed from the locals |
| **`'camelCaseOnly'`** | `{String}` | Class names will be camelized, the original class name will be removed from the locals |
| **`'dashes'`** | `{String}` | Only dashes in class names will be camelized |
| **`'dashesOnly'`** | `{String}` | Dashes in class names will be camelized, the original class name will be removed from the locals |
**file.css**
```css
.class-name {
}
```
**file.js**
```js
import { className } from 'file.css';
```
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
mode: 'local',
localsConvention: 'camelCase',
},
},
],
},
};
```
##### `exportOnlyLocals`
Type: `Boolean`
Default: `false`
Export only locals.
**Useful** when you use **css modules** for pre-rendering (for example SSR).
For pre-rendering with `mini-css-extract-plugin` you should use this option instead of `style-loader!css-loader` **in the pre-rendering bundle**.
It doesn't embed CSS but only exports the identifier mappings.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
modules: {
exportOnlyLocals: true,
},
},
},
],
},
};
```
### `sourceMap`
Type: `Boolean`
Default: depends on the `compiler.devtool` value
By default generation of source maps depends on the [`devtool`](https://webpack.js.org/configuration/devtool/) option. All values enable source map generation except `eval` and `false` value.
**webpack.config.js**
@@ -932,92 +1097,15 @@ module.exports = {
This may change in the future when the module system (i. e. webpack) supports loader matching by origin.
### `localsConvention`
Type: `String`
Default: `'asIs'`
Style of exported classnames.
By default, the exported JSON keys mirror the class names (i.e `asIs` value).
| Name | Type | Description |
| :-------------------: | :--------: | :----------------------------------------------------------------------------------------------- |
| **`'asIs'`** | `{String}` | Class names will be exported as is. |
| **`'camelCase'`** | `{String}` | Class names will be camelized, the original class name will not to be removed from the locals |
| **`'camelCaseOnly'`** | `{String}` | Class names will be camelized, the original class name will be removed from the locals |
| **`'dashes'`** | `{String}` | Only dashes in class names will be camelized |
| **`'dashesOnly'`** | `{String}` | Dashes in class names will be camelized, the original class name will be removed from the locals |
**file.css**
```css
.class-name {
}
```
**file.js**
```js
import { className } from 'file.css';
```
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
localsConvention: 'camelCase',
},
},
],
},
};
```
### `onlyLocals`
Type: `Boolean`
Default: `false`
Export only locals.
**Useful** when you use **css modules** for pre-rendering (for example SSR).
For pre-rendering with `mini-css-extract-plugin` you should use this option instead of `style-loader!css-loader` **in the pre-rendering bundle**.
It doesn't embed CSS but only exports the identifier mappings.
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
loader: 'css-loader',
options: {
onlyLocals: true,
},
},
],
},
};
```
### `esModule`
Type: `Boolean`
Default: `false`
Default: `true`
By default, `css-loader` generates JS modules that use the CommonJS modules syntax.
By default, `css-loader` generates JS modules that use the ES modules syntax.
There are some cases in which using ES modules is beneficial, like in the case of [module concatenation](https://webpack.js.org/plugins/module-concatenation-plugin/) and [tree shaking](https://webpack.js.org/guides/tree-shaking/).
You can enable a ES module syntax using:
You can enable a CommonJS modules syntax using:
**webpack.config.js**
@@ -1029,7 +1117,7 @@ module.exports = {
test: /\.css$/i,
loader: 'css-loader',
options: {
esModule: true,
esModule: false,
},
},
],
@@ -1084,7 +1172,6 @@ module.exports = {
module: {
rules: [
{
// For CSS modules
// For pure CSS - /\.css$/i,
// For Sass/SCSS - /\.((c|sa|sc)ss)$/i,
// For Less - /\.((c|le)ss)$/i,
@@ -1106,9 +1193,7 @@ module.exports = {
options: { plugins: () => [postcssPresetEnv({ stage: 0 })] },
},
// Can be `less-loader`
// The `test` property should be `\.less/i`
{
test: /\.s[ac]ss$/i,
loader: 'sass-loader',
},
],
@@ -1125,6 +1210,144 @@ module.exports = {
};
```
### Resolve unresolved URLs using an alias
**index.css**
```css
.class {
background: url(/assets/unresolved/img.png);
}
```
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
alias: {
'/assets/unresolved/img.png': path.resolve(
__dirname,
'assets/real-path-to-img/img.png'
),
},
},
};
```
### Separating `Interoperable CSS`-only and `CSS Module` features
The following setup is an example of allowing `Interoperable CSS` features only (such as `:import` and `:export`) without using further `CSS Module` functionality by setting `compileType` option for all files that do not match `*.module.scss` naming convention. This is for reference as having `ICSS` features applied to all files was default `css-loader` behavior before v4.
Meanwhile all files matching `*.module.scss` are treated as `CSS Modules` in this example.
An example case is assumed where a project requires canvas drawing variables to be synchronized with CSS - canvas drawing uses the same color (set by color name in JavaScript) as HTML background (set by class name in CSS).
**webpack.config.js**
```js
module.exports = {
module: {
rules: [
// ...
// --------
// SCSS ALL EXCEPT MODULES
{
test: /\.scss$/,
exclude: /\.module\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
compileType: 'icss'
}
}
},
{
loader: 'sass-loader'
},
],
},
// --------
// SCSS MODULES
{
test: /\.module\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: {
compileType: 'module'
}
}
},
{
loader: 'sass-loader'
},
],
},
// --------
// ...
},
};
```
**variables.scss**
File treated as `ICSS`-only.
```scss
$colorBackground: red;
:export {
colorBackgroundCanvas: $colorBackground;
}
```
**Component.module.scss**
File treated as `CSS Module`.
```scss
@import 'variables.scss';
.componentClass {
background-color: $colorBackground;
}
```
**Component.jsx**
Using both `CSS Module` functionality as well as SCSS variables directly in JavaScript.
```jsx
import svars from 'variables.scss';
import styles from 'Component.module.scss';
// Render DOM with CSS modules class name
// <div className={styles.componentClass}>
// <canvas ref={mountsCanvas}/>
// </div>
// Somewhere in JavaScript canvas drawing code use the variable directly
// const ctx = mountsCanvas.current.getContext('2d',{alpha: false});
ctx.fillStyle = `${svars.colorBackgroundCanvas}`;
```
## Contributing
Please take a moment to read our contributing guidelines if you haven't yet done so.
+105 -72
View File
@@ -31,41 +31,92 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function loader(content, map, meta) {
const options = (0, _loaderUtils.getOptions)(this) || {};
(0, _schemaUtils.default)(_options.default, options, {
async function loader(content, map, meta) {
const rawOptions = (0, _loaderUtils.getOptions)(this);
(0, _schemaUtils.default)(_options.default, rawOptions, {
name: 'CSS Loader',
baseDataPath: 'options'
});
const callback = this.async();
const sourceMap = options.sourceMap || false;
const plugins = [];
const callback = this.async();
let options;
if ((0, _utils.shouldUseModulesPlugins)(options.modules, this.resourcePath)) {
try {
options = (0, _utils.normalizeOptions)(rawOptions, this);
} catch (error) {
callback(error);
return;
}
const replacements = [];
const exports = [];
if ((0, _utils.shouldUseModulesPlugins)(options)) {
plugins.push(...(0, _utils.getModulesPlugins)(options, this));
}
const exportType = options.onlyLocals ? 'locals' : 'full';
const preRequester = (0, _utils.getPreRequester)(this);
const importPluginImports = [];
const importPluginApi = [];
const urlHandler = url => (0, _loaderUtils.stringifyRequest)(this, preRequester(options.importLoaders) + url);
plugins.push((0, _plugins.icssParser)({
urlHandler
}));
if (options.import !== false && exportType === 'full') {
if ((0, _utils.shouldUseImportPlugin)(options)) {
const resolver = this.getResolve({
conditionNames: ['style'],
extensions: ['.css'],
mainFields: ['css', 'style', 'main', '...'],
mainFiles: ['index', '...'],
restrictions: [/\.css$/i]
});
plugins.push((0, _plugins.importParser)({
imports: importPluginImports,
api: importPluginApi,
context: this.context,
rootContext: this.rootContext,
filter: (0, _utils.getFilter)(options.import, this.resourcePath),
urlHandler
resolver,
urlHandler: url => (0, _loaderUtils.stringifyRequest)(this, (0, _utils.getPreRequester)(this)(options.importLoaders) + url)
}));
}
if (options.url !== false && exportType === 'full') {
const urlPluginImports = [];
if ((0, _utils.shouldUseURLPlugin)(options)) {
const urlResolver = this.getResolve({
conditionNames: ['asset'],
mainFields: ['asset'],
mainFiles: [],
extensions: []
});
plugins.push((0, _plugins.urlParser)({
filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value)),
imports: urlPluginImports,
replacements,
context: this.context,
rootContext: this.rootContext,
filter: (0, _utils.getFilter)(options.url, this.resourcePath),
resolver: urlResolver,
urlHandler: url => (0, _loaderUtils.stringifyRequest)(this, url)
}));
}
const icssPluginImports = [];
const icssPluginApi = [];
if ((0, _utils.shouldUseIcssPlugin)(options)) {
const icssResolver = this.getResolve({
conditionNames: ['style'],
extensions: [],
mainFields: ['css', 'style', 'main', '...'],
mainFiles: ['index', '...']
});
plugins.push((0, _plugins.icssParser)({
imports: icssPluginImports,
api: icssPluginApi,
replacements,
exports,
context: this.context,
rootContext: this.rootContext,
resolver: icssResolver,
urlHandler: url => (0, _loaderUtils.stringifyRequest)(this, (0, _utils.getPreRequester)(this)(options.importLoaders) + url)
}));
} // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
@@ -80,64 +131,46 @@ function loader(content, map, meta) {
}
}
(0, _postcss.default)(plugins).process(content, {
from: this.resourcePath,
to: this.resourcePath,
map: options.sourceMap ? {
// Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
prev: sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null,
inline: false,
annotation: false
} : false
}).then(result => {
for (const warning of result.warnings()) {
this.emitWarning(new _Warning.default(warning));
}
const {
resourcePath
} = this;
let result;
const imports = [];
const apiImports = [];
const urlReplacements = [];
const icssReplacements = [];
const exports = [];
for (const message of result.messages) {
// eslint-disable-next-line default-case
switch (message.type) {
case 'import':
imports.push(message.value);
break;
case 'api-import':
apiImports.push(message.value);
break;
case 'url-replacement':
urlReplacements.push(message.value);
break;
case 'icss-replacement':
icssReplacements.push(message.value);
break;
case 'export':
exports.push(message.value);
break;
}
}
const {
localsConvention
} = options;
const esModule = typeof options.esModule !== 'undefined' ? options.esModule : false;
const importCode = (0, _utils.getImportCode)(this, exportType, imports, esModule);
const moduleCode = (0, _utils.getModuleCode)(result, exportType, sourceMap, apiImports, urlReplacements, icssReplacements, esModule);
const exportCode = (0, _utils.getExportCode)(exports, exportType, localsConvention, icssReplacements, esModule);
return callback(null, `${importCode}${moduleCode}${exportCode}`);
}).catch(error => {
try {
result = await (0, _postcss.default)(plugins).process(content, {
from: resourcePath,
to: resourcePath,
map: options.sourceMap ? {
prev: map ? (0, _utils.normalizeSourceMap)(map, resourcePath) : null,
inline: false,
annotation: false
} : false
});
} catch (error) {
if (error.file) {
this.addDependency(error.file);
}
callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
});
return;
}
for (const warning of result.warnings()) {
this.emitWarning(new _Warning.default(warning));
}
const imports = [].concat(icssPluginImports.sort(_utils.sort)).concat(importPluginImports.sort(_utils.sort)).concat(urlPluginImports.sort(_utils.sort));
const api = [].concat(importPluginApi.sort(_utils.sort)).concat(icssPluginApi.sort(_utils.sort));
if (options.modules.exportOnlyLocals !== true) {
imports.unshift({
importName: '___CSS_LOADER_API_IMPORT___',
url: (0, _loaderUtils.stringifyRequest)(this, require.resolve('./runtime/api'))
});
}
const importCode = (0, _utils.getImportCode)(imports, options);
const moduleCode = (0, _utils.getModuleCode)(result, api, replacements, options, this);
const exportCode = (0, _utils.getExportCode)(exports, replacements, options);
callback(null, `${importCode}${moduleCode}${exportCode}`);
}
+52 -26
View File
@@ -36,7 +36,12 @@
"type": "object",
"additionalProperties": false,
"properties": {
"compileType": {
"description": "Controls the extent to which css-loader will process module code (https://github.com/webpack-contrib/css-loader#type)",
"enum": ["module", "icss"]
},
"auto": {
"description": "Allows auto enable CSS modules based on filename (https://github.com/webpack-contrib/css-loader#auto).",
"anyOf": [
{
"instanceof": "RegExp"
@@ -50,6 +55,7 @@
]
},
"mode": {
"description": "Setup `mode` option (https://github.com/webpack-contrib/css-loader#mode).",
"anyOf": [
{
"enum": ["local", "global", "pure"]
@@ -59,42 +65,67 @@
}
]
},
"exportGlobals": {
"type": "boolean"
},
"localIdentName": {
"type": "string"
"description": "Allows to configure the generated local ident name (https://github.com/webpack-contrib/css-loader#localidentname).",
"type": "string",
"minLength": 1
},
"localIdentContext": {
"description": "Allows to redefine basic loader context for local ident name (https://github.com/webpack-contrib/css-loader#localidentcontext).",
"type": "string",
"minLength": 1
},
"localIdentHashPrefix": {
"description": "Allows to add custom hash to generate more unique classes (https://github.com/webpack-contrib/css-loader#localidenthashprefix).",
"type": "string",
"minLength": 1
},
"localIdentRegExp": {
"description": "Allows to specify custom RegExp for local ident name (https://github.com/webpack-contrib/css-loader#localidentregexp).",
"anyOf": [
{
"type": "string"
"type": "string",
"minLength": 1
},
{
"instanceof": "RegExp"
}
]
},
"context": {
"type": "string"
},
"hashPrefix": {
"type": "string"
},
"getLocalIdent": {
"anyOf": [
{
"type": "boolean"
},
{
"instanceof": "Function"
}
"description": "Allows to specify a function to generate the classname (https://github.com/webpack-contrib/css-loader#getlocalident).",
"instanceof": "Function"
},
"namedExport": {
"description": "Enables/disables ES modules named export for locals (https://github.com/webpack-contrib/css-loader#namedexport).",
"type": "boolean"
},
"exportGlobals": {
"description": "Allows to export names from global class or id, so you can use that as local name (https://github.com/webpack-contrib/css-loader#exportglobals).",
"type": "boolean"
},
"exportLocalsConvention": {
"description": "Style of exported classnames (https://github.com/webpack-contrib/css-loader#localsconvention).",
"enum": [
"asIs",
"camelCase",
"camelCaseOnly",
"dashes",
"dashesOnly"
]
},
"exportOnlyLocals": {
"description": "Export only locals (https://github.com/webpack-contrib/css-loader#exportonlylocals).",
"type": "boolean"
}
}
}
]
},
"icss": {
"description": "Enables/Disables handling the CSS module interoperable import/export format ((https://github.com/webpack-contrib/css-loader#icss)",
"type": "boolean"
},
"sourceMap": {
"description": "Enables/Disables generation of source maps (https://github.com/webpack-contrib/css-loader#sourcemap).",
"type": "boolean"
@@ -105,19 +136,14 @@
{
"type": "boolean"
},
{
"type": "string"
},
{
"type": "integer"
}
]
},
"localsConvention": {
"description": "Style of exported classnames (https://github.com/webpack-contrib/css-loader#localsconvention).",
"enum": ["asIs", "camelCase", "camelCaseOnly", "dashes", "dashesOnly"]
},
"onlyLocals": {
"description": "Export only locals (https://github.com/webpack-contrib/css-loader#onlylocals).",
"type": "boolean"
},
"esModule": {
"description": "Use the ES modules syntax (https://github.com/webpack-contrib/css-loader#esmodule).",
"type": "boolean"
+80 -67
View File
@@ -9,70 +9,90 @@ var _postcss = _interopRequireDefault(require("postcss"));
var _icssUtils = require("icss-utils");
var _loaderUtils = require("loader-utils");
var _utils = require("../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function makeRequestableIcssImports(icssImports) {
return Object.keys(icssImports).reduce((accumulator, url) => {
const tokensMap = icssImports[url];
const tokens = Object.keys(tokensMap);
if (tokens.length === 0) {
return accumulator;
}
const normalizedUrl = (0, _loaderUtils.urlToRequest)(url);
if (!accumulator[normalizedUrl]) {
// eslint-disable-next-line no-param-reassign
accumulator[normalizedUrl] = tokensMap;
} else {
// eslint-disable-next-line no-param-reassign
accumulator[normalizedUrl] = { ...accumulator[normalizedUrl],
...tokensMap
};
}
return accumulator;
}, {});
}
var _default = _postcss.default.plugin('postcss-icss-parser', options => (css, result) => {
var _default = _postcss.default.plugin('postcss-icss-parser', options => async css => {
const importReplacements = Object.create(null);
const extractedICSS = (0, _icssUtils.extractICSS)(css);
const icssImports = makeRequestableIcssImports(extractedICSS.icssImports);
const {
icssImports,
icssExports
} = (0, _icssUtils.extractICSS)(css);
const imports = new Map();
const tasks = []; // eslint-disable-next-line guard-for-in
for (const [importIndex, url] of Object.keys(icssImports).entries()) {
const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;
result.messages.push({
type: 'import',
value: {
importName,
url: options.urlHandler ? options.urlHandler(url) : url
}
}, {
type: 'api-import',
value: {
type: 'internal',
importName,
dedupe: true
}
});
const tokenMap = icssImports[url];
const tokens = Object.keys(tokenMap);
for (const url in icssImports) {
const tokens = icssImports[url];
for (const [replacementIndex, token] of tokens.entries()) {
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
const localName = tokenMap[token];
if (Object.keys(tokens).length === 0) {
// eslint-disable-next-line no-continue
continue;
}
let normalizedUrl = url;
let prefix = '';
const queryParts = normalizedUrl.split('!');
if (queryParts.length > 1) {
normalizedUrl = queryParts.pop();
prefix = queryParts.join('!');
}
const request = (0, _utils.requestify)((0, _utils.normalizeUrl)(normalizedUrl, true), options.rootContext);
const doResolve = async () => {
const {
resolver,
context
} = options;
const resolvedUrl = await (0, _utils.resolveRequests)(resolver, context, [...new Set([normalizedUrl, request])]);
return {
url: resolvedUrl,
prefix,
tokens
};
};
tasks.push(doResolve());
}
const results = await Promise.all(tasks);
for (let index = 0; index <= results.length - 1; index++) {
const {
url,
prefix,
tokens
} = results[index];
const newUrl = prefix ? `${prefix}!${url}` : url;
const importKey = newUrl;
let importName = imports.get(importKey);
if (!importName) {
importName = `___CSS_LOADER_ICSS_IMPORT_${imports.size}___`;
imports.set(importKey, importName);
options.imports.push({
importName,
url: options.urlHandler(newUrl),
icss: true,
index
});
options.api.push({
importName,
dedupe: true,
index
});
}
for (const [replacementIndex, token] of Object.keys(tokens).entries()) {
const replacementName = `___CSS_LOADER_ICSS_IMPORT_${index}_REPLACEMENT_${replacementIndex}___`;
const localName = tokens[token];
importReplacements[token] = replacementName;
result.messages.push({
type: 'icss-replacement',
value: {
replacementName,
importName,
localName
}
options.replacements.push({
replacementName,
importName,
localName
});
}
}
@@ -81,18 +101,11 @@ var _default = _postcss.default.plugin('postcss-icss-parser', options => (css, r
(0, _icssUtils.replaceSymbols)(css, importReplacements);
}
const {
icssExports
} = extractedICSS;
for (const name of Object.keys(icssExports)) {
const value = (0, _icssUtils.replaceValueSymbols)(icssExports[name], importReplacements);
result.messages.push({
type: 'export',
value: {
name,
value
}
options.exports.push({
name,
value
});
}
});
+124 -51
View File
@@ -5,20 +5,20 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = void 0;
var _util = require("util");
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
var _loaderUtils = require("loader-utils");
var _utils = require("../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const pluginName = 'postcss-import-parser';
var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
const importsMap = new Map();
function walkAtRules(css, result, options, callback) {
const accumulator = [];
css.walkAtRules(/^import$/i, atRule => {
// Convert only top-level @import
if (atRule.parent.type !== 'root') {
@@ -34,11 +34,11 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
}
const {
nodes
nodes: paramsNodes
} = (0, _postcssValueParser.default)(atRule.params); // No nodes - `@import ;`
// Invalid type - `@import foo-bar;`
if (nodes.length === 0 || nodes[0].type !== 'string' && nodes[0].type !== 'function') {
if (paramsNodes.length === 0 || paramsNodes[0].type !== 'string' && paramsNodes[0].type !== 'function') {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule
});
@@ -48,20 +48,20 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
let isStringValue;
let url;
if (nodes[0].type === 'string') {
if (paramsNodes[0].type === 'string') {
isStringValue = true;
url = nodes[0].value;
} else if (nodes[0].type === 'function') {
url = paramsNodes[0].value;
} else {
// Invalid function - `@import nourl(test.css);`
if (nodes[0].value.toLowerCase() !== 'url') {
if (paramsNodes[0].value.toLowerCase() !== 'url') {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule
});
return;
}
isStringValue = nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
url = isStringValue ? nodes[0].nodes[0].value : _postcssValueParser.default.stringify(nodes[0].nodes);
isStringValue = paramsNodes[0].nodes.length !== 0 && paramsNodes[0].nodes[0].type === 'string';
url = isStringValue ? paramsNodes[0].nodes[0].value : _postcssValueParser.default.stringify(paramsNodes[0].nodes);
} // Empty url - `@import "";` or `@import url();`
@@ -72,70 +72,143 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
return;
}
const isRequestable = (0, _loaderUtils.isUrlRequest)(url);
accumulator.push({
atRule,
url,
isStringValue,
mediaNodes: paramsNodes.slice(1)
});
});
callback(null, accumulator);
}
const asyncWalkAtRules = (0, _util.promisify)(walkAtRules);
var _default = _postcss.default.plugin(pluginName, options => async (css, result) => {
const parsedResults = await asyncWalkAtRules(css, result, options);
if (parsedResults.length === 0) {
return Promise.resolve();
}
const imports = new Map();
const tasks = [];
for (const parsedResult of parsedResults) {
const {
atRule,
url,
isStringValue,
mediaNodes
} = parsedResult;
let normalizedUrl = url;
let prefix = '';
const isRequestable = (0, _utils.isUrlRequestable)(normalizedUrl);
if (isRequestable) {
url = (0, _utils.normalizeUrl)(url, isStringValue); // Empty url after normalize - `@import '\
const queryParts = normalizedUrl.split('!');
if (queryParts.length > 1) {
normalizedUrl = queryParts.pop();
prefix = queryParts.join('!');
}
normalizedUrl = (0, _utils.normalizeUrl)(normalizedUrl, isStringValue); // Empty url after normalize - `@import '\
// \
// \
// ';
if (url.trim().length === 0) {
if (normalizedUrl.trim().length === 0) {
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
node: atRule
});
return;
}); // eslint-disable-next-line no-continue
continue;
}
}
const media = _postcssValueParser.default.stringify(nodes.slice(1)).trim().toLowerCase();
let media;
if (options.filter && !options.filter({
url,
media
})) {
return;
if (mediaNodes.length > 0) {
media = _postcssValueParser.default.stringify(mediaNodes).trim().toLowerCase();
}
if (options.filter && !options.filter(normalizedUrl, media)) {
// eslint-disable-next-line no-continue
continue;
}
atRule.remove();
if (isRequestable) {
const importKey = url;
let importName = importsMap.get(importKey);
const request = (0, _utils.requestify)(normalizedUrl, options.rootContext);
tasks.push((async () => {
const {
resolver,
context
} = options;
const resolvedUrl = await (0, _utils.resolveRequests)(resolver, context, [...new Set([request, normalizedUrl])]);
return {
url: resolvedUrl,
media,
prefix,
isRequestable
};
})());
} else {
tasks.push({
url,
media,
prefix,
isRequestable
});
}
}
const results = await Promise.all(tasks);
for (let index = 0; index <= results.length - 1; index++) {
const {
url,
isRequestable,
media
} = results[index];
if (isRequestable) {
const {
prefix
} = results[index];
const newUrl = prefix ? `${prefix}!${url}` : url;
const importKey = newUrl;
let importName = imports.get(importKey);
if (!importName) {
importName = `___CSS_LOADER_AT_RULE_IMPORT_${importsMap.size}___`;
importsMap.set(importKey, importName);
result.messages.push({
type: 'import',
value: {
importName,
url: options.urlHandler ? options.urlHandler(url) : url
}
importName = `___CSS_LOADER_AT_RULE_IMPORT_${imports.size}___`;
imports.set(importKey, importName);
options.imports.push({
importName,
url: options.urlHandler(newUrl),
index
});
}
result.messages.push({
type: 'api-import',
value: {
type: 'internal',
importName,
media
}
});
return;
options.api.push({
importName,
media,
index
}); // eslint-disable-next-line no-continue
continue;
}
result.messages.push({
pluginName,
type: 'api-import',
value: {
type: 'external',
url,
media
}
options.api.push({
url,
media,
index
});
});
}
return Promise.resolve();
});
exports.default = _default;
+204 -108
View File
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = void 0;
var _util = require("util");
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
@@ -22,140 +24,234 @@ function getNodeFromUrlFunc(node) {
return node.nodes && node.nodes[0];
}
function walkUrls(parsed, callback) {
parsed.walk(node => {
if (node.type !== 'function') {
return;
}
function shouldHandleRule(rule, decl, result) {
// https://www.w3.org/TR/css-syntax-3/#typedef-url-token
if (rule.url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
result.warn(`Unable to find uri in '${decl.toString()}'`, {
node: decl
});
return false;
}
if (isUrlFunc.test(node.value)) {
const {
nodes
} = node;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
callback(getNodeFromUrlFunc(node), url, false, isStringValue); // Do not traverse inside `url`
// eslint-disable-next-line consistent-return
if (!(0, _utils.isUrlRequestable)(rule.url)) {
return false;
}
return false;
}
if (isImageSetFunc.test(node.value)) {
for (const nNode of node.nodes) {
const {
type,
value
} = nNode;
if (type === 'function' && isUrlFunc.test(value)) {
const {
nodes
} = nNode;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
callback(getNodeFromUrlFunc(nNode), url, false, isStringValue);
}
if (type === 'string') {
callback(nNode, value, true, true);
}
} // Do not traverse inside `image-set`
// eslint-disable-next-line consistent-return
return false;
}
});
return true;
}
var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
const importsMap = new Map();
const replacementsMap = new Map();
let hasHelper = false;
function walkCss(css, result, options, callback) {
const accumulator = [];
css.walkDecls(decl => {
if (!needParseDecl.test(decl.value)) {
return;
}
const parsed = (0, _postcssValueParser.default)(decl.value);
walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
// https://www.w3.org/TR/css-syntax-3/#typedef-url-token
if (url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
result.warn(`Unable to find uri in '${decl ? decl.toString() : decl.value}'`, {
node: decl
});
parsed.walk(node => {
if (node.type !== 'function') {
return;
}
if (options.filter && !options.filter(url)) {
return;
}
if (isUrlFunc.test(node.value)) {
const {
nodes
} = node;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
const rule = {
node: getNodeFromUrlFunc(node),
url,
needQuotes: false,
isStringValue
};
const splittedUrl = url.split(/(\?)?#/);
const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
const normalizedUrl = (0, _utils.normalizeUrl)(urlWithoutHash, isStringValue);
const importKey = normalizedUrl;
let importName = importsMap.get(importKey);
if (!importName) {
importName = `___CSS_LOADER_URL_IMPORT_${importsMap.size}___`;
importsMap.set(importKey, importName);
if (!hasHelper) {
const urlToHelper = require.resolve('../runtime/getUrl.js');
result.messages.push({
pluginName,
type: 'import',
value: {
importName: '___CSS_LOADER_GET_URL_IMPORT___',
url: options.urlHandler ? options.urlHandler(urlToHelper) : urlToHelper
}
if (shouldHandleRule(rule, decl, result)) {
accumulator.push({
decl,
rule,
parsed
});
hasHelper = true;
}
} // Do not traverse inside `url`
// eslint-disable-next-line consistent-return
result.messages.push({
pluginName,
type: 'import',
value: {
importName,
url: options.urlHandler ? options.urlHandler(normalizedUrl) : normalizedUrl
return false;
} else if (isImageSetFunc.test(node.value)) {
for (const nNode of node.nodes) {
const {
type,
value
} = nNode;
if (type === 'function' && isUrlFunc.test(value)) {
const {
nodes
} = nNode;
const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
const rule = {
node: getNodeFromUrlFunc(nNode),
url,
needQuotes: false,
isStringValue
};
if (shouldHandleRule(rule, decl, result)) {
accumulator.push({
decl,
rule,
parsed
});
}
} else if (type === 'string') {
const rule = {
node: nNode,
url: value,
needQuotes: true,
isStringValue: true
};
if (shouldHandleRule(rule, decl, result)) {
accumulator.push({
decl,
rule,
parsed
});
}
}
});
}
} // Do not traverse inside `image-set`
// eslint-disable-next-line consistent-return
const replacementKey = JSON.stringify({
importKey,
return false;
}
});
});
callback(null, accumulator);
}
const asyncWalkCss = (0, _util.promisify)(walkCss);
var _default = _postcss.default.plugin(pluginName, options => async (css, result) => {
const parsedResults = await asyncWalkCss(css, result, options);
if (parsedResults.length === 0) {
return Promise.resolve();
}
const tasks = [];
const imports = new Map();
const replacements = new Map();
let hasUrlImportHelper = false;
for (const parsedResult of parsedResults) {
const {
url,
isStringValue
} = parsedResult.rule;
let normalizedUrl = url;
let prefix = '';
const queryParts = normalizedUrl.split('!');
if (queryParts.length > 1) {
normalizedUrl = queryParts.pop();
prefix = queryParts.join('!');
}
normalizedUrl = (0, _utils.normalizeUrl)(normalizedUrl, isStringValue);
if (!options.filter(normalizedUrl)) {
// eslint-disable-next-line no-continue
continue;
}
if (!hasUrlImportHelper) {
options.imports.push({
importName: '___CSS_LOADER_GET_URL_IMPORT___',
url: options.urlHandler(require.resolve('../runtime/getUrl.js')),
index: -1
});
hasUrlImportHelper = true;
}
const splittedUrl = normalizedUrl.split(/(\?)?#/);
const [pathname, query, hashOrQuery] = splittedUrl;
let hash = query ? '?' : '';
hash += hashOrQuery ? `#${hashOrQuery}` : '';
const request = (0, _utils.requestify)(pathname, options.rootContext);
tasks.push((async () => {
const {
resolver,
context
} = options;
const resolvedUrl = await (0, _utils.resolveRequests)(resolver, context, [...new Set([request, normalizedUrl])]);
return {
url: resolvedUrl,
prefix,
hash,
parsedResult
};
})());
}
const results = await Promise.all(tasks);
for (let index = 0; index <= results.length - 1; index++) {
const {
url,
prefix,
hash,
parsedResult: {
decl,
rule,
parsed
}
} = results[index];
const newUrl = prefix ? `${prefix}!${url}` : url;
const importKey = newUrl;
let importName = imports.get(importKey);
if (!importName) {
importName = `___CSS_LOADER_URL_IMPORT_${imports.size}___`;
imports.set(importKey, importName);
options.imports.push({
importName,
url: options.urlHandler(newUrl),
index
});
}
const {
needQuotes
} = rule;
const replacementKey = JSON.stringify({
newUrl,
hash,
needQuotes
});
let replacementName = replacements.get(replacementKey);
if (!replacementName) {
replacementName = `___CSS_LOADER_URL_REPLACEMENT_${replacements.size}___`;
replacements.set(replacementKey, replacementName);
options.replacements.push({
replacementName,
importName,
hash,
needQuotes
});
let replacementName = replacementsMap.get(replacementKey);
if (!replacementName) {
replacementName = `___CSS_LOADER_URL_REPLACEMENT_${replacementsMap.size}___`;
replacementsMap.set(replacementKey, replacementName);
result.messages.push({
pluginName,
type: 'url-replacement',
value: {
replacementName,
importName,
hash,
needQuotes
}
});
} // eslint-disable-next-line no-param-reassign
} // eslint-disable-next-line no-param-reassign
node.type = 'word'; // eslint-disable-next-line no-param-reassign
rule.node.type = 'word'; // eslint-disable-next-line no-param-reassign
node.value = replacementName;
}); // eslint-disable-next-line no-param-reassign
rule.node.value = replacementName; // eslint-disable-next-line no-param-reassign
decl.value = parsed.toString();
});
}
return Promise.resolve();
});
exports.default = _default;
+370 -140
View File
@@ -3,22 +3,31 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.normalizeOptions = normalizeOptions;
exports.shouldUseModulesPlugins = shouldUseModulesPlugins;
exports.shouldUseImportPlugin = shouldUseImportPlugin;
exports.shouldUseURLPlugin = shouldUseURLPlugin;
exports.shouldUseIcssPlugin = shouldUseIcssPlugin;
exports.normalizeUrl = normalizeUrl;
exports.requestify = requestify;
exports.getFilter = getFilter;
exports.getModulesOptions = getModulesOptions;
exports.getModulesPlugins = getModulesPlugins;
exports.normalizeSourceMap = normalizeSourceMap;
exports.getPreRequester = getPreRequester;
exports.getImportCode = getImportCode;
exports.getModuleCode = getModuleCode;
exports.getExportCode = getExportCode;
exports.shouldUseModulesPlugins = shouldUseModulesPlugins;
exports.resolveRequests = resolveRequests;
exports.isUrlRequestable = isUrlRequestable;
exports.sort = sort;
var _url = require("url");
var _path = _interopRequireDefault(require("path"));
var _loaderUtils = require("loader-utils");
var _normalizePath = _interopRequireDefault(require("normalize-path"));
var _cssesc = _interopRequireDefault(require("cssesc"));
var _postcssModulesValues = _interopRequireDefault(require("postcss-modules-values"));
@@ -39,6 +48,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
*/
const whitespace = '[\\x20\\t\\r\\n\\f]';
const unescapeRegExp = new RegExp(`\\\\([\\da-f]{1,6}${whitespace}?|(${whitespace})|.)`, 'ig');
const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
function unescape(str) {
return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
@@ -54,127 +64,226 @@ function unescape(str) {
String.fromCharCode(high >> 10 | 0xd800, high & 0x3ff | 0xdc00);
/* eslint-enable line-comment-position */
});
}
function normalizePath(file) {
return _path.default.sep === '\\' ? file.replace(/\\/g, '/') : file;
} // eslint-disable-next-line no-control-regex
const filenameReservedRegex = /[<>:"/\\|?*\x00-\x1F]/g; // eslint-disable-next-line no-control-regex
const filenameReservedRegex = /[<>:"/\\|?*]/g; // eslint-disable-next-line no-control-regex
const reControlChars = /[\u0000-\u001f\u0080-\u009f]/g;
const reRelativePath = /^\.+/;
function getLocalIdent(loaderContext, localIdentName, localName, options) {
if (!options.context) {
// eslint-disable-next-line no-param-reassign
options.context = loaderContext.rootContext;
}
function defaultGetLocalIdent(loaderContext, localIdentName, localName, options) {
const {
context,
hashPrefix
} = options;
const {
resourcePath
} = loaderContext;
const request = normalizePath(_path.default.relative(context, resourcePath)); // eslint-disable-next-line no-param-reassign
const request = (0, _normalizePath.default)(_path.default.relative(options.context || '', loaderContext.resourcePath)); // eslint-disable-next-line no-param-reassign
options.content = `${options.hashPrefix + request}+${unescape(localName)}`; // Using `[path]` placeholder outputs `/` we need escape their
options.content = `${hashPrefix + request}\x00${unescape(localName)}`; // Using `[path]` placeholder outputs `/` we need escape their
// Also directories can contains invalid characters for css we need escape their too
return (0, _cssesc.default)((0, _loaderUtils.interpolateName)(loaderContext, localIdentName, options) // For `[hash]` placeholder
.replace(/^((-?[0-9])|--)/, '_$1').replace(filenameReservedRegex, '-').replace(reControlChars, '-').replace(reRelativePath, '-').replace(/\./g, '-'), {
.replace(/^((-?[0-9])|--)/, '_$1').replace(filenameReservedRegex, '-').replace(reControlChars, '-').replace(/\./g, '-'), {
isIdentifier: true
}).replace(/\\\[local\\\]/gi, localName);
}).replace(/\\\[local\\]/gi, localName);
}
function normalizeUrl(url, isStringValue) {
let normalizedUrl = url;
if (isStringValue && /\\[\n]/.test(normalizedUrl)) {
normalizedUrl = normalizedUrl.replace(/\\[\n]/g, '');
if (isStringValue && /\\(\n|\r\n|\r|\f)/.test(normalizedUrl)) {
normalizedUrl = normalizedUrl.replace(/\\(\n|\r\n|\r|\f)/g, '');
}
return (0, _loaderUtils.urlToRequest)(decodeURIComponent(unescape(normalizedUrl)));
if (matchNativeWin32Path.test(url)) {
return decodeURIComponent(normalizedUrl);
}
return decodeURIComponent(unescape(normalizedUrl));
}
function getFilter(filter, resourcePath, defaultFilter = null) {
return item => {
if (defaultFilter && !defaultFilter(item)) {
return false;
}
function requestify(url, rootContext) {
if (/^file:/i.test(url)) {
return (0, _url.fileURLToPath)(url);
}
return url.charAt(0) === '/' ? (0, _loaderUtils.urlToRequest)(url, rootContext) : (0, _loaderUtils.urlToRequest)(url);
}
function getFilter(filter, resourcePath) {
return (...args) => {
if (typeof filter === 'function') {
return filter(item, resourcePath);
return filter(...args, resourcePath);
}
return true;
};
}
function shouldUseModulesPlugins(modules, resourcePath) {
if (typeof modules === 'undefined') {
const moduleRegExp = /\.module\.\w+$/i;
function getModulesOptions(rawOptions, loaderContext) {
const {
resourcePath
} = loaderContext;
if (typeof rawOptions.modules === 'undefined') {
const isModules = moduleRegExp.test(resourcePath);
if (!isModules) {
return false;
}
} else if (typeof rawOptions.modules === 'boolean' && rawOptions.modules === false) {
return false;
}
if (typeof modules === 'boolean') {
return modules;
}
if (typeof modules === 'string') {
return true;
}
if (typeof modules.auto === 'boolean') {
return modules.auto ? /\.module\.\w+$/i.test(resourcePath) : false;
}
if (modules.auto instanceof RegExp) {
return modules.auto.test(resourcePath);
}
if (typeof modules.auto === 'function') {
return modules.auto(resourcePath);
}
return true;
}
function getModulesPlugins(options, loaderContext) {
let modulesOptions = {
compileType: rawOptions.icss ? 'icss' : 'module',
auto: true,
mode: 'local',
exportGlobals: false,
localIdentName: '[hash:base64]',
getLocalIdent,
hashPrefix: '',
localIdentRegExp: null
localIdentContext: loaderContext.rootContext,
localIdentHashPrefix: '',
// eslint-disable-next-line no-undefined
localIdentRegExp: undefined,
getLocalIdent: defaultGetLocalIdent,
namedExport: false,
exportLocalsConvention: 'asIs',
exportOnlyLocals: false
};
if (typeof options.modules === 'boolean' || typeof options.modules === 'string') {
modulesOptions.mode = typeof options.modules === 'string' ? options.modules : 'local';
if (typeof rawOptions.modules === 'boolean' || typeof rawOptions.modules === 'string') {
modulesOptions.mode = typeof rawOptions.modules === 'string' ? rawOptions.modules : 'local';
} else {
modulesOptions = Object.assign({}, modulesOptions, options.modules);
if (rawOptions.modules) {
if (typeof rawOptions.modules.auto === 'boolean') {
const isModules = rawOptions.modules.auto && moduleRegExp.test(resourcePath);
if (!isModules) {
return false;
}
} else if (rawOptions.modules.auto instanceof RegExp) {
const isModules = rawOptions.modules.auto.test(resourcePath);
if (!isModules) {
return false;
}
} else if (typeof rawOptions.modules.auto === 'function') {
const isModule = rawOptions.modules.auto(resourcePath);
if (!isModule) {
return false;
}
}
if (rawOptions.modules.namedExport === true && typeof rawOptions.modules.exportLocalsConvention === 'undefined') {
modulesOptions.exportLocalsConvention = 'camelCaseOnly';
}
}
modulesOptions = { ...modulesOptions,
...(rawOptions.modules || {})
};
}
if (typeof modulesOptions.mode === 'function') {
modulesOptions.mode = modulesOptions.mode(loaderContext.resourcePath);
}
if (modulesOptions.namedExport === true) {
if (rawOptions.esModule === false) {
throw new Error('The "modules.namedExport" option requires the "esModules" option to be enabled');
}
if (modulesOptions.exportLocalsConvention !== 'camelCaseOnly') {
throw new Error('The "modules.namedExport" option requires the "modules.exportLocalsConvention" option to be "camelCaseOnly"');
}
}
return modulesOptions;
}
function normalizeOptions(rawOptions, loaderContext) {
if (rawOptions.icss) {
loaderContext.emitWarning(new Error('The "icss" option is deprecated, use "modules.compileType: "icss"" instead'));
}
const modulesOptions = getModulesOptions(rawOptions, loaderContext);
return {
url: typeof rawOptions.url === 'undefined' ? true : rawOptions.url,
import: typeof rawOptions.import === 'undefined' ? true : rawOptions.import,
modules: modulesOptions,
// TODO remove in the next major release
icss: typeof rawOptions.icss === 'undefined' ? false : rawOptions.icss,
sourceMap: typeof rawOptions.sourceMap === 'boolean' ? rawOptions.sourceMap : loaderContext.sourceMap,
importLoaders: typeof rawOptions.importLoaders === 'string' ? parseInt(rawOptions.importLoaders, 10) : rawOptions.importLoaders,
esModule: typeof rawOptions.esModule === 'undefined' ? true : rawOptions.esModule
};
}
function shouldUseImportPlugin(options) {
if (options.modules.exportOnlyLocals) {
return false;
}
if (typeof options.import === 'boolean') {
return options.import;
}
return true;
}
function shouldUseURLPlugin(options) {
if (options.modules.exportOnlyLocals) {
return false;
}
if (typeof options.url === 'boolean') {
return options.url;
}
return true;
}
function shouldUseModulesPlugins(options) {
return options.modules.compileType === 'module';
}
function shouldUseIcssPlugin(options) {
return options.icss === true || Boolean(options.modules);
}
function getModulesPlugins(options, loaderContext) {
const {
mode,
getLocalIdent,
localIdentName,
localIdentContext,
localIdentHashPrefix,
localIdentRegExp
} = options.modules;
let plugins = [];
try {
plugins = [_postcssModulesValues.default, (0, _postcssModulesLocalByDefault.default)({
mode: modulesOptions.mode
mode
}), (0, _postcssModulesExtractImports.default)(), (0, _postcssModulesScope.default)({
generateScopedName: function generateScopedName(exportName) {
let localIdent = modulesOptions.getLocalIdent(loaderContext, modulesOptions.localIdentName, exportName, {
context: modulesOptions.context,
hashPrefix: modulesOptions.hashPrefix,
regExp: modulesOptions.localIdentRegExp
generateScopedName(exportName) {
return getLocalIdent(loaderContext, localIdentName, exportName, {
context: localIdentContext,
hashPrefix: localIdentHashPrefix,
regExp: localIdentRegExp
});
if (!localIdent) {
localIdent = getLocalIdent(loaderContext, modulesOptions.localIdentName, exportName, {
context: modulesOptions.context,
hashPrefix: modulesOptions.hashPrefix,
regExp: modulesOptions.localIdentRegExp
});
}
return localIdent;
},
exportGlobals: modulesOptions.exportGlobals
exportGlobals: options.modules.exportGlobals
})];
} catch (error) {
loaderContext.emitError(error);
@@ -183,26 +292,57 @@ function getModulesPlugins(options, loaderContext) {
return plugins;
}
function normalizeSourceMap(map) {
const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
const ABSOLUTE_SCHEME = /^[a-z0-9+\-.]+:/i;
function getURLType(source) {
if (source[0] === '/') {
if (source[1] === '/') {
return 'scheme-relative';
}
return 'path-absolute';
}
if (IS_NATIVE_WIN32_PATH.test(source)) {
return 'path-absolute';
}
return ABSOLUTE_SCHEME.test(source) ? 'absolute' : 'path-relative';
}
function normalizeSourceMap(map, resourcePath) {
let newMap = map; // Some loader emit source map as string
// Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
if (typeof newMap === 'string') {
newMap = JSON.parse(newMap);
} // Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
// We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
if (newMap.file) {
newMap.file = (0, _normalizePath.default)(newMap.file);
}
if (newMap.sourceRoot) {
newMap.sourceRoot = (0, _normalizePath.default)(newMap.sourceRoot);
}
delete newMap.file;
const {
sourceRoot
} = newMap;
delete newMap.sourceRoot;
if (newMap.sources) {
newMap.sources = newMap.sources.map(source => (0, _normalizePath.default)(source));
// Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
// We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
newMap.sources = newMap.sources.map(source => {
// Non-standard syntax from `postcss`
if (source.indexOf('<') === 0) {
return source;
}
const sourceType = getURLType(source); // Do no touch `scheme-relative` and `absolute` URLs
if (sourceType === 'path-relative' || sourceType === 'path-absolute') {
const absoluteSource = sourceType === 'path-relative' && sourceRoot ? _path.default.resolve(sourceRoot, normalizePath(source)) : normalizePath(source);
return _path.default.relative(_path.default.dirname(resourcePath), absoluteSource);
}
return source;
});
}
return newMap;
@@ -229,94 +369,127 @@ function getPreRequester({
};
}
function getImportCode(loaderContext, exportType, imports, esModule) {
function getImportCode(imports, options) {
let code = '';
if (exportType === 'full') {
const apiUrl = (0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/api'));
code += esModule ? `import ___CSS_LOADER_API_IMPORT___ from ${apiUrl};\n` : `var ___CSS_LOADER_API_IMPORT___ = require(${apiUrl});\n`;
}
for (const item of imports) {
const {
importName,
url
url,
icss
} = item;
code += esModule ? `import ${importName} from ${url};\n` : `var ${importName} = require(${url});\n`;
if (options.esModule) {
if (icss && options.modules.namedExport) {
code += `import ${options.modules.exportOnlyLocals ? '' : `${importName}, `}* as ${importName}_NAMED___ from ${url};\n`;
} else {
code += `import ${importName} from ${url};\n`;
}
} else {
code += `var ${importName} = require(${url});\n`;
}
}
return code ? `// Imports\n${code}` : '';
}
function getModuleCode(result, exportType, sourceMap, apiImports, urlReplacements, icssReplacements, esModule) {
if (exportType !== 'full') {
function normalizeSourceMapForRuntime(map, loaderContext) {
const resultMap = map ? map.toJSON() : null;
if (resultMap) {
delete resultMap.file;
resultMap.sourceRoot = '';
resultMap.sources = resultMap.sources.map(source => {
// Non-standard syntax from `postcss`
if (source.indexOf('<') === 0) {
return source;
}
const sourceType = getURLType(source);
if (sourceType !== 'path-relative') {
return source;
}
const resourceDirname = _path.default.dirname(loaderContext.resourcePath);
const absoluteSource = _path.default.resolve(resourceDirname, source);
const contextifyPath = normalizePath(_path.default.relative(loaderContext.rootContext, absoluteSource));
return `webpack://${contextifyPath}`;
});
}
return JSON.stringify(resultMap);
}
function getModuleCode(result, api, replacements, options, loaderContext) {
if (options.modules.exportOnlyLocals === true) {
return '';
}
const {
css,
map
} = result;
const sourceMapValue = sourceMap && map ? `,${map}` : '';
let code = JSON.stringify(css);
let beforeCode = '';
beforeCode += esModule ? `var exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});\n` : `exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});\n`;
const sourceMapValue = options.sourceMap ? `,${normalizeSourceMapForRuntime(result.map, loaderContext)}` : '';
let code = JSON.stringify(result.css);
let beforeCode = `var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(${options.sourceMap});\n`;
for (const item of apiImports) {
for (const item of api) {
const {
type,
url,
media,
dedupe
} = item;
beforeCode += type === 'internal' ? `exports.i(${item.importName}${media ? `, ${JSON.stringify(media)}` : dedupe ? ', ""' : ''}${dedupe ? ', true' : ''});\n` : `exports.push([module.id, ${JSON.stringify(`@import url(${item.url});`)}${media ? `, ${JSON.stringify(media)}` : ''}]);\n`;
beforeCode += url ? `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(`@import url(${url});`)}${media ? `, ${JSON.stringify(media)}` : ''}]);\n` : `___CSS_LOADER_EXPORT___.i(${item.importName}${media ? `, ${JSON.stringify(media)}` : dedupe ? ', ""' : ''}${dedupe ? ', true' : ''});\n`;
}
for (const item of urlReplacements) {
const {
replacementName,
importName,
hash,
needQuotes
} = item;
const getUrlOptions = [].concat(hash ? [`hash: ${JSON.stringify(hash)}`] : []).concat(needQuotes ? 'needQuotes: true' : []);
const preparedOptions = getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(', ')} }` : '';
beforeCode += `var ${replacementName} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});\n`;
code = code.replace(new RegExp(replacementName, 'g'), () => `" + ${replacementName} + "`);
}
for (const replacement of icssReplacements) {
for (const item of replacements) {
const {
replacementName,
importName,
localName
} = replacement;
code = code.replace(new RegExp(replacementName, 'g'), () => `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
} = item;
if (localName) {
code = code.replace(new RegExp(replacementName, 'g'), () => options.modules.namedExport ? `" + ${importName}_NAMED___[${JSON.stringify((0, _camelcase.default)(localName))}] + "` : `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
} else {
const {
hash,
needQuotes
} = item;
const getUrlOptions = [].concat(hash ? [`hash: ${JSON.stringify(hash)}`] : []).concat(needQuotes ? 'needQuotes: true' : []);
const preparedOptions = getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(', ')} }` : '';
beforeCode += `var ${replacementName} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});\n`;
code = code.replace(new RegExp(replacementName, 'g'), () => `" + ${replacementName} + "`);
}
}
return `${beforeCode}// Module\nexports.push([module.id, ${code}, ""${sourceMapValue}]);\n`;
return `${beforeCode}// Module\n___CSS_LOADER_EXPORT___.push([module.id, ${code}, ""${sourceMapValue}]);\n`;
}
function dashesCamelCase(str) {
return str.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
}
function getExportCode(exports, exportType, localsConvention, icssReplacements, esModule) {
let code = '';
function getExportCode(exports, replacements, options) {
let code = '// Exports\n';
let localsCode = '';
const addExportToLocalsCode = (name, value) => {
if (localsCode) {
localsCode += `,\n`;
}
if (options.modules.namedExport) {
localsCode += `export const ${(0, _camelcase.default)(name)} = ${JSON.stringify(value)};\n`;
} else {
if (localsCode) {
localsCode += `,\n`;
}
localsCode += `\t${JSON.stringify(name)}: ${JSON.stringify(value)}`;
localsCode += `\t${JSON.stringify(name)}: ${JSON.stringify(value)}`;
}
};
for (const {
name,
value
} of exports) {
switch (localsConvention) {
switch (options.modules.exportLocalsConvention) {
case 'camelCase':
{
addExportToLocalsCode(name, value);
@@ -360,24 +533,81 @@ function getExportCode(exports, exportType, localsConvention, icssReplacements,
}
}
for (const replacement of icssReplacements) {
for (const item of replacements) {
const {
replacementName,
importName,
localName
} = replacement;
localsCode = localsCode.replace(new RegExp(replacementName, 'g'), () => exportType === 'locals' ? `" + ${importName}[${JSON.stringify(localName)}] + "` : `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
} = item;
if (localName) {
const {
importName
} = item;
localsCode = localsCode.replace(new RegExp(replacementName, 'g'), () => {
if (options.modules.namedExport) {
return `" + ${importName}_NAMED___[${JSON.stringify((0, _camelcase.default)(localName))}] + "`;
} else if (options.modules.exportOnlyLocals) {
return `" + ${importName}[${JSON.stringify(localName)}] + "`;
}
return `" + ${importName}.locals[${JSON.stringify(localName)}] + "`;
});
} else {
localsCode = localsCode.replace(new RegExp(replacementName, 'g'), () => `" + ${replacementName} + "`);
}
}
if (exportType === 'locals') {
code += `${esModule ? 'export default' : 'module.exports ='} ${localsCode ? `{\n${localsCode}\n}` : '{}'};\n`;
} else {
if (localsCode) {
code += `exports.locals = {\n${localsCode}\n};\n`;
if (options.modules.exportOnlyLocals) {
code += options.modules.namedExport ? localsCode : `${options.esModule ? 'export default' : 'module.exports ='} {\n${localsCode}\n};\n`;
return code;
}
if (localsCode) {
code += options.modules.namedExport ? localsCode : `___CSS_LOADER_EXPORT___.locals = {\n${localsCode}\n};\n`;
}
code += `${options.esModule ? 'export default' : 'module.exports ='} ___CSS_LOADER_EXPORT___;\n`;
return code;
}
async function resolveRequests(resolve, context, possibleRequests) {
return resolve(context, possibleRequests[0]).then(result => {
return result;
}).catch(error => {
const [, ...tailPossibleRequests] = possibleRequests;
if (tailPossibleRequests.length === 0) {
throw error;
}
code += `${esModule ? 'export default' : 'module.exports ='} exports;\n`;
return resolveRequests(resolve, context, tailPossibleRequests);
});
}
function isUrlRequestable(url) {
// Protocol-relative URLs
if (/^\/\//.test(url)) {
return false;
} // `file:` protocol
if (/^file:/i.test(url)) {
return true;
} // Absolute URLs
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !matchNativeWin32Path.test(url)) {
return false;
} // `#` URLs
if (/^#/.test(url)) {
return false;
}
return `// Exports\n${code}`;
return true;
}
function sort(a, b) {
return a.index - b.index;
}
+103
View File
@@ -0,0 +1,103 @@
declare namespace camelcase {
interface Options {
/**
Uppercase the first character: `foo-bar` → `FooBar`.
@default false
*/
readonly pascalCase?: boolean;
/**
Preserve the consecutive uppercase characters: `foo-BAR` → `FooBAR`.
@default false
*/
readonly preserveConsecutiveUppercase?: boolean;
/**
The locale parameter indicates the locale to be used to convert to upper/lower case according to any locale-specific case mappings. If multiple locales are given in an array, the best available locale is used.
Setting `locale: false` ignores the platform locale and uses the [Unicode Default Case Conversion](https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#simple-single-character-case-mapping) algorithm.
Default: The host environments current locale.
@example
```
import camelCase = require('camelcase');
camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
camelCase('lorem-ipsum', {locale: 'tr-TR'});
//=> 'loremİpsum'
camelCase('lorem-ipsum', {locale: ['en-US', 'en-GB']});
//=> 'loremIpsum'
camelCase('lorem-ipsum', {locale: ['tr', 'TR', 'tr-TR']});
//=> 'loremİpsum'
```
*/
readonly locale?: false | string | readonly string[];
}
}
/**
Convert a dash/dot/underscore/space separated string to camelCase or PascalCase: `foo-bar` → `fooBar`.
Correctly handles Unicode strings.
@param input - String to convert to camel case.
@example
```
import camelCase = require('camelcase');
camelCase('foo-bar');
//=> 'fooBar'
camelCase('foo_bar');
//=> 'fooBar'
camelCase('Foo-Bar');
//=> 'fooBar'
camelCase('розовый_пушистый_единорог');
//=> 'розовыйПушистыйЕдинорог'
camelCase('Foo-Bar', {pascalCase: true});
//=> 'FooBar'
camelCase('--foo.bar', {pascalCase: false});
//=> 'fooBar'
camelCase('Foo-BAR', {preserveConsecutiveUppercase: true});
//=> 'fooBAR'
camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true}));
//=> 'FooBAR'
camelCase('foo bar');
//=> 'fooBar'
console.log(process.argv[3]);
//=> '--foo-bar'
camelCase(process.argv[3]);
//=> 'fooBar'
camelCase(['foo', 'bar']);
//=> 'fooBar'
camelCase(['__foo__', '--bar'], {pascalCase: true});
//=> 'FooBar'
camelCase(['foo', 'BAR'], {pascalCase: true, preserveConsecutiveUppercase: true})
//=> 'FooBAR'
camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
```
*/
declare function camelcase(
input: string | readonly string[],
options?: camelcase.Options
): string;
export = camelcase;
+113
View File
@@ -0,0 +1,113 @@
'use strict';
const UPPERCASE = /[\p{Lu}]/u;
const LOWERCASE = /[\p{Ll}]/u;
const LEADING_CAPITAL = /^[\p{Lu}](?![\p{Lu}])/gu;
const IDENTIFIER = /([\p{Alpha}\p{N}_]|$)/u;
const SEPARATORS = /[_.\- ]+/;
const LEADING_SEPARATORS = new RegExp('^' + SEPARATORS.source);
const SEPARATORS_AND_IDENTIFIER = new RegExp(SEPARATORS.source + IDENTIFIER.source, 'gu');
const NUMBERS_AND_IDENTIFIER = new RegExp('\\d+' + IDENTIFIER.source, 'gu');
const preserveCamelCase = (string, toLowerCase, toUpperCase) => {
let isLastCharLower = false;
let isLastCharUpper = false;
let isLastLastCharUpper = false;
for (let i = 0; i < string.length; i++) {
const character = string[i];
if (isLastCharLower && UPPERCASE.test(character)) {
string = string.slice(0, i) + '-' + string.slice(i);
isLastCharLower = false;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = true;
i++;
} else if (isLastCharUpper && isLastLastCharUpper && LOWERCASE.test(character)) {
string = string.slice(0, i - 1) + '-' + string.slice(i - 1);
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = false;
isLastCharLower = true;
} else {
isLastCharLower = toLowerCase(character) === character && toUpperCase(character) !== character;
isLastLastCharUpper = isLastCharUpper;
isLastCharUpper = toUpperCase(character) === character && toLowerCase(character) !== character;
}
}
return string;
};
const preserveConsecutiveUppercase = (input, toLowerCase) => {
LEADING_CAPITAL.lastIndex = 0;
return input.replace(LEADING_CAPITAL, m1 => toLowerCase(m1));
};
const postProcess = (input, toUpperCase) => {
SEPARATORS_AND_IDENTIFIER.lastIndex = 0;
NUMBERS_AND_IDENTIFIER.lastIndex = 0;
return input.replace(SEPARATORS_AND_IDENTIFIER, (_, identifier) => toUpperCase(identifier))
.replace(NUMBERS_AND_IDENTIFIER, m => toUpperCase(m));
};
const camelCase = (input, options) => {
if (!(typeof input === 'string' || Array.isArray(input))) {
throw new TypeError('Expected the input to be `string | string[]`');
}
options = {
pascalCase: false,
preserveConsecutiveUppercase: false,
...options
};
if (Array.isArray(input)) {
input = input.map(x => x.trim())
.filter(x => x.length)
.join('-');
} else {
input = input.trim();
}
if (input.length === 0) {
return '';
}
const toLowerCase = options.locale === false ?
string => string.toLowerCase() :
string => string.toLocaleLowerCase(options.locale);
const toUpperCase = options.locale === false ?
string => string.toUpperCase() :
string => string.toLocaleUpperCase(options.locale);
if (input.length === 1) {
return options.pascalCase ? toUpperCase(input) : toLowerCase(input);
}
const hasUpperCase = input !== toLowerCase(input);
if (hasUpperCase) {
input = preserveCamelCase(input, toLowerCase, toUpperCase);
}
input = input.replace(LEADING_SEPARATORS, '');
if (options.preserveConsecutiveUppercase) {
input = preserveConsecutiveUppercase(input, toLowerCase);
} else {
input = toLowerCase(input);
}
if (options.pascalCase) {
input = toUpperCase(input.charAt(0)) + input.slice(1);
}
return postProcess(input, toUpperCase);
};
module.exports = camelCase;
// TODO: Remove this for the next major release
module.exports.default = camelCase;
+9
View File
@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+79
View File
@@ -0,0 +1,79 @@
{
"_args": [
[
"camelcase@6.3.0",
"/home/node/nuxt"
]
],
"_from": "camelcase@6.3.0",
"_id": "camelcase@6.3.0",
"_inBundle": false,
"_integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
"_location": "/css-loader/camelcase",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "camelcase@6.3.0",
"name": "camelcase",
"escapedName": "camelcase",
"rawSpec": "6.3.0",
"saveSpec": null,
"fetchSpec": "6.3.0"
},
"_requiredBy": [
"/css-loader"
],
"_resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
"_spec": "6.3.0",
"_where": "/home/node/nuxt",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"bugs": {
"url": "https://github.com/sindresorhus/camelcase/issues"
},
"description": "Convert a dash/dot/underscore/space separated string to camelCase or PascalCase: `foo-bar` → `fooBar`",
"devDependencies": {
"ava": "^1.4.1",
"tsd": "^0.11.0",
"xo": "^0.28.3"
},
"engines": {
"node": ">=10"
},
"files": [
"index.js",
"index.d.ts"
],
"funding": "https://github.com/sponsors/sindresorhus",
"homepage": "https://github.com/sindresorhus/camelcase#readme",
"keywords": [
"camelcase",
"camel-case",
"camel",
"case",
"dash",
"hyphen",
"dot",
"underscore",
"separator",
"string",
"text",
"convert",
"pascalcase",
"pascal-case"
],
"license": "MIT",
"name": "camelcase",
"repository": {
"type": "git",
"url": "git+https://github.com/sindresorhus/camelcase.git"
},
"scripts": {
"test": "xo && ava && tsd"
},
"version": "6.3.0"
}
+144
View File
@@ -0,0 +1,144 @@
# camelcase
> Convert a dash/dot/underscore/space separated string to camelCase or PascalCase: `foo-bar` → `fooBar`
Correctly handles Unicode strings.
If you use this on untrusted user input, don't forget to limit the length to something reasonable.
## Install
```
$ npm install camelcase
```
*If you need to support Firefox < 78, stay on version 5 as version 6 uses regex features not available in Firefox < 78.*
## Usage
```js
const camelCase = require('camelcase');
camelCase('foo-bar');
//=> 'fooBar'
camelCase('foo_bar');
//=> 'fooBar'
camelCase('Foo-Bar');
//=> 'fooBar'
camelCase('розовый_пушистый_единорог');
//=> 'розовыйПушистыйЕдинорог'
camelCase('Foo-Bar', {pascalCase: true});
//=> 'FooBar'
camelCase('--foo.bar', {pascalCase: false});
//=> 'fooBar'
camelCase('Foo-BAR', {preserveConsecutiveUppercase: true});
//=> 'fooBAR'
camelCase('fooBAR', {pascalCase: true, preserveConsecutiveUppercase: true}));
//=> 'FooBAR'
camelCase('foo bar');
//=> 'fooBar'
console.log(process.argv[3]);
//=> '--foo-bar'
camelCase(process.argv[3]);
//=> 'fooBar'
camelCase(['foo', 'bar']);
//=> 'fooBar'
camelCase(['__foo__', '--bar'], {pascalCase: true});
//=> 'FooBar'
camelCase(['foo', 'BAR'], {pascalCase: true, preserveConsecutiveUppercase: true})
//=> 'FooBAR'
camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
```
## API
### camelCase(input, options?)
#### input
Type: `string | string[]`
String to convert to camel case.
#### options
Type: `object`
##### pascalCase
Type: `boolean`\
Default: `false`
Uppercase the first character: `foo-bar``FooBar`
##### preserveConsecutiveUppercase
Type: `boolean`\
Default: `false`
Preserve the consecutive uppercase characters: `foo-BAR``FooBAR`.
##### locale
Type: `false | string | string[]`\
Default: The host environments current locale.
The locale parameter indicates the locale to be used to convert to upper/lower case according to any locale-specific case mappings. If multiple locales are given in an array, the best available locale is used.
```js
const camelCase = require('camelcase');
camelCase('lorem-ipsum', {locale: 'en-US'});
//=> 'loremIpsum'
camelCase('lorem-ipsum', {locale: 'tr-TR'});
//=> 'loremİpsum'
camelCase('lorem-ipsum', {locale: ['en-US', 'en-GB']});
//=> 'loremIpsum'
camelCase('lorem-ipsum', {locale: ['tr', 'TR', 'tr-TR']});
//=> 'loremİpsum'
```
Setting `locale: false` ignores the platform locale and uses the [Unicode Default Case Conversion](https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#simple-single-character-case-mapping) algorithm:
```js
const camelCase = require('camelcase');
// On a platform with 'tr-TR'
camelCase('lorem-ipsum');
//=> 'loremİpsum'
camelCase('lorem-ipsum', {locale: false});
//=> 'loremIpsum'
```
## camelcase for enterprise
Available as part of the Tidelift Subscription.
The maintainers of camelcase and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-camelcase?utm_source=npm-camelcase&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
## Related
- [decamelize](https://github.com/sindresorhus/decamelize) - The inverse of this module
- [uppercamelcase](https://github.com/SamVerschueren/uppercamelcase) - Like this module, but to PascalCase instead of camelCase
- [titleize](https://github.com/sindresorhus/titleize) - Capitalize every word in string
- [humanize-string](https://github.com/sindresorhus/humanize-string) - Convert a camelized/dasherized/underscored string into a humanized one
- [camelcase-keys](https://github.com/sindresorhus/camelcase-keys) - Convert object keys to camel case
+20
View File
@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+275
View File
@@ -0,0 +1,275 @@
# loader-utils
## Methods
### `getOptions`
Recommended way to retrieve the options of a loader invocation:
```javascript
// inside your loader
const options = loaderUtils.getOptions(this);
```
1. If `this.query` is a string:
- Tries to parse the query string and returns a new object
- Throws if it's not a valid query string
2. If `this.query` is object-like, it just returns `this.query`
3. In any other case, it just returns `null`
**Please note:** The returned `options` object is *read-only*. It may be re-used across multiple invocations.
If you pass it on to another library, make sure to make a *deep copy* of it:
```javascript
const options = Object.assign(
{},
defaultOptions,
loaderUtils.getOptions(this) // it is safe to pass null to Object.assign()
);
// don't forget nested objects or arrays
options.obj = Object.assign({}, options.obj);
options.arr = options.arr.slice();
someLibrary(options);
```
[clone](https://www.npmjs.com/package/clone) is a good library to make a deep copy of the options.
#### Options as query strings
If the loader options have been passed as loader query string (`loader?some&params`), the string is parsed by using [`parseQuery`](#parsequery).
### `parseQuery`
Parses a passed string (e.g. `loaderContext.resourceQuery`) as a query string, and returns an object.
``` javascript
const params = loaderUtils.parseQuery(this.resourceQuery); // resource: `file?param1=foo`
if (params.param1 === "foo") {
// do something
}
```
The string is parsed like this:
``` text
-> Error
? -> {}
?flag -> { flag: true }
?+flag -> { flag: true }
?-flag -> { flag: false }
?xyz=test -> { xyz: "test" }
?xyz=1 -> { xyz: "1" } // numbers are NOT parsed
?xyz[]=a -> { xyz: ["a"] }
?flag1&flag2 -> { flag1: true, flag2: true }
?+flag1,-flag2 -> { flag1: true, flag2: false }
?xyz[]=a,xyz[]=b -> { xyz: ["a", "b"] }
?a%2C%26b=c%2C%26d -> { "a,&b": "c,&d" }
?{data:{a:1},isJSON5:true} -> { data: { a: 1 }, isJSON5: true }
```
### `stringifyRequest`
Turns a request into a string that can be used inside `require()` or `import` while avoiding absolute paths.
Use it instead of `JSON.stringify(...)` if you're generating code inside a loader.
**Why is this necessary?** Since webpack calculates the hash before module paths are translated into module ids, we must avoid absolute paths to ensure
consistent hashes across different compilations.
This function:
- resolves absolute requests into relative requests if the request and the module are on the same hard drive
- replaces `\` with `/` if the request and the module are on the same hard drive
- won't change the path at all if the request and the module are on different hard drives
- applies `JSON.stringify` to the result
```javascript
loaderUtils.stringifyRequest(this, "./test.js");
// "\"./test.js\""
loaderUtils.stringifyRequest(this, ".\\test.js");
// "\"./test.js\""
loaderUtils.stringifyRequest(this, "test");
// "\"test\""
loaderUtils.stringifyRequest(this, "test/lib/index.js");
// "\"test/lib/index.js\""
loaderUtils.stringifyRequest(this, "otherLoader?andConfig!test?someConfig");
// "\"otherLoader?andConfig!test?someConfig\""
loaderUtils.stringifyRequest(this, require.resolve("test"));
// "\"../node_modules/some-loader/lib/test.js\""
loaderUtils.stringifyRequest(this, "C:\\module\\test.js");
// "\"../../test.js\"" (on Windows, in case the module and the request are on the same drive)
loaderUtils.stringifyRequest(this, "C:\\module\\test.js");
// "\"C:\\module\\test.js\"" (on Windows, in case the module and the request are on different drives)
loaderUtils.stringifyRequest(this, "\\\\network-drive\\test.js");
// "\"\\\\network-drive\\\\test.js\"" (on Windows, in case the module and the request are on different drives)
```
### `urlToRequest`
Converts some resource URL to a webpack module request.
> i Before call `urlToRequest` you need call `isUrlRequest` to ensure it is requestable url
```javascript
const url = "path/to/module.js";
if (loaderUtils.isUrlRequest(url)) {
// Logic for requestable url
const request = loaderUtils.urlToRequest(url);
} else {
// Logic for not requestable url
}
```
Simple example:
```javascript
const url = "path/to/module.js";
const request = loaderUtils.urlToRequest(url); // "./path/to/module.js"
```
#### Module URLs
Any URL containing a `~` will be interpreted as a module request. Anything after the `~` will be considered the request path.
```javascript
const url = "~path/to/module.js";
const request = loaderUtils.urlToRequest(url); // "path/to/module.js"
```
#### Root-relative URLs
URLs that are root-relative (start with `/`) can be resolved relative to some arbitrary path by using the `root` parameter:
```javascript
const url = "/path/to/module.js";
const root = "./root";
const request = loaderUtils.urlToRequest(url, root); // "./root/path/to/module.js"
```
To convert a root-relative URL into a module URL, specify a `root` value that starts with `~`:
```javascript
const url = "/path/to/module.js";
const root = "~";
const request = loaderUtils.urlToRequest(url, root); // "path/to/module.js"
```
### `interpolateName`
Interpolates a filename template using multiple placeholders and/or a regular expression.
The template and regular expression are set as query params called `name` and `regExp` on the current loader's context.
```javascript
const interpolatedName = loaderUtils.interpolateName(loaderContext, name, options);
```
The following tokens are replaced in the `name` parameter:
* `[ext]` the extension of the resource
* `[name]` the basename of the resource
* `[path]` the path of the resource relative to the `context` query parameter or option.
* `[folder]` the folder the resource is in
* `[query]` the queryof the resource, i.e. `?foo=bar`
* `[emoji]` a random emoji representation of `options.content`
* `[emoji:<length>]` same as above, but with a customizable number of emojis
* `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the md4 hash)
* `[<hashType>:contenthash:<digestType>:<length>]` optionally one can configure
* other `hashType`s, i. e. `sha1`, `md4`, `md5`, `sha256`, `sha512`
* other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
* and `length` the length in chars
* `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the md4 hash)
* `[<hashType>:hash:<digestType>:<length>]` optionally one can configure
* other `hashType`s, i. e. `sha1`, `md4`, `md5`, `sha256`, `sha512`
* other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
* and `length` the length in chars
* `[N]` the N-th match obtained from matching the current file name against `options.regExp`
In loader context `[hash]` and `[contenthash]` are the same, but we recommend using `[contenthash]` for avoid misleading.
Examples
``` javascript
// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
loaderUtils.interpolateName(loaderContext, "js/[hash].script.[ext]", { content: ... });
// => js/9473fdd0d880a43c21b7778d34872157.script.js
// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
// loaderContext.resourceQuery = "?foo=bar"
loaderUtils.interpolateName(loaderContext, "js/[hash].script.[ext][query]", { content: ... });
// => js/9473fdd0d880a43c21b7778d34872157.script.js?foo=bar
// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
loaderUtils.interpolateName(loaderContext, "js/[contenthash].script.[ext]", { content: ... });
// => js/9473fdd0d880a43c21b7778d34872157.script.js
// loaderContext.resourcePath = "/absolute/path/to/app/page.html"
loaderUtils.interpolateName(loaderContext, "html-[hash:6].html", { content: ... });
// => html-9473fd.html
// loaderContext.resourcePath = "/absolute/path/to/app/flash.txt"
loaderUtils.interpolateName(loaderContext, "[hash]", { content: ... });
// => c31e9820c001c9c4a86bce33ce43b679
// loaderContext.resourcePath = "/absolute/path/to/app/img/image.gif"
loaderUtils.interpolateName(loaderContext, "[emoji]", { content: ... });
// => 👍
// loaderContext.resourcePath = "/absolute/path/to/app/img/image.gif"
loaderUtils.interpolateName(loaderContext, "[emoji:4]", { content: ... });
// => 🙍🏢📤🐝
// loaderContext.resourcePath = "/absolute/path/to/app/img/image.png"
loaderUtils.interpolateName(loaderContext, "[sha512:hash:base64:7].[ext]", { content: ... });
// => 2BKDTjl.png
// use sha512 hash instead of md4 and with only 7 chars of base64
// loaderContext.resourcePath = "/absolute/path/to/app/img/myself.png"
// loaderContext.query.name =
loaderUtils.interpolateName(loaderContext, "picture.png");
// => picture.png
// loaderContext.resourcePath = "/absolute/path/to/app/dir/file.png"
loaderUtils.interpolateName(loaderContext, "[path][name].[ext]?[hash]", { content: ... });
// => /app/dir/file.png?9473fdd0d880a43c21b7778d34872157
// loaderContext.resourcePath = "/absolute/path/to/app/js/page-home.js"
loaderUtils.interpolateName(loaderContext, "script-[1].[ext]", { regExp: "page-(.*)\\.js", content: ... });
// => script-home.js
// loaderContext.resourcePath = "/absolute/path/to/app/js/javascript.js"
// loaderContext.resourceQuery = "?foo=bar"
loaderUtils.interpolateName(
loaderContext,
(resourcePath, resourceQuery) => {
// resourcePath - `/app/js/javascript.js`
// resourceQuery - `?foo=bar`
return "js/[hash].script.[ext]";
},
{ content: ... }
);
// => js/9473fdd0d880a43c21b7778d34872157.script.js
```
### `getHashDigest`
``` javascript
const digestString = loaderUtils.getHashDigest(buffer, hashType, digestType, maxLength);
```
* `buffer` the content that should be hashed
* `hashType` one of `sha1`, `md4`, `md5`, `sha256`, `sha512` or any other node.js supported hash type
* `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
* `maxLength` the maximum length in chars
## License
MIT (http://www.opensource.org/licenses/mit-license.php)
@@ -0,0 +1,16 @@
'use strict';
function getCurrentRequest(loaderContext) {
if (loaderContext.currentRequest) {
return loaderContext.currentRequest;
}
const request = loaderContext.loaders
.slice(loaderContext.loaderIndex)
.map((obj) => obj.request)
.concat([loaderContext.resource]);
return request.join('!');
}
module.exports = getCurrentRequest;
+91
View File
@@ -0,0 +1,91 @@
'use strict';
const baseEncodeTables = {
26: 'abcdefghijklmnopqrstuvwxyz',
32: '123456789abcdefghjkmnpqrstuvwxyz', // no 0lio
36: '0123456789abcdefghijklmnopqrstuvwxyz',
49: 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no lIO
52: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
58: '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no 0lIO
62: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
64: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_',
};
function encodeBufferToBase(buffer, base) {
const encodeTable = baseEncodeTables[base];
if (!encodeTable) {
throw new Error('Unknown encoding base' + base);
}
const readLength = buffer.length;
const Big = require('big.js');
Big.RM = Big.DP = 0;
let b = new Big(0);
for (let i = readLength - 1; i >= 0; i--) {
b = b.times(256).plus(buffer[i]);
}
let output = '';
while (b.gt(0)) {
output = encodeTable[b.mod(base)] + output;
b = b.div(base);
}
Big.DP = 20;
Big.RM = 1;
return output;
}
let createMd4 = undefined;
let BatchedHash = undefined;
function getHashDigest(buffer, hashType, digestType, maxLength) {
hashType = hashType || 'md4';
maxLength = maxLength || 9999;
let hash;
try {
hash = require('crypto').createHash(hashType);
} catch (error) {
if (error.code === 'ERR_OSSL_EVP_UNSUPPORTED' && hashType === 'md4') {
if (createMd4 === undefined) {
createMd4 = require('./hash/md4');
if (BatchedHash === undefined) {
BatchedHash = require('./hash/BatchedHash');
}
}
hash = new BatchedHash(createMd4());
}
if (!hash) {
throw error;
}
}
hash.update(buffer);
if (
digestType === 'base26' ||
digestType === 'base32' ||
digestType === 'base36' ||
digestType === 'base49' ||
digestType === 'base52' ||
digestType === 'base58' ||
digestType === 'base62'
) {
return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr(
0,
maxLength
);
} else {
return hash.digest(digestType || 'hex').substr(0, maxLength);
}
}
module.exports = getHashDigest;
+20
View File
@@ -0,0 +1,20 @@
'use strict';
const parseQuery = require('./parseQuery');
function getOptions(loaderContext) {
const query = loaderContext.query;
if (typeof query === 'string' && query !== '') {
return parseQuery(loaderContext.query);
}
if (!query || typeof query !== 'object') {
// Not object-like queries are not supported.
return {};
}
return query;
}
module.exports = getOptions;
@@ -0,0 +1,16 @@
'use strict';
function getRemainingRequest(loaderContext) {
if (loaderContext.remainingRequest) {
return loaderContext.remainingRequest;
}
const request = loaderContext.loaders
.slice(loaderContext.loaderIndex + 1)
.map((obj) => obj.request)
.concat([loaderContext.resource]);
return request.join('!');
}
module.exports = getRemainingRequest;
@@ -0,0 +1,64 @@
const MAX_SHORT_STRING = require('./wasm-hash').MAX_SHORT_STRING;
class BatchedHash {
constructor(hash) {
this.string = undefined;
this.encoding = undefined;
this.hash = hash;
}
/**
* Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
* @param {string|Buffer} data data
* @param {string=} inputEncoding data encoding
* @returns {this} updated hash
*/
update(data, inputEncoding) {
if (this.string !== undefined) {
if (
typeof data === 'string' &&
inputEncoding === this.encoding &&
this.string.length + data.length < MAX_SHORT_STRING
) {
this.string += data;
return this;
}
this.hash.update(this.string, this.encoding);
this.string = undefined;
}
if (typeof data === 'string') {
if (
data.length < MAX_SHORT_STRING &&
// base64 encoding is not valid since it may contain padding chars
(!inputEncoding || !inputEncoding.startsWith('ba'))
) {
this.string = data;
this.encoding = inputEncoding;
} else {
this.hash.update(data, inputEncoding);
}
} else {
this.hash.update(data);
}
return this;
}
/**
* Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
* @param {string=} encoding encoding of the return value
* @returns {string|Buffer} digest
*/
digest(encoding) {
if (this.string !== undefined) {
this.hash.update(this.string, this.encoding);
}
return this.hash.digest(encoding);
}
}
module.exports = BatchedHash;
+20
View File
@@ -0,0 +1,20 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
'use strict';
const create = require('./wasm-hash');
//#region wasm code: md4 (../../../assembly/hash/md4.asm.ts) --initialMemory 1
const md4 = new WebAssembly.Module(
Buffer.from(
// 2150 bytes
'AGFzbQEAAAABCAJgAX8AYAAAAwUEAQAAAAUDAQABBhoFfwFBAAt/AUEAC38BQQALfwFBAAt/AUEACwciBARpbml0AAAGdXBkYXRlAAIFZmluYWwAAwZtZW1vcnkCAAqFEAQmAEGBxpS6BiQBQYnXtv5+JAJB/rnrxXkkA0H2qMmBASQEQQAkAAvMCgEYfyMBIQojAiEGIwMhByMEIQgDQCAAIAVLBEAgBSgCCCINIAcgBiAFKAIEIgsgCCAHIAUoAgAiDCAKIAggBiAHIAhzcXNqakEDdyIDIAYgB3Nxc2pqQQd3IgEgAyAGc3FzampBC3chAiAFKAIUIg8gASACIAUoAhAiCSADIAEgBSgCDCIOIAYgAyACIAEgA3Nxc2pqQRN3IgQgASACc3FzampBA3ciAyACIARzcXNqakEHdyEBIAUoAiAiEiADIAEgBSgCHCIRIAQgAyAFKAIYIhAgAiAEIAEgAyAEc3FzampBC3ciAiABIANzcXNqakETdyIEIAEgAnNxc2pqQQN3IQMgBSgCLCIVIAQgAyAFKAIoIhQgAiAEIAUoAiQiEyABIAIgAyACIARzcXNqakEHdyIBIAMgBHNxc2pqQQt3IgIgASADc3FzampBE3chBCAPIBAgCSAVIBQgEyAFKAI4IhYgAiAEIAUoAjQiFyABIAIgBSgCMCIYIAMgASAEIAEgAnNxc2pqQQN3IgEgAiAEc3FzampBB3ciAiABIARzcXNqakELdyIDIAkgAiAMIAEgBSgCPCIJIAQgASADIAEgAnNxc2pqQRN3IgEgAiADcnEgAiADcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyaiASakGZ84nUBWpBCXciAyAPIAQgCyACIBggASADIAIgBHJxIAIgBHFyampBmfOJ1AVqQQ13IgEgAyAEcnEgAyAEcXJqakGZ84nUBWpBA3ciAiABIANycSABIANxcmpqQZnzidQFakEFdyIEIAEgAnJxIAEgAnFyampBmfOJ1AVqQQl3IgMgECAEIAIgFyABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmogDWpBmfOJ1AVqQQN3IgIgASADcnEgASADcXJqakGZ84nUBWpBBXciBCABIAJycSABIAJxcmpqQZnzidQFakEJdyIDIBEgBCAOIAIgFiABIAMgAiAEcnEgAiAEcXJqakGZ84nUBWpBDXciASADIARycSADIARxcmpqQZnzidQFakEDdyICIAEgA3JxIAEgA3FyampBmfOJ1AVqQQV3IgQgASACcnEgASACcXJqakGZ84nUBWpBCXciAyAMIAIgAyAJIAEgAyACIARycSACIARxcmpqQZnzidQFakENdyIBcyAEc2pqQaHX5/YGakEDdyICIAQgASACcyADc2ogEmpBodfn9gZqQQl3IgRzIAFzampBodfn9gZqQQt3IgMgAiADIBggASADIARzIAJzampBodfn9gZqQQ93IgFzIARzaiANakGh1+f2BmpBA3ciAiAUIAQgASACcyADc2pqQaHX5/YGakEJdyIEcyABc2pqQaHX5/YGakELdyIDIAsgAiADIBYgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgIgEyAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3chAyAKIA4gAiADIBcgASADIARzIAJzampBodfn9gZqQQ93IgFzIARzampBodfn9gZqQQN3IgJqIQogBiAJIAEgESADIAIgFSAEIAEgAnMgA3NqakGh1+f2BmpBCXciBHMgAXNqakGh1+f2BmpBC3ciAyAEcyACc2pqQaHX5/YGakEPd2ohBiADIAdqIQcgBCAIaiEIIAVBQGshBQwBCwsgCiQBIAYkAiAHJAMgCCQECw0AIAAQASMAIABqJAAL/wQCA38BfiMAIABqrUIDhiEEIABByABqQUBxIgJBCGshAyAAIgFBAWohACABQYABOgAAA0AgACACSUEAIABBB3EbBEAgAEEAOgAAIABBAWohAAwBCwsDQCAAIAJJBEAgAEIANwMAIABBCGohAAwBCwsgAyAENwMAIAIQAUEAIwGtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEIIwKtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEQIwOtIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAEEYIwStIgRC//8DgyAEQoCA/P8Pg0IQhoQiBEL/gYCA8B+DIARCgP6DgIDgP4NCCIaEIgRCj4C8gPCBwAeDQgiGIARC8IHAh4CegPgAg0IEiIQiBEKGjJiw4MCBgwZ8QgSIQoGChIiQoMCAAYNCJ34gBEKw4MCBg4aMmDCEfDcDAAs=',
'base64'
)
);
//#endregion
module.exports = create.bind(null, md4, [], 64, 32);
+208
View File
@@ -0,0 +1,208 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
'use strict';
// 65536 is the size of a wasm memory page
// 64 is the maximum chunk size for every possible wasm hash implementation
// 4 is the maximum number of bytes per char for string encoding (max is utf-8)
// ~3 makes sure that it's always a block of 4 chars, so avoid partially encoded bytes for base64
const MAX_SHORT_STRING = Math.floor((65536 - 64) / 4) & ~3;
class WasmHash {
/**
* @param {WebAssembly.Instance} instance wasm instance
* @param {WebAssembly.Instance[]} instancesPool pool of instances
* @param {number} chunkSize size of data chunks passed to wasm
* @param {number} digestSize size of digest returned by wasm
*/
constructor(instance, instancesPool, chunkSize, digestSize) {
const exports = /** @type {any} */ (instance.exports);
exports.init();
this.exports = exports;
this.mem = Buffer.from(exports.memory.buffer, 0, 65536);
this.buffered = 0;
this.instancesPool = instancesPool;
this.chunkSize = chunkSize;
this.digestSize = digestSize;
}
reset() {
this.buffered = 0;
this.exports.init();
}
/**
* @param {Buffer | string} data data
* @param {BufferEncoding=} encoding encoding
* @returns {this} itself
*/
update(data, encoding) {
if (typeof data === 'string') {
while (data.length > MAX_SHORT_STRING) {
this._updateWithShortString(data.slice(0, MAX_SHORT_STRING), encoding);
data = data.slice(MAX_SHORT_STRING);
}
this._updateWithShortString(data, encoding);
return this;
}
this._updateWithBuffer(data);
return this;
}
/**
* @param {string} data data
* @param {BufferEncoding=} encoding encoding
* @returns {void}
*/
_updateWithShortString(data, encoding) {
const { exports, buffered, mem, chunkSize } = this;
let endPos;
if (data.length < 70) {
if (!encoding || encoding === 'utf-8' || encoding === 'utf8') {
endPos = buffered;
for (let i = 0; i < data.length; i++) {
const cc = data.charCodeAt(i);
if (cc < 0x80) {
mem[endPos++] = cc;
} else if (cc < 0x800) {
mem[endPos] = (cc >> 6) | 0xc0;
mem[endPos + 1] = (cc & 0x3f) | 0x80;
endPos += 2;
} else {
// bail-out for weird chars
endPos += mem.write(data.slice(i), endPos, encoding);
break;
}
}
} else if (encoding === 'latin1') {
endPos = buffered;
for (let i = 0; i < data.length; i++) {
const cc = data.charCodeAt(i);
mem[endPos++] = cc;
}
} else {
endPos = buffered + mem.write(data, buffered, encoding);
}
} else {
endPos = buffered + mem.write(data, buffered, encoding);
}
if (endPos < chunkSize) {
this.buffered = endPos;
} else {
const l = endPos & ~(this.chunkSize - 1);
exports.update(l);
const newBuffered = endPos - l;
this.buffered = newBuffered;
if (newBuffered > 0) {
mem.copyWithin(0, l, endPos);
}
}
}
/**
* @param {Buffer} data data
* @returns {void}
*/
_updateWithBuffer(data) {
const { exports, buffered, mem } = this;
const length = data.length;
if (buffered + length < this.chunkSize) {
data.copy(mem, buffered, 0, length);
this.buffered += length;
} else {
const l = (buffered + length) & ~(this.chunkSize - 1);
if (l > 65536) {
let i = 65536 - buffered;
data.copy(mem, buffered, 0, i);
exports.update(65536);
const stop = l - buffered - 65536;
while (i < stop) {
data.copy(mem, 0, i, i + 65536);
exports.update(65536);
i += 65536;
}
data.copy(mem, 0, i, l - buffered);
exports.update(l - buffered - i);
} else {
data.copy(mem, buffered, 0, l - buffered);
exports.update(l);
}
const newBuffered = length + buffered - l;
this.buffered = newBuffered;
if (newBuffered > 0) {
data.copy(mem, 0, length - newBuffered, length);
}
}
}
digest(type) {
const { exports, buffered, mem, digestSize } = this;
exports.final(buffered);
this.instancesPool.push(this);
const hex = mem.toString('latin1', 0, digestSize);
if (type === 'hex') {
return hex;
}
if (type === 'binary' || !type) {
return Buffer.from(hex, 'hex');
}
return Buffer.from(hex, 'hex').toString(type);
}
}
const create = (wasmModule, instancesPool, chunkSize, digestSize) => {
if (instancesPool.length > 0) {
const old = instancesPool.pop();
old.reset();
return old;
} else {
return new WasmHash(
new WebAssembly.Instance(wasmModule),
instancesPool,
chunkSize,
digestSize
);
}
};
module.exports = create;
module.exports.MAX_SHORT_STRING = MAX_SHORT_STRING;
+23
View File
@@ -0,0 +1,23 @@
'use strict';
const getOptions = require('./getOptions');
const parseQuery = require('./parseQuery');
const stringifyRequest = require('./stringifyRequest');
const getRemainingRequest = require('./getRemainingRequest');
const getCurrentRequest = require('./getCurrentRequest');
const isUrlRequest = require('./isUrlRequest');
const urlToRequest = require('./urlToRequest');
const parseString = require('./parseString');
const getHashDigest = require('./getHashDigest');
const interpolateName = require('./interpolateName');
exports.getOptions = getOptions;
exports.parseQuery = parseQuery;
exports.stringifyRequest = stringifyRequest;
exports.getRemainingRequest = getRemainingRequest;
exports.getCurrentRequest = getCurrentRequest;
exports.isUrlRequest = isUrlRequest;
exports.urlToRequest = urlToRequest;
exports.parseString = parseString;
exports.getHashDigest = getHashDigest;
exports.interpolateName = interpolateName;
@@ -0,0 +1,151 @@
'use strict';
const path = require('path');
const emojisList = require('emojis-list');
const getHashDigest = require('./getHashDigest');
const emojiRegex = /[\uD800-\uDFFF]./;
const emojiList = emojisList.filter((emoji) => emojiRegex.test(emoji));
const emojiCache = {};
function encodeStringToEmoji(content, length) {
if (emojiCache[content]) {
return emojiCache[content];
}
length = length || 1;
const emojis = [];
do {
if (!emojiList.length) {
throw new Error('Ran out of emoji');
}
const index = Math.floor(Math.random() * emojiList.length);
emojis.push(emojiList[index]);
emojiList.splice(index, 1);
} while (--length > 0);
const emojiEncoding = emojis.join('');
emojiCache[content] = emojiEncoding;
return emojiEncoding;
}
function interpolateName(loaderContext, name, options) {
let filename;
const hasQuery =
loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1;
if (typeof name === 'function') {
filename = name(
loaderContext.resourcePath,
hasQuery ? loaderContext.resourceQuery : undefined
);
} else {
filename = name || '[hash].[ext]';
}
const context = options.context;
const content = options.content;
const regExp = options.regExp;
let ext = 'bin';
let basename = 'file';
let directory = '';
let folder = '';
let query = '';
if (loaderContext.resourcePath) {
const parsed = path.parse(loaderContext.resourcePath);
let resourcePath = loaderContext.resourcePath;
if (parsed.ext) {
ext = parsed.ext.substr(1);
}
if (parsed.dir) {
basename = parsed.name;
resourcePath = parsed.dir + path.sep;
}
if (typeof context !== 'undefined') {
directory = path
.relative(context, resourcePath + '_')
.replace(/\\/g, '/')
.replace(/\.\.(\/)?/g, '_$1');
directory = directory.substr(0, directory.length - 1);
} else {
directory = resourcePath.replace(/\\/g, '/').replace(/\.\.(\/)?/g, '_$1');
}
if (directory.length === 1) {
directory = '';
} else if (directory.length > 1) {
folder = path.basename(directory);
}
}
if (loaderContext.resourceQuery && loaderContext.resourceQuery.length > 1) {
query = loaderContext.resourceQuery;
const hashIdx = query.indexOf('#');
if (hashIdx >= 0) {
query = query.substr(0, hashIdx);
}
}
let url = filename;
if (content) {
// Match hash template
url = url
// `hash` and `contenthash` are same in `loader-utils` context
// let's keep `hash` for backward compatibility
.replace(
/\[(?:([^:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
(all, hashType, digestType, maxLength) =>
getHashDigest(content, hashType, digestType, parseInt(maxLength, 10))
)
.replace(/\[emoji(?::(\d+))?\]/gi, (all, length) =>
encodeStringToEmoji(content, parseInt(length, 10))
);
}
url = url
.replace(/\[ext\]/gi, () => ext)
.replace(/\[name\]/gi, () => basename)
.replace(/\[path\]/gi, () => directory)
.replace(/\[folder\]/gi, () => folder)
.replace(/\[query\]/gi, () => query);
if (regExp && loaderContext.resourcePath) {
const match = loaderContext.resourcePath.match(new RegExp(regExp));
match &&
match.forEach((matched, i) => {
url = url.replace(new RegExp('\\[' + i + '\\]', 'ig'), matched);
});
}
if (
typeof loaderContext.options === 'object' &&
typeof loaderContext.options.customInterpolateName === 'function'
) {
url = loaderContext.options.customInterpolateName.call(
loaderContext,
url,
name,
options
);
}
return url;
}
module.exports = interpolateName;
+31
View File
@@ -0,0 +1,31 @@
'use strict';
const path = require('path');
function isUrlRequest(url, root) {
// An URL is not an request if
// 1. It's an absolute url and it is not `windows` path like `C:\dir\file`
if (/^[a-z][a-z0-9+.-]*:/i.test(url) && !path.win32.isAbsolute(url)) {
return false;
}
// 2. It's a protocol-relative
if (/^\/\//.test(url)) {
return false;
}
// 3. It's some kind of url for a template
if (/^[{}[\]#*;,'§$%&(=?`´^°<>]/.test(url)) {
return false;
}
// 4. It's also not an request if root isn't set and it's a root-relative url
if ((root === undefined || root === false) && /^\//.test(url)) {
return false;
}
return true;
}
module.exports = isUrlRequest;
+69
View File
@@ -0,0 +1,69 @@
'use strict';
const JSON5 = require('json5');
const specialValues = {
null: null,
true: true,
false: false,
};
function parseQuery(query) {
if (query.substr(0, 1) !== '?') {
throw new Error(
"A valid query string passed to parseQuery should begin with '?'"
);
}
query = query.substr(1);
if (!query) {
return {};
}
if (query.substr(0, 1) === '{' && query.substr(-1) === '}') {
return JSON5.parse(query);
}
const queryArgs = query.split(/[,&]/g);
const result = {};
queryArgs.forEach((arg) => {
const idx = arg.indexOf('=');
if (idx >= 0) {
let name = arg.substr(0, idx);
let value = decodeURIComponent(arg.substr(idx + 1));
// eslint-disable-next-line no-prototype-builtins
if (specialValues.hasOwnProperty(value)) {
value = specialValues[value];
}
if (name.substr(-2) === '[]') {
name = decodeURIComponent(name.substr(0, name.length - 2));
if (!Array.isArray(result[name])) {
result[name] = [];
}
result[name].push(value);
} else {
name = decodeURIComponent(name);
result[name] = value;
}
} else {
if (arg.substr(0, 1) === '-') {
result[decodeURIComponent(arg.substr(1))] = false;
} else if (arg.substr(0, 1) === '+') {
result[decodeURIComponent(arg.substr(1))] = true;
} else {
result[decodeURIComponent(arg)] = true;
}
}
});
return result;
}
module.exports = parseQuery;
+23
View File
@@ -0,0 +1,23 @@
'use strict';
function parseString(str) {
try {
if (str[0] === '"') {
return JSON.parse(str);
}
if (str[0] === "'" && str.substr(str.length - 1) === "'") {
return parseString(
str
.replace(/\\.|"/g, (x) => (x === '"' ? '\\"' : x))
.replace(/^'|'$/g, '"')
);
}
return JSON.parse('"' + str + '"');
} catch (e) {
return str;
}
}
module.exports = parseString;
@@ -0,0 +1,51 @@
'use strict';
const path = require('path');
const matchRelativePath = /^\.\.?[/\\]/;
function isAbsolutePath(str) {
return path.posix.isAbsolute(str) || path.win32.isAbsolute(str);
}
function isRelativePath(str) {
return matchRelativePath.test(str);
}
function stringifyRequest(loaderContext, request) {
const splitted = request.split('!');
const context =
loaderContext.context ||
(loaderContext.options && loaderContext.options.context);
return JSON.stringify(
splitted
.map((part) => {
// First, separate singlePath from query, because the query might contain paths again
const splittedPart = part.match(/^(.*?)(\?.*)/);
const query = splittedPart ? splittedPart[2] : '';
let singlePath = splittedPart ? splittedPart[1] : part;
if (isAbsolutePath(singlePath) && context) {
singlePath = path.relative(context, singlePath);
if (isAbsolutePath(singlePath)) {
// If singlePath still matches an absolute path, singlePath was on a different drive than context.
// In this case, we leave the path platform-specific without replacing any separators.
// @see https://github.com/webpack/loader-utils/pull/14
return singlePath + query;
}
if (isRelativePath(singlePath) === false) {
// Ensure that the relative path starts at least with ./ otherwise it would be a request into the modules directory (like node_modules).
singlePath = './' + singlePath;
}
}
return singlePath.replace(/\\/g, '/') + query;
})
.join('!')
);
}
module.exports = stringifyRequest;
+60
View File
@@ -0,0 +1,60 @@
'use strict';
// we can't use path.win32.isAbsolute because it also matches paths starting with a forward slash
const matchNativeWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
function urlToRequest(url, root) {
// Do not rewrite an empty url
if (url === '') {
return '';
}
const moduleRequestRegex = /^[^?]*~/;
let request;
if (matchNativeWin32Path.test(url)) {
// absolute windows path, keep it
request = url;
} else if (root !== undefined && root !== false && /^\//.test(url)) {
// if root is set and the url is root-relative
switch (typeof root) {
// 1. root is a string: root is prefixed to the url
case 'string':
// special case: `~` roots convert to module request
if (moduleRequestRegex.test(root)) {
request = root.replace(/([^~/])$/, '$1/') + url.slice(1);
} else {
request = root + url;
}
break;
// 2. root is `true`: absolute paths are allowed
// *nix only, windows-style absolute paths are always allowed as they doesn't start with a `/`
case 'boolean':
request = url;
break;
default:
throw new Error(
"Unexpected parameters to loader-utils 'urlToRequest': url = " +
url +
', root = ' +
root +
'.'
);
}
} else if (/^\.\.?\//.test(url)) {
// A relative url stays
request = url;
} else {
// every other url is threaded like a relative url
request = './' + url;
}
// A `~` makes the url an module
if (moduleRequestRegex.test(request)) {
request = request.replace(moduleRequestRegex, '');
}
return request;
}
module.exports = urlToRequest;
+73
View File
@@ -0,0 +1,73 @@
{
"_args": [
[
"loader-utils@2.0.2",
"/home/node/nuxt"
]
],
"_from": "loader-utils@2.0.2",
"_id": "loader-utils@2.0.2",
"_inBundle": false,
"_integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"_location": "/css-loader/loader-utils",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "loader-utils@2.0.2",
"name": "loader-utils",
"escapedName": "loader-utils",
"rawSpec": "2.0.2",
"saveSpec": null,
"fetchSpec": "2.0.2"
},
"_requiredBy": [
"/css-loader"
],
"_resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"_spec": "2.0.2",
"_where": "/home/node/nuxt",
"author": {
"name": "Tobias Koppers @sokra"
},
"bugs": {
"url": "https://github.com/webpack/loader-utils/issues"
},
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
},
"description": "utils for webpack loaders",
"devDependencies": {
"coveralls": "^3.0.9",
"eslint": "^6.8.0",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-prettier": "^3.1.2",
"jest": "^25.1.0",
"prettier": "^1.19.1",
"standard-version": "^7.1.0"
},
"engines": {
"node": ">=8.9.0"
},
"files": [
"lib"
],
"homepage": "https://github.com/webpack/loader-utils#readme",
"license": "MIT",
"main": "lib/index.js",
"name": "loader-utils",
"repository": {
"type": "git",
"url": "git+https://github.com/webpack/loader-utils.git"
},
"scripts": {
"lint": "eslint lib test",
"pretest": "yarn lint",
"release": "yarn test && standard-version",
"test": "jest",
"test:ci": "jest --coverage"
},
"version": "2.0.2"
}
+286
View File
@@ -0,0 +1,286 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.7.1](https://github.com/webpack/schema-utils/compare/v2.7.0...v2.7.1) (2020-08-31)
### Bug Fixes
* remove esModuleInterop from tsconfig ([#110](https://github.com/webpack/schema-utils/issues/110)) ([#111](https://github.com/webpack/schema-utils/issues/111)) ([2f40154](https://github.com/webpack/schema-utils/commit/2f40154b91e45b393258ae9dd8f10cc3b8590b7d))
## [2.7.0](https://github.com/webpack/schema-utils/compare/v2.6.6...v2.7.0) (2020-05-29)
### Features
* improve hints ([a36e535](https://github.com/webpack/schema-utils/commit/a36e535faca1b01e27c3bfa3c8bee9227c3f836c))
* smart not case ([#101](https://github.com/webpack/schema-utils/issues/101)) ([698d8b0](https://github.com/webpack/schema-utils/commit/698d8b05462d86aadb217e25a45c7b953a79a52e))
### Bug Fixes
* move @types/json-schema from devDependencies to dependencies ([#97](https://github.com/webpack/schema-utils/issues/97)) ([#98](https://github.com/webpack/schema-utils/issues/98)) ([945e67d](https://github.com/webpack/schema-utils/commit/945e67db5e19baf7ec7df72813b0739dd56f950d))
### [2.6.6](https://github.com/webpack/schema-utils/compare/v2.6.5...v2.6.6) (2020-04-17)
### Bug Fixes
* improve perf
### [2.6.5](https://github.com/webpack/schema-utils/compare/v2.6.4...v2.6.5) (2020-03-11)
### Bug Fixes
* correct dots at end of sentence ([7284beb](https://github.com/webpack/schema-utils/commit/7284bebe00cd570f1bef2c15951a07b9794038e6))
### [2.6.4](https://github.com/webpack/schema-utils/compare/v2.6.3...v2.6.4) (2020-01-17)
### Bug Fixes
* change `initialised` to `initialized` ([#87](https://github.com/webpack/schema-utils/issues/87)) ([70f12d3](https://github.com/webpack/schema-utils/commit/70f12d33a8eaa27249bc9c1a27f886724cf91ea7))
### [2.6.3](https://github.com/webpack/schema-utils/compare/v2.6.2...v2.6.3) (2020-01-17)
### Bug Fixes
* prefer the `baseDataPath` option from arguments ([#86](https://github.com/webpack/schema-utils/issues/86)) ([e236859](https://github.com/webpack/schema-utils/commit/e236859e85b28e35e1294f86fc1ff596a5031cea))
### [2.6.2](https://github.com/webpack/schema-utils/compare/v2.6.1...v2.6.2) (2020-01-14)
### Bug Fixes
* better handle Windows absolute paths ([#85](https://github.com/webpack/schema-utils/issues/85)) ([1fa2930](https://github.com/webpack/schema-utils/commit/1fa2930a161e907b9fc53a7233d605910afdb883))
### [2.6.1](https://github.com/webpack/schema-utils/compare/v2.6.0...v2.6.1) (2019-11-28)
### Bug Fixes
* typescript declarations ([#84](https://github.com/webpack/schema-utils/issues/84)) ([89d55a9](https://github.com/webpack/schema-utils/commit/89d55a9a8edfa6a8ac8b112f226bb3154e260319))
## [2.6.0](https://github.com/webpack/schema-utils/compare/v2.5.0...v2.6.0) (2019-11-27)
### Features
* support configuration via title ([#81](https://github.com/webpack/schema-utils/issues/81)) ([afddc10](https://github.com/webpack/schema-utils/commit/afddc109f6891cd37a9f1835d50862d119a072bf))
### Bug Fixes
* typescript definitions ([#70](https://github.com/webpack/schema-utils/issues/70)) ([f38158d](https://github.com/webpack/schema-utils/commit/f38158d6d040e2c701622778ae8122fb26a4f990))
## [2.5.0](https://github.com/webpack/schema-utils/compare/v2.4.1...v2.5.0) (2019-10-15)
### Bug Fixes
* rework format for maxLength, minLength ([#67](https://github.com/webpack/schema-utils/issues/67)) ([0d12259](https://github.com/webpack/schema-utils/commit/0d12259))
* support all cases with one number in range ([#64](https://github.com/webpack/schema-utils/issues/64)) ([7fc8069](https://github.com/webpack/schema-utils/commit/7fc8069))
* typescript definition and export naming ([#69](https://github.com/webpack/schema-utils/issues/69)) ([a435b79](https://github.com/webpack/schema-utils/commit/a435b79))
### Features
* "smart" numbers range ([62fb107](https://github.com/webpack/schema-utils/commit/62fb107))
### [2.4.1](https://github.com/webpack/schema-utils/compare/v2.4.0...v2.4.1) (2019-09-27)
### Bug Fixes
* publish definitions ([#58](https://github.com/webpack/schema-utils/issues/58)) ([1885faa](https://github.com/webpack/schema-utils/commit/1885faa))
## [2.4.0](https://github.com/webpack/schema-utils/compare/v2.3.0...v2.4.0) (2019-09-26)
### Features
* better errors when the `type` keyword doesn't exist ([0988be2](https://github.com/webpack/schema-utils/commit/0988be2))
* support $data reference ([#56](https://github.com/webpack/schema-utils/issues/56)) ([d2f11d6](https://github.com/webpack/schema-utils/commit/d2f11d6))
* types definitions ([#52](https://github.com/webpack/schema-utils/issues/52)) ([facb431](https://github.com/webpack/schema-utils/commit/facb431))
## [2.3.0](https://github.com/webpack/schema-utils/compare/v2.2.0...v2.3.0) (2019-09-26)
### Features
* support `not` keyword ([#53](https://github.com/webpack/schema-utils/issues/53)) ([765f458](https://github.com/webpack/schema-utils/commit/765f458))
## [2.2.0](https://github.com/webpack/schema-utils/compare/v2.1.0...v2.2.0) (2019-09-02)
### Features
* better error output for `oneOf` and `anyOf` ([#48](https://github.com/webpack/schema-utils/issues/48)) ([#50](https://github.com/webpack/schema-utils/issues/50)) ([332242f](https://github.com/webpack/schema-utils/commit/332242f))
## [2.1.0](https://github.com/webpack-contrib/schema-utils/compare/v2.0.1...v2.1.0) (2019-08-07)
### Bug Fixes
* throw error on sparse arrays ([#47](https://github.com/webpack-contrib/schema-utils/issues/47)) ([b85ac38](https://github.com/webpack-contrib/schema-utils/commit/b85ac38))
### Features
* export `ValidateError` ([#46](https://github.com/webpack-contrib/schema-utils/issues/46)) ([ff781d7](https://github.com/webpack-contrib/schema-utils/commit/ff781d7))
### [2.0.1](https://github.com/webpack-contrib/schema-utils/compare/v2.0.0...v2.0.1) (2019-07-18)
### Bug Fixes
* error message for empty object ([#44](https://github.com/webpack-contrib/schema-utils/issues/44)) ([0b4b4a2](https://github.com/webpack-contrib/schema-utils/commit/0b4b4a2))
### [2.0.0](https://github.com/webpack-contrib/schema-utils/compare/v1.0.0...v2.0.0) (2019-07-17)
### BREAKING CHANGES
* drop support for Node.js < 8.9.0
* drop support `errorMessage`, please use `description` for links.
* api was changed, please look documentation.
* error messages was fully rewritten.
<a name="1.0.0"></a>
# [1.0.0](https://github.com/webpack-contrib/schema-utils/compare/v0.4.7...v1.0.0) (2018-08-07)
### Features
* **src:** add support for custom error messages ([#33](https://github.com/webpack-contrib/schema-utils/issues/33)) ([1cbe4ef](https://github.com/webpack-contrib/schema-utils/commit/1cbe4ef))
<a name="0.4.7"></a>
## [0.4.7](https://github.com/webpack-contrib/schema-utils/compare/v0.4.6...v0.4.7) (2018-08-07)
### Bug Fixes
* **src:** `node >= v4.0.0` support ([#32](https://github.com/webpack-contrib/schema-utils/issues/32)) ([cb13dd4](https://github.com/webpack-contrib/schema-utils/commit/cb13dd4))
<a name="0.4.6"></a>
## [0.4.6](https://github.com/webpack-contrib/schema-utils/compare/v0.4.5...v0.4.6) (2018-08-06)
### Bug Fixes
* **package:** remove lockfile ([#28](https://github.com/webpack-contrib/schema-utils/issues/28)) ([69f1a81](https://github.com/webpack-contrib/schema-utils/commit/69f1a81))
* **package:** remove unnecessary `webpack` dependency ([#26](https://github.com/webpack-contrib/schema-utils/issues/26)) ([532eaa5](https://github.com/webpack-contrib/schema-utils/commit/532eaa5))
<a name="0.4.5"></a>
## [0.4.5](https://github.com/webpack-contrib/schema-utils/compare/v0.4.4...v0.4.5) (2018-02-13)
### Bug Fixes
* **CHANGELOG:** update broken links ([4483b9f](https://github.com/webpack-contrib/schema-utils/commit/4483b9f))
* **package:** update broken links ([f2494ba](https://github.com/webpack-contrib/schema-utils/commit/f2494ba))
<a name="0.4.4"></a>
## [0.4.4](https://github.com/webpack-contrib/schema-utils/compare/v0.4.3...v0.4.4) (2018-02-13)
### Bug Fixes
* **package:** update `dependencies` ([#22](https://github.com/webpack-contrib/schema-utils/issues/22)) ([3aecac6](https://github.com/webpack-contrib/schema-utils/commit/3aecac6))
<a name="0.4.3"></a>
## [0.4.3](https://github.com/webpack-contrib/schema-utils/compare/v0.4.2...v0.4.3) (2017-12-14)
### Bug Fixes
* **validateOptions:** throw `err` instead of `process.exit(1)` ([#17](https://github.com/webpack-contrib/schema-utils/issues/17)) ([c595eda](https://github.com/webpack-contrib/schema-utils/commit/c595eda))
* **ValidationError:** never return `this` in the ctor ([#16](https://github.com/webpack-contrib/schema-utils/issues/16)) ([c723791](https://github.com/webpack-contrib/schema-utils/commit/c723791))
<a name="0.4.2"></a>
## [0.4.2](https://github.com/webpack-contrib/schema-utils/compare/v0.4.1...v0.4.2) (2017-11-09)
### Bug Fixes
* **validateOptions:** catch `ValidationError` and handle it internally ([#15](https://github.com/webpack-contrib/schema-utils/issues/15)) ([9c5ef5e](https://github.com/webpack-contrib/schema-utils/commit/9c5ef5e))
<a name="0.4.1"></a>
## [0.4.1](https://github.com/webpack-contrib/schema-utils/compare/v0.4.0...v0.4.1) (2017-11-03)
### Bug Fixes
* **ValidationError:** use `Error.captureStackTrace` for `err.stack` handling ([#14](https://github.com/webpack-contrib/schema-utils/issues/14)) ([a6fb974](https://github.com/webpack-contrib/schema-utils/commit/a6fb974))
<a name="0.4.0"></a>
# [0.4.0](https://github.com/webpack-contrib/schema-utils/compare/v0.3.0...v0.4.0) (2017-10-28)
### Features
* add support for `typeof`, `instanceof` (`{Function\|RegExp}`) ([#10](https://github.com/webpack-contrib/schema-utils/issues/10)) ([9f01816](https://github.com/webpack-contrib/schema-utils/commit/9f01816))
<a name="0.3.0"></a>
# [0.3.0](https://github.com/webpack-contrib/schema-utils/compare/v0.2.1...v0.3.0) (2017-04-29)
### Features
* add ValidationError ([#8](https://github.com/webpack-contrib/schema-utils/issues/8)) ([d48f0fb](https://github.com/webpack-contrib/schema-utils/commit/d48f0fb))
<a name="0.2.1"></a>
## [0.2.1](https://github.com/webpack-contrib/schema-utils/compare/v0.2.0...v0.2.1) (2017-03-13)
### Bug Fixes
* Include .babelrc to `files` ([28f0363](https://github.com/webpack-contrib/schema-utils/commit/28f0363))
* Include source to `files` ([43b0f2f](https://github.com/webpack-contrib/schema-utils/commit/43b0f2f))
<a name="0.2.0"></a>
# [0.2.0](https://github.com/webpack-contrib/schema-utils/compare/v0.1.0...v0.2.0) (2017-03-12)
<a name="0.1.0"></a>
# 0.1.0 (2017-03-07)
### Features
* **validations:** add validateOptions module ([ae9b47b](https://github.com/webpack-contrib/schema-utils/commit/ae9b47b))
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+20
View File
@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+276
View File
@@ -0,0 +1,276 @@
<div align="center">
<a href="http://json-schema.org">
<img width="160" height="160"
src="https://raw.githubusercontent.com/webpack-contrib/schema-utils/master/.github/assets/logo.png">
</a>
<a href="https://github.com/webpack/webpack">
<img width="200" height="200"
src="https://webpack.js.org/assets/icon-square-big.svg">
</a>
</div>
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![deps][deps]][deps-url]
[![tests][tests]][tests-url]
[![coverage][cover]][cover-url]
[![chat][chat]][chat-url]
[![size][size]][size-url]
# schema-utils
Package for validate options in loaders and plugins.
## Getting Started
To begin, you'll need to install `schema-utils`:
```console
npm install schema-utils
```
## API
**schema.json**
```json
{
"type": "object",
"properties": {
"option": {
"type": "boolean"
}
},
"additionalProperties": false
}
```
```js
import schema from './path/to/schema.json';
import validate from 'schema-utils';
const options = { option: true };
const configuration = { name: 'Loader Name/Plugin Name/Name' };
validate(schema, options, configuration);
```
### `schema`
Type: `String`
JSON schema.
Simple example of schema:
```json
{
"type": "object",
"properties": {
"name": {
"description": "This is description of option.",
"type": "string"
}
},
"additionalProperties": false
}
```
### `options`
Type: `Object`
Object with options.
```js
validate(
schema,
{
name: 123,
},
{ name: 'MyPlugin' }
);
```
### `configuration`
Allow to configure validator.
There is an alternative method to configure the `name` and`baseDataPath` options via the `title` property in the schema.
For example:
```json
{
"title": "My Loader options",
"type": "object",
"properties": {
"name": {
"description": "This is description of option.",
"type": "string"
}
},
"additionalProperties": false
}
```
The last word used for the `baseDataPath` option, other words used for the `name` option.
Based on the example above the `name` option equals `My Loader`, the `baseDataPath` option equals `options`.
#### `name`
Type: `Object`
Default: `"Object"`
Allow to setup name in validation errors.
```js
validate(schema, options, { name: 'MyPlugin' });
```
```shell
Invalid configuration object. MyPlugin has been initialised using a configuration object that does not match the API schema.
- configuration.optionName should be a integer.
```
#### `baseDataPath`
Type: `String`
Default: `"configuration"`
Allow to setup base data path in validation errors.
```js
validate(schema, options, { name: 'MyPlugin', baseDataPath: 'options' });
```
```shell
Invalid options object. MyPlugin has been initialised using an options object that does not match the API schema.
- options.optionName should be a integer.
```
#### `postFormatter`
Type: `Function`
Default: `undefined`
Allow to reformat errors.
```js
validate(schema, options, {
name: 'MyPlugin',
postFormatter: (formattedError, error) => {
if (error.keyword === 'type') {
return `${formattedError}\nAdditional Information.`;
}
return formattedError;
},
});
```
```shell
Invalid options object. MyPlugin has been initialized using an options object that does not match the API schema.
- options.optionName should be a integer.
Additional Information.
```
## Examples
**schema.json**
```json
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"test": {
"anyOf": [
{ "type": "array" },
{ "type": "string" },
{ "instanceof": "RegExp" }
]
},
"transform": {
"instanceof": "Function"
},
"sourceMap": {
"type": "boolean"
}
},
"additionalProperties": false
}
```
### `Loader`
```js
import { getOptions } from 'loader-utils';
import validateOptions from 'schema-utils';
import schema from 'path/to/schema.json';
function loader(src, map) {
const options = getOptions(this) || {};
validateOptions(schema, options, {
name: 'Loader Name',
baseDataPath: 'options',
});
// Code...
}
export default loader;
```
### `Plugin`
```js
import validateOptions from 'schema-utils';
import schema from 'path/to/schema.json';
class Plugin {
constructor(options) {
validateOptions(schema, options, {
name: 'Plugin Name',
baseDataPath: 'options',
});
this.options = options;
}
apply(compiler) {
// Code...
}
}
export default Plugin;
```
## Contributing
Please take a moment to read our contributing guidelines if you haven't yet done so.
[CONTRIBUTING](./.github/CONTRIBUTING.md)
## License
[MIT](./LICENSE)
[npm]: https://img.shields.io/npm/v/schema-utils.svg
[npm-url]: https://npmjs.com/package/schema-utils
[node]: https://img.shields.io/node/v/schema-utils.svg
[node-url]: https://nodejs.org
[deps]: https://david-dm.org/webpack/schema-utils.svg
[deps-url]: https://david-dm.org/webpack/schema-utils
[tests]: https://github.com/webpack/schema-utils/workflows/schema-utils/badge.svg
[tests-url]: https://github.com/webpack/schema-utils/actions
[cover]: https://codecov.io/gh/webpack/schema-utils/branch/master/graph/badge.svg
[cover-url]: https://codecov.io/gh/webpack/schema-utils
[chat]: https://badges.gitter.im/webpack/webpack.svg
[chat-url]: https://gitter.im/webpack/webpack
[size]: https://packagephobia.com/badge?p=schema-utils
[size-url]: https://packagephobia.com/result?p=schema-utils
@@ -0,0 +1,88 @@
export default ValidationError;
export type JSONSchema6 = import('json-schema').JSONSchema6;
export type JSONSchema7 = import('json-schema').JSONSchema7;
export type Schema =
| (import('json-schema').JSONSchema4 & import('./validate').Extend)
| (import('json-schema').JSONSchema6 & import('./validate').Extend)
| (import('json-schema').JSONSchema7 & import('./validate').Extend);
export type ValidationErrorConfiguration = {
name?: string | undefined;
baseDataPath?: string | undefined;
postFormatter?: import('./validate').PostFormatter | undefined;
};
export type PostFormatter = (
formattedError: string,
error: import('ajv').ErrorObject & {
children?: import('ajv').ErrorObject[] | undefined;
}
) => string;
export type SchemaUtilErrorObject = import('ajv').ErrorObject & {
children?: import('ajv').ErrorObject[] | undefined;
};
export type SPECIFICITY = number;
declare class ValidationError extends Error {
/**
* @param {Array<SchemaUtilErrorObject>} errors
* @param {Schema} schema
* @param {ValidationErrorConfiguration} configuration
*/
constructor(
errors: Array<SchemaUtilErrorObject>,
schema: Schema,
configuration?: ValidationErrorConfiguration
);
/** @type {Array<SchemaUtilErrorObject>} */
errors: Array<SchemaUtilErrorObject>;
/** @type {Schema} */
schema: Schema;
/** @type {string} */
headerName: string;
/** @type {string} */
baseDataPath: string;
/** @type {PostFormatter | null} */
postFormatter: PostFormatter | null;
/**
* @param {string} path
* @returns {Schema}
*/
getSchemaPart(path: string): Schema;
/**
* @param {Schema} schema
* @param {boolean} logic
* @param {Array<Object>} prevSchemas
* @returns {string}
*/
formatSchema(
schema: Schema,
logic?: boolean,
prevSchemas?: Array<Object>
): string;
/**
* @param {Schema=} schemaPart
* @param {(boolean | Array<string>)=} additionalPath
* @param {boolean=} needDot
* @param {boolean=} logic
* @returns {string}
*/
getSchemaPartText(
schemaPart?: Schema | undefined,
additionalPath?: (boolean | Array<string>) | undefined,
needDot?: boolean | undefined,
logic?: boolean | undefined
): string;
/**
* @param {Schema=} schemaPart
* @returns {string}
*/
getSchemaPartDescription(schemaPart?: Schema | undefined): string;
/**
* @param {SchemaUtilErrorObject} error
* @returns {string}
*/
formatValidationError(error: SchemaUtilErrorObject): string;
/**
* @param {Array<SchemaUtilErrorObject>} errors
* @returns {string}
*/
formatValidationErrors(errors: Array<SchemaUtilErrorObject>): string;
}
@@ -0,0 +1,2 @@
declare const _exports: typeof import('./validate').default;
export = _exports;
@@ -0,0 +1,12 @@
export default addAbsolutePathKeyword;
export type Ajv = import('ajv').Ajv;
export type ValidateFunction = import('ajv').ValidateFunction;
export type SchemaUtilErrorObject = import('ajv').ErrorObject & {
children?: import('ajv').ErrorObject[] | undefined;
};
/**
*
* @param {Ajv} ajv
* @returns {Ajv}
*/
declare function addAbsolutePathKeyword(ajv: Ajv): Ajv;
@@ -0,0 +1,82 @@
export = Range;
/**
* @typedef {[number, boolean]} RangeValue
*/
/**
* @callback RangeValueCallback
* @param {RangeValue} rangeValue
* @returns {boolean}
*/
declare class Range {
/**
* @param {"left" | "right"} side
* @param {boolean} exclusive
* @returns {">" | ">=" | "<" | "<="}
*/
static getOperator(
side: 'left' | 'right',
exclusive: boolean
): '>' | '>=' | '<' | '<=';
/**
* @param {number} value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string}
*/
static formatRight(value: number, logic: boolean, exclusive: boolean): string;
/**
* @param {number} value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string}
*/
static formatLeft(value: number, logic: boolean, exclusive: boolean): string;
/**
* @param {number} start left side value
* @param {number} end right side value
* @param {boolean} startExclusive is range exclusive from left side
* @param {boolean} endExclusive is range exclusive from right side
* @param {boolean} logic is not logic applied
* @returns {string}
*/
static formatRange(
start: number,
end: number,
startExclusive: boolean,
endExclusive: boolean,
logic: boolean
): string;
/**
* @param {Array<RangeValue>} values
* @param {boolean} logic is not logic applied
* @return {RangeValue} computed value and it's exclusive flag
*/
static getRangeValue(
values: Array<[number, boolean]>,
logic: boolean
): [number, boolean];
/** @type {Array<RangeValue>} */
_left: Array<[number, boolean]>;
/** @type {Array<RangeValue>} */
_right: Array<[number, boolean]>;
/**
* @param {number} value
* @param {boolean=} exclusive
*/
left(value: number, exclusive?: boolean | undefined): void;
/**
* @param {number} value
* @param {boolean=} exclusive
*/
right(value: number, exclusive?: boolean | undefined): void;
/**
* @param {boolean} logic is not logic applied
* @return {string} "smart" range string representation
*/
format(logic?: boolean): string;
}
declare namespace Range {
export { RangeValue, RangeValueCallback };
}
type RangeValue = [number, boolean];
type RangeValueCallback = (rangeValue: [number, boolean]) => boolean;
@@ -0,0 +1,6 @@
export function stringHints(schema: Schema, logic: boolean): string[];
export function numberHints(schema: Schema, logic: boolean): string[];
export type Schema =
| (import('json-schema').JSONSchema4 & import('../validate').Extend)
| (import('json-schema').JSONSchema6 & import('../validate').Extend)
| (import('json-schema').JSONSchema7 & import('../validate').Extend);
@@ -0,0 +1,43 @@
export default validate;
export type JSONSchema4 = import('json-schema').JSONSchema4;
export type JSONSchema6 = import('json-schema').JSONSchema6;
export type JSONSchema7 = import('json-schema').JSONSchema7;
export type ErrorObject = import('ajv').ErrorObject;
export type Extend = {
formatMinimum?: number | undefined;
formatMaximum?: number | undefined;
formatExclusiveMinimum?: boolean | undefined;
formatExclusiveMaximum?: boolean | undefined;
};
export type Schema =
| (import('json-schema').JSONSchema4 & Extend)
| (import('json-schema').JSONSchema6 & Extend)
| (import('json-schema').JSONSchema7 & Extend);
export type SchemaUtilErrorObject = import('ajv').ErrorObject & {
children?: import('ajv').ErrorObject[] | undefined;
};
export type PostFormatter = (
formattedError: string,
error: SchemaUtilErrorObject
) => string;
export type ValidationErrorConfiguration = {
name?: string | undefined;
baseDataPath?: string | undefined;
postFormatter?: PostFormatter | undefined;
};
/**
* @param {Schema} schema
* @param {Array<object> | object} options
* @param {ValidationErrorConfiguration=} configuration
* @returns {void}
*/
declare function validate(
schema: Schema,
options: Array<object> | object,
configuration?: ValidationErrorConfiguration | undefined
): void;
declare namespace validate {
export { ValidationError };
export { ValidationError as ValidateError };
}
import ValidationError from './ValidationError';
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
"use strict";
const validate = require('./validate');
module.exports = validate.default;
@@ -0,0 +1,93 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
/** @typedef {import("ajv").Ajv} Ajv */
/** @typedef {import("ajv").ValidateFunction} ValidateFunction */
/** @typedef {import("../validate").SchemaUtilErrorObject} SchemaUtilErrorObject */
/**
* @param {string} message
* @param {object} schema
* @param {string} data
* @returns {SchemaUtilErrorObject}
*/
function errorMessage(message, schema, data) {
return {
// @ts-ignore
// eslint-disable-next-line no-undefined
dataPath: undefined,
// @ts-ignore
// eslint-disable-next-line no-undefined
schemaPath: undefined,
keyword: 'absolutePath',
params: {
absolutePath: data
},
message,
parentSchema: schema
};
}
/**
* @param {boolean} shouldBeAbsolute
* @param {object} schema
* @param {string} data
* @returns {SchemaUtilErrorObject}
*/
function getErrorFor(shouldBeAbsolute, schema, data) {
const message = shouldBeAbsolute ? `The provided value ${JSON.stringify(data)} is not an absolute path!` : `A relative path is expected. However, the provided value ${JSON.stringify(data)} is an absolute path!`;
return errorMessage(message, schema, data);
}
/**
*
* @param {Ajv} ajv
* @returns {Ajv}
*/
function addAbsolutePathKeyword(ajv) {
ajv.addKeyword('absolutePath', {
errors: true,
type: 'string',
compile(schema, parentSchema) {
/** @type {ValidateFunction} */
const callback = data => {
let passes = true;
const isExclamationMarkPresent = data.includes('!');
if (isExclamationMarkPresent) {
callback.errors = [errorMessage(`The provided value ${JSON.stringify(data)} contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.`, parentSchema, data)];
passes = false;
} // ?:[A-Za-z]:\\ - Windows absolute path
// \\\\ - Windows network absolute path
// \/ - Unix-like OS absolute path
const isCorrectAbsolutePath = schema === /^(?:[A-Za-z]:(\\|\/)|\\\\|\/)/.test(data);
if (!isCorrectAbsolutePath) {
callback.errors = [getErrorFor(schema, parentSchema, data)];
passes = false;
}
return passes;
};
callback.errors = [];
return callback;
}
});
return ajv;
}
var _default = addAbsolutePathKeyword;
exports.default = _default;
+163
View File
@@ -0,0 +1,163 @@
"use strict";
/**
* @typedef {[number, boolean]} RangeValue
*/
/**
* @callback RangeValueCallback
* @param {RangeValue} rangeValue
* @returns {boolean}
*/
class Range {
/**
* @param {"left" | "right"} side
* @param {boolean} exclusive
* @returns {">" | ">=" | "<" | "<="}
*/
static getOperator(side, exclusive) {
if (side === 'left') {
return exclusive ? '>' : '>=';
}
return exclusive ? '<' : '<=';
}
/**
* @param {number} value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string}
*/
static formatRight(value, logic, exclusive) {
if (logic === false) {
return Range.formatLeft(value, !logic, !exclusive);
}
return `should be ${Range.getOperator('right', exclusive)} ${value}`;
}
/**
* @param {number} value
* @param {boolean} logic is not logic applied
* @param {boolean} exclusive is range exclusive
* @returns {string}
*/
static formatLeft(value, logic, exclusive) {
if (logic === false) {
return Range.formatRight(value, !logic, !exclusive);
}
return `should be ${Range.getOperator('left', exclusive)} ${value}`;
}
/**
* @param {number} start left side value
* @param {number} end right side value
* @param {boolean} startExclusive is range exclusive from left side
* @param {boolean} endExclusive is range exclusive from right side
* @param {boolean} logic is not logic applied
* @returns {string}
*/
static formatRange(start, end, startExclusive, endExclusive, logic) {
let result = 'should be';
result += ` ${Range.getOperator(logic ? 'left' : 'right', logic ? startExclusive : !startExclusive)} ${start} `;
result += logic ? 'and' : 'or';
result += ` ${Range.getOperator(logic ? 'right' : 'left', logic ? endExclusive : !endExclusive)} ${end}`;
return result;
}
/**
* @param {Array<RangeValue>} values
* @param {boolean} logic is not logic applied
* @return {RangeValue} computed value and it's exclusive flag
*/
static getRangeValue(values, logic) {
let minMax = logic ? Infinity : -Infinity;
let j = -1;
const predicate = logic ?
/** @type {RangeValueCallback} */
([value]) => value <= minMax :
/** @type {RangeValueCallback} */
([value]) => value >= minMax;
for (let i = 0; i < values.length; i++) {
if (predicate(values[i])) {
[minMax] = values[i];
j = i;
}
}
if (j > -1) {
return values[j];
}
return [Infinity, true];
}
constructor() {
/** @type {Array<RangeValue>} */
this._left = [];
/** @type {Array<RangeValue>} */
this._right = [];
}
/**
* @param {number} value
* @param {boolean=} exclusive
*/
left(value, exclusive = false) {
this._left.push([value, exclusive]);
}
/**
* @param {number} value
* @param {boolean=} exclusive
*/
right(value, exclusive = false) {
this._right.push([value, exclusive]);
}
/**
* @param {boolean} logic is not logic applied
* @return {string} "smart" range string representation
*/
format(logic = true) {
const [start, leftExclusive] = Range.getRangeValue(this._left, logic);
const [end, rightExclusive] = Range.getRangeValue(this._right, !logic);
if (!Number.isFinite(start) && !Number.isFinite(end)) {
return '';
}
const realStart = leftExclusive ? start + 1 : start;
const realEnd = rightExclusive ? end - 1 : end; // e.g. 5 < x < 7, 5 < x <= 6, 6 <= x <= 6
if (realStart === realEnd) {
return `should be ${logic ? '' : '!'}= ${realStart}`;
} // e.g. 4 < x < ∞
if (Number.isFinite(start) && !Number.isFinite(end)) {
return Range.formatLeft(start, logic, leftExclusive);
} // e.g. ∞ < x < 4
if (!Number.isFinite(start) && Number.isFinite(end)) {
return Range.formatRight(end, logic, rightExclusive);
}
return Range.formatRange(start, end, leftExclusive, rightExclusive, logic);
}
}
module.exports = Range;
+105
View File
@@ -0,0 +1,105 @@
"use strict";
const Range = require('./Range');
/** @typedef {import("../validate").Schema} Schema */
/**
* @param {Schema} schema
* @param {boolean} logic
* @return {string[]}
*/
module.exports.stringHints = function stringHints(schema, logic) {
const hints = [];
let type = 'string';
const currentSchema = { ...schema
};
if (!logic) {
const tmpLength = currentSchema.minLength;
const tmpFormat = currentSchema.formatMinimum;
const tmpExclusive = currentSchema.formatExclusiveMaximum;
currentSchema.minLength = currentSchema.maxLength;
currentSchema.maxLength = tmpLength;
currentSchema.formatMinimum = currentSchema.formatMaximum;
currentSchema.formatMaximum = tmpFormat;
currentSchema.formatExclusiveMaximum = !currentSchema.formatExclusiveMinimum;
currentSchema.formatExclusiveMinimum = !tmpExclusive;
}
if (typeof currentSchema.minLength === 'number') {
if (currentSchema.minLength === 1) {
type = 'non-empty string';
} else {
const length = Math.max(currentSchema.minLength - 1, 0);
hints.push(`should be longer than ${length} character${length > 1 ? 's' : ''}`);
}
}
if (typeof currentSchema.maxLength === 'number') {
if (currentSchema.maxLength === 0) {
type = 'empty string';
} else {
const length = currentSchema.maxLength + 1;
hints.push(`should be shorter than ${length} character${length > 1 ? 's' : ''}`);
}
}
if (currentSchema.pattern) {
hints.push(`should${logic ? '' : ' not'} match pattern ${JSON.stringify(currentSchema.pattern)}`);
}
if (currentSchema.format) {
hints.push(`should${logic ? '' : ' not'} match format ${JSON.stringify(currentSchema.format)}`);
}
if (currentSchema.formatMinimum) {
hints.push(`should be ${currentSchema.formatExclusiveMinimum ? '>' : '>='} ${JSON.stringify(currentSchema.formatMinimum)}`);
}
if (currentSchema.formatMaximum) {
hints.push(`should be ${currentSchema.formatExclusiveMaximum ? '<' : '<='} ${JSON.stringify(currentSchema.formatMaximum)}`);
}
return [type].concat(hints);
};
/**
* @param {Schema} schema
* @param {boolean} logic
* @return {string[]}
*/
module.exports.numberHints = function numberHints(schema, logic) {
const hints = [schema.type === 'integer' ? 'integer' : 'number'];
const range = new Range();
if (typeof schema.minimum === 'number') {
range.left(schema.minimum);
}
if (typeof schema.exclusiveMinimum === 'number') {
range.left(schema.exclusiveMinimum, true);
}
if (typeof schema.maximum === 'number') {
range.right(schema.maximum);
}
if (typeof schema.exclusiveMaximum === 'number') {
range.right(schema.exclusiveMaximum, true);
}
const rangeFormat = range.format(logic);
if (rangeFormat) {
hints.push(rangeFormat);
}
if (typeof schema.multipleOf === 'number') {
hints.push(`should${logic ? '' : ' not'} be multiple of ${schema.multipleOf}`);
}
return hints;
};
+162
View File
@@ -0,0 +1,162 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _absolutePath = _interopRequireDefault(require("./keywords/absolutePath"));
var _ValidationError = _interopRequireDefault(require("./ValidationError"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Use CommonJS require for ajv libs so TypeScript consumers aren't locked into esModuleInterop (see #110).
const Ajv = require('ajv');
const ajvKeywords = require('ajv-keywords');
/** @typedef {import("json-schema").JSONSchema4} JSONSchema4 */
/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
/** @typedef {import("ajv").ErrorObject} ErrorObject */
/**
* @typedef {Object} Extend
* @property {number=} formatMinimum
* @property {number=} formatMaximum
* @property {boolean=} formatExclusiveMinimum
* @property {boolean=} formatExclusiveMaximum
*/
/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7) & Extend} Schema */
/** @typedef {ErrorObject & { children?: Array<ErrorObject>}} SchemaUtilErrorObject */
/**
* @callback PostFormatter
* @param {string} formattedError
* @param {SchemaUtilErrorObject} error
* @returns {string}
*/
/**
* @typedef {Object} ValidationErrorConfiguration
* @property {string=} name
* @property {string=} baseDataPath
* @property {PostFormatter=} postFormatter
*/
const ajv = new Ajv({
allErrors: true,
verbose: true,
$data: true
});
ajvKeywords(ajv, ['instanceof', 'formatMinimum', 'formatMaximum', 'patternRequired']); // Custom keywords
(0, _absolutePath.default)(ajv);
/**
* @param {Schema} schema
* @param {Array<object> | object} options
* @param {ValidationErrorConfiguration=} configuration
* @returns {void}
*/
function validate(schema, options, configuration) {
let errors = [];
if (Array.isArray(options)) {
errors = Array.from(options, nestedOptions => validateObject(schema, nestedOptions));
errors.forEach((list, idx) => {
const applyPrefix =
/**
* @param {SchemaUtilErrorObject} error
*/
error => {
// eslint-disable-next-line no-param-reassign
error.dataPath = `[${idx}]${error.dataPath}`;
if (error.children) {
error.children.forEach(applyPrefix);
}
};
list.forEach(applyPrefix);
});
errors = errors.reduce((arr, items) => {
arr.push(...items);
return arr;
}, []);
} else {
errors = validateObject(schema, options);
}
if (errors.length > 0) {
throw new _ValidationError.default(errors, schema, configuration);
}
}
/**
* @param {Schema} schema
* @param {Array<object> | object} options
* @returns {Array<SchemaUtilErrorObject>}
*/
function validateObject(schema, options) {
const compiledSchema = ajv.compile(schema);
const valid = compiledSchema(options);
if (valid) return [];
return compiledSchema.errors ? filterErrors(compiledSchema.errors) : [];
}
/**
* @param {Array<ErrorObject>} errors
* @returns {Array<SchemaUtilErrorObject>}
*/
function filterErrors(errors) {
/** @type {Array<SchemaUtilErrorObject>} */
let newErrors = [];
for (const error of
/** @type {Array<SchemaUtilErrorObject>} */
errors) {
const {
dataPath
} = error;
/** @type {Array<SchemaUtilErrorObject>} */
let children = [];
newErrors = newErrors.filter(oldError => {
if (oldError.dataPath.includes(dataPath)) {
if (oldError.children) {
children = children.concat(oldError.children.slice(0));
} // eslint-disable-next-line no-undefined, no-param-reassign
oldError.children = undefined;
children.push(oldError);
return false;
}
return true;
});
if (children.length) {
error.children = children;
}
newErrors.push(error);
}
return newErrors;
} // TODO change after resolve https://github.com/microsoft/TypeScript/issues/34994
validate.ValidationError = _ValidationError.default;
validate.ValidateError = _ValidationError.default;
var _default = validate;
exports.default = _default;
+112
View File
@@ -0,0 +1,112 @@
{
"_args": [
[
"schema-utils@2.7.1",
"/home/node/nuxt"
]
],
"_from": "schema-utils@2.7.1",
"_id": "schema-utils@2.7.1",
"_inBundle": false,
"_integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
"_location": "/css-loader/schema-utils",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "schema-utils@2.7.1",
"name": "schema-utils",
"escapedName": "schema-utils",
"rawSpec": "2.7.1",
"saveSpec": null,
"fetchSpec": "2.7.1"
},
"_requiredBy": [
"/css-loader"
],
"_resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
"_spec": "2.7.1",
"_where": "/home/node/nuxt",
"author": {
"name": "webpack Contrib",
"url": "https://github.com/webpack-contrib"
},
"bugs": {
"url": "https://github.com/webpack/schema-utils/issues"
},
"dependencies": {
"@types/json-schema": "^7.0.5",
"ajv": "^6.12.4",
"ajv-keywords": "^3.5.2"
},
"description": "webpack Validation Utils",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.4",
"@babel/preset-env": "^7.11.0",
"@commitlint/cli": "^10.0.0",
"@commitlint/config-conventional": "^10.0.0",
"@webpack-contrib/defaults": "^6.3.0",
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
"babel-jest": "^25.5.1",
"cross-env": "^6.0.3",
"del": "^5.1.0",
"del-cli": "^3.0.1",
"eslint": "^7.7.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.22.0",
"husky": "^4.2.5",
"jest": "^25.5.4",
"lint-staged": "^10.2.13",
"npm-run-all": "^4.1.5",
"prettier": "^1.19.1",
"standard-version": "^9.0.0",
"typescript": "^4.0.2"
},
"engines": {
"node": ">= 8.9.0"
},
"files": [
"dist",
"declarations"
],
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"homepage": "https://github.com/webpack/schema-utils",
"keywords": [
"webpack"
],
"license": "MIT",
"main": "dist/index.js",
"name": "schema-utils",
"repository": {
"type": "git",
"url": "git+https://github.com/webpack/schema-utils.git"
},
"scripts": {
"build": "npm-run-all -p \"build:**\"",
"build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files",
"build:types": "tsc --declaration --emitDeclarationOnly --outDir declarations && prettier \"declarations/**/*.ts\" --write",
"clean": "del-cli dist declarations",
"commitlint": "commitlint --from=master",
"defaults": "webpack-defaults",
"lint": "npm-run-all -l -p \"lint:**\"",
"lint:js": "eslint --cache .",
"lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
"lint:types": "tsc --pretty --noEmit",
"prebuild": "npm run clean",
"prepare": "npm run build",
"pretest": "npm run lint",
"release": "standard-version",
"security": "npm audit",
"start": "npm run build -- -w",
"test": "npm run test:coverage",
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
"test:only": "cross-env NODE_ENV=test jest",
"test:watch": "npm run test:only -- --watch"
},
"types": "declarations/index.d.ts",
"version": "2.7.1"
}
+51 -39
View File
@@ -1,32 +1,39 @@
{
"_args": [
[
"css-loader@3.6.0",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
"css-loader@4.3.0",
"/home/node/nuxt"
]
],
"_from": "css-loader@3.6.0",
"_id": "css-loader@3.6.0",
"_from": "css-loader@4.3.0",
"_id": "css-loader@4.3.0",
"_inBundle": false,
"_integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
"_integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==",
"_location": "/css-loader",
"_phantomChildren": {},
"_phantomChildren": {
"@types/json-schema": "7.0.11",
"ajv": "6.12.6",
"ajv-keywords": "3.5.2",
"big.js": "5.2.2",
"emojis-list": "3.0.0",
"json5": "2.2.1"
},
"_requested": {
"type": "version",
"registry": true,
"raw": "css-loader@3.6.0",
"raw": "css-loader@4.3.0",
"name": "css-loader",
"escapedName": "css-loader",
"rawSpec": "3.6.0",
"rawSpec": "4.3.0",
"saveSpec": null,
"fetchSpec": "3.6.0"
"fetchSpec": "4.3.0"
},
"_requiredBy": [
"/@nuxt/webpack"
],
"_resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
"_spec": "3.6.0",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"_resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz",
"_spec": "4.3.0",
"_where": "/home/node/nuxt",
"author": {
"name": "Tobias Koppers @sokra"
},
@@ -34,55 +41,60 @@
"url": "https://github.com/webpack-contrib/css-loader/issues"
},
"dependencies": {
"camelcase": "^5.3.1",
"camelcase": "^6.0.0",
"cssesc": "^3.0.0",
"icss-utils": "^4.1.1",
"loader-utils": "^1.2.3",
"normalize-path": "^3.0.0",
"loader-utils": "^2.0.0",
"postcss": "^7.0.32",
"postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2",
"postcss-modules-local-by-default": "^3.0.3",
"postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0",
"postcss-value-parser": "^4.1.0",
"schema-utils": "^2.7.0",
"semver": "^6.3.0"
"schema-utils": "^2.7.1",
"semver": "^7.3.2"
},
"description": "css loader module for webpack",
"devDependencies": {
"@babel/cli": "^7.10.1",
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"@babel/cli": "^7.11.6",
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@webpack-contrib/defaults": "^6.3.0",
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
"babel-jest": "^25.5.1",
"babel-jest": "^26.1.0",
"cross-env": "^7.0.2",
"del": "^5.1.0",
"del-cli": "^3.0.1",
"es-check": "^5.1.0",
"eslint": "^6.8.0",
"eslint": "^7.8.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-import": "^2.21.2",
"file-loader": "^6.0.0",
"husky": "^4.2.5",
"jest": "^25.5.4",
"lint-staged": "^10.2.10",
"eslint-plugin-import": "^2.22.0",
"file-loader": "^6.1.0",
"husky": "^4.3.0",
"jest": "^26.4.2",
"less": "^3.12.2",
"less-loader": "^7.0.1",
"lint-staged": "^10.3.0",
"memfs": "^3.2.0",
"mini-css-extract-plugin": "^0.11.0",
"npm-run-all": "^4.1.5",
"postcss-loader": "^3.0.0",
"postcss-loader": "^4.0.0",
"postcss-preset-env": "^6.7.0",
"prettier": "^2.0.5",
"sass": "^1.26.8",
"sass-loader": "^8.0.2",
"standard-version": "^8.0.0",
"prettier": "^2.1.1",
"sass": "^1.26.10",
"sass-loader": "^10.0.2",
"standard-version": "^9.0.0",
"strip-ansi": "^6.0.0",
"style-loader": "^1.2.1",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"url-loader": "^4.1.0",
"webpack": "^4.43.0"
"webpack": "^4.44.1"
},
"engines": {
"node": ">= 8.9.0"
"node": ">= 10.13.0"
},
"files": [
"dist"
@@ -103,7 +115,7 @@
"main": "dist/cjs.js",
"name": "css-loader",
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
"webpack": "^4.27.0 || ^5.0.0"
},
"repository": {
"type": "git",
@@ -130,5 +142,5 @@
"test:watch": "npm run test:only -- --watch",
"validate:runtime": "es-check es5 \"dist/runtime/**/*.js\""
},
"version": "3.6.0"
"version": "4.3.0"
}