chushihua
This commit is contained in:
+37
@@ -0,0 +1,37 @@
|
||||
<a name="2.3.0"></a>
|
||||
# [2.3.0](https://github.com/michael-ciniawsky/postcss-load-plugins/compare/v2.2.0...v2.3.0) (2017-02-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **index:** Allow extensions for .postcssrc ([65cc0d0](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/65cc0d0))
|
||||
|
||||
|
||||
|
||||
<a name="2.2.0"></a>
|
||||
# 2.2.0 (2017-01-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **index:** expose config file ([c643172](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/c643172))
|
||||
* **index:** improve error handling ([f3a4048](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/f3a4048))
|
||||
* **lib:** improve error handling ([a64bb03](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/a64bb03))
|
||||
|
||||
|
||||
|
||||
<a name="2.1.0"></a>
|
||||
# 2.1.0 (2016-12-05)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **index:** set NODE_ENV if undefined ([920f806](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/920f806))
|
||||
* **index:** support node v0.12 ([e31fab3](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/e31fab3))
|
||||
* **lib/plugins:** support node v0.12 ([c440e6b](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/c440e6b))
|
||||
* **loadPlugins:** add object-assign polyfill ([acd3f84](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/acd3f84))
|
||||
* **plugins:** check for plugin.default ([024e8c7](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/024e8c7))
|
||||
|
||||
### Features
|
||||
|
||||
* function support, jsdoc, cleanups ([f637d60](https://github.com/michael-ciniawsky/postcss-load-plugins/commit/f637d60))
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
License (MIT)
|
||||
|
||||
Copyright (c) Michael Ciniawsky <michael.ciniawsky@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
[![npm][npm]][npm-url]
|
||||
[![node][node]][node-url]
|
||||
[![deps][deps]][deps-url]
|
||||
[![tests][tests]][tests-url]
|
||||
[![coverage][cover]][cover-url]
|
||||
[![code style][style]][style-url]
|
||||
[![chat][chat]][chat-url]
|
||||
|
||||
<div align="center">
|
||||
<img width="100" height="100" title="Load Plugins" src="http://michael-ciniawsky.github.io/postcss-load-plugins/logo.svg">
|
||||
<a href="https://github.com/postcss/postcss">
|
||||
<img width="110" height="110" title="PostCSS" src="http://postcss.github.io/postcss/logo.svg" hspace="10">
|
||||
</a>
|
||||
<h1>Load Plugins</h1>
|
||||
</div>
|
||||
|
||||
<h2 align="center">Install</h2>
|
||||
|
||||
```bash
|
||||
npm i -D postcss-load-plugins
|
||||
```
|
||||
|
||||
<h2 align="center">Usage</h2>
|
||||
|
||||
```
|
||||
npm i -S|-D postcss-plugin
|
||||
```
|
||||
|
||||
Install plugins and save them to your ***package.json*** dependencies/devDependencies.
|
||||
|
||||
### `package.json`
|
||||
|
||||
Create **`postcss`** section in your projects **`package.json`**.
|
||||
|
||||
```
|
||||
App
|
||||
|– client
|
||||
|– public
|
||||
|
|
||||
|- package.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"postcss-plugin": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `.postcssrc`
|
||||
|
||||
Create a **`.postcssrc`** file.
|
||||
|
||||
```
|
||||
App
|
||||
|– client
|
||||
|– public
|
||||
|
|
||||
|- (.postcssrc|.postcssrc.json|.postcssrc.yaml)
|
||||
|- package.json
|
||||
```
|
||||
|
||||
**`JSON`**
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"postcss-plugin": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`YAML`**
|
||||
```yaml
|
||||
plugins:
|
||||
postcss-plugin: {}
|
||||
```
|
||||
|
||||
### `postcss.config.js` or `.postcssrc.js`
|
||||
|
||||
You may need some JavaScript logic to generate your config. For this case you can use a file named **`postcss.config.js`** or **`.postcssrc.js`**.
|
||||
|
||||
```
|
||||
App
|
||||
|– client
|
||||
|– public
|
||||
|
|
||||
|- (postcss.config.js|.postcssrc.js)
|
||||
|- package.json
|
||||
```
|
||||
|
||||
Plugins can be loaded in either using an `{Object}` or an `{Array}`.
|
||||
|
||||
##### `{Object}`
|
||||
|
||||
```js
|
||||
module.exports = (ctx) => ({
|
||||
plugins: {
|
||||
'postcss-plugin': ctx.plugin
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### `{Array}`
|
||||
|
||||
```js
|
||||
module.exports = (ctx) => ({
|
||||
plugins: [
|
||||
require('postcss-plugin')(ctx.plugin)
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
<h2 align="center">Options</h2>
|
||||
|
||||
Plugin **options** can take the following values.
|
||||
|
||||
**`{}`: Plugin loads with defaults**
|
||||
|
||||
```js
|
||||
'postcss-plugin': {} || null
|
||||
```
|
||||
|
||||
> :warning: `{}` must be an **empty** object
|
||||
|
||||
**`{Object}`: Plugin loads with options**
|
||||
|
||||
```js
|
||||
'postcss-plugin': { option: '', option: '' }
|
||||
```
|
||||
|
||||
**`false`: Plugin will not be loaded**
|
||||
|
||||
```js
|
||||
'postcss-plugin': false
|
||||
```
|
||||
|
||||
### Order
|
||||
|
||||
Plugin **order** is determined by declaration in the plugins section.
|
||||
|
||||
```js
|
||||
{
|
||||
plugins: {
|
||||
'postcss-plugin': {}, // plugins[0]
|
||||
'postcss-plugin': {}, // plugins[1]
|
||||
'postcss-plugin': {} // plugins[2]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Context
|
||||
|
||||
When using a function `(postcss.config.js)`, it is possible to pass context to `postcss-load-plugins`, which will be evaluated before loading your plugins. By default `ctx.env (process.env.NODE_ENV)` and `ctx.cwd (process.cwd())` are available.
|
||||
|
||||
<h2 align="center">Examples</h2>
|
||||
|
||||
**`postcss.config.js`**
|
||||
|
||||
```js
|
||||
module.exports = (ctx) => ({
|
||||
plugins: {
|
||||
postcss-import: {},
|
||||
postcss-modules: ctx.modules ? {} : false,
|
||||
cssnano: ctx.env === 'production' ? {} : false
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### <img width="80" height="80" src="https://worldvectorlogo.com/logos/nodejs-icon.svg">
|
||||
|
||||
```js
|
||||
const { readFileSync } = require('fs')
|
||||
|
||||
const postcss = require('postcss')
|
||||
const pluginsrc = require('postcss-load-plugins')
|
||||
|
||||
const css = readFileSync('index.css', 'utf8')
|
||||
|
||||
const ctx = { modules: true }
|
||||
|
||||
pluginsrc(ctx).then((plugins) => {
|
||||
postcss(plugins)
|
||||
.process(css)
|
||||
.then((result) => console.log(result.css))
|
||||
})
|
||||
```
|
||||
|
||||
<h2 align="center">Maintainers</h2>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img width="150" height="150"
|
||||
src="https://github.com/michael-ciniawsky.png?v=3&s=150">
|
||||
<br>
|
||||
<a href="https://github.com/michael-ciniawsky">Michael Ciniawsky</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img width="150" height="150"
|
||||
src="https://github.com/ertrzyiks.png?v=3&s=150">
|
||||
<br>
|
||||
<a href="https://github.com/ertrzyiks">Mateusz Derks</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 align="center">Contributors</h2>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img width="150" height="150"
|
||||
src="https://github.com/Kovensky.png?v=3&s=150">
|
||||
<br>
|
||||
<a href="https://github.com/Kovensky">Diogo Franco</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
[npm]: https://img.shields.io/npm/v/postcss-load-plugins.svg
|
||||
[npm-url]: https://npmjs.com/package/postcss-load-plugins
|
||||
|
||||
[node]: https://img.shields.io/node/v/postcss-load-plugins.svg
|
||||
[node-url]: https://nodejs.org/
|
||||
|
||||
[deps]: https://david-dm.org/michael-ciniawsky/postcss-load-plugins.svg
|
||||
[deps-url]: https://david-dm.org/michael-ciniawsky/postcss-load-plugins
|
||||
|
||||
[tests]: http://img.shields.io/travis/michael-ciniawsky/postcss-load-plugins.svg
|
||||
[tests-url]: https://travis-ci.org/michael-ciniawsky/postcss-load-plugins
|
||||
|
||||
[cover]: https://coveralls.io/repos/github/michael-ciniawsky/postcss-load-plugins/badge.svg
|
||||
[cover-url]: https://coveralls.io/github/michael-ciniawsky/postcss-load-plugins
|
||||
|
||||
[style]: https://img.shields.io/badge/code%20style-standard-yellow.svg
|
||||
[style-url]: http://standardjs.com/
|
||||
|
||||
[chat]: https://img.shields.io/gitter/room/postcss/postcss.svg
|
||||
[chat-url]: https://gitter.im/postcss/postcss
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
// ------------------------------------
|
||||
// # POSTCSS - LOAD PLUGINS - INDEX
|
||||
// ------------------------------------
|
||||
|
||||
'use strict'
|
||||
|
||||
var resolve = require('path').resolve
|
||||
|
||||
var config = require('cosmiconfig')
|
||||
var assign = require('object-assign')
|
||||
|
||||
var loadPlugins = require('./lib/plugins')
|
||||
|
||||
/**
|
||||
* Autoload Plugins for PostCSS
|
||||
*
|
||||
* @author Michael Ciniawsky (@michael-ciniawsky) <michael.ciniawsky@gmail.com>
|
||||
* @license MIT
|
||||
*
|
||||
* @module postcss-load-plugins
|
||||
* @version 2.3.0
|
||||
*
|
||||
* @requires cosmiconfig
|
||||
* @requires object-assign
|
||||
* @requires ./lib/plugins.js
|
||||
*
|
||||
* @method pluginsrc
|
||||
*
|
||||
* @param {Object} ctx Context
|
||||
* @param {String} path Directory
|
||||
* @param {Object} options Options
|
||||
*
|
||||
* @return {Array} config PostCSS Plugins
|
||||
*/
|
||||
module.exports = function pluginsrc (ctx, path, options) {
|
||||
ctx = assign({ cwd: process.cwd(), env: process.env.NODE_ENV }, ctx)
|
||||
|
||||
path = path ? resolve(path) : process.cwd()
|
||||
|
||||
options = assign({ rcExtensions: true }, options)
|
||||
|
||||
if (!ctx.env) process.env.NODE_ENV = 'development'
|
||||
|
||||
var file
|
||||
|
||||
return config('postcss', options)
|
||||
.load(path)
|
||||
.then(function (result) {
|
||||
if (!result) throw new Error('No PostCSS Config found in: ' + path)
|
||||
|
||||
file = result ? result.filepath : ''
|
||||
|
||||
return result ? result.config : {}
|
||||
})
|
||||
.then(function (plugins) {
|
||||
if (typeof plugins === 'function') plugins = plugins(ctx)
|
||||
else plugins = assign(plugins, ctx)
|
||||
|
||||
if (!plugins.plugins) plugins.plugins = []
|
||||
|
||||
return { plugins: loadPlugins(plugins), file: file }
|
||||
})
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
// ------------------------------------
|
||||
// # POSTCSS - LOAD PLUGINS - PLUGINS
|
||||
// ------------------------------------
|
||||
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @method plugins
|
||||
*
|
||||
* @param {Object} config PostCSS Config
|
||||
*
|
||||
* @return {Array} plugins PostCSS Plugins
|
||||
*/
|
||||
module.exports = function plugins (config) {
|
||||
var plugins = []
|
||||
|
||||
if (Array.isArray(config.plugins)) {
|
||||
plugins = config.plugins.filter(Boolean)
|
||||
|
||||
if (plugins.length && plugins.length > 0) {
|
||||
plugins.forEach(function (plugin, i) {
|
||||
if (!plugin) throw new Error('Loading PostCSS Plugin failed')
|
||||
|
||||
if (plugin.postcss) plugin = plugin.postcss
|
||||
|
||||
if (plugin.default) plugin = plugin.default
|
||||
|
||||
if (
|
||||
!(typeof plugin === 'object' && Array.isArray(plugin.plugins) ||
|
||||
typeof plugin === 'function')
|
||||
) {
|
||||
throw new TypeError('Invalid PostCSS Plugin found: ' + '[' + i + ']')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return plugins
|
||||
} else {
|
||||
config = config.plugins
|
||||
|
||||
var load = function (plugin, options) {
|
||||
if (options === null || Object.keys(options).length === 0) {
|
||||
try {
|
||||
return require(plugin)
|
||||
} catch (err) {
|
||||
err.message = 'Loading PostCSS Plugin failed: ' + err.message
|
||||
|
||||
throw err
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return require(plugin)(options)
|
||||
} catch (err) {
|
||||
err.message = 'Loading PostCSS Plugin failed: ' + err.message
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.keys(config)
|
||||
.filter(function (plugin) {
|
||||
return config[plugin] !== false ? plugin : ''
|
||||
})
|
||||
.forEach(function (plugin, i) {
|
||||
plugin = load(plugin, config[plugin])
|
||||
|
||||
if (plugin.postcss) plugin = plugin.postcss
|
||||
|
||||
if (plugin.default) plugin = plugin.default
|
||||
|
||||
if (
|
||||
!(typeof plugin === 'object' && Array.isArray(plugin.plugins) ||
|
||||
typeof plugin === 'function')
|
||||
) {
|
||||
throw new TypeError('Invalid PostCSS Plugin found: ' + '[' + i + ']')
|
||||
}
|
||||
|
||||
return plugins.push(plugin)
|
||||
})
|
||||
|
||||
return plugins
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Changelog
|
||||
|
||||
## 2.2.2
|
||||
|
||||
- Fixed: `options.configPath` and `--config` flag are respected.
|
||||
|
||||
## 2.2.0-1
|
||||
|
||||
- 2.2.0 included a number of improvements but somehow broke stylelint. The changes were reverted in 2.2.1, to be restored later.
|
||||
|
||||
## 2.1.3
|
||||
|
||||
- Licensing improvement: switched from `json-parse-helpfulerror` to `parse-json`.
|
||||
|
||||
## 2.1.2
|
||||
|
||||
- Fixed: bug where an `ENOENT` error would be thrown is `searchPath` referenced a non-existent file.
|
||||
- Fixed: JSON parsing errors in Node v7.
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- Fixed: swapped `graceful-fs` for regular `fs`, fixing a garbage collection problem.
|
||||
|
||||
## 2.1.0
|
||||
|
||||
- Added: Node 0.12 support.
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- Fixed: Node version specified in `package.json`.
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- Fixed: no more infinite loop in Windows.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Changed: module now creates cosmiconfig instances with `load` methods (see README).
|
||||
- Added: caching (enabled by the change above).
|
||||
- Removed: support for Node versions <4.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Add `rcExtensions` option.
|
||||
|
||||
## 1.0.2
|
||||
|
||||
- Fix handling of `require()`'s within JS module configs.
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- Switch Promise implementation to pinkie-promise.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- Initial release.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 David Clark
|
||||
|
||||
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.
|
||||
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
# cosmiconfig
|
||||
|
||||
[](https://travis-ci.org/davidtheclark/cosmiconfig) [](https://ci.appveyor.com/project/davidtheclark/cosmiconfig/branch/master)
|
||||
|
||||
Find and load a configuration object from
|
||||
- a `package.json` property (anywhere down the file tree)
|
||||
- a JSON or YAML "rc file" (anywhere down the file tree)
|
||||
- a `.config.js` CommonJS module (anywhere down the file tree)
|
||||
- a CLI `--config` argument
|
||||
|
||||
For example, if your module's name is "soursocks," cosmiconfig will search out configuration in the following places:
|
||||
- a `soursocks` property in `package.json` (anywhere down the file tree)
|
||||
- a `.soursocksrc` file in JSON or YAML format (anywhere down the file tree)
|
||||
- a `soursocks.config.js` file exporting a JS object (anywhere down the file tree)
|
||||
- a CLI `--config` argument
|
||||
|
||||
cosmiconfig continues to search in these places all the way down the file tree until it finds acceptable configuration (or hits the home directory). And it does all this asynchronously, so it shouldn't get in your way.
|
||||
|
||||
Additionally, all of these search locations are configurable: you can customize filenames or turn off any location.
|
||||
|
||||
You can also look for rc files with extensions, e.g. `.soursocksrc.json` or `.soursocksrc.yaml`.
|
||||
You may like extensions on your rc files because you'll get syntax highlighting and linting in text editors.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
npm install cosmiconfig
|
||||
```
|
||||
|
||||
Tested in Node 0.12+.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var cosmiconfig = require('cosmiconfig');
|
||||
|
||||
var explorer = cosmiconfig(yourModuleName[, options]);
|
||||
|
||||
explorer.load(yourSearchPath)
|
||||
.then((result) => {
|
||||
// result.config is the parsed configuration object
|
||||
// result.filepath is the path to the config file that was found
|
||||
})
|
||||
.catch((parsingError) => {
|
||||
// do something constructive
|
||||
});
|
||||
```
|
||||
|
||||
The function `cosmiconfig()` searches for a configuration object and returns a Promise,
|
||||
which resolves with an object containing the information you're looking for.
|
||||
|
||||
So let's say `var yourModuleName = 'goldengrahams'` — here's how cosmiconfig will work:
|
||||
|
||||
- Starting from `process.cwd()` (or some other directory defined by the `searchPath` argument to `load()`), it looks for configuration objects in three places, in this order:
|
||||
1. A `goldengrahams` property in a `package.json` file (or some other property defined by `options.packageProp`);
|
||||
2. A `.goldengrahamsrc` file with JSON or YAML syntax (or some other filename defined by `options.rc`);
|
||||
3. A `goldengrahams.config.js` JS file exporting the object (or some other filename defined by `options.js`).
|
||||
- If none of those searches reveal a configuration object, it moves down one directory and tries again. So the search continues in `./`, `../`, `../../`, `../../../`, etc., checking those three locations in each directory.
|
||||
- It continues searching until it arrives at your home directory (or some other directory defined by `options.stopDir`).
|
||||
- If at any point a parseable configuration is found, the `cosmiconfig()` Promise resolves with its result object.
|
||||
- If no configuration object is found, the `cosmiconfig()` Promise resolves with `null`.
|
||||
- If a configuration object is found *but is malformed* (causing a parsing error), the `cosmiconfig()` Promise rejects and shares that error (so you should `.catch()` it).
|
||||
|
||||
All this searching can be short-circuited by passing `options.configPath` or a `--config` CLI argument to specify a file.
|
||||
cosmiconfig will read that file and try parsing it as JSON, YAML, or JS.
|
||||
|
||||
## Caching
|
||||
|
||||
As of v2, cosmiconfig uses a few caches to reduce the need for repetitious reading of the filesystem. Every new cosmiconfig instance (created with `cosmiconfig()`) has its own caches.
|
||||
|
||||
To avoid or work around caching, you can
|
||||
- create separate instances of cosmiconfig, or
|
||||
- set `cache: false` in your options.
|
||||
- use the cache clearing methods documented below.
|
||||
|
||||
## API
|
||||
|
||||
### `var explorer = cosmiconfig(moduleName[, options])`
|
||||
|
||||
Creates a cosmiconfig instance (i.e. explorer) configured according to the arguments, and initializes its caches.
|
||||
|
||||
#### moduleName
|
||||
|
||||
Type: `string`
|
||||
|
||||
You module name. This is used to create the default filenames that cosmiconfig will look for.
|
||||
|
||||
#### Options
|
||||
|
||||
##### packageProp
|
||||
|
||||
Type: `string` or `false`
|
||||
Default: `'[moduleName]'`
|
||||
|
||||
Name of the property in `package.json` to look for.
|
||||
|
||||
If `false`, cosmiconfig will not look in `package.json` files.
|
||||
|
||||
##### rc
|
||||
|
||||
Type: `string` or `false`
|
||||
Default: `'.[moduleName]rc'`
|
||||
|
||||
Name of the "rc file" to look for, which can be formatted as JSON or YAML.
|
||||
|
||||
If `false`, cosmiconfig will not look for an rc file.
|
||||
|
||||
If `rcExtensions: true`, the rc file can also have extensions that specify the syntax, e.g. `.[moduleName]rc.json`.
|
||||
You may like extensions on your rc files because you'll get syntax highlighting and linting in text editors.
|
||||
Also, with `rcExtensions: true`, you can use JS modules as rc files, e.g. `.[moduleName]rc.js`.
|
||||
|
||||
##### js
|
||||
|
||||
Type: `string` or `false`
|
||||
Default: `'[moduleName].config.js'`
|
||||
|
||||
Name of a JS file to look for, which must export the configuration object.
|
||||
|
||||
If `false`, cosmiconfig will not look for a JS file.
|
||||
|
||||
##### argv
|
||||
|
||||
Type: `string` or `false`
|
||||
Default: `'config'`
|
||||
|
||||
Name of a `process.argv` argument to look for, whose value should be the path to a configuration file.
|
||||
cosmiconfig will read the file and try to parse it as JSON, YAML, or JS.
|
||||
By default, cosmiconfig looks for `--config`.
|
||||
|
||||
If `false`, cosmiconfig will not look for any `process.argv` arguments.
|
||||
|
||||
##### rcStrictJson
|
||||
|
||||
Type: `boolean`
|
||||
Default: `false`
|
||||
|
||||
If `true`, cosmiconfig will expect rc files to be strict JSON. No YAML permitted, and no sloppy JSON.
|
||||
|
||||
By default, rc files are parsed with [js-yaml](https://github.com/nodeca/js-yaml), which is
|
||||
more permissive with punctuation than standard strict JSON.
|
||||
|
||||
##### rcExtensions
|
||||
|
||||
Type: `boolean`
|
||||
Default: `false`
|
||||
|
||||
If `true`, cosmiconfig will look for rc files with extensions, in addition to rc files without.
|
||||
|
||||
This adds a few steps to the search process.
|
||||
Instead of *just* looking for `.goldengrahamsrc` (no extension), it will also look for the following, in this order:
|
||||
|
||||
- `.goldengrahamsrc.json`
|
||||
- `.goldengrahamsrc.yaml`
|
||||
- `.goldengrahamsrc.yml`
|
||||
- `.goldengrahamsrc.js`
|
||||
|
||||
##### stopDir
|
||||
|
||||
Type: `string`
|
||||
Default: Absolute path to your home directory
|
||||
|
||||
Directory where the search will stop.
|
||||
|
||||
##### cache
|
||||
|
||||
Type: `boolean`
|
||||
Default: `true`
|
||||
|
||||
If `false`, no caches will be used.
|
||||
|
||||
##### transform
|
||||
|
||||
Type: `Function` returning a Promise
|
||||
|
||||
A function that transforms the parsed configuration. Receives the result object with `config` and `filepath` properties, and must return a Promise that resolves with the transformed result.
|
||||
|
||||
The reason you might use this option instead of simply applying your transform function some other way is that *the transformed result will be cached*. If your transformation involves additional filesystem I/O or other potentially slow processing, you can use this option to avoid repeating those steps every time a given configuration is loaded.
|
||||
|
||||
### Instance methods (on `explorer`)
|
||||
|
||||
#### `load([searchPath, configPath])`
|
||||
|
||||
Find and load a configuration file. Returns a Promise that resolves with `null`, if nothing is found, or an object with two properties:
|
||||
- `config`: The loaded and parsed configuration.
|
||||
- `filepath`: The filepath where this configuration was found.
|
||||
|
||||
You should provide *either* `searchPath` *or* `configPath`. Use `configPath` if you know the path of the configuration file you want to load. Otherwise, use `searchPath`.
|
||||
|
||||
```js
|
||||
explorer.load('start/search/here');
|
||||
explorer.load('start/search/at/this/file.css');
|
||||
|
||||
explorer.load(null, 'load/this/file.json');
|
||||
```
|
||||
|
||||
If you provide `searchPath`, cosmiconfig will start its search at `searchPath` and continue to search up the file tree, as documented above.
|
||||
|
||||
If you provide `configPath` (i.e. you already know where the configuration is that you want to load), cosmiconfig will try to read and parse that file.
|
||||
|
||||
#### `clearFileCache()`
|
||||
|
||||
Clears the cache used when you provide a `configPath` argument to `load`.
|
||||
|
||||
#### `clearDirectoryCache()`
|
||||
|
||||
Clears the cache used when you provide a `searchPath` argument to `load`.
|
||||
|
||||
#### `clearCaches()`
|
||||
|
||||
Performs both `clearFileCache()` and `clearDirectoryCache()`.
|
||||
|
||||
## Differences from [rc](https://github.com/dominictarr/rc)
|
||||
|
||||
[rc](https://github.com/dominictarr/rc) serves its focused purpose well. cosmiconfig differs in a few key ways — making it more useful for some projects, less useful for others:
|
||||
|
||||
- Looks for configuration in some different places: in a `package.json` property, an rc file, a `.config.js` file, and rc files with extensions.
|
||||
- Built-in support for JSON, YAML, and CommonJS formats.
|
||||
- Stops at the first configuration found, instead of finding all that can be found down the filetree and merging them automatically.
|
||||
- Options.
|
||||
- Asynchronicity.
|
||||
|
||||
## Contributing & Development
|
||||
|
||||
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
|
||||
|
||||
And please do participate!
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var oshomedir = require('os-homedir');
|
||||
var minimist = require('minimist');
|
||||
var assign = require('object-assign');
|
||||
var createExplorer = require('./lib/createExplorer');
|
||||
|
||||
var parsedCliArgs = minimist(process.argv);
|
||||
|
||||
module.exports = function (moduleName, options) {
|
||||
options = assign({
|
||||
packageProp: moduleName,
|
||||
rc: '.' + moduleName + 'rc',
|
||||
js: moduleName + '.config.js',
|
||||
argv: 'config',
|
||||
rcStrictJson: false,
|
||||
stopDir: oshomedir(),
|
||||
cache: true,
|
||||
}, options);
|
||||
|
||||
if (options.argv && parsedCliArgs[options.argv]) {
|
||||
options.configPath = path.resolve(parsedCliArgs[options.argv]);
|
||||
}
|
||||
|
||||
return createExplorer(options);
|
||||
};
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var isDir = require('is-directory');
|
||||
var loadPackageProp = require('./loadPackageProp');
|
||||
var loadRc = require('./loadRc');
|
||||
var loadJs = require('./loadJs');
|
||||
var loadDefinedFile = require('./loadDefinedFile');
|
||||
|
||||
module.exports = function (options) {
|
||||
// These cache Promises that resolve with results, not the results themselves
|
||||
var fileCache = (options.cache) ? new Map() : null;
|
||||
var directoryCache = (options.cache) ? new Map() : null;
|
||||
var transform = options.transform || identityPromise;
|
||||
|
||||
function clearFileCache() {
|
||||
if (fileCache) fileCache.clear();
|
||||
}
|
||||
|
||||
function clearDirectoryCache() {
|
||||
if (directoryCache) directoryCache.clear();
|
||||
}
|
||||
|
||||
function clearCaches() {
|
||||
clearFileCache();
|
||||
clearDirectoryCache();
|
||||
}
|
||||
|
||||
function load(searchPath, configPath) {
|
||||
if (!configPath && options.configPath) {
|
||||
configPath = options.configPath;
|
||||
}
|
||||
|
||||
if (configPath) {
|
||||
var absoluteConfigPath = path.resolve(process.cwd(), configPath);
|
||||
if (fileCache && fileCache.has(absoluteConfigPath)) {
|
||||
return fileCache.get(absoluteConfigPath);
|
||||
}
|
||||
var result = loadDefinedFile(absoluteConfigPath, options)
|
||||
.then(transform);
|
||||
if (fileCache) fileCache.set(absoluteConfigPath, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!searchPath) return Promise.resolve(null);
|
||||
|
||||
var absoluteSearchPath = path.resolve(process.cwd(), searchPath);
|
||||
|
||||
return isDirectory(absoluteSearchPath)
|
||||
.then(function (searchPathIsDirectory) {
|
||||
var directory = (searchPathIsDirectory)
|
||||
? absoluteSearchPath
|
||||
: path.dirname(absoluteSearchPath);
|
||||
return searchDirectory(directory);
|
||||
});
|
||||
}
|
||||
|
||||
function searchDirectory(directory) {
|
||||
if (directoryCache && directoryCache.has(directory)) {
|
||||
return directoryCache.get(directory);
|
||||
}
|
||||
|
||||
var result = Promise.resolve()
|
||||
.then(function () {
|
||||
if (!options.packageProp) return;
|
||||
return loadPackageProp(directory, options);
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result || !options.rc) return result;
|
||||
return loadRc(path.join(directory, options.rc), options);
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result || !options.js) return result;
|
||||
return loadJs(path.join(directory, options.js));
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result) return result;
|
||||
|
||||
var splitPath = directory.split(path.sep);
|
||||
var nextDirectory = (splitPath.length > 1)
|
||||
? splitPath.slice(0, -1).join(path.sep)
|
||||
: null;
|
||||
|
||||
if (!nextDirectory || directory === options.stopDir) return null;
|
||||
|
||||
return searchDirectory(nextDirectory);
|
||||
})
|
||||
.then(transform);
|
||||
|
||||
if (directoryCache) directoryCache.set(directory, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
load: load,
|
||||
clearFileCache: clearFileCache,
|
||||
clearDirectoryCache: clearDirectoryCache,
|
||||
clearCaches: clearCaches,
|
||||
};
|
||||
};
|
||||
|
||||
function isDirectory(filepath) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
return isDir(filepath, function (err, dir) {
|
||||
if (err) return reject(err);
|
||||
return resolve(dir);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function identityPromise(x) {
|
||||
return Promise.resolve(x);
|
||||
}
|
||||
Generated
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
'use strict';
|
||||
|
||||
var yaml = require('js-yaml');
|
||||
var requireFromString = require('require-from-string');
|
||||
var readFile = require('./readFile');
|
||||
var parseJson = require('./parseJson');
|
||||
|
||||
module.exports = function (filepath, options) {
|
||||
return readFile(filepath, { throwNotFound: true }).then(function (content) {
|
||||
var parsedConfig = (function () {
|
||||
switch (options.format) {
|
||||
case 'json':
|
||||
return parseJson(content, filepath);
|
||||
case 'yaml':
|
||||
return yaml.safeLoad(content, {
|
||||
filename: filepath,
|
||||
});
|
||||
case 'js':
|
||||
return requireFromString(content, filepath);
|
||||
default:
|
||||
return tryAllParsing(content, filepath);
|
||||
}
|
||||
})();
|
||||
|
||||
if (!parsedConfig) {
|
||||
throw new Error(
|
||||
'Failed to parse "' + filepath + '" as JSON, JS, or YAML.'
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
config: parsedConfig,
|
||||
filepath: filepath,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
function tryAllParsing(content, filepath) {
|
||||
return tryYaml(content, filepath, function () {
|
||||
return tryRequire(content, filepath, function () {
|
||||
return null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function tryYaml(content, filepath, cb) {
|
||||
try {
|
||||
var result = yaml.safeLoad(content, {
|
||||
filename: filepath,
|
||||
});
|
||||
if (typeof result === 'string') {
|
||||
return cb();
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
return cb();
|
||||
}
|
||||
}
|
||||
|
||||
function tryRequire(content, filepath, cb) {
|
||||
try {
|
||||
return requireFromString(content, filepath);
|
||||
} catch (e) {
|
||||
return cb();
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var requireFromString = require('require-from-string');
|
||||
var readFile = require('./readFile');
|
||||
|
||||
module.exports = function (filepath) {
|
||||
return readFile(filepath).then(function (content) {
|
||||
if (!content) return null;
|
||||
|
||||
return {
|
||||
config: requireFromString(content, filepath),
|
||||
filepath: filepath,
|
||||
};
|
||||
});
|
||||
};
|
||||
Generated
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var readFile = require('./readFile');
|
||||
var parseJson = require('./parseJson');
|
||||
|
||||
module.exports = function (packageDir, options) {
|
||||
var packagePath = path.join(packageDir, 'package.json');
|
||||
|
||||
return readFile(packagePath).then(function (content) {
|
||||
if (!content) return null;
|
||||
var parsedContent = parseJson(content, packagePath);
|
||||
var packagePropValue = parsedContent[options.packageProp];
|
||||
if (!packagePropValue) return null;
|
||||
|
||||
return {
|
||||
config: packagePropValue,
|
||||
filepath: packagePath,
|
||||
};
|
||||
});
|
||||
};
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
var yaml = require('js-yaml');
|
||||
var requireFromString = require('require-from-string');
|
||||
var readFile = require('./readFile');
|
||||
var parseJson = require('./parseJson');
|
||||
|
||||
module.exports = function (filepath, options) {
|
||||
return loadExtensionlessRc().then(function (result) {
|
||||
if (result) return result;
|
||||
if (options.rcExtensions) return loadRcWithExtensions();
|
||||
return null;
|
||||
});
|
||||
|
||||
function loadExtensionlessRc() {
|
||||
return readRcFile().then(function (content) {
|
||||
if (!content) return null;
|
||||
|
||||
var pasedConfig = (options.rcStrictJson)
|
||||
? parseJson(content, filepath)
|
||||
: yaml.safeLoad(content, {
|
||||
filename: filepath,
|
||||
});
|
||||
return {
|
||||
config: pasedConfig,
|
||||
filepath: filepath,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function loadRcWithExtensions() {
|
||||
return readRcFile('json').then(function (content) {
|
||||
if (content) {
|
||||
var successFilepath = filepath + '.json';
|
||||
return {
|
||||
config: parseJson(content, successFilepath),
|
||||
filepath: successFilepath,
|
||||
};
|
||||
}
|
||||
// If not content was found in the file with extension,
|
||||
// try the next possible extension
|
||||
return readRcFile('yaml');
|
||||
}).then(function (content) {
|
||||
if (content) {
|
||||
// If the previous check returned an object with a config
|
||||
// property, then it succeeded and this step can be skipped
|
||||
if (content.config) return content;
|
||||
// If it just returned a string, then *this* check succeeded
|
||||
var successFilepath = filepath + '.yaml';
|
||||
return {
|
||||
config: yaml.safeLoad(content, { filename: successFilepath }),
|
||||
filepath: successFilepath,
|
||||
};
|
||||
}
|
||||
return readRcFile('yml');
|
||||
}).then(function (content) {
|
||||
if (content) {
|
||||
if (content.config) return content;
|
||||
var successFilepath = filepath + '.yml';
|
||||
return {
|
||||
config: yaml.safeLoad(content, { filename: successFilepath }),
|
||||
filepath: successFilepath,
|
||||
};
|
||||
}
|
||||
return readRcFile('js');
|
||||
}).then(function (content) {
|
||||
if (content) {
|
||||
if (content.config) return content;
|
||||
var successFilepath = filepath + '.js';
|
||||
return {
|
||||
config: requireFromString(content, successFilepath),
|
||||
filepath: successFilepath,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function readRcFile(extension) {
|
||||
var filepathWithExtension = (extension)
|
||||
? filepath + '.' + extension
|
||||
: filepath;
|
||||
return readFile(filepathWithExtension);
|
||||
}
|
||||
};
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var parseJson = require('parse-json');
|
||||
|
||||
module.exports = function (json, filepath) {
|
||||
try {
|
||||
return parseJson(json);
|
||||
} catch (err) {
|
||||
err.message = 'JSON Error in ' + filepath + ':\n' + err.message;
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = function (filepath, options) {
|
||||
options = options || {};
|
||||
options.throwNotFound = options.throwNotFound || false;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(filepath, 'utf8', function (err, content) {
|
||||
if (err && err.code === 'ENOENT' && !options.throwNotFound) {
|
||||
return resolve(null);
|
||||
}
|
||||
|
||||
if (err) return reject(err);
|
||||
|
||||
resolve(content);
|
||||
});
|
||||
});
|
||||
};
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "cosmiconfig",
|
||||
"version": "2.2.2",
|
||||
"description": "Find and load configuration from a package.json property, rc file, or CommonJS module",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "node-version-gte-4 && eslint . || echo \"ESLint not supported\"",
|
||||
"tape": "tape test/*.test.js | tap-spec",
|
||||
"coverage": "nyc npm run tape && nyc report --reporter=html && open coverage/index.html",
|
||||
"test": "npm run tape && npm run lint"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/davidtheclark/cosmiconfig.git"
|
||||
},
|
||||
"keywords": [
|
||||
"load",
|
||||
"configuration",
|
||||
"config"
|
||||
],
|
||||
"author": "David Clark <david.dave.clark@gmail.com>",
|
||||
"contributors": [
|
||||
"Bogdan Chadkin <trysound@yandex.ru>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/davidtheclark/cosmiconfig/issues"
|
||||
},
|
||||
"homepage": "https://github.com/davidtheclark/cosmiconfig#readme",
|
||||
"dependencies": {
|
||||
"is-directory": "^0.3.1",
|
||||
"js-yaml": "^3.4.3",
|
||||
"minimist": "^1.2.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"os-homedir": "^1.0.1",
|
||||
"parse-json": "^2.2.0",
|
||||
"require-from-string": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^3.13.0",
|
||||
"eslint-config-davidtheclark-node": "^0.2.0",
|
||||
"eslint-plugin-node": "^3.0.5",
|
||||
"expect": "^1.20.2",
|
||||
"lodash": "^4.17.4",
|
||||
"node-version-check": "^2.1.1",
|
||||
"nyc": "^10.0.0",
|
||||
"sinon": "^1.17.7",
|
||||
"tap-spec": "^4.1.1",
|
||||
"tape": "^4.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
'use strict';
|
||||
var errorEx = require('error-ex');
|
||||
var fallback = require('./vendor/parse');
|
||||
|
||||
var JSONError = errorEx('JSONError', {
|
||||
fileName: errorEx.append('in %s')
|
||||
});
|
||||
|
||||
module.exports = function (x, reviver, filename) {
|
||||
if (typeof reviver === 'string') {
|
||||
filename = reviver;
|
||||
reviver = null;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
return JSON.parse(x, reviver);
|
||||
} catch (err) {
|
||||
fallback.parse(x, {
|
||||
mode: 'json',
|
||||
reviver: reviver
|
||||
});
|
||||
|
||||
throw err;
|
||||
}
|
||||
} catch (err) {
|
||||
var jsonErr = new JSONError(err);
|
||||
|
||||
if (filename) {
|
||||
jsonErr.fileName = filename;
|
||||
}
|
||||
|
||||
throw jsonErr;
|
||||
}
|
||||
};
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "parse-json",
|
||||
"version": "2.2.0",
|
||||
"description": "Parse JSON with more helpful errors",
|
||||
"license": "MIT",
|
||||
"repository": "sindresorhus/parse-json",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "sindresorhus.com"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && node test.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"vendor"
|
||||
],
|
||||
"keywords": [
|
||||
"parse",
|
||||
"json",
|
||||
"graceful",
|
||||
"error",
|
||||
"message",
|
||||
"humanize",
|
||||
"friendly",
|
||||
"helpful",
|
||||
"string",
|
||||
"str"
|
||||
],
|
||||
"dependencies": {
|
||||
"error-ex": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "0.0.4",
|
||||
"xo": "*"
|
||||
},
|
||||
"xo": {
|
||||
"ignores": [
|
||||
"vendor/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
# parse-json [](https://travis-ci.org/sindresorhus/parse-json)
|
||||
|
||||
> Parse JSON with more helpful errors
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install --save parse-json
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var parseJson = require('parse-json');
|
||||
var json = '{\n\t"foo": true,\n}';
|
||||
|
||||
|
||||
JSON.parse(json);
|
||||
/*
|
||||
undefined:3
|
||||
}
|
||||
^
|
||||
SyntaxError: Unexpected token }
|
||||
*/
|
||||
|
||||
|
||||
parseJson(json);
|
||||
/*
|
||||
JSONError: Trailing comma in object at 3:1
|
||||
}
|
||||
^
|
||||
*/
|
||||
|
||||
|
||||
parseJson(json, 'foo.json');
|
||||
/*
|
||||
JSONError: Trailing comma in object at 3:1 in foo.json
|
||||
}
|
||||
^
|
||||
*/
|
||||
|
||||
|
||||
// you can also add the filename at a later point
|
||||
try {
|
||||
parseJson(json);
|
||||
} catch (err) {
|
||||
err.fileName = 'foo.json';
|
||||
throw err;
|
||||
}
|
||||
/*
|
||||
JSONError: Trailing comma in object at 3:1 in foo.json
|
||||
}
|
||||
^
|
||||
*/
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### parseJson(input, [reviver], [filename])
|
||||
|
||||
#### input
|
||||
|
||||
Type: `string`
|
||||
|
||||
#### reviver
|
||||
|
||||
Type: `function`
|
||||
|
||||
Prescribes how the value originally produced by parsing is transformed, before being returned. See [`JSON.parse` docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter
|
||||
) for more.
|
||||
|
||||
#### filename
|
||||
|
||||
Type: `string`
|
||||
|
||||
Filename displayed in the error message.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Sindre Sorhus](http://sindresorhus.com)
|
||||
+752
@@ -0,0 +1,752 @@
|
||||
/*
|
||||
* Author: Alex Kocharin <alex@kocharin.ru>
|
||||
* GIT: https://github.com/rlidwka/jju
|
||||
* License: WTFPL, grab your copy here: http://www.wtfpl.net/txt/copying/
|
||||
*/
|
||||
|
||||
// RTFM: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
|
||||
|
||||
var Uni = require('./unicode')
|
||||
|
||||
function isHexDigit(x) {
|
||||
return (x >= '0' && x <= '9')
|
||||
|| (x >= 'A' && x <= 'F')
|
||||
|| (x >= 'a' && x <= 'f')
|
||||
}
|
||||
|
||||
function isOctDigit(x) {
|
||||
return x >= '0' && x <= '7'
|
||||
}
|
||||
|
||||
function isDecDigit(x) {
|
||||
return x >= '0' && x <= '9'
|
||||
}
|
||||
|
||||
var unescapeMap = {
|
||||
'\'': '\'',
|
||||
'"' : '"',
|
||||
'\\': '\\',
|
||||
'b' : '\b',
|
||||
'f' : '\f',
|
||||
'n' : '\n',
|
||||
'r' : '\r',
|
||||
't' : '\t',
|
||||
'v' : '\v',
|
||||
'/' : '/',
|
||||
}
|
||||
|
||||
function formatError(input, msg, position, lineno, column, json5) {
|
||||
var result = msg + ' at ' + (lineno + 1) + ':' + (column + 1)
|
||||
, tmppos = position - column - 1
|
||||
, srcline = ''
|
||||
, underline = ''
|
||||
|
||||
var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
|
||||
|
||||
// output no more than 70 characters before the wrong ones
|
||||
if (tmppos < position - 70) {
|
||||
tmppos = position - 70
|
||||
}
|
||||
|
||||
while (1) {
|
||||
var chr = input[++tmppos]
|
||||
|
||||
if (isLineTerminator(chr) || tmppos === input.length) {
|
||||
if (position >= tmppos) {
|
||||
// ending line error, so show it after the last char
|
||||
underline += '^'
|
||||
}
|
||||
break
|
||||
}
|
||||
srcline += chr
|
||||
|
||||
if (position === tmppos) {
|
||||
underline += '^'
|
||||
} else if (position > tmppos) {
|
||||
underline += input[tmppos] === '\t' ? '\t' : ' '
|
||||
}
|
||||
|
||||
// output no more than 78 characters on the string
|
||||
if (srcline.length > 78) break
|
||||
}
|
||||
|
||||
return result + '\n' + srcline + '\n' + underline
|
||||
}
|
||||
|
||||
function parse(input, options) {
|
||||
// parse as a standard JSON mode
|
||||
var json5 = !(options.mode === 'json' || options.legacy)
|
||||
var isLineTerminator = json5 ? Uni.isLineTerminator : Uni.isLineTerminatorJSON
|
||||
var isWhiteSpace = json5 ? Uni.isWhiteSpace : Uni.isWhiteSpaceJSON
|
||||
|
||||
var length = input.length
|
||||
, lineno = 0
|
||||
, linestart = 0
|
||||
, position = 0
|
||||
, stack = []
|
||||
|
||||
var tokenStart = function() {}
|
||||
var tokenEnd = function(v) {return v}
|
||||
|
||||
/* tokenize({
|
||||
raw: '...',
|
||||
type: 'whitespace'|'comment'|'key'|'literal'|'separator'|'newline',
|
||||
value: 'number'|'string'|'whatever',
|
||||
path: [...],
|
||||
})
|
||||
*/
|
||||
if (options._tokenize) {
|
||||
;(function() {
|
||||
var start = null
|
||||
tokenStart = function() {
|
||||
if (start !== null) throw Error('internal error, token overlap')
|
||||
start = position
|
||||
}
|
||||
|
||||
tokenEnd = function(v, type) {
|
||||
if (start != position) {
|
||||
var hash = {
|
||||
raw: input.substr(start, position-start),
|
||||
type: type,
|
||||
stack: stack.slice(0),
|
||||
}
|
||||
if (v !== undefined) hash.value = v
|
||||
options._tokenize.call(null, hash)
|
||||
}
|
||||
start = null
|
||||
return v
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
var column = position - linestart
|
||||
|
||||
if (!msg) {
|
||||
if (position < length) {
|
||||
var token = '\'' +
|
||||
JSON
|
||||
.stringify(input[position])
|
||||
.replace(/^"|"$/g, '')
|
||||
.replace(/'/g, "\\'")
|
||||
.replace(/\\"/g, '"')
|
||||
+ '\''
|
||||
|
||||
if (!msg) msg = 'Unexpected token ' + token
|
||||
} else {
|
||||
if (!msg) msg = 'Unexpected end of input'
|
||||
}
|
||||
}
|
||||
|
||||
var error = SyntaxError(formatError(input, msg, position, lineno, column, json5))
|
||||
error.row = lineno + 1
|
||||
error.column = column + 1
|
||||
throw error
|
||||
}
|
||||
|
||||
function newline(chr) {
|
||||
// account for <cr><lf>
|
||||
if (chr === '\r' && input[position] === '\n') position++
|
||||
linestart = position
|
||||
lineno++
|
||||
}
|
||||
|
||||
function parseGeneric() {
|
||||
var result
|
||||
|
||||
while (position < length) {
|
||||
tokenStart()
|
||||
var chr = input[position++]
|
||||
|
||||
if (chr === '"' || (chr === '\'' && json5)) {
|
||||
return tokenEnd(parseString(chr), 'literal')
|
||||
|
||||
} else if (chr === '{') {
|
||||
tokenEnd(undefined, 'separator')
|
||||
return parseObject()
|
||||
|
||||
} else if (chr === '[') {
|
||||
tokenEnd(undefined, 'separator')
|
||||
return parseArray()
|
||||
|
||||
} else if (chr === '-'
|
||||
|| chr === '.'
|
||||
|| isDecDigit(chr)
|
||||
// + number Infinity NaN
|
||||
|| (json5 && (chr === '+' || chr === 'I' || chr === 'N'))
|
||||
) {
|
||||
return tokenEnd(parseNumber(), 'literal')
|
||||
|
||||
} else if (chr === 'n') {
|
||||
parseKeyword('null')
|
||||
return tokenEnd(null, 'literal')
|
||||
|
||||
} else if (chr === 't') {
|
||||
parseKeyword('true')
|
||||
return tokenEnd(true, 'literal')
|
||||
|
||||
} else if (chr === 'f') {
|
||||
parseKeyword('false')
|
||||
return tokenEnd(false, 'literal')
|
||||
|
||||
} else {
|
||||
position--
|
||||
return tokenEnd(undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseKey() {
|
||||
var result
|
||||
|
||||
while (position < length) {
|
||||
tokenStart()
|
||||
var chr = input[position++]
|
||||
|
||||
if (chr === '"' || (chr === '\'' && json5)) {
|
||||
return tokenEnd(parseString(chr), 'key')
|
||||
|
||||
} else if (chr === '{') {
|
||||
tokenEnd(undefined, 'separator')
|
||||
return parseObject()
|
||||
|
||||
} else if (chr === '[') {
|
||||
tokenEnd(undefined, 'separator')
|
||||
return parseArray()
|
||||
|
||||
} else if (chr === '.'
|
||||
|| isDecDigit(chr)
|
||||
) {
|
||||
return tokenEnd(parseNumber(true), 'key')
|
||||
|
||||
} else if (json5
|
||||
&& Uni.isIdentifierStart(chr) || (chr === '\\' && input[position] === 'u')) {
|
||||
// unicode char or a unicode sequence
|
||||
var rollback = position - 1
|
||||
var result = parseIdentifier()
|
||||
|
||||
if (result === undefined) {
|
||||
position = rollback
|
||||
return tokenEnd(undefined)
|
||||
} else {
|
||||
return tokenEnd(result, 'key')
|
||||
}
|
||||
|
||||
} else {
|
||||
position--
|
||||
return tokenEnd(undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function skipWhiteSpace() {
|
||||
tokenStart()
|
||||
while (position < length) {
|
||||
var chr = input[position++]
|
||||
|
||||
if (isLineTerminator(chr)) {
|
||||
position--
|
||||
tokenEnd(undefined, 'whitespace')
|
||||
tokenStart()
|
||||
position++
|
||||
newline(chr)
|
||||
tokenEnd(undefined, 'newline')
|
||||
tokenStart()
|
||||
|
||||
} else if (isWhiteSpace(chr)) {
|
||||
// nothing
|
||||
|
||||
} else if (chr === '/'
|
||||
&& json5
|
||||
&& (input[position] === '/' || input[position] === '*')
|
||||
) {
|
||||
position--
|
||||
tokenEnd(undefined, 'whitespace')
|
||||
tokenStart()
|
||||
position++
|
||||
skipComment(input[position++] === '*')
|
||||
tokenEnd(undefined, 'comment')
|
||||
tokenStart()
|
||||
|
||||
} else {
|
||||
position--
|
||||
break
|
||||
}
|
||||
}
|
||||
return tokenEnd(undefined, 'whitespace')
|
||||
}
|
||||
|
||||
function skipComment(multi) {
|
||||
while (position < length) {
|
||||
var chr = input[position++]
|
||||
|
||||
if (isLineTerminator(chr)) {
|
||||
// LineTerminator is an end of singleline comment
|
||||
if (!multi) {
|
||||
// let parent function deal with newline
|
||||
position--
|
||||
return
|
||||
}
|
||||
|
||||
newline(chr)
|
||||
|
||||
} else if (chr === '*' && multi) {
|
||||
// end of multiline comment
|
||||
if (input[position] === '/') {
|
||||
position++
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
if (multi) {
|
||||
fail('Unclosed multiline comment')
|
||||
}
|
||||
}
|
||||
|
||||
function parseKeyword(keyword) {
|
||||
// keyword[0] is not checked because it should've checked earlier
|
||||
var _pos = position
|
||||
var len = keyword.length
|
||||
for (var i=1; i<len; i++) {
|
||||
if (position >= length || keyword[i] != input[position]) {
|
||||
position = _pos-1
|
||||
fail()
|
||||
}
|
||||
position++
|
||||
}
|
||||
}
|
||||
|
||||
function parseObject() {
|
||||
var result = options.null_prototype ? Object.create(null) : {}
|
||||
, empty_object = {}
|
||||
, is_non_empty = false
|
||||
|
||||
while (position < length) {
|
||||
skipWhiteSpace()
|
||||
var item1 = parseKey()
|
||||
skipWhiteSpace()
|
||||
tokenStart()
|
||||
var chr = input[position++]
|
||||
tokenEnd(undefined, 'separator')
|
||||
|
||||
if (chr === '}' && item1 === undefined) {
|
||||
if (!json5 && is_non_empty) {
|
||||
position--
|
||||
fail('Trailing comma in object')
|
||||
}
|
||||
return result
|
||||
|
||||
} else if (chr === ':' && item1 !== undefined) {
|
||||
skipWhiteSpace()
|
||||
stack.push(item1)
|
||||
var item2 = parseGeneric()
|
||||
stack.pop()
|
||||
|
||||
if (item2 === undefined) fail('No value found for key ' + item1)
|
||||
if (typeof(item1) !== 'string') {
|
||||
if (!json5 || typeof(item1) !== 'number') {
|
||||
fail('Wrong key type: ' + item1)
|
||||
}
|
||||
}
|
||||
|
||||
if ((item1 in empty_object || empty_object[item1] != null) && options.reserved_keys !== 'replace') {
|
||||
if (options.reserved_keys === 'throw') {
|
||||
fail('Reserved key: ' + item1)
|
||||
} else {
|
||||
// silently ignore it
|
||||
}
|
||||
} else {
|
||||
if (typeof(options.reviver) === 'function') {
|
||||
item2 = options.reviver.call(null, item1, item2)
|
||||
}
|
||||
|
||||
if (item2 !== undefined) {
|
||||
is_non_empty = true
|
||||
Object.defineProperty(result, item1, {
|
||||
value: item2,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
skipWhiteSpace()
|
||||
|
||||
tokenStart()
|
||||
var chr = input[position++]
|
||||
tokenEnd(undefined, 'separator')
|
||||
|
||||
if (chr === ',') {
|
||||
continue
|
||||
|
||||
} else if (chr === '}') {
|
||||
return result
|
||||
|
||||
} else {
|
||||
fail()
|
||||
}
|
||||
|
||||
} else {
|
||||
position--
|
||||
fail()
|
||||
}
|
||||
}
|
||||
|
||||
fail()
|
||||
}
|
||||
|
||||
function parseArray() {
|
||||
var result = []
|
||||
|
||||
while (position < length) {
|
||||
skipWhiteSpace()
|
||||
stack.push(result.length)
|
||||
var item = parseGeneric()
|
||||
stack.pop()
|
||||
skipWhiteSpace()
|
||||
tokenStart()
|
||||
var chr = input[position++]
|
||||
tokenEnd(undefined, 'separator')
|
||||
|
||||
if (item !== undefined) {
|
||||
if (typeof(options.reviver) === 'function') {
|
||||
item = options.reviver.call(null, String(result.length), item)
|
||||
}
|
||||
if (item === undefined) {
|
||||
result.length++
|
||||
item = true // hack for check below, not included into result
|
||||
} else {
|
||||
result.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
if (chr === ',') {
|
||||
if (item === undefined) {
|
||||
fail('Elisions are not supported')
|
||||
}
|
||||
|
||||
} else if (chr === ']') {
|
||||
if (!json5 && item === undefined && result.length) {
|
||||
position--
|
||||
fail('Trailing comma in array')
|
||||
}
|
||||
return result
|
||||
|
||||
} else {
|
||||
position--
|
||||
fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseNumber() {
|
||||
// rewind because we don't know first char
|
||||
position--
|
||||
|
||||
var start = position
|
||||
, chr = input[position++]
|
||||
, t
|
||||
|
||||
var to_num = function(is_octal) {
|
||||
var str = input.substr(start, position - start)
|
||||
|
||||
if (is_octal) {
|
||||
var result = parseInt(str.replace(/^0o?/, ''), 8)
|
||||
} else {
|
||||
var result = Number(str)
|
||||
}
|
||||
|
||||
if (Number.isNaN(result)) {
|
||||
position--
|
||||
fail('Bad numeric literal - "' + input.substr(start, position - start + 1) + '"')
|
||||
} else if (!json5 && !str.match(/^-?(0|[1-9][0-9]*)(\.[0-9]+)?(e[+-]?[0-9]+)?$/i)) {
|
||||
// additional restrictions imposed by json
|
||||
position--
|
||||
fail('Non-json numeric literal - "' + input.substr(start, position - start + 1) + '"')
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// ex: -5982475.249875e+29384
|
||||
// ^ skipping this
|
||||
if (chr === '-' || (chr === '+' && json5)) chr = input[position++]
|
||||
|
||||
if (chr === 'N' && json5) {
|
||||
parseKeyword('NaN')
|
||||
return NaN
|
||||
}
|
||||
|
||||
if (chr === 'I' && json5) {
|
||||
parseKeyword('Infinity')
|
||||
|
||||
// returning +inf or -inf
|
||||
return to_num()
|
||||
}
|
||||
|
||||
if (chr >= '1' && chr <= '9') {
|
||||
// ex: -5982475.249875e+29384
|
||||
// ^^^ skipping these
|
||||
while (position < length && isDecDigit(input[position])) position++
|
||||
chr = input[position++]
|
||||
}
|
||||
|
||||
// special case for leading zero: 0.123456
|
||||
if (chr === '0') {
|
||||
chr = input[position++]
|
||||
|
||||
// new syntax, "0o777" old syntax, "0777"
|
||||
var is_octal = chr === 'o' || chr === 'O' || isOctDigit(chr)
|
||||
var is_hex = chr === 'x' || chr === 'X'
|
||||
|
||||
if (json5 && (is_octal || is_hex)) {
|
||||
while (position < length
|
||||
&& (is_hex ? isHexDigit : isOctDigit)( input[position] )
|
||||
) position++
|
||||
|
||||
var sign = 1
|
||||
if (input[start] === '-') {
|
||||
sign = -1
|
||||
start++
|
||||
} else if (input[start] === '+') {
|
||||
start++
|
||||
}
|
||||
|
||||
return sign * to_num(is_octal)
|
||||
}
|
||||
}
|
||||
|
||||
if (chr === '.') {
|
||||
// ex: -5982475.249875e+29384
|
||||
// ^^^ skipping these
|
||||
while (position < length && isDecDigit(input[position])) position++
|
||||
chr = input[position++]
|
||||
}
|
||||
|
||||
if (chr === 'e' || chr === 'E') {
|
||||
chr = input[position++]
|
||||
if (chr === '-' || chr === '+') position++
|
||||
// ex: -5982475.249875e+29384
|
||||
// ^^^ skipping these
|
||||
while (position < length && isDecDigit(input[position])) position++
|
||||
chr = input[position++]
|
||||
}
|
||||
|
||||
// we have char in the buffer, so count for it
|
||||
position--
|
||||
return to_num()
|
||||
}
|
||||
|
||||
function parseIdentifier() {
|
||||
// rewind because we don't know first char
|
||||
position--
|
||||
|
||||
var result = ''
|
||||
|
||||
while (position < length) {
|
||||
var chr = input[position++]
|
||||
|
||||
if (chr === '\\'
|
||||
&& input[position] === 'u'
|
||||
&& isHexDigit(input[position+1])
|
||||
&& isHexDigit(input[position+2])
|
||||
&& isHexDigit(input[position+3])
|
||||
&& isHexDigit(input[position+4])
|
||||
) {
|
||||
// UnicodeEscapeSequence
|
||||
chr = String.fromCharCode(parseInt(input.substr(position+1, 4), 16))
|
||||
position += 5
|
||||
}
|
||||
|
||||
if (result.length) {
|
||||
// identifier started
|
||||
if (Uni.isIdentifierPart(chr)) {
|
||||
result += chr
|
||||
} else {
|
||||
position--
|
||||
return result
|
||||
}
|
||||
|
||||
} else {
|
||||
if (Uni.isIdentifierStart(chr)) {
|
||||
result += chr
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail()
|
||||
}
|
||||
|
||||
function parseString(endChar) {
|
||||
// 7.8.4 of ES262 spec
|
||||
var result = ''
|
||||
|
||||
while (position < length) {
|
||||
var chr = input[position++]
|
||||
|
||||
if (chr === endChar) {
|
||||
return result
|
||||
|
||||
} else if (chr === '\\') {
|
||||
if (position >= length) fail()
|
||||
chr = input[position++]
|
||||
|
||||
if (unescapeMap[chr] && (json5 || (chr != 'v' && chr != "'"))) {
|
||||
result += unescapeMap[chr]
|
||||
|
||||
} else if (json5 && isLineTerminator(chr)) {
|
||||
// line continuation
|
||||
newline(chr)
|
||||
|
||||
} else if (chr === 'u' || (chr === 'x' && json5)) {
|
||||
// unicode/character escape sequence
|
||||
var off = chr === 'u' ? 4 : 2
|
||||
|
||||
// validation for \uXXXX
|
||||
for (var i=0; i<off; i++) {
|
||||
if (position >= length) fail()
|
||||
if (!isHexDigit(input[position])) fail('Bad escape sequence')
|
||||
position++
|
||||
}
|
||||
|
||||
result += String.fromCharCode(parseInt(input.substr(position-off, off), 16))
|
||||
} else if (json5 && isOctDigit(chr)) {
|
||||
if (chr < '4' && isOctDigit(input[position]) && isOctDigit(input[position+1])) {
|
||||
// three-digit octal
|
||||
var digits = 3
|
||||
} else if (isOctDigit(input[position])) {
|
||||
// two-digit octal
|
||||
var digits = 2
|
||||
} else {
|
||||
var digits = 1
|
||||
}
|
||||
position += digits - 1
|
||||
result += String.fromCharCode(parseInt(input.substr(position-digits, digits), 8))
|
||||
/*if (!isOctDigit(input[position])) {
|
||||
// \0 is allowed still
|
||||
result += '\0'
|
||||
} else {
|
||||
fail('Octal literals are not supported')
|
||||
}*/
|
||||
|
||||
} else if (json5) {
|
||||
// \X -> x
|
||||
result += chr
|
||||
|
||||
} else {
|
||||
position--
|
||||
fail()
|
||||
}
|
||||
|
||||
} else if (isLineTerminator(chr)) {
|
||||
fail()
|
||||
|
||||
} else {
|
||||
if (!json5 && chr.charCodeAt(0) < 32) {
|
||||
position--
|
||||
fail('Unexpected control character')
|
||||
}
|
||||
|
||||
// SourceCharacter but not one of " or \ or LineTerminator
|
||||
result += chr
|
||||
}
|
||||
}
|
||||
|
||||
fail()
|
||||
}
|
||||
|
||||
skipWhiteSpace()
|
||||
var return_value = parseGeneric()
|
||||
if (return_value !== undefined || position < length) {
|
||||
skipWhiteSpace()
|
||||
|
||||
if (position >= length) {
|
||||
if (typeof(options.reviver) === 'function') {
|
||||
return_value = options.reviver.call(null, '', return_value)
|
||||
}
|
||||
return return_value
|
||||
} else {
|
||||
fail()
|
||||
}
|
||||
|
||||
} else {
|
||||
if (position) {
|
||||
fail('No data, only a whitespace')
|
||||
} else {
|
||||
fail('No data, empty input')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* parse(text, options)
|
||||
* or
|
||||
* parse(text, reviver)
|
||||
*
|
||||
* where:
|
||||
* text - string
|
||||
* options - object
|
||||
* reviver - function
|
||||
*/
|
||||
module.exports.parse = function parseJSON(input, options) {
|
||||
// support legacy functions
|
||||
if (typeof(options) === 'function') {
|
||||
options = {
|
||||
reviver: options
|
||||
}
|
||||
}
|
||||
|
||||
if (input === undefined) {
|
||||
// parse(stringify(x)) should be equal x
|
||||
// with JSON functions it is not 'cause of undefined
|
||||
// so we're fixing it
|
||||
return undefined
|
||||
}
|
||||
|
||||
// JSON.parse compat
|
||||
if (typeof(input) !== 'string') input = String(input)
|
||||
if (options == null) options = {}
|
||||
if (options.reserved_keys == null) options.reserved_keys = 'ignore'
|
||||
|
||||
if (options.reserved_keys === 'throw' || options.reserved_keys === 'ignore') {
|
||||
if (options.null_prototype == null) {
|
||||
options.null_prototype = true
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return parse(input, options)
|
||||
} catch(err) {
|
||||
// jju is a recursive parser, so JSON.parse("{{{{{{{") could blow up the stack
|
||||
//
|
||||
// this catch is used to skip all those internal calls
|
||||
if (err instanceof SyntaxError && err.row != null && err.column != null) {
|
||||
var old_err = err
|
||||
err = SyntaxError(old_err.message)
|
||||
err.column = old_err.column
|
||||
err.row = old_err.row
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.tokenize = function tokenizeJSON(input, options) {
|
||||
if (options == null) options = {}
|
||||
|
||||
options._tokenize = function(smth) {
|
||||
if (options._addstack) smth.stack.unshift.apply(smth.stack, options._addstack)
|
||||
tokens.push(smth)
|
||||
}
|
||||
|
||||
var tokens = []
|
||||
tokens.data = module.exports.parse(input, options)
|
||||
return tokens
|
||||
}
|
||||
|
||||
+71
File diff suppressed because one or more lines are too long
+65
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "postcss-load-plugins",
|
||||
"version": "2.3.0",
|
||||
"description": "Autoload Plugins for PostCSS",
|
||||
"engines": { "node": ">=0.12" },
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"lint": "standard",
|
||||
"test": "nyc ava -v test/err/index.js test/rc/index.js test/pkg/index.js test/js/**/index.js",
|
||||
"logs": "standard-changelog -i CHANGELOG.md -w",
|
||||
"docs": "jsdoc2md index.js lib/plugins.js > INDEX.md",
|
||||
"clean": "rm -rf .nyc_output coverage jsdoc-api dmd",
|
||||
"start": "sudo npm run clean && npm run lint && sudo npm test"
|
||||
},
|
||||
"dependencies": {
|
||||
"cosmiconfig": "^2.1.1",
|
||||
"object-assign": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^0.18.1",
|
||||
"coveralls": "^2.11.16",
|
||||
"cssnano": "^3.10.0",
|
||||
"jsdoc-to-markdown": "^3.0.0",
|
||||
"nyc": "^10.1.0",
|
||||
"postcss": "^5.2.12",
|
||||
"postcss-cssnext": "^2.8.0",
|
||||
"postcss-import": "^9.1.0",
|
||||
"postcss-nested": "^1.0.0",
|
||||
"postcss-sprites": "^4.2.0",
|
||||
"standard": "^8.6.0",
|
||||
"standard-changelog": "0.0.1",
|
||||
"sugarss": "^0.2.0"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"index.js"
|
||||
],
|
||||
"keywords": [
|
||||
"postcss",
|
||||
"postcss-plugin"
|
||||
],
|
||||
"author": {
|
||||
"name": "Michael Ciniawky",
|
||||
"email": "michael.ciniawsky@gmail.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Mateusz Derks",
|
||||
"url": "http://ertrzyiks.me"
|
||||
},
|
||||
{
|
||||
"name": "Diogo Franco",
|
||||
"email": "diogomfranco@gmail.com"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/michael-ciniawsky/postcss-load-plugins.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/michael-ciniawsky/postcss-load-plugins/issues"
|
||||
},
|
||||
"homepage": "https://github.com/michael-ciniawsky/postcss-load-plugins#readme",
|
||||
"license": "MIT"
|
||||
}
|
||||
Reference in New Issue
Block a user