Skip to content

Commit

Permalink
Refactor node factory API, use node factory in parser (#35282)
Browse files Browse the repository at this point in the history
* Refactor node factory API, use node factory in parser

* Move UnparsedSource nodes to factory

* Make most Node properties read-only

* Make pos/end/parent and JSDoc 'comment' read-only

* Update function/constructor-type factories

* Remove treeStateObserver

* Simplify Debug.deprecate

* Remove unused factory methods, simplify lazy factory methods

* Fix base factory used for source file updates

* Update test baseline due to merge from master

* Rename factory methods to be more consistent (#39058)
  • Loading branch information
rbuckton authored Jun 16, 2020
1 parent 0232d4a commit eb3645f
Show file tree
Hide file tree
Showing 206 changed files with 23,448 additions and 17,150 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
},
"sourceMaps": true,
"smartStep": true,
"preLaunchTask": "tests",
"preLaunchTask": "gulp: tests",
"console": "integratedTerminal",
"outFiles": [
"${workspaceRoot}/built/local/run.js"
Expand Down
43 changes: 27 additions & 16 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,42 @@
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"identifier": "local",
"type": "gulp",
"label": "gulp: local",
"command": "gulp",
"args": ["local"],
"group": { "kind": "build", "isDefault": true },
"problemMatcher": ["$gulp-tsc"]
"task": "local",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$tsc"
]
},
{
"type": "shell",
"identifier": "tsc",
"type": "gulp",
"label": "gulp: tsc",
"command": "gulp",
"args": ["tsc"],
"task": "tsc",
"group": "build",
"problemMatcher": ["$gulp-tsc"]
"problemMatcher": [
"$tsc"
]
},
{
"type": "shell",
"identifier": "tests",
"type": "gulp",
"label": "gulp: tests",
"command": "gulp",
"args": ["tests"],
"task": "tests",
"group": "build",
"problemMatcher": ["$gulp-tsc"]
"problemMatcher": [
"$tsc"
]
},
{
"type": "gulp",
"task": "services",
"label": "gulp: services",
"problemMatcher": [
"$tsc"
],
}
]
}
1,324 changes: 1,324 additions & 0 deletions src/compat/deprecations.ts

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/compat/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "../tsconfig-base",
"compilerOptions": {
"outFile": "../../built/local/compat.js"
},
"references": [
{ "path": "../compiler" }
],
"files": [
"deprecations.ts"
]
}
1,117 changes: 29 additions & 1,088 deletions src/compiler/binder.ts

Large diffs are not rendered by default.

905 changes: 506 additions & 399 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,20 @@ namespace ts {
};
}

/** A version of `memoize` that supports a single primitive argument */
export function memoizeOne<A extends string | number | boolean | undefined, T>(callback: (arg: A) => T): (arg: A) => T {
const map = createMap<T>();
return (arg: A) => {
const key = `${typeof arg}:${arg}`;
let value = map.get(key);
if (value === undefined && !map.has(key)) {
value = callback(arg);
map.set(key, value);
}
return value!;
};
}

/**
* High-order function, composes functions. Note that functions are composed inside-out;
* for example, `compose(a, b)` is the equivalent of `x => b(a(x))`.
Expand Down
1 change: 1 addition & 0 deletions src/compiler/corePublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace ts {
/** Array that is only intended to be pushed to, never read. */
export interface Push<T> {
push(...values: T[]): void;
/* @internal*/ readonly length: number;
}

/* @internal */
Expand Down
117 changes: 114 additions & 3 deletions src/compiler/debug.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,72 @@
/* @internal */
namespace ts {
export enum LogLevel {
Off,
Error,
Warning,
Info,
Verbose
}

export interface LoggingHost {
log(level: LogLevel, s: string): void;
}

export interface DeprecationOptions {
message?: string;
error?: boolean;
since?: Version | string;
warnAfter?: Version | string;
errorAfter?: Version | string;
typeScriptVersion?: Version | string;
}

export namespace Debug {
let currentAssertionLevel = AssertionLevel.None;
let typeScriptVersion: Version | undefined;

// eslint-disable-next-line prefer-const
/* eslint-disable prefer-const */
let currentAssertionLevel = AssertionLevel.None;
export let currentLogLevel = LogLevel.Warning;
export let isDebugging = false;
export let loggingHost: LoggingHost | undefined;
/* eslint-enable prefer-const */

type AssertionKeys = MatchingKeys<typeof Debug, AnyFunction>;
export function getTypeScriptVersion() {
return typeScriptVersion ?? (typeScriptVersion = new Version(version));
}

export function shouldLog(level: LogLevel): boolean {
return currentLogLevel <= level;
}

function logMessage(level: LogLevel, s: string): void {
if (loggingHost && shouldLog(level)) {
loggingHost.log(level, s);
}
}

export function log(s: string): void {
logMessage(LogLevel.Info, s);
}

export namespace log {
export function error(s: string): void {
logMessage(LogLevel.Error, s);
}

export function warn(s: string): void {
logMessage(LogLevel.Warning, s);
}

export function log(s: string): void {
logMessage(LogLevel.Info, s);
}

export function trace(s: string): void {
logMessage(LogLevel.Verbose, s);
}
}

const assertionCache: Partial<Record<AssertionKeys, { level: AssertionLevel, assertion: AnyFunction }>> = {};

Expand Down Expand Up @@ -385,7 +445,7 @@ namespace ts {
if (nodeIsSynthesized(this)) return "";
const parseNode = getParseTreeNode(this);
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode!, includeTrivia) : "";
}
}
});
Expand All @@ -410,5 +470,56 @@ namespace ts {
isDebugInfoEnabled = true;
}

