[Pkg-javascript-commits] [node-js-tokens] 01/02: Import Upstream version 2.0.0
Lucas Castro
lucascastro-guest at moszumanska.debian.org
Mon Oct 31 14:19:18 UTC 2016
This is an automated email from the git hooks/post-receive script.
lucascastro-guest pushed a commit to branch master
in repository node-js-tokens.
commit b11771f97a0718ed4f38a5d6f905ce365ff59768
Author: Lucas de Castro Borges <lucas at gnuabordo.com.br>
Date: Mon Oct 31 11:11:02 2016 -0300
Import Upstream version 2.0.0
---
.gitignore | 1 +
.travis.yml | 3 +
LICENSE | 21 ++
changelog.md | 82 +++++
esprima-compare.js | 94 +++++
generate-index.js | 11 +
index.js | 19 +
package.json | 30 ++
readme.md | 217 +++++++++++
regex.coffee | 154 ++++++++
test/fixtures/base64.js | 63 ++++
test/fixtures/base64.json | 63 ++++
test/fixtures/division.js | 37 ++
test/fixtures/division.json | 35 ++
test/fixtures/errors.js | 12 +
test/fixtures/errors.json | 10 +
test/fixtures/regex.js | 41 +++
test/fixtures/regex.json | 43 +++
test/index.js | 868 ++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 1804 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..08b2553
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2197832
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - "node"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..c9a4e1b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014, 2015, 2016 Simon Lydell
+
+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.
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 0000000..b789fdd
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,82 @@
+### Version 2.0.0 (2016-06-19) ###
+
+- Added: Support for ES2016. In other words, support for the `**` exponentiation
+ operator.
+
+These are the breaking changes:
+
+- `'**'.match(jsTokens)` no longer returns `['*', '*']`, but `['**']`.
+- `'**='.match(jsTokens)` no longer returns `['*', '*=']`, but `['**=']`.
+
+
+### Version 1.0.3 (2016-03-27) ###
+
+- Improved: Made the regex ever so slightly smaller.
+- Updated: The readme.
+
+
+### Version 1.0.2 (2015-10-18) ###
+
+- Improved: Limited npm package contents for a smaller download. Thanks to
+ @zertosh!
+
+
+### Version 1.0.1 (2015-06-20) ###
+
+- Fixed: Declared an undeclared variable.
+
+
+### Version 1.0.0 (2015-02-26) ###
+
+- Changed: Merged the 'operator' and 'punctuation' types into 'punctuator'. That
+ type is now equivalent to the Punctuator token in the ECMAScript
+ specification. (Backwards-incompatible change.)
+- Fixed: A `-` followed by a number is now correctly matched as a punctuator
+ followed by a number. It used to be matched as just a number, but there is no
+ such thing as negative number literals. (Possibly backwards-incompatible
+ change.)
+
+
+### Version 0.4.1 (2015-02-21) ###
+
+- Added: Support for the regex `u` flag.
+
+
+### Version 0.4.0 (2015-02-21) ###
+
+- Improved: `jsTokens.matchToToken` performance.
+- Added: Support for octal and binary number literals.
+- Added: Support for template strings.
+
+
+### Version 0.3.1 (2015-01-06) ###
+
+- Fixed: Support for unicode spaces. They used to be allowed in names (which is
+ very confusing), and some unicode newlines were wrongly allowed in strings and
+ regexes.
+
+
+### Version 0.3.0 (2014-12-19) ###
+
+- Changed: The `jsTokens.names` array has been replaced with the
+ `jsTokens.matchToToken` function. The capturing groups of `jsTokens` are no
+ longer part of the public API; instead use said function. See this [gist] for
+ an example. (Backwards-incompatible change.)
+- Changed: The empty string is now considered an “invalid” token, instead an
+ “empty” token (its own group). (Backwards-incompatible change.)
+- Removed: component support. (Backwards-incompatible change.)
+
+[gist]: https://gist.github.com/lydell/be49dbf80c382c473004
+
+
+### Version 0.2.0 (2014-06-19) ###
+
+- Changed: Match ES6 function arrows (`=>`) as an operator, instead of its own
+ category (“functionArrow”), for simplicity. (Backwards-incompatible change.)
+- Added: ES6 splats (`...`) are now matched as an operator (instead of three
+ punctuations). (Backwards-incompatible change.)
+
+
+### Version 0.1.0 (2014-03-08) ###
+
+- Initial release.
diff --git a/esprima-compare.js b/esprima-compare.js
new file mode 100644
index 0000000..e2d23fe
--- /dev/null
+++ b/esprima-compare.js
@@ -0,0 +1,94 @@
+// Copyright 2015 Simon Lydell
+// X11 (“MIT”) Licensed. (See LICENSE.)
+
+var fs = require("fs")
+var esprima = require("esprima")
+var jsTokens = require("./")
+
+
+var typeMap = {
+ Boolean: "name",
+ Identifier: "name",
+ Keyword: "name",
+ Null: "name",
+ Numeric: "number",
+ Punctuator: "punctuator",
+ RegularExpression: "regex",
+ String: "string"
+}
+
+function getEsprimaTokens(code) {
+ var tokens = esprima.tokenize(code, {loc: true})
+ tokens.forEach(function(token) { token.type = typeMap[token.type] })
+ return tokens
+}
+
+
+function jsTokensTokenize(string) {
+ jsTokens.lastIndex = 0
+ if (string === "") return []
+ var tokens = []
+ var match
+ while (match = jsTokens.exec(string)) {
+ tokens.push(jsTokens.matchToToken(match))
+ }
+ return tokens
+}
+
+var exclusionMap = {
+ comment: true,
+ whitespace: true
+}
+
+function getJsTokensTokens(code) {
+ return jsTokensTokenize(code)
+ .filter(function(token) { return !exclusionMap.hasOwnProperty(token.type) })
+}
+
+
+function compare(file) {
+ var code = fs.readFileSync(require.resolve(file)).toString()
+ var esprimaTokens = getEsprimaTokens(code)
+ var jsTokensTokens = getJsTokensTokens(code)
+
+ var length = Math.min(esprimaTokens.length, jsTokensTokens.length)
+ for (var index = 0; index < length; index++) {
+ var esprimaToken = esprimaTokens[index]
+ var jsTokensToken = jsTokensTokens[index]
+ if (
+ esprimaToken.type !== jsTokensToken.type ||
+ esprimaToken.value !== jsTokensToken.value
+ ) {
+ var loc = esprimaToken.loc.start
+ console.error(
+ file + ":" + loc.line + ":" + (loc.column + 1) + ": " +
+ "(token #" + (index + 1) + ")\n" +
+ " esprima: '" + esprimaToken.type + "': " + esprimaToken.value + "\n" +
+ " jsTokens: '" + jsTokensToken.type + "': " + jsTokensToken.value
+ )
+ return false
+ }
+ }
+
+ if (esprimaTokens.length !== jsTokensTokens.length) {
+ console.error(
+ file + ': Number of tokens mismatch.\n' +
+ " esprima: " + (esprimaTokens.length + 1) + "\n" +
+ " jsTokens: " + (jsTokensTokens.length + 1)
+ )
+ return false
+ }
+
+ return true
+}
+
+
+var results = process.argv.slice(2).map(compare)
+
+if (results.every(Boolean)) {
+ console.log(
+ "Comparison succeeded: esprima and jsTokens produced the same tokens!"
+ )
+} else {
+ console.error("Comparison failed.")
+}
diff --git a/generate-index.js b/generate-index.js
new file mode 100644
index 0000000..6963f4b
--- /dev/null
+++ b/generate-index.js
@@ -0,0 +1,11 @@
+// Copyright 2014 Simon Lydell
+// X11 (“MIT”) Licensed. (See LICENSE.)
+
+var fs = require("fs")
+
+require("coffee-script/register")
+var regex = require("./regex.coffee")
+
+var code = fs.readFileSync("index.js").toString()
+code = code.replace(/\/.+\/.+/, regex.toString())
+fs.writeFileSync("index.js", code)
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..2e07040
--- /dev/null
+++ b/index.js
@@ -0,0 +1,19 @@
+// Copyright 2014, 2015, 2016 Simon Lydell
+// X11 (“MIT”) Licensed. (See LICENSE.)
+
+// This regex comes from regex.coffee, and is inserted here by generate-index.js
+// (run `npm run build`).
+module.exports = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{ [...]
+
+module.exports.matchToToken = function(match) {
+ var token = {type: "invalid", value: match[0]}
+ if (match[ 1]) token.type = "string" , token.closed = !!(match[3] || match[4])
+ else if (match[ 5]) token.type = "comment"
+ else if (match[ 6]) token.type = "comment", token.closed = !!match[7]
+ else if (match[ 8]) token.type = "regex"
+ else if (match[ 9]) token.type = "number"
+ else if (match[10]) token.type = "name"
+ else if (match[11]) token.type = "punctuator"
+ else if (match[12]) token.type = "whitespace"
+ return token
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..35b0d86
--- /dev/null
+++ b/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "js-tokens",
+ "version": "2.0.0",
+ "author": "Simon Lydell",
+ "license": "MIT",
+ "description": "A regex that tokenizes JavaScript.",
+ "keywords": [
+ "JavaScript",
+ "js",
+ "token",
+ "tokenize",
+ "regex"
+ ],
+ "files": [
+ "index.js"
+ ],
+ "repository": "lydell/js-tokens",
+ "scripts": {
+ "test": "mocha --ui tdd",
+ "esprima-compare": "node esprima-compare ./index.js everything.js/es5.js",
+ "build": "node generate-index.js",
+ "dev": "npm run build && npm test"
+ },
+ "devDependencies": {
+ "coffee-script": "~1.10.0",
+ "esprima": "^2.7.2",
+ "everything.js": "^1.0.3",
+ "mocha": "^2.5.3"
+ }
+}
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..68e470f
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,217 @@
+Overview [![Build Status](https://travis-ci.org/lydell/js-tokens.png?branch=master)](https://travis-ci.org/lydell/js-tokens)
+========
+
+A regex that tokenizes JavaScript.
+
+```js
+var jsTokens = require("js-tokens")
+
+var jsString = "var foo=opts.foo;\n..."
+
+jsString.match(jsTokens)
+// ["var", " ", "foo", "=", "opts", ".", "foo", ";", "\n", ...]
+```
+
+
+Installation
+============
+
+`npm install js-tokens`
+
+```js
+var jsTokens = require("js-tokens")
+```
+
+
+Usage
+=====
+
+### `jsTokens` ###
+
+A regex with the `g` flag that matches JavaScript tokens.
+
+The regex _always_ matches, even invalid JavaScript and the empty string.
+
+The next match is always directly after the previous.
+
+### `var token = jsTokens.matchToToken(match)` ###
+
+Takes a `match` returned by `jsTokens.exec(string)`, and returns a `{type:
+String, value: String}` object. The following types are available:
+
+- string
+- comment
+- regex
+- number
+- name
+- punctuator
+- whitespace
+- invalid
+
+Multi-line comments and strings also have a `closed` property indicating if the
+token was closed or not (see below).
+
+Comments and strings both come in several flavors. To distinguish them, check if
+the token starts with `//`, `/*`, `'`, `"` or `` ` ``.
+
+Names are ECMAScript IdentifierNames, that is, including both identifiers and
+keywords. You may use [is-keyword-js] to tell them apart.
+
+Whitespace includes both line terminators and other whitespace.
+
+For example usage, please see this [gist].
+
+[is-keyword-js]: https://github.com/crissdev/is-keyword-js
+[gist]: https://gist.github.com/lydell/be49dbf80c382c473004
+
+
+ECMAScript support
+==================
+
+The intention is to always support the latest stable ECMAScript version.
+
+If adding support for a newer version requires changes, a new version with a
+major verion bump will be released.
+
+Currently, [ECMAScript 2016] is supported.
+
+[ECMAScript 2016]: http://www.ecma-international.org/ecma-262/7.0/index.html
+
+
+Invalid code handling
+=====================
+
+Unterminated strings are still matched as strings. JavaScript strings cannot
+contain (unescaped) newlines, so unterminated strings simply end at the end of
+the line. Unterminated template strings can contain unescaped newlines, though,
+so they go on to the end of input.
+
+Unterminated multi-line comments are also still matched as comments. They
+simply go on to the end of the input.
+
+Unterminated regex literals are likely matched as division and whatever is
+inside the regex.
+
+Invalid ASCII characters have their own capturing group.
+
+Invalid non-ASCII characters are treated as names, to simplify the matching of
+names (except unicode spaces which are treated as whitespace).
+
+Regex literals may contain invalid regex syntax. They are still matched as
+regex literals. They may also contain repeated regex flags, to keep the regex
+simple.
+
+Strings may contain invalid escape sequences.
+
+
+Limitations
+===========
+
+Tokenizing JavaScript using regexes—in fact, _one single regex_—won’t be
+perfect. But that’s not the point either.
+
+You may compare jsTokens with [esprima] by using `esprima-compare.js`.
+See `npm run esprima-compare`!
+
+[esprima]: http://esprima.org/
+
+### Template string interpolation ###
+
+Template strings are matched as single tokens, from the starting `` ` `` to the
+ending `` ` ``, including interpolations (whose tokens are not matched
+individually).
+
+Matching template string interpolations requires recursive balancing of `{` and
+`}`—something that JavaScript regexes cannot do. Only one level of nesting is
+supported.
+
+### Division and regex literals collision ###
+
+Consider this example:
+
+```js
+var g = 9.82
+var number = bar / 2/g
+
+var regex = / 2/g
+```
+
+A human can easily understand that in the `number` line we’re dealing with
+division, and in the `regex` line we’re dealing with a regex literal. How come?
+Because humans can look at the whole code to put the `/` characters in context.
+A JavaScript regex cannot. It only sees forwards.
+
+When the `jsTokens` regex scans throught the above, it will see the following
+at the end of both the `number` and `regex` rows:
+
+```js
+/ 2/g
+```
+
+It is then impossible to know if that is a regex literal, or part of an
+expression dealing with division.
+
+Here is a similar case:
+
+```js
+foo /= 2/g
+foo(/= 2/g)
+```
+
+The first line divides the `foo` variable with `2/g`. The second line calls the
+`foo` function with the regex literal `/= 2/g`. Again, since `jsTokens` only
+sees forwards, it cannot tell the two cases apart.
+
+There are some cases where we _can_ tell division and regex literals apart,
+though.
+
+First off, we have the simple cases where there’s only one slash in the line:
+
+```js
+var foo = 2/g
+foo /= 2
+```
+
+Regex literals cannot contain newlines, so the above cases are correctly
+identified as division. Things are only problematic when there are more than
+one non-comment slash in a single line.
+
+Secondly, not every character is a valid regex flag.
+
+```js
+var number = bar / 2/e
+```
+
+The above example is also correctly identified as division, because `e` is not a
+valid regex flag. I initially wanted to future-proof by allowing `[a-zA-Z]*`
+(any letter) as flags, but it is not worth it since it increases the amount of
+ambigous cases. So only the standard `g`, `m`, `i`, `y` and `u` flags are
+allowed. This means that the above example will be identified as division as
+long as you don’t rename the `e` variable to some permutation of `gmiyu` 1 to 5
+characters long.
+
+Lastly, we can look _forward_ for information.
+
+- If the token following what looks like a regex literal is not valid after a
+ regex literal, but is valid in a division expression, then the regex literal
+ is treated as division instead. For example, a flagless regex cannot be
+ followed by a string, number or name, but all of those three can be the
+ denominator of a division.
+- Generally, if what looks like a regex literal is followed by an operator, the
+ regex literal is treated as division instead. This is because regexes are
+ seldomly used with operators (such as `+`, `*`, `&&` and `==`), but division
+ could likely be part of such an expression.
+
+Please consult the regex source and the test cases for precise information on
+when regex or division is matched (should you need to know). In short, you
+could sum it up as:
+
+If the end of a statement looks like a regex literal (even if it isn’t), it
+will be treated as one. Otherwise it should work as expected (if you write sane
+code).
+
+
+License
+=======
+
+[The X11 (“MIT”) License](LICENSE).
diff --git a/regex.coffee b/regex.coffee
new file mode 100644
index 0000000..751586c
--- /dev/null
+++ b/regex.coffee
@@ -0,0 +1,154 @@
+# Copyright 2014, 2015, 2016 Simon Lydell
+# X11 (“MIT”) Licensed. (See LICENSE.)
+
+# <http://www.ecma-international.org/ecma-262/7.0/index.html#sec-ecmascript-language-lexical-grammar>
+
+# Don’t worry, you don’t need to know CoffeeScript. It is only used for its
+# readable regex syntax. Everything else is done in JavaScript in index.js.
+
+module.exports = ///
+ ( # <string>
+ ([ ' " ])
+ (?:
+ (?! \2 | \\ ).
+ |
+ \\(?: \r\n | [\s\S] )
+ )*
+ (\2)?
+ |
+ `
+ (?:
+ [^ ` \\ $ ]
+ |
+ \\[\s\S]
+ |
+ \$(?!\{)
+ |
+ \$\{
+ (?:
+ [^{}]
+ |
+ \{ [^}]* \}?
+ )*
+ \}?
+ )*
+ (`)?
+ )
+ |
+ ( # <comment>
+ //.*
+ )
+ |
+ ( # <comment>
+ /\*
+ (?:
+ [^*]
+ |
+ \*(?!/)
+ )*
+ ( \*/ )?
+ )
+ |
+ ( # <regex>
+ /(?!\*)
+ (?:
+ \[
+ (?:
+ (?![ \] \\ ]).
+ |
+ \\.
+ )*
+ \]
+ |
+ (?![ / \] \\ ]).
+ |
+ \\.
+ )+
+ /
+ (?:
+ (?!
+ \s*
+ (?:
+ \b
+ |
+ [ \u0080-\uFFFF $ \\ ' " ~ ( { ]
+ |
+ [ + \- ! ](?!=)
+ |
+ \.?\d
+ )
+ )
+ |
+ [ g m i y u ]{1,5} \b
+ (?!
+ [ \u0080-\uFFFF $ \\ ]
+ |
+ \s*
+ (?:
+ [ + \- * % & | ^ < > ! = ? ( { ]
+ |
+ /(?! [ / * ] )
+ )
+ )
+ )
+ )
+ |
+ ( # <number>
+ 0[xX][ \d a-f A-F ]+
+ |
+ 0[oO][0-7]+
+ |
+ 0[bB][01]+
+ |
+ (?:
+ \d*\.\d+
+ |
+ \d+\.? # Support one trailing dot for integers only.
+ )
+ (?: [eE][+-]?\d+ )?
+ )
+ |
+ ( # <name>
+ # See <http://mathiasbynens.be/notes/javascript-identifiers>.
+ (?!\d)
+ (?:
+ (?!\s)[ $ \w \u0080-\uFFFF ]
+ |
+ \\u[ \d a-f A-F ]{4}
+ |
+ \\u\{[ \d a-f A-F ]{1,6}\}
+ )+
+ )
+ |
+ ( # <punctuator>
+ -- | \+\+
+ |
+ && | \|\|
+ |
+ =>
+ |
+ \.{3}
+ |
+ (?:
+ [ + \- / % & | ^ ]
+ |
+ \*{1,2}
+ |
+ <{1,2} | >{1,3}
+ |
+ !=? | ={1,2}
+ )=?
+ |
+ [ ? ~ . , : ; [ \] ( ) { } ]
+ )
+ |
+ ( # <whitespace>
+ \s+
+ )
+ |
+ ( # <invalid>
+ ^$ # Empty.
+ |
+ [\s\S] # Catch-all rule for anything not matched by the above.
+ )
+///g
diff --git a/test/fixtures/base64.js b/test/fixtures/base64.js
new file mode 100644
index 0000000..22c2bb6
--- /dev/null
+++ b/test/fixtures/base64.js
@@ -0,0 +1,63 @@
+/*
+ * https://github.com/davidchambers/Base64.js
+ */
+;(function () {
+
+ var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
+ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ function InvalidCharacterError(message) {
+ this.message = message;
+ }
+ InvalidCharacterError.prototype = new Error;
+ InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+ // encoder
+ // [https://gist.github.com/999166] by [https://github.com/nignag]
+ object.btoa || (
+ object.btoa = function (input) {
+ for (
+ // initialize result and counter
+ var block, charCode, idx = 0, map = chars, output = '';
+ // if the next input index does not exist:
+ // change the mapping table to "="
+ // check if d has no fractional digits
+ input.charAt(idx | 0) || (map = '=', idx % 1);
+ // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
+ output += map.charAt(63 & block >> 8 - idx % 1 * 8)
+ ) {
+ charCode = input.charCodeAt(idx += 3/4);
+ if (charCode > 0xFF) {
+ throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
+ }
+ block = block << 8 | charCode;
+ }
+ return output;
+ });
+
+ // decoder
+ // [https://gist.github.com/1020396] by [https://github.com/atk]
+ object.atob || (
+ object.atob = function (input) {
+ input = input.replace(/=+$/, '')
+ if (input.length % 4 == 1) {
+ throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
+ }
+ for (
+ // initialize result and counters
+ var bc = 0, bs, buffer, idx = 0, output = '';
+ // get next character
+ buffer = input.charAt(idx++);
+ // character found in table? initialize bit storage and add its ascii value;
+ ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
+ // and if not first of each 4 characters,
+ // convert the first 8 bits to one ascii character
+ bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
+ ) {
+ // try to find character in table (0-63, not found => -1)
+ buffer = chars.indexOf(buffer);
+ }
+ return output;
+ });
+
+}());
diff --git a/test/fixtures/base64.json b/test/fixtures/base64.json
new file mode 100644
index 0000000..fd3982a
--- /dev/null
+++ b/test/fixtures/base64.json
@@ -0,0 +1,63 @@
+[
+"/*\n * https://github.com/davidchambers/Base64.js\n */","\n",
+";","(","function"," ","(",")"," ","{","\n\n ",
+
+"var"," ","object"," ","="," ","typeof"," ","exports"," ","!="," ","'undefined'"," ","?"," ","exports"," ",":"," ","this",";"," ","// #8: web workers","\n ",
+"var"," ","chars"," ","="," ","'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='",";","\n\n ",
+
+"function"," ","InvalidCharacterError","(","message",")"," ","{","\n ",
+"this",".","message"," ","="," ","message",";","\n ",
+"}","\n ",
+"InvalidCharacterError",".","prototype"," ","="," ","new"," ","Error",";","\n ",
+"InvalidCharacterError",".","prototype",".","name"," ","="," ","'InvalidCharacterError'",";","\n\n ",
+
+"// encoder","\n ",
+"// [https://gist.github.com/999166] by [https://github.com/nignag]","\n ",
+"object",".","btoa"," ","||"," ","(","\n ",
+"object",".","btoa"," ","="," ","function"," ","(","input",")"," ","{","\n ",
+"for"," ","(","\n ",
+"// initialize result and counter","\n ",
+"var"," ","block",","," ","charCode",","," ","idx"," ","="," ","0",","," ","map"," ","="," ","chars",","," ","output"," ","="," ","''",";","\n ",
+"// if the next input index does not exist:","\n ",
+"// change the mapping table to \"=\"","\n ",
+"// check if d has no fractional digits","\n ",
+"input",".","charAt","(","idx"," ","|"," ","0",")"," ","||"," ","(","map"," ","="," ","'='",","," ","idx"," ","%"," ","1",")",";","\n ",
+"// \"8 - idx % 1 * 8\" generates the sequence 2, 4, 6, 8","\n ",
+"output"," ","+="," ","map",".","charAt","(","63"," ","&"," ","block"," ",">>"," ","8"," ","-"," ","idx"," ","%"," ","1"," ","*"," ","8",")","\n ",
+")"," ","{","\n ",
+"charCode"," ","="," ","input",".","charCodeAt","(","idx"," ","+="," ","3","/","4",")",";","\n ",
+"if"," ","(","charCode"," ",">"," ","0xFF",")"," ","{","\n ",
+"throw"," ","new"," ","InvalidCharacterError","(","\"'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.\"",")",";","\n ",
+"}","\n ",
+"block"," ","="," ","block"," ","<<"," ","8"," ","|"," ","charCode",";","\n ",
+"}","\n ",
+"return"," ","output",";","\n ",
+"}",")",";","\n\n ",
+
+"// decoder","\n ",
+"// [https://gist.github.com/1020396] by [https://github.com/atk]","\n ",
+"object",".","atob"," ","||"," ","(","\n ",
+"object",".","atob"," ","="," ","function"," ","(","input",")"," ","{","\n ",
+"input"," ","="," ","input",".","replace","(","/=+$/",","," ","''",")","\n ",
+"if"," ","(","input",".","length"," ","%"," ","4"," ","=="," ","1",")"," ","{","\n ",
+"throw"," ","new"," ","InvalidCharacterError","(","\"'atob' failed: The string to be decoded is not correctly encoded.\"",")",";","\n ",
+"}","\n ",
+"for"," ","(","\n ",
+"// initialize result and counters","\n ",
+"var"," ","bc"," ","="," ","0",","," ","bs",","," ","buffer",","," ","idx"," ","="," ","0",","," ","output"," ","="," ","''",";","\n ",
+"// get next character","\n ",
+"buffer"," ","="," ","input",".","charAt","(","idx","++",")",";","\n ",
+"// character found in table? initialize bit storage and add its ascii value;","\n ",
+"~","buffer"," ","&&"," ","(","bs"," ","="," ","bc"," ","%"," ","4"," ","?"," ","bs"," ","*"," ","64"," ","+"," ","buffer"," ",":"," ","buffer",",","\n ",
+"// and if not first of each 4 characters,","\n ",
+"// convert the first 8 bits to one ascii character","\n ",
+"bc","++"," ","%"," ","4",")"," ","?"," ","output"," ","+="," ","String",".","fromCharCode","(","255"," ","&"," ","bs"," ",">>"," ","(","-","2"," ","*"," ","bc"," ","&"," ","6",")",")"," ",":"," ","0","\n ",
+")"," ","{","\n ",
+"// try to find character in table (0-63, not found => -1)","\n ",
+"buffer"," ","="," ","chars",".","indexOf","(","buffer",")",";","\n ",
+"}","\n ",
+"return"," ","output",";","\n ",
+"}",")",";","\n\n",
+
+"}","(",")",")",";","\n"
+]
diff --git a/test/fixtures/division.js b/test/fixtures/division.js
new file mode 100644
index 0000000..89294a4
--- /dev/null
+++ b/test/fixtures/division.js
@@ -0,0 +1,37 @@
+foo = 1/a/2
+foo = 1/a/
+ 2
+foo = 1/a/(b+1)
+foo = 1/a/~bar.indexOf(baz)
+foo = 1/a/+str
+foo = 1/a/-1
+foo = 1/a/-bar
+foo = 1/a/--bar
+foo = 1/a/
+ --bar
+foo = 1/a/ ++bar
+
+foo = 1/a/g+1
+foo = 1/a/g - 1
+foo = 1/a/g*1
+foo = 1/a/g/1
+foo = 1/a/g
+ /1
+
+if (1/a/g && foo) {}
+if (1/a/g
+ && foo) {}
+if (1/a/g || foo) {}
+if (1/a/g === 3) {}
+
+foo = 1/a/g ? true : false
+
+nan = 1/a/''
+nan = 1/a/ ""
+
+foo = 1/a/goo
+foo = 1/a/iff
+foo = 1/a/igor
+foo = 1/a/moo
+foo = 1/a/yüm
+foo = 1/a/imgyp
diff --git a/test/fixtures/division.json b/test/fixtures/division.json
new file mode 100644
index 0000000..7e87be9
--- /dev/null
+++ b/test/fixtures/division.json
@@ -0,0 +1,35 @@
+[
+"foo"," ","="," ","1","/","a","/","2","\n",
+"foo"," ","="," ","1","/","a","/","\n ","2","\n",
+"foo"," ","="," ","1","/","a","/","(","b","+","1",")","\n",
+"foo"," ","="," ","1","/","a","/","~","bar",".","indexOf","(","baz",")","\n",
+"foo"," ","="," ","1","/","a","/","+","str","\n",
+"foo"," ","="," ","1","/","a","/","-","1","\n",
+"foo"," ","="," ","1","/","a","/","-","bar","\n",
+"foo"," ","="," ","1","/","a","/","--","bar","\n",
+"foo"," ","="," ","1","/","a","/","\n ","--","bar","\n",
+"foo"," ","="," ","1","/","a","/"," ","++","bar","\n\n",
+
+"foo"," ","="," ","1","/","a","/","g","+","1","\n",
+"foo"," ","="," ","1","/","a","/","g"," ","-"," ","1","\n",
+"foo"," ","="," ","1","/","a","/","g","*","1","\n",
+"foo"," ","="," ","1","/","a","/","g","/","1","\n",
+"foo"," ","="," ","1","/","a","/","g","\n ","/","1","\n\n",
+
+"if"," ","(","1","/","a","/","g"," ","&&"," ","foo",")"," ","{","}","\n",
+"if"," ","(","1","/","a","/","g","\n ","&&"," ","foo",")"," ","{","}","\n",
+"if"," ","(","1","/","a","/","g"," ","||"," ","foo",")"," ","{","}","\n",
+"if"," ","(","1","/","a","/","g"," ","==="," ","3",")"," ","{","}","\n\n",
+
+"foo"," ","="," ","1","/","a","/","g"," ","?"," ","true"," ",":"," ","false","\n\n",
+
+"nan"," ","="," ","1","/","a","/","''","\n",
+"nan"," ","="," ","1","/","a","/"," ","\"\"","\n\n",
+
+"foo"," ","="," ","1","/","a","/","goo","\n",
+"foo"," ","="," ","1","/","a","/","iff","\n",
+"foo"," ","="," ","1","/","a","/","igor","\n",
+"foo"," ","="," ","1","/","a","/","moo","\n",
+"foo"," ","="," ","1","/","a","/","yüm","\n",
+"foo"," ","="," ","1","/","a","/","imgyp","\n"
+]
diff --git a/test/fixtures/errors.js b/test/fixtures/errors.js
new file mode 100644
index 0000000..0ccb6c2
--- /dev/null
+++ b/test/fixtures/errors.js
@@ -0,0 +1,12 @@
+var multiLineString = '\
+While I was writing along\
+I suddenly forgot to
+add a backslash @ the end of a line'
+
+var unterminatedRegex = /3?2:1
+
+# Oops, forgot that this isn’t coffee-script.
+
+/* Let’s try a valid JavaScript comment instead
+
+var string='Pity I forgot to close it, though'
diff --git a/test/fixtures/errors.json b/test/fixtures/errors.json
new file mode 100644
index 0000000..6806781
--- /dev/null
+++ b/test/fixtures/errors.json
@@ -0,0 +1,10 @@
+[
+"var"," ","multiLineString"," ","="," ","'\\\nWhile I was writing along\\\nI suddenly forgot to","\n",
+"add"," ","a"," ","backslash"," ","@"," ","the"," ","end"," ","of"," ","a"," ","line","'","\n\n",
+
+"var"," ","unterminatedRegex"," ","="," ","/","3","?","2",":","1","\n\n",
+
+"#"," ","Oops",","," ","forgot"," ","that"," ","this"," ","isn’t"," ","coffee","-","script",".","\n\n",
+
+"/* Let’s try a valid JavaScript comment instead\n\nvar string='Pity I forgot to close it, though'\n"
+]
diff --git a/test/fixtures/regex.js b/test/fixtures/regex.js
new file mode 100644
index 0000000..83defa4
--- /dev/null
+++ b/test/fixtures/regex.js
@@ -0,0 +1,41 @@
+foo(/a/)
+foo(/a/g)
+foo( /a/ )
+foo( /a/g )
+foo(/a/, bar)
+foo(/a/g, bar)
+foo(/a/, /a/g, /b/g, /b/)
+
+arr = [/a/]
+arr = [/a/g]
+arr = [ /a/ ]
+arr = [ /a/g ]
+
+obj = {re: /a/}
+obj = {re: /a/g}
+obj = { re: /a/ }
+obj = { re: /a/g }
+
+re = foo ? /a/ : RegExp(bar)
+re = foo ? /a/g : RegExp(bar)
+
+/a/.exec(foo)
+/a/g.exec(foo)
+
+foo = (1/2) + /a/.exec(bar)[0]
+foo = (1/2) + /a/g.exec(bar)[0]
+
+re = /a/// comment
+re = /a/g// comment
+re = /a//* comment */
+re = /a/g/* comment */
+
+re = /a/ // comment
+re = /a/g // comment
+re = /a/ /* comment */
+re = /a/g /* comment */
+
+silly = /a/ ? true : false
+if (/a/ == "/a/") {}
+if (/a/ && foo) {}
+if (/a/ || foo) {}
diff --git a/test/fixtures/regex.json b/test/fixtures/regex.json
new file mode 100644
index 0000000..154c641
--- /dev/null
+++ b/test/fixtures/regex.json
@@ -0,0 +1,43 @@
+[
+"foo","(","/a/",")","\n",
+"foo","(","/a/g",")","\n",
+"foo","("," ","/a/"," ",")","\n",
+"foo","("," ","/a/g"," ",")","\n",
+"foo","(","/a/",","," ","bar",")","\n",
+"foo","(","/a/g",","," ","bar",")","\n",
+"foo","(","/a/",","," ","/a/g",","," ","/b/g",","," ","/b/",")","\n\n",
+
+"arr"," ","="," ","[","/a/","]","\n",
+"arr"," ","="," ","[","/a/g","]","\n",
+"arr"," ","="," ","["," ","/a/"," ","]","\n",
+"arr"," ","="," ","["," ","/a/g"," ","]","\n\n",
+
+"obj"," ","="," ","{","re",":"," ","/a/","}","\n",
+"obj"," ","="," ","{","re",":"," ","/a/g","}","\n",
+"obj"," ","="," ","{"," ","re",":"," ","/a/"," ","}","\n",
+"obj"," ","="," ","{"," ","re",":"," ","/a/g"," ","}","\n\n",
+
+"re"," ","="," ","foo"," ","?"," ","/a/"," ",":"," ","RegExp","(","bar",")","\n",
+"re"," ","="," ","foo"," ","?"," ","/a/g"," ",":"," ","RegExp","(","bar",")","\n\n",
+
+"/a/",".","exec","(","foo",")","\n",
+"/a/g",".","exec","(","foo",")","\n\n",
+
+"foo"," ","="," ","(","1","/","2",")"," ","+"," ","/a/",".","exec","(","bar",")","[","0","]","\n",
+"foo"," ","="," ","(","1","/","2",")"," ","+"," ","/a/g",".","exec","(","bar",")","[","0","]","\n\n",
+
+"re"," ","="," ","/a/","// comment","\n",
+"re"," ","="," ","/a/g","// comment","\n",
+"re"," ","="," ","/a/","/* comment */","\n",
+"re"," ","="," ","/a/g","/* comment */","\n\n",
+
+"re"," ","="," ","/a/"," ","// comment","\n",
+"re"," ","="," ","/a/g"," ","// comment","\n",
+"re"," ","="," ","/a/"," ","/* comment */","\n",
+"re"," ","="," ","/a/g"," ","/* comment */","\n\n",
+
+"silly"," ","="," ","/a/"," ","?"," ","true"," ",":"," ","false","\n",
+"if"," ","(","/a/"," ","=="," ","\"/a/\"",")"," ","{","}","\n",
+"if"," ","(","/a/"," ","&&"," ","foo",")"," ","{","}","\n",
+"if"," ","(","/a/"," ","||"," ","foo",")"," ","{","}","\n"
+]
diff --git a/test/index.js b/test/index.js
new file mode 100644
index 0000000..392f5ed
--- /dev/null
+++ b/test/index.js
@@ -0,0 +1,868 @@
+// Copyright 2014, 2015, 2016 Simon Lydell
+// X11 (“MIT”) Licensed. (See LICENSE.)
+
+var fs = require("fs")
+var util = require("util")
+var assert = require("assert")
+var jsTokens = require("../")
+
+
+suite("jsTokens", function() {
+
+ test("is a regex", function() {
+ assert(util.isRegExp(jsTokens))
+ })
+
+})
+
+
+suite("jsTokens.matchToToken", function() {
+
+ test("is a function", function() {
+ assert.equal(typeof jsTokens.matchToToken, "function")
+ })
+
+})
+
+
+suite("tokens", function() {
+
+ function token(name, fn) {
+ suite(name, fn.bind(null, matchHelper.bind(null, name)))
+ }
+
+ function matchHelper(type, string, expected, extra) {
+ extra = extra || {}
+ if (typeof expected === "object") {
+ extra = expected
+ expected = undefined
+ }
+ jsTokens.lastIndex = 0
+ var token = jsTokens.matchToToken(jsTokens.exec(string))
+
+ test(string, function() {
+ if (expected === false) {
+ assert.notEqual(token.type, type)
+ } else {
+ assert.equal(token.type, type)
+ assert.equal(
+ token.value,
+ (typeof expected === "string" ? expected : string)
+ )
+ if ("closed" in extra) {
+ assert.equal(token.closed, extra.closed)
+ } else if (type === "string") {
+ assert.equal(token.closed, true)
+ }
+ }
+ })
+ }
+
+
+ token("whitespace", function(match) {
+
+ match(" ")
+ match(" ")
+ match(" a", " ")
+ match("\t")
+ match("\t\t\t")
+ match("\ta", "\t")
+ match("\n")
+ match("\n\n\n")
+ match("\na", "\n")
+ match("\r")
+ match("\r\r\r")
+ match("\ra", "\r")
+ match(" \t\n\r \r\n")
+ match(" \t\n\r \r\n-1", " \t\n\r \r\n")
+ match("\f")
+ match("\v")
+
+ match("\u00a0")
+ match("\u1680")
+ match("\u180e")
+ match("\u2000")
+ match("\u2001")
+ match("\u2002")
+ match("\u2003")
+ match("\u2004")
+ match("\u2005")
+ match("\u2006")
+ match("\u2007")
+ match("\u2008")
+ match("\u2009")
+ match("\u200a")
+ match("\u2028")
+ match("\u2029")
+ match("\u202f")
+ match("\u205f")
+ match("\u3000")
+
+ })
+
+
+ token("comment", function(match) {
+
+ match("//")
+ match("//comment")
+ match("// comment")
+ match("//comment ")
+ match("///")
+ match("//**//")
+ match("//comment\n", "//comment")
+ match("//comment\r", "//comment")
+ match("//comment\u2028", "//comment")
+ match("//comment\u2029", "//comment")
+ match("//comment\r\n", "//comment")
+ match("//comment \n", "//comment ")
+ match("//comment\t\n", "//comment\t")
+
+ match("/**/", {closed: true})
+ match("/*comment*/", {closed: true})
+ match("/* comment */", {closed: true})
+ match("/***/", {closed: true})
+ match("/*/*/", {closed: true})
+ match("/*\n\r\u2028\u2029 \r\n*/", {closed: true})
+
+ match("/*", {closed: false})
+ match("/*/", {closed: false})
+ match("/*unclosed", {closed: false})
+ match("/*unclosed\nnew Line(this == code ? true : false)", {closed: false})
+
+ })
+
+
+ token("string", function(match) {
+
+ match("''")
+ match('""')
+ match("``")
+ match("'string'")
+ match('"string"')
+ match("`string`")
+ match("'\\''")
+ match('"\\""')
+ match("`\\``")
+ match("'\\\\''", "'\\\\'")
+ match('"\\\\""', '"\\\\"')
+ match("`\\\\``", "`\\\\`")
+ match("'\\\\\\''")
+ match('"\\\\\\""')
+ match("`\\\\\\``")
+ match("'\\u05aF'")
+ match('"\\u05aF"')
+ match("`\\u05aF`")
+ match("'invalid escape sequence is OK: \\u'")
+ match('"invalid escape sequence is OK: \\u"')
+ match("`invalid escape sequence is OK: \\u`")
+ match("'\\\n'")
+ match('"\\\n"')
+ match("`\\\n`")
+ match("'\\\r'")
+ match('"\\\r"')
+ match("`\\\r`")
+ match("'\\\u2028'")
+ match('"\\\u2028"')
+ match("`\\\u2028`")
+ match("'\\\u2029'")
+ match('"\\\u2029"')
+ match("`\\\u2029`")
+ match("'\\\r\n'")
+ match('"\\\r\n"')
+ match("`\\\r\n`")
+ match("'string'code'another string'", "'string'")
+ match('"string"code"another string"', '"string"')
+ match("`string`code`another string`", "`string`")
+ match("'\"'")
+ match("'`'")
+ match('"\'"')
+ match('"`"')
+ match("`'`")
+ match('`"`')
+
+ match("'", {closed: false})
+ match('"', {closed: false})
+ match("`", {closed: false})
+ match("'unclosed", {closed: false})
+ match('"unclosed', {closed: false})
+ match("`unclosed", {closed: false})
+ match("'\n", "'", {closed: false})
+ match('"\n', '"', {closed: false})
+ match("`\n", {closed: false})
+ match("'\r", "'", {closed: false})
+ match('"\r', '"', {closed: false})
+ match("`\r", {closed: false})
+ match("'\u2028", "'", {closed: false})
+ match('"\u2028', '"', {closed: false})
+ match("`\u2028", {closed: false})
+ match("'\u2029", "'", {closed: false})
+ match('"\u2029', '"', {closed: false})
+ match("`\u2029", {closed: false})
+ match("'\r\n", "'", {closed: false})
+ match('"\r\n', '"', {closed: false})
+ match("`\r\n", {closed: false})
+ match("'\\\n", {closed: false})
+ match('"\\\n', {closed: false})
+ match("`\\\n", {closed: false})
+ match("'\\\r", {closed: false})
+ match('"\\\r', {closed: false})
+ match("`\\\r", {closed: false})
+ match("'\\\u2028", {closed: false})
+ match('"\\\u2028', {closed: false})
+ match("`\\\u2028", {closed: false})
+ match("'\\\u2029", {closed: false})
+ match('"\\\u2029', {closed: false})
+ match("`\\\u2029", {closed: false})
+ match("'\\\r\n", {closed: false})
+ match('"\\\r\n', {closed: false})
+ match("`\\\r\n", {closed: false})
+
+ match("'${}'")
+ match('"${}"')
+ match("`${}`")
+ match("'${a}'")
+ match('"${a}"')
+ match("`${a}`")
+ match("'a${b}c'")
+ match('"a${b}c"')
+ match("`a${b}c`")
+ match("'${'a'}'", "'${'")
+ match('"${"a"}"', '"${"')
+ match("`${`a`}`")
+ match("`${`${a}`}`")
+ match("`${fn({a: b})}`")
+ match("`${fn({a: '{'})}`")
+ match("`a${}${a}${ `${b\r}` + `${`c`}` } d $${\n(x=>{return x*2})(4)}$`")
+ match("`\\${{{}}}a`")
+
+ match("`a ${b c`.length", {closed: false})
+ match("`a ${`b${c`} d`.length", {closed: false})
+ match("`a ${ {c:d } e`.length", {closed: false})
+
+ })
+
+
+ token("regex", function(match) {
+
+ match("//", false)
+ match("/a/")
+ match("/\\//")
+ match("/\\\\//", "/\\\\/")
+ match("/\\\\\\//")
+ match("/[/]/")
+ match("/[\\]]/")
+ match("/[\\]/]/")
+ match("/[\\\\]/]/", "/[\\\\]/")
+ match("/[\\\\\\]/]/")
+ match(/\\u05aF/)
+ match("/invalid escape sequence is OK: \\u/")
+ match("/?foo/")
+ match("/*foo/", false)
+
+ match("/a/g")
+ match("/a/m")
+ match("/a/i")
+ match("/a/y")
+ match("/a/u")
+ match("/a/gmiyu")
+ match("/a/myg")
+ match("/a/e", false)
+ match("/a/invalidFlags", false)
+ match("/a/f00", false)
+
+ match("/\n/", false)
+ match("/\r/", false)
+ match("/\u2028/", false)
+ match("/\u2029/", false)
+ match("/\r\n/", false)
+ match("/\\\n/", false)
+ match("/\\\r/", false)
+ match("/\\\u2028/", false)
+ match("/\\\u2029/", false)
+ match("/\\\r\n/", false)
+ match("/[\n]/", false)
+ match("/[\r]/", false)
+ match("/[\u2028]/", false)
+ match("/[\u2029]/", false)
+ match("/[\r\n]/", false)
+ match("/[\\\n]/", false)
+ match("/[\\\r]/", false)
+ match("/[\\\u2028]/", false)
+ match("/[\\\u2029]/", false)
+ match("/[\\\r\n]/", false)
+
+ match("/a/", "/a/")
+ match("/a/g", "/a/g")
+ match("/a/;", "/a/")
+ match("/a/g;", "/a/g")
+ match("/a/ ;", "/a/")
+ match("/a/g ;", "/a/g")
+ match("/a/, b", "/a/")
+ match("/a/g, b", "/a/g")
+ match("/a/ , b", "/a/")
+ match("/a/g , b", "/a/g")
+ match("/a/.exec(b)", "/a/")
+ match("/a/g.exec(b)", "/a/g")
+ match("/a/ .exec(b)", "/a/")
+ match("/a/g .exec(b)", "/a/g")
+ match("/a/['exec'](b)", "/a/")
+ match("/a/g['exec'](b)", "/a/g")
+ match("/a/ ['exec'](b)", "/a/")
+ match("/a/g ['exec'](b)", "/a/g")
+ match("/a/]", "/a/")
+ match("/a/g]", "/a/g")
+ match("/a/ ]", "/a/")
+ match("/a/g ]", "/a/g")
+ match("/a/)", "/a/")
+ match("/a/g)", "/a/g")
+ match("/a/ )", "/a/")
+ match("/a/g )", "/a/g")
+ match("/a/}", "/a/")
+ match("/a/g}", "/a/g")
+ match("/a/ }", "/a/")
+ match("/a/g }", "/a/g")
+
+ match("/a/+=b", "/a/")
+ match("/a/ +=b", "/a/")
+ match("/a/-=b", "/a/")
+ match("/a/ -=b", "/a/")
+ match("/a/*b", "/a/")
+ match("/a/ *b", "/a/")
+ match("/a/ *=b", "/a/")
+ match("/a//b", "/a/")
+ match("/a/ /b", "/a/")
+ match("/a/ /=b", "/a/")
+ match("/a/%b", "/a/")
+ match("/a/ %b", "/a/")
+ match("/a/%=b", "/a/")
+ match("/a/ %=b", "/a/")
+ match("/a/&b", "/a/")
+ match("/a/ &b", "/a/")
+ match("/a/&=b", "/a/")
+ match("/a/ &=b", "/a/")
+ match("/a/&&b", "/a/")
+ match("/a/ &&b", "/a/")
+ match("/a/|b", "/a/")
+ match("/a/ |b", "/a/")
+ match("/a/|=b", "/a/")
+ match("/a/ |=b", "/a/")
+ match("/a/||b", "/a/")
+ match("/a/ ||b", "/a/")
+ match("/a/^b", "/a/")
+ match("/a/ ^b", "/a/")
+ match("/a/^=b", "/a/")
+ match("/a/ ^=b", "/a/")
+ match("/a/<b", "/a/")
+ match("/a/ <b", "/a/")
+ match("/a/<=b", "/a/")
+ match("/a/ <=b", "/a/")
+ match("/a/<<b", "/a/")
+ match("/a/ <<b", "/a/")
+ match("/a/<<=b", "/a/")
+ match("/a/ <<=b", "/a/")
+ match("/a/>b", "/a/")
+ match("/a/ >b", "/a/")
+ match("/a/>=b", "/a/")
+ match("/a/ >=b", "/a/")
+ match("/a/>>b", "/a/")
+ match("/a/ >>b", "/a/")
+ match("/a/>>=b", "/a/")
+ match("/a/ >>=b", "/a/")
+ match("/a/>>>b", "/a/")
+ match("/a/ >>>=b", "/a/")
+ match("/a/>>>=b", "/a/")
+ match("/a/ >>>b", "/a/")
+ match("/a/!=b", "/a/")
+ match("/a/ !=b", "/a/")
+ match("/a/!==b", "/a/")
+ match("/a/ !==b", "/a/")
+ match("/a/=b", "/a/")
+ match("/a/ =b", "/a/")
+ match("/a/==b", "/a/")
+ match("/a/ ==b", "/a/")
+ match("/a/===b", "/a/")
+ match("/a/ ===b", "/a/")
+
+ match("/a/?b:c", "/a/")
+ match("/a/ ? b : c", "/a/")
+ match("/a/:c", "/a/")
+ match("/a/g:c", "/a/g")
+ match("/a/ : c", "/a/")
+ match("/a/g : c", "/a/g")
+
+ match("/a///", "/a/")
+ match("/a/g//", "/a/g")
+ match("/a/ //", "/a/")
+ match("/a/g //", "/a/g")
+ match("/a//**/", "/a/")
+ match("/a/g/**/", "/a/g")
+ match("/a/ /**/", "/a/")
+ match("/a/g /**/", "/a/g")
+
+ match("/a/g''", "/a/g")
+ match("/a/g ''", "/a/g")
+
+ match('/a/g""', "/a/g")
+ match('/a/g ""', "/a/g")
+
+ match("/a//b/", "/a/")
+ match("/a/ /b/", "/a/")
+
+ match("/a/g 0", "/a/g")
+ match("/a/g 0.1", "/a/g")
+ match("/a/g .1", "/a/g")
+ match("/a/g 0x1", "/a/g")
+
+ match("/a/g e", "/a/g")
+ match("/a/g _", "/a/g")
+ match("/a/g $", "/a/g")
+ match("/a/g é", "/a/g")
+ match("/a/g \\u0080", "/a/g")
+
+ })
+
+
+ token("number", function(match) {
+
+ match("1")
+ match("1.")
+ match("1..", "1.")
+ match("0.1")
+ match(".1")
+ match("0.1.", "0.1")
+
+ match("-1", false)
+ match("-1.", false)
+ match("-1..", false)
+ match("-0.1", false)
+ match("-.1", false)
+ match("-0.1.", false)
+ match("-", false)
+
+ match("1e1")
+ match("1.e1")
+ match("1.e1.", "1.e1")
+ match("0.1e1")
+ match(".1e1")
+ match("0.1e1.", "0.1e1")
+
+ match("1e+1")
+ match("1e-1")
+ match("1e0123")
+ match("1e0.123", "1e0")
+ match("1e0x123", "1e0")
+ match("1E1")
+ match("1E+1")
+ match("1E-1")
+ match("1E0123")
+ match("1E0.123", "1E0")
+ match("1E0x123", "1E0")
+ match("1E0o123", "1E0")
+ match("1E0b123", "1E0")
+
+ match("e1", false)
+ match("e+1", false)
+ match("e-1", false)
+ match("E1", false)
+ match("E+1", false)
+ match("E-1", false)
+
+ match("-e1", false)
+ match("-e+1", false)
+ match("-e-1", false)
+ match("-E1", false)
+ match("-E+1", false)
+ match("-E-1", false)
+
+ match("0x1")
+ match("0xa")
+ match("0x015cF")
+ match("0x1e1")
+ match("0x1E1")
+ match("0x1g1", "0x1")
+
+ match("0X1")
+ match("0Xa")
+ match("0X015cF")
+ match("0X1e1")
+ match("0X1E1")
+ match("0X1g1", "0X1")
+
+ match("-0x1", false)
+ match("-0xa", false)
+ match("-0x015cF", false)
+ match("-0x1e1", false)
+ match("-0x1E1", false)
+ match("-0x1g1", false)
+
+ match("0x", "0")
+ match("1x1", "1")
+ match("0x1.", "0x1")
+ match("0x1.1", "0x1")
+ match("0.0x1", "0.0")
+ match(".0x1", ".0")
+
+ match("0o1")
+ match("0oa", "0")
+ match("0o01574")
+ match("0o1e1", "0o1")
+ match("0o1E1", "0o1")
+ match("0o1g1", "0o1")
+
+ match("0O1")
+ match("0Oa", "0")
+ match("0O01574")
+ match("0O1e1", "0O1")
+ match("0O1E1", "0O1")
+ match("0O1g1", "0O1")
+
+ match("-0o1", false)
+ match("-0oa", false)
+ match("-0o01574", false)
+ match("-0o1e1", false)
+ match("-0o1E1", false)
+ match("-0o1g1", false)
+
+ match("0o", "0")
+ match("1o1", "1")
+ match("0o1.", "0o1")
+ match("0o1.1", "0o1")
+ match("0.0o1", "0.0")
+ match(".0o1", ".0")
+
+ match("0b1")
+ match("0ba", "0")
+ match("0b01011")
+ match("0b1e1", "0b1")
+ match("0b1E1", "0b1")
+ match("0b1g1", "0b1")
+
+ match("0B1")
+ match("0Ba", "0")
+ match("0B01011")
+ match("0B1e1", "0B1")
+ match("0B1E1", "0B1")
+ match("0B1g1", "0B1")
+
+ match("-0b1", false)
+ match("-0ba", false)
+ match("-0b01011", false)
+ match("-0b1e1", false)
+ match("-0b1E1", false)
+ match("-0b1g1", false)
+
+ match("0b", "0")
+ match("1b1", "1")
+ match("0b1.", "0b1")
+ match("0b1.1", "0b1")
+ match("0.0b1", "0.0")
+ match(".0b1", ".0")
+
+ })
+
+
+ token("name", function(match) {
+
+ match("$")
+ match("_")
+ match("a")
+ match("z")
+ match("A")
+ match("Z")
+ match("å")
+ match("π")
+ match("0", false)
+ match("0a", false)
+ match("$0")
+ match("_0")
+ match("a0")
+ match("z0")
+ match("A0")
+ match("Z0")
+ match("å0")
+ match("π0")
+ match("a_56åπ")
+ match("Iñtërnâtiônàlizætiøn☃💩") // The last character is Pile of poo.
+
+ match("a\u00a0", "a")
+ match("a\u1680", "a")
+ match("a\u180e", "a")
+ match("a\u2000", "a")
+ match("a\u2001", "a")
+ match("a\u2002", "a")
+ match("a\u2003", "a")
+ match("a\u2004", "a")
+ match("a\u2005", "a")
+ match("a\u2006", "a")
+ match("a\u2007", "a")
+ match("a\u2008", "a")
+ match("a\u2009", "a")
+ match("a\u200a", "a")
+ match("a\u2028", "a")
+ match("a\u2029", "a")
+ match("a\u202f", "a")
+ match("a\u205f", "a")
+ match("a\u3000", "a")
+
+ match("\\u0000")
+ match("\\u15cF")
+ match("\\u15cG", false)
+ match("\\u000", false)
+ match("\\u00000")
+ match("a\\u0000b")
+
+ match("\\u{0}")
+ match("\\u{01}")
+ match("\\u{012}")
+ match("\\u{0123}")
+ match("\\u{01234}")
+ match("\\u{012345}")
+ match("\\u{0123456}", false)
+ match("\\u{15cF}")
+ match("\\u{15cG}", false)
+ match("a\\u{0000}b")
+
+ match("\\x09", false)
+
+ })
+
+
+ token("punctuator", function(match) {
+
+ match("+")
+ match("++")
+ match("+=")
+ match("++=", "++")
+ match("-")
+ match("--")
+ match("-=")
+ match("--=", "--")
+ match("*")
+ match("**")
+ match("*=")
+ match("**=")
+ match("/")
+ match("//", false)
+ match("/=")
+ match("//=", false)
+ match("%")
+ match("%%", "%")
+ match("%=")
+ match("%%=", "%")
+ match("&")
+ match("&&")
+ match("&=")
+ match("&&=", "&&")
+ match("|")
+ match("||")
+ match("|=")
+ match("||=", "||")
+ match("^")
+ match("^^", "^")
+ match("^=")
+ match("^^=", "^")
+ match("<")
+ match("<<")
+ match("<<<", "<<")
+ match("<=")
+ match("<<=")
+ match(">")
+ match(">>")
+ match(">>>")
+ match(">=")
+ match(">>=")
+ match(">>>=")
+ match("!")
+ match("!=")
+ match("!==")
+ match("!===", "!==")
+ match("=")
+ match("==")
+ match("===")
+
+ match("=>")
+ match("==>", "==")
+ match("=>>", "=>")
+
+ match("...")
+ match("..", ".")
+ match(".")
+ match("....", "...")
+
+ match("?")
+ match("~")
+ match(".")
+ match(",")
+ match(":")
+ match(";")
+ match("[")
+ match("]")
+ match("(")
+ match(")")
+ match("{")
+ match("}")
+
+ match("/a/()", "/")
+ match("/a/g()", "/")
+ match("/a/ ()", "/")
+ match("/a/g ()", "/")
+ match("/a/{}", "/")
+ match("/a/g{}", "/")
+ match("/a/ {}", "/")
+ match("/a/g {}", "/")
+
+ match("/a/+b", "/")
+ match("/a/ +b", "/")
+ match("/a/++b", "/")
+ match("/a/ ++b", "/")
+ match("/a/-b", "/")
+ match("/a/ -b", "/")
+ match("/a/--b", "/")
+ match("/a/ --b", "/")
+ match("/a/!b", "/")
+ match("/a/ !b", "/")
+ match("/a/~b", "/")
+ match("/a/ ~b", "/")
+
+ match("/a/g+b", "/")
+ match("/a/g +b", "/")
+ match("/a/g+=b", "/")
+ match("/a/g +=b", "/")
+ match("/a/g++", "/")
+ match("/a/g ++", "/")
+ match("/a/g-b", "/")
+ match("/a/g -b", "/")
+ match("/a/g-=b", "/")
+ match("/a/g -=b", "/")
+ match("/a/g--", "/")
+ match("/a/g --", "/")
+ match("/a/g*b", "/")
+ match("/a/g *b", "/")
+ match("/a/g *=b", "/")
+ match("/a/g/b", "/")
+ match("/a/g /b", "/")
+ match("/a/g /=b", "/")
+ match("/a/g%b", "/")
+ match("/a/g %b", "/")
+ match("/a/g%=b", "/")
+ match("/a/g %=b", "/")
+ match("/a/g&b", "/")
+ match("/a/g &b", "/")
+ match("/a/g&=b", "/")
+ match("/a/g &=b", "/")
+ match("/a/g&&b", "/")
+ match("/a/g &&b", "/")
+ match("/a/g|b", "/")
+ match("/a/g |b", "/")
+ match("/a/g|=b", "/")
+ match("/a/g |=b", "/")
+ match("/a/g||b", "/")
+ match("/a/g ||b", "/")
+ match("/a/g^b", "/")
+ match("/a/g ^b", "/")
+ match("/a/g^=b", "/")
+ match("/a/g ^=b", "/")
+ match("/a/g<b", "/")
+ match("/a/g <b", "/")
+ match("/a/g<=b", "/")
+ match("/a/g <=b", "/")
+ match("/a/g<<b", "/")
+ match("/a/g <<b", "/")
+ match("/a/g<<=b", "/")
+ match("/a/g <<=b", "/")
+ match("/a/g>b", "/")
+ match("/a/g >b", "/")
+ match("/a/g>=b", "/")
+ match("/a/g >=b", "/")
+ match("/a/g>>b", "/")
+ match("/a/g >>b", "/")
+ match("/a/g>>=b", "/")
+ match("/a/g >>=b", "/")
+ match("/a/g>>>b", "/")
+ match("/a/g >>>=b", "/")
+ match("/a/g>>>=b", "/")
+ match("/a/g >>>b", "/")
+ match("/a/g!=b", "/")
+ match("/a/g !=b", "/")
+ match("/a/g!==b", "/")
+ match("/a/g !==b", "/")
+ match("/a/g=b", "/")
+ match("/a/g =b", "/")
+ match("/a/g==b", "/")
+ match("/a/g ==b", "/")
+ match("/a/g===b", "/")
+ match("/a/g ===b", "/")
+
+ match("/a/g?b:c", "/")
+ match("/a/g ? b : c", "/")
+
+ match("/a/''", "/")
+ match("/a/ ''", "/")
+
+ match('/a/""', "/")
+ match('/a/ ""', "/")
+
+ match("/a/g/b/", "/")
+ match("/a/g /b/", "/")
+
+ match("/a/0", "/")
+ match("/a/ 0", "/")
+ match("/a/0.1", "/")
+ match("/a/ 0.1", "/")
+ match("/a/.1", "/")
+ match("/a/ .1", "/")
+
+ match("/a/e", "/")
+ match("/a/ e", "/")
+ match("/a/_", "/")
+ match("/a/ _", "/")
+ match("/a/$", "/")
+ match("/a/ $", "/")
+ match("/a/é", "/")
+ match("/a/ é", "/")
+ match("/a/\\u0080", "/")
+ match("/a/ \\u0080", "/")
+
+ match("/a/ge", "/")
+ match("/a/g_", "/")
+ match("/a/g$", "/")
+ match("/a/gé", "/")
+ match("/a/g0", "/")
+ match("/a/g\\u0080", "/")
+
+ })
+
+
+ token("invalid", function(match) {
+
+ match("")
+ match("@")
+ match("#")
+ match("\\")
+ match("\\xa9", "\\")
+ match("\u0000")
+ match("\u007F")
+
+ })
+
+})
+
+
+suite("tokenization", function() {
+
+ function testFile(file) {
+ var contents = fs.readFileSync("test/fixtures/" + file + ".js").toString()
+ var expected = require("./fixtures/" + file + ".json")
+ var actual = contents.match(jsTokens)
+ test(file + ".js", function() {
+ assert.deepEqual(actual, expected)
+ assert.equal(actual.join(""), contents)
+ })
+ }
+
+ testFile("base64")
+ testFile("errors")
+ testFile("regex")
+ testFile("division")
+
+})
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-js-tokens.git
More information about the Pkg-javascript-commits
mailing list