typescript - Hur kan jag injicera ytterligare satser i en funktion med hjälp av ts.transform
Jag använder Typescript-kompilatorns API (ts.transform, ts.updateFunctionDeclaration) för att injicera ytterligare uttryck i början av funktioner i befintliga källfiler. Detta fungerar utmärkt, förutom att när jag skriver ut den transformerade koden (med ts.Printer) så placeras den första kommentaren i originalkoden ovanför mina injicerade uttryck. Hur kan jag förhindra att det händer?
Jag har försökt olika sätt att konstruera de nya noder som returneras av transformern, men inget förändrar resultatet. Här är hela min kod, jag kör den med Node.
import * as ts from 'typescript';
const sourceLines = [
"// The list of properties exposed by this script to the user",
"var properties = {'speed': 20};",
"",
"function tick(deltaTime)",
"{",
" var currentDeltaTime = deltaTime;",
"}"
];
var sourceCode = sourceLines.join('\n');
const sourceFile = ts.createSourceFile("originalSource.js", sourceCode, ts.ScriptTarget.Latest, true);
const additionalSource: ts.SourceFile = ts.createSourceFile(
'ownerCheck.js', "var variableToAdd = 5;", ts.ScriptTarget.ES5, false, ts.ScriptKind.JS
);
const transformer = <T extends ts.Node>(context: ts.TransformationContext) =>
(rootNode: T) => {
function visit(node: ts.Node): ts.Node {
if (ts.isFunctionDeclaration(node)) {
var functionDeclaration = <ts.FunctionDeclaration>node;
var functionName: ts.Identifier = functionDeclaration.name;
var updatedFunction = ts.updateFunctionDeclaration(
functionDeclaration,
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*asteriskToken*/ functionDeclaration.asteriskToken,
/*functionName*/ functionName,
/*typeParameters*/ undefined,
/*parameters*/ functionDeclaration.parameters,
/*returnType*/ undefined,
/*body*/ ts.createBlock(ts.createNodeArray([].concat(additionalSource.statements, functionDeclaration.body.statements), false))
);
return updatedFunction;
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
const result = ts.transform(
sourceFile, [transformer]
);
const transformedNodes = result.transformed[0];
const printer: ts.Printer = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed,
removeComments: false
});
console.log(printer.printNode(ts.EmitHint.SourceFile, transformedNodes, sourceFile));
Utdata :
// The list of properties exposed by this script to the user
var properties = { 'speed': 20 };
function tick(deltaTime) {
// The list of properties exposed by this script to the user
var variableToAdd = 5;
var currentDeltaTime = deltaTime;
}
Jag skulle förvänta mig att resultatet inkluderar de ytterligare uttalandena utan den upprepade kommentarprefixen.
Uppdatering: Lägger till denna funktion:
stripRanges(additionalSource);
function stripRanges(node: ts.Node) {
node.pos = -1;
node.end = -1;
ts.forEachChild(node, stripRanges);
}
att ta bort nodintervallen i additionalSource-noderna fungerar tekniskt sett, men tar bort alla radbrytningar i utdata efter dessa noder vilket resulterar i följande utdata:
// The list of properties exposed by this script to the user
var properties = { 'speed': 20 };
function tick(deltaTime) { var variableToAdd = 5; var currentDeltaTime = deltaTime; }
Uppdatering 2: Att ändra ts.createBlock()-anropet så att multiLine är satt till true fixade resultatet:
ts.createBlock(
ts.createNodeArray(
[].concat(
additionalSource.statements,
functionDeclaration.body.statements),
false), /*has trailing comma*/
true) /*multiLine*/
Svar #1
Detta beror på att när skrivaren ska skriva ut additionalSource.statements-noderna använder den sourceFile-nodens text för att hämta kommentarerna baserat på positionen för noderna i additionalSource.
Du kan se detta återgivet genom att köra följande kod:
console.log(ts.createPrinter().printNode(
ts.EmitHint.Unspecified,
additionalSource.statements[0],
sourceFile // it's getting the comments from this sourceFile.text
));
Utdata :
// The list of properties exposed by this script to the user
var variableToAdd = 5;
Lösning
En lösning är att ta bort positionerna från noderna i additionalSource innan du använder det i sourceFile:
stripRanges(additionalSource);
function stripRanges(node: ts.Node) {
node.pos = -1;
node.end = -1;
ts.forEachChild(node, stripRanges);
}
Jag använder -1 för pos och end eftersom det är vad kompilatorn gör när en nod skapas med en fabrikfunktion. Till exempel:
const binaryExpr = ts.createBinary(1, "+", 2);
binaryExpr.pos; // -1
binaryExpr.end; // -1
Sidnotering: Sättet TypeScript-kompilatorn hanterar kommentarer på är inte optimalt enligt min mening... särskilt för transformation och utskrift (jag föredrar hur Babel hanterar kommentarer, men det finns förbättringar som också skulle kunna göras där...).