function formatDeprecationMessage(name: string, error: boolean | undefined, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) {
let deprecationMessage = error ? "DeprecationError: " : "DeprecationWarning: ";
deprecationMessage += `'${name}' `;
deprecationMessage += since ? `has been deprecated since v${since}` : "is deprecated";
deprecationMessage += error ? " and can no longer be used." : errorAfter ? ` and will no longer be usable after v${errorAfter}.` : ".";
deprecationMessage += message ? ` ${formatStringFromArgs(message, [name], 0)}` : "";
return deprecationMessage;
}

function createErrorDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) {
const deprecationMessage = formatDeprecationMessage(name, /*error*/ true, errorAfter, since, message);
return () => {
throw new TypeError(deprecationMessage);
};
}

function createWarningDeprecation(name: string, errorAfter: Version | undefined, since: Version | undefined, message: string | undefined) {
let hasWrittenDeprecation = false;
return () => {
if (!hasWrittenDeprecation) {
log.warn(formatDeprecationMessage(name, /*error*/ false, errorAfter, since, message));
hasWrittenDeprecation = true;
}
};
}

function createDeprecation(name: string, options: DeprecationOptions & { error: true }): () => never;
function createDeprecation(name: string, options?: DeprecationOptions): () => void;
function createDeprecation(name: string, options: DeprecationOptions = {}) {
const version = typeof options.typeScriptVersion === "string" ? new Version(options.typeScriptVersion) : options.typeScriptVersion ?? getTypeScriptVersion();
const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) : options.errorAfter;
const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) : options.warnAfter;
const since = typeof options.since === "string" ? new Version(options.since) : options.since ?? warnAfter;
const error = options.error || errorAfter && version.compareTo(errorAfter) <= 0;
const warn = !warnAfter || version.compareTo(warnAfter) >= 0;
return error ? createErrorDeprecation(name, errorAfter, since, options.message) :
warn ? createWarningDeprecation(name, errorAfter, since, options.message) :
noop;
}

function wrapFunction<F extends (...args: any[]) => any>(deprecation: () => void, func: F): F {
return function (this: unknown) {
deprecation();
return func.apply(this, arguments);
} as F;
}

