node_modules

This commit is contained in:
saeid
2019-07-15 13:07:31 +04:30
parent d3735c6d30
commit ce1a3ebf9c
35713 changed files with 3639219 additions and 1 deletions
+7
View File
@@ -0,0 +1,7 @@
Copyright 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.
+94
View File
@@ -0,0 +1,94 @@
# CSS Modules: CSS selector Tokenizer
Parses and stringifies CSS selectors.
``` js
import Tokenizer from "css-selector-tokenizer";
let input = "a#content.active > div::first-line [data-content], a:not(:visited)";
Tokenizer.parse(input); // === expected
let expected = {
type: "selectors",
nodes: [
{
type: "selector",
nodes: [
{ type: "element", name: "a" },
{ type: "id", name: "content" },
{ type: "class", name: "active" },
{ type: "operator", operator: ">", before: " ", after: " " },
{ type: "element", name: "div" },
{ type: "pseudo-element", name: "first-line" },
{ type: "spacing", value: " " },
{ type: "attribute", content: "data-content" },
]
},
{
type: "selector",
nodes: [
{ type: "element", name: "a" },
{ type: "nested-pseudo-class", name: "not", nodes: [
{
type: "selector",
nodes: [
{ type: "pseudo-class", name: "visited" }
]
}
] }
],
before: " "
}
]
}
Tokenizer.stringify(expected) // === input
// * => { type: "universal" }
// foo|element = { type: "element", name: "element", namespace: "foo" }
// *|* = { type: "universal", namespace: "*" }
// :has(h1, h2) => { type: "nested-pseudo-class", name: "has", nodes: [
// {
// type: "selector",
// nodes: [
// { type: "element", name: "h1" }
// ]
// },
// {
// type: "selector",
// nodes: [
// { type: "element", name: "h2" }
// ],
// before: " "
// }
// ] }
```
## Building
```
npm install
npm test
```
[![Build Status](https://travis-ci.org/css-modules/css-selector-tokenizer.svg?branch=master)](https://travis-ci.org/css-modules/css-selector-tokenizer)
* Lines: [![Coverage Status](https://coveralls.io/repos/css-modules/css-selector-tokenizer/badge.svg?branch=master)](https://coveralls.io/r/css-modules/css-selector-tokenizer?branch=master)
* Statements: [![codecov.io](http://codecov.io/github/css-modules/css-selector-tokenizer/coverage.svg?branch=master)](http://codecov.io/github/css-modules/css-selector-tokenizer?branch=master)
## Development
- `npm autotest` will watch `lib` and `test` for changes and retest
## License
MIT
## With thanks
- Mark Dalgleish
- Glen Maddern
- Guy Bedford
---
Tobias Koppers, 2015.
+4
View File
@@ -0,0 +1,4 @@
exports.parse = require("./parse");
exports.stringify = require("./stringify");
exports.parseValues = require("./parseValues");
exports.stringifyValues = require("./stringifyValues");
+239
View File
@@ -0,0 +1,239 @@
"use strict";
var Parser = require("fastparse");
var regexpu = require("regexpu-core");
function unescape(str) {
return str.replace(/\\(.)/g, "$1");
}
function commentMatch(match, content) {
this.selector.nodes.push({
type: "comment",
content: content
});
}
function typeMatch(type) {
return function(match, name) {
this.selector.nodes.push({
type: type,
name: unescape(name)
});
};
}
function pseudoClassStartMatch(match, name) {
var newToken = {
type: "pseudo-class",
name: unescape(name),
content: ""
};
this.selector.nodes.push(newToken);
this.token = newToken;
this.brackets = 1;
return "inBrackets";
}
function nestedPseudoClassStartMatch(match, name, after) {
var newSelector = {
type: "selector",
nodes: []
};
var newToken = {
type: "nested-pseudo-class",
name: unescape(name),
nodes: [newSelector]
};
if(after) {
newSelector.before = after;
}
this.selector.nodes.push(newToken);
this.stack.push(this.root);
this.root = newToken;
this.selector = newSelector;
}
function nestedEnd(match, before) {
if(this.stack.length > 0) {
if(before) {
this.selector.after = before;
}
this.root = this.stack.pop();
this.selector = this.root.nodes[this.root.nodes.length - 1];
} else {
this.selector.nodes.push({
type: "invalid",
value: match
});
}
}
function operatorMatch(match, before, operator, after) {
var token = {
type: "operator",
operator: operator
};
if(before) {
token.before = before;
}
if(after) {
token.after = after;
}
this.selector.nodes.push(token);
}
function spacingMatch(match) {
this.selector.nodes.push({
type: "spacing",
value: match
});
}
function elementMatch(match, namespace, name) {
var newToken = {
type: "element",
name: unescape(name)
};
if(namespace) {
newToken.namespace = unescape(namespace.substr(0, namespace.length - 1));
}
this.selector.nodes.push(newToken);
}
function universalMatch(match, namespace) {
var newToken = {
type: "universal"
};
if(namespace) {
newToken.namespace = unescape(namespace.substr(0, namespace.length - 1));
}
this.selector.nodes.push(newToken);
}
function attributeMatch(match, content) {
this.selector.nodes.push({
type: "attribute",
content: content
});
}
function invalidMatch(match) {
this.selector.nodes.push({
type: "invalid",
value: match
});
}
function irrelevantSpacingStartMatch(match) {
this.selector.before = match;
}
function irrelevantSpacingEndMatch(match) {
this.selector.after = match;
}
function nextSelectorMatch(match, before, after) {
var newSelector = {
type: "selector",
nodes: []
};
if(before) {
this.selector.after = before;
}
if(after) {
newSelector.before = after;
}
this.root.nodes.push(newSelector);
this.selector = newSelector;
}
function addToCurrent(match) {
this.token.content += match;
}
function bracketStart(match) {
this.token.content += match;
this.brackets++;
}
function bracketEnd(match) {
if(--this.brackets === 0) {
return "selector";
}
this.token.content += match;
}
function getSelectors() {
// The assignment here is split to preserve the property enumeration order.
var selectors = {
"/\\*([\\s\\S]*?)\\*/": commentMatch
};
// https://www.w3.org/TR/CSS21/syndata.html#characters
// 4.1.3: identifiers (...) can contain only the characters [a-zA-Z0-9] and
// ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_)
//
// 10ffff is the maximum allowed in current Unicode
selectors[regexpu("\\.((?:\\\\.|[A-Za-z_\\-\\u{00a0}-\\u{10ffff}])(?:\\\\.|[A-Za-z_\\-0-9\\u{00a0}-\\u{10ffff}])*)", "u")] = typeMatch("class");
selectors[regexpu("#((?:\\\\.|[A-Za-z_\\-\\u{00a0}-\\u{10ffff}])(?:\\\\.|[A-Za-z_\\-0-9\\u{00a0}-\\u{10ffff}])*)", "u")] = typeMatch("id");
var selectorsSecondHalf = {
":(not|matches|has|local|global)\\((\\s*)": nestedPseudoClassStartMatch,
":((?:\\\\.|[A-Za-z_\\-0-9])+)\\(": pseudoClassStartMatch,
":((?:\\\\.|[A-Za-z_\\-0-9])+)": typeMatch("pseudo-class"),
"::((?:\\\\.|[A-Za-z_\\-0-9])+)": typeMatch("pseudo-element"),
"(\\*\\|)((?:\\\\.|[A-Za-z_\\-0-9])+)": elementMatch,
"(\\*\\|)\\*": universalMatch,
"((?:\\\\.|[A-Za-z_\\-0-9])*\\|)?\\*": universalMatch,
"((?:\\\\.|[A-Za-z_\\-0-9])*\\|)?((?:\\\\.|[A-Za-z_\\-])(?:\\\\.|[A-Za-z_\\-0-9])*)": elementMatch,
"\\[([^\\]]+)\\]": attributeMatch,
"(\\s*)\\)": nestedEnd,
"(\\s*)((?:\\|\\|)|(?:>>)|[>+~])(\\s*)": operatorMatch,
"(\\s*),(\\s*)": nextSelectorMatch,
"\\s+$": irrelevantSpacingEndMatch,
"^\\s+": irrelevantSpacingStartMatch,
"\\s+": spacingMatch,
".": invalidMatch
};
var selector;
for (selector in selectorsSecondHalf) {
if (Object.prototype.hasOwnProperty.call(selectorsSecondHalf, selector)) {
selectors[selector] = selectorsSecondHalf[selector];
}
}
return selectors;
}
var parser = new Parser({
selector: getSelectors(),
inBrackets: {
"/\\*[\\s\\S]*?\\*/": addToCurrent,
"\"([^\\\\\"]|\\\\.)*\"": addToCurrent,
"'([^\\\\']|\\\\.)*'": addToCurrent,
"[^()'\"/]+": addToCurrent,
"\\(": bracketStart,
"\\)": bracketEnd,
".": addToCurrent
}
});
function parse(str) {
var selectorNode = {
type: "selector",
nodes: []
};
var rootNode = {
type: "selectors",
nodes: [
selectorNode
]
};
parser.parse("selector", str, {
stack: [],
root: rootNode,
selector: selectorNode
});
return rootNode;
}
module.exports = parse;
+167
View File
@@ -0,0 +1,167 @@
"use strict";
var Parser = require("fastparse");
function commentMatch(match, content) {
this.value.nodes.push({
type: "comment",
content: content
});
}
function spacingMatch(match) {
var item = this.value.nodes[this.value.nodes.length - 1];
item.after = (item.after || "") + match;
}
function initialSpacingMatch(match) {
this.value.before = match;
}
function endSpacingMatch(match) {
this.value.after = match;
}
function unescapeString(content) {
return content.replace(/\\(?:([a-fA-F0-9]{1,6})|(.))/g, function(all, unicode, otherCharacter) {
if (otherCharacter) {
return otherCharacter;
}
var C = parseInt(unicode, 16);
if(C < 0x10000) {
return String.fromCharCode(C);
} else {
return String.fromCharCode(Math.floor((C - 0x10000) / 0x400) + 0xD800) +
String.fromCharCode((C - 0x10000) % 0x400 + 0xDC00);
}
});
}
function stringMatch(match, content) {
var value = unescapeString(content);
this.value.nodes.push({
type: "string",
value: value,
stringType: match[0]
});
}
function commaMatch(match, spacing) {
var newValue = {
type: "value",
nodes: []
};
if(spacing) {
newValue.before = spacing;
}
this.root.nodes.push(newValue);
this.value = newValue;
}
function itemMatch(match) {
this.value.nodes.push({
type: "item",
name: match
});
}
function nestedItemMatch(match, name, spacing) {
this.stack.push(this.root);
this.root = {
type: "nested-item",
name: name,
nodes: [
{ type: "value", nodes: [] }
]
};
if(spacing) {
this.root.nodes[0].before = spacing;
}
this.value.nodes.push(this.root);
this.value = this.root.nodes[0];
}
function nestedItemEndMatch(match, spacing, remaining) {
if(this.stack.length === 0) {
if(spacing) {
var item = this.value.nodes[this.value.nodes.length - 1];
item.after = (item.after || "") + spacing;
}
this.value.nodes.push({
type: "invalid",
value: remaining
});
} else {
if(spacing) {
this.value.after = spacing;
}
this.root = this.stack.pop();
this.value = this.root.nodes[this.root.nodes.length - 1];
}
}
function urlMatch(match, innerSpacingBefore, content, innerSpacingAfter) {
var item = {
type: "url"
};
if(innerSpacingBefore) {
item.innerSpacingBefore = innerSpacingBefore;
}
if(innerSpacingAfter) {
item.innerSpacingAfter = innerSpacingAfter;
}
switch(content[0]) {
case "\"":
item.stringType = "\"";
item.url = unescapeString(content.substr(1, content.length - 2));
break;
case "'":
item.stringType = "'";
item.url = unescapeString(content.substr(1, content.length - 2));
break;
default:
item.url = unescapeString(content);
break;
}
this.value.nodes.push(item);
}
var parser = new Parser({
decl: {
"^\\s+": initialSpacingMatch,
"/\\*([\\s\\S]*?)\\*/": commentMatch,
"\"((?:[^\\\\\"]|\\\\.)*)\"": stringMatch,
"'((?:[^\\\\']|\\\\.)*)'": stringMatch,
"url\\((\\s*)(\"(?:[^\\\\\"]|\\\\.)*\")(\\s*)\\)": urlMatch,
"url\\((\\s*)('(?:[^\\\\']|\\\\.)*')(\\s*)\\)": urlMatch,
"url\\((\\s*)((?:[^\\\\)'\"]|\\\\.)*)(\\s*)\\)": urlMatch,
"([\\w\-]+)\\((\\s*)": nestedItemMatch,
"(\\s*)(\\))": nestedItemEndMatch,
",(\\s*)": commaMatch,
"\\s+$": endSpacingMatch,
"\\s+": spacingMatch,
"[^\\s,\)]+": itemMatch
}
});
function parseValues(str) {
var valueNode = {
type: "value",
nodes: []
};
var rootNode = {
type: "values",
nodes: [
valueNode
]
};
parser.parse("decl", str, {
stack: [],
root: rootNode,
value: valueNode
});
return rootNode;
}
module.exports = parseValues;
+67
View File
@@ -0,0 +1,67 @@
"use strict";
var stringify;
var regexpu = require("regexpu-core");
var identifierEscapeRegexp = new RegExp(
regexpu("(^[^A-Za-z_\\-\\u{00a0}-\\u{10ffff}]|^\\-\\-|[^A-Za-z_0-9\\-\\u{00a0}-\\u{10ffff}])", "ug"),
"g"
);
function escape(str, identifier) {
if(str === "*") {
return "*";
}
if (identifier) {
return str.replace(identifierEscapeRegexp, "\\$1");
} else {
return str.replace(/(^[^A-Za-z_\\-]|^\-\-|[^A-Za-z_0-9\\-])/g, "\\$1");
}
}
function stringifyWithoutBeforeAfter(tree) {
switch(tree.type) {
case "selectors":
return tree.nodes.map(stringify).join(",");
case "selector":
return tree.nodes.map(stringify).join("");
case "element":
return (typeof tree.namespace === "string" ? escape(tree.namespace) + "|" : "") + escape(tree.name);
case "class":
return "." + escape(tree.name, true);
case "id":
return "#" + escape(tree.name, true);
case "attribute":
return "[" + tree.content + "]";
case "spacing":
return tree.value;
case "pseudo-class":
return ":" + escape(tree.name) + (typeof tree.content === "string" ? "(" + tree.content + ")" : "");
case "nested-pseudo-class":
return ":" + escape(tree.name) + "(" + tree.nodes.map(stringify).join(",") + ")";
case "pseudo-element":
return "::" + escape(tree.name);
case "universal":
return (typeof tree.namespace === "string" ? escape(tree.namespace) + "|" : "") + "*";
case "operator":
return tree.operator;
case "comment":
return "/*" + tree.content + "*/";
case "invalid":
return tree.value;
}
}
stringify = function stringify(tree) {
var str = stringifyWithoutBeforeAfter(tree);
if(tree.before) {
str = tree.before + str;
}
if(tree.after) {
str = str + tree.after;
}
return str;
};
module.exports = stringify;
+62
View File
@@ -0,0 +1,62 @@
"use strict";
var cssesc = require("cssesc");
var stringify;
function escape(str, stringType) {
return cssesc(str, {
quotes: stringType === "\"" ? "double" : "single"
});
}
function stringifyWithoutBeforeAfter(tree) {
switch(tree.type) {
case "values":
return tree.nodes.map(stringify).join(",");
case "value":
return tree.nodes.map(stringify).join("");
case "item":
return tree.name;
case "nested-item":
return tree.name + "(" + tree.nodes.map(stringify).join(",") + ")";
case "invalid":
return tree.value;
case "comment":
return "/*" + tree.content + "*/";
case "string":
switch(tree.stringType) {
case "'":
return "'" + escape(tree.value, "'") + "'";
case "\"":
return "\"" + escape(tree.value, "\"") + "\"";
}
/* istanbul ignore next */
throw new Error("Invalid stringType");
case "url":
var start = "url(" + (tree.innerSpacingBefore || "");
var end = (tree.innerSpacingAfter || "") + ")";
switch(tree.stringType) {
case "'":
return start + "'" + tree.url.replace(/(\\)/g, "\\$1").replace(/'/g, "\\'") + "'" + end;
case "\"":
return start + "\"" + tree.url.replace(/(\\)/g, "\\$1").replace(/"/g, "\\\"") + "\"" + end;
default:
return start + tree.url.replace(/("|'|\)|\\)/g, "\\$1") + end;
}
}
}
stringify = function stringify(tree) {
var str = stringifyWithoutBeforeAfter(tree);
if(tree.before) {
str = tree.before + str;
}
if(tree.after) {
str = str + tree.after;
}
return str;
};
module.exports = stringify;
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../cssesc/bin/cssesc" "$@"
ret=$?
else
node "$basedir/../cssesc/bin/cssesc" "$@"
ret=$?
fi
exit $ret
+7
View File
@@ -0,0 +1,7 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\cssesc\bin\cssesc" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\cssesc\bin\cssesc" %*
)
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
else
node "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
fi
exit $ret
+7
View File
@@ -0,0 +1,7 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jsesc\bin\jsesc" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jsesc\bin\jsesc" %*
)
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../regjsparser/bin/parser" "$@"
ret=$?
else
node "$basedir/../regjsparser/bin/parser" "$@"
ret=$?
fi
exit $ret
@@ -0,0 +1,7 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\regjsparser\bin\parser" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\regjsparser\bin\parser" %*
)
@@ -0,0 +1,20 @@
Copyright Mathias Bynens <http://mathiasbynens.be/>
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.
+207
View File
@@ -0,0 +1,207 @@
# cssesc [![Build status](https://travis-ci.org/mathiasbynens/cssesc.png?branch=master)](https://travis-ci.org/mathiasbynens/cssesc) [![Dependency status](https://gemnasium.com/mathiasbynens/cssesc.png)](https://gemnasium.com/mathiasbynens/cssesc)
A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output.
This is a JavaScript library for [escaping text for use in CSS strings or identifiers](http://mathiasbynens.be/notes/css-escapes) while generating the shortest possible valid ASCII-only output. [Here’s an online demo.](http://mothereff.in/css-escapes)
Feel free to fork if you see possible improvements!
## Installation
Via [Bower](http://bower.io/):
```bash
bower install cssesc
```
Via [Component](https://github.com/component/component):
```bash
component install mathiasbynens/cssesc
```
Via [npm](http://npmjs.org/):
```bash
npm install cssesc
```
In a browser:
```html
<script src="cssesc.js"></script>
```
In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/):
```js
var cssesc = require('cssesc');
```
In [Narwhal](http://narwhaljs.org/):
```js
var cssesc = require('cssesc').cssesc;
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('cssesc.js');
```
Using an AMD loader like [RequireJS](http://requirejs.org/):
```js
require(
{
'paths': {
'cssesc': 'path/to/cssesc'
}
},
['cssesc'],
function(cssesc) {
console.log(cssesc);
}
);
```
## API
### `cssesc(value, options)`
This function takes a value and returns an escaped version of the value where any characters that are not printable ASCII symbols are escaped using the shortest possible (but valid) [escape sequences for use in CSS strings or identifiers](http://mathiasbynens.be/notes/css-escapes).
```js
cssesc('Ich ♥ Bücher');
// → 'Ich \\2665 B\\FC cher'
cssesc('foo 𝌆 bar');
// → 'foo \\1D306 bar'
```
By default, `cssesc` returns a string that can be used as part of a CSS string. If the target is a CSS identifier rather than a CSS string, use the `isIdentifier: true` setting (see below).
The optional `options` argument accepts an object with the following options:
#### `isIdentifier`
The default value for the `isIdentifier` option is `false`. This means that the input text will be escaped for use in a CSS string literal. If you want to use the result as a CSS identifier instead (in a selector, for example), set this option to `true`.
```js
cssesc('123a2b');
// → '123a2b'
cssesc('123a2b', {
'isIdentifier': true
});
// → '\\31 23a2b'
```
#### `quotes`
The default value for the `quotes` option is `'single'`. This means that any occurences of `'` in the input text will be escaped as `\'`, so that the output can be used in a CSS string literal wrapped in single quotes.
```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.');
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
// → "Lorem ipsum \"dolor\" sit \\'amet\\' etc."
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'single'
});
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
// → "Lorem ipsum \"dolor\" sit \\'amet\\' etc."
```
If you want to use the output as part of a CSS string literal wrapped in double quotes, set the `quotes` option to `'double'`.
```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'double'
});
// → 'Lorem ipsum \\"dolor\\" sit \'amet\' etc.'
// → "Lorem ipsum \\\"dolor\\\" sit 'amet' etc."
```
#### `wrap`
The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output will be a valid CSS string literal wrapped in quotes. The type of quotes can be specified through the `quotes` setting.
```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'single',
'wrap': true
});
// → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\''
// → "\'Lorem ipsum \"dolor\" sit \\\'amet\\\' etc.\'"
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'double',
'wrap': true
});
// → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."'
// → "\"Lorem ipsum \\\"dolor\\\" sit \'amet\' etc.\""
```
#### `escapeEverything`
The `escapeEverything` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, all the symbols in the output will be escaped, even printable ASCII symbols.
```js
cssesc('lolwat"foo\'bar', {
'escapeEverything': true
});
// → '\\6C\\6F\\6C\\77\\61\\74\\"\\66\\6F\\6F\\\'\\62\\61\\72'
// → "\\6C\\6F\\6C\\77\\61\\74\\\"\\66\\6F\\6F\\'\\62\\61\\72"
```
### `cssesc.version`
A string representing the semantic version number.
### Using the `cssesc` binary
To use the `cssesc` binary in your shell, simply install cssesc globally using npm:
```bash
npm install -g cssesc
```
After that you will be able to escape text for use in CSS strings or identifiers from the command line:
```bash
$ cssesc 'föo ♥ bår 𝌆 baz'
f\F6o \2665 b\E5r \1D306 baz
```
If the output needs to be a CSS identifier rather than part of a string literal, use the `-i`/`--identifier` option:
```bash
$ cssesc --identifier 'föo ♥ bår 𝌆 baz'
f\F6o\ \2665\ b\E5r\ \1D306\ baz
```
See `cssesc --help` for the full list of options.
## Support
This library has been tested in at least Chrome 28-30, Firefox 3-23, Safari 4-6, Opera 10-15, IE 6-10, Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.9, PhantomJS 1.9.0, and Rhino 1.7RC4.
## Unit tests & code coverage
After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`.
To generate [the code coverage report](http://rawgithub.com/mathiasbynens/cssesc/master/coverage/cssesc/cssesc.js.html), use `grunt cover`.
## Author
| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](http://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](http://mathiasbynens.be/) |
## License
This library is available under the [MIT](http://mths.be/mit) license.
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env node
(function() {
var fs = require('fs');
var cssesc = require('../cssesc.js');
var strings = process.argv.splice(2);
var stdin = process.stdin;
var data;
var timeout;
var isObject = false;
var options = {};
var log = console.log;
var main = function() {
var option = strings[0];
if (/^(?:-h|--help|undefined)$/.test(option)) {
log(
'cssesc v%s - http://mths.be/cssesc',
cssesc.version
);
log([
'\nUsage:\n',
'\tcssesc [string]',
'\tcssesc [-i | --identifier] [string]',
'\tcssesc [-s | --single-quotes] [string]',
'\tcssesc [-d | --double-quotes] [string]',
'\tcssesc [-w | --wrap] [string]',
'\tcssesc [-e | --escape-everything] [string]',
'\tcssesc [-v | --version]',
'\tcssesc [-h | --help]',
'\nExamples:\n',
'\tcssesc \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tcssesc --identifier \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tcssesc --escape-everything \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tcssesc --double-quotes --wrap \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\techo \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\' | cssesc'
].join('\n'));
return process.exit(1);
}
if (/^(?:-v|--version)$/.test(option)) {
log('v%s', cssesc.version);
return process.exit(1);
}
strings.forEach(function(string) {
// Process options
if (/^(?:-i|--identifier)$/.test(string)) {
options.isIdentifier = true;
return;
}
if (/^(?:-s|--single-quotes)$/.test(string)) {
options.quotes = 'single';
return;
}
if (/^(?:-d|--double-quotes)$/.test(string)) {
options.quotes = 'double';
return;
}
if (/^(?:-w|--wrap)$/.test(string)) {
options.wrap = true;
return;
}
if (/^(?:-e|--escape-everything)$/.test(string)) {
options.escapeEverything = true;
return;
}
// Process string(s)
var result;
try {
result = cssesc(string, options);
log(result);
} catch(error) {
log(error.message + '\n');
log('Error: failed to escape.');
log('If you think this is a bug in cssesc, please report it:');
log('https://github.com/mathiasbynens/cssesc/issues/new');
log(
'\nStack trace using cssesc@%s:\n',
cssesc.version
);
log(error.stack);
return process.exit(1);
}
});
// Return with exit status 0 outside of the `forEach` loop, in case
// multiple strings were passed in.
return process.exit(0);
};
if (stdin.isTTY) {
// handle shell arguments
main();
} else {
// Either the script is called from within a non-TTY context, or `stdin`
// content is being piped in.
if (!process.stdout.isTTY) {
// The script was called from a non-TTY context. This is a rather uncommon
// use case we don’t actively support. However, we don’t want the script
// to wait forever in such cases, so…
timeout = setTimeout(function() {
// …if no piped data arrived after a whole minute, handle shell
// arguments instead.
main();
}, 60000);
}
data = '';
stdin.on('data', function(chunk) {
clearTimeout(timeout);
data += chunk;
});
stdin.on('end', function() {
strings.push(data.trim());
main();
});
stdin.resume();
}
}());
+177
View File
@@ -0,0 +1,177 @@
/*! http://mths.be/cssesc v0.1.0 by @mathias */
;(function(root) {
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports;
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
var object = {};
var hasOwnProperty = object.hasOwnProperty;
var merge = function(options, defaults) {
if (!options) {
return defaults;
}
var key;
var result = {};
for (key in defaults) {
// `if (defaults.hasOwnProperty(key) { … }` is not needed here, since
// only recognized option names are used
result[key] = hasOwnProperty.call(options, key)
? options[key]
: defaults[key];
}
return result;
};
/*--------------------------------------------------------------------------*/
var regexAnySingleEscape = /[\x20-\x2C\x2E\x2F\x3B-\x40\x5B-\x5E\x60\x7B-\x7E]/;
var regexSingleEscape = /[\x20\x21\x23-\x26\x28-\x2C\x2E\x2F\x3B-\x40\x5B\x5D\x5E\x60\x7B-\x7E]/;
var regexAlwaysEscape = /['"\\]/;
var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
// http://mathiasbynens.be/notes/css-escapes#css
var cssesc = function(string, options) {
// Handle options
options = merge(options, cssesc.options);
if (options.quotes != 'single' && options.quotes != 'double') {
options.quotes = 'single';
}
var quote = options.quotes == 'double' ? '"' : '\'';
var isIdentifier = options.isIdentifier;
var firstChar = string.charAt(0);
var output = '';
var counter = 0;
var length = string.length;
var value;
var character;
var codePoint;
var extra; // used for potential low surrogates
while (counter < length) {
character = string.charAt(counter++);
codePoint = character.charCodeAt();
// if it’s not a printable ASCII character
if (codePoint < 0x20 || codePoint > 0x7E) {
if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // next character is low surrogate
codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
counter--;
}
}
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
} else {
if (options.escapeEverything) {
if (regexAnySingleEscape.test(character)) {
value = '\\' + character;
} else {
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
}
// `:` can be escaped as `\:`, but that fails in IE < 8
} else if (/[\t\n\f\r\x0B:]/.test(character)) {
if (!isIdentifier && character == ':') {
value = character;
} else {
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
}
} else if (
character == '\\' ||
(
!isIdentifier &&
(
(character == '"' && quote == character) ||
(character == '\'' && quote == character)
)
) ||
(isIdentifier && regexSingleEscape.test(character))
) {
value = '\\' + character;
} else {
value = character;
}
}
output += value;
}
if (isIdentifier) {
if (/^_/.test(output)) {
// Prevent IE6 from ignoring the rule altogether (in case this is for an
// identifier used as a selector)
output = '\\_' + output.slice(1);
} else if (/^-[-\d]/.test(output)) {
output = '\\-' + output.slice(1);
} else if (/\d/.test(firstChar)) {
output = '\\3' + firstChar + ' ' + output.slice(1);
}
}
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
// since they’re redundant. Note that this is only possible if the escape
// sequence isn’t preceded by an odd number of backslashes.
output = output.replace(regexExcessiveSpaces, function($0, $1, $2) {
if ($1 && $1.length % 2) {
// it’s not safe to remove the space, so don’t
return $0;
}
// strip the space
return ($1 || '') + $2;
});
if (!isIdentifier && options.wrap) {
return quote + output + quote;
}
return output;
};
// Expose default options (so they can be overridden globally)
cssesc.options = {
'escapeEverything': false,
'isIdentifier': false,
'quotes': 'single',
'wrap': false
};
cssesc.version = '0.1.0';
/*--------------------------------------------------------------------------*/
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
define(function() {
return cssesc;
});
} else if (freeExports && !freeExports.nodeType) {
if (freeModule) { // in Node.js or RingoJS v0.8.0+
freeModule.exports = cssesc;
} else { // in Narwhal or RingoJS v0.7.0-
freeExports.cssesc = cssesc;
}
} else { // in Rhino or a web browser
root.cssesc = cssesc;
}
}(this));
+70
View File
@@ -0,0 +1,70 @@
.Dd August 9, 2013
.Dt cssesc 1
.Sh NAME
.Nm cssesc
.Nd escape text for use in CSS string literals or identifiers
.Sh SYNOPSIS
.Nm
.Op Fl i | -identifier Ar string
.br
.Op Fl s | -single-quotes Ar string
.br
.Op Fl d | -double-quotes Ar string
.br
.Op Fl w | -wrap Ar string
.br
.Op Fl e | -escape-everything Ar string
.br
.Op Fl v | -version
.br
.Op Fl h | -help
.Sh DESCRIPTION
.Nm
escapes strings for use in CSS string literals or identifiers while generating the shortest possible valid ASCII-only output.
.Sh OPTIONS
.Bl -ohang -offset
.It Sy "-s, --single-quotes"
Escape any occurences of ' in the input string as \\', so that the output can be used in a CSS string literal wrapped in single quotes.
.It Sy "-d, --double-quotes"
Escape any occurences of " in the input string as \\", so that the output can be used in a CSS string literal wrapped in double quotes.
.It Sy "-w, --wrap"
Make sure the output is a valid CSS string literal wrapped in quotes. The type of quotes can be specified using the
.Ar -s | --single-quotes
or
.Ar -d | --double-quotes
settings.
.It Sy "-e, --escape-everything"
Escape all the symbols in the output, even printable ASCII symbols.
.It Sy "-v, --version"
Print cssesc's version.
.It Sy "-h, --help"
Show the help screen.
.El
.Sh EXIT STATUS
The
.Nm cssesc
utility exits with one of the following values:
.Pp
.Bl -tag -width flag -compact
.It Li 0
.Nm
successfully escaped the given text and printed the result.
.It Li 1
.Nm
wasn't instructed to escape anything (for example, the
.Ar --help
flag was set); or, an error occurred.
.El
.Sh EXAMPLES
.Bl -ohang -offset
.It Sy "cssesc 'foo bar baz'"
Print an escaped version of the given text.
.It Sy echo\ 'foo bar baz'\ |\ cssesc
Print an escaped version of the text that gets piped in.
.El
.Sh BUGS
cssesc's bug tracker is located at <https://github.com/mathiasbynens/cssesc/issues>.
.Sh AUTHOR
Mathias Bynens <http://mathiasbynens.be/>
.Sh WWW
<http://mths.be/cssesc>
+85
View File
@@ -0,0 +1,85 @@
{
"_from": "cssesc@^0.1.0",
"_id": "cssesc@0.1.0",
"_inBundle": false,
"_integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
"_location": "/css-selector-tokenizer/cssesc",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "cssesc@^0.1.0",
"name": "cssesc",
"escapedName": "cssesc",
"rawSpec": "^0.1.0",
"saveSpec": null,
"fetchSpec": "^0.1.0"
},
"_requiredBy": [
"/css-selector-tokenizer"
],
"_resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
"_shasum": "c814903e45623371a0477b40109aaafbeeaddbb4",
"_spec": "cssesc@^0.1.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\css-selector-tokenizer",
"author": {
"name": "Mathias Bynens",
"url": "http://mathiasbynens.be/"
},
"bin": {
"cssesc": "bin/cssesc"
},
"bugs": {
"url": "https://github.com/mathiasbynens/cssesc/issues"
},
"bundleDependencies": false,
"dependencies": {},
"deprecated": false,
"description": "A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output.",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-shell": "~0.3.1",
"grunt-template": "~0.2.0",
"istanbul": "~0.1.42",
"qunit-clib": "~1.3.0",
"qunitjs": "~1.11.0",
"regenerate": "~0.5.2",
"requirejs": "~2.1.8"
},
"directories": {
"test": "tests"
},
"files": [
"LICENSE-MIT.txt",
"cssesc.js",
"bin/",
"man/"
],
"homepage": "http://mths.be/cssesc",
"keywords": [
"css",
"escape",
"identifier",
"string",
"tool"
],
"licenses": [
{
"type": "MIT",
"url": "http://mths.be/mit"
}
],
"main": "cssesc.js",
"man": [
"man/cssesc.1"
],
"name": "cssesc",
"repository": {
"type": "git",
"url": "git+https://github.com/mathiasbynens/cssesc.git"
},
"scripts": {
"test": "node tests/tests.js"
},
"version": "0.1.0"
}
+20
View File
@@ -0,0 +1,20 @@
Copyright Mathias Bynens <http://mathiasbynens.be/>
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.
+375
View File
@@ -0,0 +1,375 @@
# jsesc [![Build status](https://travis-ci.org/mathiasbynens/jsesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/jsesc) [![Code coverage status](http://img.shields.io/coveralls/mathiasbynens/jsesc/master.svg)](https://coveralls.io/r/mathiasbynens/jsesc) [![Dependency status](https://gemnasium.com/mathiasbynens/jsesc.svg)](https://gemnasium.com/mathiasbynens/jsesc)
This is a JavaScript library for [escaping JavaScript strings](http://mathiasbynens.be/notes/javascript-escapes) while generating the shortest possible valid ASCII-only output. [Here’s an online demo.](http://mothereff.in/js-escapes)
This can be used to avoid [mojibake](http://en.wikipedia.org/wiki/Mojibake) and other encoding issues, or even to [avoid errors](https://twitter.com/annevk/status/380000829643571200) when passing JSON-formatted data (which may contain U+2028 LINE SEPARATOR, U+2029 PARAGRAPH SEPARATOR, or [lone surrogates](http://esdiscuss.org/topic/code-points-vs-unicode-scalar-values#content-14)) to a JavaScript parser or an UTF-8 encoder, respectively.
Feel free to fork if you see possible improvements!
## Installation
Via [Bower](http://bower.io/):
```bash
bower install jsesc
```
Via [Component](https://github.com/component/component):
```bash
component install mathiasbynens/jsesc
```
Via [npm](http://npmjs.org/):
```bash
npm install jsesc
```
In a browser:
```html
<script src="jsesc.js"></script>
```
In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/):
```js
var jsesc = require('jsesc');
```
In [Narwhal](http://narwhaljs.org/):
```js
var jsesc = require('jsesc').jsesc;
```
In [Rhino](http://www.mozilla.org/rhino/):
```js
load('jsesc.js');
```
Using an AMD loader like [RequireJS](http://requirejs.org/):
```js
require(
{
'paths': {
'jsesc': 'path/to/jsesc'
}
},
['jsesc'],
function(jsesc) {
console.log(jsesc);
}
);
```
## API
### `jsesc(value, options)`
This function takes a value and returns an escaped version of the value where any characters that are not printable ASCII symbols are escaped using the shortest possible (but valid) [escape sequences for use in JavaScript strings](http://mathiasbynens.be/notes/javascript-escapes). The first supported value type is strings:
```js
jsesc('Ich ♥ Bücher');
// → 'Ich \\u2665 B\\xFCcher'
jsesc('foo 𝌆 bar');
// → 'foo \\uD834\\uDF06 bar'
```
Instead of a string, the `value` can also be an array, or an object. In such cases, `jsesc` will return a stringified version of the value where any characters that are not printable ASCII symbols are escaped in the same way.
```js
// Escaping an array
jsesc([
'Ich ♥ Bücher', 'foo 𝌆 bar'
]);
// → '[\'Ich \\u2665 B\\xFCcher\',\'foo \\uD834\\uDF06 bar\']'
// Escaping an object
jsesc({
'Ich ♥ Bücher': 'foo 𝌆 bar'
});
// → '{\'Ich \\u2665 B\\xFCcher\':\'foo \\uD834\\uDF06 bar\'}'
```
The optional `options` argument accepts an object with the following options:
#### `quotes`
The default value for the `quotes` option is `'single'`. This means that any occurences of `'` in the input string will be escaped as `\'`, so that the output can be used in a string literal wrapped in single quotes.
```js
jsesc('Lorem ipsum "dolor" sit \'amet\' etc.');
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'single'
});
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
// → "Lorem ipsum \"dolor\" sit \\'amet\\' etc."
```
If you want to use the output as part of a string literal wrapped in double quotes, set the `quotes` option to `'double'`.
```js
jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'double'
});
// → 'Lorem ipsum \\"dolor\\" sit \'amet\' etc.'
// → "Lorem ipsum \\\"dolor\\\" sit 'amet' etc."
```
This setting also affects the output for arrays and objects:
```js
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'quotes': 'double'
});
// → '{"Ich \\u2665 B\\xFCcher":"foo \\uD834\\uDF06 bar"}'
jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], {
'quotes': 'double'
});
// → '["Ich \\u2665 B\\xFCcher","foo \\uD834\\uDF06 bar"]'
```
#### `wrap`
The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output will be a valid JavaScript string literal wrapped in quotes. The type of quotes can be specified through the `quotes` setting.
```js
jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'single',
'wrap': true
});
// → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\''
// → "\'Lorem ipsum \"dolor\" sit \\\'amet\\\' etc.\'"
jsesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
'quotes': 'double',
'wrap': true
});
// → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."'
// → "\"Lorem ipsum \\\"dolor\\\" sit \'amet\' etc.\""
```
#### `es6`
The `es6` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, any astral Unicode symbols in the input will be escaped using [ECMAScript 6 Unicode code point escape sequences](http://mathiasbynens.be/notes/javascript-escapes#unicode-code-point) instead of using separate escape sequences for each surrogate half. If backwards compatibility with ES5 environments is a concern, don’t enable this setting. If the `json` setting is enabled, the value for the `es6` setting is ignored (as if it was `false`).
```js
// By default, the `es6` option is disabled:
jsesc('foo 𝌆 bar 💩 baz');
// → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz'
// To explicitly disable it:
jsesc('foo 𝌆 bar 💩 baz', {
'es6': false
});
// → 'foo \\uD834\\uDF06 bar \\uD83D\\uDCA9 baz'
// To enable it:
jsesc('foo 𝌆 bar 💩 baz', {
'es6': true
});
// → 'foo \\u{1D306} bar \\u{1F4A9} baz'
```
#### `escapeEverything`
The `escapeEverything` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, all the symbols in the output will be escaped, even printable ASCII symbols.
```js
jsesc('lolwat"foo\'bar', {
'escapeEverything': true
});
// → '\\x6C\\x6F\\x6C\\x77\\x61\\x74\\"\\x66\\x6F\\x6F\\\'\\x62\\x61\\x72'
// → "\\x6C\\x6F\\x6C\\x77\\x61\\x74\\\"\\x66\\x6F\\x6F\\'\\x62\\x61\\x72"
```
This setting also affects the output for arrays and objects:
```js
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'escapeEverything': true
});
// → '{\'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72\':\'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72\'}'
// → "{'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72':'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72'}"
jsesc([ 'Ich ♥ Bücher': 'foo 𝌆 bar' ], {
'escapeEverything': true
});
// → '[\'\x49\x63\x68\x20\u2665\x20\x42\xFC\x63\x68\x65\x72\',\'\x66\x6F\x6F\x20\uD834\uDF06\x20\x62\x61\x72\']'
```
#### `compact`
The `compact` option takes a boolean value (`true` or `false`), and defaults to `true` (enabled). When enabled, the output for arrays and objects will be as compact as possible; it won’t be formatted nicely.
```js
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'compact': true // this is the default
});
// → '{\'Ich \u2665 B\xFCcher\':\'foo \uD834\uDF06 bar\'}'
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'compact': false
});
// → '{\n\t\'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}'
jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], {
'compact': false
});
// → '[\n\t\'Ich \u2665 B\xFCcher\',\n\t\'foo \uD834\uDF06 bar\'\n]'
```
This setting has no effect on the output for strings.
#### `indent`
The `indent` option takes a string value, and defaults to `'\t'`. When the `compact` setting is enabled (`true`), the value of the `indent` option is used to format the output for arrays and objects.
```js
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'compact': false,
'indent': '\t' // this is the default
});
// → '{\n\t\'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}'
jsesc({ 'Ich ♥ Bücher': 'foo 𝌆 bar' }, {
'compact': false,
'indent': ' '
});
// → '{\n \'Ich \u2665 B\xFCcher\': \'foo \uD834\uDF06 bar\'\n}'
jsesc([ 'Ich ♥ Bücher', 'foo 𝌆 bar' ], {
'compact': false,
'indent': ' '
});
// → '[\n \'Ich \u2665 B\xFCcher\',\n\ t\'foo \uD834\uDF06 bar\'\n]'
```
This setting has no effect on the output for strings.
#### `json`
The `json` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output is valid JSON. [Hexadecimal character escape sequences](http://mathiasbynens.be/notes/javascript-escapes#hexadecimal) and [the `\v` or `\0` escape sequences](http://mathiasbynens.be/notes/javascript-escapes#single) will not be used. Setting `json: true` implies `quotes: 'double', wrap: true, es6: false`, although these values can still be overridden if needed — but in such cases, the output won’t be valid JSON anymore.
```js
jsesc('foo\x00bar\xFF\uFFFDbaz', {
'json': true
});
// → '"foo\\u0000bar\\u00FF\\uFFFDbaz"'
jsesc({ 'foo\x00bar\xFF\uFFFDbaz': 'foo\x00bar\xFF\uFFFDbaz' }, {
'json': true
});
// → '{"foo\\u0000bar\\u00FF\\uFFFDbaz":"foo\\u0000bar\\u00FF\\uFFFDbaz"}'
jsesc([ 'foo\x00bar\xFF\uFFFDbaz', 'foo\x00bar\xFF\uFFFDbaz' ], {
'json': true
});
// → '["foo\\u0000bar\\u00FF\\uFFFDbaz","foo\\u0000bar\\u00FF\\uFFFDbaz"]'
// Values that are acceptable in JSON but aren’t strings, arrays, or object
// literals can’t be escaped, so they’ll just be preserved:
jsesc([ 'foo\x00bar', [1, '©', { 'foo': true, 'qux': null }], 42 ], {
'json': true
});
// → '["foo\\u0000bar",[1,"\\u00A9",{"foo":true,"qux":null}],42]'
// Values that aren’t allowed in JSON are run through `JSON.stringify()`:
jsesc([ undefined, -Infinity ], {
'json': true
});
// → '[null,null]'
```
**Note:** Using this option on objects or arrays that contain non-string values relies on `JSON.stringify()`. For legacy environments like IE ≤ 7, use [a `JSON` polyfill](http://bestiejs.github.io/json3/).
### `jsesc.version`
A string representing the semantic version number.
### Using the `jsesc` binary
To use the `jsesc` binary in your shell, simply install jsesc globally using npm:
```bash
npm install -g jsesc
```
After that you will be able to escape strings from the command line:
```bash
$ jsesc 'föo ♥ bår 𝌆 baz'
f\xF6o \u2665 b\xE5r \uD834\uDF06 baz
```
To escape arrays or objects containing string values, use the `-o`/`--object` option:
```bash
$ jsesc --object '{ "föo": "♥", "bår": "𝌆 baz" }'
{'f\xF6o':'\u2665','b\xE5r':'\uD834\uDF06 baz'}
```
To prettify the output in such cases, use the `-p`/`--pretty` option:
```bash
$ jsesc --pretty '{ "föo": "♥", "bår": "𝌆 baz" }'
{
'f\xF6o': '\u2665',
'b\xE5r': '\uD834\uDF06 baz'
}
```
For valid JSON output, use the `-j`/`--json` option:
```bash
$ jsesc --json --pretty '{ "föo": "♥", "bår": "𝌆 baz" }'
{
"f\u00F6o": "\u2665",
"b\u00E5r": "\uD834\uDF06 baz"
}
```
Read a local JSON file, escape any non-ASCII symbols, and save the result to a new file:
```bash
$ jsesc --json --object < data-raw.json > data-escaped.json
```
Or do the same with an online JSON file:
```bash
$ curl -sL "http://git.io/aorKgQ" | jsesc --json --object > data-escaped.json
```
See `jsesc --help` for the full list of options.
## Support
This library has been tested in at least Chrome 27-29, Firefox 3-22, Safari 4-6, Opera 10-12, IE 6-10, Node.js v0.10.0, Narwhal 0.3.2, RingoJS 0.8-0.9, PhantomJS 1.9.0, and Rhino 1.7RC4.
**Note:** Using the `json` option on objects or arrays that contain non-string values relies on `JSON.parse()`. For legacy environments like IE ≤ 7, use [a `JSON` polyfill](http://bestiejs.github.io/json3/).
## Unit tests & code coverage
After cloning this repository, run `npm install` to install the dependencies needed for development and testing. You may want to install Istanbul _globally_ using `npm install istanbul -g`.
Once that’s done, you can run the unit tests in Node using `npm test` or `node tests/tests.js`. To run the tests in Rhino, Ringo, Narwhal, and web browsers as well, use `grunt test`.
To generate the code coverage report, use `grunt cover`.
## Author
| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](http://mathiasbynens.be/) |
## License
This library is available under the [MIT](http://mths.be/mit) license.
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/env node
(function() {
var fs = require('fs');
var stringEscape = require('../jsesc.js');
var strings = process.argv.splice(2);
var stdin = process.stdin;
var data;
var timeout;
var isObject = false;
var options = {};
var log = console.log;
var main = function() {
var option = strings[0];
if (/^(?:-h|--help|undefined)$/.test(option)) {
log(
'jsesc v%s - http://mths.be/jsesc',
stringEscape.version
);
log([
'\nUsage:\n',
'\tjsesc [string]',
'\tjsesc [-s | --single-quotes] [string]',
'\tjsesc [-d | --double-quotes] [string]',
'\tjsesc [-w | --wrap] [string]',
'\tjsesc [-e | --escape-everything] [string]',
'\tjsesc [-6 | --es6] [string]',
'\tjsesc [-j | --json] [string]',
'\tjsesc [-o | --object] [stringified_object]', // `JSON.parse()` the argument
'\tjsesc [-p | --pretty] [string]', // `compact: false`
'\tjsesc [-v | --version]',
'\tjsesc [-h | --help]',
'\nExamples:\n',
'\tjsesc \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tjsesc --json \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tjsesc --json --escape-everything \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\tjsesc --double-quotes --wrap \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
'\techo \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\' | jsesc'
].join('\n'));
return process.exit(1);
}
if (/^(?:-v|--version)$/.test(option)) {
log('v%s', stringEscape.version);
return process.exit(1);
}
strings.forEach(function(string) {
// Process options
if (/^(?:-s|--single-quotes)$/.test(string)) {
options.quotes = 'single';
return;
}
if (/^(?:-d|--double-quotes)$/.test(string)) {
options.quotes = 'double';
return;
}
if (/^(?:-w|--wrap)$/.test(string)) {
options.wrap = true;
return;
}
if (/^(?:-6|--es6)$/.test(string)) {
options.es6 = true;
return;
}
if (/^(?:-e|--escape-everything)$/.test(string)) {
options.escapeEverything = true;
return;
}
if (/^(?:-j|--json)$/.test(string)) {
options.json = true;
return;
}
if (/^(?:-o|--object)$/.test(string)) {
isObject = true;
return;
}
if (/^(?:-p|--pretty)$/.test(string)) {
isObject = true;
options.compact = false;
return;
}
// Process string(s)
var result;
try {
if (isObject) {
string = JSON.parse(string);
}
result = stringEscape(string, options);
log(result);
} catch(error) {
log(error.message + '\n');
log('Error: failed to escape.');
log('If you think this is a bug in jsesc, please report it:');
log('https://github.com/mathiasbynens/jsesc/issues/new');
log(
'\nStack trace using jsesc@%s:\n',
stringEscape.version
);
log(error.stack);
return process.exit(1);
}
});
// Return with exit status 0 outside of the `forEach` loop, in case
// multiple strings were passed in.
return process.exit(0);
};
if (stdin.isTTY) {
// handle shell arguments
main();
} else {
// Either the script is called from within a non-TTY context,
// or `stdin` content is being piped in.
if (!process.stdout.isTTY) { // called from a non-TTY context
timeout = setTimeout(function() {
// if no piped data arrived after a while, handle shell arguments
main();
}, 250);
}
data = '';
stdin.on('data', function(chunk) {
clearTimeout(timeout);
data += chunk;
});
stdin.on('end', function() {
strings.push(data.trim());
main();
});
stdin.resume();
}
}());
+265
View File
@@ -0,0 +1,265 @@
/*! http://mths.be/jsesc v0.5.0 by @mathias */
;(function(root) {
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports;
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
var object = {};
var hasOwnProperty = object.hasOwnProperty;
var forOwn = function(object, callback) {
var key;
for (key in object) {
if (hasOwnProperty.call(object, key)) {
callback(key, object[key]);
}
}
};
var extend = function(destination, source) {
if (!source) {
return destination;
}
forOwn(source, function(key, value) {
destination[key] = value;
});
return destination;
};
var forEach = function(array, callback) {
var length = array.length;
var index = -1;
while (++index < length) {
callback(array[index]);
}
};
var toString = object.toString;
var isArray = function(value) {
return toString.call(value) == '[object Array]';
};
var isObject = function(value) {
// This is a very simple check, but it’s good enough for what we need.
return toString.call(value) == '[object Object]';
};
var isString = function(value) {
return typeof value == 'string' ||
toString.call(value) == '[object String]';
};
var isFunction = function(value) {
// In a perfect world, the `typeof` check would be sufficient. However,
// in Chrome 1–12, `typeof /x/ == 'object'`, and in IE 6–8
// `typeof alert == 'object'` and similar for other host objects.
return typeof value == 'function' ||
toString.call(value) == '[object Function]';
};
/*--------------------------------------------------------------------------*/
// http://mathiasbynens.be/notes/javascript-escapes#single
var singleEscapes = {
'"': '\\"',
'\'': '\\\'',
'\\': '\\\\',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t'
// `\v` is omitted intentionally, because in IE < 9, '\v' == 'v'.
// '\v': '\\x0B'
};
var regexSingleEscape = /["'\\\b\f\n\r\t]/;
var regexDigit = /[0-9]/;
var regexWhitelist = /[ !#-&\(-\[\]-~]/;
var jsesc = function(argument, options) {
// Handle options
var defaults = {
'escapeEverything': false,
'quotes': 'single',
'wrap': false,
'es6': false,
'json': false,
'compact': true,
'indent': '\t',
'__indent__': ''
};
var json = options && options.json;
if (json) {
defaults.quotes = 'double';
defaults.wrap = true;
}
options = extend(defaults, options);
if (options.quotes != 'single' && options.quotes != 'double') {
options.quotes = 'single';
}
var quote = options.quotes == 'double' ? '"' : '\'';
var compact = options.compact;
var indent = options.indent;
var oldIndent;
var newLine = compact ? '' : '\n';
var result;
var isEmpty = true;
if (json && argument && isFunction(argument.toJSON)) {
argument = argument.toJSON();
}
if (!isString(argument)) {
if (isArray(argument)) {
result = [];
options.wrap = true;
oldIndent = options.__indent__;
indent += oldIndent;
options.__indent__ = indent;
forEach(argument, function(value) {
isEmpty = false;
result.push(
(compact ? '' : indent) +
jsesc(value, options)
);
});
if (isEmpty) {
return '[]';
}
return '[' + newLine + result.join(',' + newLine) + newLine +
(compact ? '' : oldIndent) + ']';
} else if (!isObject(argument)) {
if (json) {
// For some values (e.g. `undefined`, `function` objects),
// `JSON.stringify(value)` returns `undefined` (which isn’t valid
// JSON) instead of `'null'`.
return JSON.stringify(argument) || 'null';
}
return String(argument);
} else { // it’s an object
result = [];
options.wrap = true;
oldIndent = options.__indent__;
indent += oldIndent;
options.__indent__ = indent;
forOwn(argument, function(key, value) {
isEmpty = false;
result.push(
(compact ? '' : indent) +
jsesc(key, options) + ':' +
(compact ? '' : ' ') +
jsesc(value, options)
);
});
if (isEmpty) {
return '{}';
}
return '{' + newLine + result.join(',' + newLine) + newLine +
(compact ? '' : oldIndent) + '}';
}
}
var string = argument;
// Loop over each code unit in the string and escape it
var index = -1;
var length = string.length;
var first;
var second;
var codePoint;
result = '';
while (++index < length) {
var character = string.charAt(index);
if (options.es6) {
first = string.charCodeAt(index);
if ( // check if it’s the start of a surrogate pair
first >= 0xD800 && first <= 0xDBFF && // high surrogate
length > index + 1 // there is a next code unit
) {
second = string.charCodeAt(index + 1);
if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint = (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
result += '\\u{' + codePoint.toString(16).toUpperCase() + '}';
index++;
continue;
}
}
}
if (!options.escapeEverything) {
if (regexWhitelist.test(character)) {
// It’s a printable ASCII character that is not `"`, `'` or `\`,
// so don’t escape it.
result += character;
continue;
}
if (character == '"') {
result += quote == character ? '\\"' : character;
continue;
}
if (character == '\'') {
result += quote == character ? '\\\'' : character;
continue;
}
}
if (
character == '\0' &&
!json &&
!regexDigit.test(string.charAt(index + 1))
) {
result += '\\0';
continue;
}
if (regexSingleEscape.test(character)) {
// no need for a `hasOwnProperty` check here
result += singleEscapes[character];
continue;
}
var charCode = character.charCodeAt(0);
var hexadecimal = charCode.toString(16).toUpperCase();
var longhand = hexadecimal.length > 2 || json;
var escaped = '\\' + (longhand ? 'u' : 'x') +
('0000' + hexadecimal).slice(longhand ? -4 : -2);
result += escaped;
continue;
}
if (options.wrap) {
result = quote + result + quote;
}
return result;
};
jsesc.version = '0.5.0';
/*--------------------------------------------------------------------------*/
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
typeof define == 'function' &&
typeof define.amd == 'object' &&
define.amd
) {
define(function() {
return jsesc;
});
} else if (freeExports && !freeExports.nodeType) {
if (freeModule) { // in Node.js or RingoJS v0.8.0+
freeModule.exports = jsesc;
} else { // in Narwhal or RingoJS v0.7.0-
freeExports.jsesc = jsesc;
}
} else { // in Rhino or a web browser
root.jsesc = jsesc;
}
}(this));
+90
View File
@@ -0,0 +1,90 @@
.Dd October 25, 2013
.Dt jsesc 1
.Sh NAME
.Nm jsesc
.Nd escape strings for use in JavaScript string literals
.Sh SYNOPSIS
.Nm
.Op Fl s | -single-quotes Ar string
.br
.Op Fl d | -double-quotes Ar string
.br
.Op Fl w | -wrap Ar string
.br
.Op Fl 6 | -es6 Ar string
.br
.Op Fl e | -escape-everything Ar string
.br
.Op Fl j | -json Ar string
.br
.Op Fl p | -object Ar string
.br
.Op Fl p | -pretty Ar string
.br
.Op Fl v | -version
.br
.Op Fl h | -help
.Sh DESCRIPTION
.Nm
escapes strings for use in JavaScript string literals while generating the shortest possible valid ASCII-only output.
.Sh OPTIONS
.Bl -ohang -offset
.It Sy "-s, --single-quotes"
Escape any occurences of ' in the input string as \\', so that the output can be used in a JavaScript string literal wrapped in single quotes.
.It Sy "-d, --double-quotes"
Escape any occurences of " in the input string as \\", so that the output can be used in a JavaScript string literal wrapped in double quotes.
.It Sy "-w, --wrap"
Make sure the output is a valid JavaScript string literal wrapped in quotes. The type of quotes can be specified using the
.Ar -s | --single-quotes
or
.Ar -d | --double-quotes
settings.
.It Sy "-6, --es6"
Escape any astral Unicode symbols using ECMAScript 6 Unicode code point escape sequences.
.It Sy "-e, --escape-everything"
Escape all the symbols in the output, even printable ASCII symbols.
.It Sy "-j, --json"
Make sure the output is valid JSON. Hexadecimal character escape sequences and the \\v or \\0 escape sequences will not be used. Setting this flag enables the
.Ar -d | --double-quotes
and
.Ar -w | --wrap
settings.
.It Sy "-o, --object"
Treat the input as a JavaScript object rather than a string. Accepted values are flat arrays containing only string values, and flat objects containing only string values.
.It Sy "-p, --pretty"
Pretty-print the output for objects, using whitespace to make it more readable. Setting this flag enables the
.Ar -o | --object
setting.
.It Sy "-v, --version"
Print jsesc's version.
.It Sy "-h, --help"
Show the help screen.
.El
.Sh EXIT STATUS
The
.Nm jsesc
utility exits with one of the following values:
.Pp
.Bl -tag -width flag -compact
.It Li 0
.Nm
successfully escaped the given string and printed the result.
.It Li 1
.Nm
wasn't instructed to escape anything (for example, the
.Ar --help
flag was set); or, an error occurred.
.El
.Sh EXAMPLES
.Bl -ohang -offset
.It Sy "jsesc 'foo bar baz'"
Print an escaped version of the given string.
.It Sy echo\ 'foo bar baz'\ |\ jsesc
Print an escaped version of the string that gets piped in.
.El
.Sh BUGS
jsesc's bug tracker is located at <https://github.com/mathiasbynens/jsesc/issues>.
.Sh AUTHOR
Mathias Bynens <http://mathiasbynens.be/>
.Sh WWW
<http://mths.be/jsesc>
+84
View File
@@ -0,0 +1,84 @@
{
"_from": "jsesc@~0.5.0",
"_id": "jsesc@0.5.0",
"_inBundle": false,
"_integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"_location": "/css-selector-tokenizer/jsesc",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "jsesc@~0.5.0",
"name": "jsesc",
"escapedName": "jsesc",
"rawSpec": "~0.5.0",
"saveSpec": null,
"fetchSpec": "~0.5.0"
},
"_requiredBy": [
"/css-selector-tokenizer/regjsparser"
],
"_resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"_shasum": "e7dee66e35d6fc16f710fe91d5cf69f70f08911d",
"_spec": "jsesc@~0.5.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\css-selector-tokenizer\\node_modules\\regjsparser",
"author": {
"name": "Mathias Bynens",
"url": "http://mathiasbynens.be/"
},
"bin": {
"jsesc": "bin/jsesc"
},
"bugs": {
"url": "https://github.com/mathiasbynens/jsesc/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "A JavaScript library for escaping JavaScript strings while generating the shortest possible valid output.",
"devDependencies": {
"coveralls": "^2.10.0",
"grunt": "^0.4.5",
"grunt-shell": "^0.7.0",
"grunt-template": "^0.2.3",
"istanbul": "^0.3.0",
"qunit-extras": "^1.2.0",
"qunitjs": "~1.11.0",
"regenerate": "^0.6.2",
"requirejs": "^2.1.14"
},
"directories": {
"test": "tests"
},
"files": [
"LICENSE-MIT.txt",
"jsesc.js",
"bin/",
"man/"
],
"homepage": "http://mths.be/jsesc",
"keywords": [
"string",
"escape",
"javascript",
"tool"
],
"licenses": [
{
"type": "MIT",
"url": "http://mths.be/mit"
}
],
"main": "jsesc.js",
"man": [
"man/jsesc.1"
],
"name": "jsesc",
"repository": {
"type": "git",
"url": "git+https://github.com/mathiasbynens/jsesc.git"
},
"scripts": {
"test": "node tests/tests.js"
},
"version": "0.5.0"
}
@@ -0,0 +1,20 @@
Copyright Mathias Bynens <https://mathiasbynens.be/>
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.
@@ -0,0 +1,62 @@
# regexpu-core [![Build status](https://travis-ci.org/mathiasbynens/regexpu-core.svg?branch=master)](https://travis-ci.org/mathiasbynens/regexpu-core) [![Code coverage status](http://img.shields.io/coveralls/mathiasbynens/regexpu-core/master.svg)](https://coveralls.io/r/mathiasbynens/regexpu-core) [![Dependency status](https://gemnasium.com/mathiasbynens/regexpu-core.svg)](https://gemnasium.com/mathiasbynens/regexpu-core)
_regexpu_ is a source code transpiler that enables the use of ES6 Unicode regular expressions in JavaScript-of-today (ES5).
_regexpu-core_ contains _regexpu_’s core functionality, i.e. `rewritePattern(pattern, flag)`, which enables rewriting regular expressions that make use of [the ES6 `u` flag](https://mathiasbynens.be/notes/es6-unicode-regex) into equivalent ES5-compatible regular expression patterns.
## Installation
To use _regexpu-core_ programmatically, install it as a dependency via [npm](https://www.npmjs.com/):
```bash
npm install regexpu-core --save-dev
```
Then, `require` it:
```js
const rewritePattern = require('regexpu-core');
```
## API
This module exports a single function named `rewritePattern`.
### `rewritePattern(pattern, flags)`
This function takes a string that represents a regular expression pattern as well as a string representing its flags, and returns an ES5-compatible version of the pattern.
```js
rewritePattern('foo.bar', 'u');
// → 'foo(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uDC00-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF])bar'
rewritePattern('[\\u{1D306}-\\u{1D308}a-z]', 'u');
// → '(?:[a-z]|\\uD834[\\uDF06-\\uDF08])'
rewritePattern('[\\u{1D306}-\\u{1D308}a-z]', 'ui');
// → '(?:[a-z\\u017F\\u212A]|\\uD834[\\uDF06-\\uDF08])'
```
_regexpu-core_ can rewrite non-ES6 regular expressions too, which is useful to demonstrate how their behavior changes once the `u` and `i` flags are added:
```js
// In ES5, the dot operator only matches BMP symbols:
rewritePattern('foo.bar');
// → 'foo(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uFFFF])bar'
// But with the ES6 `u` flag, it matches astral symbols too:
rewritePattern('foo.bar', 'u');
// → 'foo(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uD7FF\\uDC00-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF])bar'
```
`rewritePattern` uses [regjsgen](https://github.com/d10/regjsgen), [regjsparser](https://github.com/jviereck/regjsparser), and [regenerate](https://github.com/mathiasbynens/regenerate) as internal dependencies.
## Author
| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](https://mathiasbynens.be/) |
## License
_regexpu-core_ is available under the [MIT](https://mths.be/mit) license.
@@ -0,0 +1,104 @@
// Generated by `/scripts/character-class-escape-sets.js`. Do not edit.
var regenerate = require('regenerate');
exports.REGULAR = {
'd': regenerate()
.addRange(0x30, 0x39),
'D': regenerate()
.addRange(0x0, 0x2F)
.addRange(0x3A, 0xFFFF),
's': regenerate(0x20, 0xA0, 0x1680, 0x180E, 0x202F, 0x205F, 0x3000, 0xFEFF)
.addRange(0x9, 0xD)
.addRange(0x2000, 0x200A)
.addRange(0x2028, 0x2029),
'S': regenerate()
.addRange(0x0, 0x8)
.addRange(0xE, 0x1F)
.addRange(0x21, 0x9F)
.addRange(0xA1, 0x167F)
.addRange(0x1681, 0x180D)
.addRange(0x180F, 0x1FFF)
.addRange(0x200B, 0x2027)
.addRange(0x202A, 0x202E)
.addRange(0x2030, 0x205E)
.addRange(0x2060, 0x2FFF)
.addRange(0x3001, 0xFEFE)
.addRange(0xFF00, 0xFFFF),
'w': regenerate(0x5F)
.addRange(0x30, 0x39)
.addRange(0x41, 0x5A)
.addRange(0x61, 0x7A),
'W': regenerate(0x60)
.addRange(0x0, 0x2F)
.addRange(0x3A, 0x40)
.addRange(0x5B, 0x5E)
.addRange(0x7B, 0xFFFF)
};
exports.UNICODE = {
'd': regenerate()
.addRange(0x30, 0x39),
'D': regenerate()
.addRange(0x0, 0x2F)
.addRange(0x3A, 0x10FFFF),
's': regenerate(0x20, 0xA0, 0x1680, 0x180E, 0x202F, 0x205F, 0x3000, 0xFEFF)
.addRange(0x9, 0xD)
.addRange(0x2000, 0x200A)
.addRange(0x2028, 0x2029),
'S': regenerate()
.addRange(0x0, 0x8)
.addRange(0xE, 0x1F)
.addRange(0x21, 0x9F)
.addRange(0xA1, 0x167F)
.addRange(0x1681, 0x180D)
.addRange(0x180F, 0x1FFF)
.addRange(0x200B, 0x2027)
.addRange(0x202A, 0x202E)
.addRange(0x2030, 0x205E)
.addRange(0x2060, 0x2FFF)
.addRange(0x3001, 0xFEFE)
.addRange(0xFF00, 0x10FFFF),
'w': regenerate(0x5F)
.addRange(0x30, 0x39)
.addRange(0x41, 0x5A)
.addRange(0x61, 0x7A),
'W': regenerate(0x60)
.addRange(0x0, 0x2F)
.addRange(0x3A, 0x40)
.addRange(0x5B, 0x5E)
.addRange(0x7B, 0x10FFFF)
};
exports.UNICODE_IGNORE_CASE = {
'd': regenerate()
.addRange(0x30, 0x39),
'D': regenerate()
.addRange(0x0, 0x2F)
.addRange(0x3A, 0x10FFFF),
's': regenerate(0x20, 0xA0, 0x1680, 0x180E, 0x202F, 0x205F, 0x3000, 0xFEFF)
.addRange(0x9, 0xD)
.addRange(0x2000, 0x200A)
.addRange(0x2028, 0x2029),
'S': regenerate()
.addRange(0x0, 0x8)
.addRange(0xE, 0x1F)
.addRange(0x21, 0x9F)
.addRange(0xA1, 0x167F)
.addRange(0x1681, 0x180D)
.addRange(0x180F, 0x1FFF)
.addRange(0x200B, 0x2027)
.addRange(0x202A, 0x202E)
.addRange(0x2030, 0x205E)
.addRange(0x2060, 0x2FFF)
.addRange(0x3001, 0xFEFE)
.addRange(0xFF00, 0x10FFFF),
'w': regenerate(0x5F, 0x17F, 0x212A)
.addRange(0x30, 0x39)
.addRange(0x41, 0x5A)
.addRange(0x61, 0x7A),
'W': regenerate(0x4B, 0x53, 0x60)
.addRange(0x0, 0x2F)
.addRange(0x3A, 0x40)
.addRange(0x5B, 0x5E)
.addRange(0x7B, 0x10FFFF)
};
@@ -0,0 +1,296 @@
{
"75": 8490,
"83": 383,
"107": 8490,
"115": 383,
"181": 924,
"197": 8491,
"383": 83,
"452": 453,
"453": 452,
"455": 456,
"456": 455,
"458": 459,
"459": 458,
"497": 498,
"498": 497,
"837": 8126,
"914": 976,
"917": 1013,
"920": 1012,
"921": 8126,
"922": 1008,
"924": 181,
"928": 982,
"929": 1009,
"931": 962,
"934": 981,
"937": 8486,
"962": 931,
"976": 914,
"977": 1012,
"981": 934,
"982": 928,
"1008": 922,
"1009": 929,
"1012": [
920,
977
],
"1013": 917,
"7776": 7835,
"7835": 7776,
"8126": [
837,
921
],
"8486": 937,
"8490": 75,
"8491": 197,
"66560": 66600,
"66561": 66601,
"66562": 66602,
"66563": 66603,
"66564": 66604,
"66565": 66605,
"66566": 66606,
"66567": 66607,
"66568": 66608,
"66569": 66609,
"66570": 66610,
"66571": 66611,
"66572": 66612,
"66573": 66613,
"66574": 66614,
"66575": 66615,
"66576": 66616,
"66577": 66617,
"66578": 66618,
"66579": 66619,
"66580": 66620,
"66581": 66621,
"66582": 66622,
"66583": 66623,
"66584": 66624,
"66585": 66625,
"66586": 66626,
"66587": 66627,
"66588": 66628,
"66589": 66629,
"66590": 66630,
"66591": 66631,
"66592": 66632,
"66593": 66633,
"66594": 66634,
"66595": 66635,
"66596": 66636,
"66597": 66637,
"66598": 66638,
"66599": 66639,
"66600": 66560,
"66601": 66561,
"66602": 66562,
"66603": 66563,
"66604": 66564,
"66605": 66565,
"66606": 66566,
"66607": 66567,
"66608": 66568,
"66609": 66569,
"66610": 66570,
"66611": 66571,
"66612": 66572,
"66613": 66573,
"66614": 66574,
"66615": 66575,
"66616": 66576,
"66617": 66577,
"66618": 66578,
"66619": 66579,
"66620": 66580,
"66621": 66581,
"66622": 66582,
"66623": 66583,
"66624": 66584,
"66625": 66585,
"66626": 66586,
"66627": 66587,
"66628": 66588,
"66629": 66589,
"66630": 66590,
"66631": 66591,
"66632": 66592,
"66633": 66593,
"66634": 66594,
"66635": 66595,
"66636": 66596,
"66637": 66597,
"66638": 66598,
"66639": 66599,
"68736": 68800,
"68737": 68801,
"68738": 68802,
"68739": 68803,
"68740": 68804,
"68741": 68805,
"68742": 68806,
"68743": 68807,
"68744": 68808,
"68745": 68809,
"68746": 68810,
"68747": 68811,
"68748": 68812,
"68749": 68813,
"68750": 68814,
"68751": 68815,
"68752": 68816,
"68753": 68817,
"68754": 68818,
"68755": 68819,
"68756": 68820,
"68757": 68821,
"68758": 68822,
"68759": 68823,
"68760": 68824,
"68761": 68825,
"68762": 68826,
"68763": 68827,
"68764": 68828,
"68765": 68829,
"68766": 68830,
"68767": 68831,
"68768": 68832,
"68769": 68833,
"68770": 68834,
"68771": 68835,
"68772": 68836,
"68773": 68837,
"68774": 68838,
"68775": 68839,
"68776": 68840,
"68777": 68841,
"68778": 68842,
"68779": 68843,
"68780": 68844,
"68781": 68845,
"68782": 68846,
"68783": 68847,
"68784": 68848,
"68785": 68849,
"68786": 68850,
"68800": 68736,
"68801": 68737,
"68802": 68738,
"68803": 68739,
"68804": 68740,
"68805": 68741,
"68806": 68742,
"68807": 68743,
"68808": 68744,
"68809": 68745,
"68810": 68746,
"68811": 68747,
"68812": 68748,
"68813": 68749,
"68814": 68750,
"68815": 68751,
"68816": 68752,
"68817": 68753,
"68818": 68754,
"68819": 68755,
"68820": 68756,
"68821": 68757,
"68822": 68758,
"68823": 68759,
"68824": 68760,
"68825": 68761,
"68826": 68762,
"68827": 68763,
"68828": 68764,
"68829": 68765,
"68830": 68766,
"68831": 68767,
"68832": 68768,
"68833": 68769,
"68834": 68770,
"68835": 68771,
"68836": 68772,
"68837": 68773,
"68838": 68774,
"68839": 68775,
"68840": 68776,
"68841": 68777,
"68842": 68778,
"68843": 68779,
"68844": 68780,
"68845": 68781,
"68846": 68782,
"68847": 68783,
"68848": 68784,
"68849": 68785,
"68850": 68786,
"71840": 71872,
"71841": 71873,
"71842": 71874,
"71843": 71875,
"71844": 71876,
"71845": 71877,
"71846": 71878,
"71847": 71879,
"71848": 71880,
"71849": 71881,
"71850": 71882,
"71851": 71883,
"71852": 71884,
"71853": 71885,
"71854": 71886,
"71855": 71887,
"71856": 71888,
"71857": 71889,
"71858": 71890,
"71859": 71891,
"71860": 71892,
"71861": 71893,
"71862": 71894,
"71863": 71895,
"71864": 71896,
"71865": 71897,
"71866": 71898,
"71867": 71899,
"71868": 71900,
"71869": 71901,
"71870": 71902,
"71871": 71903,
"71872": 71840,
"71873": 71841,
"71874": 71842,
"71875": 71843,
"71876": 71844,
"71877": 71845,
"71878": 71846,
"71879": 71847,
"71880": 71848,
"71881": 71849,
"71882": 71850,
"71883": 71851,
"71884": 71852,
"71885": 71853,
"71886": 71854,
"71887": 71855,
"71888": 71856,
"71889": 71857,
"71890": 71858,
"71891": 71859,
"71892": 71860,
"71893": 71861,
"71894": 71862,
"71895": 71863,
"71896": 71864,
"71897": 71865,
"71898": 71866,
"71899": 71867,
"71900": 71868,
"71901": 71869,
"71902": 71870,
"71903": 71871
}
@@ -0,0 +1,89 @@
{
"_from": "regexpu-core@^1.0.0",
"_id": "regexpu-core@1.0.0",
"_inBundle": false,
"_integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
"_location": "/css-selector-tokenizer/regexpu-core",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "regexpu-core@^1.0.0",
"name": "regexpu-core",
"escapedName": "regexpu-core",
"rawSpec": "^1.0.0",
"saveSpec": null,
"fetchSpec": "^1.0.0"
},
"_requiredBy": [
"/css-selector-tokenizer"
],
"_resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
"_shasum": "86a763f58ee4d7c2f6b102e4764050de7ed90c6b",
"_spec": "regexpu-core@^1.0.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\css-selector-tokenizer",
"author": {
"name": "Mathias Bynens",
"url": "https://mathiasbynens.be/"
},
"bugs": {
"url": "https://github.com/mathiasbynens/regexpu-core/issues"
},
"bundleDependencies": false,
"dependencies": {
"regenerate": "^1.2.1",
"regjsgen": "^0.2.0",
"regjsparser": "^0.1.4"
},
"deprecated": false,
"description": "regexpu’s core functionality (i.e. `rewritePattern(pattern, flag)`), capable of translating ES6 Unicode regular expressions to ES5.",
"devDependencies": {
"coveralls": "^2.11.2",
"istanbul": "^0.4.0",
"jsesc": "^0.5.0",
"lodash": "^3.6.0",
"mocha": "^2.2.1",
"regexpu-fixtures": "^1.0.0",
"unicode-5.1.0": "^0.1.5",
"unicode-8.0.0": "^0.1.5"
},
"files": [
"LICENSE-MIT.txt",
"rewrite-pattern.js",
"data/character-class-escape-sets.js",
"data/iu-mappings.json"
],
"homepage": "https://mths.be/regexpu",
"keywords": [
"codegen",
"desugaring",
"ecmascript",
"es5",
"es6",
"harmony",
"javascript",
"refactoring",
"regex",
"regexp",
"regular expressions",
"rewriting",
"syntax",
"transformation",
"transpile",
"transpiler",
"unicode"
],
"license": "MIT",
"main": "rewrite-pattern.js",
"name": "regexpu-core",
"repository": {
"type": "git",
"url": "git+https://github.com/mathiasbynens/regexpu-core.git"
},
"scripts": {
"build": "node scripts/iu-mappings.js && node scripts/character-class-escape-sets.js",
"coverage": "istanbul cover --report html node_modules/.bin/_mocha tests/tests.js -- -u exports -R spec",
"test": "mocha tests"
},
"version": "1.0.0"
}
@@ -0,0 +1,193 @@
var generate = require('regjsgen').generate;
var parse = require('regjsparser').parse;
var regenerate = require('regenerate');
var iuMappings = require('./data/iu-mappings.json');
var ESCAPE_SETS = require('./data/character-class-escape-sets.js');
function getCharacterClassEscapeSet(character) {
if (unicode) {
if (ignoreCase) {
return ESCAPE_SETS.UNICODE_IGNORE_CASE[character];
}
return ESCAPE_SETS.UNICODE[character];
}
return ESCAPE_SETS.REGULAR[character];
}
var object = {};
var hasOwnProperty = object.hasOwnProperty;
function has(object, property) {
return hasOwnProperty.call(object, property);
}
// Prepare a Regenerate set containing all code points, used for negative
// character classes (if any).
var UNICODE_SET = regenerate().addRange(0x0, 0x10FFFF);
// Without the `u` flag, the range stops at 0xFFFF.
// https://mths.be/es6#sec-pattern-semantics
var BMP_SET = regenerate().addRange(0x0, 0xFFFF);
// Prepare a Regenerate set containing all code points that are supposed to be
// matched by `/./u`. https://mths.be/es6#sec-atom
var DOT_SET_UNICODE = UNICODE_SET.clone() // all Unicode code points
.remove(
// minus `LineTerminator`s (https://mths.be/es6#sec-line-terminators):
0x000A, // Line Feed <LF>
0x000D, // Carriage Return <CR>
0x2028, // Line Separator <LS>
0x2029 // Paragraph Separator <PS>
);
// Prepare a Regenerate set containing all code points that are supposed to be
// matched by `/./` (only BMP code points).
var DOT_SET = DOT_SET_UNICODE.clone()
.intersection(BMP_SET);
// Add a range of code points + any case-folded code points in that range to a
// set.
regenerate.prototype.iuAddRange = function(min, max) {
var $this = this;
do {
var folded = caseFold(min);
if (folded) {
$this.add(folded);
}
} while (++min <= max);
return $this;
};
function assign(target, source) {
for (var key in source) {
// Note: `hasOwnProperty` is not needed here.
target[key] = source[key];
}
}
function update(item, pattern) {
// TODO: Test if memoizing `pattern` here is worth the effort.
if (!pattern) {
return;
}
var tree = parse(pattern, '');
switch (tree.type) {
case 'characterClass':
case 'group':
case 'value':
// No wrapping needed.
break;
default:
// Wrap the pattern in a non-capturing group.
tree = wrap(tree, pattern);
}
assign(item, tree);
}
function wrap(tree, pattern) {
// Wrap the pattern in a non-capturing group.
return {
'type': 'group',
'behavior': 'ignore',
'body': [tree],
'raw': '(?:' + pattern + ')'
};
}
function caseFold(codePoint) {
return has(iuMappings, codePoint) ? iuMappings[codePoint] : false;
}
var ignoreCase = false;
var unicode = false;
function processCharacterClass(characterClassItem) {
var set = regenerate();
var body = characterClassItem.body.forEach(function(item) {
switch (item.type) {
case 'value':
set.add(item.codePoint);
if (ignoreCase && unicode) {
var folded = caseFold(item.codePoint);
if (folded) {
set.add(folded);
}
}
break;
case 'characterClassRange':
var min = item.min.codePoint;
var max = item.max.codePoint;
set.addRange(min, max);
if (ignoreCase && unicode) {
set.iuAddRange(min, max);
}
break;
case 'characterClassEscape':
set.add(getCharacterClassEscapeSet(item.value));
break;
// The `default` clause is only here as a safeguard; it should never be
// reached. Code coverage tools should ignore it.
/* istanbul ignore next */
default:
throw Error('Unknown term type: ' + item.type);
}
});
if (characterClassItem.negative) {
set = (unicode ? UNICODE_SET : BMP_SET).clone().remove(set);
}
update(characterClassItem, set.toString());
return characterClassItem;
}
function processTerm(item) {
switch (item.type) {
case 'dot':
update(
item,
(unicode ? DOT_SET_UNICODE : DOT_SET).toString()
);
break;
case 'characterClass':
item = processCharacterClass(item);
break;
case 'characterClassEscape':
update(
item,
getCharacterClassEscapeSet(item.value).toString()
);
break;
case 'alternative':
case 'disjunction':
case 'group':
case 'quantifier':
item.body = item.body.map(processTerm);
break;
case 'value':
var codePoint = item.codePoint;
var set = regenerate(codePoint);
if (ignoreCase && unicode) {
var folded = caseFold(codePoint);
if (folded) {
set.add(folded);
}
}
update(item, set.toString());
break;
case 'anchor':
case 'empty':
case 'group':
case 'reference':
// Nothing to do here.
break;
// The `default` clause is only here as a safeguard; it should never be
// reached. Code coverage tools should ignore it.
/* istanbul ignore next */
default:
throw Error('Unknown term type: ' + item.type);
}
return item;
};
module.exports = function(pattern, flags) {
var tree = parse(pattern, flags);
ignoreCase = flags ? flags.indexOf('i') > -1 : false;
unicode = flags ? flags.indexOf('u') > -1 : false;
assign(tree, processTerm(tree));
return generate(tree);
};
+20
View File
@@ -0,0 +1,20 @@
Copyright 2014 Benjamin Tan <demoneaux@gmail.com> (https://d10.github.io/)
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.
+60
View File
@@ -0,0 +1,60 @@
# RegJSGen
Generate `RegExp`s from [RegJSParser](https://github.com/jviereck/regjsparser)’s AST.
## Installation
```bash
npm install --save regjsgen
```
## Usage
```js
var regjsgen = require('regjsgen');
// With `regjsparser`
var regjsparser = require('regjsparser');
var regex = '^a$';
var ast = regjsparser.parse(regex);
// Modify AST
// ...
// Regenerate `RegExp`
regex = regjsgen.generate(ast);
```
## See Also
* [RegJSParser](https://github.com/jviereck/regjsparser)
* [RegExp.js](https://github.com/jviereck/regexp.js)
## Testing
Run the command
```bash
npm test
```
To create a new reference file, execute
```bash
node test/update-fixture.js
```
from the repo top directory.
## Support
Tested in Node.js 0.8.26~0.10.30.
## Author
| [![twitter/demoneaux](http://gravatar.com/avatar/029b19dba521584d83398ada3ecf6131?s=70)](https://twitter.com/demoneaux "Follow @demoneaux on Twitter") |
|---|
| [Benjamin Tan](http://d10.github.io/) |
## Contributors
| [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](http://mathiasbynens.be/) |
+76
View File
@@ -0,0 +1,76 @@
{
"_from": "regjsgen@^0.2.0",
"_id": "regjsgen@0.2.0",
"_inBundle": false,
"_integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
"_location": "/css-selector-tokenizer/regjsgen",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "regjsgen@^0.2.0",
"name": "regjsgen",
"escapedName": "regjsgen",
"rawSpec": "^0.2.0",
"saveSpec": null,
"fetchSpec": "^0.2.0"
},
"_requiredBy": [
"/css-selector-tokenizer/regexpu-core"
],
"_resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
"_shasum": "6c016adeac554f75823fe37ac05b92d5a4edb1f7",
"_spec": "regjsgen@^0.2.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\css-selector-tokenizer\\node_modules\\regexpu-core",
"author": {
"name": "Benjamin Tan",
"email": "demoneaux@gmail.com",
"url": "https://d10.github.io/"
},
"bugs": {
"url": "https://github.com/d10/regjsgen/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Benjamin Tan",
"email": "demoneaux@gmail.com",
"url": "https://d10.github.io/"
},
{
"name": "Mathias Bynens",
"email": "mathias@qiwi.be",
"url": "https://mathiasbynens.be/"
}
],
"deprecated": false,
"description": "Generate `RegExp`s from RegJSParser’s AST",
"devDependencies": {
"got": "~1.2.0",
"jsesc": "~0.5.0"
},
"files": [
"LICENSE.txt",
"regjsgen.js",
"README.md"
],
"homepage": "https://github.com/d10/regjsgen",
"keywords": [
"ast",
"generate",
"regex",
"regexp",
"regular expressions"
],
"license": "MIT",
"main": "regjsgen.js",
"name": "regjsgen",
"repository": {
"type": "git",
"url": "git+https://github.com/d10/regjsgen.git"
},
"scripts": {
"test": "node test/test.js"
},
"version": "0.2.0"
}
+408
View File
@@ -0,0 +1,408 @@
/*!
* RegJSGen
* Copyright 2014 Benjamin Tan <https://d10.github.io/>
* Available under MIT license <http://d10.mit-license.org/>
*/
;(function() {
'use strict';
/** Used to determine if values are of the language type `Object` */
var objectTypes = {
'function': true,
'object': true
};
/** Used as a reference to the global object */
var root = (objectTypes[typeof window] && window) || this;
/** Backup possible global object */
var oldRoot = root;
/** Detect free variable `exports` */
var freeExports = objectTypes[typeof exports] && exports;
/** Detect free variable `module` */
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
var freeGlobal = freeExports && freeModule && typeof global == 'object' && global;
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal || freeGlobal.self === freeGlobal)) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
/*! Based on https://mths.be/fromcodepoint v0.2.0 by @mathias */
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
function fromCodePoint() {
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) != codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) {
// BMP code point
codeUnits.push(codePoint);
} else {
// Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 == length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
}
function assertType(type, expected) {
if (expected.indexOf('|') == -1) {
if (type == expected) {
return;
}
throw Error('Invalid node type: ' + type);
}
expected = assertType.hasOwnProperty(expected)
? assertType[expected]
: (assertType[expected] = RegExp('^(?:' + expected + ')$'));
if (expected.test(type)) {
return;
}
throw Error('Invalid node type: ' + type);
}
/*--------------------------------------------------------------------------*/
function generate(node) {
var type = node.type;
if (generate.hasOwnProperty(type) && typeof generate[type] == 'function') {
return generate[type](node);
}
throw Error('Invalid node type: ' + type);
}
/*--------------------------------------------------------------------------*/
function generateAlternative(node) {
assertType(node.type, 'alternative');
var terms = node.body,
length = terms ? terms.length : 0;
if (length == 1) {
return generateTerm(terms[0]);
} else {
var i = -1,
result = '';
while (++i < length) {
result += generateTerm(terms[i]);
}
return result;
}
}
function generateAnchor(node) {
assertType(node.type, 'anchor');
switch (node.kind) {
case 'start':
return '^';
case 'end':
return '$';
case 'boundary':
return '\\b';
case 'not-boundary':
return '\\B';
default:
throw Error('Invalid assertion');
}
}
function generateAtom(node) {
assertType(node.type, 'anchor|characterClass|characterClassEscape|dot|group|reference|value');
return generate(node);
}
function generateCharacterClass(node) {
assertType(node.type, 'characterClass');
var classRanges = node.body,
length = classRanges ? classRanges.length : 0;
var i = -1,
result = '[';
if (node.negative) {
result += '^';
}
while (++i < length) {
result += generateClassAtom(classRanges[i]);
}
result += ']';
return result;
}
function generateCharacterClassEscape(node) {
assertType(node.type, 'characterClassEscape');
return '\\' + node.value;
}
function generateCharacterClassRange(node) {
assertType(node.type, 'characterClassRange');
var min = node.min,
max = node.max;
if (min.type == 'characterClassRange' || max.type == 'characterClassRange') {
throw Error('Invalid character class range');
}
return generateClassAtom(min) + '-' + generateClassAtom(max);
}
function generateClassAtom(node) {
assertType(node.type, 'anchor|characterClassEscape|characterClassRange|dot|value');
return generate(node);
}
function generateDisjunction(node) {
assertType(node.type, 'disjunction');
var body = node.body,
length = body ? body.length : 0;
if (length == 0) {
throw Error('No body');
} else if (length == 1) {
return generate(body[0]);
} else {
var i = -1,
result = '';
while (++i < length) {
if (i != 0) {
result += '|';
}
result += generate(body[i]);
}
return result;
}
}
function generateDot(node) {
assertType(node.type, 'dot');
return '.';
}
function generateGroup(node) {
assertType(node.type, 'group');
var result = '(';
switch (node.behavior) {
case 'normal':
break;
case 'ignore':
result += '?:';
break;
case 'lookahead':
result += '?=';
break;
case 'negativeLookahead':
result += '?!';
break;
default:
throw Error('Invalid behaviour: ' + node.behaviour);
}
var body = node.body,
length = body ? body.length : 0;
if (length == 1) {
result += generate(body[0]);
} else {
var i = -1;
while (++i < length) {
result += generate(body[i]);
}
}
result += ')';
return result;
}
function generateQuantifier(node) {
assertType(node.type, 'quantifier');
var quantifier = '',
min = node.min,
max = node.max;
switch (max) {
case undefined:
case null:
switch (min) {
case 0:
quantifier = '*'
break;
case 1:
quantifier = '+';
break;
default:
quantifier = '{' + min + ',}';
break;
}
break;
default:
if (min == max) {
quantifier = '{' + min + '}';
}
else if (min == 0 && max == 1) {
quantifier = '?';
} else {
quantifier = '{' + min + ',' + max + '}';
}
break;
}
if (!node.greedy) {
quantifier += '?';
}
return generateAtom(node.body[0]) + quantifier;
}
function generateReference(node) {
assertType(node.type, 'reference');
return '\\' + node.matchIndex;
}
function generateTerm(node) {
assertType(node.type, 'anchor|characterClass|characterClassEscape|empty|group|quantifier|reference|value');
return generate(node);
}
function generateValue(node) {
assertType(node.type, 'value');
var kind = node.kind,
codePoint = node.codePoint;
switch (kind) {
case 'controlLetter':
return '\\c' + fromCodePoint(codePoint + 64);
case 'hexadecimalEscape':
return '\\x' + ('00' + codePoint.toString(16).toUpperCase()).slice(-2);
case 'identifier':
return '\\' + fromCodePoint(codePoint);
case 'null':
return '\\' + codePoint;
case 'octal':
return '\\' + codePoint.toString(8);
case 'singleEscape':
switch (codePoint) {
case 0x0008:
return '\\b';
case 0x009:
return '\\t';
case 0x00A:
return '\\n';
case 0x00B:
return '\\v';
case 0x00C:
return '\\f';
case 0x00D:
return '\\r';
default:
throw Error('Invalid codepoint: ' + codePoint);
}
case 'symbol':
return fromCodePoint(codePoint);
case 'unicodeEscape':
return '\\u' + ('0000' + codePoint.toString(16).toUpperCase()).slice(-4);
case 'unicodeCodePointEscape':
return '\\u{' + codePoint.toString(16).toUpperCase() + '}';
default:
throw Error('Unsupported node kind: ' + kind);
}
}
/*--------------------------------------------------------------------------*/
generate.alternative = generateAlternative;
generate.anchor = generateAnchor;
generate.characterClass = generateCharacterClass;
generate.characterClassEscape = generateCharacterClassEscape;
generate.characterClassRange = generateCharacterClassRange;
generate.disjunction = generateDisjunction;
generate.dot = generateDot;
generate.group = generateGroup;
generate.quantifier = generateQuantifier;
generate.reference = generateReference;
generate.value = generateValue;
/*--------------------------------------------------------------------------*/
// export regjsgen
// some AMD build optimizers, like r.js, check for condition patterns like the following:
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
// define as an anonymous module so, through path mapping, it can be aliased
define(function() {
return {
'generate': generate
};
});
}
// check for `exports` after `define` in case a build optimizer adds an `exports` object
else if (freeExports && freeModule) {
// in Narwhal, Node.js, Rhino -require, or RingoJS
freeExports.generate = generate;
}
// in a browser or Rhino
else {
root.regjsgen = {
'generate': generate
};
}
}.call(this));
+12
View File
@@ -0,0 +1,12 @@
2014-08-31: Version 0.1.2
* Change the field ref to matchIndex on the type=refernce node (issue #67)
2014-08-30: Version 0.1.1
* Only handled unicode code point escapes if 'u' flag is set (issue #56)
* Removed `matchIdx` from the AST
* References like /\1/ were broken (issue #57)
* Renamed type `ref` to `reference` in the AST
* Update regex to match identifier and include script to generate regex
2014-06-29: Version 0.1.0
* first tagged release
@@ -0,0 +1,19 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+34
View File
@@ -0,0 +1,34 @@
# RegJSParser
Parsing the JavaScript's RegExp in JavaScript.
## Installation
```bash
npm install regjsparser
```
## Usage
```js
var parse = require('regjsparser').parse;
var parseTree = parse('^a'); // /^a/
console.log(parseTree);
```
## Testing
To run the tests, run the following command:
```bash
npm test
```
To create a new reference file, execute…
```bash
node test/update-fixtures.js
```
…from the repo top directory.
@@ -0,0 +1,50 @@
#!/usr/bin/env node
(function() {
var fs = require('fs');
var parse = require('../parser').parse;
var jsesc = require('jsesc');
var regexes = process.argv.splice(2);
var first = regexes[0];
var data;
var log = console.log;
var main = function() {
if (/^(?:-h|--help|undefined)$/.test(first)) {
log([
'\nUsage:\n',
'\tregjsparser [regex ...]',
'\tregjsparser [-h | --help]',
'\nExamples:\n',
'\tregjsparser \'^foo.bar$\'',
'\tregjsparser \'[a-zA-Z0-9]\''
].join('\n'));
return process.exit(1);
}
regexes.forEach(function(snippet) {
var result;
try {
result = parse(snippet);
log(jsesc(result, {
'json': true,
'compact': false,
'indent': '\t'
}));
} catch(error) {
log(error.message + '\n');
log('Error: failed to parse. Make sure the regular expression is valid.');
log('If you think this is a bug in regjsparser, please report it:');
log('\thttps://github.com/jviereck/regjsparser/issues/new');
log('\nStack trace:\n');
log(error.stack);
return process.exit(1);
}
});
// Return with exit status 0 outside of the `forEach` loop, in case
// multiple regular expressions were passed in.
return process.exit(0);
};
main();
}());
@@ -0,0 +1,63 @@
{
"_from": "regjsparser@^0.1.4",
"_id": "regjsparser@0.1.5",
"_inBundle": false,
"_integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
"_location": "/css-selector-tokenizer/regjsparser",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "regjsparser@^0.1.4",
"name": "regjsparser",
"escapedName": "regjsparser",
"rawSpec": "^0.1.4",
"saveSpec": null,
"fetchSpec": "^0.1.4"
},
"_requiredBy": [
"/css-selector-tokenizer/regexpu-core"
],
"_resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
"_shasum": "7ee8f84dc6fa792d3fd0ae228d24bd949ead205c",
"_spec": "regjsparser@^0.1.4",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\css-selector-tokenizer\\node_modules\\regexpu-core",
"author": {
"name": "'Julian Viereck'",
"email": "julian.viereck@gmail.com"
},
"bin": {
"regjsparser": "bin/parser"
},
"bugs": {
"url": "https://github.com/jviereck/regjsparser/issues"
},
"bundleDependencies": false,
"dependencies": {
"jsesc": "~0.5.0"
},
"deprecated": false,
"description": "Parsing the JavaScript's RegExp in JavaScript.",
"devDependencies": {
"regenerate": "~1.0.1",
"unicode-7.0.0": "~0.1.5"
},
"files": [
"bin/",
"LICENSE.BSD",
"parser.js",
"README.md"
],
"homepage": "https://github.com/jviereck/regjsparser",
"license": "BSD",
"main": "./parser",
"name": "regjsparser",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/jviereck/regjsparser.git"
},
"scripts": {
"test": "node test/index.js"
},
"version": "0.1.5"
}
File diff suppressed because one or more lines are too long
+81
View File
@@ -0,0 +1,81 @@
{
"_from": "css-selector-tokenizer@^0.7.0",
"_id": "css-selector-tokenizer@0.7.1",
"_inBundle": false,
"_integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
"_location": "/css-selector-tokenizer",
"_phantomChildren": {
"regenerate": "1.4.0"
},
"_requested": {
"type": "range",
"registry": true,
"raw": "css-selector-tokenizer@^0.7.0",
"name": "css-selector-tokenizer",
"escapedName": "css-selector-tokenizer",
"rawSpec": "^0.7.0",
"saveSpec": null,
"fetchSpec": "^0.7.0"
},
"_requiredBy": [
"/@vue/cli-service/css-loader",
"/laravel-mix/css-loader",
"/postcss-modules-local-by-default",
"/postcss-modules-scope"
],
"_resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
"_shasum": "a177271a8bca5019172f4f891fc6eed9cbf68d5d",
"_spec": "css-selector-tokenizer@^0.7.0",
"_where": "D:\\Atom\\Git\\Laravel_CSSd\\node_modules\\@vue\\cli-service\\node_modules\\css-loader",
"author": {
"name": "Tobias Koppers @sokra"
},
"bugs": {
"url": "https://github.com/css-modules/css-selector-tokenizer/issues"
},
"bundleDependencies": false,
"dependencies": {
"cssesc": "^0.1.0",
"fastparse": "^1.1.1",
"regexpu-core": "^1.0.0"
},
"deprecated": false,
"description": "Parses and stringifies CSS selectors",
"devDependencies": {
"chokidar-cli": "^0.2.1",
"codecov.io": "^0.1.2",
"coveralls": "^2.11.2",
"eslint": "^0.21.2",
"istanbul": "^0.3.14",
"mocha": "^2.2.5"
},
"directories": {
"test": "test"
},
"files": [
"lib"
],
"homepage": "https://github.com/css-modules/css-selector-tokenizer",
"keywords": [
"css-modules",
"selectors"
],
"license": "MIT",
"main": "lib/index.js",
"name": "css-selector-tokenizer",
"repository": {
"type": "git",
"url": "git+https://github.com/css-modules/css-selector-tokenizer.git"
},
"scripts": {
"autotest": "chokidar lib test -c 'npm test'",
"cover": "istanbul cover node_modules/mocha/bin/_mocha",
"lint": "eslint lib",
"precover": "npm run lint",
"pretest": "npm run lint",
"publish-patch": "npm test && npm version patch && git push && git push --tags && npm publish",
"test": "mocha",
"travis": "npm run cover -- --report lcovonly"
},
"version": "0.7.1"
}