Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created December 23, 2021 14:30
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mizchi/503c26ad99c3a8a2cfe961480a500ad8 to your computer and use it in GitHub Desktop.
Save mizchi/503c26ad99c3a8a2cfe961480a500ad8 to your computer and use it in GitHub Desktop.
import ts, { factory } from "typescript";
export function transformerFactory(context: ts.TransformationContext) {
function visitNode(node: ts.Node): ts.Node {
const newNode = ts.visitEachChild(node, visitNode, context);
if (
ts.isJsxOpeningElement(newNode) ||
ts.isJsxSelfClosingElement(newNode)
) {
return appendSourceMapAttribute(newNode.getSourceFile(), newNode);
}
return newNode;
}
return (source: ts.SourceFile) => {
return ts.factory.updateSourceFile(
source,
ts.visitNodes(source.statements, visitNode)
);
};
}
function appendSourceMapAttribute(
source: ts.SourceFile,
node: ts.JsxOpeningElement | ts.JsxSelfClosingElement
) {
if (ts.isIdentifier(node.tagName)) {
const fileName = node.getSourceFile().fileName;
const start = node.getStart(source);
const end = node.getEnd();
// const line = ts.getPositionOfLineAndCharacter(source, node.getStart(source), start);
const position = ts.getLineAndCharacterOfPosition(source, start);
const factoryMethod =
node.kind === ts.SyntaxKind.JsxOpeningElement
? factory.createJsxOpeningElement
: factory.createJsxSelfClosingElement;
return factoryMethod(
node.tagName,
node.typeArguments,
factory.updateJsxAttributes(node.attributes, [
...node.attributes.properties,
factory.createJsxAttribute(
factory.createIdentifier("data-sourcemap"),
factory.createStringLiteral(`${start}:${end}`)
),
factory.createJsxAttribute(
factory.createIdentifier("onClick"),
factory.createJsxExpression(
undefined,
createClickHandler(
fileName,
start,
end,
position.line + 1,
position.character + 1
)
)
),
])
);
}
return node;
}
function createClickHandler(
fileName: string,
start: number,
end: number,
line: number,
character: number
) {
return factory.createArrowFunction(
undefined,
undefined,
[
factory.createParameterDeclaration(
undefined,
undefined,
undefined,
factory.createIdentifier("ev"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("Event"),
undefined
),
undefined
),
],
undefined,
factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
factory.createBlock(
[
// ev.stopPropagation();
factory.createExpressionStatement(
factory.createCallExpression(
factory.createPropertyAccessExpression(
factory.createIdentifier("ev"),
factory.createIdentifier("stopPropagation")
),
[],
[]
)
),
// dispatchEvent(new CustomEvent("sourcemap-click", { start, end }))
factory.createExpressionStatement(
factory.createCallExpression(
factory.createIdentifier("dispatchEvent"),
undefined,
[
factory.createNewExpression(
factory.createIdentifier("CustomEvent"),
undefined,
[
factory.createStringLiteral("element-sourcemap"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("detail"),
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("fileName"),
factory.createStringLiteral(fileName)
),
factory.createPropertyAssignment(
factory.createIdentifier("start"),
factory.createNumericLiteral(start)
),
factory.createPropertyAssignment(
factory.createIdentifier("end"),
factory.createNumericLiteral(end)
),
factory.createPropertyAssignment(
factory.createIdentifier("line"),
factory.createNumericLiteral(line)
),
factory.createPropertyAssignment(
factory.createIdentifier("character"),
factory.createNumericLiteral(character)
),
],
false
)
),
],
true
),
]
),
]
)
),
],
true
)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment