• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import * as ts from "typescript";
17
18export function exportAllTransformer(): ts.TransformerFactory<ts.SourceFile> {
19  return (context) => {
20    return (sourceFile) => {
21      const exportModifier = ts.factory.createModifier(ts.SyntaxKind.ExportKeyword);
22
23      const visitor = (node: ts.Node): ts.Node => {
24        if (isTopLevelExportable(node)) {
25          const modifiers = ts.getModifiers(node as ts.HasModifiers) || [];
26          if (!hasExportModifier(modifiers)) {
27            const newNode = updateNodeWithExport(node, modifiers, exportModifier);
28            return newNode || node;
29          }
30        }
31        return ts.visitEachChild(node, visitor, context);
32      };
33
34      return ts.visitNode(sourceFile, visitor);
35    };
36  };
37}
38
39function isTopLevelExportable(node: ts.Node): boolean {
40  return ts.isFunctionDeclaration(node) ||
41    ts.isClassDeclaration(node) ||
42    ts.isVariableStatement(node) ||
43    ts.isInterfaceDeclaration(node) ||
44    ts.isTypeAliasDeclaration(node) ||
45    ts.isEnumDeclaration(node) ||
46    ts.isModuleDeclaration(node);
47}
48
49function hasExportModifier(modifiers: readonly ts.Modifier[]): boolean {
50  return modifiers.some(m => m.kind === ts.SyntaxKind.ExportKeyword);
51}
52
53function hasDeclareModifier(modifiers: readonly ts.Modifier[]): boolean {
54  return modifiers.some(m => m.kind === ts.SyntaxKind.DeclareKeyword);
55}
56
57function handleClassModifiers(existingModifiers: readonly ts.Modifier[]): ts.Modifier[] {
58  const newModifiers = [...existingModifiers]
59  if (!hasDeclareModifier(existingModifiers)) {
60    newModifiers.unshift(ts.factory.createModifier(ts.SyntaxKind.DeclareKeyword));
61  }
62  if (!hasExportModifier(existingModifiers)) {
63    newModifiers.unshift(ts.factory.createModifier(ts.SyntaxKind.ExportKeyword));
64  }
65  return newModifiers;
66}
67
68function updateNodeWithExport(
69  node: ts.Node,
70  existingModifiers: readonly ts.Modifier[],
71  exportModifier: ts.Modifier
72): ts.Node {
73  const newModifiers = [exportModifier, ...existingModifiers];
74
75  switch (node.kind) {
76    case ts.SyntaxKind.VariableStatement:
77      return ts.factory.updateVariableStatement(
78        node as ts.VariableStatement,
79        newModifiers,
80        (node as ts.VariableStatement).declarationList
81      );
82
83    case ts.SyntaxKind.FunctionDeclaration:
84      const func = node as ts.FunctionDeclaration;
85      return ts.factory.updateFunctionDeclaration(
86        func,
87        newModifiers,
88        func.asteriskToken,
89        func.name,
90        func.typeParameters,
91        func.parameters,
92        func.type,
93        func.body
94      );
95
96    case ts.SyntaxKind.ClassDeclaration:
97      const cls = node as ts.ClassDeclaration;
98      return ts.factory.updateClassDeclaration(
99        cls,
100        handleClassModifiers(existingModifiers),
101        cls.name,
102        cls.typeParameters,
103        cls.heritageClauses,
104        cls.members
105      );
106
107    case ts.SyntaxKind.InterfaceDeclaration:
108      const intf = node as ts.InterfaceDeclaration;
109      return ts.factory.updateInterfaceDeclaration(
110        intf,
111        newModifiers,
112        intf.name,
113        intf.typeParameters,
114        intf.heritageClauses,
115        intf.members
116      );
117
118    case ts.SyntaxKind.TypeAliasDeclaration:
119      const type = node as ts.TypeAliasDeclaration;
120      return ts.factory.updateTypeAliasDeclaration(
121        type,
122        newModifiers.filter(m => m.kind !== ts.SyntaxKind.DeclareKeyword),
123        type.name,
124        type.typeParameters,
125        type.type
126      );
127
128    case ts.SyntaxKind.EnumDeclaration:
129      const enm = node as ts.EnumDeclaration;
130      return ts.factory.updateEnumDeclaration(
131        enm,
132        newModifiers,
133        enm.name,
134        enm.members
135      );
136
137    case ts.SyntaxKind.ModuleDeclaration:
138      const mod = node as ts.ModuleDeclaration;
139      return ts.factory.updateModuleDeclaration(
140        mod,
141        newModifiers,
142        mod.name,
143        mod.body
144      );
145
146    default:
147      return node;
148  }
149}