Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor node factory API, use node factory in parser #35282

Merged
merged 20 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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