Skip to content

Transformer that updates an ambient property declaration is emitted as non-ambient #63419

@JoostK

Description

@JoostK

🔎 Search Terms

Applying a TypeScript transformer using the API that updates an ambient property declaration does not propagate the internal Ambient flag, as only the context flags of the parent node are copied. This causes the property declaration to be emitted, even though it was transformed with the declare modifier kept intact.

🕗 Version & Regression Information

  • This changed between versions 4.2 and 4.3

4.2 output

class Test {
}

4.3 output

class Test {
    transformed;
}

(both versions require a slight change to the reproduction code)

⏯ Playground Link

https://stackblitz.com/edit/node-vmtqds5k?file=index.ts

(Sorry, not a Playground link, but TMK I cannot apply a transformer there; the plugin I attempted didn't do what I needed it to, so sharing a StackBlitz link instead)

💻 Code

import ts from 'typescript';

const output = ts.transpileModule(
  `
class Test {
  declare a: boolean;
  declare b: boolean;
}
`,
  {
    compilerOptions: {
      target: ts.ScriptTarget.ESNext,
    },
    transformers: {
      before: [
        (context: ts.TransformationContext) => (sf: ts.SourceFile) => {
          const transform = (node: ts.Node): ts.Node => {
            if (ts.isPropertyDeclaration(node) && node.name.getText() === 'a') {
              return context.factory.updatePropertyDeclaration(
                node,
                node.modifiers,
                context.factory.createIdentifier('transformed'),
                node.questionToken,
                node.type,
                node.initializer
              );
            }
            return ts.visitEachChild(node, transform, context);
          };
          return ts.visitEachChild(sf, transform, context);
        },
      ],
    },
  }
);
console.log(output.outputText);

🙁 Actual behavior

class Test {
    transformed;
}

🙂 Expected behavior

class Test {
}

Additional information about the issue

The updated node's flags are copied from the parent node, but in the case of a property declaration the declare modifier (and therefore NodeFlag.Ambient) is not set on that parent; the presence of the declare token as modifier does not cause NodeFlag.Ambient to be set on the updated node, whereas it was on the original, affecting emit behavior.

Cause of angular/angular#68069

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions