"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Project = exports.Target = exports.Library = void 0; const child_process = require("child_process"); const fs = require("fs"); const path = require("path"); const log = require("./log"); const ProjectFile_1 = require("./ProjectFile"); class Library { } exports.Library = Library; class Target { constructor(baseTarget, backends) { this.baseTarget = baseTarget; this.backends = backends; } } exports.Target = Target; function contains(main, sub) { main = path.resolve(main); sub = path.resolve(sub); if (process.platform === 'win32') { main = main.toLowerCase(); sub = sub.toLowerCase(); } return sub.indexOf(main) === 0 && sub.slice(main.length)[0] === path.sep; } class Project { constructor(name) { this.icon = null; this.name = name; this.safeName = name.replace(/[^A-z0-9\-\_]/g, '-'); this.version = '1.0'; this.sources = []; this.defines = ['hxcpp_smart_strings']; this.cdefines = []; this.cflags = []; this.cppflags = []; this.parameters = []; this.scriptdir = Project.scriptdir; this.libraries = []; this.localLibraryPath = 'Libraries'; this.assetMatchers = []; this.shaderMatchers = []; this.customTargets = new Map(); this.stackSize = 0; this.windowOptions = {}; this.targetOptions = { html5: {}, flash: {}, android: {}, android_native: {}, ios: {}, xboxOne: {}, playStation4: {}, switch: {}, xboxSeriesXS: {}, playStation5: {}, stadia: {} }; } getSafeName() { return this.safeName; } async addProject(projectDir) { if (!path.isAbsolute(projectDir)) { projectDir = path.join(this.scriptdir, projectDir); } if (!fs.existsSync(path.join(projectDir, 'khafile.js')) && (fs.existsSync(path.join(projectDir, 'kincfile.js')) || fs.existsSync(path.join(projectDir, 'korefile.js')) || fs.existsSync(path.join(projectDir, 'kfile.js')))) { this.libraries.push({ libpath: projectDir, libroot: projectDir }); } else { let project = await (0, ProjectFile_1.loadProject)(projectDir, 'khafile.js', Project.platform); this.assetMatchers = this.assetMatchers.concat(project.assetMatchers); this.sources = this.sources.concat(project.sources); this.shaderMatchers = this.shaderMatchers.concat(project.shaderMatchers); this.defines = this.defines.concat(project.defines); this.cdefines = this.cdefines.concat(project.cdefines); this.cflags = this.cflags.concat(project.cflags); this.cppflags = this.cppflags.concat(project.cppflags); this.parameters = this.parameters.concat(project.parameters); this.libraries = this.libraries.concat(project.libraries); if (this.icon === null && project.icon !== null) this.icon = path.join(projectDir, project.icon); for (let customTarget of project.customTargets.keys()) { this.customTargets.set(customTarget, project.customTargets.get(customTarget)); } // windowOptions and targetOptions are ignored } } unglob(str) { const globChars = ['\\@', '\\!', '\\+', '\\*', '\\?', '\\(', '\\[', '\\{', '\\)', '\\]', '\\}']; str = str.replace(/\\/g, '/'); for (const char of globChars) { str = str.replace(new RegExp(char, 'g'), char); } return str; } getBaseDir(str) { // replace \\ to / if next char is not glob str = str.replace(/\\([^@!+*?{}()[\]]|$)/g, '/$1'); // find non-globby path part const globby = /[^\\][@!+*?{}()[\]]/; while (globby.test(str)) { str = path.posix.dirname(str); } str = this.removeGlobEscaping(str); if (!str.endsWith('/')) str += '/'; return str; } removeGlobEscaping(str) { return str.replace(/\\([@!+*?{}()[\]]|$)/g, '$1'); } /** * Add all assets matching the match glob relative to the directory containing the current khafile. * Asset types are infered from the file suffix. * Glob syntax is very simple, the most important patterns are * for anything and ** for anything across directories. */ addAssets(match, options) { if (!options) options = {}; if (!path.isAbsolute(match)) { let base = this.unglob(path.resolve(this.scriptdir)); if (!base.endsWith('/')) base += '/'; // if there is no nameBaseDir: extract relative assets path from match const baseName = options.nameBaseDir == null ? this.getBaseDir(match) : options.nameBaseDir; match = path.posix.join(base, match.replace(/\\/g, '/')); options.baseDir = path.posix.join(this.removeGlobEscaping(base), baseName); } else { options.baseDir = this.getBaseDir(match); } this.assetMatchers.push({ match: match, options: options }); } addSources(source) { this.sources.push(path.resolve(path.join(this.scriptdir, source))); } /** * Add all shaders matching the match glob relative to the directory containing the current khafile. * Glob syntax is very simple, the most important patterns are * for anything and ** for anything across directories. */ addShaders(match, options) { if (!options) options = {}; if (!path.isAbsolute(match)) { let base = this.unglob(path.resolve(this.scriptdir)); if (!base.endsWith('/')) { base += '/'; } match = base + match.replace(/\\/g, '/'); } this.shaderMatchers.push({ match: match, options: options }); } addDefine(define) { this.defines.push(define); } addCDefine(define) { this.cdefines.push(define); } addCFlag(flag) { this.cflags.push(flag); } addCppFlag(flag) { this.cppflags.push(flag); } addParameter(parameter) { this.parameters.push(parameter); } addTarget(name, baseTarget, backends) { this.customTargets.set(name, new Target(baseTarget, backends)); } addLibrary(library) { this.addDefine(library); let self = this; function findLibraryDirectory(name) { if (path.isAbsolute(name)) { return { libpath: name, libroot: name }; } // Tries to load the default library from inside the kha project. // e.g. 'Libraries/wyngine' let libpath = path.join(self.scriptdir, self.localLibraryPath, name); if (fs.existsSync(libpath) && fs.statSync(libpath).isDirectory()) { let dir = path.resolve(libpath); return { libpath: dir, libroot: dir }; } // If the library couldn't be found in Libraries folder, try // looking in the haxelib folders. // e.g. addLibrary('hxcpp') => '/usr/lib/haxelib/hxcpp/3,2,193' try { libpath = path.join(child_process.execSync('haxelib config', { encoding: 'utf8' }).trim(), name.replace(/\./g, ',')); } catch (error) { if (process.env.HAXEPATH) { libpath = path.join(process.env.HAXEPATH, 'lib', name.toLowerCase()); } } if (fs.existsSync(libpath) && fs.statSync(libpath).isDirectory()) { if (fs.existsSync(path.join(libpath, '.dev'))) { libpath = fs.readFileSync(path.join(libpath, '.dev'), 'utf8'); if (!path.isAbsolute(libpath)) { libpath = path.resolve(libpath); } return { libpath: libpath, libroot: libpath }; } else if (fs.existsSync(path.join(libpath, '.current'))) { // Get the latest version of the haxelib path, // e.g. for 'hxcpp', latest version '3,2,193' let current = fs.readFileSync(path.join(libpath, '.current'), 'utf8'); return { libpath: path.join(libpath, current.replace(/\./g, ',')), libroot: libpath }; } } // check relative path if (fs.existsSync(path.resolve(name))) { let libpath = path.resolve(name); return { libpath: libpath, libroot: libpath }; } // Show error if library isn't found in Libraries or haxelib folder log.error('Error: Library ' + name + ' not found.'); log.error('Add it to the \'Libraries\' subdirectory of your project. You may also install it via haxelib but that\'s less cool.'); throw 'Library ' + name + ' not found.'; } let libInfo = findLibraryDirectory(library); let dir = libInfo.libpath; if (dir !== '') { for (let elem of this.libraries) { if (elem.libroot === libInfo.libroot) return ''; } this.libraries.push({ libpath: dir, libroot: libInfo.libroot }); // If this is a haxelib library, there must be a haxelib.json if (fs.existsSync(path.join(dir, 'haxelib.json'))) { let options = JSON.parse(fs.readFileSync(path.join(dir, 'haxelib.json'), 'utf8')); // If there is a classPath value, add that directory to be loaded. // Otherwise, just load the current path. if (options.classPath) { // TODO find an example haxelib that has a classPath value this.sources.push(path.join(dir, options.classPath)); } else { // e.g. '/usr/lib/haxelib/hxcpp/3,2,193' this.sources.push(dir); } // If this haxelib has other library dependencies, add them too if (options.dependencies) { for (let dependency in options.dependencies) { if (dependency.toLowerCase() !== 'kha') { this.addLibrary(dependency); } } } } else { // If there is no haxelib.json file, then just load the library // by the Sources folder. // e.g. Libraries/wyngine/Sources if (!fs.existsSync(path.join(dir, 'Sources'))) { log.info('Warning: No haxelib.json and no Sources directory found in library ' + library + '.'); } this.sources.push(path.join(dir, 'Sources')); } if (fs.existsSync(path.join(dir, 'extraParams.hxml'))) { let params = fs.readFileSync(path.join(dir, 'extraParams.hxml'), 'utf8'); for (let parameter of params.split('\n')) { let param = parameter.trim(); if (param !== '') { if (param.startsWith('-lib')) { // (DK) // - '-lib xxx' is for linking a library via haxe, it forces the use of the haxelib version // - this should be handled by khamake though, as it tracks the dependencies better (local folder or haxelib) log.info('Ignoring ' + dir + '/extraParams.hxml "' + param + '"'); } else { this.addParameter(param); } } } } this.addShaders(dir + '/Sources/Shaders/**', {}); } return dir; } } exports.Project = Project; //# sourceMappingURL=Project.js.map