export function deprecate<F extends (...args: any[]) => any>(func: F, options?: DeprecationOptions): F {
const deprecation = createDeprecation(getFunctionName(func), options);
return wrapFunction(deprecation, func);
}
}
}
50 changes: 25 additions & 25 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace ts {
if (outFile(options)) {
const prepends = host.getPrependNodes();
if (sourceFiles.length || prepends.length) {
const bundle = createBundle(sourceFiles, prepends);
const bundle = factory.createBundle(sourceFiles, prepends);
const result = action(getOutputPathsFor(bundle, host, forceDtsEmit), bundle);
if (result) {
return result;
Expand Down Expand Up @@ -356,7 +356,7 @@ namespace ts {
return;
}
// Transform the source files
const transform = transformNodes(resolver, host, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);
const transform = transformNodes(resolver, host, factory, compilerOptions, [sourceFileOrBundle], scriptTransformers, /*allowDtsFiles*/ false);

const printerOptions: PrinterOptions = {
removeComments: compilerOptions.removeComments,
Expand Down Expand Up @@ -404,13 +404,13 @@ namespace ts {
const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson);
// Setup and perform the transformation to retrieve declarations from the input files
const inputListOrBundle = outFile(compilerOptions) ? [createBundle(filesForEmit, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : filesForEmit;
const inputListOrBundle = outFile(compilerOptions) ? [factory.createBundle(filesForEmit, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : filesForEmit;
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
// Do that here when emitting only dts files
filesForEmit.forEach(collectLinkedAliases);
}
const declarationTransform = transformNodes(resolver, host, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false);
const declarationTransform = transformNodes(resolver, host, factory, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false);
if (length(declarationTransform.diagnostics)) {
for (const diagnostic of declarationTransform.diagnostics!) {
emitterDiagnostics.add(diagnostic);
Expand Down Expand Up @@ -680,30 +680,30 @@ namespace ts {
}

function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: EmitUsingBuildInfoHost): readonly SourceFile[] {
const sourceFiles = bundle.sourceFiles.map(fileName => {
const sourceFile = createNode(SyntaxKind.SourceFile, 0, 0) as SourceFile;
const jsBundle = Debug.checkDefined(bundle.js);
const prologueMap = jsBundle.sources?.prologues && arrayToMap(jsBundle.sources.prologues, prologueInfo => "" + prologueInfo.file);
return bundle.sourceFiles.map((fileName, index) => {
const prologueInfo = prologueMap?.get("" + index);
const statements = prologueInfo?.directives.map(directive => {
const literal = setTextRange(factory.createStringLiteral(directive.expression.text), directive.expression);
const statement = setTextRange(factory.createExpressionStatement(literal), directive);
setParent(literal, statement);
return statement;
});
const eofToken = factory.createToken(SyntaxKind.EndOfFileToken);
const sourceFile = factory.createSourceFile(statements ?? [], eofToken, NodeFlags.None);
sourceFile.fileName = getRelativePathFromDirectory(
host.getCurrentDirectory(),
getNormalizedAbsolutePath(fileName, buildInfoDirectory),
!host.useCaseSensitiveFileNames()
);
sourceFile.text = "";
sourceFile.statements = createNodeArray();
sourceFile.text = prologueInfo?.text ?? "";
setTextRangePosWidth(sourceFile, 0, prologueInfo?.text.length ?? 0);
setEachParent(sourceFile.statements, sourceFile);
setTextRangePosWidth(eofToken, sourceFile.end, 0);
setParent(eofToken, sourceFile);
return sourceFile;
});
const jsBundle = Debug.checkDefined(bundle.js);
forEach(jsBundle.sources && jsBundle.sources.prologues, prologueInfo => {
const sourceFile = sourceFiles[prologueInfo.file];
sourceFile.text = prologueInfo.text;
sourceFile.end = prologueInfo.text.length;
sourceFile.statements = createNodeArray(prologueInfo.directives.map(directive => {
const statement = createNode(SyntaxKind.ExpressionStatement, directive.pos, directive.end) as PrologueDirective;
statement.expression = createNode(SyntaxKind.StringLiteral, directive.expression.pos, directive.expression.end) as StringLiteral;
statement.expression.text = directive.expression.text;
return statement;
}));
});
return sourceFiles;
}

/*@internal*/
Expand Down Expand Up @@ -2292,7 +2292,7 @@ namespace ts {

function emitPropertyAccessExpression(node: PropertyAccessExpression) {
const expression = cast(emitExpression(node.expression), isExpression);
const token = node.questionDotToken || createNode(SyntaxKind.DotToken, node.expression.end, node.name.pos) as DotToken;
const token = node.questionDotToken || setTextRangePosEnd(factory.createToken(SyntaxKind.DotToken) as DotToken, node.expression.end, node.name.pos);
const linesBeforeDot = getLinesBetweenNodes(node, node.expression, token);
const linesAfterDot = getLinesBetweenNodes(node, token, node.name);

Expand Down Expand Up @@ -3559,15 +3559,15 @@ namespace ts {
}

function emitJSDocTypeLiteral(lit: JSDocTypeLiteral) {
emitList(lit, createNodeArray(lit.jsDocPropertyTags), ListFormat.JSDocComment);
emitList(lit, factory.createNodeArray(lit.jsDocPropertyTags), ListFormat.JSDocComment);
}

function emitJSDocSignature(sig: JSDocSignature) {
if (sig.typeParameters) {
emitList(sig, createNodeArray(sig.typeParameters), ListFormat.JSDocComment);
emitList(sig, factory.createNodeArray(sig.typeParameters), ListFormat.JSDocComment);
}
if (sig.parameters) {
emitList(sig, createNodeArray(sig.parameters), ListFormat.JSDocComment);
emitList(sig, factory.createNodeArray(sig.parameters), ListFormat.JSDocComment);
}
if (sig.type) {
writeLine();
Expand Down
Loading

0 comments on commit eb3645f

Please sign in to comment.