Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F100650789
BlockStatement.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Feb 1, 12:50
Size
10 KB
Mime Type
text/x-java
Expires
Mon, Feb 3, 12:50 (2 d)
Engine
blob
Format
Raw Data
Handle
24007121
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
BlockStatement.js
View Options
import Node from './Node.js';
import Scope from './Scope.js';
import destructure from '../utils/destructure.js';
function isUseStrict(node) {
if (!node) return false;
if (node.type !== 'ExpressionStatement') return false;
if (node.expression.type !== 'Literal') return false;
return node.expression.value === 'use strict';
}
export default class BlockStatement extends Node {
createScope() {
this.parentIsFunction = /Function/.test(this.parent.type);
this.isFunctionBlock = this.parentIsFunction || this.parent.type === 'Root';
this.scope = new Scope({
block: !this.isFunctionBlock,
parent: this.parent.findScope(false),
declare: id => this.createdDeclarations.push(id)
});
if (this.parentIsFunction) {
this.parent.params.forEach(node => {
this.scope.addDeclaration(node, 'param');
});
}
}
initialise(transforms) {
this.thisAlias = null;
this.argumentsAlias = null;
this.defaultParameters = [];
this.createdDeclarations = [];
// normally the scope gets created here, during initialisation,
// but in some cases (e.g. `for` statements), we need to create
// the scope early, as it pertains to both the init block and
// the body of the statement
if (!this.scope) this.createScope();
this.body.forEach(node => node.initialise(transforms));
this.scope.consolidate();
}
findLexicalBoundary() {
if (this.type === 'Program') return this;
if (/^Function/.test(this.parent.type)) return this;
return this.parent.findLexicalBoundary();
}
findScope(functionScope) {
if (functionScope && !this.isFunctionBlock)
return this.parent.findScope(functionScope);
return this.scope;
}
getArgumentsAlias() {
if (!this.argumentsAlias) {
this.argumentsAlias = this.scope.createIdentifier('arguments');
}
return this.argumentsAlias;
}
getArgumentsArrayAlias() {
if (!this.argumentsArrayAlias) {
this.argumentsArrayAlias = this.scope.createIdentifier('argsArray');
}
return this.argumentsArrayAlias;
}
getThisAlias() {
if (!this.thisAlias) {
this.thisAlias = this.scope.createIdentifier('this');
}
return this.thisAlias;
}
getIndentation() {
if (this.indentation === undefined) {
const source = this.program.magicString.original;
const useOuter = this.synthetic || !this.body.length;
let c = useOuter ? this.start : this.body[0].start;
while (c && source[c] !== '\n') c -= 1;
this.indentation = '';
// eslint-disable-next-line no-constant-condition
while (true) {
c += 1;
const char = source[c];
if (char !== ' ' && char !== '\t') break;
this.indentation += char;
}
const indentString = this.program.magicString.getIndentString();
// account for dedented class constructors
let parent = this.parent;
while (parent) {
if (parent.kind === 'constructor' && !parent.parent.parent.superClass) {
this.indentation = this.indentation.replace(indentString, '');
}
parent = parent.parent;
}
if (useOuter) this.indentation += indentString;
}
return this.indentation;
}
transpile(code, transforms) {
const indentation = this.getIndentation();
const introStatementGenerators = [];
if (this.argumentsAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.argumentsAlias} = arguments${
suffix
}`;
code.appendLeft(start, assignment);
});
}
if (this.thisAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.thisAlias} = this${suffix}`;
code.appendLeft(start, assignment);
});
}
if (this.argumentsArrayAlias) {
introStatementGenerators.push((start, prefix, suffix) => {
const i = this.scope.createIdentifier('i');
const assignment = `${prefix}var ${i} = arguments.length, ${
this.argumentsArrayAlias
} = Array(${i});\n${indentation}while ( ${i}-- ) ${
this.argumentsArrayAlias
}[${i}] = arguments[${i}]${suffix}`;
code.appendLeft(start, assignment);
});
}
if (/Function/.test(this.parent.type)) {
this.transpileParameters(
this.parent.params,
code,
transforms,
indentation,
introStatementGenerators
);
} else if ('CatchClause' === this.parent.type) {
this.transpileParameters(
[this.parent.param],
code,
transforms,
indentation,
introStatementGenerators
);
}
if (transforms.letConst && this.isFunctionBlock) {
this.transpileBlockScopedIdentifiers(code);
}
super.transpile(code, transforms);
if (this.createdDeclarations.length) {
introStatementGenerators.push((start, prefix, suffix) => {
const assignment = `${prefix}var ${this.createdDeclarations.join(', ')}${suffix}`;
code.appendLeft(start, assignment);
});
}
if (this.synthetic) {
if (this.parent.type === 'ArrowFunctionExpression') {
const expr = this.body[0];
if (introStatementGenerators.length) {
code
.appendLeft(this.start, `{`)
.prependRight(this.end, `${this.parent.getIndentation()}}`);
code.prependRight(expr.start, `\n${indentation}return `);
code.appendLeft(expr.end, `;\n`);
} else if (transforms.arrow) {
code.prependRight(expr.start, `{ return `);
code.appendLeft(expr.end, `; }`);
}
} else if (introStatementGenerators.length) {
code.prependRight(this.start, `{`).appendLeft(this.end, `}`);
}
}
let start;
if (isUseStrict(this.body[0])) {
start = this.body[0].end;
} else if (this.synthetic || this.parent.type === 'Root') {
start = this.start;
} else {
start = this.start + 1;
}
const prefix = `\n${indentation}`;
let suffix = ';';
introStatementGenerators.forEach((fn, i) => {
if (i === introStatementGenerators.length - 1) suffix = `;\n`;
fn(start, prefix, suffix);
});
}
transpileParameters(params, code, transforms, indentation, introStatementGenerators) {
params.forEach(param => {
if (
param.type === 'AssignmentPattern' &&
param.left.type === 'Identifier'
) {
if (transforms.defaultParameter) {
introStatementGenerators.push((start, prefix, suffix) => {
const lhs = `${prefix}if ( ${param.left.name} === void 0 ) ${
param.left.name
}`;
code
.prependRight(param.left.end, lhs)
.move(param.left.end, param.right.end, start)
.appendLeft(param.right.end, suffix);
});
}
} else if (param.type === 'RestElement') {
if (transforms.spreadRest) {
introStatementGenerators.push((start, prefix, suffix) => {
const penultimateParam = params[params.length - 2];
if (penultimateParam) {
code.remove(
penultimateParam ? penultimateParam.end : param.start,
param.end
);
} else {
let start = param.start,
end = param.end; // TODO https://gitlab.com/Rich-Harris/buble/issues/8
while (/\s/.test(code.original[start - 1])) start -= 1;
while (/\s/.test(code.original[end])) end += 1;
code.remove(start, end);
}
const name = param.argument.name;
const len = this.scope.createIdentifier('len');
const count = params.length - 1;
if (count) {
code.prependRight(
start,
`${prefix}var ${name} = [], ${len} = arguments.length - ${
count
};\n${indentation}while ( ${len}-- > 0 ) ${name}[ ${
len
} ] = arguments[ ${len} + ${count} ]${suffix}`
);
} else {
code.prependRight(
start,
`${prefix}var ${name} = [], ${len} = arguments.length;\n${
indentation
}while ( ${len}-- ) ${name}[ ${len} ] = arguments[ ${len} ]${
suffix
}`
);
}
});
}
} else if (param.type !== 'Identifier') {
if (transforms.parameterDestructuring) {
const ref = this.scope.createIdentifier('ref');
destructure(
code,
id => this.scope.createIdentifier(id),
({ name }) => this.scope.resolveName(name),
param,
ref,
false,
introStatementGenerators
);
code.prependRight(param.start, ref);
}
}
});
}
transpileBlockScopedIdentifiers(code) {
Object.keys(this.scope.blockScopedDeclarations).forEach(name => {
const declarations = this.scope.blockScopedDeclarations[name];
for (const declaration of declarations) {
let cont = false; // TODO implement proper continue...
if (declaration.kind === 'for.let') {
// special case
const forStatement = declaration.node.findNearest('ForStatement');
if (forStatement.shouldRewriteAsFunction) {
const outerAlias = this.scope.createIdentifier(name);
const innerAlias = forStatement.reassigned[name]
? this.scope.createIdentifier(name)
: name;
declaration.name = outerAlias;
code.overwrite(
declaration.node.start,
declaration.node.end,
outerAlias,
{ storeName: true }
);
forStatement.aliases[name] = {
outer: outerAlias,
inner: innerAlias
};
for (const identifier of declaration.instances) {
const alias = forStatement.body.contains(identifier)
? innerAlias
: outerAlias;
if (name !== alias) {
code.overwrite(identifier.start, identifier.end, alias, {
storeName: true
});
}
}
cont = true;
}
}
if (!cont) {
const alias = this.scope.createIdentifier(name);
if (name !== alias) {
const declarationParent = declaration.node.parent;
declaration.name = alias;
code.overwrite(
declaration.node.start,
declaration.node.end,
alias,
{ storeName: true }
);
if (declarationParent.type === 'Property' && declarationParent.shorthand) {
declarationParent.shorthand = false;
code.prependLeft(declaration.node.start, `${name}: `);
}
for (const identifier of declaration.instances) {
identifier.rewritten = true;
const identifierParent = identifier.parent;
code.overwrite(identifier.start, identifier.end, alias, {
storeName: true
});
if (identifierParent.type === 'Property' && identifierParent.shorthand) {
identifierParent.shorthand = false;
code.prependLeft(identifier.start, `${name}: `);
}
}
}
}
}
});
}
}
Event Timeline
Log In to Comment