"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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __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 }); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os_family_1 = __importDefault(require("os-family")); const strip_bom_1 = __importDefault(require("strip-bom")); const crypto_1 = require("crypto"); const url_1 = require("url"); const pinkie_1 = __importDefault(require("pinkie")); const legacy_1 = require("./legacy"); const require_reader_1 = __importDefault(require("./require-reader")); const promisify_1 = __importDefault(require("../utils/promisify")); var readFile = (0, promisify_1.default)(fs.readFile); function exists(filePath) { return new pinkie_1.default(resolve => fs.exists(filePath, resolve)); } const FIXTURE_RE = /(^|;|\s+)('|")@fixture\s+.+?\2/; const PAGE_RE = /(^|;|\s+)('|")@page\s+.+?\2/; const TEST_RE = /(^|;|\s+)('|")@test\2\s*\[('|").+?\3\]\s*=\s*\{/; class CompilerAdapter { constructor(hammerheadProcessScript) { this.cache = { requires: {}, requireJsMap: {}, sourceIndex: [], configs: {} }; this.hammerheadProcessScript = hammerheadProcessScript; this.requireReader = new require_reader_1.default(this.cache.requires, this.hammerheadProcessScript); } static _resolveConfigModules(cfg, dirName) { if (cfg.modules) { Object.keys(cfg.modules).forEach(name => { var mod = cfg.modules[name]; if (Array.isArray(mod)) mod = mod.map(filePath => path.resolve(dirName, filePath)); else mod = path.resolve(dirName, mod); cfg.modules[name] = mod; }); } } static async _collectDirConfigs(dirName) { var cfgs = []; var dirHierarchy = dirName .split(path.sep) .reduce((dirs, chunk) => { var dir = null; if (dirs.length) dir = path.join(dirs[dirs.length - 1], chunk); else if (os_family_1.default.win) dir = chunk; else dir = path.sep + chunk; dirs.push(dir); return dirs; }, []); for (var dir of dirHierarchy) { var cfgPath = path.join(dir, 'test_config.json'); var isExists = await exists(cfgPath); if (isExists) { var data = await readFile(cfgPath); var cfg = JSON.parse((0, strip_bom_1.default)(data)); CompilerAdapter._resolveConfigModules(cfg, dir); cfgs.push(cfg); } } return cfgs; } async _getConfig(filePath) { var dirName = path.dirname(filePath); var cfg = {}; var cachedCfg = this.cache.configs[dirName]; if (cachedCfg) cfg = cachedCfg; else { // NOTE: walk up in the directories hierarchy and collect test_config.json files var dirConfigs = await CompilerAdapter._collectDirConfigs(dirName); cfg = { modules: {}, baseUrl: '' }; dirConfigs.forEach(dirCfg => { if (dirCfg.modules) { Object.keys(dirCfg.modules).forEach(name => { cfg.modules[name] = dirCfg.modules[name]; }); } if (dirCfg.baseUrl) cfg.baseUrl = (0, url_1.resolve)(cfg.baseUrl, dirCfg.baseUrl); }); this.cache.configs[dirName] = cfg; } return cfg; } _createLegacyCompilerPromise(code, filename, modules) { return new pinkie_1.default((resolve, reject) => { var legacyCompiler = new legacy_1.Compiler(code, filename, modules, this.requireReader, this.cache.sourceIndex, this.hammerheadProcessScript); legacyCompiler.compile((errs, out) => { if (errs) { var msg = 'There are test compilation errors:\n'; msg += errs.map(err => ` * ${(0, legacy_1.getErrMsg)(err)}`).join('\n'); reject(new Error(msg)); } else resolve(out); }); }); } _createTests(compiled, filePath, baseUrl, requireJsMapKey, remainderJs) { var fixture = { name: compiled.fixture, path: filePath, pageUrl: (0, url_1.resolve)(baseUrl, compiled.page), authCredentials: compiled.authCredentials, getSharedJs: () => this.cache.requireJsMap[requireJsMapKey] + remainderJs }; return Object.keys(compiled.testsStepData).map(testName => ({ name: testName, sourceIndex: this.cache.sourceIndex, stepData: compiled.testsStepData[testName], fixture: fixture, isLegacy: true, pageUrl: fixture.pageUrl, authCredentials: fixture.authCredentials })); } canCompile(code, filename) { return /\.test\.js$/.test(filename) && FIXTURE_RE.test(code) && PAGE_RE.test(code) && TEST_RE.test(code); } getSupportedExtension() { return '.test.js'; } cleanUp() { // NOTE: Do nothing. } async compile(code, filename) { var { modules, baseUrl } = await this._getConfig(filename); var compiled = await this._createLegacyCompilerPromise(code, filename, modules); //NOTE: solve memory overuse issue by storing requireJs in the suite-level hash-based map //(see: B237609 - Fixture file compiler memory overuse) var hash = (0, crypto_1.createHash)('md5'); var requireJsMap = this.cache.requireJsMap; var remainderJs = compiled.remainderJs; hash.update(compiled.requireJs); var requireJsMapKey = hash.digest('hex'); if (!requireJsMap[requireJsMapKey]) requireJsMap[requireJsMapKey] = compiled.requireJs; return this._createTests(compiled, filename, baseUrl, requireJsMapKey, remainderJs); } } exports.default = CompilerAdapter;