line_push/node_modules/eslint-template-visitor/test/_shift-to-espree-safe.js
2022-07-17 13:16:16 +08:00

284 lines
5.6 KiB
JavaScript

import reduceUsing, { CloneReducer } from 'shift-reducer';
import analyzeScope, { ScopeLookup } from 'shift-scope';
import { check as isReservedWord } from 'reserved-words';
class RegexReducer extends CloneReducer {
reduceLiteralRegExpExpression(node) {
return {
...node,
unicode: false,
};
}
}
class NoReservedKeywordsReducer extends CloneReducer {
isSafeName(name) {
return !isReservedWord(name, 3)
&& !isReservedWord(name, 6, true)
&& name !== 'arguments'
&& name !== 'eval';
}
reduceLabeledStatement(node, rest) {
if (this.isSafeName(node.label)) {
return super.reduceLabeledStatement(node, rest);
}
return {
...node,
...rest,
label: node.label + '_avoid_reserved_word',
};
}
reduceBindingIdentifier(node) {
if (this.isSafeName(node.name)) {
return node;
}
return {
...node,
name: node.name + '_avoid_reserved_word',
};
}
reduceAssignmentTargetIdentifier(...args) {
return this.reduceBindingIdentifier(...args);
}
reduceIdentifierExpression(...args) {
return this.reduceBindingIdentifier(...args);
}
}
class NoIdentifierDuplicatingAnImportReducer extends CloneReducer {
reduceImportNamespace(node, { namespaceBinding, ...rest }) {
return {
...node,
...rest,
namespaceBinding: namespaceBinding && {
...namespaceBinding,
name: namespaceBinding.name + '_avoid_capture',
},
};
}
}
class ScopeLookupCloneReducer extends CloneReducer {
constructor(scopeLookup) {
super();
this.scopeLookup = scopeLookup;
}
}
class NoUndeclaredExportReducer extends ScopeLookupCloneReducer {
reduceExportLocals(node, { namedExports, ...rest }) {
return {
...node,
...rest,
namedExports: namedExports.filter(export_ => !export_._isUndeclaredVariable),
};
}
reduceExportLocalSpecifier(node, { name: { _isUndeclaredVariable, ...name }, ...rest }) {
return {
...node,
...rest,
name,
_isUndeclaredVariable,
};
}
reduceIdentifierExpression(node) {
const [ variable ] = this.scopeLookup.lookup(node);
return {
...node,
_isUndeclaredVariable: variable && variable.declarations.length === 0,
};
}
}
const removingHOR = Reducer => class extends Reducer {
constructor(...args) {
super(...args);
this.nodesToRemove = new Set();
this.shouldKeep = statement => !this.nodesToRemove.has(statement);
}
markForRemoval(node) {
this.nodesToRemove.add(node);
}
propagateRemoval(from, to) {
if (this.nodesToRemove.has(from)) {
this.nodesToRemove.add(to);
}
}
reduceSwitchCase(node, { consequent, ...rest }) {
return {
...node,
...rest,
consequent: consequent.filter(this.shouldKeep),
};
}
reduceSwitchDefault(node, { consequent, ...rest }) {
return {
...node,
...rest,
consequent: consequent.filter(this.shouldKeep),
};
}
reduceScript(node, { statements, ...rest }) {
return {
...node,
...rest,
statements: statements.filter(this.shouldKeep),
};
}
reduceFunctionBody(node, { statements, ...rest }) {
return {
...node,
...rest,
statements: statements.filter(this.shouldKeep),
};
}
reduceBlock(node, { statements, ...rest }) {
return {
...node,
...rest,
statements: statements.filter(this.shouldKeep),
};
}
reduceVariableDeclaration(node, { declarators, ...rest }) {
declarators = declarators.filter(this.shouldKeep);
node = {
...node,
...rest,
declarators,
};
if (declarators.length === 0) {
this.markForRemoval(node);
}
return node;
}
reduceVariableDeclarationStatement(node, { declaration }) {
this.propagateRemoval(declaration, node);
return node;
}
reduceForStatement(node, { body }) {
this.propagateRemoval(body, node);
return node;
}
reduceWhileStatement(node, { body }) {
this.propagateRemoval(body, node);
return node;
}
reduceLabeledStatement(node, { body }) {
this.propagateRemoval(body, node);
return node;
}
reduceForInStatement(node, { body }) {
this.propagateRemoval(body, node);
return node;
}
reduceIfStatement(node, { consequent, alternate }) {
this.propagateRemoval(consequent, node);
this.propagateRemoval(alternate, node);
return node;
}
reduceDoWhileStatement(node, { body }) {
this.propagateRemoval(body, node);
return node;
}
};
class NoNonStrictFeaturesReducer extends removingHOR(CloneReducer) {
reduceWithStatement(node) {
this.markForRemoval(node);
return node;
}
reduceUnaryExpression(node) {
if (node.operator === 'delete' && node.operand.type === 'IdentifierExpression') {
return node.operand;
}
return node;
}
}
class NoLabeledFunctionDeclarationReducer extends CloneReducer {
reduceLabeledStatement(node, { body }) {
if (body.type === 'FunctionDeclaration') {
return body;
}
return node;
}
}
class NoLabeledBreakContinueReducer extends CloneReducer {
reduceBreakStatement(node) {
return {
...node,
label: null,
};
}
}
class UniqueBindingIdentifiersReducer extends CloneReducer {
constructor() {
super();
this.boundNames = new Set();
}
reduceBindingIdentifier(node) {
if (!this.boundNames.has(node.name)) {
this.boundNames.add(node.name);
return node;
}
return {
...node,
name: node.name + Math.random().toString(16).slice(2),
};
}
}
export default shiftAST => {
[
NoNonStrictFeaturesReducer,
RegexReducer,
NoReservedKeywordsReducer,
NoIdentifierDuplicatingAnImportReducer,
NoUndeclaredExportReducer,
NoLabeledFunctionDeclarationReducer,
UniqueBindingIdentifiersReducer,
NoLabeledBreakContinueReducer,
].forEach(Reducer => {
const scope = analyzeScope(shiftAST);
const scopeLookup = new ScopeLookup(scope);
shiftAST = reduceUsing(new Reducer(scopeLookup), shiftAST);
});
return shiftAST;
};