Skip to content

Instantly share code, notes, and snippets.

@willmtemple
Last active June 29, 2020 18:16
Show Gist options
  • Save willmtemple/cc873e48ce18ac004f4407b7816af83d to your computer and use it in GitHub Desktop.
Save willmtemple/cc873e48ce18ac004f4407b7816af83d to your computer and use it in GitHub Desktop.
magic typescript function that returns its arguments' AST
// This uses my modified version of typescript from my branch github.com/willmtemple/typescript#alchemy
import * as ts from "typescript/built/local/typescript";
import * as fs from "fs";
import * as os from "os";
import { promisify } from "util";
const readFile = promisify(fs.readFile);
interface CallSite {
fileName: string;
lineNumber: number;
columnNumber: number;
}
/**
* Gets the filename of the calling function
*/
function getCaller(): CallSite {
const stack = new Error().stack.split("\n").slice(1);
let relevantStackEntry = stack.filter(
(s) => !s.includes(__filename) && s.includes(".ts")
)[0];
if (relevantStackEntry.includes("(")) {
relevantStackEntry = relevantStackEntry.split("(")[1].split(")")[0];
} else {
relevantStackEntry = relevantStackEntry.split(" ").slice(-1)[0];
}
const site = relevantStackEntry.split(":");
return {
fileName: site[0],
lineNumber: parseInt(site[1]),
columnNumber: parseInt(site[2]),
};
}
async function readFragmentToString(callSite: CallSite): Promise<string> {
const content = (await readFile(callSite.fileName)).toString("utf-8");
const relevantLines = content.split(os.EOL).slice(callSite.lineNumber - 1);
relevantLines[0] = relevantLines[0].substring(callSite.columnNumber - 1);
return relevantLines.join(os.EOL);
}
export async function getAsts(..._: any[]): Promise<Array<ts.Expression>> {
const callSite = getCaller();
const text = await readFragmentToString(callSite);
console.log(text);
ts.Parser.initializeState(
"",
text,
ts.ScriptTarget.ESNext,
undefined,
ts.ScriptKind.TS
);
// Prime the scanner with a new token
ts.Parser.nextToken();
const expr = ts.Parser.parseExpression();
console.log(expr);
// Top level AST points to the call, so we know it will be a call expression
// and have arguments.
return (expr as any).arguments;
}
@willmtemple
Copy link
Author

needs source map support and for the TS source to be available wherever the map lists it, as the source file is read by the implementation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment