Как добавить дополнительные реквизиты в компоненты JSX во время компиляции tsc

#typescript #jsx #tsc

#typescript #jsx #tsc

Вопрос:

Я использую синтаксис JSX в своем TypeScript node.js проект (без использования React вообще).

В моем tsconfig я использую свой собственный jsxFactory

 {
  "compilerOptions": {
    ...
    "jsxFactory": "myJSXFactory",
    ...
  }
}
  
 <MyBanner backgroundColor="red" />
  

Все работает нормально, и вышеупомянутый JSX становится таким после компиляции tsc

 myJSXFactory(MyBanner, {
  backgroundColor: 'red' 
});
  

Теперь я хочу добавить дополнительные props к All компонентам JSX во время компиляции, например:

 myJSXFactory(MyBanner, {
  backgroundColor: 'red',
  theme: myTheme // a variable that's available in the parent context
});
  

Я просматривал API компилятора, но неясно, как изменить исходный код во время преобразования JSX.

Ответ №1:

Отвечая на мой собственный вопрос…

 import * as ts from "typescript";

type TYPESCRIPT = typeof ts;
function nodeVisitor(ts: TYPESCRIPT, ctx: ts.TransformationContext, sf: ts.SourceFile) {
  const visitor: ts.Visitor = (node) => {
      if (ts.isJsxOpeningElement(node) || ts.isJsxSelfClosingElement(node)) {
          // Create theme attr
          const themeAttr = ts.createPropertyAssignment(
              'theme',
              ts.createIdentifier('request.query.theme')
          )

          // Create __my_extra_prop={{ theme: request.query.theme }} JSX Attribute
          const sourceJsxAttr = ts.createJsxAttribute(
              ts.createIdentifier('__my_extra_prop'),
              ts.createJsxExpression(undefined, ts.createObjectLiteral([themeAttr]))
          )
          const jsxAttributes = ts.createJsxAttributes([...node.attributes.properties, sourceJsxAttr])
          const clonedNode = ts.getMutableClone(node)
          clonedNode.attributes = jsxAttributes
          return clonedNode
      }
      return ts.visitEachChild(node, visitor, ctx)
  }
  return visitor
}

function transform(ts: TYPESCRIPT): ts.TransformerFactory<ts.SourceFile> {
  return (ctx) => (sf) => ts.visitNode(sf, nodeVisitor(ts, ctx, sf))
}

// JSX expression
const source = "<MyBanner backgroundColor='red' />";

const result = ts.transpileModule(source,
  {
    compilerOptions: {
      module: ts.ModuleKind.CommonJS,
      jsxFactory: "myJSXFactory",
      jsx: ts.JsxEmit.React
    },
    transformers: {
      before: [transform(ts)]
    }
  }
);

console.log(result.outputText);
  

https://repl.it/@ABMAdnan/TS-JSX-extra-props#index.ts

 myJSXFactory(MyBanner, { backgroundColor: 'red', __my_extra_prop: { theme: request.query.theme } });