Refactor emit substitution into transform (#42676)

* Refactor emit substitution into transform

* Add reusable state machine for binary expressions

* Allow emitBinary to use state machine for comments/sourcemaps

* Switch core trampoline state back to arrays

* Switch binder to parallel stacks, temporarily partially revert emitBinary

* Add link to benchmark when posting perf results

* Ensure work stacks are per-execution

* Reenable comments and sourcemaps
This commit is contained in:
Ron Buckton 2021-02-25 23:01:41 -08:00 committed by GitHub
parent df5ffc0ea1
commit 68b0323b72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 3281 additions and 1538 deletions

View file

@ -3,45 +3,86 @@
// Must reference esnext.asynciterable lib, since octokit uses AsyncIterable internally
const { Octokit } = require("@octokit/rest");
const fs = require("fs");
const ado = require("azure-devops-node-api");
const { default: fetch } = require("node-fetch");
const requester = process.env.requesting_user;
const source = process.env.source_issue;
const postedComment = process.env.status_comment;
console.log(`Loading fragment from ${process.argv[3]}...`);
const outputTableText = fs.readFileSync(process.argv[3], { encoding: "utf8" });
console.log(`Fragment contents:
${outputTableText}`);
const gh = new Octokit({
auth: process.argv[2]
});
gh.issues.createComment({
issue_number: +source,
owner: "Microsoft",
repo: "TypeScript",
body: `@${requester}
The results of the perf run you requested are in!
<details><summary> Here they are:</summary><p>
${outputTableText}
</p></details>`
}).then(async data => {
console.log(`Results posted!`);
const newCommentUrl = data.data.html_url;
const comment = await gh.issues.getComment({
owner: "Microsoft",
repo: "TypeScript",
comment_id: +postedComment
});
const newBody = `${comment.data.body}
async function main() {
const source = process.env.SOURCE_ISSUE;
if (!source) throw new Error("SOURCE_ISSUE environment variable not set.");
Update: [The results are in!](${newCommentUrl})`;
return await gh.issues.updateComment({
owner: "Microsoft",
repo: "TypeScript",
comment_id: +postedComment,
body: newBody
});
}).catch(e => {
const requester = process.env.REQUESTING_USER;
if (!requester) throw new Error("REQUESTING_USER environment variable not set.");
const buildId = process.env.BUILD_BUILDID;
if (!requester) throw new Error("BUILD_BUILDID environment variable not set.");
const postedComment = process.env.STATUS_COMMENT;
if (!postedComment) throw new Error("STATUS_COMMENT environment variable not set.");
const [auth, fragment, includeArtifact] = process.argv.slice(2);
if (!auth) throw new Error("First argument must be a GitHub auth token.");
if (!fragment) throw new Error("Second argument must be a path to an HTML fragment.");
const gh = new Octokit({ auth });
try {
console.log(`Loading fragment from ${fragment}...`);
const outputTableText = fs.readFileSync(fragment, { encoding: "utf8" });
console.log(`Fragment contents:\n${outputTableText}`);
let benchmarkText = "";
if (includeArtifact === "--include-artifact") {
// post a link to the benchmark file
const cli = new ado.WebApi("https://typescript.visualstudio.com/defaultcollection", ado.getHandlerFromToken("")); // Empty token, anon auth
const build = await cli.getBuildApi();
const artifact = await build.getArtifact("typescript", +buildId, "benchmark");
const updatedUrl = new URL(artifact.resource.url);
updatedUrl.search = `artifactName=benchmark&fileId=${artifact.resource.data}&fileName=manifest`;
const resp = await (await fetch(`${updatedUrl}`)).json();
for (const file of resp.items) {
if (/[\\/]linux\.benchmark$/.test(file.path)) {
const benchmarkUrl = new URL(artifact.resource.url);
benchmarkUrl.search = `artifactName=benchmark&fileId=${file.blob.id}&fileName=linux.benchmark`;
benchmarkText = `\n<details><summary>Developer Information:</summary><p><a href="${benchmarkUrl.href}">Download Benchmark</a></p></details>\n`;
break;
}
}
}
const data = await gh.issues.createComment({
issue_number: +source,
owner: "Microsoft",
repo: "TypeScript",
body: `@${requester}\nThe results of the perf run you requested are in!\n<details><summary> Here they are:</summary><p>\n${outputTableText}\n</p>${benchmarkText}</details>`
});
console.log(`Results posted!`);
const newCommentUrl = data.data.html_url;
const comment = await gh.issues.getComment({
owner: "Microsoft",
repo: "TypeScript",
comment_id: +postedComment
});
const newBody = `${comment.data.body}\n\nUpdate: [The results are in!](${newCommentUrl})`;
await gh.issues.updateComment({
owner: "Microsoft",
repo: "TypeScript",
comment_id: +postedComment,
body: newBody
});
}
catch (e) {
const gh = new Octokit({ auth });
await gh.issues.createComment({
issue_number: +source,
owner: "Microsoft",
repo: "TypeScript",
body: `Hey @${requester}, something went wrong when publishing results. ([You can check the log here](https://typescript.visualstudio.com/TypeScript/_build/index?buildId=${buildId}&_a=summary)).`
});
}
}
main().catch(e => {
console.error(e);
process.exit(1);
});

View file

@ -227,6 +227,7 @@ namespace ts {
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
const bindBinaryExpressionFlow = createBindBinaryExpressionFlow();
/**
* Inside the binder, we may create a diagnostic for an as-yet unbound node (with potentially no parent pointers, implying no accessible source file)
@ -1497,132 +1498,110 @@ namespace ts {
bindAssignmentTargetFlow(node.left);
}
const enum BindBinaryExpressionFlowState {
BindThenBindChildren,
MaybeBindLeft,
BindToken,
BindRight,
FinishBind
}
function bindBinaryExpressionFlow(node: BinaryExpression) {
const workStacks: {
expr: BinaryExpression[],
state: BindBinaryExpressionFlowState[],
inStrictMode: (boolean | undefined)[],
parent: (Node | undefined)[],
} = {
expr: [node],
state: [BindBinaryExpressionFlowState.MaybeBindLeft],
inStrictMode: [undefined],
parent: [undefined],
};
let stackIndex = 0;
while (stackIndex >= 0) {
node = workStacks.expr[stackIndex];
switch (workStacks.state[stackIndex]) {
case BindBinaryExpressionFlowState.BindThenBindChildren: {
// This state is used only when recuring, to emulate the work that `bind` does before
// reaching `bindChildren`. A normal call to `bindBinaryExpressionFlow` will already have done this work.
setParent(node, parent);
const saveInStrictMode = inStrictMode;
bindWorker(node);
const saveParent = parent;
parent = node;
advanceState(BindBinaryExpressionFlowState.MaybeBindLeft, saveInStrictMode, saveParent);
break;
}
case BindBinaryExpressionFlowState.MaybeBindLeft: {
const operator = node.operatorToken.kind;
// TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions
// we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too
// For now, though, since the common cases are chained `+`, leaving it recursive is fine
if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken ||
isLogicalOrCoalescingAssignmentOperator(operator)) {
if (isTopLevelLogicalExpression(node)) {
const postExpressionLabel = createBranchLabel();
bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel);
currentFlow = finishFlowLabel(postExpressionLabel);
}
else {
bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
}
completeNode();
}
else {
advanceState(BindBinaryExpressionFlowState.BindToken);
maybeBind(node.left);
}
break;
}
case BindBinaryExpressionFlowState.BindToken: {
if (node.operatorToken.kind === SyntaxKind.CommaToken) {
maybeBindExpressionFlowIfCall(node.left);
}
advanceState(BindBinaryExpressionFlowState.BindRight);
maybeBind(node.operatorToken);
break;
}
case BindBinaryExpressionFlowState.BindRight: {
advanceState(BindBinaryExpressionFlowState.FinishBind);
maybeBind(node.right);
break;
}
case BindBinaryExpressionFlowState.FinishBind: {
const operator = node.operatorToken.kind;
if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) {
bindAssignmentTargetFlow(node.left);
if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) {
const elementAccess = <ElementAccessExpression>node.left;
if (isNarrowableOperand(elementAccess.expression)) {
currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node);
}
}
}
completeNode();
break;
}
default: return Debug.fail(`Invalid state ${workStacks.state[stackIndex]} for bindBinaryExpressionFlow`);
}
function createBindBinaryExpressionFlow() {
interface WorkArea {
stackIndex: number;
skip: boolean;
inStrictModeStack: (boolean | undefined)[];
parentStack: (Node | undefined)[];
}
/**
* Note that `advanceState` sets the _current_ head state, and that `maybeBind` potentially pushes on a new
* head state; so `advanceState` must be called before any `maybeBind` during a state's execution.
*/
function advanceState(state: BindBinaryExpressionFlowState, isInStrictMode?: boolean, parent?: Node) {
workStacks.state[stackIndex] = state;
if (isInStrictMode !== undefined) {
workStacks.inStrictMode[stackIndex] = isInStrictMode;
}
if (parent !== undefined) {
workStacks.parent[stackIndex] = parent;
}
}
return createBinaryExpressionTrampoline(onEnter, onLeft, onOperator, onRight, onExit, /*foldState*/ undefined);
function completeNode() {
if (workStacks.inStrictMode[stackIndex] !== undefined) {
inStrictMode = workStacks.inStrictMode[stackIndex]!;
parent = workStacks.parent[stackIndex]!;
}
stackIndex--;
}
/**
* If `node` is a BinaryExpression, adds it to the local work stack, otherwise recursively binds it
*/
function maybeBind(node: Node) {
if (node && isBinaryExpression(node) && !isDestructuringAssignment(node)) {
stackIndex++;
workStacks.expr[stackIndex] = node;
workStacks.state[stackIndex] = BindBinaryExpressionFlowState.BindThenBindChildren;
workStacks.inStrictMode[stackIndex] = undefined;
workStacks.parent[stackIndex] = undefined;
function onEnter(node: BinaryExpression, state: WorkArea | undefined) {
if (state) {
state.stackIndex++;
// Emulate the work that `bind` does before reaching `bindChildren`. A normal call to
// `bindBinaryExpressionFlow` will already have done this work.
setParent(node, parent);
const saveInStrictMode = inStrictMode;
bindWorker(node);
const saveParent = parent;
parent = node;
state.skip = false;
state.inStrictModeStack[state.stackIndex] = saveInStrictMode;
state.parentStack[state.stackIndex] = saveParent;
}
else {
bind(node);
state = {
stackIndex: 0,
skip: false,
inStrictModeStack: [undefined],
parentStack: [undefined]
};
}
// TODO: bindLogicalExpression is recursive - if we want to handle deeply nested `&&` expressions
// we'll need to handle the `bindLogicalExpression` scenarios in this state machine, too
// For now, though, since the common cases are chained `+`, leaving it recursive is fine
const operator = node.operatorToken.kind;
if (operator === SyntaxKind.AmpersandAmpersandToken ||
operator === SyntaxKind.BarBarToken ||
operator === SyntaxKind.QuestionQuestionToken ||
isLogicalOrCoalescingAssignmentOperator(operator)) {
if (isTopLevelLogicalExpression(node)) {
const postExpressionLabel = createBranchLabel();
bindLogicalLikeExpression(node, postExpressionLabel, postExpressionLabel);
currentFlow = finishFlowLabel(postExpressionLabel);
}
else {
bindLogicalLikeExpression(node, currentTrueTarget!, currentFalseTarget!);
}
state.skip = true;
}
return state;
}
function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) {
if (!state.skip) {
return maybeBind(left);
}
}
function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) {
if (!state.skip) {
if (operatorToken.kind === SyntaxKind.CommaToken) {
maybeBindExpressionFlowIfCall(node.left);
}
bind(operatorToken);
}
}
function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) {
if (!state.skip) {
return maybeBind(right);
}
}
function onExit(node: BinaryExpression, state: WorkArea) {
if (!state.skip) {
const operator = node.operatorToken.kind;
if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) {
bindAssignmentTargetFlow(node.left);
if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) {
const elementAccess = <ElementAccessExpression>node.left;
if (isNarrowableOperand(elementAccess.expression)) {
currentFlow = createFlowMutation(FlowFlags.ArrayMutation, currentFlow, node);
}
}
}
}
const savedInStrictMode = state.inStrictModeStack[state.stackIndex];
const savedParent = state.parentStack[state.stackIndex];
if (savedInStrictMode !== undefined) {
inStrictMode = savedInStrictMode;
}
if (savedParent !== undefined) {
parent = savedParent;
}
state.skip = false;
state.stackIndex--;
}
function maybeBind(node: Node) {
if (node && isBinaryExpression(node) && !isDestructuringAssignment(node)) {
return node;
}
bind(node);
}
}

