/// /// /// /// /// import * as sourceMapSupport from 'source-map-support'; sourceMapSupport.install(); import * as fs from "fs"; import * as path from "path"; import * as webpack from "webpack"; const MemoryFileSystem = require("./memoryfs"); const name = 'g6'; export interface IInstance { location: string; folder: string; } function _requireNotCached(path: string) { const r = eval("require"); delete r.cache[path]; return r(path); } function _require(path: string) { const r = eval("require"); return r(path); } export function resolve(options: { which?: boolean } = {}): Promise { return new Promise((resolve, reject) => { const resolve_if_at = (location, folder) => { const js_path = path.join(folder, 'bin', name + ".js"); const package_path = path.join(folder, 'package.json'); if (!fs.existsSync(folder) || !fs.existsSync(js_path) || !fs.existsSync(package_path)) return false; resolve({ location, folder } as IInstance); return true; }; if (resolve_if_at("command line", path.dirname(process.argv[1]).split(path.delimiter).slice(0, -1).join(path.delimiter))) return; try { const folder = eval("require").resolve(name); if (resolve_if_at("local", folder.slice(0, -("/bin/" + name + ".js".length)))) return; } catch (e) { } if (process.env.NODE_PATH && !process.env.NODE_PATH.split(path.delimiter).every(p => !resolve_if_at("global", path.normalize(path.join(p, name))))) return; if (resolve_if_at("sibling", path.normalize(path.join(__dirname, '..', '..', name)))) return; reject('Cannot find ' + name + '.\nPlease install it locally with:\n\n npm install ' + name + ' --save-dev\n\n' + 'Or globally with:\n\n npm install ' + name + ' -g'); }); } export interface SpecExpectation { matcherName: string; message: string; stack: string; passed: boolean; } export interface SpecResult { fullName: string; description: string; failedExpectations: SpecExpectation[]; passedExpectations: SpecExpectation[]; } export async function spawnTest(specFile: string) { return new Promise((resolve, reject) => { var child_process = require("child_process"); console.log("Testing " + specFile + "..."); const _process = child_process.fork(path.resolve(package_folder, "bin/g6.jasmine.js"), [specFile]); _process.on("close", (code) => { console.log("exiting with code " + code); if (code) { reject(); return; } resolve(); }); }); } export async function test(from_path = process.cwd()) { if (!loader_folder) init((await resolve()).folder); const workspace = await getWorkspace(from_path); for (const project of workspace.projects) { const output_folder = path.join(project.package_folder, "bin"); // console.log("checking " + output_folder); const fail_file = path.join(output_folder, ".fail"); try { for (const spec of await find_files(output_folder, null, null, file_info => file_info.file.endsWith(".spec.js"))) await spawnTest(spec.file); } catch (error) { fs.writeFileSync(fail_file, error); throw error; } if (fs.existsSync(fail_file)) fs.truncateSync(fail_file); // const failed_specs: SpecResult[] = []; // for (const spec_result of await executeSpecs(spec_files, {})) // if ((spec_result as any).failedExpectations && (spec_result as any).failedExpectations.length) // failed_specs.push(spec_result); // if (failed_specs.length) { // for (const spec of failed_specs) { // console.log(); // console.log("Spec failed: " + spec.fullName); // for (const expectataion of spec.failedExpectations) { // // console.log(expectataion.message) // console.log(expectataion.stack); // console.log(); // } // console.log(); // } // fs.writeFileSync(fail_file, JSON.stringify(failed_specs)); // throw new Error("failed specs"); // } } } let package_folder: string = null; let loader_folder: string = null; export function init(folder: string) { package_folder = folder; loader_folder = path.join(folder, "node_modules"); } function spliceFilenameDottedParts(index: number, delete_count: number, insert: string = undefined) { return (_path: any) => { var parts = _path.split('.'); if (insert) parts.splice(index, delete_count, insert); else parts.splice(index, delete_count); _path = parts.join('.'); return _path; } } export async function clean(from_path = process.cwd()) { function remove_folder(path: string) { remove_files(path); fs.rmdirSync(path); }; function remove_files(path: string) { if (!fs.existsSync(path)) return; for (const full_path of fs.readdirSync(path).map((p: string) => path + "/" + p)) { if (fs.lstatSync(full_path).isDirectory()) remove_folder(full_path); else fs.unlinkSync(full_path); } } remove_files(path.join(from_path, 'bin')); } export type EntryPointKind = "web" | "node" | "electron" | "test-web" | "test-node"; export class EntryPoint { constructor(public project: Project, public kind: EntryPointKind, public file_info: IFileInfo, public build_config: IBuildConfig) { } } export interface IProjectReference { project: Project; version: string; } export type DependencyMap = { [name: string]: IProjectReference[] }; export interface IBuildConfig { kind: EntryPointKind; extension: string; config: (project: Project, entry_point: EntryPoint, entry_points: EntryPoint[]) => { webpack_config: any }; } export class Project { public name: string; public version: string; public package_json: any; public package_path: any; constructor(public package_folder: string) { try { this.package_path = path.join(package_folder, "package.json"); try { this.package_json = JSON.parse(fs.readFileSync(this.package_path).toString()); } catch (error) { } this.name = this.package_json.name; this.version = this.package_json.version; } catch (error) { } } async getLastModified(workspace?: Workspace) { const files = await find_files(this.package_folder, (folder_or_file_name: string) => folder_or_file_name[0] !== '.' && !ignore_paths[folder_or_file_name], (filter_from_path: string, file_info: IFileInfo[]) => { const result = filter_from_path === this.package_folder || file_info.every(f => f.file !== "package.json"); return result; }, (file_info: IFileInfo) => { const file_name = file_info.file.toLowerCase(); return file_name.endsWith(".ts") || file_name.endsWith(".json") || file_name.endsWith(".js"); }); let latest_modified = new Date(0); for (const file of files) if (file.stat.mtime.getTime() > latest_modified.getTime()) latest_modified = file.stat.mtime; if (workspace) { for (const dep of workspace.getAllDependencies(this)) { const latest_dep_built = await dep.project.getLastBuilt(); if (latest_dep_built.getTime() > latest_modified.getTime()) latest_modified = latest_dep_built; } } return latest_modified; } async getLastBuilt() { const output_folder = path.join(this.package_folder, "bin"); // console.log("checking " + output_folder); const files = await find_files(output_folder, null, null, file_info => true); let oldest_built: Date; for (const file of files) if (!oldest_built || oldest_built.getTime() > file.stat.mtime.getTime()) oldest_built = file.stat.mtime; return oldest_built || new Date(0); } getFailedTests() { return fs.existsSync(path.join(this.package_folder, "bin/.fail")); } } function getProject(from_path: string): Promise { // console.log("getProject " + from_path); return new Promise((resolve: (project: Project) => void, reject: Function) => { let last_candidate_path: string = undefined; let candidate_path = from_path; while (candidate_path && candidate_path !== last_candidate_path) { // console.log("checking " + candidate_path); const project = new Project(candidate_path); if (project.package_json) { resolve(project); return; } last_candidate_path = candidate_path; candidate_path = path.resolve(candidate_path, ".."); } // console.log("rejecting"); reject("No package.json file found in this or parent folders"); }) } const ignore_paths: { [folder_name: string]: boolean } = { "node_modules": true, "bin": true }; export class Workspace { public projects: Project[]; public dependencies: DependencyMap; private Workspace() { } static async create(from_path: string) { const workspace = new Workspace(); workspace.projects = await getProjects(from_path); workspace.dependencies = getDependencies(workspace.projects); return workspace; } getAllDependencies(project: Project, except: { [name: string]: boolean } = {}) { let result = this.dependencies[project.name].filter(p => !except[p.project.name]); // console.log("getAllDependencies of project: " + project.name + " = " + result.map(r => r.project.name)); for (const dependency of result) except[dependency.project.name] = true; for (const dependency of result.slice()) result = result.concat(this.getAllDependencies(dependency.project, except)); return result; } getAllDependents(project: Project) { return this.projects.filter(p => !!this.getAllDependencies(p).find(d => d.project.name == project.name)); } getProject = (name: string) => this.projects.find(p => p.name === name); async getEntryPoints(project?: Project): Promise { if (!project) { let entry_points = await Promise.all(this.projects.map(p => this.getEntryPoints(p))); const result = entry_points.reduce((prev, current) => prev.concat(current), []); // console.log("result: " + JSON.stringify(result)); return result; } // console.log("getting entry points for project: " + JSON.stringify(project.package_folder)); const include_file_or_folder = name => name[0] !== '.' && !ignore_paths[name]; const include_folder = (from_path, file_info) => from_path === project.package_folder || file_info.every(f => f.file !== "package.json"); const build_configs: IBuildConfig[] = [ { kind: "node", extension: ".entry.ts", config: configNode }, { kind: "electron", extension: ".entry.electron.ts", config: configElectron }, { kind: "test-node", extension: ".spec.node.ts", config: configTestNode }, ]; const include_file = (file_info: IFileInfo) => { const file_name = file_info.file.toLowerCase(); return !!build_configs.find(build_config => file_name.endsWith(build_config.extension)); }; const files = await find_files(project.package_folder, include_file_or_folder, include_folder, include_file); // console.log("entry points: " + JSON.stringify(files.map(f => f.file))); return files.map(f => new EntryPoint(project, "node", f, build_configs.find(build_config => f.file.endsWith(build_config.extension)))); } } function getExternals(entry_point: EntryPoint, entry_points: EntryPoint[]) { const o = {}; Object.assign(o, getInstalledNodeModules(entry_point.project.package_folder)); Object.assign(o, getOtherEntryPointModules(entry_point, entry_points)); if (entry_point.build_config.kind === "electron") o["electron"] = "commonjs electron-prebuilt"; // console.log("externals: " + JSON.stringify(o)); return o; } function getOtherEntryPointModules(this_entry_point: EntryPoint, entry_points: EntryPoint[]) { var modules: { [name: string]: string } = {}; for (const entry_point of entry_points.filter(ep => ep !== this_entry_point)) { let name = path.basename(entry_point.file_info.file, ".ts"); const extension = entry_point.build_config.extension.slice(0, -3); // console.log("extension: '" + extension + "'") let new_name = name; if (new_name.endsWith(extension)) new_name = new_name.slice(0, -extension.length); // console.log("name: " + name + ", new_name: '" + new_name + "'") modules[name] = "commonjs " + new_name; modules["./" + name] = "commonjs " + new_name; modules["../" + name] = "commonjs " + new_name; modules["../../" + name] = "commonjs " + new_name; } // console.log("OEP: " + JSON.stringify(modules)); return modules; } function getInstalledNodeModules(from_path: string) { var modules: { [name: string]: string } = {}; const node_modules_path = path.join(from_path, 'node_modules'); if (fs.existsSync(node_modules_path)) fs.readdirSync(node_modules_path) .filter((x: any) => ['.bin'].indexOf(x) === -1) .forEach((mod: any) => { modules[mod] = 'commonjs ' + mod; }); return modules; } function configNode(project: Project, entry_point: EntryPoint, entry_points: EntryPoint[]) { return { webpack_config: { target: 'node', resolve: { extensions: ['', '.ts', '.tsx', '.json', '.js'] }, entry: entry_point.file_info.file, devtool: 'source-map', context: project.package_folder, output: { path: path.resolve(project.package_folder, "bin"), filename: path.basename(entry_point.file_info.file, ".ts") + ".js", libraryTarget: 'commonjs', devtoolModuleFilenameTemplate: "[absolute-resource-path]", devtoolFallbackModuleFilenameTemplate: "[absolute-resource-path]?[hash]" }, module: { loaders: [ { test: /\.tsx?$/, loader: 'awesome-typescript-loader?declaration=true&useBabel=false&forkChecker=false&moduleResolution=node&forceConsistentCasingInFileNames=true' }, { test: /\.json$/, loader: 'json-loader' } ] }, devServer: { port: 80, inline: true, hot: true }, resolveLoader: { root: loader_folder }, externals: getExternals(entry_point, entry_points) } }; } function configTestNode(project: Project, entry_point: EntryPoint, entry_points: EntryPoint[]) { const config = configNode(project, entry_point, entry_points); config.webpack_config.output.filename = 'tests.node.spec.js'; config.webpack_config.module.loaders = [ { test: /\.tsx?$/, loader: 'awesome-typescript-loader?useBabel=false&forkChecker=false&moduleResolution=node&forceConsistentCasingInFileNames=true' }, { test: /\.json$/, loader: 'json-loader' } ]; return config; } function configElectron(project: Project, entry_point: EntryPoint, entry_points: EntryPoint[]) { const config = configNode(project, entry_point, entry_points); config.webpack_config.target = "electron"; config.webpack_config.module.loaders = [ { test: /\.tsx?$/, loader: 'awesome-typescript-loader?useBabel=false&forkChecker=false&moduleResolution=node&forceConsistentCasingInFileNames=true' }, { test: /\.json$/, loader: 'json-loader' } ]; return config; } export async function getWorkspace(from_path: string) { return await Workspace.create(from_path); } async function getProjects(from_path: string) { const package_files = await find_files(from_path, (folder_or_file_name: string) => folder_or_file_name[0] !== '.' && !ignore_paths[folder_or_file_name], null, (file_info: IFileInfo) => file_info.file === "package.json"); return package_files.map(f => new Project(path.dirname(f.file))) .filter(f => f.package_json); } async function find_files(from_path: string, ignore_file_or_folder_predicate: (folder_name: string) => boolean, folder_predicate: (from_path: string, file_infos: IFileInfo[]) => boolean, file_predicate: (file_info: IFileInfo) => boolean): Promise { var dir = readDir(from_path, ignore_file_or_folder_predicate); if (folder_predicate && !folder_predicate(from_path, dir)) return Promise.resolve([]); const files = dir.filter(d => !d.stat.isDirectory() && (!file_predicate || file_predicate(d))) .map(f => ({ file: path.join(from_path, f.file), stat: f.stat })); const folders = dir.filter(d => d.stat.isDirectory()); const promises = folders.map(folder => find_files(path.join(from_path, folder.file), ignore_file_or_folder_predicate, folder_predicate, file_predicate)); const found_in_folders = await Promise.all(promises); const files_found_in_folders = found_in_folders.reduce((previous, current) => previous.concat(current), []); return files.concat(files_found_in_folders); }; export interface IFileInfo { file: string; stat: any; } function readDir(from_path: string, predicate: (name: string) => boolean): IFileInfo[] { try { return (fs.readdirSync(path.normalize(from_path)) as string[]) .filter(f => !predicate || predicate(f)) .map(file => { try { return { file, stat: fs.statSync(path.resolve(from_path, file)) }; } catch (error) { return null; } }) .filter(f => !!f); } catch (error) { return []; } } function getFolders(from_path: string, ignore: (folder_name: string) => boolean) { return readDir(from_path, ignore) .filter(entry => !!entry && entry.stat && entry.stat.isDirectory()); } function getDependencies(projects: Project[]) { var result: DependencyMap = {}; for (const project of projects) { var dev_dependencies: { [name: string]: string } = project.package_json.devDependencies || {}; // console.log("dependencies: " + JSON.stringify(dev_dependencies)); result[project.name] = []; for (const name in dev_dependencies) if (dev_dependencies.hasOwnProperty(name)) { const referenced = projects.filter(p => p.name === name)[0]; if (referenced) result[project.name].push({ project: referenced, version: dev_dependencies[name] }); } } return result; } // return new Promise((resolve: Function, reject: Function) => { // function endsWith(value: string, ends_with: string) { // if (value.length < ends_with.length) // return false; // return value.slice(-ends_with.length) === ends_with; // } // const entry_points: EntryPoint[] = []; // function check_files(files: string[]) { // for (var file of files) { // if (endsWith(file, ".spec.ts")) // entry_points.push(new EntryPoint("test-web", file)) // if (endsWith(file, ".spec.node.ts")) // entry_points.push(new EntryPoint("test-node", file)) // if (endsWith(file, ".entry.ts")) // entry_points.push(new EntryPoint("node", file)) // if (endsWith(file, ".entry.web.ts")) // entry_points.push(new EntryPoint("web", file)) // } // } // // dir.files(__dirname, (err: any, files: string[]) => { // // if (err) // // reject(err); // // else // // check_files(files) // // }, () => resolve(entry_points)); // }) // } const chokidar = require("chokidar"); export async function watch(from_path = process.cwd()) { const w = await getWorkspace(from_path); const this_project = w.projects[0]; if (!w || !this_project) return Promise.resolve(); let buildNeeded = true; // const p = await getProject(process.cwd()); for (const p of w.projects) chokidar.watch(p.package_folder, { ignoreInitial: true, cwd: p.package_folder, ignored: [ /[\/\\]\./, '**/node_modules/**/*', '**/bin/**/*' ] }) .on("all", (event: any, path: any) => { if (event == "addDir") return; // console.log("file " + event + " " + path); buildNeeded = true; }); let building = false; async function buildIfNeeded() { if (buildNeeded && !building) { // console.log("build needed..."); buildNeeded = false; building = true; try { await build(from_path); } catch (error) { console.log("build errors: " + error); } finally { building = false; console.log("watch..."); } } setTimeout(() => buildIfNeeded().catch(error => console.error(error))); } await buildIfNeeded().catch(error => console.log(error)); } var mkdirSync = function (path) { if (fs.existsSync(path)) return; try { fs.mkdirSync(path); } catch (e) { if (e.code != 'EEXIST') throw e; } } var mkdirpSync = function (dirpath) { var parts = dirpath.split(path.sep); for (var i = 1; i <= parts.length; i++) { mkdirSync(path.join.apply(null, parts.slice(0, i))); } } async function buildNode(workspace: Workspace) { let built: { [name: string]: boolean } = {}; let queued: { [name: string]: Project } = {}; let keys = (o: { [name: string]: any }) => { const result = []; for (const key in o) if (o.hasOwnProperty(key)) result.push(key) return result; } const modified_projects = []; for (const p of workspace.projects) if ((await p.getLastModified(workspace)) > (await p.getLastBuilt())) modified_projects.push(p); else if (!p.getFailedTests()) built[p.name] = true; // console.log("modified_projects: " + modified_projects.map(p => p.name).join(", ")); const to_queue = modified_projects.map(p => [p].concat(workspace.getAllDependents(p))).reduce((prev, current) => prev.concat(current), []); // console.log("to_queue: " + to_queue.map(p => p.name).join(", ")); const to_build = []; for (const p of to_queue) if ((await workspace.getEntryPoints(p)).length) to_build.push(p); // console.log("to_build: " + to_build.map(p => p.name).join(", ")); if (!to_build.length) { console.log("everything is up-to-date") } for (const project of to_build) queued[project.name] = project; // console.log("queued: " + JSON.stringify(queued)); while (true) { const queued_projects = keys(queued).map(n => queued[n]); if (!queued_projects.length) break; const ready_to_run = queued_projects.filter(p => { const deps = workspace.getAllDependencies(p); // console.log("dependencies of " + p.name + " are " + deps.map(d => d.project.name).join(", ")); return deps.every(d => built[d.project.name]); }); if (!ready_to_run.length) throw new Error("Unmet dependencies - can't build any of:" + queued_projects.map(p => p.name).join(",") + "\nUse 'g6 list' to diagnose.") // console.log("ready_to_run: " + ready_to_run.map(p => p.name).join(", ")); for (const project of ready_to_run) { const entry_points = await workspace.getEntryPoints(project); if (entry_points.length) { await buildNodeProject(workspace, project, entry_points); } built[project.name] = true; delete queued[project.name]; } } } async function buildNodeProject(workspace: Workspace, project: Project, entry_points: EntryPoint[]) { // console.log("build '" + project.name + "'...");// with " + entry_points.length + " entry points"); await clean(project.package_folder); const configs = entry_points.map(entry_point => Object.assign({}, entry_point.build_config.config(entry_point.project, entry_point, entry_points).webpack_config)); // console.log("webpacking: " + JSON.stringify(configs)); process.chdir(project.package_folder); var memory_fs = new MemoryFileSystem(); var compiler = webpack(configs); compiler.outputFileSystem = memory_fs; const build_result = await new Promise((resolve, reject) => { compiler.run((err, stats) => { try { if (err) { reject(err); return; } if (stats.hasErrors()) { reject("\n\nError/s: ---------------------------------------------------------\n\n" + stats.toJson({ reasons: true, errorDetails: true, timings: true }).errors.map(e => e.startsWith("(undefined) [default] ") ? e.slice("(undefined) [default] ".length) : e).join("\n") + "\n\n------------------------------------------------------------------\n\n\n"); return; } const output_folder = path.resolve(project.package_folder, "bin"); function copy_files(from_folder) { var files = memory_fs.readdirSync(from_folder); for (var file of files) { const file_path = path.join(from_folder, file); // console.log("checking file_path: " + file_path); var stat = memory_fs.statSync(file_path); if (stat.isDirectory()) { // console.log("found folder: " + file_path); copy_files(file_path); } else { var contents = memory_fs.readfilesync(file_path); let new_file_path = file_path; for (const ep of entry_points) { let config_entry = path.basename(ep.file_info.file, ".ts"); let file_basename = path.basename(file_path); // console.log("checking config for file: " + file_basename + " vs " + config_entry + ".d.ts"); if (file_basename === config_entry + ".js") { new_file_path = file_path.slice(0, -ep.build_config.extension.length) + ".js"; const lines: string[] = contents.toString().split(/\r?\n/); const package_json = project.package_json; const bin = package_json.bin; // console.log("checking project.package_json.bin for : " + new_file_path + ", using " + JSON.stringify(package_json)); if (bin) for (var key in bin) if (bin.hasOwnProperty(key)) { const _path = bin[key]; const path_of_command = path.resolve(project.package_folder, _path); if (path_of_command === new_file_path) { lines.splice(0, 0, "#!/usr/bin/env/node"); break; } } const last_line = lines[lines.length - 1]; const map_name = ep.build_config.extension.slice(0, -3) + ".js.map"; if (last_line.startsWith("//# sourceMappingURL=") && last_line.endsWith(map_name)) lines[lines.length - 1] = last_line.slice(0, last_line.length - map_name.length) + ".js.map"; lines.push("//# sourceURL=" + config_entry + ".ts"); contents = lines.join("\n"); console.log("building " + ep.build_config.kind + ": " + new_file_path); } else if (file_basename === config_entry + ".d.ts") { new_file_path = file_path.slice(0, -(ep.build_config.extension.length + ".d".length)) + ".d.ts"; } else if (file_basename === config_entry + ".js.map") { new_file_path = file_path.slice(0, -(ep.build_config.extension.length + ".map".length)) + ".js.map"; const map_file = JSON.parse(contents) as { "version": number, "file": string, "sourceRoot": string, "sources": string[], "sourcesContent": string[], "names": string[], "mappings": string }; if (map_file.file.endsWith(ep.build_config.extension)) map_file.file = map_file.file.slice(0, -ep.build_config.extension.length) + ".js" map_file.sourcesContent = map_file.sourcesContent.map(c => null); map_file.sourceRoot = ""; //path.relative(output_folder, project.package_folder); map_file.sources = map_file.sources.map(s => { s = path.isAbsolute(s) ? s : path.resolve(s); s = path.relative(output_folder, s); return s.replace(/\\/g, "/"); }); contents = JSON.stringify(map_file); } } if (new_file_path.endsWith(".d.ts")) { // console.log("filtering triple-slash comment lines from: " + file_basename); contents = contents.toString().split(/\r?\n/).filter((l: string) => !l.startsWith("///")).join('\n'); // console.log("moving .d.ts"); const name = path.basename(new_file_path); // console.log("name: " + name); new_file_path = path.join(output_folder, name); // console.log("to " + new_file_path); } mkdirpSync(path.dirname(new_file_path)); if (!fs.existsSync(new_file_path)) fs.writeFileSync(new_file_path, contents); } } } if (!memory_fs.existsSync(output_folder)) console.log("no output for: " + project.name); else copy_files(output_folder); resolve(stats); } catch (error) { reject(error); } }); }); await test(project.package_folder); return build_result; } export async function build(from_path = process.cwd()) { const webpack = require('webpack'); const ws = await getWorkspace(from_path); if (!loader_folder) init((await resolve()).folder); // function buildWeb(source: any, target: any, renameTo: string | Function): Promise { // if (!source) // return Promise.resolve(); // const config = { // resolve: { // extensions: ['', '.ts', '.tsx'] // }, // resolveLoader: { // root: path.join(__dirname, "node_modules") // }, // // devtool: 'inline-source-map', // module: { // loaders: [ // { test: /\.tsx?$/, loader: 'awesome-typescript-loader?useBabel=false&forkChecker=false&moduleResolution=node&forceConsistentCasingInFileNames=true' } // ] // }, // devServer: { // port: 80, // inline: true, // hot: true // }, // target // }; // console.log("buildWeb: " + JSON.stringify(config)); // return gulp_promise(source // .pipe(sourcemaps.init()) // .pipe(webpack(config, null, (err: any, stats: string) => { // if (err) // throw err; // // console.log("stats: " + stats); // })) // .pipe(rename(renameTo)) // // .pipe(uglify()) // .pipe(sourcemaps.write('.', { sourceRoot: '.' })) // .pipe(gulp.dest("bin"))); // } // console.log("building..."); // console.log("building node outputs..."); const promises = [ // buildWeb(src_exists('**/*.entry.web.ts'), "web", removeSegment), buildNode(ws), // buildWeb(src_exists('**/*.spec.ts'), "web", "specs.js"), // buildNode(process.cwd(), src_exists('**/*.spec.node.ts'), "tests/node.spec.js") ]; await Promise.all(promises); } export async function testWeb() { return new Promise(async function (resolve: Function, reject: Function) { await build(); console.log("Testing..."); const karma = require('karma'); const karma_config = { basePath: '', frameworks: ['jasmine'], files: ['bin/specs.js'], reporters: ['progress', 'junit'], port: 9876, colors: true, autoWatch: true, browsers: ['Firefox'], singleRun: true, junitReporter: { outputDir: process.env.CIRCLE_ARTIFACTS || "bin", outputFile: 'junit.xml' } }; new karma.Server(karma_config, () => resolve()).start(); }) }