UNPKG

@adpt/core

Version:
444 lines 16.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); /* * Copyright 2017-2019 Unbounded Systems, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const fs = tslib_1.__importStar(require("fs")); const path_1 = require("path"); const error_1 = require("../error"); const utils_1 = require("../utils"); const ts = tslib_1.__importStar(require("./tsmod")); // tslint:disable-next-line:no-var-requires const typeName = require("type-name"); const tsmod = ts.tsmod; exports.debugChainableHosts = false; exports.debugChainableHostsVerbose = false; if (exports.debugChainableHostsVerbose) exports.debugChainableHosts = true; exports.debugDir = true; // Member function -> Which arg to canonicalize const initCanonicalize = { fileExists: 0, directoryExists: 0, readFile: 0, getFileVersion: 0, getSourceFile: 0, writeFile: 0, getDirectories: 0, realFilename: 0, }; const noop = undefined; function callSource(proto, propKey, desc) { return Object.assign({}, desc, { value: function _toSource(...args) { if (!this.source) throw new error_1.InternalError(`source for ${this.constructor.name} is null`); return this.source[propKey].apply(this.source, args); } }); } class ChainableHost { constructor(cwd) { this.cwd = cwd; this._id = ""; // @ts-ignore - Cheat so we don't have to check for null everywhere this.source = null; for (const key of Object.keys(initCanonicalize)) { // @ts-ignore this.canonicalizeFunc(key, initCanonicalize[key]); } } directoryExists(directoryname) { return noop; } fileExists(fileName) { return noop; } getCancellationToken() { return noop; } getDefaultLibFileName(options) { return noop; } getDirectories(path) { return noop; } getFileVersion(fileName) { return noop; } getNewLine() { return noop; } getSourceFile(fileName, languageVersion, onError) { return noop; } readFile(fileName) { return noop; } /** * Should be implemented by any Host that performs filename translation. * Given a possibly "faked" or virtual filename, return the real filename * that corresponds. */ realFilename(fileName) { return noop; } resolveModuleName(modName, containingFile, runnable) { return noop; } resolveModuleNames(moduleNames, containingFile, reusedNames) { return noop; } useCaseSensitiveFileNames() { return noop; } writeFile(fileName, data) { return noop; } getCanonicalFileName(fileName) { return path_1.resolve(this.getCurrentDirectory(), fileName); } getCurrentDirectory() { return (this.source && this.source.getCurrentDirectory()) || this.cwd; } setSource(source) { if (this.source === null) { this.source = source; } else { throw new Error(`A chainable host can be connected to a source ` + `only once. It looks like you're trying to include the same ` + `instance in multiple chains.`); } } dir() { return []; } dirTrace() { const dflag = exports.debugChainableHosts || exports.debugDir; if (!dflag) return; // tslint:disable-next-line:no-this-assignment let s = this; while (true) { const objname = typeName(s) + s._id; utils_1.trace(dflag, `\nFiles in ${objname}:`); for (const f of s.dir()) { utils_1.trace(dflag, ` ${f}`); } if (!s.source) break; s = s.source; } } canonicalizeFunc(funcName, argNo) { const origFunc = this[funcName]; this[funcName] = function (...args) { args[argNo] = path_1.resolve(this.getCurrentDirectory(), args[argNo]); return origFunc.apply(this, args); }; } } tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Boolean) ], ChainableHost.prototype, "directoryExists", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Boolean) ], ChainableHost.prototype, "fileExists", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", Object) ], ChainableHost.prototype, "getCancellationToken", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", String) ], ChainableHost.prototype, "getDefaultLibFileName", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Array) ], ChainableHost.prototype, "getDirectories", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", String) ], ChainableHost.prototype, "getFileVersion", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", String) ], ChainableHost.prototype, "getNewLine", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, Number, Function]), tslib_1.__metadata("design:returntype", Object) ], ChainableHost.prototype, "getSourceFile", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Object) ], ChainableHost.prototype, "readFile", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", Object) ], ChainableHost.prototype, "realFilename", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, String, Boolean]), tslib_1.__metadata("design:returntype", Object) ], ChainableHost.prototype, "resolveModuleName", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Array, String, Array]), tslib_1.__metadata("design:returntype", Array) ], ChainableHost.prototype, "resolveModuleNames", null); tslib_1.__decorate([ callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", Boolean) ], ChainableHost.prototype, "useCaseSensitiveFileNames", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), callSource, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, String]), tslib_1.__metadata("design:returntype", void 0) ], ChainableHost.prototype, "writeFile", null); exports.ChainableHost = ChainableHost; class HostFinal extends ChainableHost { fileExists() { return false; } directoryExists() { return false; } getFileVersion() { return undefined; } getSourceFile() { return undefined; } useCaseSensitiveFileNames() { return true; } getNewLine() { return "\n"; } getDefaultLibFileName() { return "lib.d.ts"; } resolveModuleName() { return { resolvedFileName: undefined }; } getDirectories() { return []; } readFile() { return undefined; } getCancellationToken() { return null; } resolveModuleNames(moduleNames, containingFile) { return moduleNames.map((modName) => { return this.resolveModuleName(); }); } realFilename() { return undefined; } writeFile() { throw new Error(`Base Compiler host is not writable`); } dir() { return []; } } exports.HostFinal = HostFinal; class FileSystemHost extends ChainableHost { constructor(rootDir, cwd = process.cwd()) { super(cwd); this.rootDir = rootDir; this.rootDir = fs.realpathSync(rootDir); } readDirectory(path, extensions, excludes, includes, depth) { if (!this.allowed(path)) return []; return tsmod().sys.readDirectory(path, extensions, excludes, includes, depth); } getDirectories(fileName) { if (!this.allowed(fileName)) return []; return tsmod().sys.getDirectories(fileName); } directoryExists(path) { if (!this.allowed(path)) return false; return tsmod().sys.directoryExists(path); } readFile(path, encoding) { if (!this.allowed(path)) return undefined; const contents = fs.readFileSync(path, encoding); if (contents) return contents.toString(); return undefined; } getFileVersion(fileName) { try { const stats = fs.statSync(fileName); return stats.mtimeMs.toString(); } catch (err) { return this.source.getFileVersion(fileName); } } fileExists(path) { return this.allowed(path) && tsmod().sys.fileExists(path); } realFilename(fileName) { return fileName; } writeFile() { throw new Error(`FileSystemHost is not writable`); } dir() { // We don't really want to list the whole filesystem. return [`File system at ${this.rootDir}`]; } allowed(path) { try { const resolved = fs.realpathSync(path); return resolved.startsWith(this.rootDir); } catch (err) { if (err.code && err.code === "ENOENT") { return false; } throw err; } } } tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, String]), tslib_1.__metadata("design:returntype", void 0) ], FileSystemHost.prototype, "readFile", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], FileSystemHost.prototype, "getFileVersion", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], FileSystemHost.prototype, "fileExists", null); exports.FileSystemHost = FileSystemHost; // Pretends files are on disk for the TS Language Services API class MemoryHost extends ChainableHost { constructor(rootDir, cwd = process.cwd()) { super(cwd); this.files = new Map(); this.dirs = new Map(); this.mkdirs(rootDir); this.mkdirs(cwd); } writeFile(path, data) { let f = this.files.get(path); if (f !== undefined) { f.version++; f.contents = data; } else { f = { version: 1, contents: data }; this.files.set(path, f); // Set up directory const dir = path_1.dirname(path); this.mkdirs(dir); const dirSet = this.dirs.get(dir); if (!dirSet) throw new error_1.InternalError(`dir not found`); dirSet.add(path); } } readFile(path, encoding) { const f = this.files.get(path); if (f !== undefined) { return f.contents; } return this.source.readFile(path); } getFileVersion(fileName) { const f = this.files.get(fileName); if (f !== undefined) { return f.version.toString(); } return this.source.getFileVersion(fileName); } fileExists(path) { return (this.files.has(path) || super.fileExists(path)); } directoryExists(directoryName) { return this.dirs.has(directoryName) || this.source.directoryExists(directoryName); } getDirectories(path) { const pdirs = this.source.getDirectories(path); if (!path.endsWith(path_1.sep)) { path += path_1.sep; } // Yes this is crappy, but this operation is very infrequent. // regex is anything that matches path in the beginning and only // has one more slash (added above) const re = new RegExp(`^${path}[^/]+$`); for (const d of this.dirs.keys()) { if (re.test(d)) pdirs.push(d); } return pdirs; } dir() { return Array.from(this.files.keys()); } mkdirs(dir) { while (true) { if (!this.dirs.get(dir)) { this.dirs.set(dir, new Set()); } const parent = path_1.dirname(dir); if (parent === dir) { break; } dir = parent; } } } tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "writeFile", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "readFile", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "getFileVersion", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "fileExists", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "directoryExists", null); tslib_1.__decorate([ utils_1.tracef(exports.debugChainableHosts), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String]), tslib_1.__metadata("design:returntype", void 0) ], MemoryHost.prototype, "getDirectories", null); exports.MemoryHost = MemoryHost; function chainHosts(...hosts) { if (hosts.length < 2) throw new Error(`Must chain at least two hosts`); for (let i = 1; i < hosts.length; i++) { hosts[i - 1].setSource(hosts[i]); } return hosts[0]; } exports.chainHosts = chainHosts; function MemFileHost(rootDir, cwd = process.cwd()) { return chainHosts(new MemoryHost(rootDir, cwd), new FileSystemHost(rootDir, cwd), new HostFinal(cwd)); } exports.MemFileHost = MemFileHost; //# sourceMappingURL=hosts.js.map