View file

@ -275,6 +275,14 @@ namespace ts {
}
}
/**
* Asserts a value has the specified type in typespace only (does not perform a runtime assertion).
* This is useful in cases where we switch on `node.kind` and can be reasonably sure the type is accurate, and
* as a result can reduce the number of unnecessary casts.
*/
export function type<T>(value: unknown): asserts value is T;
export function type(_value: unknown) { }
export function getFunctionName(func: AnyFunction) {
if (typeof func !== "function") {
return "";

File diff suppressed because it is too large Load diff

View file

@ -39,12 +39,106 @@ namespace ts {
return node.kind === SyntaxKind.TemplateTail;
}
// Punctuation
export function isDotDotDotToken(node: Node): node is DotDotDotToken {
return node.kind === SyntaxKind.DotDotDotToken;
}
/*@internal*/
export function isCommaToken(node: Node): node is Token<SyntaxKind.CommaToken> {
return node.kind === SyntaxKind.CommaToken;
}
export function isPlusToken(node: Node): node is PlusToken {
return node.kind === SyntaxKind.PlusToken;
}
export function isMinusToken(node: Node): node is MinusToken {
return node.kind === SyntaxKind.MinusToken;
}
export function isAsteriskToken(node: Node): node is AsteriskToken {
return node.kind === SyntaxKind.AsteriskToken;
}
/*@internal*/
export function isExclamationToken(node: Node): node is ExclamationToken {
return node.kind === SyntaxKind.ExclamationToken;
}
/*@internal*/
export function isQuestionToken(node: Node): node is QuestionToken {
return node.kind === SyntaxKind.QuestionToken;
}
/*@internal*/
export function isColonToken(node: Node): node is ColonToken {
return node.kind === SyntaxKind.ColonToken;
}
/*@internal*/
export function isQuestionDotToken(node: Node): node is QuestionDotToken {
return node.kind === SyntaxKind.QuestionDotToken;
}
/*@internal*/
export function isEqualsGreaterThanToken(node: Node): node is EqualsGreaterThanToken {
return node.kind === SyntaxKind.EqualsGreaterThanToken;
}
// Identifiers
export function isIdentifier(node: Node): node is Identifier {
return node.kind === SyntaxKind.Identifier;
}
export function isPrivateIdentifier(node: Node): node is PrivateIdentifier {
return node.kind === SyntaxKind.PrivateIdentifier;
}
// Reserved Words
/* @internal */
export function isExportModifier(node: Node): node is ExportKeyword {
return node.kind === SyntaxKind.ExportKeyword;
}
/* @internal */
export function isAsyncModifier(node: Node): node is AsyncKeyword {
return node.kind === SyntaxKind.AsyncKeyword;
}
/* @internal */
export function isAssertsKeyword(node: Node): node is AssertsKeyword {
return node.kind === SyntaxKind.AssertsKeyword;
}
/* @internal */
export function isAwaitKeyword(node: Node): node is AwaitKeyword {
return node.kind === SyntaxKind.AwaitKeyword;
}
/* @internal */
export function isReadonlyKeyword(node: Node): node is ReadonlyKeyword {
return node.kind === SyntaxKind.ReadonlyKeyword;
}
/* @internal */
export function isStaticModifier(node: Node): node is StaticKeyword {
return node.kind === SyntaxKind.StaticKeyword;
}
/*@internal*/
export function isSuperKeyword(node: Node): node is SuperExpression {
return node.kind === SyntaxKind.SuperKeyword;
}
/*@internal*/
export function isImportKeyword(node: Node): node is ImportExpression {
return node.kind === SyntaxKind.ImportKeyword;
}
// Names
export function isQualifiedName(node: Node): node is QualifiedName {
@ -55,37 +149,6 @@ namespace ts {
return node.kind === SyntaxKind.ComputedPropertyName;
}
export function isPrivateIdentifier(node: Node): node is PrivateIdentifier {
return node.kind === SyntaxKind.PrivateIdentifier;
}
// Tokens
/*@internal*/
export function isSuperKeyword(node: Node): node is Token<SyntaxKind.SuperKeyword> {
return node.kind === SyntaxKind.SuperKeyword;
}
/*@internal*/
export function isImportKeyword(node: Node): node is Token<SyntaxKind.ImportKeyword> {
return node.kind === SyntaxKind.ImportKeyword;
}
/*@internal*/
export function isCommaToken(node: Node): node is Token<SyntaxKind.CommaToken> {
return node.kind === SyntaxKind.CommaToken;
}
/*@internal*/
export function isQuestionToken(node: Node): node is Token<SyntaxKind.QuestionToken> {
return node.kind === SyntaxKind.QuestionToken;
}
/*@internal*/
export function isExclamationToken(node: Node): node is Token<SyntaxKind.ExclamationToken> {
return node.kind === SyntaxKind.ExclamationToken;
}
// Signature elements
export function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration {

View file

@ -13,7 +13,7 @@ namespace ts {
}
else {
const expression = setTextRange(
isIdentifierOrPrivateIdentifier(memberName)
isMemberName(memberName)
? factory.createPropertyAccessExpression(target, memberName)
: factory.createElementAccessExpression(target, memberName),
memberName
@ -412,7 +412,7 @@ namespace ts {
const helperNames: string[] = [];
for (const helper of helpers) {
if (!helper.scoped) {
const importName = (helper as UnscopedEmitHelper).importName;
const importName = helper.importName;
if (importName) {
pushIfUnique(helperNames, importName);
}
@ -815,18 +815,300 @@ namespace ts {
|| kind === SyntaxKind.ExportDeclaration;
}
/* @internal */
export function isExportModifier(node: Modifier): node is ExportKeyword {
return node.kind === SyntaxKind.ExportKeyword;
export const isTypeNodeOrTypeParameterDeclaration = or(isTypeNode, isTypeParameterDeclaration) as (node: Node) => node is TypeNode | TypeParameterDeclaration;
export const isQuestionOrExclamationToken = or(isQuestionToken, isExclamationToken) as (node: Node) => node is QuestionToken | ExclamationToken;
export const isIdentifierOrThisTypeNode = or(isIdentifier, isThisTypeNode) as (node: Node) => node is Identifier | ThisTypeNode;
export const isReadonlyKeywordOrPlusOrMinusToken = or(isReadonlyKeyword, isPlusToken, isMinusToken) as (node: Node) => node is ReadonlyKeyword | PlusToken | MinusToken;
export const isQuestionOrPlusOrMinusToken = or(isQuestionToken, isPlusToken, isMinusToken) as (node: Node) => node is QuestionToken | PlusToken | MinusToken;
export const isModuleName = or(isIdentifier, isStringLiteral) as (node: Node) => node is ModuleName;
export function isLiteralTypeLikeExpression(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression {
const kind = node.kind;
return kind === SyntaxKind.NullKeyword
|| kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.FalseKeyword
|| isLiteralExpression(node)
|| isPrefixUnaryExpression(node);
}
/* @internal */
export function isAsyncModifier(node: Modifier): node is AsyncKeyword {
return node.kind === SyntaxKind.AsyncKeyword;
function isExponentiationOperator(kind: SyntaxKind): kind is ExponentiationOperator {
return kind === SyntaxKind.AsteriskAsteriskToken;
}
/* @internal */
export function isStaticModifier(node: Modifier): node is StaticKeyword {
return node.kind === SyntaxKind.StaticKeyword;
function isMultiplicativeOperator(kind: SyntaxKind): kind is MultiplicativeOperator {
return kind === SyntaxKind.AsteriskToken
|| kind === SyntaxKind.SlashToken
|| kind === SyntaxKind.PercentToken;
}
function isMultiplicativeOperatorOrHigher(kind: SyntaxKind): kind is MultiplicativeOperatorOrHigher {
return isExponentiationOperator(kind)
|| isMultiplicativeOperator(kind);
}
function isAdditiveOperator(kind: SyntaxKind): kind is AdditiveOperator {
return kind === SyntaxKind.PlusToken
|| kind === SyntaxKind.MinusToken;
}
function isAdditiveOperatorOrHigher(kind: SyntaxKind): kind is AdditiveOperatorOrHigher {
return isAdditiveOperator(kind)
|| isMultiplicativeOperatorOrHigher(kind);
}
function isShiftOperator(kind: SyntaxKind): kind is ShiftOperator {
return kind === SyntaxKind.LessThanLessThanToken
|| kind === SyntaxKind.GreaterThanGreaterThanToken
|| kind === SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
}
function isShiftOperatorOrHigher(kind: SyntaxKind): kind is ShiftOperatorOrHigher {
return isShiftOperator(kind)
|| isAdditiveOperatorOrHigher(kind);
}
function isRelationalOperator(kind: SyntaxKind): kind is RelationalOperator {
return kind === SyntaxKind.LessThanToken
|| kind === SyntaxKind.LessThanEqualsToken
|| kind === SyntaxKind.GreaterThanToken
|| kind === SyntaxKind.GreaterThanEqualsToken
|| kind === SyntaxKind.InstanceOfKeyword
|| kind === SyntaxKind.InKeyword;
}
function isRelationalOperatorOrHigher(kind: SyntaxKind): kind is RelationalOperatorOrHigher {
return isRelationalOperator(kind)
|| isShiftOperatorOrHigher(kind);
}
function isEqualityOperator(kind: SyntaxKind): kind is EqualityOperator {
return kind === SyntaxKind.EqualsEqualsToken
|| kind === SyntaxKind.EqualsEqualsEqualsToken
|| kind === SyntaxKind.ExclamationEqualsToken
|| kind === SyntaxKind.ExclamationEqualsEqualsToken;
}
function isEqualityOperatorOrHigher(kind: SyntaxKind): kind is EqualityOperatorOrHigher {
return isEqualityOperator(kind)
|| isRelationalOperatorOrHigher(kind);
}
function isBitwiseOperator(kind: SyntaxKind): kind is BitwiseOperator {
return kind === SyntaxKind.AmpersandToken
|| kind === SyntaxKind.BarToken
|| kind === SyntaxKind.CaretToken;
}
function isBitwiseOperatorOrHigher(kind: SyntaxKind): kind is BitwiseOperatorOrHigher {
return isBitwiseOperator(kind)
|| isEqualityOperatorOrHigher(kind);
}
// NOTE: The version in utilities includes ExclamationToken, which is not a binary operator.
function isLogicalOperator(kind: SyntaxKind): kind is LogicalOperator {
return kind === SyntaxKind.AmpersandAmpersandToken
|| kind === SyntaxKind.BarBarToken;
}
function isLogicalOperatorOrHigher(kind: SyntaxKind): kind is LogicalOperatorOrHigher {
return isLogicalOperator(kind)
|| isBitwiseOperatorOrHigher(kind);
}
function isAssignmentOperatorOrHigher(kind: SyntaxKind): kind is AssignmentOperatorOrHigher {
return kind === SyntaxKind.QuestionQuestionToken
|| isLogicalOperatorOrHigher(kind)
|| isAssignmentOperator(kind);
}
function isBinaryOperator(kind: SyntaxKind): kind is BinaryOperator {
return isAssignmentOperatorOrHigher(kind)
|| kind === SyntaxKind.CommaToken;
}
export function isBinaryOperatorToken(node: Node): node is BinaryOperatorToken {
return isBinaryOperator(node.kind);
}
type BinaryExpressionState = <TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }) => number;
namespace BinaryExpressionState {
/**
* Handles walking into a `BinaryExpression`.
* @param machine State machine handler functions
* @param frame The current frame
* @returns The new frame
*/
export function enter<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number {
const prevUserState = stackIndex > 0 ? userStateStack[stackIndex - 1] : undefined;
Debug.assertEqual(stateStack[stackIndex], enter);
userStateStack[stackIndex] = machine.onEnter(nodeStack[stackIndex], prevUserState);
stateStack[stackIndex] = nextState(machine, enter);
return stackIndex;
}
/**
* Handles walking the `left` side of a `BinaryExpression`.
* @param machine State machine handler functions
* @param frame The current frame
* @returns The new frame
*/
export function left<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number {
Debug.assertEqual(stateStack[stackIndex], left);
Debug.assertIsDefined(machine.onLeft);
stateStack[stackIndex] = nextState(machine, left);
const nextNode = machine.onLeft(nodeStack[stackIndex].left, userStateStack[stackIndex], nodeStack[stackIndex]);
if (nextNode) {
checkCircularity(stackIndex, nodeStack, nextNode);
return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode);
}
return stackIndex;
}
/**
* Handles walking the `operatorToken` of a `BinaryExpression`.
* @param machine State machine handler functions
* @param frame The current frame
* @returns The new frame
*/
export function operator<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number {
Debug.assertEqual(stateStack[stackIndex], operator);
Debug.assertIsDefined(machine.onOperator);
stateStack[stackIndex] = nextState(machine, operator);
machine.onOperator(nodeStack[stackIndex].operatorToken, userStateStack[stackIndex], nodeStack[stackIndex]);
return stackIndex;
}
/**
* Handles walking the `right` side of a `BinaryExpression`.
* @param machine State machine handler functions
* @param frame The current frame
* @returns The new frame
*/
export function right<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], _resultHolder: { value: TResult }): number {
Debug.assertEqual(stateStack[stackIndex], right);
Debug.assertIsDefined(machine.onRight);
stateStack[stackIndex] = nextState(machine, right);
const nextNode = machine.onRight(nodeStack[stackIndex].right, userStateStack[stackIndex], nodeStack[stackIndex]);
if (nextNode) {
checkCircularity(stackIndex, nodeStack, nextNode);
return pushStack(stackIndex, stateStack, nodeStack, userStateStack, nextNode);
}
return stackIndex;
}
/**
* Handles walking out of a `BinaryExpression`.
* @param machine State machine handler functions
* @param frame The current frame
* @returns The new frame
*/
export function exit<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], resultHolder: { value: TResult }): number {
Debug.assertEqual(stateStack[stackIndex], exit);
stateStack[stackIndex] = nextState(machine, exit);
const result = machine.onExit(nodeStack[stackIndex], userStateStack[stackIndex]);
if (stackIndex > 0) {
stackIndex--;
if (machine.foldState) {
const side = stateStack[stackIndex] === exit ? "right" : "left";
userStateStack[stackIndex] = machine.foldState(userStateStack[stackIndex], result, side);
}
}
else {
resultHolder.value = result;
}
return stackIndex;
}
/**
* Handles a frame that is already done.
* @returns The `done` state.
*/
export function done<TState, TResult>(_machine: BinaryExpressionStateMachine<TState, TResult>, stackIndex: number, stateStack: BinaryExpressionState[], _nodeStack: BinaryExpression[], _userStateStack: TState[], _resultHolder: { value: TResult }): number {
Debug.assertEqual(stateStack[stackIndex], done);
return stackIndex;
}
export function nextState<TState, TResult>(machine: BinaryExpressionStateMachine<TState, TResult>, currentState: BinaryExpressionState) {
switch (currentState) {
case enter:
if (machine.onLeft) return left;
// falls through
case left:
if (machine.onOperator) return operator;
// falls through
case operator:
if (machine.onRight) return right;
// falls through
case right: return exit;
case exit: return done;
case done: return done;
default: Debug.fail("Invalid state");
}
}
function pushStack<TState>(stackIndex: number, stateStack: BinaryExpressionState[], nodeStack: BinaryExpression[], userStateStack: TState[], node: BinaryExpression) {
stackIndex++;
stateStack[stackIndex] = enter;
nodeStack[stackIndex] = node;
userStateStack[stackIndex] = undefined!;
return stackIndex;
}
function checkCircularity(stackIndex: number, nodeStack: BinaryExpression[], node: BinaryExpression) {
if (Debug.shouldAssert(AssertionLevel.Aggressive)) {
while (stackIndex >= 0) {
Debug.assert(nodeStack[stackIndex] !== node, "Circular traversal detected.");
stackIndex--;
}
}
}
}
/**
* Holds state machine handler functions
*/
class BinaryExpressionStateMachine<TState, TResult> {
constructor(
readonly onEnter: (node: BinaryExpression, prev: TState | undefined) => TState,
readonly onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined,
readonly onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined,
readonly onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined,
readonly onExit: (node: BinaryExpression, userState: TState) => TResult,
readonly foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined,
) {
}
}
/**
* Creates a state machine that walks a `BinaryExpression` using the heap to reduce call-stack depth on a large tree.
* @param onEnter Callback evaluated when entering a `BinaryExpression`. Returns new user-defined state to associate with the node while walking.
* @param onLeft Callback evaluated when walking the left side of a `BinaryExpression`. Return a `BinaryExpression` to continue walking, or `void` to advance to the right side.
* @param onRight Callback evaluated when walking the right side of a `BinaryExpression`. Return a `BinaryExpression` to continue walking, or `void` to advance to the end of the node.
* @param onExit Callback evaluated when exiting a `BinaryExpression`. The result returned will either be folded into the parent's state, or returned from the walker if at the top frame.
* @param foldState Callback evaluated when the result from a nested `onExit` should be folded into the state of that node's parent.
* @returns A function that walks a `BinaryExpression` node using the above callbacks, returning the result of the call to `onExit` from the outermost `BinaryExpression` node.
*/
export function createBinaryExpressionTrampoline<TState, TResult>(
onEnter: (node: BinaryExpression, prev: TState | undefined) => TState,
onLeft: ((left: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined,
onOperator: ((operatorToken: BinaryOperatorToken, userState: TState, node: BinaryExpression) => void) | undefined,
onRight: ((right: Expression, userState: TState, node: BinaryExpression) => BinaryExpression | void) | undefined,
onExit: (node: BinaryExpression, userState: TState) => TResult,
foldState: ((userState: TState, result: TResult, side: "left" | "right") => TState) | undefined,
) {
const machine = new BinaryExpressionStateMachine(onEnter, onLeft, onOperator, onRight, onExit, foldState);
return (node: BinaryExpression) => {
const resultHolder: { value: TResult } = { value: undefined! };
const stateStack: BinaryExpressionState[] = [BinaryExpressionState.enter];
const nodeStack: BinaryExpression[] = [node];
const userStateStack: TState[] = [undefined!];
let stackIndex = 0;
while (stateStack[stackIndex] !== BinaryExpressionState.done) {
stackIndex = stateStack[stackIndex](machine, stackIndex, stateStack, nodeStack, userStateStack, resultHolder);
}
Debug.assertEqual(stackIndex, 0);
return resultHolder.value;
};
}
}

View file

@ -1864,17 +1864,22 @@ namespace ts {
if (exportedNames) {
let expression: Expression = node.kind === SyntaxKind.PostfixUnaryExpression
? setTextRange(
factory.createBinaryExpression(
node.operand,
factory.createToken(node.operator === SyntaxKind.PlusPlusToken ? SyntaxKind.PlusEqualsToken : SyntaxKind.MinusEqualsToken),
factory.createNumericLiteral(1)
factory.createPrefixUnaryExpression(
node.operator,
node.operand
),
/*location*/ node)
: node;
for (const exportName of exportedNames) {
// Mark the node to prevent triggering this rule again.
noSubstitution[getNodeId(expression)] = true;
expression = factory.createParenthesizedExpression(createExportExpression(exportName, expression));
expression = createExportExpression(exportName, expression);
}
if (node.kind === SyntaxKind.PostfixUnaryExpression) {
noSubstitution[getNodeId(expression)] = true;
expression = node.operator === SyntaxKind.PlusPlusToken
? factory.createSubtract(expression, factory.createNumericLiteral(1))
: factory.createAdd(expression, factory.createNumericLiteral(1));
}
return expression;
}

View file

@ -361,17 +361,14 @@ namespace ts {
// JSDoc nodes
JSDocTypeExpression,
JSDocNameReference,
// The * type
JSDocAllType,
// The ? type
JSDocUnknownType,
JSDocAllType, // The * type
JSDocUnknownType, // The ? type
JSDocNullableType,
JSDocNonNullableType,
JSDocOptionalType,
JSDocFunctionType,
JSDocVariadicType,
// https://jsdoc.app/about-namepaths.html
JSDocNamepathType,
JSDocNamepathType, // https://jsdoc.app/about-namepaths.html
JSDocComment,
JSDocTypeLiteral,
JSDocSignature,
@ -1118,6 +1115,8 @@ namespace ts {
export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier;
export type MemberName = Identifier | PrivateIdentifier;
export type DeclarationName =
| Identifier
| PrivateIdentifier
@ -2224,7 +2223,7 @@ namespace ts {
readonly kind: SyntaxKind.PropertyAccessExpression;
readonly expression: LeftHandSideExpression;
readonly questionDotToken?: QuestionDotToken;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
/*@internal*/
@ -2234,7 +2233,7 @@ namespace ts {
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
/* @internal */
@ -4124,9 +4123,9 @@ namespace ts {
*/
/* @internal */ tryGetMemberInModuleExportsAndProperties(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
/* @internal */ getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined;
/* @internal */ getSuggestedSymbolForNonexistentProperty(name: MemberName | string, containingType: Type): Symbol | undefined;
/* @internal */ getSuggestedSymbolForNonexistentJSXAttribute(name: Identifier | string, containingType: Type): Symbol | undefined;
/* @internal */ getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined;
/* @internal */ getSuggestionForNonexistentProperty(name: MemberName | string, containingType: Type): string | undefined;
/* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
/* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
/* @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined;
@ -6570,7 +6569,7 @@ namespace ts {
/*@internal*/ IgnoreSourceNewlines = 1 << 27, // Overrides `printerOptions.preserveSourceNewlines` to print this node (and all descendants) with default whitespace.
}
export interface EmitHelper {
export interface EmitHelperBase {
readonly name: string; // A unique name for this helper.
readonly scoped: boolean; // Indicates whether the helper MUST be emitted in the current scope.
readonly text: string | ((node: EmitHelperUniqueNameCallback) => string); // ES3-compatible raw script text, or a function yielding such a string
@ -6578,13 +6577,19 @@ namespace ts {
readonly dependencies?: EmitHelper[]
}
export interface UnscopedEmitHelper extends EmitHelper {
export interface ScopedEmitHelper extends EmitHelperBase {
readonly scoped: true;
}
export interface UnscopedEmitHelper extends EmitHelperBase {
readonly scoped: false; // Indicates whether the helper MUST be emitted in the current scope.
/* @internal */
readonly importName?: string; // The name of the helper to use when importing via `--importHelpers`.
readonly text: string; // ES3-compatible raw script text, or a function yielding such a string
}
export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper;
/* @internal */
export type UniqueNameHandler = (baseName: string, checkFn?: (name: string) => boolean, optimistic?: boolean) => string;
@ -6943,10 +6948,10 @@ namespace ts {
updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression;
createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression;
updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain;
createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain;
createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression;
updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
@ -7782,13 +7787,13 @@ namespace ts {
* });
* ```
*/
onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void;
onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* A hook used to check if an emit notification is required for a node.
* @param node The node to emit.
*/
isEmitNotificationEnabled?(node: Node | undefined): boolean;
isEmitNotificationEnabled?(node: Node): boolean;
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
@ -7810,6 +7815,8 @@ namespace ts {
/*@internal*/ onEmitSourceMapOfToken?: (node: Node | undefined, token: SyntaxKind, writer: (s: string) => void, pos: number, emitCallback: (token: SyntaxKind, writer: (s: string) => void, pos: number) => number) => number;
/*@internal*/ onEmitSourceMapOfPosition?: (pos: number) => void;
/*@internal*/ onSetSourceFile?: (node: SourceFile) => void;
/*@internal*/ onBeforeEmitNode?: (node: Node | undefined) => void;
/*@internal*/ onAfterEmitNode?: (node: Node | undefined) => void;
/*@internal*/ onBeforeEmitNodeArray?: (nodes: NodeArray<any> | undefined) => void;
/*@internal*/ onAfterEmitNodeArray?: (nodes: NodeArray<any> | undefined) => void;
/*@internal*/ onBeforeEmitToken?: (node: Node) => void;

View file

@ -3186,11 +3186,11 @@ namespace ts {
}
}
export function getTextOfIdentifierOrLiteral(node: PropertyNameLiteral): string {
return isIdentifierOrPrivateIdentifier(node) ? idText(node) : node.text;
return isMemberName(node) ? idText(node) : node.text;
}
export function getEscapedTextOfIdentifierOrLiteral(node: PropertyNameLiteral): __String {
return isIdentifierOrPrivateIdentifier(node) ? node.escapedText : escapeLeadingUnderscores(node.text);
return isMemberName(node) ? node.escapedText : escapeLeadingUnderscores(node.text);
}
export function getPropertyNameForUniqueESSymbol(symbol: Symbol): __String {
@ -3574,6 +3574,7 @@ namespace ts {
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.MetaProperty:
return OperatorPrecedence.Member;
case SyntaxKind.AsExpression:

View file

@ -930,7 +930,7 @@ namespace ts {
// #region
export function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier {
export function isMemberName(node: Node): node is MemberName {
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.PrivateIdentifier;
}
@ -1055,13 +1055,22 @@ namespace ts {
return kind >= SyntaxKind.FirstNode;
}
/**
* True if kind is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
* Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
*/
export function isTokenKind(kind: SyntaxKind): boolean {
return kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken;
}
/**
* True if node is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
* Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
*/
export function isToken(n: Node): boolean {
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
return isTokenKind(n.kind);
}
// Node Arrays

File diff suppressed because it is too large Load diff

View file

@ -1354,4 +1354,24 @@ namespace ts {
export interface Map<T> extends ESMap<string, T> { }
// #endregion
// DEPRECATION: Renamed node tests
// DEPRECATION PLAN:
// - soft: 4.2
// - warn: 4.3
// - error: TBD
// #region Renamed node Tests
/**
* @deprecated Use `isMemberName` instead.
*/
export const isIdentifierOrPrivateIdentifier = Debug.deprecate(function isIdentifierOrPrivateIdentifier(node: Node): node is MemberName {
return isMemberName(node);
}, {
since: "4.2",
warnAfter: "4.3",
message: "Use `isMemberName` instead."
});
// #endregion Renamed node Tests
}

View file

@ -46,7 +46,7 @@ namespace ts.codefix {
let suggestedSymbol: Symbol | undefined;
if (isPropertyAccessExpression(parent) && parent.name === node) {
Debug.assert(isIdentifierOrPrivateIdentifier(node), "Expected an identifier for spelling (property access)");
Debug.assert(isMemberName(node), "Expected an identifier for spelling (property access)");
let containingType = checker.getTypeAtLocation(parent.expression);
if (parent.flags & NodeFlags.OptionalChain) {
containingType = checker.getNonNullableType(containingType);

View file

@ -977,7 +977,7 @@ namespace ts.Completions {
// Check if the caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
// Skip this partial identifier and adjust the contextToken to the token that precedes it.
if (contextToken && position <= contextToken.end && (isIdentifierOrPrivateIdentifier(contextToken) || isKeyword(contextToken.kind))) {
if (contextToken && position <= contextToken.end && (isMemberName(contextToken) || isKeyword(contextToken.kind))) {
const start = timestamp();
contextToken = findPrecedingToken(contextToken.getFullStart(), sourceFile, /*startNode*/ undefined)!; // TODO: GH#18217
log("getCompletionData: Get previous token 2: " + (timestamp() - start));

View file

@ -1037,11 +1037,12 @@ namespace ts.textChanges {
let lastNonTriviaPosition = 0;
const writer = createTextWriter(newLine);
const onEmitNode: PrintHandlers["onEmitNode"] = (hint, node, printCallback) => {
const onBeforeEmitNode: PrintHandlers["onBeforeEmitNode"] = node => {
if (node) {
setPos(node, lastNonTriviaPosition);
}
printCallback(hint, node);
};
const onAfterEmitNode: PrintHandlers["onAfterEmitNode"] = node => {
if (node) {
setEnd(node, lastNonTriviaPosition);
}
@ -1163,7 +1164,8 @@ namespace ts.textChanges {
}
return {
onEmitNode,
onBeforeEmitNode,
onAfterEmitNode,
onBeforeEmitNodeArray,
onAfterEmitNodeArray,
onBeforeEmitToken,

View file

@ -638,6 +638,7 @@ declare namespace ts {
}
export type EntityName = Identifier | QualifiedName;
export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier;
export type MemberName = Identifier | PrivateIdentifier;
export type DeclarationName = Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression;
export interface Declaration extends Node {
_declarationBrand: any;
@ -1216,11 +1217,11 @@ declare namespace ts {
readonly kind: SyntaxKind.PropertyAccessExpression;
readonly expression: LeftHandSideExpression;
readonly questionDotToken?: QuestionDotToken;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
readonly expression: SuperExpression;
@ -3130,17 +3131,21 @@ declare namespace ts {
Iterator = 8388608,
NoAsciiEscaping = 16777216,
}
export interface EmitHelper {
export interface EmitHelperBase {
readonly name: string;
readonly scoped: boolean;
readonly text: string | ((node: EmitHelperUniqueNameCallback) => string);
readonly priority?: number;
readonly dependencies?: EmitHelper[];
}
export interface UnscopedEmitHelper extends EmitHelper {
export interface ScopedEmitHelper extends EmitHelperBase {
readonly scoped: true;
}
export interface UnscopedEmitHelper extends EmitHelperBase {
readonly scoped: false;
readonly text: string;
}
export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper;
export type EmitHelperUniqueNameCallback = (name: string) => string;
export enum EmitHint {
SourceFile = 0,
@ -3286,10 +3291,10 @@ declare namespace ts {
updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression;
createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression;
updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain;
createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain;
createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression;
updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
@ -3750,12 +3755,12 @@ declare namespace ts {
* });
* ```
*/
onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void;
onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* A hook used to check if an emit notification is required for a node.
* @param node The node to emit.
*/
isEmitNotificationEnabled?(node: Node | undefined): boolean;
isEmitNotificationEnabled?(node: Node): boolean;
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
@ -4191,7 +4196,7 @@ declare namespace ts {
*/
function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[];
function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier;
function isMemberName(node: Node): node is MemberName;
function isPropertyAccessChain(node: Node): node is PropertyAccessChain;
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallChain(node: Node): node is CallChain;
@ -4206,6 +4211,12 @@ declare namespace ts {
function isUnparsedTextLike(node: Node): node is UnparsedTextLike;
function isUnparsedNode(node: Node): node is UnparsedNode;
function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag;
/**
* True if kind is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
* Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
*/
function isTokenKind(kind: SyntaxKind): boolean;
/**
* True if node is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
@ -4348,10 +4359,14 @@ declare namespace ts {
function isTemplateHead(node: Node): node is TemplateHead;
function isTemplateMiddle(node: Node): node is TemplateMiddle;
function isTemplateTail(node: Node): node is TemplateTail;
function isDotDotDotToken(node: Node): node is DotDotDotToken;
function isPlusToken(node: Node): node is PlusToken;
function isMinusToken(node: Node): node is MinusToken;
function isAsteriskToken(node: Node): node is AsteriskToken;
function isIdentifier(node: Node): node is Identifier;
function isPrivateIdentifier(node: Node): node is PrivateIdentifier;
function isQualifiedName(node: Node): node is QualifiedName;
function isComputedPropertyName(node: Node): node is ComputedPropertyName;
function isPrivateIdentifier(node: Node): node is PrivateIdentifier;
function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration;
function isParameter(node: Node): node is ParameterDeclaration;
function isDecorator(node: Node): node is Decorator;
@ -10370,13 +10385,13 @@ declare namespace ts {
/** @deprecated Use `factory.updateObjectLiteralExpression` or the factory supplied by your transformation context instead. */
const updateObjectLiteral: (node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) => ObjectLiteralExpression;
/** @deprecated Use `factory.createPropertyAccessExpression` or the factory supplied by your transformation context instead. */
const createPropertyAccess: (expression: Expression, name: string | Identifier | PrivateIdentifier) => PropertyAccessExpression;
const createPropertyAccess: (expression: Expression, name: string | MemberName) => PropertyAccessExpression;
/** @deprecated Use `factory.updatePropertyAccessExpression` or the factory supplied by your transformation context instead. */
const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) => PropertyAccessExpression;
const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: MemberName) => PropertyAccessExpression;
/** @deprecated Use `factory.createPropertyAccessChain` or the factory supplied by your transformation context instead. */
const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) => PropertyAccessChain;
const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName) => PropertyAccessChain;
/** @deprecated Use `factory.updatePropertyAccessChain` or the factory supplied by your transformation context instead. */
const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) => PropertyAccessChain;
const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName) => PropertyAccessChain;
/** @deprecated Use `factory.createElementAccessExpression` or the factory supplied by your transformation context instead. */
const createElementAccess: (expression: Expression, index: number | Expression) => ElementAccessExpression;
/** @deprecated Use `factory.updateElementAccessExpression` or the factory supplied by your transformation context instead. */
@ -10946,6 +10961,10 @@ declare namespace ts {
*/
interface Map<T> extends ESMap<string, T> {
}
/**
* @deprecated Use `isMemberName` instead.
*/
const isIdentifierOrPrivateIdentifier: (node: Node) => node is MemberName;
}
export = ts;

View file

@ -638,6 +638,7 @@ declare namespace ts {
}
export type EntityName = Identifier | QualifiedName;
export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier;
export type MemberName = Identifier | PrivateIdentifier;
export type DeclarationName = Identifier | PrivateIdentifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern | EntityNameExpression;
export interface Declaration extends Node {
_declarationBrand: any;
@ -1216,11 +1217,11 @@ declare namespace ts {
readonly kind: SyntaxKind.PropertyAccessExpression;
readonly expression: LeftHandSideExpression;
readonly questionDotToken?: QuestionDotToken;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
export interface PropertyAccessChain extends PropertyAccessExpression {
_optionalChainBrand: any;
readonly name: Identifier | PrivateIdentifier;
readonly name: MemberName;
}
export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
readonly expression: SuperExpression;
@ -3130,17 +3131,21 @@ declare namespace ts {
Iterator = 8388608,
NoAsciiEscaping = 16777216,
}
export interface EmitHelper {
export interface EmitHelperBase {
readonly name: string;
readonly scoped: boolean;
readonly text: string | ((node: EmitHelperUniqueNameCallback) => string);
readonly priority?: number;
readonly dependencies?: EmitHelper[];
}
export interface UnscopedEmitHelper extends EmitHelper {
export interface ScopedEmitHelper extends EmitHelperBase {
readonly scoped: true;
}
export interface UnscopedEmitHelper extends EmitHelperBase {
readonly scoped: false;
readonly text: string;
}
export type EmitHelper = ScopedEmitHelper | UnscopedEmitHelper;
export type EmitHelperUniqueNameCallback = (name: string) => string;
export enum EmitHint {
SourceFile = 0,
@ -3286,10 +3291,10 @@ declare namespace ts {
updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression;
createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression;
updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain;
createPropertyAccessExpression(expression: Expression, name: string | MemberName): PropertyAccessExpression;
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: MemberName): PropertyAccessExpression;
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName): PropertyAccessChain;
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName): PropertyAccessChain;
createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression;
updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
@ -3750,12 +3755,12 @@ declare namespace ts {
* });
* ```
*/
onEmitNode?(hint: EmitHint, node: Node | undefined, emitCallback: (hint: EmitHint, node: Node | undefined) => void): void;
onEmitNode?(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void): void;
/**
* A hook used to check if an emit notification is required for a node.
* @param node The node to emit.
*/
isEmitNotificationEnabled?(node: Node | undefined): boolean;
isEmitNotificationEnabled?(node: Node): boolean;
/**
* A hook used by the Printer to perform just-in-time substitution of a node. This is
* primarily used by node transformations that need to substitute one node for another,
@ -4191,7 +4196,7 @@ declare namespace ts {
*/
function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[];
function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
function isIdentifierOrPrivateIdentifier(node: Node): node is Identifier | PrivateIdentifier;
function isMemberName(node: Node): node is MemberName;
function isPropertyAccessChain(node: Node): node is PropertyAccessChain;
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallChain(node: Node): node is CallChain;
@ -4206,6 +4211,12 @@ declare namespace ts {
function isUnparsedTextLike(node: Node): node is UnparsedTextLike;
function isUnparsedNode(node: Node): node is UnparsedNode;
function isJSDocPropertyLikeTag(node: Node): node is JSDocPropertyLikeTag;
/**
* True if kind is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
* Literals are considered tokens, except TemplateLiteral, but does include TemplateHead/Middle/Tail.
*/
function isTokenKind(kind: SyntaxKind): boolean;
/**
* True if node is of some token syntax kind.
* For example, this is true for an IfKeyword but not for an IfStatement.
@ -4348,10 +4359,14 @@ declare namespace ts {
function isTemplateHead(node: Node): node is TemplateHead;
function isTemplateMiddle(node: Node): node is TemplateMiddle;
function isTemplateTail(node: Node): node is TemplateTail;
function isDotDotDotToken(node: Node): node is DotDotDotToken;
function isPlusToken(node: Node): node is PlusToken;
function isMinusToken(node: Node): node is MinusToken;
function isAsteriskToken(node: Node): node is AsteriskToken;
function isIdentifier(node: Node): node is Identifier;
function isPrivateIdentifier(node: Node): node is PrivateIdentifier;
function isQualifiedName(node: Node): node is QualifiedName;
function isComputedPropertyName(node: Node): node is ComputedPropertyName;
function isPrivateIdentifier(node: Node): node is PrivateIdentifier;
function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration;
function isParameter(node: Node): node is ParameterDeclaration;
function isDecorator(node: Node): node is Decorator;
@ -6643,13 +6658,13 @@ declare namespace ts {
/** @deprecated Use `factory.updateObjectLiteralExpression` or the factory supplied by your transformation context instead. */
const updateObjectLiteral: (node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]) => ObjectLiteralExpression;
/** @deprecated Use `factory.createPropertyAccessExpression` or the factory supplied by your transformation context instead. */
const createPropertyAccess: (expression: Expression, name: string | Identifier | PrivateIdentifier) => PropertyAccessExpression;
const createPropertyAccess: (expression: Expression, name: string | MemberName) => PropertyAccessExpression;
/** @deprecated Use `factory.updatePropertyAccessExpression` or the factory supplied by your transformation context instead. */
const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) => PropertyAccessExpression;
const updatePropertyAccess: (node: PropertyAccessExpression, expression: Expression, name: MemberName) => PropertyAccessExpression;
/** @deprecated Use `factory.createPropertyAccessChain` or the factory supplied by your transformation context instead. */
const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier) => PropertyAccessChain;
const createPropertyAccessChain: (expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | MemberName) => PropertyAccessChain;
/** @deprecated Use `factory.updatePropertyAccessChain` or the factory supplied by your transformation context instead. */
const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier) => PropertyAccessChain;
const updatePropertyAccessChain: (node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: MemberName) => PropertyAccessChain;
/** @deprecated Use `factory.createElementAccessExpression` or the factory supplied by your transformation context instead. */
const createElementAccess: (expression: Expression, index: number | Expression) => ElementAccessExpression;
/** @deprecated Use `factory.updateElementAccessExpression` or the factory supplied by your transformation context instead. */
@ -7219,6 +7234,10 @@ declare namespace ts {
*/
interface Map<T> extends ESMap<string, T> {
}
/**
* @deprecated Use `isMemberName` instead.
*/
const isIdentifierOrPrivateIdentifier: (node: Node) => node is MemberName;
}
export = ts;

View file

@ -32,6 +32,6 @@ exports.buzz = buzz;
exports.buzz = buzz += 3;
var bizz = 8;
exports.bizz = bizz;
(exports.bizz = bizz += 1); // compiles to exports.bizz = bizz += 1
(exports.bizz = bizz -= 1); // similarly
(exports.bizz = ++bizz); // compiles to exports.bizz = ++bizz
(exports.bizz = ++bizz) - 1; // compiles to exports.bizz = bizz += 1
(exports.bizz = --bizz) + 1; // similarly
exports.bizz = ++bizz; // compiles to exports.bizz = ++bizz

View file

@ -101,8 +101,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.z = exports.y = exports.x = void 0;
exports.x = (import.meta);
exports.y = (import.metal);
exports.x = import.meta;
exports.y = import.metal;
exports.z = import.import.import.malkovich;
//// [scriptLookingFile01.js]
"use strict";

View file

@ -55,8 +55,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.z = exports.y = exports.x = void 0;
exports.x = (import.meta);
exports.y = (import.metal);
exports.x = import.meta;
exports.y = import.metal;
exports.z = import.import.import.malkovich;
//// [scriptLookingFile01.js]
"use strict";

View file

@ -112,8 +112,8 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
exports_1("x", x = (context_1.meta));
exports_1("y", y = (import.metal));
exports_1("x", x = context_1.meta);
exports_1("y", y = import.metal);
exports_1("z", z = import.import.import.malkovich);
}
};
@ -126,8 +126,8 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
globalA = (context_1.meta);
globalB = (import.metal);
globalA = context_1.meta;
globalB = import.metal;
globalC = import.import.import.malkovich;
}
};

View file

@ -66,8 +66,8 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
exports_1("x", x = (context_1.meta));
exports_1("y", y = (import.metal));
exports_1("x", x = context_1.meta);
exports_1("y", y = import.metal);
exports_1("z", z = import.import.import.malkovich);
}
};
@ -80,8 +80,8 @@ System.register([], function (exports_1, context_1) {
return {
setters: [],
execute: function () {
globalA = (context_1.meta);
globalB = (import.metal);
globalA = context_1.meta;
globalB = import.metal;
globalC = import.import.import.malkovich;
}
};

View file

@ -161,6 +161,4 @@ var _brokenTree = renderer_1.dom(component_1.MySFC, { x: 1, y: 2 },
renderer_1.dom(component_1.MyClass, { x: 3, y: 4 }),
renderer_1.dom(component_1.MyClass, { x: 5, y: 6 }));
// Should fail, nondom isn't allowed as children of dom
var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 },
component_1.tree,
component_1.tree);
var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 }, component_1.tree, component_1.tree);

View file

@ -23,5 +23,5 @@ let x = <MyComp<Prop> a={10} b="hi" />; // error, no type arguments in js
exports.__esModule = true;
var component_1 = require("./component");
var React = require("react");
var x = <component_1.MyComp />, <Prop> a={10} b="hi" />; // error, no type arguments in js
</>;
var x = (<component_1.MyComp />, <Prop> a={10} b="hi" />; // error, no type arguments in js
</>);

View file

@ -23,17 +23,17 @@ exports.x = exports.foo = void 0;
var x = 1;
exports.x = x;
function foo(y) {
if (y <= (exports.x = x += 1))
return y <= (exports.x = x += 1);
if (y <= (exports.x = x -= 1))
return y <= (exports.x = x -= 1);
if (y <= (exports.x = ++x) - 1)
return y <= (exports.x = ++x) - 1;
if (y <= (exports.x = --x) + 1)
return y <= (exports.x = --x) + 1;
if (y <= (exports.x = ++x))
return y <= (exports.x = ++x);
if (y <= (exports.x = --x))
return y <= (exports.x = --x);
(exports.x = x += 1);
(exports.x = x -= 1);
(exports.x = ++x);
(exports.x = --x);
(exports.x = ++x) - 1;
(exports.x = --x) + 1;
exports.x = ++x;
exports.x = --x;
}
exports.foo = foo;

View file

@ -35,8 +35,7 @@ var y = {
"typeof":
};
var x = (_a = {
a: a,
: .b,
a: a, : .b,
a: a
},
_a["ss"] = ,

View file

@ -25,8 +25,7 @@ var n;
(function (n) {
var z = 10000;
n.y = {
m: m,
: .x // error
m: m, : .x // error
};
})(n || (n = {}));
m.y.x;

View file

@ -42,6 +42,5 @@ var C2 = /** @class */ (function () {
return C2;
}());
var b = {
x: function () { },
1: // error
x: function () { }, 1: // error
};

View file

@ -3,4 +3,5 @@ var v = { a
return;
//// [parserErrorRecovery_ObjectLiteral2.js]
var v = { a: a, "return": };
var v = { a: a,
"return": };