@adpt/core
Version:
AdaptJS core library
444 lines • 16.6 kB
JavaScript
;
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