import { expect, test } from "bun:test"; import { bunEnv, bunExe, tempDir } from "harness"; // TODO: Remove skip once the issue is fixed test.skip("TypeScript __exportStar helper should not hang with complex module structures", async () => { // Regression test for Angular CLI compatibility issue // Angular CLI hangs when using bun run --bun due to an infinite loop in __exportStar helper // when processing modules with certain patterns of exports, classes, and property initializers using dir = tempDir("typescript-exportstar-hang", { "index.js": ` console.log("Testing TypeScript __exportStar helper pattern"); // TypeScript's __exportStar helper (as generated by tsc) var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) { __createBinding(exports, m, p); } }; // Set timeout to detect hanging const timeout = setTimeout(() => { console.error("HANG: Script timed out after 3 seconds"); process.exit(1); }, 3000); Object.defineProperty(exports, "__esModule", { value: true }); // This pattern mimics what happens in @angular-devkit/core/src/json/schema/index.js // Multiple __exportStar calls in sequence __exportStar(require("./module1"), exports); __exportStar(require("./module2"), exports); __exportStar(require("./module3"), exports); // This is where Angular hangs clearTimeout(timeout); console.log("SUCCESS: No hang occurred"); process.exit(0); `, // First module - simple exports "module1.js": ` "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.simpleFunction = function() { return "test1"; }; exports.simpleValue = 42; `, // Second module - class with methods "module2.js": ` "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SimpleClass = void 0; class SimpleClass { method() { return "test2"; } } exports.SimpleClass = SimpleClass; `, // Third module - complex structure that triggers the hang // This mimics @angular-devkit/core/src/json/schema/registry.js structure "module3.js": ` "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) { if (k[i] !== "default") __createBinding(result, mod, k[i]); } __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComplexClass = exports.ComplexException = void 0; // Import Node.js built-in modules with __importStar const http = __importStar(require("node:http")); const https = __importStar(require("node:https")); const url = __importStar(require("node:url")); // Import from relative module const utils = require("./utils"); // Exception class (mimics SchemaValidationException) class ComplexException extends Error { errors; constructor(errors, baseMessage = 'Validation failed with the following errors:') { if (!errors || errors.length === 0) { super('Validation failed.'); this.errors = []; return; } const messages = ComplexException.createMessages(errors); super(baseMessage + messages.join(', ')); this.errors = errors; } static createMessages(errors) { if (!errors || errors.length === 0) { return []; } return errors.map((err) => { let message = 'Error: ' + err.message; if (err.params) { switch (err.keyword) { case 'additionalProperties': message += '(' + err.params.additionalProperty + ')'; break; case 'enum': message += '. Allowed values are: ' + (err.params.allowedValues || []).join(', '); break; } } return message + '.'; }); } } exports.ComplexException = ComplexException; // Complex class with property initializers (mimics CoreSchemaRegistry) class ComplexClass { _cache = new Map(); _handlers = new Set(); _pre = []; _post = []; _currentInfo; constructor() { this._cache.set("default", {}); this._pre.push({ order: 0 }); this._post.push({ order: 1 }); } async process(value) { const cached = this._cache.get(value); if (cached) { return cached; } const result = await this._doProcess(value); this._cache.set(value, result); return result; } async _doProcess(value) { // Simulate some async processing return new Promise(resolve => { setTimeout(() => resolve({ processed: value }), 0); }); } addHandler(handler) { this._handlers.add(handler); } static isValid(value) { return value != null && typeof value === 'object'; } } exports.ComplexClass = ComplexClass; `, // Utils module imported by module3 "utils.js": ` "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PartiallyOrderedSet = void 0; exports.isObject = function(v) { return typeof v === 'object' && v !== null; }; class PartiallyOrderedSet { _items = []; add(item) { this._items.push(item); } clear() { this._items = []; } } exports.PartiallyOrderedSet = PartiallyOrderedSet; `, }); await using proc = Bun.spawn({ cmd: [bunExe(), "index.js"], env: bunEnv, cwd: String(dir), stderr: "pipe", stdout: "pipe", }); const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); expect(stdout).toContain("SUCCESS: No hang occurred"); expect(stdout).not.toContain("HANG: Script timed out"); expect(exitCode).toBe(0); });