Skip to content

Commit dd164d2

Browse files
TS2Swift: warn when exported declarations are skipped
1 parent 8bbf832 commit dd164d2

File tree

1 file changed

+63
-4
lines changed
  • Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src

1 file changed

+63
-4
lines changed

Plugins/BridgeJS/Sources/TS2Swift/JavaScript/src/processor.js

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ export class TypeProcessor {
5757
/** @type {Set<string>} */
5858
this.emittedStringLiteralUnionNames = new Set();
5959

60+
/** @type {Set<ts.Node>} */
61+
this.warnedExportNodes = new Set();
62+
6063
/** @type {Set<string>} */
6164
this.visitedDeclarationKeys = new Set();
6265

@@ -192,6 +195,8 @@ export class TypeProcessor {
192195
this.visitEnumDeclaration(node);
193196
} else if (ts.isExportDeclaration(node)) {
194197
this.visitExportDeclaration(node);
198+
} else if (ts.isExportAssignment(node)) {
199+
this.visitExportAssignment(node);
195200
}
196201
}
197202

@@ -239,6 +244,7 @@ export class TypeProcessor {
239244
}
240245
} else {
241246
// export * as ns from "..." is not currently supported by BridgeJS imports.
247+
this.warnExportSkip(node, "Skipping namespace re-export (export * as ns) which is not supported");
242248
return;
243249
}
244250

@@ -254,6 +260,19 @@ export class TypeProcessor {
254260
this.visitNode(declaration);
255261
}
256262
}
263+
264+
if (targetSymbols.length === 0) {
265+
this.warnExportSkip(node, "Export declaration resolved to no symbols; nothing was generated");
266+
}
267+
}
268+
269+
/**
270+
* Handle `export default foo;` style assignments.
271+
* @param {ts.ExportAssignment} node
272+
*/
273+
visitExportAssignment(node) {
274+
// BridgeJS does not currently model default export assignments (they may point to expressions).
275+
this.warnExportSkip(node, "Skipping export assignment (export default ...) which is not supported");
257276
}
258277

259278
/**
@@ -271,7 +290,10 @@ export class TypeProcessor {
271290
const isConst = (node.declarationList.flags & ts.NodeFlags.Const) !== 0;
272291

273292
for (const decl of node.declarationList.declarations) {
274-
if (!ts.isIdentifier(decl.name)) continue;
293+
if (!ts.isIdentifier(decl.name)) {
294+
this.warnExportSkip(decl, "Skipping exported variable with a non-identifier name");
295+
continue;
296+
}
275297

276298
const jsName = decl.name.text;
277299
const swiftName = this.swiftTypeName(jsName);
@@ -399,7 +421,12 @@ export class TypeProcessor {
399421
*/
400422
visitEnumDeclaration(node) {
401423
const name = node.name?.text;
402-
if (!name) return;
424+
if (!name) {
425+
if (this.isExported(node)) {
426+
this.warnExportSkip(node, "Skipping exported enum without a name");
427+
}
428+
return;
429+
}
403430
this.emitEnumFromDeclaration(name, node, node);
404431
}
405432

@@ -532,7 +559,12 @@ export class TypeProcessor {
532559
* @private
533560
*/
534561
visitFunctionDeclaration(node) {
535-
if (!node.name) return;
562+
if (!node.name) {
563+
if (this.isExported(node)) {
564+
this.warnExportSkip(node, "Skipping exported function without a name");
565+
}
566+
return;
567+
}
536568
const jsName = node.name.text;
537569
const swiftName = this.swiftTypeName(jsName);
538570
const fromArg = this.renderDefaultJSImportFromArgument();
@@ -774,7 +806,12 @@ export class TypeProcessor {
774806
* @private
775807
*/
776808
visitClassDecl(node) {
777-
if (!node.name) return;
809+
if (!node.name) {
810+
if (this.isExported(node)) {
811+
this.warnExportSkip(node, "Skipping exported class without a name");
812+
}
813+
return;
814+
}
778815

779816
const jsName = node.name.text;
780817
if (this.emittedStructuredTypeNames.has(jsName)) return;
@@ -1244,6 +1281,28 @@ export class TypeProcessor {
12441281
return parts.join(" ");
12451282
}
12461283

1284+
/**
1285+
* @param {ts.Node} node
1286+
* @returns {boolean}
1287+
*/
1288+
isExported(node) {
1289+
const hasExportModifier = /** @type {ts.ModifierLike[] | undefined} */ (node.modifiers)?.some(
1290+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
1291+
) ?? false;
1292+
return hasExportModifier || ts.isExportAssignment(node);
1293+
}
1294+
1295+
/**
1296+
* Emit a single warning per node when an exported declaration cannot be generated.
1297+
* @param {ts.Node} node
1298+
* @param {string} reason
1299+
*/
1300+
warnExportSkip(node, reason) {
1301+
if (this.warnedExportNodes.has(node)) return;
1302+
this.warnedExportNodes.add(node);
1303+
this.diagnosticEngine.print("warning", `${reason}. Swift binding not generated`, node);
1304+
}
1305+
12471306
/**
12481307
* Render identifier with backticks if needed
12491308
* @param {string} name

0 commit comments

Comments
 (0)