@dhlab/e2e-autogen
Version:
Google 스프레드시트 기반 시나리오를 Playwright 테스트 스텁 코드로 자동 생성하고, 테스트 실행 결과를 다시 시트에 업데이트하는 CLI 도구
193 lines (191 loc) • 8.14 kB
JavaScript
;
var _UserConfig_instances, _UserConfig_configPath, _UserConfig_fileExists, _UserConfig_loadConfig, _UserConfig_loadWithTsx, _UserConfig_loadWithTsNode, _UserConfig_loadWithDynamicImport, _UserConfig_validateConfig;
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadUserConfig = void 0;
const tslib_1 = require("tslib");
const child_process_1 = require("child_process");
const path_1 = tslib_1.__importDefault(require("path"));
const util_1 = require("util");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
class UserConfig {
constructor(configPath = "e2e-autogen.config.ts") {
_UserConfig_instances.add(this);
_UserConfig_configPath.set(this, void 0);
tslib_1.__classPrivateFieldSet(this, _UserConfig_configPath, path_1.default.resolve(configPath), "f");
}
async load() {
if (!tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_fileExists).call(this)) {
throw new Error(`Config file not found: ${tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f")}`);
}
return tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_loadConfig).call(this);
}
}
_UserConfig_configPath = new WeakMap(), _UserConfig_instances = new WeakSet(), _UserConfig_fileExists = function _UserConfig_fileExists() {
try {
const fs = require("fs");
return fs.existsSync(tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f"));
}
catch {
return false;
}
}, _UserConfig_loadConfig = async function _UserConfig_loadConfig() {
// 방법 1: tsx 사용
try {
return await tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_loadWithTsx).call(this);
}
catch (error) { }
// 방법 2: ts-node 사용
try {
return await tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_loadWithTsNode).call(this);
}
catch (error) { }
// 방법 3: 직접 파일 읽기 후 동적 import
try {
return await tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_loadWithDynamicImport).call(this);
}
catch (error) { }
throw new Error(`Failed to load config from ${tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f")}. All methods failed.`);
}, _UserConfig_loadWithTsx = async function _UserConfig_loadWithTsx() {
const command = `tsx -e "
import('${tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f")}').then(module => {
const config = module.default || module;
console.log(JSON.stringify(config));
}).catch(err => {
console.error('Import error:', err.message);
process.exit(1);
})
"`;
const { stdout } = await execAsync(command);
const output = stdout.trim();
if (!output) {
throw new Error("Empty output from tsx");
}
try {
const parsed = JSON.parse(output);
const config = parsed.default || parsed;
tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_validateConfig).call(this, config);
return config;
}
catch (parseError) {
// JSON 파싱이 실패하면 수동으로 추출 시도
try {
const jsonMatch = output.match(/\{[\s\S]*\}/);
if (jsonMatch) {
const manualParsed = JSON.parse(jsonMatch[0]);
const config = manualParsed.default || manualParsed;
tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_validateConfig).call(this, config);
return config;
}
}
catch {
// 무시
}
throw new Error(`Failed to parse tsx output: ${parseError.message}`);
}
}, _UserConfig_loadWithTsNode = async function _UserConfig_loadWithTsNode() {
const command = `npx ts-node --esm -e "
import('${tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f").replace(".ts", "")}').then(module => {
const config = module.default || module;
console.log(JSON.stringify(config));
}).catch(err => {
console.error('Import error:', err.message);
process.exit(1);
})
"`;
try {
const { stdout } = await execAsync(command);
const output = stdout.trim();
if (!output) {
throw new Error("Empty output from ts-node");
}
const parsed = JSON.parse(output);
const config = parsed.default || parsed;
tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_validateConfig).call(this, config);
return config;
}
catch (execError) {
// ts-node가 실패하면 다른 방법 시도
try {
const fallbackCommand = `npx ts-node -e "
const fs = require('fs');
const content = fs.readFileSync('${tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f")}', 'utf-8');
const config = eval('(' + content.replace(/export\\s+default\\s+/, '') + ')');
console.log(JSON.stringify(config));
"`;
const { stdout } = await execAsync(fallbackCommand);
const output = stdout.trim();
const config = JSON.parse(output);
tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_validateConfig).call(this, config);
return config;
}
catch {
throw new Error(`Failed to parse ts-node output: ${execError.message}`);
}
}
}, _UserConfig_loadWithDynamicImport = async function _UserConfig_loadWithDynamicImport() {
const fs = await import('fs');
const content = fs.readFileSync(tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f"), "utf-8");
// export default를 찾아서 추출
const defaultExportPatterns = [
/export\s+default\s+({[\s\S]*?});?$/m,
/export\s+default\s+([^;]+);?$/m,
/const\s+config\s*=\s*({[\s\S]*?});?\s*export\s+default\s+config;?$/m,
/export\s+default\s+([^;]+);?$/m,
];
let defaultExportMatch = null;
for (const pattern of defaultExportPatterns) {
defaultExportMatch = content.match(pattern);
if (defaultExportMatch) {
break;
}
}
if (!defaultExportMatch) {
// export default가 없으면 전체 파일에서 객체를 찾기
const objectPattern = /({[\s\S]*?});?$/m;
const objectMatch = content.match(objectPattern);
if (objectMatch) {
defaultExportMatch = objectMatch;
}
else {
throw new Error("No default export or object found in config file");
}
}
// 임시 JS 파일 생성
const tempJsPath = tslib_1.__classPrivateFieldGet(this, _UserConfig_configPath, "f").replace(".ts", ".temp.js");
const jsContent = `
const config = ${defaultExportMatch[1]};
console.log(JSON.stringify(config));
`;
fs.writeFileSync(tempJsPath, jsContent);
try {
const { stdout } = await execAsync(`node ${tempJsPath}`);
const output = stdout.trim();
const config = JSON.parse(output);
tslib_1.__classPrivateFieldGet(this, _UserConfig_instances, "m", _UserConfig_validateConfig).call(this, config);
return config;
}
finally {
// 임시 파일 정리
try {
fs.unlinkSync(tempJsPath);
}
catch {
// 무시
}
}
}, _UserConfig_validateConfig = function _UserConfig_validateConfig(config) {
if (!config || typeof config !== "object") {
throw new Error("Config must be an object");
}
const requiredFields = ["sheetsUrl", "framework", "stubOutputFolder"];
for (const field of requiredFields) {
if (!(field in config)) {
throw new Error(`Missing required config field: ${field}`);
}
}
};
const loadUserConfig = async () => {
const loader = new UserConfig();
return loader.load();
};
exports.loadUserConfig = loadUserConfig;