tools: add unescaped regexp dot rule to linter
PR-URL: https://github.com/nodejs/node/pull/11834 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Teddy Katz <teddy.katz@gmail.com> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
This commit is contained in:
parent
678480e328
commit
61ebfa8d1f
@ -136,6 +136,7 @@ rules:
|
|||||||
assert-throws-arguments: [2, { requireTwo: false }]
|
assert-throws-arguments: [2, { requireTwo: false }]
|
||||||
new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError]
|
new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError]
|
||||||
timer-arguments: 2
|
timer-arguments: 2
|
||||||
|
no-unescaped-regexp-dot: 2
|
||||||
|
|
||||||
# Global scoped method and vars
|
# Global scoped method and vars
|
||||||
globals:
|
globals:
|
||||||
|
@ -9,6 +9,7 @@ const bench = common.createBenchmark(main, {
|
|||||||
function main(conf) {
|
function main(conf) {
|
||||||
const n = +conf.n;
|
const n = +conf.n;
|
||||||
const s = 'abcd'.repeat(8 << 20);
|
const s = 'abcd'.repeat(8 << 20);
|
||||||
|
// eslint-disable-next-line no-unescaped-regexp-dot
|
||||||
s.match(/./); // Flatten string.
|
s.match(/./); // Flatten string.
|
||||||
assert.strictEqual(s.length % 4, 0);
|
assert.strictEqual(s.length % 4, 0);
|
||||||
const b = Buffer.allocUnsafe(s.length / 4 * 3);
|
const b = Buffer.allocUnsafe(s.length / 4 * 3);
|
||||||
|
@ -18,6 +18,7 @@ function main(conf) {
|
|||||||
const len = +conf.len;
|
const len = +conf.len;
|
||||||
|
|
||||||
const msg = `"${'.'.repeat(len)}"`;
|
const msg = `"${'.'.repeat(len)}"`;
|
||||||
|
// eslint-disable-next-line no-unescaped-regexp-dot
|
||||||
msg.match(/./);
|
msg.match(/./);
|
||||||
const options = {'stdio': ['ignore', 'pipe', 'ignore']};
|
const options = {'stdio': ['ignore', 'pipe', 'ignore']};
|
||||||
const child = exec(`yes ${msg}`, options);
|
const child = exec(`yes ${msg}`, options);
|
||||||
|
@ -7,7 +7,7 @@ const re = new RegExp(
|
|||||||
'^Error: The module \'.+\'\n' +
|
'^Error: The module \'.+\'\n' +
|
||||||
'was compiled against a different Node\\.js version using\n' +
|
'was compiled against a different Node\\.js version using\n' +
|
||||||
'NODE_MODULE_VERSION 42\\. This version of Node\\.js requires\n' +
|
'NODE_MODULE_VERSION 42\\. This version of Node\\.js requires\n' +
|
||||||
`NODE_MODULE_VERSION ${process.versions.modules}. ` +
|
`NODE_MODULE_VERSION ${process.versions.modules}\\. ` +
|
||||||
'Please try re-compiling or re-installing\n' +
|
'Please try re-compiling or re-installing\n' +
|
||||||
'the module \\(for instance, using `npm rebuild` or `npm install`\\)\\.$');
|
'the module \\(for instance, using `npm rebuild` or `npm install`\\)\\.$');
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ repl.addTest('restart', [].concat(
|
|||||||
],
|
],
|
||||||
repl.handshakeLines,
|
repl.handshakeLines,
|
||||||
[
|
[
|
||||||
/Restoring breakpoint mod.js:2/,
|
/Restoring breakpoint mod\.js:2/,
|
||||||
/Warning: script 'mod\.js' was not loaded yet\./,
|
/Warning: script 'mod\.js' was not loaded yet\./,
|
||||||
/Restoring breakpoint \).*:\d+/,
|
/Restoring breakpoint \).*:\d+/,
|
||||||
/Warning: script '\)[^']*' was not loaded yet\./
|
/Warning: script '\)[^']*' was not loaded yet\./
|
||||||
|
@ -72,7 +72,7 @@ addTest('sb("setInterval()", "!(setInterval.flag++)")', [
|
|||||||
|
|
||||||
// Continue
|
// Continue
|
||||||
addTest('c', [
|
addTest('c', [
|
||||||
/break in timers.js:\d+/,
|
/break in timers\.js:\d+/,
|
||||||
/\d/, /\d/, /\d/, /\d/, /\d/
|
/\d/, /\d/, /\d/, /\d/, /\d/
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ function checkListResponse(err, response) {
|
|||||||
assert.ok(response[0]['devtoolsFrontendUrl']);
|
assert.ok(response[0]['devtoolsFrontendUrl']);
|
||||||
assert.ok(
|
assert.ok(
|
||||||
response[0]['webSocketDebuggerUrl']
|
response[0]['webSocketDebuggerUrl']
|
||||||
.match(/ws:\/\/127.0.0.1:\d+\/[0-9A-Fa-f]{8}-/));
|
.match(/ws:\/\/127\.0\.0\.1:\d+\/[0-9A-Fa-f]{8}-/));
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkVersion(err, response) {
|
function checkVersion(err, response) {
|
||||||
|
@ -406,7 +406,7 @@ assert.doesNotThrow(function() { assert.ifError(); });
|
|||||||
|
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
assert.doesNotThrow(makeBlock(thrower, Error), 'user message');
|
assert.doesNotThrow(makeBlock(thrower, Error), 'user message');
|
||||||
}, /Got unwanted exception. user message/,
|
}, /Got unwanted exception: user message/,
|
||||||
'a.doesNotThrow ignores user message');
|
'a.doesNotThrow ignores user message');
|
||||||
|
|
||||||
// make sure that validating using constructor really works
|
// make sure that validating using constructor really works
|
||||||
|
@ -923,7 +923,7 @@ assert.throws(() => Buffer.allocUnsafe(10).copy(),
|
|||||||
/TypeError: argument should be a Buffer/);
|
/TypeError: argument should be a Buffer/);
|
||||||
|
|
||||||
const regErrorMsg = new RegExp('First argument must be a string, Buffer, ' +
|
const regErrorMsg = new RegExp('First argument must be a string, Buffer, ' +
|
||||||
'ArrayBuffer, Array, or array-like object.');
|
'ArrayBuffer, Array, or array-like object\\.');
|
||||||
|
|
||||||
assert.throws(() => Buffer.from(), regErrorMsg);
|
assert.throws(() => Buffer.from(), regErrorMsg);
|
||||||
assert.throws(() => Buffer.from(null), regErrorMsg);
|
assert.throws(() => Buffer.from(null), regErrorMsg);
|
||||||
|
@ -301,7 +301,7 @@ ecdh5.setPrivateKey(cafebabeKey, 'hex');
|
|||||||
].forEach((element) => {
|
].forEach((element) => {
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
ecdh5.setPrivateKey(element, 'hex');
|
ecdh5.setPrivateKey(element, 'hex');
|
||||||
}, /^Error: Private key is not valid for specified curve.$/);
|
}, /^Error: Private key is not valid for specified curve\.$/);
|
||||||
// Verify object state did not change.
|
// Verify object state did not change.
|
||||||
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
|
assert.strictEqual(ecdh5.getPrivateKey('hex'), cafebabeKey);
|
||||||
});
|
});
|
||||||
|
@ -11,8 +11,8 @@ const child = spawn(process.execPath, args, childOptions);
|
|||||||
|
|
||||||
const reDeprecationWarning = new RegExp(
|
const reDeprecationWarning = new RegExp(
|
||||||
/^\(node:\d+\) \[DEP0062\] DeprecationWarning: /.source +
|
/^\(node:\d+\) \[DEP0062\] DeprecationWarning: /.source +
|
||||||
/node --debug is deprecated. /.source +
|
/node --debug is deprecated\. /.source +
|
||||||
/Please use node --inspect instead.$/.source
|
/Please use node --inspect instead\.$/.source
|
||||||
);
|
);
|
||||||
|
|
||||||
child.stdin.write("process.send({ msg: 'childready' });\n");
|
child.stdin.write("process.send({ msg: 'childready' });\n");
|
||||||
@ -47,9 +47,9 @@ function assertOutputLines() {
|
|||||||
// need a var so can swap the first two lines in following
|
// need a var so can swap the first two lines in following
|
||||||
// eslint-disable-next-line no-var
|
// eslint-disable-next-line no-var
|
||||||
var expectedLines = [
|
var expectedLines = [
|
||||||
/^Starting debugger agent.$/,
|
/^Starting debugger agent\.$/,
|
||||||
reDeprecationWarning,
|
reDeprecationWarning,
|
||||||
new RegExp(`^Debugger listening on 127.0.0.1:${debugPort}$`)
|
new RegExp(`^Debugger listening on 127\\.0\\.0\\.1:${debugPort}$`)
|
||||||
];
|
];
|
||||||
|
|
||||||
if (os.platform() === 'win32') {
|
if (os.platform() === 'win32') {
|
||||||
|
@ -17,7 +17,7 @@ if (cluster.isMaster) {
|
|||||||
const socket = dgram.createSocket('udp4');
|
const socket = dgram.createSocket('udp4');
|
||||||
|
|
||||||
socket.on('error', common.mustCall((err) => {
|
socket.on('error', common.mustCall((err) => {
|
||||||
assert(/^Error: bind UNKNOWN 0.0.0.0$/.test(err.toString()));
|
assert(/^Error: bind UNKNOWN 0\.0\.0\.0$/.test(err.toString()));
|
||||||
process.nextTick(common.mustCall(() => {
|
process.nextTick(common.mustCall(() => {
|
||||||
assert.strictEqual(socket._bindState, 0); // BIND_STATE_UNBOUND
|
assert.strictEqual(socket._bindState, 0); // BIND_STATE_UNBOUND
|
||||||
socket.close();
|
socket.close();
|
||||||
|
@ -5,10 +5,10 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const numberError = new RegExp('^TypeError: "options" must be a string ' +
|
const numberError = new RegExp('^TypeError: "options" must be a string ' +
|
||||||
'or an object, got number instead.$');
|
'or an object, got number instead\\.$');
|
||||||
|
|
||||||
const booleanError = new RegExp('^TypeError: "options" must be a string ' +
|
const booleanError = new RegExp('^TypeError: "options" must be a string ' +
|
||||||
'or an object, got boolean instead.$');
|
'or an object, got boolean instead\\.$');
|
||||||
|
|
||||||
const example = path.join(common.tmpDir, 'dummy');
|
const example = path.join(common.tmpDir, 'dummy');
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ assert.throws(() => {
|
|||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const outgoingMessage = new OutgoingMessage();
|
const outgoingMessage = new OutgoingMessage();
|
||||||
outgoingMessage.setHeader.call({_header: 'test'}, 'test', 'value');
|
outgoingMessage.setHeader.call({_header: 'test'}, 'test', 'value');
|
||||||
}, /^Error: Can't set headers after they are sent.$/);
|
}, /^Error: Can't set headers after they are sent\.$/);
|
||||||
|
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
const outgoingMessage = new OutgoingMessage();
|
const outgoingMessage = new OutgoingMessage();
|
||||||
|
@ -51,7 +51,7 @@ testCases.findByPath = function(path) {
|
|||||||
|
|
||||||
const server = net.createServer(function(connection) {
|
const server = net.createServer(function(connection) {
|
||||||
connection.on('data', function(data) {
|
connection.on('data', function(data) {
|
||||||
const path = data.toString().match(/GET (.*) HTTP.1.1/)[1];
|
const path = data.toString().match(/GET (.*) HTTP\/1\.1/)[1];
|
||||||
const testCase = testCases.findByPath(path);
|
const testCase = testCases.findByPath(path);
|
||||||
|
|
||||||
connection.write(testCase.response);
|
connection.write(testCase.response);
|
||||||
|
@ -18,7 +18,7 @@ const options = {
|
|||||||
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem'),
|
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectedHeader = /^HTTP\/1.1 200 OK/;
|
const expectedHeader = /^HTTP\/1\.1 200 OK/;
|
||||||
const expectedBody = /hello world\n/;
|
const expectedBody = /hello world\n/;
|
||||||
const expectCertError = /^Error: unable to verify the first certificate$/;
|
const expectCertError = /^Error: unable to verify the first certificate$/;
|
||||||
|
|
||||||
|
@ -41,11 +41,11 @@ assert.strictEqual(err5.code, 'TEST_ERROR_1');
|
|||||||
|
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => new errors.Error('TEST_FOO_KEY'),
|
() => new errors.Error('TEST_FOO_KEY'),
|
||||||
/^AssertionError: An invalid error message key was used: TEST_FOO_KEY.$/);
|
/^AssertionError: An invalid error message key was used: TEST_FOO_KEY\.$/);
|
||||||
// Calling it twice yields same result (using the key does not create it)
|
// Calling it twice yields same result (using the key does not create it)
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => new errors.Error('TEST_FOO_KEY'),
|
() => new errors.Error('TEST_FOO_KEY'),
|
||||||
/^AssertionError: An invalid error message key was used: TEST_FOO_KEY.$/);
|
/^AssertionError: An invalid error message key was used: TEST_FOO_KEY\.$/);
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => new errors.Error(1),
|
() => new errors.Error(1),
|
||||||
/^AssertionError: 'number' === 'string'$/);
|
/^AssertionError: 'number' === 'string'$/);
|
||||||
|
@ -5,8 +5,10 @@ const assert = require('assert');
|
|||||||
const util = require('internal/util');
|
const util = require('internal/util');
|
||||||
|
|
||||||
if (!process.versions.openssl) {
|
if (!process.versions.openssl) {
|
||||||
assert.throws(() => util.assertCrypto(),
|
assert.throws(
|
||||||
/^Error: Node.js is not compiled with openssl crypto support$/);
|
() => util.assertCrypto(),
|
||||||
|
/^Error: Node\.js is not compiled with openssl crypto support$/
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
assert.doesNotThrow(() => util.assertCrypto());
|
assert.doesNotThrow(() => util.assertCrypto());
|
||||||
}
|
}
|
||||||
|
@ -90,15 +90,15 @@ const unixSpecialCaseFormatTests = [
|
|||||||
|
|
||||||
const errors = [
|
const errors = [
|
||||||
{method: 'parse', input: [null],
|
{method: 'parse', input: [null],
|
||||||
message: /^TypeError: Path must be a string. Received null$/},
|
message: /^TypeError: Path must be a string\. Received null$/},
|
||||||
{method: 'parse', input: [{}],
|
{method: 'parse', input: [{}],
|
||||||
message: /^TypeError: Path must be a string. Received {}$/},
|
message: /^TypeError: Path must be a string\. Received {}$/},
|
||||||
{method: 'parse', input: [true],
|
{method: 'parse', input: [true],
|
||||||
message: /^TypeError: Path must be a string. Received true$/},
|
message: /^TypeError: Path must be a string\. Received true$/},
|
||||||
{method: 'parse', input: [1],
|
{method: 'parse', input: [1],
|
||||||
message: /^TypeError: Path must be a string. Received 1$/},
|
message: /^TypeError: Path must be a string\. Received 1$/},
|
||||||
{method: 'parse', input: [],
|
{method: 'parse', input: [],
|
||||||
message: /^TypeError: Path must be a string. Received undefined$/},
|
message: /^TypeError: Path must be a string\. Received undefined$/},
|
||||||
{method: 'format', input: [null],
|
{method: 'format', input: [null],
|
||||||
message:
|
message:
|
||||||
/^TypeError: Parameter "pathObject" must be an object, not object$/},
|
/^TypeError: Parameter "pathObject" must be an object, not object$/},
|
||||||
|
@ -35,16 +35,16 @@ validateTuple(process.hrtime(tuple));
|
|||||||
// test that only an Array may be passed to process.hrtime()
|
// test that only an Array may be passed to process.hrtime()
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
process.hrtime(1);
|
process.hrtime(1);
|
||||||
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
}, /^TypeError: process\.hrtime\(\) only accepts an Array tuple$/);
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
process.hrtime([]);
|
process.hrtime([]);
|
||||||
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
}, /^TypeError: process\.hrtime\(\) only accepts an Array tuple$/);
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
process.hrtime([1]);
|
process.hrtime([1]);
|
||||||
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
}, /^TypeError: process\.hrtime\(\) only accepts an Array tuple$/);
|
||||||
assert.throws(() => {
|
assert.throws(() => {
|
||||||
process.hrtime([1, 2, 3]);
|
process.hrtime([1, 2, 3]);
|
||||||
}, /^TypeError: process.hrtime\(\) only accepts an Array tuple$/);
|
}, /^TypeError: process\.hrtime\(\) only accepts an Array tuple$/);
|
||||||
|
|
||||||
function validateTuple(tuple) {
|
function validateTuple(tuple) {
|
||||||
assert(Array.isArray(tuple));
|
assert(Array.isArray(tuple));
|
||||||
|
@ -110,7 +110,9 @@ const qsColonTestCases = [
|
|||||||
const extendedFunction = function() {};
|
const extendedFunction = function() {};
|
||||||
extendedFunction.prototype = {a: 'b'};
|
extendedFunction.prototype = {a: 'b'};
|
||||||
const qsWeirdObjects = [
|
const qsWeirdObjects = [
|
||||||
|
// eslint-disable-next-line no-unescaped-regexp-dot
|
||||||
[{regexp: /./g}, 'regexp=', {'regexp': ''}],
|
[{regexp: /./g}, 'regexp=', {'regexp': ''}],
|
||||||
|
// eslint-disable-next-line no-unescaped-regexp-dot
|
||||||
[{regexp: new RegExp('.', 'g')}, 'regexp=', {'regexp': ''}],
|
[{regexp: new RegExp('.', 'g')}, 'regexp=', {'regexp': ''}],
|
||||||
[{fn: function() {}}, 'fn=', {'fn': ''}],
|
[{fn: function() {}}, 'fn=', {'fn': ''}],
|
||||||
[{fn: new Function('')}, 'fn=', {'fn': ''}],
|
[{fn: new Function('')}, 'fn=', {'fn': ''}],
|
||||||
|
@ -35,7 +35,7 @@ oStream.on('end', common.mustCall(() => {
|
|||||||
|
|
||||||
iStream.write('process.s\t');
|
iStream.write('process.s\t');
|
||||||
|
|
||||||
assert(/process.std\b/.test(output)); // Completion works.
|
assert(/process\.std\b/.test(output)); // Completion works.
|
||||||
assert(!/stdout/.test(output)); // Completion doesn’t show all results yet.
|
assert(!/stdout/.test(output)); // Completion doesn’t show all results yet.
|
||||||
|
|
||||||
iStream.write('\t');
|
iStream.write('\t');
|
||||||
|
@ -35,8 +35,9 @@ r.defineCommand('say2', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
inputStream.write('.help\n');
|
inputStream.write('.help\n');
|
||||||
assert(/\n.say1 help for say1\n/.test(output), 'help for say1 not present');
|
assert(/\n\.say1 help for say1\n/.test(output),
|
||||||
assert(/\n.say2\n/.test(output), 'help for say2 not present');
|
'help for say1 not present');
|
||||||
|
assert(/\n\.say2\n/.test(output), 'help for say2 not present');
|
||||||
inputStream.write('.say1 node developer\n');
|
inputStream.write('.say1 node developer\n');
|
||||||
assert(/> hello node developer/.test(output), 'say1 outputted incorrectly');
|
assert(/> hello node developer/.test(output), 'say1 outputted incorrectly');
|
||||||
inputStream.write('.say2 node developer\n');
|
inputStream.write('.say2 node developer\n');
|
||||||
|
@ -28,7 +28,7 @@ const args = ['-i'];
|
|||||||
const child = spawn(process.execPath, args);
|
const child = spawn(process.execPath, args);
|
||||||
|
|
||||||
const input = '(function(){"use strict"; const y=1;y=2})()\n';
|
const input = '(function(){"use strict"; const y=1;y=2})()\n';
|
||||||
const expectOut = /^> TypeError: Assignment to constant variable.\n/;
|
const expectOut = /^> TypeError: Assignment to constant variable\.\n/;
|
||||||
|
|
||||||
child.stderr.setEncoding('utf8');
|
child.stderr.setEncoding('utf8');
|
||||||
child.stderr.on('data', function(c) {
|
child.stderr.on('data', function(c) {
|
||||||
|
@ -12,7 +12,7 @@ const child = spawn(process.execPath, args);
|
|||||||
|
|
||||||
const input = 'var foo = "bar\\\nbaz"';
|
const input = 'var foo = "bar\\\nbaz"';
|
||||||
// Match '...' as well since it marks a multi-line statement
|
// Match '...' as well since it marks a multi-line statement
|
||||||
const expectOut = /^> ... undefined\n/;
|
const expectOut = /^> \.\.\. undefined\n/;
|
||||||
|
|
||||||
child.stderr.setEncoding('utf8');
|
child.stderr.setEncoding('utf8');
|
||||||
child.stderr.on('data', function(c) {
|
child.stderr.on('data', function(c) {
|
||||||
|
@ -212,7 +212,7 @@ function error_test() {
|
|||||||
{
|
{
|
||||||
client: client_unix,
|
client: client_unix,
|
||||||
send: '(function() { "use strict"; if (true) function f() { } })()',
|
send: '(function() { "use strict"; if (true) function f() { } })()',
|
||||||
expect: /\bSyntaxError: In strict mode code, functions can only be declared at top level or inside a block./ // eslint-disable-line max-len
|
expect: /\bSyntaxError: In strict mode code, functions can only be declared at top level or inside a block\./ // eslint-disable-line max-len
|
||||||
},
|
},
|
||||||
// Named functions can be used:
|
// Named functions can be used:
|
||||||
{ client: client_unix, send: 'function blah() { return 1; }',
|
{ client: client_unix, send: 'function blah() { return 1; }',
|
||||||
|
@ -27,7 +27,7 @@ const assert = require('assert');
|
|||||||
try {
|
try {
|
||||||
require(path.join(common.fixturesDir, 'invalid.json'));
|
require(path.join(common.fixturesDir, 'invalid.json'));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const re = /test[/\\]fixtures[/\\]invalid.json: Unexpected string/;
|
const re = /test[/\\]fixtures[/\\]invalid\.json: Unexpected string/;
|
||||||
const i = err.message.match(re);
|
const i = err.message.match(re);
|
||||||
assert.notStrictEqual(null, i, 'require() json error should include path');
|
assert.notStrictEqual(null, i, 'require() json error should include path');
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ r._read = function(n) {
|
|||||||
function pushError() {
|
function pushError() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
r.push(Buffer.allocUnsafe(1));
|
r.push(Buffer.allocUnsafe(1));
|
||||||
}, /^Error: stream.push\(\) after EOF$/);
|
}, /^Error: stream\.push\(\) after EOF$/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ w._write = function(chunk, encoding, cb) {
|
|||||||
r.on('end', common.mustCall(function() {
|
r.on('end', common.mustCall(function() {
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
r.unshift(Buffer.allocUnsafe(1));
|
r.unshift(Buffer.allocUnsafe(1));
|
||||||
}, /^Error: stream.unshift\(\) after end event$/);
|
}, /^Error: stream\.unshift\(\) after end event$/);
|
||||||
w.end();
|
w.end();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -89,4 +89,4 @@ assert.throws(() => {
|
|||||||
new vm.Script('function abc() {}', {
|
new vm.Script('function abc() {}', {
|
||||||
cachedData: 'ohai'
|
cachedData: 'ohai'
|
||||||
});
|
});
|
||||||
}, /^TypeError: options.cachedData must be a Buffer instance$/);
|
}, /^TypeError: options\.cachedData must be a Buffer instance$/);
|
||||||
|
@ -90,7 +90,7 @@ assert.throws(function() {
|
|||||||
columnOffset: 123
|
columnOffset: 123
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
return /expected-filename.js:33:130/.test(err.stack);
|
return /expected-filename\.js:33:130/.test(err.stack);
|
||||||
}, 'Expected appearance of proper offset in Error stack');
|
}, 'Expected appearance of proper offset in Error stack');
|
||||||
|
|
||||||
// https://github.com/nodejs/node/issues/6158
|
// https://github.com/nodejs/node/issues/6158
|
||||||
|
@ -52,7 +52,7 @@ assert.throws(function() {
|
|||||||
};
|
};
|
||||||
vm.runInNewContext('runInVM(10)', context, { timeout: 10000 });
|
vm.runInNewContext('runInVM(10)', context, { timeout: 10000 });
|
||||||
throw new Error('Test 5 failed');
|
throw new Error('Test 5 failed');
|
||||||
}, /Script execution timed out./);
|
}, /Script execution timed out\./);
|
||||||
|
|
||||||
// Test 6: Nested vm timeouts, outer timeout is shorter and fires first.
|
// Test 6: Nested vm timeouts, outer timeout is shorter and fires first.
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
@ -63,7 +63,7 @@ assert.throws(function() {
|
|||||||
};
|
};
|
||||||
vm.runInNewContext('runInVM(10000)', context, { timeout: 100 });
|
vm.runInNewContext('runInVM(10000)', context, { timeout: 100 });
|
||||||
throw new Error('Test 6 failed');
|
throw new Error('Test 6 failed');
|
||||||
}, /Script execution timed out./);
|
}, /Script execution timed out\./);
|
||||||
|
|
||||||
// Test 7: Nested vm timeouts, inner script throws an error.
|
// Test 7: Nested vm timeouts, inner script throws an error.
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
|
@ -61,7 +61,9 @@ execFile(node, traceDep, function(er, stdout, stderr) {
|
|||||||
assert.strictEqual(stdout, '');
|
assert.strictEqual(stdout, '');
|
||||||
const stack = stderr.trim().split('\n');
|
const stack = stderr.trim().split('\n');
|
||||||
// just check the top and bottom.
|
// just check the top and bottom.
|
||||||
assert(/util.debug is deprecated. Use console.error instead./.test(stack[1]));
|
assert(
|
||||||
|
/util\.debug is deprecated\. Use console\.error instead\./.test(stack[1])
|
||||||
|
);
|
||||||
assert(/DEBUG: This is deprecated/.test(stack[0]));
|
assert(/DEBUG: This is deprecated/.test(stack[0]));
|
||||||
console.log('trace ok');
|
console.log('trace ok');
|
||||||
});
|
});
|
||||||
|
@ -121,7 +121,7 @@ const my_path = require('../fixtures/path');
|
|||||||
assert.ok(my_path.path_func instanceof Function);
|
assert.ok(my_path.path_func instanceof Function);
|
||||||
// this one does not exist and should throw
|
// this one does not exist and should throw
|
||||||
assert.throws(function() { require('./utils'); },
|
assert.throws(function() { require('./utils'); },
|
||||||
/^Error: Cannot find module '.\/utils'$/);
|
/^Error: Cannot find module '\.\/utils'$/);
|
||||||
|
|
||||||
let errorThrown = false;
|
let errorThrown = false;
|
||||||
try {
|
try {
|
||||||
@ -318,5 +318,5 @@ assert.strictEqual(42, require('../fixtures/utf8-bom.json'));
|
|||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
require('../fixtures/test-error-first-line-offset.js');
|
require('../fixtures/test-error-first-line-offset.js');
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
return /test-error-first-line-offset.js:1:/.test(err.stack);
|
return /test-error-first-line-offset\.js:1:/.test(err.stack);
|
||||||
}, 'Expected appearance of proper offset in Error stack');
|
}, 'Expected appearance of proper offset in Error stack');
|
||||||
|
@ -29,5 +29,5 @@ execFile(node, traceWarn, function(er, stdout, stderr) {
|
|||||||
assert.strictEqual(er, null);
|
assert.strictEqual(er, null);
|
||||||
assert.strictEqual(stdout, '');
|
assert.strictEqual(stdout, '');
|
||||||
assert(/^\(.+\)\sWarning: a bad practice warning/.test(stderr));
|
assert(/^\(.+\)\sWarning: a bad practice warning/.test(stderr));
|
||||||
assert(/at Object\.<anonymous>\s\(.+warnings.js:3:9\)/.test(stderr));
|
assert(/at Object\.<anonymous>\s\(.+warnings\.js:3:9\)/.test(stderr));
|
||||||
});
|
});
|
||||||
|
157
tools/eslint-rules/no-unescaped-regexp-dot.js
Normal file
157
tools/eslint-rules/no-unescaped-regexp-dot.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Look for unescaped "literal" dots in regular expressions
|
||||||
|
* @author Brian White
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const utilsPath = path.join(__dirname, '..', 'eslint', 'lib', 'ast-utils.js');
|
||||||
|
const astUtils = require(utilsPath);
|
||||||
|
const getLocationFromRangeIndex = astUtils.getLocationFromRangeIndex;
|
||||||
|
const getRangeIndexFromLocation = astUtils.getRangeIndexFromLocation;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Rule Definition
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module.exports = function(context) {
|
||||||
|
const sourceCode = context.getSourceCode();
|
||||||
|
const regexpStack = [];
|
||||||
|
var regexpBuffer = [];
|
||||||
|
var inRegExp = false;
|
||||||
|
|
||||||
|
var getLocFromIndex;
|
||||||
|
if (typeof sourceCode.getLocFromIndex === 'function') {
|
||||||
|
getLocFromIndex = function(index) {
|
||||||
|
return sourceCode.getLocFromIndex(index);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
getLocFromIndex = function(index) {
|
||||||
|
return getLocationFromRangeIndex(sourceCode, index);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var getIndexFromLoc;
|
||||||
|
if (typeof sourceCode.getIndexFromLoc === 'function') {
|
||||||
|
getIndexFromLoc = function(loc) {
|
||||||
|
return sourceCode.getIndexFromLoc(loc);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
getIndexFromLoc = function(loc) {
|
||||||
|
return getRangeIndexFromLocation(sourceCode, loc);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function report(node, startOffset) {
|
||||||
|
context.report({
|
||||||
|
node,
|
||||||
|
loc: getLocFromIndex(getIndexFromLoc(node.loc.start) + startOffset),
|
||||||
|
message: 'Unescaped dot character in regular expression'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedModifiers = ['+', '*', '?', '{'];
|
||||||
|
function checkRegExp(nodes) {
|
||||||
|
var escaping = false;
|
||||||
|
var inCharClass = false;
|
||||||
|
for (var n = 0; n < nodes.length; ++n) {
|
||||||
|
const pair = nodes[n];
|
||||||
|
const node = pair[0];
|
||||||
|
const str = pair[1];
|
||||||
|
for (var i = 0; i < str.length; ++i) {
|
||||||
|
switch (str[i]) {
|
||||||
|
case '[':
|
||||||
|
if (!escaping)
|
||||||
|
inCharClass = true;
|
||||||
|
else
|
||||||
|
escaping = false;
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
if (!escaping) {
|
||||||
|
if (inCharClass)
|
||||||
|
inCharClass = false;
|
||||||
|
} else {
|
||||||
|
escaping = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
escaping = !escaping;
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if (!escaping) {
|
||||||
|
if (!inCharClass &&
|
||||||
|
((i + 1) === str.length ||
|
||||||
|
allowedModifiers.indexOf(str[i + 1]) === -1)) {
|
||||||
|
report(node, i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
escaping = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (escaping)
|
||||||
|
escaping = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkRegExpStart(node) {
|
||||||
|
if (node.callee && node.callee.name === 'RegExp') {
|
||||||
|
if (inRegExp) {
|
||||||
|
regexpStack.push(regexpBuffer);
|
||||||
|
regexpBuffer = [];
|
||||||
|
}
|
||||||
|
inRegExp = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkRegExpEnd(node) {
|
||||||
|
if (node.callee && node.callee.name === 'RegExp') {
|
||||||
|
checkRegExp(regexpBuffer);
|
||||||
|
if (regexpStack.length) {
|
||||||
|
regexpBuffer = regexpStack.pop();
|
||||||
|
} else {
|
||||||
|
inRegExp = false;
|
||||||
|
regexpBuffer = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkLiteral(node) {
|
||||||
|
const isTemplate = (node.type === 'TemplateLiteral' && node.quasis &&
|
||||||
|
node.quasis.length);
|
||||||
|
if (inRegExp &&
|
||||||
|
(isTemplate || (typeof node.value === 'string' && node.value.length))) {
|
||||||
|
var p = node.parent;
|
||||||
|
while (p && p.type === 'BinaryExpression') {
|
||||||
|
p = p.parent;
|
||||||
|
}
|
||||||
|
if (p && (p.type === 'NewExpression' || p.type === 'CallExpression') &&
|
||||||
|
p.callee && p.callee.type === 'Identifier' &&
|
||||||
|
p.callee.name === 'RegExp') {
|
||||||
|
if (isTemplate) {
|
||||||
|
const quasis = node.quasis;
|
||||||
|
for (var i = 0; i < quasis.length; ++i) {
|
||||||
|
const el = quasis[i];
|
||||||
|
if (el.type === 'TemplateElement' && el.value && el.value.cooked)
|
||||||
|
regexpBuffer.push([el, el.value.cooked]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
regexpBuffer.push([node, node.value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.regex) {
|
||||||
|
checkRegExp([[node, node.regex.pattern]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
TemplateLiteral: checkLiteral,
|
||||||
|
Literal: checkLiteral,
|
||||||
|
CallExpression: checkRegExpStart,
|
||||||
|
NewExpression: checkRegExpStart,
|
||||||
|
'CallExpression:exit': checkRegExpEnd,
|
||||||
|
'NewExpression:exit': checkRegExpEnd
|
||||||
|
};
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user