Typechecking after running Typescript compiler plugin/transformer












1














I'm following a blog (https://dev.doctorevidence.com/how-to-write-a-typescript-transform-plugin-fc5308fdd943) on how to write a Typescript compiler plugin/transformer.



After applying a first simple transformation which should introduce a type-error (some property accessed on an object that doesn't have that property) I noticed that the no type-error is shown. In fact, the compiler proceeds as normal.



import * as ts from "typescript";

export const transformerFactory = (
program: ts.Program
): ts.TransformerFactory<ts.SourceFile> => {
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
if (node.expression.escapedText === "someCall") {
return ts.createCall(
ts.createPropertyAccess(node.expression, "nonExisting"),
node.typeArguments,
node.arguments
);
}
}
return ts.visitEachChild(node, visitor, context);
};

return (sf: ts.SourceFile) => ts.visitNode(sf, visitor);
};
};


Applied to index.ts:



declare function someCall(...args: any): string;

console.log(someCall(1, 2, true));


Yields index.js:



console.log(someCall.nonExisting(1, 2, true));


(even with noEmitOnError: true)



Is this intended behavior? Is this something I can enable somewhere?










share|improve this question





























    1














    I'm following a blog (https://dev.doctorevidence.com/how-to-write-a-typescript-transform-plugin-fc5308fdd943) on how to write a Typescript compiler plugin/transformer.



    After applying a first simple transformation which should introduce a type-error (some property accessed on an object that doesn't have that property) I noticed that the no type-error is shown. In fact, the compiler proceeds as normal.



    import * as ts from "typescript";

    export const transformerFactory = (
    program: ts.Program
    ): ts.TransformerFactory<ts.SourceFile> => {
    return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
    const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
    if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
    if (node.expression.escapedText === "someCall") {
    return ts.createCall(
    ts.createPropertyAccess(node.expression, "nonExisting"),
    node.typeArguments,
    node.arguments
    );
    }
    }
    return ts.visitEachChild(node, visitor, context);
    };

    return (sf: ts.SourceFile) => ts.visitNode(sf, visitor);
    };
    };


    Applied to index.ts:



    declare function someCall(...args: any): string;

    console.log(someCall(1, 2, true));


    Yields index.js:



    console.log(someCall.nonExisting(1, 2, true));


    (even with noEmitOnError: true)



    Is this intended behavior? Is this something I can enable somewhere?










    share|improve this question



























      1












      1








      1







      I'm following a blog (https://dev.doctorevidence.com/how-to-write-a-typescript-transform-plugin-fc5308fdd943) on how to write a Typescript compiler plugin/transformer.



      After applying a first simple transformation which should introduce a type-error (some property accessed on an object that doesn't have that property) I noticed that the no type-error is shown. In fact, the compiler proceeds as normal.



      import * as ts from "typescript";

      export const transformerFactory = (
      program: ts.Program
      ): ts.TransformerFactory<ts.SourceFile> => {
      return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
      const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
      if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
      if (node.expression.escapedText === "someCall") {
      return ts.createCall(
      ts.createPropertyAccess(node.expression, "nonExisting"),
      node.typeArguments,
      node.arguments
      );
      }
      }
      return ts.visitEachChild(node, visitor, context);
      };

      return (sf: ts.SourceFile) => ts.visitNode(sf, visitor);
      };
      };


      Applied to index.ts:



      declare function someCall(...args: any): string;

      console.log(someCall(1, 2, true));


      Yields index.js:



      console.log(someCall.nonExisting(1, 2, true));


      (even with noEmitOnError: true)



      Is this intended behavior? Is this something I can enable somewhere?










      share|improve this question















      I'm following a blog (https://dev.doctorevidence.com/how-to-write-a-typescript-transform-plugin-fc5308fdd943) on how to write a Typescript compiler plugin/transformer.



      After applying a first simple transformation which should introduce a type-error (some property accessed on an object that doesn't have that property) I noticed that the no type-error is shown. In fact, the compiler proceeds as normal.



      import * as ts from "typescript";

      export const transformerFactory = (
      program: ts.Program
      ): ts.TransformerFactory<ts.SourceFile> => {
      return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
      const visitor: ts.Visitor = (node: ts.Node): ts.VisitResult<ts.Node> => {
      if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
      if (node.expression.escapedText === "someCall") {
      return ts.createCall(
      ts.createPropertyAccess(node.expression, "nonExisting"),
      node.typeArguments,
      node.arguments
      );
      }
      }
      return ts.visitEachChild(node, visitor, context);
      };

      return (sf: ts.SourceFile) => ts.visitNode(sf, visitor);
      };
      };


      Applied to index.ts:



      declare function someCall(...args: any): string;

      console.log(someCall(1, 2, true));


      Yields index.js:



      console.log(someCall.nonExisting(1, 2, true));


      (even with noEmitOnError: true)



      Is this intended behavior? Is this something I can enable somewhere?







      typescript plugins transformer






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 '18 at 14:46

























      asked Nov 23 '18 at 14:39









      Werner de Groot

      30128




      30128
























          1 Answer
          1






          active

          oldest

          votes


















          2















          Is this intended behavior?




          Yes.




          Is this something I can enable somewhere?




          No, transformers have limited purpose. General all-purpose "plugins" for the compiler are not supported.



          Transformers are run as part of the "emit" phase which generates javascript code from type-checked AST.



          This comment in the transformers PR says




          Transforms, all of them, happen after the checking phase has happened




          UPDATE




          is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files.




          I don't know. The first thing to try is to have your transformers modify AST as before, then type-check modified files manually by calling



          program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile)


          (getDiagnostics has second parameter - cancellationToken - but it seems that it's safe to omit it because it's always checked against being undefined in the type checker code. In general, you can look how various compiler APIs are used in its own source code, for example emit does type-checking first by calling various program.getNNNDiagnostics, then runs emitter with transforms.)



          This might or might not work, because type checker modifies AST, and it depends on AST being in the correct state.



          Then, you might want to look at the builder API - it's purpose is to watch for source file modifications and recompile changed files (source code link). I don't know how hard it would be to make it recompile on AST modifications, also it looks like you would not be able to use visitors available in tranformers; you'll have to traverse AST manually.



          Also, there's ts-simple-ast library, whose stated purpose is to "Provide a simple way to navigate and manipulate TypeScript and JavaScript code". I haven't used it myself and have no idea how useful it is for your goal.






          share|improve this answer























          • I was afraid of that! Thank you for your answer!
            – Werner de Groot
            Nov 24 '18 at 11:55










          • Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
            – Werner de Groot
            Nov 24 '18 at 11:57










          • @WernerdeGroot I updated the answer
            – artem
            Nov 24 '18 at 16:20










          • Thanks! I will definitely try that out! Will also report back if I'm succesful :)
            – Werner de Groot
            Nov 26 '18 at 6:04











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448691%2ftypechecking-after-running-typescript-compiler-plugin-transformer%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          2















          Is this intended behavior?




          Yes.




          Is this something I can enable somewhere?




          No, transformers have limited purpose. General all-purpose "plugins" for the compiler are not supported.



          Transformers are run as part of the "emit" phase which generates javascript code from type-checked AST.



          This comment in the transformers PR says




          Transforms, all of them, happen after the checking phase has happened




          UPDATE




          is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files.




          I don't know. The first thing to try is to have your transformers modify AST as before, then type-check modified files manually by calling



          program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile)


          (getDiagnostics has second parameter - cancellationToken - but it seems that it's safe to omit it because it's always checked against being undefined in the type checker code. In general, you can look how various compiler APIs are used in its own source code, for example emit does type-checking first by calling various program.getNNNDiagnostics, then runs emitter with transforms.)



          This might or might not work, because type checker modifies AST, and it depends on AST being in the correct state.



          Then, you might want to look at the builder API - it's purpose is to watch for source file modifications and recompile changed files (source code link). I don't know how hard it would be to make it recompile on AST modifications, also it looks like you would not be able to use visitors available in tranformers; you'll have to traverse AST manually.



          Also, there's ts-simple-ast library, whose stated purpose is to "Provide a simple way to navigate and manipulate TypeScript and JavaScript code". I haven't used it myself and have no idea how useful it is for your goal.






          share|improve this answer























          • I was afraid of that! Thank you for your answer!
            – Werner de Groot
            Nov 24 '18 at 11:55










          • Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
            – Werner de Groot
            Nov 24 '18 at 11:57










          • @WernerdeGroot I updated the answer
            – artem
            Nov 24 '18 at 16:20










          • Thanks! I will definitely try that out! Will also report back if I'm succesful :)
            – Werner de Groot
            Nov 26 '18 at 6:04
















          2















          Is this intended behavior?




          Yes.




          Is this something I can enable somewhere?




          No, transformers have limited purpose. General all-purpose "plugins" for the compiler are not supported.



          Transformers are run as part of the "emit" phase which generates javascript code from type-checked AST.



          This comment in the transformers PR says




          Transforms, all of them, happen after the checking phase has happened




          UPDATE




          is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files.




          I don't know. The first thing to try is to have your transformers modify AST as before, then type-check modified files manually by calling



          program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile)


          (getDiagnostics has second parameter - cancellationToken - but it seems that it's safe to omit it because it's always checked against being undefined in the type checker code. In general, you can look how various compiler APIs are used in its own source code, for example emit does type-checking first by calling various program.getNNNDiagnostics, then runs emitter with transforms.)



          This might or might not work, because type checker modifies AST, and it depends on AST being in the correct state.



          Then, you might want to look at the builder API - it's purpose is to watch for source file modifications and recompile changed files (source code link). I don't know how hard it would be to make it recompile on AST modifications, also it looks like you would not be able to use visitors available in tranformers; you'll have to traverse AST manually.



          Also, there's ts-simple-ast library, whose stated purpose is to "Provide a simple way to navigate and manipulate TypeScript and JavaScript code". I haven't used it myself and have no idea how useful it is for your goal.






          share|improve this answer























          • I was afraid of that! Thank you for your answer!
            – Werner de Groot
            Nov 24 '18 at 11:55










          • Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
            – Werner de Groot
            Nov 24 '18 at 11:57










          • @WernerdeGroot I updated the answer
            – artem
            Nov 24 '18 at 16:20










          • Thanks! I will definitely try that out! Will also report back if I'm succesful :)
            – Werner de Groot
            Nov 26 '18 at 6:04














          2












          2








          2







          Is this intended behavior?




          Yes.




          Is this something I can enable somewhere?




          No, transformers have limited purpose. General all-purpose "plugins" for the compiler are not supported.



          Transformers are run as part of the "emit" phase which generates javascript code from type-checked AST.



          This comment in the transformers PR says




          Transforms, all of them, happen after the checking phase has happened




          UPDATE




          is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files.




          I don't know. The first thing to try is to have your transformers modify AST as before, then type-check modified files manually by calling



          program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile)


          (getDiagnostics has second parameter - cancellationToken - but it seems that it's safe to omit it because it's always checked against being undefined in the type checker code. In general, you can look how various compiler APIs are used in its own source code, for example emit does type-checking first by calling various program.getNNNDiagnostics, then runs emitter with transforms.)



          This might or might not work, because type checker modifies AST, and it depends on AST being in the correct state.



          Then, you might want to look at the builder API - it's purpose is to watch for source file modifications and recompile changed files (source code link). I don't know how hard it would be to make it recompile on AST modifications, also it looks like you would not be able to use visitors available in tranformers; you'll have to traverse AST manually.



          Also, there's ts-simple-ast library, whose stated purpose is to "Provide a simple way to navigate and manipulate TypeScript and JavaScript code". I haven't used it myself and have no idea how useful it is for your goal.






          share|improve this answer















          Is this intended behavior?




          Yes.




          Is this something I can enable somewhere?




          No, transformers have limited purpose. General all-purpose "plugins" for the compiler are not supported.



          Transformers are run as part of the "emit" phase which generates javascript code from type-checked AST.



          This comment in the transformers PR says




          Transforms, all of them, happen after the checking phase has happened




          UPDATE




          is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files.




          I don't know. The first thing to try is to have your transformers modify AST as before, then type-check modified files manually by calling



          program.getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile)


          (getDiagnostics has second parameter - cancellationToken - but it seems that it's safe to omit it because it's always checked against being undefined in the type checker code. In general, you can look how various compiler APIs are used in its own source code, for example emit does type-checking first by calling various program.getNNNDiagnostics, then runs emitter with transforms.)



          This might or might not work, because type checker modifies AST, and it depends on AST being in the correct state.



          Then, you might want to look at the builder API - it's purpose is to watch for source file modifications and recompile changed files (source code link). I don't know how hard it would be to make it recompile on AST modifications, also it looks like you would not be able to use visitors available in tranformers; you'll have to traverse AST manually.



          Also, there's ts-simple-ast library, whose stated purpose is to "Provide a simple way to navigate and manipulate TypeScript and JavaScript code". I haven't used it myself and have no idea how useful it is for your goal.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 24 '18 at 16:20

























          answered Nov 23 '18 at 15:38









          artem

          13.8k12738




          13.8k12738












          • I was afraid of that! Thank you for your answer!
            – Werner de Groot
            Nov 24 '18 at 11:55










          • Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
            – Werner de Groot
            Nov 24 '18 at 11:57










          • @WernerdeGroot I updated the answer
            – artem
            Nov 24 '18 at 16:20










          • Thanks! I will definitely try that out! Will also report back if I'm succesful :)
            – Werner de Groot
            Nov 26 '18 at 6:04


















          • I was afraid of that! Thank you for your answer!
            – Werner de Groot
            Nov 24 '18 at 11:55










          • Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
            – Werner de Groot
            Nov 24 '18 at 11:57










          • @WernerdeGroot I updated the answer
            – artem
            Nov 24 '18 at 16:20










          • Thanks! I will definitely try that out! Will also report back if I'm succesful :)
            – Werner de Groot
            Nov 26 '18 at 6:04
















          I was afraid of that! Thank you for your answer!
          – Werner de Groot
          Nov 24 '18 at 11:55




          I was afraid of that! Thank you for your answer!
          – Werner de Groot
          Nov 24 '18 at 11:55












          Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
          – Werner de Groot
          Nov 24 '18 at 11:57




          Do you know a way to achieve more or less the same thing? I see that I can get a ts.Typechecker-instance from ts.Program. Is that something I can use to type-check my new nodes? Or is there some way to compile twice: once to transform the file and once to type-check the whole thing? I don't mind if I have to run a separate check for the transformed files. Any help would be greatly appreciated!
          – Werner de Groot
          Nov 24 '18 at 11:57












          @WernerdeGroot I updated the answer
          – artem
          Nov 24 '18 at 16:20




          @WernerdeGroot I updated the answer
          – artem
          Nov 24 '18 at 16:20












          Thanks! I will definitely try that out! Will also report back if I'm succesful :)
          – Werner de Groot
          Nov 26 '18 at 6:04




          Thanks! I will definitely try that out! Will also report back if I'm succesful :)
          – Werner de Groot
          Nov 26 '18 at 6:04


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53448691%2ftypechecking-after-running-typescript-compiler-plugin-transformer%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)