chushihua
This commit is contained in:
+277
@@ -0,0 +1,277 @@
|
||||
Change History
|
||||
==============
|
||||
|
||||
v2.30.1
|
||||
---
|
||||
* Revert part the performance optimization (#723) because of #753.
|
||||
|
||||
v2.30.0
|
||||
---
|
||||
* Add manual sort
|
||||
* Performance improvements (#723)
|
||||
|
||||
v2.29.0
|
||||
---
|
||||
* Add support for Webpack 3
|
||||
|
||||
v2.28.0
|
||||
---
|
||||
* Backport 3.x void tag for plugin authors
|
||||
|
||||
v2.27.1
|
||||
---
|
||||
* Revert 2.25.0 loader resolving
|
||||
|
||||
v2.27.0
|
||||
---
|
||||
* Fix a chunksorter webpack 2 issue (#569)
|
||||
* Fix template path resolving(#542)
|
||||
|
||||
v2.26.0
|
||||
---
|
||||
* Allow plugins to add attributes without values to the `<script>` and `<link>` tags
|
||||
|
||||
v2.25.0
|
||||
---
|
||||
* Clearer loader output
|
||||
* Add basic support for webpack 2
|
||||
|
||||
v2.24.1
|
||||
---
|
||||
* Hide event deprecated warning of 'applyPluginsAsyncWaterfall' for html-webpack-plugin-after-emit and improve the warning message.
|
||||
|
||||
v2.24.0
|
||||
---
|
||||
* Update dependencies
|
||||
* Add deprecate warning for plugins not returning a result
|
||||
* Add [path] for favicons
|
||||
|
||||
v2.23.0
|
||||
---
|
||||
* Update dependencies
|
||||
* Stop automated tests for webpack 2 beta because of #401
|
||||
|
||||
v2.22.0
|
||||
---
|
||||
* Update dependencies
|
||||
|
||||
v2.21.1
|
||||
---
|
||||
* Better error handling (#354)
|
||||
|
||||
v2.21.0
|
||||
----
|
||||
* Add `html-webpack-plugin-alter-asset-tags` event to allow plugins to adjust the script/link tags
|
||||
|
||||
v2.20.0
|
||||
----
|
||||
* Exclude chunks works now even if combined with dependency sort
|
||||
|
||||
v2.19.0
|
||||
----
|
||||
* Add `html-webpack-plugin-alter-chunks` event for custom chunk sorting and interpolation
|
||||
|
||||
v2.18.0
|
||||
----
|
||||
* Updated all dependencies
|
||||
|
||||
v2.17.0
|
||||
----
|
||||
* Add `type` attribute to `script` element to prevent issues in Safari 9.1.1
|
||||
|
||||
v2.16.2
|
||||
----
|
||||
* Fix bug introduced by 2.16.2. Fixes #315
|
||||
|
||||
v2.16.1
|
||||
----
|
||||
* Fix hot module replacement for webpack 2.x
|
||||
|
||||
v2.16.0
|
||||
----
|
||||
* Add support for dynamic filenames like index[hash].html
|
||||
|
||||
v2.15.0
|
||||
----
|
||||
* Add full unit test coverage for the webpack 2 beta version
|
||||
* For webpack 2 the default sort will be 'dependency' instead of 'id'
|
||||
* Upgrade dependencies
|
||||
|
||||
v2.14.0
|
||||
----
|
||||
* Export publicPath to the template
|
||||
* Add example for inlining css and js
|
||||
|
||||
v2.13.0
|
||||
----
|
||||
* Add support for absolute output file names
|
||||
* Add support for relative file names outside the output path
|
||||
|
||||
v2.12.0
|
||||
----
|
||||
* Basic Webpack 2.x support #225
|
||||
|
||||
v2.11.0
|
||||
----
|
||||
* Add `xhtml` option which is turned of by default. When activated it will inject self closed `<link href=".." />` tags instead of unclosed `<link href="..">` tags. https://github.com/ampedandwired/html-webpack-plugin/pull/255
|
||||
* Add support for webpack placeholders inside the public path e.g. `'/dist/[hash]/'`. https://github.com/ampedandwired/html-webpack-plugin/pull/249
|
||||
|
||||
v2.10.0
|
||||
----
|
||||
* Add `hash` field to the chunk object
|
||||
* Add `compilation` field to the templateParam object (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/237)
|
||||
* Add `html-webpack-plugin-before-html-generation` event
|
||||
* Improve error messages
|
||||
|
||||
v2.9.0
|
||||
----
|
||||
* Fix favicon path (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/185, https://github.com/ampedandwired/html-webpack-plugin/issues/208, https://github.com/ampedandwired/html-webpack-plugin/pull/215 )
|
||||
|
||||
v2.8.2
|
||||
----
|
||||
* Support relative URLs on Windows (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/205 )
|
||||
|
||||
v2.8.1
|
||||
----
|
||||
* Caching improvements (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/204 )
|
||||
|
||||
v2.8.0
|
||||
----
|
||||
* Add `dependency` mode for `chunksSortMode` to sort chunks based on their dependencies with each other
|
||||
|
||||
v2.7.2
|
||||
----
|
||||
* Add support for require in js templates
|
||||
|
||||
v2.7.1
|
||||
----
|
||||
* Refactoring
|
||||
* Fix relative windows path
|
||||
|
||||
v2.6.5
|
||||
----
|
||||
* Minor refactoring
|
||||
|
||||
v2.6.4
|
||||
----
|
||||
* Fix for `"Uncaught TypeError: __webpack_require__(...) is not a function"`
|
||||
* Fix incomplete cache modules causing "HtmlWebpackPlugin Error: No source available"
|
||||
* Fix some issues on Windows
|
||||
|
||||
v2.6.3
|
||||
----
|
||||
* Prevent parsing the base template with the html-loader
|
||||
|
||||
v2.6.2
|
||||
----
|
||||
* Fix `lodash` resolve error (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/172 )
|
||||
|
||||
v2.6.1
|
||||
----
|
||||
* Fix missing module (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/164 )
|
||||
|
||||
v2.6.0
|
||||
----
|
||||
* Move compiler to its own file
|
||||
* Improve error messages
|
||||
* Fix global HTML_WEBPACK_PLUGIN variable
|
||||
|
||||
v2.5.0
|
||||
----
|
||||
* Support `lodash` template's HTML _"escape"_ delimiter (`<%- %>`)
|
||||
* Fix bluebird warning (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/130 )
|
||||
* Fix an issue where incomplete cache modules were used
|
||||
|
||||
v2.4.0
|
||||
----
|
||||
* Don't recompile if the assets didn't change
|
||||
|
||||
v2.3.0
|
||||
----
|
||||
* Add events `html-webpack-plugin-before-html-processing`, `html-webpack-plugin-after-html-processing`, `html-webpack-plugin-after-emit` to allow other plugins to alter the html this plugin executes
|
||||
|
||||
v2.2.0
|
||||
----
|
||||
* Inject css and js even if the html file is incomplete (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/135 )
|
||||
* Update dependencies
|
||||
|
||||
v2.1.0
|
||||
----
|
||||
* Synchronize with the stable `@1` version
|
||||
|
||||
v2.0.4
|
||||
----
|
||||
* Fix `minify` option
|
||||
* Fix missing hash interpolation in publicPath
|
||||
|
||||
v2.0.3
|
||||
----
|
||||
* Add support for webpack.BannerPlugin
|
||||
|
||||
v2.0.2
|
||||
----
|
||||
* Add support for loaders in templates (fixes https://github.com/ampedandwired/html-webpack-plugin/pull/41 )
|
||||
* Remove `templateContent` option from configuration
|
||||
* Better error messages
|
||||
* Update dependencies
|
||||
|
||||
|
||||
v1.7.0
|
||||
----
|
||||
* Add `chunksSortMode` option to configuration to control how chunks should be sorted before they are included to the html
|
||||
* Don't insert async chunks into html (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/95 )
|
||||
* Update dependencies
|
||||
|
||||
v1.6.2
|
||||
----
|
||||
* Fix paths on Windows
|
||||
* Fix missing hash interpolation in publicPath
|
||||
* Allow only `false` or `object` in `minify` configuration option
|
||||
|
||||
v1.6.1
|
||||
----
|
||||
* Add `size` field to the chunk object
|
||||
* Fix stylesheet `<link>`s being discarded when used with `"inject: 'head'"`
|
||||
* Update dependencies
|
||||
|
||||
v1.6.0
|
||||
----
|
||||
* Support placing templates in subfolders
|
||||
* Don't include chunks with undefined name (fixes https://github.com/ampedandwired/html-webpack-plugin/pull/60 )
|
||||
* Don't include async chunks
|
||||
|
||||
v1.5.2
|
||||
----
|
||||
* Update dependencies (lodash)
|
||||
|
||||
v1.5.1
|
||||
----
|
||||
* Fix error when manifest is specified (fixes https://github.com/ampedandwired/html-webpack-plugin/issues/56 )
|
||||
|
||||
v1.5.0
|
||||
----
|
||||
* Allow to inject javascript files into the head of the html page
|
||||
* Fix error reporting
|
||||
|
||||
v1.4.0
|
||||
----
|
||||
* Add `favicon.ico` option
|
||||
* Add html minifcation
|
||||
|
||||
v1.2.0
|
||||
------
|
||||
* Set charset using HTML5 meta attribute
|
||||
* Reload upon change when using webpack watch mode
|
||||
* Generate manifest attribute when using
|
||||
[appcache-webpack-plugin](https://github.com/lettertwo/appcache-webpack-plugin)
|
||||
* Optionally add webpack hash as a query string to resources included in the HTML
|
||||
(`hash: true`) for cache busting
|
||||
* CSS files generated using webpack (for example, by using the
|
||||
[extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin))
|
||||
are now automatically included into the generated HTML
|
||||
* More detailed information about the files generated by webpack is now available
|
||||
to templates in the `o.htmlWebpackPlugin.files` attribute. See readme for more
|
||||
details. This new attribute deprecates the old `o.htmlWebpackPlugin.assets` attribute.
|
||||
* The `templateContent` option can now be a function that returns the template string to use
|
||||
* Expose webpack configuration to templates (`o.webpackConfig`)
|
||||
* Sort chunks to honour dependencies between them (useful for use with CommonsChunkPlugin).
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Charles Blaxland
|
||||
|
||||
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.
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
HTML Webpack Plugin
|
||||
===================
|
||||
[](http://badge.fury.io/js/html-webpack-plugin) [](https://david-dm.org/jantimon/html-webpack-plugin) [](https://travis-ci.org/jantimon/html-webpack-plugin) [](https://ci.appveyor.com/project/jantimon/html-webpack-plugin) [](https://github.com/Flet/semistandard) [](https://www.bithound.io/github/jantimon/html-webpack-plugin/master/dependencies/npm) []()
|
||||
|
||||
[](https://nodei.co/npm/html-webpack-plugin/)
|
||||
|
||||
This is a [webpack](http://webpack.github.io/) plugin that simplifies creation of HTML files to serve your
|
||||
webpack bundles. This is especially useful for webpack bundles that include
|
||||
a hash in the filename which changes every compilation. You can either let the plugin generate an HTML file for you, supply
|
||||
your own template using lodash templates or use your own loader.
|
||||
|
||||
Maintainer: Jan Nicklas [@jantimon](https://twitter.com/jantimon) and Thomas Sileghem [@mastilver](https://twitter.com/mastilver)
|
||||
|
||||
Installation
|
||||
------------
|
||||
Install the plugin with npm:
|
||||
```shell
|
||||
$ npm install html-webpack-plugin --save-dev
|
||||
```
|
||||
|
||||
Third party addons:
|
||||
-------------
|
||||
|
||||
The html-webpack-plugin provides [hooks](https://github.com/jantimon/html-webpack-plugin#events) to extend it to your needs.
|
||||
There are already some really powerful plugins which can be integrated with zero configuration:
|
||||
|
||||
* [webpack-subresource-integrity](https://www.npmjs.com/package/webpack-subresource-integrity) for enhanced asset security
|
||||
* [appcache-webpack-plugin](https://github.com/lettertwo/appcache-webpack-plugin) for iOS and Android offline usage
|
||||
* [favicons-webpack-plugin](https://github.com/jantimon/favicons-webpack-plugin) which generates favicons and icons for iOS, Android and desktop browsers
|
||||
* [html-webpack-harddisk-plugin](https://github.com/jantimon/html-webpack-harddisk-plugin) can be used to always write to disk the html file, useful when webpack-dev-server / HMR are being used
|
||||
* [html-webpack-inline-source-plugin](https://github.com/DustinJackson/html-webpack-inline-source-plugin) to inline your assets in the resulting HTML file
|
||||
* [html-webpack-exclude-assets-plugin](https://github.com/jamesjieye/html-webpack-exclude-assets-plugin) for excluding assets using regular expressions
|
||||
* [html-webpack-include-assets-plugin](https://github.com/jharris4/html-webpack-include-assets-plugin) for including lists of js or css file paths (such as those copied by the copy-webpack-plugin).
|
||||
* [script-ext-html-webpack-plugin](https://github.com/numical/script-ext-html-webpack-plugin) to add `async`, `defer` or `module` attributes to your`<script>` elements, or even in-line them
|
||||
* [style-ext-html-webpack-plugin](https://github.com/numical/style-ext-html-webpack-plugin) to convert your `<link>`s to external stylesheets into `<style>` elements containing internal CSS
|
||||
* [resource-hints-webpack-plugin](https://github.com/jantimon/resource-hints-webpack-plugin) to add resource hints for faster initial page loads using `<link rel='preload'>` and `<link rel='prefetch'>`
|
||||
* [preload-webpack-plugin](https://github.com/GoogleChrome/preload-webpack-plugin) for automatically wiring up asynchronous (and other types) of JavaScript chunks using `<link rel='preload'>` helping with lazy-loading
|
||||
* [link-media-html-webpack-plugin](https://github.com/yaycmyk/link-media-html-webpack-plugin) allows for injected stylesheet `<link />` tags to have their media attribute set automatically; useful for providing specific desktop/mobile/print etc. stylesheets that the browser will conditionally download
|
||||
* [inline-chunk-manifest-html-webpack-plugin](https://github.com/jouni-kantola/inline-chunk-manifest-html-webpack-plugin) for inlining webpack's chunk manifest. Default extracts manifest and inlines in `<head>`.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
The plugin will generate an HTML5 file for you that includes all your webpack
|
||||
bundles in the body using `script` tags. Just add the plugin to your webpack
|
||||
config as follows:
|
||||
|
||||
```javascript
|
||||
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
var webpackConfig = {
|
||||
entry: 'index.js',
|
||||
output: {
|
||||
path: __dirname + '/dist',
|
||||
filename: 'index_bundle.js'
|
||||
},
|
||||
plugins: [new HtmlWebpackPlugin()]
|
||||
};
|
||||
```
|
||||
|
||||
This will generate a file `dist/index.html` containing the following:
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Webpack App</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="index_bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
If you have multiple webpack entry points, they will all be included with `script`
|
||||
tags in the generated HTML.
|
||||
|
||||
If you have any CSS assets in webpack's output (for example, CSS extracted
|
||||
with the [ExtractTextPlugin](https://github.com/webpack/extract-text-webpack-plugin))
|
||||
then these will be included with `<link>` tags in the HTML head.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
You can pass a hash of configuration options to `HtmlWebpackPlugin`.
|
||||
Allowed values are as follows:
|
||||
|
||||
- `title`: The title to use for the generated HTML document.
|
||||
- `filename`: The file to write the HTML to. Defaults to `index.html`.
|
||||
You can specify a subdirectory here too (eg: `assets/admin.html`).
|
||||
- `template`: Webpack require path to the template. Please see the [docs](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md) for details.
|
||||
- `inject`: `true | 'head' | 'body' | false` Inject all assets into the given `template` or `templateContent` - When passing `true` or `'body'` all javascript resources will be placed at the bottom of the body element. `'head'` will place the scripts in the head element.
|
||||
- `favicon`: Adds the given favicon path to the output html.
|
||||
- `minify`: `{...} | false` Pass [html-minifier](https://github.com/kangax/html-minifier#options-quick-reference)'s options as object to minify the output.
|
||||
- `hash`: `true | false` if `true` then append a unique webpack compilation hash to all
|
||||
included scripts and CSS files. This is useful for cache busting.
|
||||
- `cache`: `true | false` if `true` (default) try to emit the file only if it was changed.
|
||||
- `showErrors`: `true | false` if `true` (default) errors details will be written into the HTML page.
|
||||
- `chunks`: Allows you to add only some chunks (e.g. only the unit-test chunk)
|
||||
- `chunksSortMode`: Allows to control how chunks should be sorted before they are included to the html. Allowed values: 'none' | 'auto' | 'dependency' |'manual' | {function} - default: 'auto'
|
||||
- `excludeChunks`: Allows you to skip some chunks (e.g. don't add the unit-test chunk)
|
||||
- `xhtml`: `true | false` If `true` render the `link` tags as self-closing, XHTML compliant. Default is `false`
|
||||
|
||||
Here's an example webpack config illustrating how to use these options:
|
||||
```javascript
|
||||
{
|
||||
entry: 'index.js',
|
||||
output: {
|
||||
path: __dirname + '/dist',
|
||||
filename: 'index_bundle.js'
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'My App',
|
||||
filename: 'assets/admin.html'
|
||||
})
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
FAQ
|
||||
----
|
||||
|
||||
* [Why is my HTML minified?](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
|
||||
* [Why is my `<% ... %>` template not working?](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
|
||||
* [How can I use handlebars/pug/ejs as template engine](https://github.com/jantimon/html-webpack-plugin/blob/master/docs/template-option.md)
|
||||
|
||||
Generating Multiple HTML Files
|
||||
------------------------------
|
||||
To generate more than one HTML file, declare the plugin more than
|
||||
once in your plugins array:
|
||||
```javascript
|
||||
{
|
||||
entry: 'index.js',
|
||||
output: {
|
||||
path: __dirname + '/dist',
|
||||
filename: 'index_bundle.js'
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin(), // Generates default index.html
|
||||
new HtmlWebpackPlugin({ // Also generate a test.html
|
||||
filename: 'test.html',
|
||||
template: 'src/assets/test.html'
|
||||
})
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Writing Your Own Templates
|
||||
--------------------------
|
||||
If the default generated HTML doesn't meet your needs you can supply
|
||||
your own template. The easiest way is to use the `template` option and pass a custom HTML file.
|
||||
The html-webpack-plugin will automatically inject all necessary CSS, JS, manifest
|
||||
and favicon files into the markup.
|
||||
|
||||
```javascript
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Custom template',
|
||||
template: 'my-index.ejs', // Load a custom template (ejs by default see the FAQ for details)
|
||||
})
|
||||
]
|
||||
```
|
||||
|
||||
`my-index.ejs`:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
If you already have a template loader, you can use it to parse the template.
|
||||
Please note that this will also happen if you specifiy the html-loader and use `.html` file as template.
|
||||
|
||||
```javascript
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.hbs$/, loader: "handlebars" }
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'Custom template using Handlebars',
|
||||
template: 'my-index.hbs'
|
||||
})
|
||||
]
|
||||
```
|
||||
|
||||
You can use the lodash syntax out of the box.
|
||||
If the `inject` feature doesn't fit your needs and you want full control over the asset placement use the [default template](https://github.com/jaketrent/html-webpack-template/blob/86f285d5c790a6c15263f5cc50fd666d51f974fd/index.html) of the [html-webpack-template project](https://github.com/jaketrent/html-webpack-template) as a starting point for writing your own.
|
||||
|
||||
The following variables are available in the template:
|
||||
- `htmlWebpackPlugin`: data specific to this plugin
|
||||
- `htmlWebpackPlugin.files`: a massaged representation of the
|
||||
`assetsByChunkName` attribute of webpack's [stats](https://github.com/webpack/docs/wiki/node.js-api#stats)
|
||||
object. It contains a mapping from entry point name to the bundle filename, eg:
|
||||
```json
|
||||
"htmlWebpackPlugin": {
|
||||
"files": {
|
||||
"css": [ "main.css" ],
|
||||
"js": [ "assets/head_bundle.js", "assets/main_bundle.js"],
|
||||
"chunks": {
|
||||
"head": {
|
||||
"entry": "assets/head_bundle.js",
|
||||
"css": [ "main.css" ]
|
||||
},
|
||||
"main": {
|
||||
"entry": "assets/main_bundle.js",
|
||||
"css": []
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
If you've set a publicPath in your webpack config this will be reflected
|
||||
correctly in this assets hash.
|
||||
|
||||
- `htmlWebpackPlugin.options`: the options hash that was passed to
|
||||
the plugin. In addition to the options actually used by this plugin,
|
||||
you can use this hash to pass arbitrary data through to your template.
|
||||
|
||||
- `webpack`: the webpack [stats](https://github.com/webpack/docs/wiki/node.js-api#stats)
|
||||
object. Note that this is the stats object as it was at the time the HTML template
|
||||
was emitted and as such may not have the full set of stats that are available
|
||||
after the webpack run is complete.
|
||||
|
||||
- `webpackConfig`: the webpack configuration that was used for this compilation. This
|
||||
can be used, for example, to get the `publicPath` (`webpackConfig.output.publicPath`).
|
||||
|
||||
|
||||
Filtering chunks
|
||||
----------------
|
||||
|
||||
To include only certain chunks you can limit the chunks being used:
|
||||
|
||||
```javascript
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
chunks: ['app']
|
||||
})
|
||||
]
|
||||
```
|
||||
|
||||
It is also possible to exclude certain chunks by setting the `excludeChunks` option:
|
||||
|
||||
```javascript
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
excludeChunks: ['dev-helper']
|
||||
})
|
||||
]
|
||||
```
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
To allow other [plugins](https://github.com/webpack/docs/wiki/plugins) to alter the HTML this plugin executes the following events:
|
||||
|
||||
Async:
|
||||
|
||||
* `html-webpack-plugin-before-html-generation`
|
||||
* `html-webpack-plugin-before-html-processing`
|
||||
* `html-webpack-plugin-alter-asset-tags`
|
||||
* `html-webpack-plugin-after-html-processing`
|
||||
* `html-webpack-plugin-after-emit`
|
||||
|
||||
Sync:
|
||||
|
||||
* `html-webpack-plugin-alter-chunks`
|
||||
|
||||
Example implementation: [html-webpack-harddisk-plugin](https://github.com/jantimon/html-webpack-harddisk-plugin)
|
||||
|
||||
Usage:
|
||||
|
||||
```javascript
|
||||
// MyPlugin.js
|
||||
|
||||
function MyPlugin(options) {
|
||||
// Configure your plugin with options...
|
||||
}
|
||||
|
||||
MyPlugin.prototype.apply = function(compiler) {
|
||||
// ...
|
||||
compiler.plugin('compilation', function(compilation) {
|
||||
console.log('The compiler is starting a new compilation...');
|
||||
|
||||
compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) {
|
||||
htmlPluginData.html += 'The magic footer';
|
||||
callback(null, htmlPluginData);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.exports = MyPlugin;
|
||||
```
|
||||
Then in `webpack.config.js`
|
||||
|
||||
```javascript
|
||||
plugins: [
|
||||
new MyPlugin({options: ''})
|
||||
]
|
||||
```
|
||||
|
||||
Note that the callback must be passed the htmlPluginData in order to pass this onto any other plugins listening on the same `html-webpack-plugin-before-html-processing` event.
|
||||
|
||||
|
||||
# Contribution
|
||||
|
||||
You're free to contribute to this project by submitting [issues](https://github.com/jantimon/html-webpack-plugin/issues) and/or [pull requests](https://github.com/jantimon/html-webpack-plugin/pulls). This project is test-driven, so keep in mind that every change and new feature should be covered by tests.
|
||||
This project uses the [semistandard code style](https://github.com/Flet/semistandard).
|
||||
|
||||
Before running the tests, make sure to execute `yarn link` and `yarn link html-webpack-plugin` (or the npm variant of this).
|
||||
|
||||
# License
|
||||
|
||||
This project is licensed under [MIT](https://github.com/jantimon/html-webpack-plugin/blob/master/LICENSE).
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
+655
@@ -0,0 +1,655 @@
|
||||
'use strict';
|
||||
var vm = require('vm');
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var Promise = require('bluebird');
|
||||
var path = require('path');
|
||||
var childCompiler = require('./lib/compiler.js');
|
||||
var prettyError = require('./lib/errors.js');
|
||||
var chunkSorter = require('./lib/chunksorter.js');
|
||||
Promise.promisifyAll(fs);
|
||||
|
||||
function HtmlWebpackPlugin (options) {
|
||||
// Default options
|
||||
this.options = _.extend({
|
||||
template: path.join(__dirname, 'default_index.ejs'),
|
||||
filename: 'index.html',
|
||||
hash: false,
|
||||
inject: true,
|
||||
compile: true,
|
||||
favicon: false,
|
||||
minify: false,
|
||||
cache: true,
|
||||
showErrors: true,
|
||||
chunks: 'all',
|
||||
excludeChunks: [],
|
||||
title: 'Webpack App',
|
||||
xhtml: false
|
||||
}, options);
|
||||
}
|
||||
|
||||
HtmlWebpackPlugin.prototype.apply = function (compiler) {
|
||||
var self = this;
|
||||
var isCompilationCached = false;
|
||||
var compilationPromise;
|
||||
|
||||
this.options.template = this.getFullTemplatePath(this.options.template, compiler.context);
|
||||
|
||||
// convert absolute filename into relative so that webpack can
|
||||
// generate it at correct location
|
||||
var filename = this.options.filename;
|
||||
if (path.resolve(filename) === path.normalize(filename)) {
|
||||
this.options.filename = path.relative(compiler.options.output.path, filename);
|
||||
}
|
||||
|
||||
compiler.plugin('make', function (compilation, callback) {
|
||||
// Compile the template (queued)
|
||||
compilationPromise = childCompiler.compileTemplate(self.options.template, compiler.context, self.options.filename, compilation)
|
||||
.catch(function (err) {
|
||||
compilation.errors.push(prettyError(err, compiler.context).toString());
|
||||
return {
|
||||
content: self.options.showErrors ? prettyError(err, compiler.context).toJsonHtml() : 'ERROR',
|
||||
outputName: self.options.filename
|
||||
};
|
||||
})
|
||||
.then(function (compilationResult) {
|
||||
// If the compilation change didnt change the cache is valid
|
||||
isCompilationCached = compilationResult.hash && self.childCompilerHash === compilationResult.hash;
|
||||
self.childCompilerHash = compilationResult.hash;
|
||||
self.childCompilationOutputName = compilationResult.outputName;
|
||||
callback();
|
||||
return compilationResult.content;
|
||||
});
|
||||
});
|
||||
|
||||
compiler.plugin('emit', function (compilation, callback) {
|
||||
var applyPluginsAsyncWaterfall = self.applyPluginsAsyncWaterfall(compilation);
|
||||
// Get all chunks
|
||||
var allChunks = compilation.getStats().toJson().chunks;
|
||||
// Filter chunks (options.chunks and options.excludeCHunks)
|
||||
var chunks = self.filterChunks(allChunks, self.options.chunks, self.options.excludeChunks);
|
||||
// Sort chunks
|
||||
chunks = self.sortChunks(chunks, self.options.chunksSortMode);
|
||||
// Let plugins alter the chunks and the chunk sorting
|
||||
chunks = compilation.applyPluginsWaterfall('html-webpack-plugin-alter-chunks', chunks, { plugin: self });
|
||||
// Get assets
|
||||
var assets = self.htmlWebpackPluginAssets(compilation, chunks);
|
||||
// If this is a hot update compilation, move on!
|
||||
// This solves a problem where an `index.html` file is generated for hot-update js files
|
||||
// It only happens in Webpack 2, where hot updates are emitted separately before the full bundle
|
||||
if (self.isHotUpdateCompilation(assets)) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
// If the template and the assets did not change we don't have to emit the html
|
||||
var assetJson = JSON.stringify(self.getAssetFiles(assets));
|
||||
if (isCompilationCached && self.options.cache && assetJson === self.assetJson) {
|
||||
return callback();
|
||||
} else {
|
||||
self.assetJson = assetJson;
|
||||
}
|
||||
|
||||
Promise.resolve()
|
||||
// Favicon
|
||||
.then(function () {
|
||||
if (self.options.favicon) {
|
||||
return self.addFileToAssets(self.options.favicon, compilation)
|
||||
.then(function (faviconBasename) {
|
||||
var publicPath = compilation.mainTemplate.getPublicPath({hash: compilation.hash}) || '';
|
||||
if (publicPath && publicPath.substr(-1) !== '/') {
|
||||
publicPath += '/';
|
||||
}
|
||||
assets.favicon = publicPath + faviconBasename;
|
||||
});
|
||||
}
|
||||
})
|
||||
// Wait for the compilation to finish
|
||||
.then(function () {
|
||||
return compilationPromise;
|
||||
})
|
||||
.then(function (compiledTemplate) {
|
||||
// Allow to use a custom function / string instead
|
||||
if (self.options.templateContent !== undefined) {
|
||||
return self.options.templateContent;
|
||||
}
|
||||
// Once everything is compiled evaluate the html factory
|
||||
// and replace it with its content
|
||||
return self.evaluateCompilationResult(compilation, compiledTemplate);
|
||||
})
|
||||
// Allow plugins to make changes to the assets before invoking the template
|
||||
// This only makes sense to use if `inject` is `false`
|
||||
.then(function (compilationResult) {
|
||||
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-generation', false, {
|
||||
assets: assets,
|
||||
outputName: self.childCompilationOutputName,
|
||||
plugin: self
|
||||
})
|
||||
.then(function () {
|
||||
return compilationResult;
|
||||
});
|
||||
})
|
||||
// Execute the template
|
||||
.then(function (compilationResult) {
|
||||
// If the loader result is a function execute it to retrieve the html
|
||||
// otherwise use the returned html
|
||||
return typeof compilationResult !== 'function'
|
||||
? compilationResult
|
||||
: self.executeTemplate(compilationResult, chunks, assets, compilation);
|
||||
})
|
||||
// Allow plugins to change the html before assets are injected
|
||||
.then(function (html) {
|
||||
var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName};
|
||||
return applyPluginsAsyncWaterfall('html-webpack-plugin-before-html-processing', true, pluginArgs);
|
||||
})
|
||||
.then(function (result) {
|
||||
var html = result.html;
|
||||
var assets = result.assets;
|
||||
// Prepare script and link tags
|
||||
var assetTags = self.generateAssetTags(assets);
|
||||
var pluginArgs = {head: assetTags.head, body: assetTags.body, plugin: self, chunks: chunks, outputName: self.childCompilationOutputName};
|
||||
// Allow plugins to change the assetTag definitions
|
||||
return applyPluginsAsyncWaterfall('html-webpack-plugin-alter-asset-tags', true, pluginArgs)
|
||||
.then(function (result) {
|
||||
// Add the stylesheets, scripts and so on to the resulting html
|
||||
return self.postProcessHtml(html, assets, { body: result.body, head: result.head })
|
||||
.then(function (html) {
|
||||
return _.extend(result, {html: html, assets: assets});
|
||||
});
|
||||
});
|
||||
})
|
||||
// Allow plugins to change the html after assets are injected
|
||||
.then(function (result) {
|
||||
var html = result.html;
|
||||
var assets = result.assets;
|
||||
var pluginArgs = {html: html, assets: assets, plugin: self, outputName: self.childCompilationOutputName};
|
||||
return applyPluginsAsyncWaterfall('html-webpack-plugin-after-html-processing', true, pluginArgs)
|
||||
.then(function (result) {
|
||||
return result.html;
|
||||
});
|
||||
})
|
||||
.catch(function (err) {
|
||||
// In case anything went wrong the promise is resolved
|
||||
// with the error message and an error is logged
|
||||
compilation.errors.push(prettyError(err, compiler.context).toString());
|
||||
// Prevent caching
|
||||
self.hash = null;
|
||||
return self.options.showErrors ? prettyError(err, compiler.context).toHtml() : 'ERROR';
|
||||
})
|
||||
.then(function (html) {
|
||||
// Replace the compilation result with the evaluated html code
|
||||
compilation.assets[self.childCompilationOutputName] = {
|
||||
source: function () {
|
||||
return html;
|
||||
},
|
||||
size: function () {
|
||||
return html.length;
|
||||
}
|
||||
};
|
||||
})
|
||||
.then(function () {
|
||||
// Let other plugins know that we are done:
|
||||
return applyPluginsAsyncWaterfall('html-webpack-plugin-after-emit', false, {
|
||||
html: compilation.assets[self.childCompilationOutputName],
|
||||
outputName: self.childCompilationOutputName,
|
||||
plugin: self
|
||||
}).catch(function (err) {
|
||||
console.error(err);
|
||||
return null;
|
||||
}).then(function () {
|
||||
return null;
|
||||
});
|
||||
})
|
||||
// Let webpack continue with it
|
||||
.finally(function () {
|
||||
callback();
|
||||
// Tell blue bird that we don't want to wait for callback.
|
||||
// Fixes "Warning: a promise was created in a handler but none were returned from it"
|
||||
// https://github.com/petkaantonov/bluebird/blob/master/docs/docs/warning-explanations.md#warning-a-promise-was-created-in-a-handler-but-none-were-returned-from-it
|
||||
return null;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluates the child compilation result
|
||||
* Returns a promise
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.evaluateCompilationResult = function (compilation, source) {
|
||||
if (!source) {
|
||||
return Promise.reject('The child compilation didn\'t provide a result');
|
||||
}
|
||||
|
||||
// The LibraryTemplatePlugin stores the template result in a local variable.
|
||||
// To extract the result during the evaluation this part has to be removed.
|
||||
source = source.replace('var HTML_WEBPACK_PLUGIN_RESULT =', '');
|
||||
var template = this.options.template.replace(/^.+!/, '').replace(/\?.+$/, '');
|
||||
var vmContext = vm.createContext(_.extend({HTML_WEBPACK_PLUGIN: true, require: require}, global));
|
||||
var vmScript = new vm.Script(source, {filename: template});
|
||||
// Evaluate code and cast to string
|
||||
var newSource;
|
||||
try {
|
||||
newSource = vmScript.runInContext(vmContext);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
if (typeof newSource === 'object' && newSource.__esModule && newSource.default) {
|
||||
newSource = newSource.default;
|
||||
}
|
||||
return typeof newSource === 'string' || typeof newSource === 'function'
|
||||
? Promise.resolve(newSource)
|
||||
: Promise.reject('The loader "' + this.options.template + '" didn\'t return html.');
|
||||
};
|
||||
|
||||
/**
|
||||
* Html post processing
|
||||
*
|
||||
* Returns a promise
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.executeTemplate = function (templateFunction, chunks, assets, compilation) {
|
||||
var self = this;
|
||||
return Promise.resolve()
|
||||
// Template processing
|
||||
.then(function () {
|
||||
var templateParams = {
|
||||
compilation: compilation,
|
||||
webpack: compilation.getStats().toJson(),
|
||||
webpackConfig: compilation.options,
|
||||
htmlWebpackPlugin: {
|
||||
files: assets,
|
||||
options: self.options
|
||||
}
|
||||
};
|
||||
var html = '';
|
||||
try {
|
||||
html = templateFunction(templateParams);
|
||||
} catch (e) {
|
||||
compilation.errors.push(new Error('Template execution failed: ' + e));
|
||||
return Promise.reject(e);
|
||||
}
|
||||
return html;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Html post processing
|
||||
*
|
||||
* Returns a promise
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.postProcessHtml = function (html, assets, assetTags) {
|
||||
var self = this;
|
||||
if (typeof html !== 'string') {
|
||||
return Promise.reject('Expected html to be a string but got ' + JSON.stringify(html));
|
||||
}
|
||||
return Promise.resolve()
|
||||
// Inject
|
||||
.then(function () {
|
||||
if (self.options.inject) {
|
||||
return self.injectAssetsIntoHtml(html, assets, assetTags);
|
||||
} else {
|
||||
return html;
|
||||
}
|
||||
})
|
||||
// Minify
|
||||
.then(function (html) {
|
||||
if (self.options.minify) {
|
||||
var minify = require('html-minifier').minify;
|
||||
return minify(html, self.options.minify);
|
||||
}
|
||||
return html;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Pushes the content of the given filename to the compilation assets
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.addFileToAssets = function (filename, compilation) {
|
||||
filename = path.resolve(compilation.compiler.context, filename);
|
||||
return Promise.props({
|
||||
size: fs.statAsync(filename),
|
||||
source: fs.readFileAsync(filename)
|
||||
})
|
||||
.catch(function () {
|
||||
return Promise.reject(new Error('HtmlWebpackPlugin: could not load file ' + filename));
|
||||
})
|
||||
.then(function (results) {
|
||||
var basename = path.basename(filename);
|
||||
compilation.fileDependencies.push(filename);
|
||||
compilation.assets[basename] = {
|
||||
source: function () {
|
||||
return results.source;
|
||||
},
|
||||
size: function () {
|
||||
return results.size.size;
|
||||
}
|
||||
};
|
||||
return basename;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to sort chunks
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.sortChunks = function (chunks, sortMode) {
|
||||
// Sort mode auto by default:
|
||||
if (typeof sortMode === 'undefined') {
|
||||
sortMode = 'auto';
|
||||
}
|
||||
// Custom function
|
||||
if (typeof sortMode === 'function') {
|
||||
return chunks.sort(sortMode);
|
||||
}
|
||||
// Disabled sorting:
|
||||
if (sortMode === 'none') {
|
||||
return chunkSorter.none(chunks);
|
||||
}
|
||||
// Check if the given sort mode is a valid chunkSorter sort mode
|
||||
if (typeof chunkSorter[sortMode] !== 'undefined') {
|
||||
return chunkSorter[sortMode](chunks, this.options.chunks);
|
||||
}
|
||||
throw new Error('"' + sortMode + '" is not a valid chunk sort mode');
|
||||
};
|
||||
|
||||
/**
|
||||
* Return all chunks from the compilation result which match the exclude and include filters
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.filterChunks = function (chunks, includedChunks, excludedChunks) {
|
||||
return chunks.filter(function (chunk) {
|
||||
var chunkName = chunk.names[0];
|
||||
// This chunk doesn't have a name. This script can't handled it.
|
||||
if (chunkName === undefined) {
|
||||
return false;
|
||||
}
|
||||
// Skip if the chunk should be lazy loaded
|
||||
if (typeof chunk.isInitial === 'function') {
|
||||
if (!chunk.isInitial()) {
|
||||
return false;
|
||||
}
|
||||
} else if (!chunk.initial) {
|
||||
return false;
|
||||
}
|
||||
// Skip if the chunks should be filtered and the given chunk was not added explicity
|
||||
if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) {
|
||||
return false;
|
||||
}
|
||||
// Skip if the chunks should be filtered and the given chunk was excluded explicity
|
||||
if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) {
|
||||
return false;
|
||||
}
|
||||
// Add otherwise
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
HtmlWebpackPlugin.prototype.isHotUpdateCompilation = function (assets) {
|
||||
return assets.js.length && assets.js.every(function (name) {
|
||||
return /\.hot-update\.js$/.test(name);
|
||||
});
|
||||
};
|
||||
|
||||
HtmlWebpackPlugin.prototype.htmlWebpackPluginAssets = function (compilation, chunks) {
|
||||
var self = this;
|
||||
var compilationHash = compilation.hash;
|
||||
|
||||
// Use the configured public path or build a relative path
|
||||
var publicPath = typeof compilation.options.output.publicPath !== 'undefined'
|
||||
// If a hard coded public path exists use it
|
||||
? compilation.mainTemplate.getPublicPath({hash: compilationHash})
|
||||
// If no public path was set get a relative url path
|
||||
: path.relative(path.resolve(compilation.options.output.path, path.dirname(self.childCompilationOutputName)), compilation.options.output.path)
|
||||
.split(path.sep).join('/');
|
||||
|
||||
if (publicPath.length && publicPath.substr(-1, 1) !== '/') {
|
||||
publicPath += '/';
|
||||
}
|
||||
|
||||
var assets = {
|
||||
// The public path
|
||||
publicPath: publicPath,
|
||||
// Will contain all js & css files by chunk
|
||||
chunks: {},
|
||||
// Will contain all js files
|
||||
js: [],
|
||||
// Will contain all css files
|
||||
css: [],
|
||||
// Will contain the html5 appcache manifest files if it exists
|
||||
manifest: Object.keys(compilation.assets).filter(function (assetFile) {
|
||||
return path.extname(assetFile) === '.appcache';
|
||||
})[0]
|
||||
};
|
||||
|
||||
// Append a hash for cache busting
|
||||
if (this.options.hash) {
|
||||
assets.manifest = self.appendHash(assets.manifest, compilationHash);
|
||||
assets.favicon = self.appendHash(assets.favicon, compilationHash);
|
||||
}
|
||||
|
||||
for (var i = 0; i < chunks.length; i++) {
|
||||
var chunk = chunks[i];
|
||||
var chunkName = chunk.names[0];
|
||||
|
||||
assets.chunks[chunkName] = {};
|
||||
|
||||
// Prepend the public path to all chunk files
|
||||
var chunkFiles = [].concat(chunk.files).map(function (chunkFile) {
|
||||
return publicPath + chunkFile;
|
||||
});
|
||||
|
||||
// Append a hash for cache busting
|
||||
if (this.options.hash) {
|
||||
chunkFiles = chunkFiles.map(function (chunkFile) {
|
||||
return self.appendHash(chunkFile, compilationHash);
|
||||
});
|
||||
}
|
||||
|
||||
// Webpack outputs an array for each chunk when using sourcemaps
|
||||
// But we need only the entry file
|
||||
var entry = chunkFiles[0];
|
||||
assets.chunks[chunkName].size = chunk.size;
|
||||
assets.chunks[chunkName].entry = entry;
|
||||
assets.chunks[chunkName].hash = chunk.hash;
|
||||
assets.js.push(entry);
|
||||
|
||||
// Gather all css files
|
||||
var css = chunkFiles.filter(function (chunkFile) {
|
||||
// Some chunks may contain content hash in their names, for ex. 'main.css?1e7cac4e4d8b52fd5ccd2541146ef03f'.
|
||||
// We must proper handle such cases, so we use regexp testing here
|
||||
return /.css($|\?)/.test(chunkFile);
|
||||
});
|
||||
assets.chunks[chunkName].css = css;
|
||||
assets.css = assets.css.concat(css);
|
||||
}
|
||||
|
||||
// Duplicate css assets can occur on occasion if more than one chunk
|
||||
// requires the same css.
|
||||
assets.css = _.uniq(assets.css);
|
||||
|
||||
return assets;
|
||||
};
|
||||
|
||||
/**
|
||||
* Injects the assets into the given html string
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.generateAssetTags = function (assets) {
|
||||
// Turn script files into script tags
|
||||
var scripts = assets.js.map(function (scriptPath) {
|
||||
return {
|
||||
tagName: 'script',
|
||||
closeTag: true,
|
||||
attributes: {
|
||||
type: 'text/javascript',
|
||||
src: scriptPath
|
||||
}
|
||||
};
|
||||
});
|
||||
// Make tags self-closing in case of xhtml
|
||||
var selfClosingTag = !!this.options.xhtml;
|
||||
// Turn css files into link tags
|
||||
var styles = assets.css.map(function (stylePath) {
|
||||
return {
|
||||
tagName: 'link',
|
||||
selfClosingTag: selfClosingTag,
|
||||
attributes: {
|
||||
href: stylePath,
|
||||
rel: 'stylesheet'
|
||||
}
|
||||
};
|
||||
});
|
||||
// Injection targets
|
||||
var head = [];
|
||||
var body = [];
|
||||
|
||||
// If there is a favicon present, add it to the head
|
||||
if (assets.favicon) {
|
||||
head.push({
|
||||
tagName: 'link',
|
||||
selfClosingTag: selfClosingTag,
|
||||
attributes: {
|
||||
rel: 'shortcut icon',
|
||||
href: assets.favicon
|
||||
}
|
||||
});
|
||||
}
|
||||
// Add styles to the head
|
||||
head = head.concat(styles);
|
||||
// Add scripts to body or head
|
||||
if (this.options.inject === 'head') {
|
||||
head = head.concat(scripts);
|
||||
} else {
|
||||
body = body.concat(scripts);
|
||||
}
|
||||
return {head: head, body: body};
|
||||
};
|
||||
|
||||
/**
|
||||
* Injects the assets into the given html string
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function (html, assets, assetTags) {
|
||||
var htmlRegExp = /(<html[^>]*>)/i;
|
||||
var headRegExp = /(<\/head\s*>)/i;
|
||||
var bodyRegExp = /(<\/body\s*>)/i;
|
||||
var body = assetTags.body.map(this.createHtmlTag);
|
||||
var head = assetTags.head.map(this.createHtmlTag);
|
||||
|
||||
if (body.length) {
|
||||
if (bodyRegExp.test(html)) {
|
||||
// Append assets to body element
|
||||
html = html.replace(bodyRegExp, function (match) {
|
||||
return body.join('') + match;
|
||||
});
|
||||
} else {
|
||||
// Append scripts to the end of the file if no <body> element exists:
|
||||
html += body.join('');
|
||||
}
|
||||
}
|
||||
|
||||
if (head.length) {
|
||||
// Create a head tag if none exists
|
||||
if (!headRegExp.test(html)) {
|
||||
if (!htmlRegExp.test(html)) {
|
||||
html = '<head></head>' + html;
|
||||
} else {
|
||||
html = html.replace(htmlRegExp, function (match) {
|
||||
return match + '<head></head>';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Append assets to head element
|
||||
html = html.replace(headRegExp, function (match) {
|
||||
return head.join('') + match;
|
||||
});
|
||||
}
|
||||
|
||||
// Inject manifest into the opening html tag
|
||||
if (assets.manifest) {
|
||||
html = html.replace(/(<html[^>]*)(>)/i, function (match, start, end) {
|
||||
// Append the manifest only if no manifest was specified
|
||||
if (/\smanifest\s*=/.test(match)) {
|
||||
return match;
|
||||
}
|
||||
return start + ' manifest="' + assets.manifest + '"' + end;
|
||||
});
|
||||
}
|
||||
return html;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends a cache busting hash
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.appendHash = function (url, hash) {
|
||||
if (!url) {
|
||||
return url;
|
||||
}
|
||||
return url + (url.indexOf('?') === -1 ? '?' : '&') + hash;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turn a tag definition into a html string
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.createHtmlTag = function (tagDefinition) {
|
||||
var attributes = Object.keys(tagDefinition.attributes || {})
|
||||
.filter(function (attributeName) {
|
||||
return tagDefinition.attributes[attributeName] !== false;
|
||||
})
|
||||
.map(function (attributeName) {
|
||||
if (tagDefinition.attributes[attributeName] === true) {
|
||||
return attributeName;
|
||||
}
|
||||
return attributeName + '="' + tagDefinition.attributes[attributeName] + '"';
|
||||
});
|
||||
// Backport of 3.x void tag definition
|
||||
var voidTag = tagDefinition.voidTag !== undefined ? tagDefinition.voidTag : !tagDefinition.closeTag;
|
||||
var selfClosingTag = tagDefinition.voidTag !== undefined ? tagDefinition.voidTag && this.options.xhtml : tagDefinition.selfClosingTag;
|
||||
return '<' + [tagDefinition.tagName].concat(attributes).join(' ') + (selfClosingTag ? '/' : '') + '>' +
|
||||
(tagDefinition.innerHTML || '') +
|
||||
(voidTag ? '' : '</' + tagDefinition.tagName + '>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to return the absolute template path with a fallback loader
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.getFullTemplatePath = function (template, context) {
|
||||
// If the template doesn't use a loader use the lodash template loader
|
||||
if (template.indexOf('!') === -1) {
|
||||
template = require.resolve('./lib/loader.js') + '!' + path.resolve(context, template);
|
||||
}
|
||||
// Resolve template path
|
||||
return template.replace(
|
||||
/([!])([^/\\][^!?]+|[^/\\!?])($|\?[^!?\n]+$)/,
|
||||
function (match, prefix, filepath, postfix) {
|
||||
return prefix + path.resolve(filepath) + postfix;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to return a sorted unique array of all asset files out of the
|
||||
* asset object
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.getAssetFiles = function (assets) {
|
||||
var files = _.uniq(Object.keys(assets).filter(function (assetType) {
|
||||
return assetType !== 'chunks' && assets[assetType];
|
||||
}).reduce(function (files, assetType) {
|
||||
return files.concat(assets[assetType]);
|
||||
}, []));
|
||||
files.sort();
|
||||
return files;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to promisify compilation.applyPluginsAsyncWaterfall that returns
|
||||
* a function that helps to merge given plugin arguments with processed ones
|
||||
*/
|
||||
HtmlWebpackPlugin.prototype.applyPluginsAsyncWaterfall = function (compilation) {
|
||||
var promisedApplyPluginsAsyncWaterfall = Promise.promisify(compilation.applyPluginsAsyncWaterfall, {context: compilation});
|
||||
return function (eventName, requiresResult, pluginArgs) {
|
||||
return promisedApplyPluginsAsyncWaterfall(eventName, pluginArgs)
|
||||
.then(function (result) {
|
||||
if (requiresResult && !result) {
|
||||
compilation.warnings.push(new Error('Using ' + eventName + ' without returning a result is deprecated.'));
|
||||
}
|
||||
return _.extend(pluginArgs, result);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = HtmlWebpackPlugin;
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
|
||||
var toposort = require('toposort');
|
||||
var _ = require('lodash');
|
||||
|
||||
/*
|
||||
Sorts dependencies between chunks by their "parents" attribute.
|
||||
|
||||
This function sorts chunks based on their dependencies with each other.
|
||||
The parent relation between chunks as generated by Webpack for each chunk
|
||||
is used to define a directed (and hopefully acyclic) graph, which is then
|
||||
topologically sorted in order to retrieve the correct order in which
|
||||
chunks need to be embedded into HTML. A directed edge in this graph is
|
||||
describing a "is parent of" relationship from a chunk to another (distinct)
|
||||
chunk. Thus topological sorting orders chunks from bottom-layer chunks to
|
||||
highest level chunks that use the lower-level chunks.
|
||||
|
||||
@param {Array} chunks an array of chunks as generated by the html-webpack-plugin.
|
||||
It is assumed that each entry contains at least the properties "id"
|
||||
(containing the chunk id) and "parents" (array containing the ids of the
|
||||
parent chunks).
|
||||
|
||||
@return {Array} A topologically sorted version of the input chunks
|
||||
*/
|
||||
module.exports.dependency = function (chunks) {
|
||||
if (!chunks) {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
// We build a map (chunk-id -> chunk) for faster access during graph building.
|
||||
var nodeMap = {};
|
||||
|
||||
chunks.forEach(function (chunk) {
|
||||
nodeMap[chunk.id] = chunk;
|
||||
});
|
||||
|
||||
// Next, we add an edge for each parent relationship into the graph
|
||||
var edges = [];
|
||||
|
||||
chunks.forEach(function (chunk) {
|
||||
if (chunk.parents) {
|
||||
// Add an edge for each parent (parent -> child)
|
||||
chunk.parents.forEach(function (parentId) {
|
||||
// webpack2 chunk.parents are chunks instead of string id(s)
|
||||
var parentChunk = _.isObject(parentId) ? parentId : nodeMap[parentId];
|
||||
// If the parent chunk does not exist (e.g. because of an excluded chunk)
|
||||
// we ignore that parent
|
||||
if (parentChunk) {
|
||||
edges.push([parentChunk, chunk]);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// We now perform a topological sorting on the input chunks and built edges
|
||||
return toposort.array(chunks, edges);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts the chunks based on the chunk id.
|
||||
*
|
||||
* @param {Array} chunks the list of chunks to sort
|
||||
* @return {Array} The sorted list of chunks
|
||||
*/
|
||||
module.exports.id = function (chunks) {
|
||||
return chunks.sort(function orderEntryLast (a, b) {
|
||||
if (a.entry !== b.entry) {
|
||||
return b.entry ? 1 : -1;
|
||||
} else {
|
||||
return b.id - a.id;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs identity mapping (no-sort).
|
||||
* @param {Array} chunks the chunks to sort
|
||||
* @return {Array} The sorted chunks
|
||||
*/
|
||||
module.exports.none = function (chunks) {
|
||||
return chunks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sort manually by the chunks
|
||||
* @param {Array} chunks the chunks to sort
|
||||
* @return {Array} The sorted chunks
|
||||
*/
|
||||
module.exports.manual = function (chunks, specifyChunks) {
|
||||
var chunksResult = [];
|
||||
var filterResult = [];
|
||||
if (Array.isArray(specifyChunks)) {
|
||||
for (var i = 0; i < specifyChunks.length; i++) {
|
||||
filterResult = chunks.filter(function (chunk) {
|
||||
if (chunk.names[0] && chunk.names[0] === specifyChunks[i]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
filterResult.length > 0 && chunksResult.push(filterResult[0]);
|
||||
}
|
||||
}
|
||||
return chunksResult;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines the default sorter.
|
||||
*/
|
||||
module.exports.auto = module.exports.id;
|
||||
|
||||
// In webpack 2 the ids have been flipped.
|
||||
// Therefore the id sort doesn't work the same way as it did for webpack 1
|
||||
// Luckily the dependency sort is working as expected
|
||||
if (Number(require('webpack/package.json').version.split('.')[0]) > 1) {
|
||||
module.exports.auto = module.exports.dependency;
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file uses webpack to compile a template with a child compiler.
|
||||
*
|
||||
* [TEMPLATE] -> [JAVASCRIPT]
|
||||
*
|
||||
*/
|
||||
'use strict';
|
||||
var Promise = require('bluebird');
|
||||
var _ = require('lodash');
|
||||
var path = require('path');
|
||||
var NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
|
||||
var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
|
||||
var LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
|
||||
var LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
|
||||
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
|
||||
|
||||
/**
|
||||
* Compiles the template into a nodejs factory, adds its to the compilation.assets
|
||||
* and returns a promise of the result asset object.
|
||||
*
|
||||
* @param template relative path to the template file
|
||||
* @param context path context
|
||||
* @param outputFilename the file name
|
||||
* @param compilation The webpack compilation object
|
||||
*
|
||||
* Returns an object:
|
||||
* {
|
||||
* hash: {String} - Base64 hash of the file
|
||||
* content: {String} - Javascript executable code of the template
|
||||
* }
|
||||
*
|
||||
*/
|
||||
module.exports.compileTemplate = function compileTemplate (template, context, outputFilename, compilation) {
|
||||
// The entry file is just an empty helper as the dynamic template
|
||||
// require is added in "loader.js"
|
||||
var outputOptions = {
|
||||
filename: outputFilename,
|
||||
publicPath: compilation.outputOptions.publicPath
|
||||
};
|
||||
// Store the result of the parent compilation before we start the child compilation
|
||||
var assetsBeforeCompilation = _.assign({}, compilation.assets[outputOptions.filename]);
|
||||
// Create an additional child compiler which takes the template
|
||||
// and turns it into an Node.JS html factory.
|
||||
// This allows us to use loaders during the compilation
|
||||
var compilerName = getCompilerName(context, outputFilename);
|
||||
var childCompiler = compilation.createChildCompiler(compilerName, outputOptions);
|
||||
childCompiler.context = context;
|
||||
childCompiler.apply(
|
||||
new NodeTemplatePlugin(outputOptions),
|
||||
new NodeTargetPlugin(),
|
||||
new LibraryTemplatePlugin('HTML_WEBPACK_PLUGIN_RESULT', 'var'),
|
||||
new SingleEntryPlugin(this.context, template),
|
||||
new LoaderTargetPlugin('node')
|
||||
);
|
||||
|
||||
// Fix for "Uncaught TypeError: __webpack_require__(...) is not a function"
|
||||
// Hot module replacement requires that every child compiler has its own
|
||||
// cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179
|
||||
childCompiler.plugin('compilation', function (compilation) {
|
||||
if (compilation.cache) {
|
||||
if (!compilation.cache[compilerName]) {
|
||||
compilation.cache[compilerName] = {};
|
||||
}
|
||||
compilation.cache = compilation.cache[compilerName];
|
||||
}
|
||||
});
|
||||
|
||||
// Compile and return a promise
|
||||
return new Promise(function (resolve, reject) {
|
||||
childCompiler.runAsChild(function (err, entries, childCompilation) {
|
||||
// Resolve / reject the promise
|
||||
if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
|
||||
var errorDetails = childCompilation.errors.map(function (error) {
|
||||
return error.message + (error.error ? ':\n' + error.error : '');
|
||||
}).join('\n');
|
||||
reject(new Error('Child compilation failed:\n' + errorDetails));
|
||||
} else if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
// Replace [hash] placeholders in filename
|
||||
var outputName = compilation.mainTemplate.applyPluginsWaterfall('asset-path', outputOptions.filename, {
|
||||
hash: childCompilation.hash,
|
||||
chunk: entries[0]
|
||||
});
|
||||
// Restore the parent compilation to the state like it
|
||||
// was before the child compilation
|
||||
compilation.assets[outputName] = assetsBeforeCompilation[outputName];
|
||||
if (assetsBeforeCompilation[outputName] === undefined) {
|
||||
// If it wasn't there - delete it
|
||||
delete compilation.assets[outputName];
|
||||
}
|
||||
resolve({
|
||||
// Hash of the template entry point
|
||||
hash: entries[0].hash,
|
||||
// Output name
|
||||
outputName: outputName,
|
||||
// Compiled code
|
||||
content: childCompilation.assets[outputName].source()
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the child compiler name e.g. 'html-webpack-plugin for "index.html"'
|
||||
*/
|
||||
function getCompilerName (context, filename) {
|
||||
var absolutePath = path.resolve(context, filename);
|
||||
var relativePath = path.relative(context, absolutePath);
|
||||
return 'html-webpack-plugin for "' + (absolutePath.length < relativePath.length ? absolutePath : relativePath) + '"';
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
var PrettyError = require('pretty-error');
|
||||
var prettyError = new PrettyError();
|
||||
prettyError.withoutColors();
|
||||
prettyError.skipPackage(['html-plugin-evaluation']);
|
||||
prettyError.skipNodeFiles();
|
||||
prettyError.skip(function (traceLine) {
|
||||
return traceLine.path === 'html-plugin-evaluation';
|
||||
});
|
||||
|
||||
module.exports = function (err, context) {
|
||||
return {
|
||||
toHtml: function () {
|
||||
return 'Html Webpack Plugin:\n<pre>\n' + this.toString() + '</pre>';
|
||||
},
|
||||
toJsonHtml: function () {
|
||||
return JSON.stringify(this.toHtml());
|
||||
},
|
||||
toString: function () {
|
||||
return prettyError.render(err).replace(/webpack:\/\/\/\./g, context);
|
||||
}
|
||||
};
|
||||
};
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/* This loader renders the template with underscore if no other loader was found */
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
var loaderUtils = require('loader-utils');
|
||||
|
||||
module.exports = function (source) {
|
||||
if (this.cacheable) {
|
||||
this.cacheable();
|
||||
}
|
||||
var allLoadersButThisOne = this.loaders.filter(function (loader) {
|
||||
// Loader API changed from `loader.module` to `loader.normal` in Webpack 2.
|
||||
return (loader.module || loader.normal) !== module.exports;
|
||||
});
|
||||
// This loader shouldn't kick in if there is any other loader
|
||||
if (allLoadersButThisOne.length > 0) {
|
||||
return source;
|
||||
}
|
||||
// Skip .js files
|
||||
if (/\.js$/.test(this.resourcePath)) {
|
||||
return source;
|
||||
}
|
||||
|
||||
// The following part renders the tempalte with lodash as aminimalistic loader
|
||||
//
|
||||
// Get templating options
|
||||
var options = loaderUtils.parseQuery(this.query);
|
||||
// Webpack 2 does not allow with() statements, which lodash templates use to unwrap
|
||||
// the parameters passed to the compiled template inside the scope. We therefore
|
||||
// need to unwrap them ourselves here. This is essentially what lodash does internally
|
||||
// To tell lodash it should not use with we set a variable
|
||||
var template = _.template(source, _.defaults(options, { variable: 'data' }));
|
||||
// All templateVariables which should be available
|
||||
// @see HtmlWebpackPlugin.prototype.executeTemplate
|
||||
var templateVariables = [
|
||||
'compilation',
|
||||
'webpack',
|
||||
'webpackConfig',
|
||||
'htmlWebpackPlugin'
|
||||
];
|
||||
return 'var _ = require(' + loaderUtils.stringifyRequest(this, require.resolve('lodash')) + ');' +
|
||||
'module.exports = function (templateParams) {' +
|
||||
// Declare the template variables in the outer scope of the
|
||||
// lodash template to unwrap them
|
||||
templateVariables.map(function (variableName) {
|
||||
return 'var ' + variableName + ' = templateParams.' + variableName;
|
||||
}).join(';') + ';' +
|
||||
// Execute the lodash template
|
||||
'return (' + template.source + ')();' +
|
||||
'}';
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
../json5/lib/cli.js
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
The MIT Expat Licence.
|
||||
|
||||
Copyright (c) 2012 Michael Mclaughlin
|
||||
|
||||
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.
|
||||
|
||||
+263
@@ -0,0 +1,263 @@
|
||||
|
||||
# big.js #
|
||||
|
||||
A small, fast JavaScript library for arbitrary-precision decimal arithmetic.
|
||||
|
||||
The little sister to [bignumber.js](https://github.com/MikeMcl/bignumber.js/).
|
||||
See also [decimal.js](https://github.com/MikeMcl/decimal.js/), and [here](https://github.com/MikeMcl/big.js/wiki) for the difference between them.
|
||||
|
||||
## Features
|
||||
|
||||
- Faster, smaller and easier-to-use than JavaScript versions of Java's BigDecimal
|
||||
- Only 2.7 KB minified and gzipped
|
||||
- Simple API
|
||||
- Replicates the `toExponential`, `toFixed` and `toPrecision` methods of JavaScript's Number type
|
||||
- Includes a `sqrt` method
|
||||
- Stores values in an accessible decimal floating point format
|
||||
- No dependencies
|
||||
- Comprehensive [documentation](http://mikemcl.github.io/big.js/) and test set
|
||||
|
||||
## Load
|
||||
|
||||
The library is the single JavaScript file *big.js* (or *big.min.js*, which is *big.js* minified).
|
||||
|
||||
It can be loaded via a script tag in an HTML document for the browser
|
||||
|
||||
<script src='./relative/path/to/big.js'></script>
|
||||
|
||||
or as a CommonJS, [Node.js](http://nodejs.org) or AMD module using `require`.
|
||||
|
||||
var Big = require('big.js');
|
||||
|
||||
For Node.js, the library is available from the npm registry:
|
||||
|
||||
$ npm install big.js
|
||||
|
||||
|
||||
|
||||
## Use
|
||||
|
||||
*In all examples below, `var`, semicolons and `toString` calls are not shown.
|
||||
If a commented-out value is in quotes it means `toString` has been called on the preceding expression.*
|
||||
|
||||
The library exports a single function: Big, the constructor of Big number instances.
|
||||
It accepts a value of type Number, String or Big number Object.
|
||||
|
||||
x = new Big(123.4567)
|
||||
y = Big('123456.7e-3') // 'new' is optional
|
||||
z = new Big(x)
|
||||
x.eq(y) && x.eq(z) && y.eq(z) // true
|
||||
|
||||
A Big number is immutable in the sense that it is not changed by its methods.
|
||||
|
||||
0.3 - 0.1 // 0.19999999999999998
|
||||
x = new Big(0.3)
|
||||
x.minus(0.1) // "0.2"
|
||||
x // "0.3"
|
||||
|
||||
The methods that return a Big number can be chained.
|
||||
|
||||
x.div(y).plus(z).times(9).minus('1.234567801234567e+8').plus(976.54321).div('2598.11772')
|
||||
x.sqrt().div(y).pow(3).gt(y.mod(z)) // true
|
||||
|
||||
Like JavaScript's Number type, there are `toExponential`, `toFixed` and `toPrecision` methods.
|
||||
|
||||
x = new Big(255.5)
|
||||
x.toExponential(5) // "2.55500e+2"
|
||||
x.toFixed(5) // "255.50000"
|
||||
x.toPrecision(5) // "255.50"
|
||||
|
||||
The maximum number of decimal places and the rounding mode used to round the results of the `div`, `sqrt` and `pow`
|
||||
(with negative exponent) methods is determined by the value of the `DP` and `RM` properties of the `Big` number constructor.
|
||||
|
||||
The other methods always give the exact result.
|
||||
|
||||
(From *v3.0.0*, multiple Big number constructors can be created, see Change Log below.)
|
||||
|
||||
Big.DP = 10
|
||||
Big.RM = 1
|
||||
|
||||
x = new Big(2);
|
||||
y = new Big(3);
|
||||
z = x.div(y) // "0.6666666667"
|
||||
z.sqrt() // "0.8164965809"
|
||||
z.pow(-3) // "3.3749999995"
|
||||
z.times(z) // "0.44444444448888888889"
|
||||
z.times(z).round(10) // "0.4444444445"
|
||||
|
||||
|
||||
The value of a Big number is stored in a decimal floating point format in terms of a coefficient, exponent and sign.
|
||||
|
||||
x = new Big(-123.456);
|
||||
x.c // [1,2,3,4,5,6] coefficient (i.e. significand)
|
||||
x.e // 2 exponent
|
||||
x.s // -1 sign
|
||||
|
||||
For further information see the [API](http://mikemcl.github.io/big.js/) reference from the *doc* folder.
|
||||
|
||||
## Test
|
||||
|
||||
The *test* directory contains the test scripts for each Big number method.
|
||||
|
||||
The tests can be run with Node or a browser.
|
||||
|
||||
To test a single method, from a command-line shell at the *test* directory, use e.g.
|
||||
|
||||
$ node toFixed
|
||||
|
||||
To test all the methods
|
||||
|
||||
$ node every-test
|
||||
|
||||
For the browser, see *single-test.html* and *every-test.html* in the *test/browser* directory.
|
||||
|
||||
*big-vs-number.html* enables some of the methods of big.js to be compared with those of JavaScript's Number type.
|
||||
|
||||
## Performance
|
||||
|
||||
The *perf* directory contains two applications and a *lib* directory containing the BigDecimal libraries used by both.
|
||||
|
||||
*big-vs-bigdecimal.html* tests the performance of big.js against the JavaScript translations of two versions of BigDecimal, its use should be more or less self-explanatory.
|
||||
(The GWT version doesn't work in IE 6.)
|
||||
|
||||
* GWT: java.math.BigDecimal
|
||||
<https://github.com/iriscouch/bigdecimal.js>
|
||||
* ICU4J: com.ibm.icu.math.BigDecimal
|
||||
<https://github.com/dtrebbien/BigDecimal.js>
|
||||
|
||||
The BigDecimal in Node's npm registry is the GWT version. Despite its seeming popularity I have found it to have some serious bugs, see the Node script *perf/lib/bigdecimal_GWT/bugs.js* for examples of flaws in its *remainder*, *divide* and *compareTo* methods.
|
||||
|
||||
*bigtime.js* is a Node command-line application which tests the performance of big.js against the GWT version of
|
||||
BigDecimal from the npm registry.
|
||||
|
||||
For example, to compare the time taken by the big.js `plus` method and the BigDecimal `add` method:
|
||||
|
||||
$ node bigtime plus 10000 40
|
||||
|
||||
This will time 10000 calls to each, using operands of up to 40 random digits and will check that the results match.
|
||||
|
||||
For help:
|
||||
|
||||
$ node bigtime -h
|
||||
|
||||
## Build
|
||||
|
||||
I.e. minify.
|
||||
|
||||
For Node, if uglify-js is installed globally ( `npm install uglify-js -g` ) then
|
||||
|
||||
uglifyjs -o ./big.min.js ./big.js
|
||||
|
||||
will create *big.min.js*.
|
||||
|
||||
The *big.min.js* already present was created with *Microsoft Ajax Minifier 5.11*.
|
||||
|
||||
## TypeScript
|
||||
|
||||
The [DefinitelyTyped](https://github.com/borisyankov/DefinitelyTyped) project has a TypeScript [definitions file](https://github.com/borisyankov/DefinitelyTyped/blob/master/big.js/big.js.d.ts) for big.js.
|
||||
|
||||
The definitions file can be added to your project via the [big.js.TypeScript.DefinitelyTyped](https://www.nuget.org/packages/big.js.TypeScript.DefinitelyTyped/0.0.1) NuGet package or via [tsd](http://definitelytyped.org/tsd/).
|
||||
|
||||
tsd query big.js --action install
|
||||
|
||||
Any questions about the TypeScript definitions file should be addressed to the DefinitelyTyped project.
|
||||
|
||||
## Feedback
|
||||
|
||||
Feedback is welcome.
|
||||
|
||||
Bugs/comments/questions?
|
||||
Open an issue, or email
|
||||
|
||||
Michael
|
||||
<a href="mailto:M8ch88l@gmail.com">M8ch88l@gmail.com</a>
|
||||
|
||||
Bitcoin donation to:
|
||||
**1DppGRQSjVSMgGxuygDEHQuWEdTiVEzJYG**
|
||||
Thank you
|
||||
|
||||
## Licence
|
||||
|
||||
See LICENCE.
|
||||
|
||||
## Change Log
|
||||
|
||||
####3.2.0
|
||||
|
||||
* 14/09/17 Aid ES6 import.
|
||||
|
||||
####3.1.3
|
||||
|
||||
* Minor documentation updates.
|
||||
|
||||
####3.1.2
|
||||
|
||||
* README typo.
|
||||
|
||||
####3.1.1
|
||||
|
||||
* API documentation update, including FAQ additions.
|
||||
|
||||
####3.1.0
|
||||
|
||||
* Renamed and exposed `TO_EXP_NEG` and `TO_EXP_POS` as `Big.E_NEG` and
|
||||
`Big.E_POS`.
|
||||
|
||||
####3.0.2
|
||||
|
||||
* Remove *.npmignore*, use `files` field in *package.json* instead.
|
||||
|
||||
####3.0.1
|
||||
|
||||
* Added `sub`, `add` and `mul` aliases.
|
||||
* Clean-up after lint.
|
||||
|
||||
####3.0.0
|
||||
|
||||
* 10/12/14 Added [multiple constructor functionality](http://mikemcl.github.io/big.js/#faq).
|
||||
* No breaking changes or other additions, but a major code reorganisation,
|
||||
so *v3* seemed appropriate.
|
||||
|
||||
####2.5.2
|
||||
|
||||
* 1/11/14 Added bower.json.
|
||||
|
||||
####2.5.1
|
||||
|
||||
* 8/06/14 Amend README requires.
|
||||
|
||||
####2.5.0
|
||||
|
||||
* 26/01/14 Added `toJSON` method so serialization uses `toString`.
|
||||
|
||||
####2.4.1
|
||||
|
||||
* 17/10/13 Conform signed zero to IEEEE 754 (2008).
|
||||
|
||||
####2.4.0
|
||||
|
||||
* 19/09/13 Throw instances of `Error`.
|
||||
|
||||
####2.3.0
|
||||
|
||||
* 16/09/13 Added `cmp` method.
|
||||
|
||||
####2.2.0
|
||||
|
||||
* 11/07/13 Added 'round up' mode.
|
||||
|
||||
####2.1.0
|
||||
|
||||
* 26/06/13 Allow e.g. `.1` and `2.`.
|
||||
|
||||
####2.0.0
|
||||
|
||||
* 12/05/13 Added `abs` method and replaced `cmp` with `eq`, `gt`, `gte`, `lt`, and `lte` methods.
|
||||
|
||||
####1.0.1
|
||||
|
||||
* Changed default value of MAX_DP to 1E6
|
||||
|
||||
####1.0.0
|
||||
|
||||
* 7/11/2012 Initial release
|
||||
+1146
File diff suppressed because it is too large
Load Diff
+3
File diff suppressed because one or more lines are too long
+43
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "big.js",
|
||||
"description": "A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic",
|
||||
"version": "3.2.0",
|
||||
"keywords": [
|
||||
"arbitrary",
|
||||
"precision",
|
||||
"arithmetic",
|
||||
"big",
|
||||
"number",
|
||||
"decimal",
|
||||
"float",
|
||||
"biginteger",
|
||||
"bigdecimal",
|
||||
"bignumber",
|
||||
"bigint",
|
||||
"bignum"
|
||||
],
|
||||
"repository" : {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MikeMcl/big.js.git"
|
||||
},
|
||||
"main": "big.js",
|
||||
"author": {
|
||||
"name": "Michael Mclaughlin",
|
||||
"email": "M8ch88l@gmail.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/MikeMcl/big.js/issues"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "node ./test/every-test.js",
|
||||
"build": "uglifyjs big.js --source-map doc/big.js.map -c -m -o big.min.js --preamble \"/* big.js v3.2.0 https://github.com/MikeMcl/big.js/LICENCE */\""
|
||||
},
|
||||
"files": [
|
||||
"big.js",
|
||||
"big.min.js"
|
||||
]
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
<a name="2.1.0"></a>
|
||||
# 2.1.0 (2016-10-03)
|
||||
|
||||
* Fetch new emoji ([7dbe84d](https://github.com/kikobeats/emojis-list/commit/7dbe84d))
|
||||
|
||||
|
||||
|
||||
<a name="2.0.1"></a>
|
||||
## 2.0.1 (2016-05-12)
|
||||
|
||||
* Fix typo ([3808909](https://github.com/kikobeats/emojis-list/commit/3808909))
|
||||
|
||||
|
||||
|
||||
<a name="2.0.0"></a>
|
||||
# 2.0.0 (2016-05-12)
|
||||
|
||||
* Add update script ([f846dd6](https://github.com/kikobeats/emojis-list/commit/f846dd6))
|
||||
* Block dependencies in last version ([1d9e0a5](https://github.com/kikobeats/emojis-list/commit/1d9e0a5))
|
||||
* Extract main file name ([9ffe7bb](https://github.com/kikobeats/emojis-list/commit/9ffe7bb))
|
||||
* Remove unnecessary files ([4c34729](https://github.com/kikobeats/emojis-list/commit/4c34729))
|
||||
* Update docs, special webpack setup is not necessary ([c4aefe9](https://github.com/kikobeats/emojis-list/commit/c4aefe9))
|
||||
* Update example ([1e2ae03](https://github.com/kikobeats/emojis-list/commit/1e2ae03))
|
||||
* Update how to generate emojis array ([b56bad9](https://github.com/kikobeats/emojis-list/commit/b56bad9))
|
||||
* Update main file based in the new interface ([996fccb](https://github.com/kikobeats/emojis-list/commit/996fccb))
|
||||
|
||||
|
||||
|
||||
<a name="1.0.3"></a>
|
||||
## 1.0.3 (2016-05-12)
|
||||
|
||||
* Add standard as linter ([5e939d6](https://github.com/kikobeats/emojis-list/commit/5e939d6))
|
||||
* Change interface ([16bc0c0](https://github.com/kikobeats/emojis-list/commit/16bc0c0))
|
||||
* Generate emoji file ([fbcf8e9](https://github.com/kikobeats/emojis-list/commit/fbcf8e9))
|
||||
* Remove unnecessary special doc ([2b12bec](https://github.com/kikobeats/emojis-list/commit/2b12bec))
|
||||
* chore(package): update browserify to version 13.0.1 ([e2c98bf](https://github.com/kikobeats/emojis-list/commit/e2c98bf))
|
||||
* chore(package): update gulp-header to version 1.8.1 ([28de793](https://github.com/kikobeats/emojis-list/commit/28de793))
|
||||
|
||||
|
||||
|
||||
<a name="1.0.2"></a>
|
||||
## 1.0.2 (2016-05-05)
|
||||
|
||||
* fixed #2 ([9a6abe7](https://github.com/kikobeats/emojis-list/commit/9a6abe7)), closes [#2](https://github.com/kikobeats/emojis-list/issues/2)
|
||||
* Fomar using standard ([5202f9f](https://github.com/kikobeats/emojis-list/commit/5202f9f))
|
||||
* Update badge ([53fad9b](https://github.com/kikobeats/emojis-list/commit/53fad9b))
|
||||
|
||||
|
||||
|
||||
<a name="1.0.1"></a>
|
||||
## 1.0.1 (2016-04-13)
|
||||
|
||||
* lock versions ([4a5d82e](https://github.com/kikobeats/emojis-list/commit/4a5d82e))
|
||||
* setup devDependencies ([d1de0fc](https://github.com/kikobeats/emojis-list/commit/d1de0fc))
|
||||
* update bumped ([9941038](https://github.com/kikobeats/emojis-list/commit/9941038))
|
||||
* Update package.json ([6c14b74](https://github.com/kikobeats/emojis-list/commit/6c14b74))
|
||||
* Update README.md ([1d9beeb](https://github.com/kikobeats/emojis-list/commit/1d9beeb))
|
||||
* Update README.md ([73f215e](https://github.com/kikobeats/emojis-list/commit/73f215e))
|
||||
* Update tests ([a94f7dc](https://github.com/kikobeats/emojis-list/commit/a94f7dc))
|
||||
|
||||
|
||||
|
||||
<a name="1.0.0"></a>
|
||||
# 1.0.0 (2015-05-12)
|
||||
|
||||
* first commit ([a65b79d](https://github.com/kikobeats/emojis-list/commit/a65b79d))
|
||||
* updated ([9f0564c](https://github.com/kikobeats/emojis-list/commit/9f0564c))
|
||||
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2015 Kiko Beats
|
||||
|
||||
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.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# emojis-list
|
||||
|
||||
[](https://david-dm.org/Kikobeats/emojis-list)
|
||||
[](https://david-dm.org/Kikobeats/emojis-list#info=devDependencies)
|
||||
[](https://www.npmjs.org/package/emojis-list)
|
||||
[](https://paypal.me/kikobeats)
|
||||
|
||||
> Complete list of standard Unicode Hex Character Code that represent emojis.
|
||||
|
||||
**NOTE**: The lists is related with the Unicode Hex Character Code. The representation of the emoji depend of the system. Will be possible that the system don't have all the representations.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install emojis-list --save
|
||||
```
|
||||
|
||||
If you want to use in the browser (powered by [Browserify](http://browserify.org/)):
|
||||
|
||||
```bash
|
||||
bower install emojis-list --save
|
||||
```
|
||||
|
||||
and later link in your HTML:
|
||||
|
||||
```html
|
||||
<script src="bower_components/emojis-list/dist/emojis-list.js"></script>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
var emojis = require('emojis-list');
|
||||
console.log(emojis[0]);
|
||||
// => 🀄
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
* [emojis-unicode](https://github.com/Kikobeats/emojis-unicode) – Complete list of standard Unicode codes that represent emojis.
|
||||
* [emojis-keywords](https://github.com/Kikobeats/emojis-keywords) – Complete list of am emoji shortcuts.
|
||||
* [is-emoji-keyword](https://github.com/Kikobeats/is-emoji-keyword) – Check if a word is a emoji shortcut.
|
||||
* [is-standard-emoji](https://github.com/kikobeats/is-standard-emoji) – Simply way to check if a emoji is a standard emoji.
|
||||
* [trim-emoji](https://github.com/Kikobeats/trim-emoji) – Deletes ':' from the begin and the end of an emoji shortcut.
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Kiko Beats](http://www.kikobeats.com)
|
||||
+2479
File diff suppressed because it is too large
Load Diff
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "emojis-list",
|
||||
"description": "Complete list of standard emojis.",
|
||||
"homepage": "https://github.com/Kikobeats/emojis-list",
|
||||
"version": "2.1.0",
|
||||
"main": "./index.js",
|
||||
"author": {
|
||||
"email": "josefrancisco.verdu@gmail.com",
|
||||
"name": "Kiko Beats",
|
||||
"url": "https://github.com/Kikobeats"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/kikobeats/emojis-list.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/Kikobeats/emojis-list/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"archive",
|
||||
"complete",
|
||||
"emoji",
|
||||
"list",
|
||||
"standard"
|
||||
],
|
||||
"devDependencies": {
|
||||
"acho": "latest",
|
||||
"browserify": "latest",
|
||||
"cheerio": "latest",
|
||||
"got": ">=5 <6",
|
||||
"gulp": "latest",
|
||||
"gulp-header": "latest",
|
||||
"gulp-uglify": "latest",
|
||||
"gulp-util": "latest",
|
||||
"standard": "latest",
|
||||
"vinyl-buffer": "latest",
|
||||
"vinyl-source-stream": "latest"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"pretest": "standard update.js",
|
||||
"test": "echo 'YOLO'",
|
||||
"update": "node update"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
### v0.5.1 [[code][c0.5.1], [diff][d0.5.1]]
|
||||
|
||||
[c0.5.1]: https://github.com/aseemk/json5/tree/v0.5.1
|
||||
[d0.5.1]: https://github.com/aseemk/json5/compare/v0.5.0...v0.5.1
|
||||
|
||||
This release includes a minor fix for indentations when stringifying empty
|
||||
arrays.
|
||||
|
||||
- Fix: Indents no longer appear in empty arrays when stringified. ([#134])
|
||||
|
||||
|
||||
### v0.5.0 [[code][c0.5.0], [diff][d0.5.0]]
|
||||
|
||||
[c0.5.0]: https://github.com/aseemk/json5/tree/v0.5.0
|
||||
[d0.5.0]: https://github.com/aseemk/json5/compare/v0.4.0...v0.5.0
|
||||
|
||||
This release includes major internal changes and public API enhancements.
|
||||
|
||||
- **Major:** JSON5 officially supports Node.js v4 LTS and v5. Support for
|
||||
Node.js v0.6 and v0.8 have been dropped, while support for v0.10 and v0.12
|
||||
remain.
|
||||
|
||||
- Fix: YUI Compressor no longer fails when compressing json5.js. ([#97])
|
||||
|
||||
- New: `parse` and the CLI provide line and column numbers when displaying error
|
||||
messages. ([#101]; awesome work by [@amb26].)
|
||||
|
||||
|
||||
### v0.4.0 [[code][c0.4.0], [diff][d0.4.0]]
|
||||
|
||||
[c0.4.0]: https://github.com/aseemk/json5/tree/v0.4.0
|
||||
[d0.4.0]: https://github.com/aseemk/json5/compare/v0.2.0...v0.4.0
|
||||
|
||||
Note that v0.3.0 was tagged, but never published to npm, so this v0.4.0
|
||||
changelog entry includes v0.3.0 features.
|
||||
|
||||
This is a massive release that adds `stringify` support, among other things.
|
||||
|
||||
- **Major:** `JSON5.stringify()` now exists!
|
||||
This method is analogous to the native `JSON.stringify()`;
|
||||
it just avoids quoting keys where possible.
|
||||
See the [usage documentation](./README.md#usage) for more.
|
||||
([#32]; huge thanks and props [@aeisenberg]!)
|
||||
|
||||
- New: `NaN` and `-NaN` are now allowed number literals.
|
||||
([#30]; thanks [@rowanhill].)
|
||||
|
||||
- New: Duplicate object keys are now allowed; the last value is used.
|
||||
This is the same behavior as JSON. ([#57]; thanks [@jordanbtucker].)
|
||||
|
||||
- Fix: Properly handle various whitespace and newline cases now.
|
||||
E.g. JSON5 now properly supports escaped CR and CRLF newlines in strings,
|
||||
and JSON5 now accepts the same whitespace as JSON (stricter than ES5).
|
||||
([#58], [#60], and [#63]; thanks [@jordanbtucker].)
|
||||
|
||||
- New: Negative hexadecimal numbers (e.g. `-0xC8`) are allowed again.
|
||||
(They were disallowed in v0.2.0; see below.)
|
||||
It turns out they *are* valid in ES5, so JSON5 supports them now too.
|
||||
([#36]; thanks [@jordanbtucker]!)
|
||||
|
||||
|
||||
### v0.2.0 [[code][c0.2.0], [diff][d0.2.0]]
|
||||
|
||||
[c0.2.0]: https://github.com/aseemk/json5/tree/v0.2.0
|
||||
[d0.2.0]: https://github.com/aseemk/json5/compare/v0.1.0...v0.2.0
|
||||
|
||||
This release fixes some bugs and adds some more utility features to help you
|
||||
express data more easily:
|
||||
|
||||
- **Breaking:** Negative hexadecimal numbers (e.g. `-0xC8`) are rejected now.
|
||||
While V8 (e.g. Chrome and Node) supported them, it turns out they're invalid
|
||||
in ES5. This has been [fixed in V8][v8-hex-fix] (and by extension, Chrome
|
||||
and Node), so JSON5 officially rejects them now, too. ([#36])
|
||||
|
||||
- New: Trailing decimal points in decimal numbers are allowed again.
|
||||
(They were disallowed in v0.1.0; see below.)
|
||||
They're allowed by ES5, and differentiating between integers and floats may
|
||||
make sense on some platforms. ([#16]; thanks [@Midar].)
|
||||
|
||||
- New: `Infinity` and `-Infinity` are now allowed number literals.
|
||||
([#30]; thanks [@pepkin88].)
|
||||
|
||||
- New: Plus signs (`+`) in front of numbers are now allowed, since it can
|
||||
be helpful in some contexts to explicitly mark numbers as positive.
|
||||
(E.g. when a property represents changes or deltas.)
|
||||
|
||||
- Fix: unescaped newlines in strings are rejected now.
|
||||
([#24]; thanks [@Midar].)
|
||||
|
||||
|
||||
### v0.1.0 [[code][c0.1.0], [diff][d0.1.0]]
|
||||
|
||||
[c0.1.0]: https://github.com/aseemk/json5/tree/v0.1.0
|
||||
[d0.1.0]: https://github.com/aseemk/json5/compare/v0.0.1...v0.1.0
|
||||
|
||||
This release tightens JSON5 support and adds helpful utility features:
|
||||
|
||||
- New: Support hexadecimal numbers. (Thanks [@MaxNanasy].)
|
||||
|
||||
- Fix: Reject octal numbers properly now. Previously, they were accepted but
|
||||
improperly parsed as base-10 numbers. (Thanks [@MaxNanasy].)
|
||||
|
||||
- **Breaking:** Reject "noctal" numbers now (base-10 numbers that begin with a
|
||||
leading zero). These are disallowed by both JSON5 and JSON, as well as by
|
||||
ES5's strict mode. (Thanks [@MaxNanasy].)
|
||||
|
||||
- New: Support leading decimal points in decimal numbers.
|
||||
(Thanks [@MaxNanasy].)
|
||||
|
||||
- **Breaking:** Reject trailing decimal points in decimal numbers now. These
|
||||
are disallowed by both JSON5 and JSON. (Thanks [@MaxNanasy].)
|
||||
|
||||
- **Breaking:** Reject omitted elements in arrays now. These are disallowed by
|
||||
both JSON5 and JSON.
|
||||
|
||||
- Fix: Throw proper `SyntaxError` instances on errors now.
|
||||
|
||||
- New: Add Node.js `require()` hook. Register via `json5/lib/require`.
|
||||
|
||||
- New: Add Node.js `json5` executable to compile JSON5 files to JSON.
|
||||
|
||||
|
||||
### v0.0.1 [[code][c0.0.1], [diff][d0.0.1]]
|
||||
|
||||
[c0.0.1]: https://github.com/aseemk/json5/tree/v0.0.1
|
||||
[d0.0.1]: https://github.com/aseemk/json5/compare/v0.0.0...v0.0.1
|
||||
|
||||
This was the first implementation of this JSON5 parser.
|
||||
|
||||
- Support unquoted object keys, including reserved words. Unicode characters
|
||||
and escape sequences sequences aren't yet supported.
|
||||
|
||||
- Support single-quoted strings.
|
||||
|
||||
- Support multi-line strings.
|
||||
|
||||
- Support trailing commas in arrays and objects.
|
||||
|
||||
- Support comments, both inline and block.
|
||||
|
||||
|
||||
### v0.0.0 [[code](https://github.com/aseemk/json5/tree/v0.0.0)]
|
||||
|
||||
Let's consider this to be Douglas Crockford's original [json_parse.js] — a
|
||||
parser for the regular JSON format.
|
||||
|
||||
|
||||
[json_parse.js]: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
|
||||
[v8-hex-fix]: http://code.google.com/p/v8/issues/detail?id=2240
|
||||
|
||||
[@MaxNanasy]: https://github.com/MaxNanasy
|
||||
[@Midar]: https://github.com/Midar
|
||||
[@pepkin88]: https://github.com/pepkin88
|
||||
[@rowanhill]: https://github.com/rowanhill
|
||||
[@aeisenberg]: https://github.com/aeisenberg
|
||||
[@jordanbtucker]: https://github.com/jordanbtucker
|
||||
[@amb26]: https://github.com/amb26
|
||||
|
||||
[#16]: https://github.com/aseemk/json5/issues/16
|
||||
[#24]: https://github.com/aseemk/json5/issues/24
|
||||
[#30]: https://github.com/aseemk/json5/issues/30
|
||||
[#32]: https://github.com/aseemk/json5/issues/32
|
||||
[#36]: https://github.com/aseemk/json5/issues/36
|
||||
[#57]: https://github.com/aseemk/json5/issues/57
|
||||
[#58]: https://github.com/aseemk/json5/pull/58
|
||||
[#60]: https://github.com/aseemk/json5/pull/60
|
||||
[#63]: https://github.com/aseemk/json5/pull/63
|
||||
[#97]: https://github.com/aseemk/json5/pull/97
|
||||
[#101]: https://github.com/aseemk/json5/pull/101
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2012-2016 Aseem Kishore, and [others](https://github.com/aseemk/json5/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.
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
# JSON5 – Modern JSON
|
||||
|
||||
[](https://travis-ci.org/json5/json5)
|
||||
|
||||
JSON is an excellent data format, but we think it can be better.
|
||||
|
||||
**JSON5 is a proposed extension to JSON** that aims to make it easier for
|
||||
*humans to write and maintain* by hand. It does this by adding some minimal
|
||||
syntax features directly from ECMAScript 5.
|
||||
|
||||
JSON5 remains a **strict subset of JavaScript**, adds **no new data types**,
|
||||
and **works with all existing JSON content**.
|
||||
|
||||
JSON5 is *not* an official successor to JSON, and JSON5 content may *not*
|
||||
work with existing JSON parsers. For this reason, JSON5 files use a new .json5
|
||||
extension. *(TODO: new MIME type needed too.)*
|
||||
|
||||
The code here is a **reference JavaScript implementation** for both Node.js
|
||||
and all browsers. It’s based directly off of Douglas Crockford’s own [JSON
|
||||
implementation][json_parse.js], and it’s both robust and secure.
|
||||
|
||||
|
||||
## Why
|
||||
|
||||
JSON isn’t the friendliest to *write*. Keys need to be quoted, objects and
|
||||
arrays can’t have trailing commas, and comments aren’t allowed — even though
|
||||
none of these are the case with regular JavaScript today.
|
||||
|
||||
That was fine when JSON’s goal was to be a great data format, but JSON’s usage
|
||||
has expanded beyond *machines*. JSON is now used for writing [configs][ex1],
|
||||
[manifests][ex2], even [tests][ex3] — all by *humans*.
|
||||
|
||||
[ex1]: http://plovr.com/docs.html
|
||||
[ex2]: https://www.npmjs.org/doc/files/package.json.html
|
||||
[ex3]: http://code.google.com/p/fuzztester/wiki/JSONFileFormat
|
||||
|
||||
There are other formats that are human-friendlier, like YAML, but changing
|
||||
from JSON to a completely different format is undesirable in many cases.
|
||||
JSON5’s aim is to remain close to JSON and JavaScript.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
The following is the exact list of additions to JSON’s syntax introduced by
|
||||
JSON5. **All of these are optional**, and **all of these come from ES5**.
|
||||
|
||||
### Objects
|
||||
|
||||
- Object keys can be unquoted if they’re valid [identifiers][mdn_variables].
|
||||
Yes, even reserved keywords (like `default`) are valid unquoted keys in ES5
|
||||
[[§11.1.5](http://es5.github.com/#x11.1.5), [§7.6](http://es5.github.com/#x7.6)].
|
||||
([More info](https://mathiasbynens.be/notes/javascript-identifiers))
|
||||
|
||||
*(TODO: Unicode characters and escape sequences aren’t yet supported in this
|
||||
implementation.)*
|
||||
|
||||
- Object keys can also be single-quoted.
|
||||
|
||||
- Objects can have trailing commas.
|
||||
|
||||
[mdn_variables]: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Variables
|
||||
|
||||
### Arrays
|
||||
|
||||
- Arrays can have trailing commas.
|
||||
|
||||
### Strings
|
||||
|
||||
- Strings can be single-quoted.
|
||||
|
||||
- Strings can be split across multiple lines; just prefix each newline with a
|
||||
backslash. [ES5 [§7.8.4](http://es5.github.com/#x7.8.4)]
|
||||
|
||||
### Numbers
|
||||
|
||||
- Numbers can be hexadecimal (base 16).
|
||||
|
||||
- Numbers can begin or end with a (leading or trailing) decimal point.
|
||||
|
||||
- Numbers can include `Infinity`, `-Infinity`, `NaN`, and `-NaN`.
|
||||
|
||||
- Numbers can begin with an explicit plus sign.
|
||||
|
||||
### Comments
|
||||
|
||||
- Both inline (single-line) and block (multi-line) comments are allowed.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
The following is a contrived example, but it illustrates most of the features:
|
||||
|
||||
```js
|
||||
{
|
||||
foo: 'bar',
|
||||
while: true,
|
||||
|
||||
this: 'is a \
|
||||
multi-line string',
|
||||
|
||||
// this is an inline comment
|
||||
here: 'is another', // inline comment
|
||||
|
||||
/* this is a block comment
|
||||
that continues on another line */
|
||||
|
||||
hex: 0xDEADbeef,
|
||||
half: .5,
|
||||
delta: +10,
|
||||
to: Infinity, // and beyond!
|
||||
|
||||
finally: 'a trailing comma',
|
||||
oh: [
|
||||
"we shouldn't forget",
|
||||
'arrays can have',
|
||||
'trailing commas too',
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
This implementation’s own [package.json5](package.json5) is more realistic:
|
||||
|
||||
```js
|
||||
// This file is written in JSON5 syntax, naturally, but npm needs a regular
|
||||
// JSON file, so compile via `npm run build`. Be sure to keep both in sync!
|
||||
|
||||
{
|
||||
name: 'json5',
|
||||
version: '0.5.0',
|
||||
description: 'JSON for the ES5 era.',
|
||||
keywords: ['json', 'es5'],
|
||||
author: 'Aseem Kishore <aseem.kishore@gmail.com>',
|
||||
contributors: [
|
||||
// TODO: Should we remove this section in favor of GitHub's list?
|
||||
// https://github.com/aseemk/json5/contributors
|
||||
'Max Nanasy <max.nanasy@gmail.com>',
|
||||
'Andrew Eisenberg <andrew@eisenberg.as>',
|
||||
'Jordan Tucker <jordanbtucker@gmail.com>',
|
||||
],
|
||||
main: 'lib/json5.js',
|
||||
bin: 'lib/cli.js',
|
||||
files: ["lib/"],
|
||||
dependencies: {},
|
||||
devDependencies: {
|
||||
gulp: "^3.9.1",
|
||||
'gulp-jshint': "^2.0.0",
|
||||
jshint: "^2.9.1",
|
||||
'jshint-stylish': "^2.1.0",
|
||||
mocha: "^2.4.5"
|
||||
},
|
||||
scripts: {
|
||||
build: 'node ./lib/cli.js -c package.json5',
|
||||
test: 'mocha --ui exports --reporter spec',
|
||||
// TODO: Would it be better to define these in a mocha.opts file?
|
||||
},
|
||||
homepage: 'http://json5.org/',
|
||||
license: 'MIT',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'https://github.com/aseemk/json5.git',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Community
|
||||
|
||||
Join the [Google Group](http://groups.google.com/group/json5) if you’re
|
||||
interested in JSON5 news, updates, and general discussion.
|
||||
Don’t worry, it’s very low-traffic.
|
||||
|
||||
The [GitHub wiki](https://github.com/aseemk/json5/wiki) is a good place to track
|
||||
JSON5 support and usage. Contribute freely there!
|
||||
|
||||
[GitHub Issues](https://github.com/aseemk/json5/issues) is the place to
|
||||
formally propose feature requests and report bugs. Questions and general
|
||||
feedback are better directed at the Google Group.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
This JavaScript implementation of JSON5 simply provides a `JSON5` object just
|
||||
like the native ES5 `JSON` object.
|
||||
|
||||
To use from Node:
|
||||
|
||||
```sh
|
||||
npm install json5
|
||||
```
|
||||
|
||||
```js
|
||||
var JSON5 = require('json5');
|
||||
```
|
||||
|
||||
To use in the browser (adds the `JSON5` object to the global namespace):
|
||||
|
||||
```html
|
||||
<script src="json5.js"></script>
|
||||
```
|
||||
|
||||
Then in both cases, you can simply replace native `JSON` calls with `JSON5`:
|
||||
|
||||
```js
|
||||
var obj = JSON5.parse('{unquoted:"key",trailing:"comma",}');
|
||||
var str = JSON5.stringify(obj);
|
||||
```
|
||||
|
||||
`JSON5.parse` supports all of the JSON5 features listed above (*TODO: except
|
||||
Unicode*), as well as the native [`reviver` argument][json-parse].
|
||||
|
||||
[json-parse]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
||||
|
||||
`JSON5.stringify` mainly avoids quoting keys where possible, but we hope to
|
||||
keep expanding it in the future (e.g. to also output trailing commas).
|
||||
It supports the native [`replacer` and `space` arguments][json-stringify],
|
||||
as well. *(TODO: Any implemented `toJSON` methods aren’t used today.)*
|
||||
|
||||
[json-stringify]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
|
||||
|
||||
|
||||
### Extras
|
||||
|
||||
If you’re running this on Node, you can also register a JSON5 `require()` hook
|
||||
to let you `require()` `.json5` files just like you can `.json` files:
|
||||
|
||||
```js
|
||||
require('json5/lib/require');
|
||||
require('./path/to/foo'); // tries foo.json5 after foo.js, foo.json, etc.
|
||||
require('./path/to/bar.json5');
|
||||
```
|
||||
|
||||
This module also provides a `json5` executable (requires Node) for converting
|
||||
JSON5 files to JSON:
|
||||
|
||||
```sh
|
||||
json5 -c path/to/foo.json5 # generates path/to/foo.json
|
||||
```
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
git clone git://github.com/aseemk/json5.git
|
||||
cd json5
|
||||
npm install
|
||||
npm test
|
||||
```
|
||||
|
||||
As the `package.json5` file states, be sure to run `npm run build` on changes
|
||||
to `package.json5`, since npm requires `package.json`.
|
||||
|
||||
Feel free to [file issues](https://github.com/aseemk/json5/issues) and submit
|
||||
[pull requests](https://github.com/aseemk/json5/pulls) — contributions are
|
||||
welcome. If you do submit a pull request, please be sure to add or update the
|
||||
tests, and ensure that `npm test` continues to pass.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT. See [LICENSE.md](./LICENSE.md) for details.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
[Michael Bolin](http://bolinfest.com/) independently arrived at and published
|
||||
some of these same ideas with awesome explanations and detail.
|
||||
Recommended reading:
|
||||
[Suggested Improvements to JSON](http://bolinfest.com/essays/json.html)
|
||||
|
||||
[Douglas Crockford](http://www.crockford.com/) of course designed and built
|
||||
JSON, but his state machine diagrams on the [JSON website](http://json.org/),
|
||||
as cheesy as it may sound, gave me motivation and confidence that building a
|
||||
new parser to implement these ideas this was within my reach!
|
||||
This code is also modeled directly off of Doug’s open-source [json_parse.js][]
|
||||
parser. I’m super grateful for that clean and well-documented code.
|
||||
|
||||
[json_parse.js]: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
|
||||
|
||||
[Max Nanasy](https://github.com/MaxNanasy) has been an early and prolific
|
||||
supporter, contributing multiple patches and ideas. Thanks Max!
|
||||
|
||||
[Andrew Eisenberg](https://github.com/aeisenberg) has contributed the
|
||||
`stringify` method.
|
||||
|
||||
[Jordan Tucker](https://github.com/jordanbtucker) has aligned JSON5 more closely
|
||||
with ES5 and is actively maintaining this project.
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// cli.js
|
||||
// JSON5 command-line interface.
|
||||
//
|
||||
// This is pretty minimal for now; just supports compiling files via `-c`.
|
||||
// TODO More useful functionality, like output path, watch, etc.?
|
||||
|
||||
var FS = require('fs');
|
||||
var JSON5 = require('./json5');
|
||||
var Path = require('path');
|
||||
|
||||
var USAGE = [
|
||||
'Usage: json5 -c path/to/file.json5 ...',
|
||||
'Compiles JSON5 files into sibling JSON files with the same basenames.',
|
||||
].join('\n');
|
||||
|
||||
// if valid, args look like [node, json5, -c, file1, file2, ...]
|
||||
var args = process.argv;
|
||||
|
||||
if (args.length < 4 || args[2] !== '-c') {
|
||||
console.error(USAGE);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var cwd = process.cwd();
|
||||
var files = args.slice(3);
|
||||
|
||||
// iterate over each file and convert JSON5 files to JSON:
|
||||
files.forEach(function (file) {
|
||||
var path = Path.resolve(cwd, file);
|
||||
var basename = Path.basename(path, '.json5');
|
||||
var dirname = Path.dirname(path);
|
||||
|
||||
var json5 = FS.readFileSync(path, 'utf8');
|
||||
var obj = JSON5.parse(json5);
|
||||
var json = JSON.stringify(obj, null, 4); // 4 spaces; TODO configurable?
|
||||
|
||||
path = Path.join(dirname, basename + '.json');
|
||||
FS.writeFileSync(path, json, 'utf8');
|
||||
});
|
||||
+770
@@ -0,0 +1,770 @@
|
||||
// json5.js
|
||||
// Modern JSON. See README.md for details.
|
||||
//
|
||||
// This file is based directly off of Douglas Crockford's json_parse.js:
|
||||
// https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
|
||||
|
||||
var JSON5 = (typeof exports === 'object' ? exports : {});
|
||||
|
||||
JSON5.parse = (function () {
|
||||
"use strict";
|
||||
|
||||
// This is a function that can parse a JSON5 text, producing a JavaScript
|
||||
// data structure. It is a simple, recursive descent parser. It does not use
|
||||
// eval or regular expressions, so it can be used as a model for implementing
|
||||
// a JSON5 parser in other languages.
|
||||
|
||||
// We are defining the function inside of another function to avoid creating
|
||||
// global variables.
|
||||
|
||||
var at, // The index of the current character
|
||||
lineNumber, // The current line number
|
||||
columnNumber, // The current column number
|
||||
ch, // The current character
|
||||
escapee = {
|
||||
"'": "'",
|
||||
'"': '"',
|
||||
'\\': '\\',
|
||||
'/': '/',
|
||||
'\n': '', // Replace escaped newlines in strings w/ empty string
|
||||
b: '\b',
|
||||
f: '\f',
|
||||
n: '\n',
|
||||
r: '\r',
|
||||
t: '\t'
|
||||
},
|
||||
ws = [
|
||||
' ',
|
||||
'\t',
|
||||
'\r',
|
||||
'\n',
|
||||
'\v',
|
||||
'\f',
|
||||
'\xA0',
|
||||
'\uFEFF'
|
||||
],
|
||||
text,
|
||||
|
||||
renderChar = function (chr) {
|
||||
return chr === '' ? 'EOF' : "'" + chr + "'";
|
||||
},
|
||||
|
||||
error = function (m) {
|
||||
|
||||
// Call error when something is wrong.
|
||||
|
||||
var error = new SyntaxError();
|
||||
// beginning of message suffix to agree with that provided by Gecko - see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse
|
||||
error.message = m + " at line " + lineNumber + " column " + columnNumber + " of the JSON5 data. Still to read: " + JSON.stringify(text.substring(at - 1, at + 19));
|
||||
error.at = at;
|
||||
// These two property names have been chosen to agree with the ones in Gecko, the only popular
|
||||
// environment which seems to supply this info on JSON.parse
|
||||
error.lineNumber = lineNumber;
|
||||
error.columnNumber = columnNumber;
|
||||
throw error;
|
||||
},
|
||||
|
||||
next = function (c) {
|
||||
|
||||
// If a c parameter is provided, verify that it matches the current character.
|
||||
|
||||
if (c && c !== ch) {
|
||||
error("Expected " + renderChar(c) + " instead of " + renderChar(ch));
|
||||
}
|
||||
|
||||
// Get the next character. When there are no more characters,
|
||||
// return the empty string.
|
||||
|
||||
ch = text.charAt(at);
|
||||
at++;
|
||||
columnNumber++;
|
||||
if (ch === '\n' || ch === '\r' && peek() !== '\n') {
|
||||
lineNumber++;
|
||||
columnNumber = 0;
|
||||
}
|
||||
return ch;
|
||||
},
|
||||
|
||||
peek = function () {
|
||||
|
||||
// Get the next character without consuming it or
|
||||
// assigning it to the ch varaible.
|
||||
|
||||
return text.charAt(at);
|
||||
},
|
||||
|
||||
identifier = function () {
|
||||
|
||||
// Parse an identifier. Normally, reserved words are disallowed here, but we
|
||||
// only use this for unquoted object keys, where reserved words are allowed,
|
||||
// so we don't check for those here. References:
|
||||
// - http://es5.github.com/#x7.6
|
||||
// - https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Variables
|
||||
// - http://docstore.mik.ua/orelly/webprog/jscript/ch02_07.htm
|
||||
// TODO Identifiers can have Unicode "letters" in them; add support for those.
|
||||
|
||||
var key = ch;
|
||||
|
||||
// Identifiers must start with a letter, _ or $.
|
||||
if ((ch !== '_' && ch !== '$') &&
|
||||
(ch < 'a' || ch > 'z') &&
|
||||
(ch < 'A' || ch > 'Z')) {
|
||||
error("Bad identifier as unquoted key");
|
||||
}
|
||||
|
||||
// Subsequent characters can contain digits.
|
||||
while (next() && (
|
||||
ch === '_' || ch === '$' ||
|
||||
(ch >= 'a' && ch <= 'z') ||
|
||||
(ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9'))) {
|
||||
key += ch;
|
||||
}
|
||||
|
||||
return key;
|
||||
},
|
||||
|
||||
number = function () {
|
||||
|
||||
// Parse a number value.
|
||||
|
||||
var number,
|
||||
sign = '',
|
||||
string = '',
|
||||
base = 10;
|
||||
|
||||
if (ch === '-' || ch === '+') {
|
||||
sign = ch;
|
||||
next(ch);
|
||||
}
|
||||
|
||||
// support for Infinity (could tweak to allow other words):
|
||||
if (ch === 'I') {
|
||||
number = word();
|
||||
if (typeof number !== 'number' || isNaN(number)) {
|
||||
error('Unexpected word for number');
|
||||
}
|
||||
return (sign === '-') ? -number : number;
|
||||
}
|
||||
|
||||
// support for NaN
|
||||
if (ch === 'N' ) {
|
||||
number = word();
|
||||
if (!isNaN(number)) {
|
||||
error('expected word to be NaN');
|
||||
}
|
||||
// ignore sign as -NaN also is NaN
|
||||
return number;
|
||||
}
|
||||
|
||||
if (ch === '0') {
|
||||
string += ch;
|
||||
next();
|
||||
if (ch === 'x' || ch === 'X') {
|
||||
string += ch;
|
||||
next();
|
||||
base = 16;
|
||||
} else if (ch >= '0' && ch <= '9') {
|
||||
error('Octal literal');
|
||||
}
|
||||
}
|
||||
|
||||
switch (base) {
|
||||
case 10:
|
||||
while (ch >= '0' && ch <= '9' ) {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
if (ch === '.') {
|
||||
string += '.';
|
||||
while (next() && ch >= '0' && ch <= '9') {
|
||||
string += ch;
|
||||
}
|
||||
}
|
||||
if (ch === 'e' || ch === 'E') {
|
||||
string += ch;
|
||||
next();
|
||||
if (ch === '-' || ch === '+') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
while (ch >= '0' && ch <= '9') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
while (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'F' || ch >= 'a' && ch <= 'f') {
|
||||
string += ch;
|
||||
next();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(sign === '-') {
|
||||
number = -string;
|
||||
} else {
|
||||
number = +string;
|
||||
}
|
||||
|
||||
if (!isFinite(number)) {
|
||||
error("Bad number");
|
||||
} else {
|
||||
return number;
|
||||
}
|
||||
},
|
||||
|
||||
string = function () {
|
||||
|
||||
// Parse a string value.
|
||||
|
||||
var hex,
|
||||
i,
|
||||
string = '',
|
||||
delim, // double quote or single quote
|
||||
uffff;
|
||||
|
||||
// When parsing for string values, we must look for ' or " and \ characters.
|
||||
|
||||
if (ch === '"' || ch === "'") {
|
||||
delim = ch;
|
||||
while (next()) {
|
||||
if (ch === delim) {
|
||||
next();
|
||||
return string;
|
||||
} else if (ch === '\\') {
|
||||
next();
|
||||
if (ch === 'u') {
|
||||
uffff = 0;
|
||||
for (i = 0; i < 4; i += 1) {
|
||||
hex = parseInt(next(), 16);
|
||||
if (!isFinite(hex)) {
|
||||
break;
|
||||
}
|
||||
uffff = uffff * 16 + hex;
|
||||
}
|
||||
string += String.fromCharCode(uffff);
|
||||
} else if (ch === '\r') {
|
||||
if (peek() === '\n') {
|
||||
next();
|
||||
}
|
||||
} else if (typeof escapee[ch] === 'string') {
|
||||
string += escapee[ch];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (ch === '\n') {
|
||||
// unescaped newlines are invalid; see:
|
||||
// https://github.com/aseemk/json5/issues/24
|
||||
// TODO this feels special-cased; are there other
|
||||
// invalid unescaped chars?
|
||||
break;
|
||||
} else {
|
||||
string += ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
error("Bad string");
|
||||
},
|
||||
|
||||
inlineComment = function () {
|
||||
|
||||
// Skip an inline comment, assuming this is one. The current character should
|
||||
// be the second / character in the // pair that begins this inline comment.
|
||||
// To finish the inline comment, we look for a newline or the end of the text.
|
||||
|
||||
if (ch !== '/') {
|
||||
error("Not an inline comment");
|
||||
}
|
||||
|
||||
do {
|
||||
next();
|
||||
if (ch === '\n' || ch === '\r') {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
} while (ch);
|
||||
},
|
||||
|
||||
blockComment = function () {
|
||||
|
||||
// Skip a block comment, assuming this is one. The current character should be
|
||||
// the * character in the /* pair that begins this block comment.
|
||||
// To finish the block comment, we look for an ending */ pair of characters,
|
||||
// but we also watch for the end of text before the comment is terminated.
|
||||
|
||||
if (ch !== '*') {
|
||||
error("Not a block comment");
|
||||
}
|
||||
|
||||
do {
|
||||
next();
|
||||
while (ch === '*') {
|
||||
next('*');
|
||||
if (ch === '/') {
|
||||
next('/');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (ch);
|
||||
|
||||
error("Unterminated block comment");
|
||||
},
|
||||
|
||||
comment = function () {
|
||||
|
||||
// Skip a comment, whether inline or block-level, assuming this is one.
|
||||
// Comments always begin with a / character.
|
||||
|
||||
if (ch !== '/') {
|
||||
error("Not a comment");
|
||||
}
|
||||
|
||||
next('/');
|
||||
|
||||
if (ch === '/') {
|
||||
inlineComment();
|
||||
} else if (ch === '*') {
|
||||
blockComment();
|
||||
} else {
|
||||
error("Unrecognized comment");
|
||||
}
|
||||
},
|
||||
|
||||
white = function () {
|
||||
|
||||
// Skip whitespace and comments.
|
||||
// Note that we're detecting comments by only a single / character.
|
||||
// This works since regular expressions are not valid JSON(5), but this will
|
||||
// break if there are other valid values that begin with a / character!
|
||||
|
||||
while (ch) {
|
||||
if (ch === '/') {
|
||||
comment();
|
||||
} else if (ws.indexOf(ch) >= 0) {
|
||||
next();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
word = function () {
|
||||
|
||||
// true, false, or null.
|
||||
|
||||
switch (ch) {
|
||||
case 't':
|
||||
next('t');
|
||||
next('r');
|
||||
next('u');
|
||||
next('e');
|
||||
return true;
|
||||
case 'f':
|
||||
next('f');
|
||||
next('a');
|
||||
next('l');
|
||||
next('s');
|
||||
next('e');
|
||||
return false;
|
||||
case 'n':
|
||||
next('n');
|
||||
next('u');
|
||||
next('l');
|
||||
next('l');
|
||||
return null;
|
||||
case 'I':
|
||||
next('I');
|
||||
next('n');
|
||||
next('f');
|
||||
next('i');
|
||||
next('n');
|
||||
next('i');
|
||||
next('t');
|
||||
next('y');
|
||||
return Infinity;
|
||||
case 'N':
|
||||
next( 'N' );
|
||||
next( 'a' );
|
||||
next( 'N' );
|
||||
return NaN;
|
||||
}
|
||||
error("Unexpected " + renderChar(ch));
|
||||
},
|
||||
|
||||
value, // Place holder for the value function.
|
||||
|
||||
array = function () {
|
||||
|
||||
// Parse an array value.
|
||||
|
||||
var array = [];
|
||||
|
||||
if (ch === '[') {
|
||||
next('[');
|
||||
white();
|
||||
while (ch) {
|
||||
if (ch === ']') {
|
||||
next(']');
|
||||
return array; // Potentially empty array
|
||||
}
|
||||
// ES5 allows omitting elements in arrays, e.g. [,] and
|
||||
// [,null]. We don't allow this in JSON5.
|
||||
if (ch === ',') {
|
||||
error("Missing array element");
|
||||
} else {
|
||||
array.push(value());
|
||||
}
|
||||
white();
|
||||
// If there's no comma after this value, this needs to
|
||||
// be the end of the array.
|
||||
if (ch !== ',') {
|
||||
next(']');
|
||||
return array;
|
||||
}
|
||||
next(',');
|
||||
white();
|
||||
}
|
||||
}
|
||||
error("Bad array");
|
||||
},
|
||||
|
||||
object = function () {
|
||||
|
||||
// Parse an object value.
|
||||
|
||||
var key,
|
||||
object = {};
|
||||
|
||||
if (ch === '{') {
|
||||
next('{');
|
||||
white();
|
||||
while (ch) {
|
||||
if (ch === '}') {
|
||||
next('}');
|
||||
return object; // Potentially empty object
|
||||
}
|
||||
|
||||
// Keys can be unquoted. If they are, they need to be
|
||||
// valid JS identifiers.
|
||||
if (ch === '"' || ch === "'") {
|
||||
key = string();
|
||||
} else {
|
||||
key = identifier();
|
||||
}
|
||||
|
||||
white();
|
||||
next(':');
|
||||
object[key] = value();
|
||||
white();
|
||||
// If there's no comma after this pair, this needs to be
|
||||
// the end of the object.
|
||||
if (ch !== ',') {
|
||||
next('}');
|
||||
return object;
|
||||
}
|
||||
next(',');
|
||||
white();
|
||||
}
|
||||
}
|
||||
error("Bad object");
|
||||
};
|
||||
|
||||
value = function () {
|
||||
|
||||
// Parse a JSON value. It could be an object, an array, a string, a number,
|
||||
// or a word.
|
||||
|
||||
white();
|
||||
switch (ch) {
|
||||
case '{':
|
||||
return object();
|
||||
case '[':
|
||||
return array();
|
||||
case '"':
|
||||
case "'":
|
||||
return string();
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
return number();
|
||||
default:
|
||||
return ch >= '0' && ch <= '9' ? number() : word();
|
||||
}
|
||||
};
|
||||
|
||||
// Return the json_parse function. It will have access to all of the above
|
||||
// functions and variables.
|
||||
|
||||
return function (source, reviver) {
|
||||
var result;
|
||||
|
||||
text = String(source);
|
||||
at = 0;
|
||||
lineNumber = 1;
|
||||
columnNumber = 1;
|
||||
ch = ' ';
|
||||
result = value();
|
||||
white();
|
||||
if (ch) {
|
||||
error("Syntax error");
|
||||
}
|
||||
|
||||
// If there is a reviver function, we recursively walk the new structure,
|
||||
// passing each name/value pair to the reviver function for possible
|
||||
// transformation, starting with a temporary root object that holds the result
|
||||
// in an empty key. If there is not a reviver function, we simply return the
|
||||
// result.
|
||||
|
||||
return typeof reviver === 'function' ? (function walk(holder, key) {
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}({'': result}, '')) : result;
|
||||
};
|
||||
}());
|
||||
|
||||
// JSON5 stringify will not quote keys where appropriate
|
||||
JSON5.stringify = function (obj, replacer, space) {
|
||||
if (replacer && (typeof(replacer) !== "function" && !isArray(replacer))) {
|
||||
throw new Error('Replacer must be a function or an array');
|
||||
}
|
||||
var getReplacedValueOrUndefined = function(holder, key, isTopLevel) {
|
||||
var value = holder[key];
|
||||
|
||||
// Replace the value with its toJSON value first, if possible
|
||||
if (value && value.toJSON && typeof value.toJSON === "function") {
|
||||
value = value.toJSON();
|
||||
}
|
||||
|
||||
// If the user-supplied replacer if a function, call it. If it's an array, check objects' string keys for
|
||||
// presence in the array (removing the key/value pair from the resulting JSON if the key is missing).
|
||||
if (typeof(replacer) === "function") {
|
||||
return replacer.call(holder, key, value);
|
||||
} else if(replacer) {
|
||||
if (isTopLevel || isArray(holder) || replacer.indexOf(key) >= 0) {
|
||||
return value;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
function isWordChar(c) {
|
||||
return (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c === '_' || c === '$';
|
||||
}
|
||||
|
||||
function isWordStart(c) {
|
||||
return (c >= 'a' && c <= 'z') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
c === '_' || c === '$';
|
||||
}
|
||||
|
||||
function isWord(key) {
|
||||
if (typeof key !== 'string') {
|
||||
return false;
|
||||
}
|
||||
if (!isWordStart(key[0])) {
|
||||
return false;
|
||||
}
|
||||
var i = 1, length = key.length;
|
||||
while (i < length) {
|
||||
if (!isWordChar(key[i])) {
|
||||
return false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// export for use in tests
|
||||
JSON5.isWord = isWord;
|
||||
|
||||
// polyfills
|
||||
function isArray(obj) {
|
||||
if (Array.isArray) {
|
||||
return Array.isArray(obj);
|
||||
} else {
|
||||
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||
}
|
||||
}
|
||||
|
||||
function isDate(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Date]';
|
||||
}
|
||||
|
||||
var objStack = [];
|
||||
function checkForCircular(obj) {
|
||||
for (var i = 0; i < objStack.length; i++) {
|
||||
if (objStack[i] === obj) {
|
||||
throw new TypeError("Converting circular structure to JSON");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeIndent(str, num, noNewLine) {
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
// indentation no more than 10 chars
|
||||
if (str.length > 10) {
|
||||
str = str.substring(0, 10);
|
||||
}
|
||||
|
||||
var indent = noNewLine ? "" : "\n";
|
||||
for (var i = 0; i < num; i++) {
|
||||
indent += str;
|
||||
}
|
||||
|
||||
return indent;
|
||||
}
|
||||
|
||||
var indentStr;
|
||||
if (space) {
|
||||
if (typeof space === "string") {
|
||||
indentStr = space;
|
||||
} else if (typeof space === "number" && space >= 0) {
|
||||
indentStr = makeIndent(" ", space, true);
|
||||
} else {
|
||||
// ignore space parameter
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from Crokford's implementation of JSON
|
||||
// See https://github.com/douglascrockford/JSON-js/blob/e39db4b7e6249f04a195e7dd0840e610cc9e941e/json2.js#L195
|
||||
// Begin
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
function escapeString(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ?
|
||||
c :
|
||||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' : '"' + string + '"';
|
||||
}
|
||||
// End
|
||||
|
||||
function internalStringify(holder, key, isTopLevel) {
|
||||
var buffer, res;
|
||||
|
||||
// Replace the value, if necessary
|
||||
var obj_part = getReplacedValueOrUndefined(holder, key, isTopLevel);
|
||||
|
||||
if (obj_part && !isDate(obj_part)) {
|
||||
// unbox objects
|
||||
// don't unbox dates, since will turn it into number
|
||||
obj_part = obj_part.valueOf();
|
||||
}
|
||||
switch(typeof obj_part) {
|
||||
case "boolean":
|
||||
return obj_part.toString();
|
||||
|
||||
case "number":
|
||||
if (isNaN(obj_part) || !isFinite(obj_part)) {
|
||||
return "null";
|
||||
}
|
||||
return obj_part.toString();
|
||||
|
||||
case "string":
|
||||
return escapeString(obj_part.toString());
|
||||
|
||||
case "object":
|
||||
if (obj_part === null) {
|
||||
return "null";
|
||||
} else if (isArray(obj_part)) {
|
||||
checkForCircular(obj_part);
|
||||
buffer = "[";
|
||||
objStack.push(obj_part);
|
||||
|
||||
for (var i = 0; i < obj_part.length; i++) {
|
||||
res = internalStringify(obj_part, i, false);
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
if (res === null || typeof res === "undefined") {
|
||||
buffer += "null";
|
||||
} else {
|
||||
buffer += res;
|
||||
}
|
||||
if (i < obj_part.length-1) {
|
||||
buffer += ",";
|
||||
} else if (indentStr) {
|
||||
buffer += "\n";
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (obj_part.length) {
|
||||
buffer += makeIndent(indentStr, objStack.length, true)
|
||||
}
|
||||
buffer += "]";
|
||||
} else {
|
||||
checkForCircular(obj_part);
|
||||
buffer = "{";
|
||||
var nonEmpty = false;
|
||||
objStack.push(obj_part);
|
||||
for (var prop in obj_part) {
|
||||
if (obj_part.hasOwnProperty(prop)) {
|
||||
var value = internalStringify(obj_part, prop, false);
|
||||
isTopLevel = false;
|
||||
if (typeof value !== "undefined" && value !== null) {
|
||||
buffer += makeIndent(indentStr, objStack.length);
|
||||
nonEmpty = true;
|
||||
key = isWord(prop) ? prop : escapeString(prop);
|
||||
buffer += key + ":" + (indentStr ? ' ' : '') + value + ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
objStack.pop();
|
||||
if (nonEmpty) {
|
||||
buffer = buffer.substring(0, buffer.length-1) + makeIndent(indentStr, objStack.length) + "}";
|
||||
} else {
|
||||
buffer = '{}';
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
default:
|
||||
// functions and undefined should be ignored
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// special case...when undefined is used inside of
|
||||
// a compound object/array, return null.
|
||||
// but when top-level, return undefined
|
||||
var topLevelHolder = {"":obj};
|
||||
if (obj === undefined) {
|
||||
return getReplacedValueOrUndefined(topLevelHolder, '', true);
|
||||
}
|
||||
return internalStringify(topLevelHolder, '', true);
|
||||
};
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// require.js
|
||||
// Node.js only: adds a require() hook for .json5 files, just like the native
|
||||
// hook for .json files.
|
||||
//
|
||||
// Usage:
|
||||
// require('json5/require');
|
||||
// require('./foo'); // will check foo.json5 after foo.js, foo.json, etc.
|
||||
// require('./bar.json5');
|
||||
|
||||
var FS = require('fs');
|
||||
var JSON5 = require('./json5');
|
||||
|
||||
// Modeled off of (v0.6.18 link; check latest too):
|
||||
// https://github.com/joyent/node/blob/v0.6.18/lib/module.js#L468-L472
|
||||
require.extensions['.json5'] = function (module, filename) {
|
||||
var content = FS.readFileSync(filename, 'utf8');
|
||||
module.exports = JSON5.parse(content);
|
||||
};
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "json5",
|
||||
"version": "0.5.1",
|
||||
"description": "JSON for the ES5 era.",
|
||||
"keywords": [
|
||||
"json",
|
||||
"es5"
|
||||
],
|
||||
"author": "Aseem Kishore <aseem.kishore@gmail.com>",
|
||||
"contributors": [
|
||||
"Max Nanasy <max.nanasy@gmail.com>",
|
||||
"Andrew Eisenberg <andrew@eisenberg.as>",
|
||||
"Jordan Tucker <jordanbtucker@gmail.com>"
|
||||
],
|
||||
"main": "lib/json5.js",
|
||||
"bin": "lib/cli.js",
|
||||
"files": [
|
||||
"lib/"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-jshint": "^2.0.1",
|
||||
"jshint": "^2.9.3",
|
||||
"jshint-stylish": "^2.2.1",
|
||||
"mocha": "^3.1.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node ./lib/cli.js -c package.json5",
|
||||
"test": "mocha --ui exports --reporter spec"
|
||||
},
|
||||
"homepage": "http://json5.org/",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aseemk/json5.git"
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 - 2015 Tobias Koppers
|
||||
|
||||
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.
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
# loader-utils
|
||||
|
||||
## Methods
|
||||
|
||||
### `getLoaderConfig`
|
||||
|
||||
Recommended way to retrieve the loader config:
|
||||
|
||||
```javascript
|
||||
// inside your loader
|
||||
config = loaderUtils.getLoaderConfig(this, "myLoader");
|
||||
```
|
||||
|
||||
Tries to read the loader config from the `webpack.config.js` under the given property name (`"myLoader"` in this case) and merges the result with the loader query. For example, if your `webpack.config.js` had this property...
|
||||
|
||||
```javascript
|
||||
cheesecakeLoader: {
|
||||
type: "delicious",
|
||||
slices: 4
|
||||
}
|
||||
```
|
||||
|
||||
...and your loader was called with `?slices=8`, `getLoaderConfig(this, "cheesecakeLoader")` would return
|
||||
|
||||
```javascript
|
||||
{
|
||||
type: "delicious",
|
||||
slices: 8
|
||||
}
|
||||
```
|
||||
|
||||
It is recommended that you use the camelCased loader name as your default config property name.
|
||||
|
||||
### `parseQuery`
|
||||
|
||||
``` javascript
|
||||
var query = loaderUtils.parseQuery(this.query);
|
||||
assert(typeof query == "object");
|
||||
if(query.flag)
|
||||
// ...
|
||||
```
|
||||
|
||||
``` text
|
||||
null -> {}
|
||||
? -> {}
|
||||
?flag -> { flag: true }
|
||||
?+flag -> { flag: true }
|
||||
?-flag -> { flag: false }
|
||||
?xyz=test -> { xyz: "test" }
|
||||
?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" }
|
||||
?{json:5,data:{a:1}} -> { json: 5, data: { a: 1 } }
|
||||
```
|
||||
|
||||
### `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.
|
||||
|
||||
```javascript
|
||||
var url = "path/to/module.js";
|
||||
var 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
|
||||
var url = "~path/to/module.js";
|
||||
var 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
|
||||
var url = "/path/to/module.js";
|
||||
var root = "./root";
|
||||
var 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
|
||||
var url = "/path/to/module.js";
|
||||
var root = "~";
|
||||
var 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
|
||||
var 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 of the resource is in.
|
||||
* `[emoji]` a random emoji representation of `options.content`
|
||||
* `[emoji:<length>]` same as above, but with a customizable number of emojis
|
||||
* `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the md5 hash)
|
||||
* `[<hashType>:hash:<digestType>:<length>]` optionally one can configure
|
||||
* other `hashType`s, i. e. `sha1`, `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`
|
||||
|
||||
Examples
|
||||
|
||||
``` javascript
|
||||
// loaderContext.resourcePath = "/app/js/javascript.js"
|
||||
loaderUtils.interpolateName(loaderContext, "js/[hash].script.[ext]", { content: ... });
|
||||
// => js/9473fdd0d880a43c21b7778d34872157.script.js
|
||||
|
||||
// loaderContext.resourcePath = "/app/page.html"
|
||||
loaderUtils.interpolateName(loaderContext, "html-[hash:6].html", { content: ... });
|
||||
// => html-9473fd.html
|
||||
|
||||
// loaderContext.resourcePath = "/app/flash.txt"
|
||||
loaderUtils.interpolateName(loaderContext, "[hash]", { content: ... });
|
||||
// => c31e9820c001c9c4a86bce33ce43b679
|
||||
|
||||
// loaderContext.resourcePath = "/app/img/image.gif"
|
||||
loaderUtils.interpolateName(loaderContext, "[emoji]", { content: ... });
|
||||
// => 👍
|
||||
|
||||
// loaderContext.resourcePath = "/app/img/image.gif"
|
||||
loaderUtils.interpolateName(loaderContext, "[emoji:4]", { content: ... });
|
||||
// => 🙍🏢📤🐝
|
||||
|
||||
// loaderContext.resourcePath = "/app/img/image.png"
|
||||
loaderUtils.interpolateName(loaderContext, "[sha512:hash:base64:7].[ext]", { content: ... });
|
||||
// => 2BKDTjl.png
|
||||
// use sha512 hash instead of md5 and with only 7 chars of base64
|
||||
|
||||
// loaderContext.resourcePath = "/app/img/myself.png"
|
||||
// loaderContext.query.name =
|
||||
loaderUtils.interpolateName(loaderContext, "picture.png");
|
||||
// => picture.png
|
||||
|
||||
// loaderContext.resourcePath = "/app/dir/file.png"
|
||||
loaderUtils.interpolateName(loaderContext, "[path][name].[ext]?[hash]", { content: ... });
|
||||
// => /app/dir/file.png?9473fdd0d880a43c21b7778d34872157
|
||||
|
||||
// loaderContext.resourcePath = "/app/js/page-home.js"
|
||||
loaderUtils.interpolateName(loaderContext, "script-[1].[ext]", { regExp: "page-(.*)\\.js", content: ... });
|
||||
// => script-home.js
|
||||
```
|
||||
|
||||
### `getHashDigest`
|
||||
|
||||
``` javascript
|
||||
var digestString = loaderUtils.getHashDigest(buffer, hashType, digestType, maxLength);
|
||||
```
|
||||
|
||||
* `buffer` the content that should be hashed
|
||||
* `hashType` one of `sha1`, `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)
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
var JSON5 = require("json5");
|
||||
var path = require("path");
|
||||
var util = require("util");
|
||||
var os = require("os");
|
||||
var assign = require("object-assign");
|
||||
var emojiRegex = /[\uD800-\uDFFF]./;
|
||||
var emojiList = require("emojis-list").filter(function(emoji) {
|
||||
return emojiRegex.test(emoji)
|
||||
});
|
||||
var matchAbsolutePath = /^\/|^[A-Z]:[/\\]|^\\\\/i; // node 0.10 does not support path.isAbsolute()
|
||||
var matchAbsoluteWin32Path = /^[A-Z]:[/\\]|^\\\\/i;
|
||||
var matchRelativePath = /^\.\.?[/\\]/;
|
||||
|
||||
var baseEncodeTables = {
|
||||
26: "abcdefghijklmnopqrstuvwxyz",
|
||||
32: "123456789abcdefghjkmnpqrstuvwxyz", // no 0lio
|
||||
36: "0123456789abcdefghijklmnopqrstuvwxyz",
|
||||
49: "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no lIO
|
||||
52: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
58: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", // no 0lIO
|
||||
62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
64: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_"
|
||||
};
|
||||
var emojiCache = {};
|
||||
var parseQueryDeprecationWarning = util.deprecate(function() {},
|
||||
"loaderUtils.parseQuery() received a non-string value which can be problematic, " +
|
||||
"see https://github.com/webpack/loader-utils/issues/56" + os.EOL +
|
||||
"parseQuery() will be replaced with getOptions() in the next major version of loader-utils."
|
||||
);
|
||||
|
||||
function encodeStringToEmoji(content, length) {
|
||||
if (emojiCache[content]) return emojiCache[content];
|
||||
length = length || 1;
|
||||
var emojis = [];
|
||||
do {
|
||||
var index = Math.floor(Math.random() * emojiList.length);
|
||||
emojis.push(emojiList[index]);
|
||||
emojiList.splice(index, 1);
|
||||
} while (--length > 0);
|
||||
var emojiEncoding = emojis.join('');
|
||||
emojiCache[content] = emojiEncoding;
|
||||
return emojiEncoding;
|
||||
}
|
||||
|
||||
function encodeBufferToBase(buffer, base) {
|
||||
var encodeTable = baseEncodeTables[base];
|
||||
if (!encodeTable) throw new Error("Unknown encoding base" + base);
|
||||
|
||||
var readLength = buffer.length;
|
||||
|
||||
var Big = require('big.js');
|
||||
Big.RM = Big.DP = 0;
|
||||
var b = new Big(0);
|
||||
for (var i = readLength - 1; i >= 0; i--) {
|
||||
b = b.times(256).plus(buffer[i]);
|
||||
}
|
||||
|
||||
var output = "";
|
||||
while (b.gt(0)) {
|
||||
output = encodeTable[b.mod(base)] + output;
|
||||
b = b.div(base);
|
||||
}
|
||||
|
||||
Big.DP = 20;
|
||||
Big.RM = 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
exports.parseQuery = function parseQuery(query) {
|
||||
var specialValues = {
|
||||
'null': null,
|
||||
'true': true,
|
||||
'false': false
|
||||
};
|
||||
if(!query) return {};
|
||||
if(typeof query !== "string") {
|
||||
parseQueryDeprecationWarning();
|
||||
return query;
|
||||
}
|
||||
if(query.substr(0, 1) !== "?")
|
||||
throw new Error("a valid query string passed to parseQuery should begin with '?'");
|
||||
query = query.substr(1);
|
||||
var queryLength = query.length;
|
||||
if(query.substr(0, 1) === "{" && query.substr(-1) === "}") {
|
||||
return JSON5.parse(query);
|
||||
}
|
||||
var queryArgs = query.split(/[,\&]/g);
|
||||
var result = {};
|
||||
queryArgs.forEach(function(arg) {
|
||||
var idx = arg.indexOf("=");
|
||||
if(idx >= 0) {
|
||||
var name = arg.substr(0, idx);
|
||||
var value = decodeURIComponent(arg.substr(idx+1));
|
||||
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;
|
||||
};
|
||||
|
||||
exports.getLoaderConfig = function(loaderContext, defaultConfigKey) {
|
||||
var query = exports.parseQuery(loaderContext.query);
|
||||
var configKey = query.config || defaultConfigKey;
|
||||
if (configKey) {
|
||||
var config = loaderContext.options[configKey] || {};
|
||||
delete query.config;
|
||||
return assign({}, config, query);
|
||||
}
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
exports.stringifyRequest = function(loaderContext, request) {
|
||||
var splitted = request.split("!");
|
||||
var context = loaderContext.context || (loaderContext.options && loaderContext.options.context);
|
||||
return JSON.stringify(splitted.map(function(part) {
|
||||
// First, separate singlePath from query, because the query might contain paths again
|
||||
var splittedPart = part.match(/^(.*?)(\?.*)/);
|
||||
var singlePath = splittedPart ? splittedPart[1] : part;
|
||||
var query = splittedPart ? splittedPart[2] : "";
|
||||
if(matchAbsolutePath.test(singlePath) && context) {
|
||||
singlePath = path.relative(context, singlePath);
|
||||
if(matchAbsolutePath.test(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(matchRelativePath.test(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("!"));
|
||||
};
|
||||
|
||||
function dotRequest(obj) {
|
||||
return obj.request;
|
||||
}
|
||||
|
||||
exports.getRemainingRequest = function(loaderContext) {
|
||||
if(loaderContext.remainingRequest)
|
||||
return loaderContext.remainingRequest;
|
||||
var request = loaderContext.loaders.slice(loaderContext.loaderIndex+1).map(dotRequest).concat([loaderContext.resource]);
|
||||
return request.join("!");
|
||||
};
|
||||
|
||||
exports.getCurrentRequest = function(loaderContext) {
|
||||
if(loaderContext.currentRequest)
|
||||
return loaderContext.currentRequest;
|
||||
var request = loaderContext.loaders.slice(loaderContext.loaderIndex).map(dotRequest).concat([loaderContext.resource]);
|
||||
return request.join("!");
|
||||
};
|
||||
|
||||
exports.isUrlRequest = function(url, root) {
|
||||
// An URL is not an request if
|
||||
// 1. it's a Data Url
|
||||
// 2. it's an absolute url or and protocol-relative
|
||||
// 3. it's some kind of url for a template
|
||||
if(/^data:|^chrome-extension:|^(https?:)?\/\/|^[\{\}\[\]#*;,'§\$%&\(=?`´\^°<>]/.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;
|
||||
};
|
||||
|
||||
exports.urlToRequest = function(url, root) {
|
||||
var moduleRequestRegex = /^[^?]*~/;
|
||||
var request;
|
||||
|
||||
if(matchAbsoluteWin32Path.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;
|
||||
};
|
||||
|
||||
exports.parseString = function parseString(str) {
|
||||
try {
|
||||
if(str[0] === '"') return JSON.parse(str);
|
||||
if(str[0] === "'" && str.substr(str.length - 1) === "'") {
|
||||
return parseString(str.replace(/\\.|"/g, function(x) {
|
||||
if(x === '"') return '\\"';
|
||||
return x;
|
||||
}).replace(/^'|'$/g, '"'));
|
||||
}
|
||||
return JSON.parse('"' + str + '"');
|
||||
} catch(e) {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
exports.getHashDigest = function getHashDigest(buffer, hashType, digestType, maxLength) {
|
||||
hashType = hashType || "md5";
|
||||
maxLength = maxLength || 9999;
|
||||
var hash = require("crypto").createHash(hashType);
|
||||
hash.update(buffer);
|
||||
if (digestType === "base26" || digestType === "base32" || digestType === "base36" ||
|
||||
digestType === "base49" || digestType === "base52" || digestType === "base58" ||
|
||||
digestType === "base62" || digestType === "base64") {
|
||||
return encodeBufferToBase(hash.digest(), digestType.substr(4)).substr(0, maxLength);
|
||||
} else {
|
||||
return hash.digest(digestType || "hex").substr(0, maxLength);
|
||||
}
|
||||
};
|
||||
|
||||
exports.interpolateName = function interpolateName(loaderContext, name, options) {
|
||||
var filename;
|
||||
if (typeof name === "function") {
|
||||
filename = name(loaderContext.resourcePath);
|
||||
} else {
|
||||
filename = name || "[hash].[ext]";
|
||||
}
|
||||
var context = options.context;
|
||||
var content = options.content;
|
||||
var regExp = options.regExp;
|
||||
var ext = "bin";
|
||||
var basename = "file";
|
||||
var directory = "";
|
||||
var folder = "";
|
||||
if(loaderContext.resourcePath) {
|
||||
var resourcePath = loaderContext.resourcePath;
|
||||
var idx = resourcePath.lastIndexOf(".");
|
||||
var i = resourcePath.lastIndexOf("\\");
|
||||
var j = resourcePath.lastIndexOf("/");
|
||||
var p = i < 0 ? j : j < 0 ? i : i < j ? i : j;
|
||||
if(idx >= 0) {
|
||||
ext = resourcePath.substr(idx+1);
|
||||
resourcePath = resourcePath.substr(0, idx);
|
||||
}
|
||||
if(p >= 0) {
|
||||
basename = resourcePath.substr(p+1);
|
||||
resourcePath = resourcePath.substr(0, p+1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
var url = filename;
|
||||
if(content) {
|
||||
// Match hash template
|
||||
url = url.replace(/\[(?:(\w+):)?hash(?::([a-z]+\d*))?(?::(\d+))?\]/ig, function() {
|
||||
return exports.getHashDigest(content, arguments[1], arguments[2], parseInt(arguments[3], 10));
|
||||
}).replace(/\[emoji(?::(\d+))?\]/ig, function() {
|
||||
return encodeStringToEmoji(content, arguments[1]);
|
||||
});
|
||||
}
|
||||
url = url.replace(/\[ext\]/ig, function() {
|
||||
return ext;
|
||||
}).replace(/\[name\]/ig, function() {
|
||||
return basename;
|
||||
}).replace(/\[path\]/ig, function() {
|
||||
return directory;
|
||||
}).replace(/\[folder\]/ig, function() {
|
||||
return folder;
|
||||
});
|
||||
if(regExp && loaderContext.resourcePath) {
|
||||
var re = new RegExp(regExp);
|
||||
var match = loaderContext.resourcePath.match(re);
|
||||
if(match) {
|
||||
for (var i = 0; i < match.length; i++) {
|
||||
var re = new RegExp("\\[" + i + "\\]", "ig");
|
||||
url = url.replace(re, match[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(typeof loaderContext.options === "object" && typeof loaderContext.options.customInterpolateName === "function") {
|
||||
url = loaderContext.options.customInterpolateName.call(loaderContext, url, name, options);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "loader-utils",
|
||||
"version": "0.2.17",
|
||||
"author": "Tobias Koppers @sokra",
|
||||
"description": "utils for webpack loaders",
|
||||
"dependencies": {
|
||||
"big.js": "^3.1.3",
|
||||
"emojis-list": "^2.0.0",
|
||||
"json5": "^0.5.0",
|
||||
"object-assign": "^4.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"travis": "npm run cover -- --report lcovonly",
|
||||
"cover": "istanbul cover -x *.runtime.js node_modules/mocha/bin/_mocha",
|
||||
"publish-patch": "mocha && npm version patch && git push && git push --tags && npm publish"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webpack/loader-utils.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^2.11.2",
|
||||
"istanbul": "^0.3.14",
|
||||
"mocha": "^1.21.4"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
]
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "html-webpack-plugin",
|
||||
"version": "2.30.1",
|
||||
"description": "Simplifies creation of HTML files to serve your webpack bundles",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"default_index.ejs",
|
||||
"lib/"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublish": "npm run test",
|
||||
"pretest": "semistandard",
|
||||
"build-examples": "node examples/build-examples.js",
|
||||
"test": "jasmine"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jantimon/html-webpack-plugin.git"
|
||||
},
|
||||
"keywords": [
|
||||
"webpack",
|
||||
"plugin",
|
||||
"html",
|
||||
"html-webpack-plugin"
|
||||
],
|
||||
"author": "Charles Blaxland <charles.blaxland@gmail.com> (https://github.com/ampedandwired)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jantimon/html-webpack-plugin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jantimon/html-webpack-plugin",
|
||||
"semistandard": {
|
||||
"ignore": [
|
||||
"examples/*/dist/**/*.*"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"appcache-webpack-plugin": "^1.3.0",
|
||||
"css-loader": "^0.26.1",
|
||||
"dir-compare": "1.3.0",
|
||||
"es6-promise": "^4.0.5",
|
||||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"file-loader": "^0.9.0",
|
||||
"html-loader": "^0.4.4",
|
||||
"jade": "^1.11.0",
|
||||
"jade-loader": "^0.8.0",
|
||||
"jasmine": "^2.5.2",
|
||||
"rimraf": "^2.5.4",
|
||||
"semistandard": "8.0.0",
|
||||
"style-loader": "^0.13.1",
|
||||
"underscore-template-loader": "^0.7.3",
|
||||
"url-loader": "^0.5.7",
|
||||
"webpack": "^1.14.0",
|
||||
"webpack-recompilation-simulator": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "^3.4.7",
|
||||
"html-minifier": "^3.2.3",
|
||||
"loader-utils": "^0.2.16",
|
||||
"lodash": "^4.17.3",
|
||||
"pretty-error": "^2.0.2",
|
||||
"toposort": "^1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"webpack": "1 || ^2 || ^2.1.0-beta || ^2.2.0-rc || ^3"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user