-
Notifications
You must be signed in to change notification settings - Fork 189
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add printNode utility function and Node.print()
- Loading branch information
Showing
8 changed files
with
225 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import * as ts from "typescript"; | ||
import {expect} from "chai"; | ||
import {printNode, PrintNodeOptions} from "./../../utils"; | ||
import {NewLineKind} from "./../../ManipulationSettings"; | ||
import {getInfoFromText} from "./../compiler/testHelpers"; | ||
|
||
describe(nameof(printNode), () => { | ||
const nodeText = "class MyClass {\n // comment\n prop: string;\n}"; | ||
const nodeTextNoComment = nodeText.replace(" // comment\n", ""); | ||
const {sourceFile, firstChild} = getInfoFromText(nodeText); | ||
const tsSourceFile = ts.createSourceFile("file.tsx", nodeText, ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX); | ||
const tsClass = tsSourceFile.getChildren(tsSourceFile)[0].getChildren(tsSourceFile)[0]; | ||
|
||
it("should print the node when specifying a compiler node and options", () => { | ||
expect(printNode(tsClass, { newLineKind: NewLineKind.CarriageReturnLineFeed })).to.equal(nodeTextNoComment.replace(/\n/g, "\r\n")); | ||
}); | ||
|
||
it("should print with comments when specifying a source file", () => { | ||
expect(printNode(tsSourceFile)).to.equal(nodeText + "\n"); | ||
}); | ||
|
||
it("should print the node when specifying a compiler node and source file", () => { | ||
expect(printNode(tsClass, tsSourceFile)).to.equal(nodeText); | ||
}); | ||
|
||
it("should print the node when specifying a compiler node, source file, and options", () => { | ||
expect(printNode(tsClass, tsSourceFile, { newLineKind: NewLineKind.CarriageReturnLineFeed })).to.equal(nodeText.replace(/\n/g, "\r\n")); | ||
}); | ||
|
||
it("should print the node when specifying a compiler node and source file", () => { | ||
expect(printNode(tsClass)).to.equal(nodeTextNoComment); | ||
}); | ||
|
||
it("general compiler api test", () => { | ||
// https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API | ||
const tsFunctionDeclaration = ts.createFunctionDeclaration( | ||
/*decorators*/ undefined, | ||
/*modifiers*/[ts.createToken(ts.SyntaxKind.ExportKeyword)], | ||
/*asteriskToken*/ undefined, | ||
"myFunction", | ||
/*typeParameters*/ undefined, | ||
/*parameters*/ [], | ||
/*returnType*/ ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), | ||
ts.createBlock([ts.createReturn(ts.createLiteral(5))], /*multiline*/ true) | ||
); | ||
expect(printNode(tsFunctionDeclaration)).to.equal("export function myFunction(): number {\n return 5;\n}"); | ||
}); | ||
|
||
it("should print the node when printing a jsx file", () => { | ||
const node = ts.createJsxOpeningElement(ts.createIdentifier("Test"), ts.createJsxAttributes([])); | ||
expect(printNode(node, { scriptKind: ts.ScriptKind.TSX })).to.equal("<Test>"); | ||
}); | ||
|
||
it("should print the node when printing a non-jsx file", () => { | ||
const node = ts.createTypeAssertion(ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), ts.createIdentifier("test")); | ||
expect(printNode(node, { scriptKind: ts.ScriptKind.TS })).to.equal("<string>test"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import * as ts from "typescript"; | ||
import {Node} from "./../compiler"; | ||
import {newLineKindToTs} from "./newLineKindToTs"; | ||
import {NewLineKind} from "./../ManipulationSettings"; | ||
|
||
/** | ||
* Options for printing a node. | ||
*/ | ||
export interface PrintNodeOptions { | ||
/** | ||
* Whether to remove comments or not. | ||
*/ | ||
removeComments?: boolean; | ||
/** | ||
* New line kind. | ||
* | ||
* Defaults to line feed. | ||
*/ | ||
newLineKind?: NewLineKind; | ||
/** | ||
* From the compiler api: "A value indicating the purpose of a node. This is primarily used to | ||
* distinguish between an `Identifier` used in an expression position, versus an | ||
* `Identifier` used as an `IdentifierName` as part of a declaration. For most nodes you | ||
* should just pass `Unspecified`." | ||
* | ||
* Defaults to `Unspecified`. | ||
*/ | ||
emitHint?: ts.EmitHint; | ||
/** | ||
* The script kind. | ||
* | ||
* Defaults to TSX. This is only useful when not using a wrapped node and not providing a source file. | ||
*/ | ||
scriptKind?: ts.ScriptKind; | ||
} | ||
|
||
/** | ||
* Prints the provided node using the compiler's printer. | ||
* @param node - Compiler node. | ||
* @param options - Options. | ||
*/ | ||
export function printNode(node: ts.Node, options?: PrintNodeOptions): string; | ||
/** | ||
* Prints the provided node using the compiler's printer. | ||
* @param node - Compiler node. | ||
* @param sourceFile - Compiler source file. | ||
* @param options - Options. | ||
*/ | ||
export function printNode(node: ts.Node, sourceFile: ts.SourceFile, options?: PrintNodeOptions): string; | ||
export function printNode(node: ts.Node, sourceFileOrOptions?: PrintNodeOptions | ts.SourceFile, secondOverloadOptions?: PrintNodeOptions) { | ||
const isFirstOverload = sourceFileOrOptions == null || (sourceFileOrOptions as ts.SourceFile).kind !== ts.SyntaxKind.SourceFile; | ||
const options = getOptions(); | ||
const sourceFile = getSourceFile(); | ||
|
||
const printer = ts.createPrinter({ | ||
newLine: newLineKindToTs(options.newLineKind || NewLineKind.LineFeed), | ||
removeComments: options.removeComments || false | ||
}); | ||
|
||
if (sourceFile == null) | ||
return printer.printFile(node as ts.SourceFile); | ||
else | ||
return printer.printNode(options.emitHint || ts.EmitHint.Unspecified, node, sourceFile); | ||
|
||
function getSourceFile() { | ||
if (isFirstOverload) { | ||
if (node.kind === ts.SyntaxKind.SourceFile) | ||
return undefined; | ||
const scriptKind = getScriptKind(); | ||
return ts.createSourceFile(`print.${getFileExt(scriptKind)}`, "", ts.ScriptTarget.Latest, false, scriptKind); | ||
} | ||
|
||
return sourceFileOrOptions as ts.SourceFile; | ||
|
||
function getScriptKind() { | ||
return options.scriptKind == null ? ts.ScriptKind.TSX : options.scriptKind; | ||
} | ||
|
||
function getFileExt(scriptKind: ts.ScriptKind) { | ||
if (scriptKind === ts.ScriptKind.JSX || scriptKind === ts.ScriptKind.TSX) | ||
return "tsx"; | ||
return "ts"; | ||
} | ||
} | ||
|
||
function getOptions() { | ||
return (isFirstOverload ? sourceFileOrOptions as PrintNodeOptions : secondOverloadOptions) || {}; | ||
} | ||
} |