Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
export default function countVariableUsages(node: Node, name: string): number {
let numUsages = 0;
traverse(node, child => {
// Make sure it's the name we're looking for.
if (!(child instanceof Identifier) || child.data !== name) {
return;
}
// Skip `b` in `a.b`.
if (child.parentNode instanceof MemberAccessOp && child.parentNode.member === child) {
return;
}
// Skip `a` in `{ a: b }`, but not in `{ a }` or `{ [a]: b }`.
if (
child.parentNode instanceof ObjectInitialiserMember &&
child.parentNode.key === child &&
// `{ a }`
child.parentNode.expression !== null &&
// it might be modified.
if (this.isThisAssignIndexBinding()) {
return true;
}
const userIndex = this.getIndexBinding();
// We need to extract this to a variable if there's an assignment within the
// loop, but assignments outside the loop are fine, so we make a fake scope
// that only looks at assignments within the loop body. But assignments
// within closures could also happen temporally in the loop, so bail out if
// we see one of those.
if (this.getScope().hasInnerClosureModification(userIndex)) {
return true;
}
const fakeScope = new Scope(this.node, null);
traverse(this.node, child => {
fakeScope.processNode(child);
});
return fakeScope.hasModificationAfterDeclaration(userIndex);
}
initialize(): void {
for (const iifePatcher of this._iifePatcherDescendants) {
if (!iifePatcher.willPatchAsIIFE()) {
continue;
}
// Use the scope code to find all assignments, including loop assignees,
// destructuring, etc.
const fakeScope = new Scope(iifePatcher.node);
traverse(iifePatcher.node, child => {
fakeScope.processNode(child);
});
for (const name of fakeScope.getOwnNames()) {
if (
countVariableUsages(this.node, name) > countVariableUsages(iifePatcher.node, name) &&
this._explicitDeclarationsToAdd.indexOf(name) === -1
) {
this._explicitDeclarationsToAdd.push(name);
}
}
}
}
stdin.on('end', () => {
let magicString = new MagicString(input);
let ast = parse(input);
console.log(ast.context.tokens);
let patcher = makePatcher(ast, ast.context, magicString);
patcher.patch();
console.log(magicString.toString());
});
function computeParentMap(program: Program): Map {
const resultMap: Map = new Map();
traverse(program, (node, parent) => {
resultMap.set(node, parent);
});
return resultMap;
}
function computeScopeMap(program: Program): Map {
const scopeMap: Map = new Map();
traverse(program, (node, parent) => {
let scope;
switch (node.type) {
case 'Program':
scope = new Scope(node);
break;
case 'Function':
case 'BoundFunction':
case 'GeneratorFunction':
case 'BoundGeneratorFunction':
case 'AsyncFunction':
case 'Class': {
const parentScope = parent && scopeMap.get(parent);
if (!parentScope) {
throw new Error('Expected to find parent scope.');
}
export default function containsDescendant(
node: Node,
predicate: (node: Node) => boolean,
{ shouldStopTraversal = () => false }: { shouldStopTraversal?: (node: Node) => boolean } = {}
): boolean {
let found = false;
traverse(node, childNode => {
if (found) {
return false;
}
if (predicate(childNode)) {
found = true;
return false;
}
if (shouldStopTraversal(childNode)) {
return false;
}
return true;
});
return found;
}
const tokens = useCS2 ? getCoffee2Tokens(source) : getCoffee1Tokens(source);
return {
code: formatCoffeeScriptLexerTokens(tokens, context)
};
} else if (stageName === 'coffeescript-parser') {
const nodes = useCS2 ? getCoffee2Nodes(source) : getCoffee1Nodes(source);
return {
code: formatCoffeeScriptAst(nodes, context)
};
} else if (stageName === 'coffee-lex') {
return {
code: formatCoffeeLexTokens(lex(source, { useCS2 }), context)
};
} else if (stageName === 'decaffeinate-parser') {
return {
code: formatDecaffeinateParserAst(decaffeinateParse(source, { useCS2 }), context)
};
} else {
throw new Error(`Unrecognized stage name: ${stageName}`);
}
}
export default function parse(source: string): Node {
let ast = decaffeinateParse(source);
traverse(ast, attachScope);
return ast;
}
static create(source: string, useCS2: boolean): DecaffeinateContext {
const program = decaffeinateParse(source, { useCS2 });
return new DecaffeinateContext(
program,
source,
program.context.sourceTokens,
program.context.ast,
program.context.linesAndColumns,
computeParentMap(program),
computeScopeMap(program)
);
}