mirror of
https://github.com/ezolenko/rollup-plugin-typescript2.git
synced 2025-12-08 19:06:16 +00:00
commit
0a13321fc6
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "./node_modules/typescript/lib"
|
||||
"editor.tabSize": 4,
|
||||
"editor.useTabStops": true
|
||||
}
|
||||
26
README.md
26
README.md
@ -6,7 +6,7 @@ Rollup plugin for typescript with compiler errors.
|
||||
|
||||
This is a rewrite of original rollup-plugin-typescript, starting and borrowing from [this fork](https://github.com/alexlur/rollup-plugin-typescript).
|
||||
|
||||
This version is significantly slower than original, but it will print out typescript errors and warnings.
|
||||
This version is somewhat slower than original, but it will print out typescript syntactic and semantic diagnostic messages (the main reason for using typescript after all).
|
||||
|
||||
## Usage
|
||||
|
||||
@ -15,11 +15,11 @@ This version is significantly slower than original, but it will print out typesc
|
||||
import typescript from 'rollup-plugin-typescript';
|
||||
|
||||
export default {
|
||||
entry: './main.ts',
|
||||
entry: './main.ts',
|
||||
|
||||
plugins: [
|
||||
typescript()
|
||||
]
|
||||
plugins: [
|
||||
typescript()
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@ -32,7 +32,19 @@ Following compiler options are forced though:
|
||||
* `importHelpers`: true
|
||||
* `noResolve`: false
|
||||
|
||||
Plugin itself takes standard include/exclude options (each a minimatch pattern, or array of minimatch patterns), which determine which files are transpiled by Typescript (all `.ts` and `.tsx` files by default)
|
||||
Plugin takes following options:
|
||||
* `check`: true
|
||||
- set to false to avoid doing any diagnostic checks on the code
|
||||
* `verbosity`: 2
|
||||
- goes up to 3
|
||||
* `clean`: false
|
||||
- set to true for clean build (wipes out cache)
|
||||
* `cacheRoot`: ".rts2_cache"
|
||||
- path to cache
|
||||
* `include`: `[ "*.ts+(|x)", "**/*.ts+(|x)" ]`
|
||||
- passes all .ts files through typescript compiler.
|
||||
* `exclude`: `[ "*.d.ts", "**/*.d.ts" ]`
|
||||
- but not types
|
||||
|
||||
### TypeScript version
|
||||
This plugin currently requires TypeScript > 2.0.
|
||||
This plugin currently requires TypeScript 2.0+.
|
||||
|
||||
380
dist/rollup-plugin-typescript2.cjs.js
vendored
380
dist/rollup-plugin-typescript2.cjs.js
vendored
@ -1,11 +1,14 @@
|
||||
/* eslint-disable */
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs-extra');
|
||||
var ts = require('typescript');
|
||||
var rollupPluginutils = require('rollup-pluginutils');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var _ = require('lodash');
|
||||
var graph = require('graphlib');
|
||||
var hash = require('object-hash');
|
||||
var rollupPluginutils = require('rollup-pluginutils');
|
||||
var path = require('path');
|
||||
var colors = require('colors/safe');
|
||||
|
||||
const __assign = Object.assign || function (target) {
|
||||
for (var source, i = 1; i < arguments.length; i++) {
|
||||
@ -19,6 +22,272 @@ const __assign = Object.assign || function (target) {
|
||||
return target;
|
||||
};
|
||||
|
||||
var VerbosityLevel;
|
||||
(function (VerbosityLevel) {
|
||||
VerbosityLevel[VerbosityLevel["Error"] = 0] = "Error";
|
||||
VerbosityLevel[VerbosityLevel["Warning"] = 1] = "Warning";
|
||||
VerbosityLevel[VerbosityLevel["Info"] = 2] = "Info";
|
||||
VerbosityLevel[VerbosityLevel["Debug"] = 3] = "Debug";
|
||||
})(VerbosityLevel || (VerbosityLevel = {}));
|
||||
var ConsoleContext = (function () {
|
||||
function ConsoleContext(verbosity, prefix) {
|
||||
if (prefix === void 0) { prefix = ""; }
|
||||
this.verbosity = verbosity;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
ConsoleContext.prototype.warn = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Warning)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.error = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Error)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.info = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Info)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.debug = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Debug)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
return ConsoleContext;
|
||||
}());
|
||||
|
||||
var LanguageServiceHost = (function () {
|
||||
function LanguageServiceHost(parsedConfig) {
|
||||
this.parsedConfig = parsedConfig;
|
||||
this.cwd = process.cwd();
|
||||
this.snapshots = {};
|
||||
}
|
||||
LanguageServiceHost.prototype.setSnapshot = function (fileName, data) {
|
||||
var snapshot = ts.ScriptSnapshot.fromString(data);
|
||||
this.snapshots[fileName] = snapshot;
|
||||
return snapshot;
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptSnapshot = function (fileName) {
|
||||
if (_.has(this.snapshots, fileName))
|
||||
return this.snapshots[fileName];
|
||||
if (fs.existsSync(fileName)) {
|
||||
this.snapshots[fileName] = ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName));
|
||||
return this.snapshots[fileName];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
LanguageServiceHost.prototype.getCurrentDirectory = function () {
|
||||
return this.cwd;
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptVersion = function (_fileName) {
|
||||
return "0";
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptFileNames = function () {
|
||||
return this.parsedConfig.fileNames;
|
||||
};
|
||||
LanguageServiceHost.prototype.getCompilationSettings = function () {
|
||||
return this.parsedConfig.options;
|
||||
};
|
||||
LanguageServiceHost.prototype.getDefaultLibFileName = function (opts) {
|
||||
return ts.getDefaultLibFilePath(opts);
|
||||
};
|
||||
return LanguageServiceHost;
|
||||
}());
|
||||
|
||||
/**
|
||||
* Saves data in new cache folder or reads it from old one.
|
||||
* Avoids perpetually growing cache and situations when things need to consider changed and then reverted data to be changed.
|
||||
*/
|
||||
var RollingCache = (function () {
|
||||
/**
|
||||
* @param cacheRoot: root folder for the cache
|
||||
* @param checkNewCache: whether to also look in new cache when reading from cache
|
||||
*/
|
||||
function RollingCache(cacheRoot, checkNewCache) {
|
||||
this.cacheRoot = cacheRoot;
|
||||
this.checkNewCache = checkNewCache;
|
||||
this.oldCacheRoot = this.cacheRoot + "/cache";
|
||||
this.newCacheRoot = this.cacheRoot + "/cache_";
|
||||
fs.emptyDirSync(this.newCacheRoot);
|
||||
}
|
||||
/**
|
||||
* @returns true if name exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
RollingCache.prototype.exists = function (name) {
|
||||
if (this.checkNewCache && fs.existsSync(this.newCacheRoot + "/" + name))
|
||||
return true;
|
||||
return fs.existsSync(this.oldCacheRoot + "/" + name);
|
||||
};
|
||||
/**
|
||||
* @returns true if old cache contains all names and nothing more
|
||||
*/
|
||||
RollingCache.prototype.match = function (names) {
|
||||
if (!fs.existsSync(this.oldCacheRoot))
|
||||
return names.length === 0; // empty folder matches
|
||||
return _.isEqual(fs.readdirSync(this.oldCacheRoot).sort(), names.sort());
|
||||
};
|
||||
/**
|
||||
* @returns data for name, must exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
RollingCache.prototype.read = function (name) {
|
||||
if (this.checkNewCache && fs.existsSync(this.newCacheRoot + "/" + name))
|
||||
return fs.readJsonSync(this.newCacheRoot + "/" + name, "utf8");
|
||||
return fs.readJsonSync(this.oldCacheRoot + "/" + name, "utf8");
|
||||
};
|
||||
RollingCache.prototype.write = function (name, data) {
|
||||
if (data === undefined)
|
||||
return;
|
||||
if (this.checkNewCache)
|
||||
fs.writeJsonSync(this.newCacheRoot + "/" + name, data);
|
||||
else
|
||||
fs.writeJson(this.newCacheRoot + "/" + name, data, { encoding: "utf8" }, function () { });
|
||||
};
|
||||
RollingCache.prototype.touch = function (name) {
|
||||
if (this.checkNewCache)
|
||||
fs.ensureFileSync(this.newCacheRoot + "/" + name);
|
||||
else
|
||||
fs.ensureFile(this.newCacheRoot + "/" + name, function () { });
|
||||
};
|
||||
/**
|
||||
* clears old cache and moves new in its place
|
||||
*/
|
||||
RollingCache.prototype.roll = function () {
|
||||
var _this = this;
|
||||
fs.remove(this.oldCacheRoot, function () {
|
||||
fs.move(_this.newCacheRoot, _this.oldCacheRoot, function () { });
|
||||
});
|
||||
};
|
||||
return RollingCache;
|
||||
}());
|
||||
|
||||
var Cache = (function () {
|
||||
function Cache(host, cache, options, rootFilenames, context) {
|
||||
var _this = this;
|
||||
this.host = host;
|
||||
this.options = options;
|
||||
this.context = context;
|
||||
this.cacheVersion = "1";
|
||||
this.ambientTypesDirty = false;
|
||||
this.cacheDir = cache + "/" + hash.sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
|
||||
this.ambientTypes = _.filter(rootFilenames, function (file) { return _.endsWith(file, ".d.ts"); })
|
||||
.map(function (id) { return { id: id, snapshot: _this.host.getScriptSnapshot(id) }; });
|
||||
this.init();
|
||||
}
|
||||
Cache.prototype.clean = function () {
|
||||
this.context.info("cleaning cache: " + this.cacheDir);
|
||||
fs.emptyDirSync(this.cacheDir);
|
||||
this.init();
|
||||
};
|
||||
Cache.prototype.walkTree = function (cb) {
|
||||
var acyclic = graph.alg.isAcyclic(this.dependencyTree);
|
||||
if (acyclic) {
|
||||
_.each(graph.alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
return;
|
||||
}
|
||||
this.context.info("import tree has cycles");
|
||||
_.each(this.dependencyTree.nodes(), function (id) { return cb(id); });
|
||||
};
|
||||
Cache.prototype.setDependency = function (importee, importer) {
|
||||
// importee -> importer
|
||||
this.context.debug(importee + " -> " + importer);
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
};
|
||||
Cache.prototype.compileDone = function () {
|
||||
var _this = this;
|
||||
var typeNames = _.filter(this.ambientTypes, function (snaphot) { return snaphot.snapshot !== undefined; })
|
||||
.map(function (snaphot) { return _this.makeName(snaphot.id, snaphot.snapshot); });
|
||||
// types dirty if any d.ts changed, added or removed
|
||||
this.ambientTypesDirty = !this.typesCache.match(typeNames);
|
||||
if (this.ambientTypesDirty)
|
||||
this.context.info("ambient types changed, redoing all diagnostics");
|
||||
_.each(typeNames, function (name) { return _this.typesCache.touch(name); });
|
||||
};
|
||||
Cache.prototype.diagnosticsDone = function () {
|
||||
this.codeCache.roll();
|
||||
this.diagnosticsCache.roll();
|
||||
this.typesCache.roll();
|
||||
};
|
||||
Cache.prototype.getCompiled = function (id, snapshot, transform) {
|
||||
var name = this.makeName(id, snapshot);
|
||||
if (!this.codeCache.exists(name) || this.isDirty(id, snapshot, false)) {
|
||||
this.context.debug("fresh transpile for: " + id);
|
||||
var data_1 = transform();
|
||||
this.codeCache.write(name, data_1);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data_1;
|
||||
}
|
||||
this.context.debug("old transpile for: " + id);
|
||||
var data = this.codeCache.read(name);
|
||||
this.codeCache.write(name, data);
|
||||
return data;
|
||||
};
|
||||
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
|
||||
var name = this.makeName(id, snapshot);
|
||||
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true)) {
|
||||
this.context.debug("fresh diagnostics for: " + id);
|
||||
var data_2 = this.convert(check());
|
||||
this.diagnosticsCache.write(name, data_2);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data_2;
|
||||
}
|
||||
this.context.debug("old diagnostics for: " + id);
|
||||
var data = this.diagnosticsCache.read(name);
|
||||
this.diagnosticsCache.write(name, data);
|
||||
return data;
|
||||
};
|
||||
Cache.prototype.init = function () {
|
||||
this.codeCache = new RollingCache(this.cacheDir + "/code", true);
|
||||
this.typesCache = new RollingCache(this.cacheDir + "/types", false);
|
||||
this.diagnosticsCache = new RollingCache(this.cacheDir + "/diagnostics", false);
|
||||
};
|
||||
Cache.prototype.markAsDirty = function (id, _snapshot) {
|
||||
this.context.debug("changed: " + id);
|
||||
this.dependencyTree.setNode(id, { dirty: true });
|
||||
};
|
||||
// returns true if node or any of its imports or any of global types changed
|
||||
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
|
||||
var _this = this;
|
||||
var label = this.dependencyTree.node(id);
|
||||
if (!label)
|
||||
return false;
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
if (this.ambientTypesDirty)
|
||||
return true;
|
||||
var dependencies = graph.alg.dijkstra(this.dependencyTree, id);
|
||||
return _.some(dependencies, function (dependency, node) {
|
||||
if (!node || dependency.distance === Infinity)
|
||||
return false;
|
||||
var l = _this.dependencyTree.node(node);
|
||||
var dirty = l === undefined ? true : l.dirty;
|
||||
if (dirty)
|
||||
_this.context.debug("import changed: " + id + " -> " + node);
|
||||
return dirty;
|
||||
});
|
||||
};
|
||||
Cache.prototype.makeName = function (id, snapshot) {
|
||||
var data = snapshot.getText(0, snapshot.getLength());
|
||||
return hash.sha1({ data: data, id: id });
|
||||
};
|
||||
Cache.prototype.convert = function (data) {
|
||||
return _.map(data, function (diagnostic) {
|
||||
var entry = {
|
||||
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
|
||||
};
|
||||
if (diagnostic.file) {
|
||||
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
|
||||
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function getOptionsOverrides() {
|
||||
return {
|
||||
module: ts.ModuleKind.ES2015,
|
||||
@ -33,17 +302,15 @@ function getOptionsOverrides() {
|
||||
// MIT Licenced
|
||||
function findFile(cwd, filename) {
|
||||
var fp = cwd ? (cwd + "/" + filename) : filename;
|
||||
if (fs.existsSync(fp)) {
|
||||
if (fs.existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
var segs = cwd.split(path.sep);
|
||||
var len = segs.length;
|
||||
while (len--) {
|
||||
cwd = segs.slice(0, len).join("/");
|
||||
fp = cwd + "/" + filename;
|
||||
if (fs.existsSync(fp)) {
|
||||
if (fs.existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -61,42 +328,40 @@ catch (e) {
|
||||
}
|
||||
function parseTsConfig() {
|
||||
var fileName = findFile(process.cwd(), "tsconfig.json");
|
||||
if (!fileName)
|
||||
throw new Error("couldn't find 'tsconfig.json' in " + process.cwd());
|
||||
var text = ts.sys.readFile(fileName);
|
||||
var result = ts.parseConfigFileTextToJson(fileName, text);
|
||||
var configParseResult = ts.parseJsonConfigFileContent(result.config, ts.sys, path.dirname(fileName), getOptionsOverrides(), fileName);
|
||||
return configParseResult;
|
||||
}
|
||||
function printDiagnostics(context, diagnostics) {
|
||||
diagnostics.forEach(function (diagnostic) {
|
||||
var message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||
if (diagnostic.file) {
|
||||
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
|
||||
context.warn({ message: diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message });
|
||||
}
|
||||
_.each(diagnostics, function (diagnostic) {
|
||||
if (diagnostic.fileLine)
|
||||
context.warn(diagnostic.fileLine + ": " + colors.yellow(diagnostic.flatMessage));
|
||||
else
|
||||
context.warn({ message: message });
|
||||
context.warn(colors.yellow(diagnostic.flatMessage));
|
||||
});
|
||||
}
|
||||
|
||||
function typescript(options) {
|
||||
options = __assign({}, options);
|
||||
var filter = rollupPluginutils.createFilter(options.include || ["*.ts+(|x)", "**/*.ts+(|x)"], options.exclude || ["*.d.ts", "**/*.d.ts"]);
|
||||
delete options.include;
|
||||
delete options.exclude;
|
||||
_.defaults(options, {
|
||||
check: true,
|
||||
verbosity: VerbosityLevel.Info,
|
||||
clean: false,
|
||||
cacheRoot: process.cwd() + "/.rts2_cache",
|
||||
include: ["*.ts+(|x)", "**/*.ts+(|x)"],
|
||||
exclude: ["*.d.ts", "**/*.d.ts"],
|
||||
});
|
||||
var filter$$1 = rollupPluginutils.createFilter(options.include, options.exclude);
|
||||
var parsedConfig = parseTsConfig();
|
||||
var servicesHost = {
|
||||
getScriptFileNames: function () { return parsedConfig.fileNames; },
|
||||
getScriptVersion: function (_fileName) { return "0"; },
|
||||
getScriptSnapshot: function (fileName) {
|
||||
if (!fs.existsSync(fileName))
|
||||
return undefined;
|
||||
return ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName));
|
||||
},
|
||||
getCurrentDirectory: function () { return process.cwd(); },
|
||||
getCompilationSettings: function () { return parsedConfig.options; },
|
||||
getDefaultLibFileName: function (opts) { return ts.getDefaultLibFilePath(opts); },
|
||||
};
|
||||
var servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
var services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
|
||||
var context = new ConsoleContext(options.verbosity, "rollup-plugin-typescript2: ");
|
||||
var cache = new Cache(servicesHost, options.cacheRoot, parsedConfig.options, parsedConfig.fileNames, context);
|
||||
if (options.clean)
|
||||
cache.clean();
|
||||
return {
|
||||
resolveId: function (importee, importer) {
|
||||
if (importee === TSLIB)
|
||||
@ -106,6 +371,8 @@ function typescript(options) {
|
||||
importer = importer.split("\\").join("/");
|
||||
var result = ts.nodeModuleNameResolver(importee, importer, parsedConfig.options, ts.sys);
|
||||
if (result.resolvedModule && result.resolvedModule.resolvedFileName) {
|
||||
if (filter$$1(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
if (_.endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
return result.resolvedModule.resolvedFileName;
|
||||
@ -115,24 +382,45 @@ function typescript(options) {
|
||||
load: function (id) {
|
||||
if (id === "\0" + TSLIB)
|
||||
return tslibSource;
|
||||
return undefined;
|
||||
},
|
||||
transform: function (_code, id) {
|
||||
if (!filter(id))
|
||||
return null;
|
||||
var output = services.getEmitOutput(id);
|
||||
var allDiagnostics = services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
printDiagnostics(this, allDiagnostics);
|
||||
if (output.emitSkipped)
|
||||
this.error({ message: "failed to transpile " + id });
|
||||
var code = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".js"); });
|
||||
var map = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: code ? code.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
};
|
||||
transform: function (code, id) {
|
||||
var _this = this;
|
||||
if (!filter$$1(id))
|
||||
return undefined;
|
||||
var snapshot = servicesHost.setSnapshot(id, code);
|
||||
var result = cache.getCompiled(id, snapshot, function () {
|
||||
var output = services.getEmitOutput(id);
|
||||
if (output.emitSkipped)
|
||||
_this.error({ message: colors.red("failed to transpile " + id) });
|
||||
var transpiled = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".js"); });
|
||||
var map$$1 = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
|
||||
};
|
||||
});
|
||||
return result;
|
||||
},
|
||||
outro: function () {
|
||||
cache.compileDone();
|
||||
if (options.check) {
|
||||
cache.walkTree(function (id) {
|
||||
var snapshot = servicesHost.getScriptSnapshot(id);
|
||||
if (!snapshot) {
|
||||
context.error(colors.red("failed lo load snapshot for " + id));
|
||||
return;
|
||||
}
|
||||
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
|
||||
return services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
});
|
||||
printDiagnostics(context, diagnostics);
|
||||
});
|
||||
}
|
||||
cache.diagnosticsDone();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
385
dist/rollup-plugin-typescript2.es.js
vendored
385
dist/rollup-plugin-typescript2.es.js
vendored
@ -1,13 +1,19 @@
|
||||
/* eslint-disable */
|
||||
import { emptyDirSync, ensureFile, ensureFileSync, existsSync, move, readFileSync, readJsonSync, readdirSync, remove, writeJson, writeJsonSync } from 'fs-extra';
|
||||
import * as fs from 'fs-extra';
|
||||
import { ModuleKind, ScriptSnapshot, createDocumentRegistry, createLanguageService, flattenDiagnosticMessageText, getDefaultLibFilePath, nodeModuleNameResolver, parseConfigFileTextToJson, parseJsonConfigFileContent, sys } from 'typescript';
|
||||
import * as ts from 'typescript';
|
||||
import { defaults, each, endsWith, filter, find, has, isEqual, map, some } from 'lodash';
|
||||
import * as _ from 'lodash';
|
||||
import { Graph, alg } from 'graphlib';
|
||||
import * as graph from 'graphlib';
|
||||
import { sha1 } from 'object-hash';
|
||||
import * as hash from 'object-hash';
|
||||
import { createFilter } from 'rollup-pluginutils';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import * as fs from 'fs';
|
||||
import { dirname, sep } from 'path';
|
||||
import * as path from 'path';
|
||||
import { endsWith, find } from 'lodash';
|
||||
import * as _ from 'lodash';
|
||||
import { red, yellow } from 'colors/safe';
|
||||
import * as colors from 'colors/safe';
|
||||
|
||||
const __assign = Object.assign || function (target) {
|
||||
for (var source, i = 1; i < arguments.length; i++) {
|
||||
@ -21,6 +27,272 @@ const __assign = Object.assign || function (target) {
|
||||
return target;
|
||||
};
|
||||
|
||||
var VerbosityLevel;
|
||||
(function (VerbosityLevel) {
|
||||
VerbosityLevel[VerbosityLevel["Error"] = 0] = "Error";
|
||||
VerbosityLevel[VerbosityLevel["Warning"] = 1] = "Warning";
|
||||
VerbosityLevel[VerbosityLevel["Info"] = 2] = "Info";
|
||||
VerbosityLevel[VerbosityLevel["Debug"] = 3] = "Debug";
|
||||
})(VerbosityLevel || (VerbosityLevel = {}));
|
||||
var ConsoleContext = (function () {
|
||||
function ConsoleContext(verbosity, prefix) {
|
||||
if (prefix === void 0) { prefix = ""; }
|
||||
this.verbosity = verbosity;
|
||||
this.prefix = prefix;
|
||||
}
|
||||
ConsoleContext.prototype.warn = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Warning)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.error = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Error)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.info = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Info)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
ConsoleContext.prototype.debug = function (message) {
|
||||
if (this.verbosity < VerbosityLevel.Debug)
|
||||
return;
|
||||
console.log("" + this.prefix + message);
|
||||
};
|
||||
return ConsoleContext;
|
||||
}());
|
||||
|
||||
var LanguageServiceHost = (function () {
|
||||
function LanguageServiceHost(parsedConfig) {
|
||||
this.parsedConfig = parsedConfig;
|
||||
this.cwd = process.cwd();
|
||||
this.snapshots = {};
|
||||
}
|
||||
LanguageServiceHost.prototype.setSnapshot = function (fileName, data) {
|
||||
var snapshot = ScriptSnapshot.fromString(data);
|
||||
this.snapshots[fileName] = snapshot;
|
||||
return snapshot;
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptSnapshot = function (fileName) {
|
||||
if (has(this.snapshots, fileName))
|
||||
return this.snapshots[fileName];
|
||||
if (existsSync(fileName)) {
|
||||
this.snapshots[fileName] = ScriptSnapshot.fromString(sys.readFile(fileName));
|
||||
return this.snapshots[fileName];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
LanguageServiceHost.prototype.getCurrentDirectory = function () {
|
||||
return this.cwd;
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptVersion = function (_fileName) {
|
||||
return "0";
|
||||
};
|
||||
LanguageServiceHost.prototype.getScriptFileNames = function () {
|
||||
return this.parsedConfig.fileNames;
|
||||
};
|
||||
LanguageServiceHost.prototype.getCompilationSettings = function () {
|
||||
return this.parsedConfig.options;
|
||||
};
|
||||
LanguageServiceHost.prototype.getDefaultLibFileName = function (opts) {
|
||||
return getDefaultLibFilePath(opts);
|
||||
};
|
||||
return LanguageServiceHost;
|
||||
}());
|
||||
|
||||
/**
|
||||
* Saves data in new cache folder or reads it from old one.
|
||||
* Avoids perpetually growing cache and situations when things need to consider changed and then reverted data to be changed.
|
||||
*/
|
||||
var RollingCache = (function () {
|
||||
/**
|
||||
* @param cacheRoot: root folder for the cache
|
||||
* @param checkNewCache: whether to also look in new cache when reading from cache
|
||||
*/
|
||||
function RollingCache(cacheRoot, checkNewCache) {
|
||||
this.cacheRoot = cacheRoot;
|
||||
this.checkNewCache = checkNewCache;
|
||||
this.oldCacheRoot = this.cacheRoot + "/cache";
|
||||
this.newCacheRoot = this.cacheRoot + "/cache_";
|
||||
emptyDirSync(this.newCacheRoot);
|
||||
}
|
||||
/**
|
||||
* @returns true if name exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
RollingCache.prototype.exists = function (name) {
|
||||
if (this.checkNewCache && existsSync(this.newCacheRoot + "/" + name))
|
||||
return true;
|
||||
return existsSync(this.oldCacheRoot + "/" + name);
|
||||
};
|
||||
/**
|
||||
* @returns true if old cache contains all names and nothing more
|
||||
*/
|
||||
RollingCache.prototype.match = function (names) {
|
||||
if (!existsSync(this.oldCacheRoot))
|
||||
return names.length === 0; // empty folder matches
|
||||
return isEqual(readdirSync(this.oldCacheRoot).sort(), names.sort());
|
||||
};
|
||||
/**
|
||||
* @returns data for name, must exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
RollingCache.prototype.read = function (name) {
|
||||
if (this.checkNewCache && existsSync(this.newCacheRoot + "/" + name))
|
||||
return readJsonSync(this.newCacheRoot + "/" + name, "utf8");
|
||||
return readJsonSync(this.oldCacheRoot + "/" + name, "utf8");
|
||||
};
|
||||
RollingCache.prototype.write = function (name, data) {
|
||||
if (data === undefined)
|
||||
return;
|
||||
if (this.checkNewCache)
|
||||
writeJsonSync(this.newCacheRoot + "/" + name, data);
|
||||
else
|
||||
writeJson(this.newCacheRoot + "/" + name, data, { encoding: "utf8" }, function () { });
|
||||
};
|
||||
RollingCache.prototype.touch = function (name) {
|
||||
if (this.checkNewCache)
|
||||
ensureFileSync(this.newCacheRoot + "/" + name);
|
||||
else
|
||||
ensureFile(this.newCacheRoot + "/" + name, function () { });
|
||||
};
|
||||
/**
|
||||
* clears old cache and moves new in its place
|
||||
*/
|
||||
RollingCache.prototype.roll = function () {
|
||||
var _this = this;
|
||||
remove(this.oldCacheRoot, function () {
|
||||
move(_this.newCacheRoot, _this.oldCacheRoot, function () { });
|
||||
});
|
||||
};
|
||||
return RollingCache;
|
||||
}());
|
||||
|
||||
var Cache = (function () {
|
||||
function Cache(host, cache, options, rootFilenames, context) {
|
||||
var _this = this;
|
||||
this.host = host;
|
||||
this.options = options;
|
||||
this.context = context;
|
||||
this.cacheVersion = "1";
|
||||
this.ambientTypesDirty = false;
|
||||
this.cacheDir = cache + "/" + sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
|
||||
this.dependencyTree = new Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
|
||||
this.ambientTypes = filter(rootFilenames, function (file) { return endsWith(file, ".d.ts"); })
|
||||
.map(function (id) { return { id: id, snapshot: _this.host.getScriptSnapshot(id) }; });
|
||||
this.init();
|
||||
}
|
||||
Cache.prototype.clean = function () {
|
||||
this.context.info("cleaning cache: " + this.cacheDir);
|
||||
emptyDirSync(this.cacheDir);
|
||||
this.init();
|
||||
};
|
||||
Cache.prototype.walkTree = function (cb) {
|
||||
var acyclic = alg.isAcyclic(this.dependencyTree);
|
||||
if (acyclic) {
|
||||
each(alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
return;
|
||||
}
|
||||
this.context.info("import tree has cycles");
|
||||
each(this.dependencyTree.nodes(), function (id) { return cb(id); });
|
||||
};
|
||||
Cache.prototype.setDependency = function (importee, importer) {
|
||||
// importee -> importer
|
||||
this.context.debug(importee + " -> " + importer);
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
};
|
||||
Cache.prototype.compileDone = function () {
|
||||
var _this = this;
|
||||
var typeNames = filter(this.ambientTypes, function (snaphot) { return snaphot.snapshot !== undefined; })
|
||||
.map(function (snaphot) { return _this.makeName(snaphot.id, snaphot.snapshot); });
|
||||
// types dirty if any d.ts changed, added or removed
|
||||
this.ambientTypesDirty = !this.typesCache.match(typeNames);
|
||||
if (this.ambientTypesDirty)
|
||||
this.context.info("ambient types changed, redoing all diagnostics");
|
||||
each(typeNames, function (name) { return _this.typesCache.touch(name); });
|
||||
};
|
||||
Cache.prototype.diagnosticsDone = function () {
|
||||
this.codeCache.roll();
|
||||
this.diagnosticsCache.roll();
|
||||
this.typesCache.roll();
|
||||
};
|
||||
Cache.prototype.getCompiled = function (id, snapshot, transform) {
|
||||
var name = this.makeName(id, snapshot);
|
||||
if (!this.codeCache.exists(name) || this.isDirty(id, snapshot, false)) {
|
||||
this.context.debug("fresh transpile for: " + id);
|
||||
var data_1 = transform();
|
||||
this.codeCache.write(name, data_1);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data_1;
|
||||
}
|
||||
this.context.debug("old transpile for: " + id);
|
||||
var data = this.codeCache.read(name);
|
||||
this.codeCache.write(name, data);
|
||||
return data;
|
||||
};
|
||||
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
|
||||
var name = this.makeName(id, snapshot);
|
||||
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true)) {
|
||||
this.context.debug("fresh diagnostics for: " + id);
|
||||
var data_2 = this.convert(check());
|
||||
this.diagnosticsCache.write(name, data_2);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data_2;
|
||||
}
|
||||
this.context.debug("old diagnostics for: " + id);
|
||||
var data = this.diagnosticsCache.read(name);
|
||||
this.diagnosticsCache.write(name, data);
|
||||
return data;
|
||||
};
|
||||
Cache.prototype.init = function () {
|
||||
this.codeCache = new RollingCache(this.cacheDir + "/code", true);
|
||||
this.typesCache = new RollingCache(this.cacheDir + "/types", false);
|
||||
this.diagnosticsCache = new RollingCache(this.cacheDir + "/diagnostics", false);
|
||||
};
|
||||
Cache.prototype.markAsDirty = function (id, _snapshot) {
|
||||
this.context.debug("changed: " + id);
|
||||
this.dependencyTree.setNode(id, { dirty: true });
|
||||
};
|
||||
// returns true if node or any of its imports or any of global types changed
|
||||
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
|
||||
var _this = this;
|
||||
var label = this.dependencyTree.node(id);
|
||||
if (!label)
|
||||
return false;
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
if (this.ambientTypesDirty)
|
||||
return true;
|
||||
var dependencies = alg.dijkstra(this.dependencyTree, id);
|
||||
return some(dependencies, function (dependency, node) {
|
||||
if (!node || dependency.distance === Infinity)
|
||||
return false;
|
||||
var l = _this.dependencyTree.node(node);
|
||||
var dirty = l === undefined ? true : l.dirty;
|
||||
if (dirty)
|
||||
_this.context.debug("import changed: " + id + " -> " + node);
|
||||
return dirty;
|
||||
});
|
||||
};
|
||||
Cache.prototype.makeName = function (id, snapshot) {
|
||||
var data = snapshot.getText(0, snapshot.getLength());
|
||||
return sha1({ data: data, id: id });
|
||||
};
|
||||
Cache.prototype.convert = function (data) {
|
||||
return map(data, function (diagnostic) {
|
||||
var entry = {
|
||||
flatMessage: flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
|
||||
};
|
||||
if (diagnostic.file) {
|
||||
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
|
||||
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
|
||||
}
|
||||
return entry;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function getOptionsOverrides() {
|
||||
return {
|
||||
module: ModuleKind.ES2015,
|
||||
@ -35,17 +307,15 @@ function getOptionsOverrides() {
|
||||
// MIT Licenced
|
||||
function findFile(cwd, filename) {
|
||||
var fp = cwd ? (cwd + "/" + filename) : filename;
|
||||
if (existsSync(fp)) {
|
||||
if (existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
var segs = cwd.split(sep);
|
||||
var len = segs.length;
|
||||
while (len--) {
|
||||
cwd = segs.slice(0, len).join("/");
|
||||
fp = cwd + "/" + filename;
|
||||
if (existsSync(fp)) {
|
||||
if (existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -63,42 +333,40 @@ catch (e) {
|
||||
}
|
||||
function parseTsConfig() {
|
||||
var fileName = findFile(process.cwd(), "tsconfig.json");
|
||||
if (!fileName)
|
||||
throw new Error("couldn't find 'tsconfig.json' in " + process.cwd());
|
||||
var text = sys.readFile(fileName);
|
||||
var result = parseConfigFileTextToJson(fileName, text);
|
||||
var configParseResult = parseJsonConfigFileContent(result.config, sys, dirname(fileName), getOptionsOverrides(), fileName);
|
||||
return configParseResult;
|
||||
}
|
||||
function printDiagnostics(context, diagnostics) {
|
||||
diagnostics.forEach(function (diagnostic) {
|
||||
var message = flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||
if (diagnostic.file) {
|
||||
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
|
||||
context.warn({ message: diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message });
|
||||
}
|
||||
each(diagnostics, function (diagnostic) {
|
||||
if (diagnostic.fileLine)
|
||||
context.warn(diagnostic.fileLine + ": " + yellow(diagnostic.flatMessage));
|
||||
else
|
||||
context.warn({ message: message });
|
||||
context.warn(yellow(diagnostic.flatMessage));
|
||||
});
|
||||
}
|
||||
|
||||
function typescript(options) {
|
||||
options = __assign({}, options);
|
||||
var filter = createFilter(options.include || ["*.ts+(|x)", "**/*.ts+(|x)"], options.exclude || ["*.d.ts", "**/*.d.ts"]);
|
||||
delete options.include;
|
||||
delete options.exclude;
|
||||
defaults(options, {
|
||||
check: true,
|
||||
verbosity: VerbosityLevel.Info,
|
||||
clean: false,
|
||||
cacheRoot: process.cwd() + "/.rts2_cache",
|
||||
include: ["*.ts+(|x)", "**/*.ts+(|x)"],
|
||||
exclude: ["*.d.ts", "**/*.d.ts"],
|
||||
});
|
||||
var filter$$1 = createFilter(options.include, options.exclude);
|
||||
var parsedConfig = parseTsConfig();
|
||||
var servicesHost = {
|
||||
getScriptFileNames: function () { return parsedConfig.fileNames; },
|
||||
getScriptVersion: function (_fileName) { return "0"; },
|
||||
getScriptSnapshot: function (fileName) {
|
||||
if (!existsSync(fileName))
|
||||
return undefined;
|
||||
return ScriptSnapshot.fromString(sys.readFile(fileName));
|
||||
},
|
||||
getCurrentDirectory: function () { return process.cwd(); },
|
||||
getCompilationSettings: function () { return parsedConfig.options; },
|
||||
getDefaultLibFileName: function (opts) { return getDefaultLibFilePath(opts); },
|
||||
};
|
||||
var servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
var services = createLanguageService(servicesHost, createDocumentRegistry());
|
||||
var context = new ConsoleContext(options.verbosity, "rollup-plugin-typescript2: ");
|
||||
var cache = new Cache(servicesHost, options.cacheRoot, parsedConfig.options, parsedConfig.fileNames, context);
|
||||
if (options.clean)
|
||||
cache.clean();
|
||||
return {
|
||||
resolveId: function (importee, importer) {
|
||||
if (importee === TSLIB)
|
||||
@ -108,6 +376,8 @@ function typescript(options) {
|
||||
importer = importer.split("\\").join("/");
|
||||
var result = nodeModuleNameResolver(importee, importer, parsedConfig.options, sys);
|
||||
if (result.resolvedModule && result.resolvedModule.resolvedFileName) {
|
||||
if (filter$$1(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
if (endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
return result.resolvedModule.resolvedFileName;
|
||||
@ -117,24 +387,45 @@ function typescript(options) {
|
||||
load: function (id) {
|
||||
if (id === "\0" + TSLIB)
|
||||
return tslibSource;
|
||||
return undefined;
|
||||
},
|
||||
transform: function (_code, id) {
|
||||
if (!filter(id))
|
||||
return null;
|
||||
var output = services.getEmitOutput(id);
|
||||
var allDiagnostics = services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
printDiagnostics(this, allDiagnostics);
|
||||
if (output.emitSkipped)
|
||||
this.error({ message: "failed to transpile " + id });
|
||||
var code = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".js"); });
|
||||
var map = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: code ? code.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
};
|
||||
transform: function (code, id) {
|
||||
var _this = this;
|
||||
if (!filter$$1(id))
|
||||
return undefined;
|
||||
var snapshot = servicesHost.setSnapshot(id, code);
|
||||
var result = cache.getCompiled(id, snapshot, function () {
|
||||
var output = services.getEmitOutput(id);
|
||||
if (output.emitSkipped)
|
||||
_this.error({ message: red("failed to transpile " + id) });
|
||||
var transpiled = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".js"); });
|
||||
var map$$1 = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
|
||||
};
|
||||
});
|
||||
return result;
|
||||
},
|
||||
outro: function () {
|
||||
cache.compileDone();
|
||||
if (options.check) {
|
||||
cache.walkTree(function (id) {
|
||||
var snapshot = servicesHost.getScriptSnapshot(id);
|
||||
if (!snapshot) {
|
||||
context.error(red("failed lo load snapshot for " + id));
|
||||
return;
|
||||
}
|
||||
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
|
||||
return services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
});
|
||||
printDiagnostics(context, diagnostics);
|
||||
});
|
||||
}
|
||||
cache.diagnosticsDone();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
14
package.json
14
package.json
@ -20,21 +20,29 @@
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist/*",
|
||||
"build": "rollup -c",
|
||||
"lint": "tslint -c ./tslint.json src/*.ts",
|
||||
"postinstall": "typings install"
|
||||
"lint": "tslint -c ./tslint.json src/*.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"colors": "^1.1.2",
|
||||
"fs-extra": "^2.0.0",
|
||||
"graphlib": "^2.1.1",
|
||||
"lodash": "^4.17.4",
|
||||
"object-hash": "^1.1.5",
|
||||
"rollup-pluginutils": "^2.0.1",
|
||||
"tslib": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^2.0"
|
||||
"typescript": "^2.0",
|
||||
"tslib": "^1.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alexlur/rollup-plugin-typescript": "^0.8.1",
|
||||
"@types/colors": "^1.1.1",
|
||||
"@types/fs-extra": "0.0.37",
|
||||
"@types/graphlib": "^2.1.3",
|
||||
"@types/lodash": "^4.14.52",
|
||||
"@types/node": "^6.0.53",
|
||||
"@types/object-hash": "^0.5.28",
|
||||
"rimraf": "^2.5.4",
|
||||
"rollup": "^0.41.4",
|
||||
"tslint": "^4.4.2",
|
||||
|
||||
@ -7,11 +7,14 @@ export default {
|
||||
|
||||
external: [
|
||||
'path',
|
||||
'fs',
|
||||
'fs-extra',
|
||||
'object-assign',
|
||||
'rollup-pluginutils',
|
||||
'typescript',
|
||||
'lodash'
|
||||
'lodash',
|
||||
'graphlib',
|
||||
'object-hash',
|
||||
'colors/safe'
|
||||
],
|
||||
|
||||
plugins: [
|
||||
|
||||
219
src/cache.ts
Normal file
219
src/cache.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import { IContext } from "./context";
|
||||
import * as ts from "typescript";
|
||||
import * as graph from "graphlib";
|
||||
import * as hash from "object-hash";
|
||||
import * as _ from "lodash";
|
||||
import { RollingCache } from "./rollingcache";
|
||||
import * as fs from "fs-extra";
|
||||
|
||||
export interface ICode
|
||||
{
|
||||
code: string | undefined;
|
||||
map: string | undefined;
|
||||
}
|
||||
|
||||
interface INodeLabel
|
||||
{
|
||||
dirty: boolean;
|
||||
}
|
||||
|
||||
export interface IDiagnostics
|
||||
{
|
||||
flatMessage: string;
|
||||
fileLine?: string;
|
||||
}
|
||||
|
||||
interface ITypeSnapshot
|
||||
{
|
||||
id: string;
|
||||
snapshot: ts.IScriptSnapshot | undefined;
|
||||
}
|
||||
|
||||
export class Cache
|
||||
{
|
||||
private cacheVersion = "1";
|
||||
private dependencyTree: graph.Graph;
|
||||
private ambientTypes: ITypeSnapshot[];
|
||||
private ambientTypesDirty = false;
|
||||
private cacheDir: string;
|
||||
private codeCache: RollingCache<ICode | undefined>;
|
||||
private typesCache: RollingCache<string>;
|
||||
private diagnosticsCache: RollingCache<IDiagnostics[]>;
|
||||
|
||||
constructor(private host: ts.LanguageServiceHost, cache: string, private options: ts.CompilerOptions, rootFilenames: string[], private context: IContext)
|
||||
{
|
||||
this.cacheDir = `${cache}/${hash.sha1({ version: this.cacheVersion, rootFilenames, options: this.options })}`;
|
||||
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel((_node: string) => { return { dirty: false }; });
|
||||
|
||||
this.ambientTypes = _
|
||||
.filter(rootFilenames, (file) => _.endsWith(file, ".d.ts"))
|
||||
.map((id) => { return { id, snapshot: this.host.getScriptSnapshot(id) }; });
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
public clean()
|
||||
{
|
||||
this.context.info(`cleaning cache: ${this.cacheDir}`);
|
||||
fs.emptyDirSync(this.cacheDir);
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
public walkTree(cb: (id: string) => void | false): void
|
||||
{
|
||||
const acyclic = graph.alg.isAcyclic(this.dependencyTree);
|
||||
|
||||
if (acyclic)
|
||||
{
|
||||
_.each(graph.alg.topsort(this.dependencyTree), (id: string) => cb(id));
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.info("import tree has cycles");
|
||||
|
||||
_.each(this.dependencyTree.nodes(), (id: string) => cb(id));
|
||||
}
|
||||
|
||||
public setDependency(importee: string, importer: string): void
|
||||
{
|
||||
// importee -> importer
|
||||
this.context.debug(`${importee} -> ${importer}`);
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
}
|
||||
|
||||
public compileDone(): void
|
||||
{
|
||||
let typeNames = _
|
||||
.filter(this.ambientTypes, (snaphot) => snaphot.snapshot !== undefined)
|
||||
.map((snaphot) => this.makeName(snaphot.id, snaphot.snapshot!));
|
||||
|
||||
// types dirty if any d.ts changed, added or removed
|
||||
this.ambientTypesDirty = !this.typesCache.match(typeNames);
|
||||
|
||||
if (this.ambientTypesDirty)
|
||||
this.context.info("ambient types changed, redoing all diagnostics");
|
||||
|
||||
_.each(typeNames, (name) => this.typesCache.touch(name));
|
||||
}
|
||||
|
||||
public diagnosticsDone()
|
||||
{
|
||||
this.codeCache.roll();
|
||||
this.diagnosticsCache.roll();
|
||||
this.typesCache.roll();
|
||||
}
|
||||
|
||||
public getCompiled(id: string, snapshot: ts.IScriptSnapshot, transform: () => ICode | undefined): ICode | undefined
|
||||
{
|
||||
let name = this.makeName(id, snapshot);
|
||||
|
||||
if (!this.codeCache.exists(name) || this.isDirty(id, snapshot, false))
|
||||
{
|
||||
this.context.debug(`fresh transpile for: ${id}`);
|
||||
|
||||
let data = transform();
|
||||
this.codeCache.write(name, data);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data;
|
||||
}
|
||||
|
||||
this.context.debug(`old transpile for: ${id}`);
|
||||
|
||||
let data = this.codeCache.read(name);
|
||||
this.codeCache.write(name, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public getDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
|
||||
{
|
||||
let name = this.makeName(id, snapshot);
|
||||
|
||||
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true))
|
||||
{
|
||||
this.context.debug(`fresh diagnostics for: ${id}`);
|
||||
|
||||
let data = this.convert(check());
|
||||
this.diagnosticsCache.write(name, data);
|
||||
this.markAsDirty(id, snapshot);
|
||||
return data;
|
||||
}
|
||||
|
||||
this.context.debug(`old diagnostics for: ${id}`);
|
||||
|
||||
let data = this.diagnosticsCache.read(name);
|
||||
this.diagnosticsCache.write(name, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private init()
|
||||
{
|
||||
this.codeCache = new RollingCache<ICode>(`${this.cacheDir}/code`, true);
|
||||
this.typesCache = new RollingCache<string>(`${this.cacheDir}/types`, false);
|
||||
this.diagnosticsCache = new RollingCache<IDiagnostics[]>(`${this.cacheDir}/diagnostics`, false);
|
||||
}
|
||||
|
||||
private markAsDirty(id: string, _snapshot: ts.IScriptSnapshot): void
|
||||
{
|
||||
this.context.debug(`changed: ${id}`);
|
||||
this.dependencyTree.setNode(id, { dirty: true });
|
||||
}
|
||||
|
||||
// returns true if node or any of its imports or any of global types changed
|
||||
private isDirty(id: string, _snapshot: ts.IScriptSnapshot, checkImports: boolean): boolean
|
||||
{
|
||||
let label = this.dependencyTree.node(id) as INodeLabel;
|
||||
|
||||
if (!label)
|
||||
return false;
|
||||
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
|
||||
if (this.ambientTypesDirty)
|
||||
return true;
|
||||
|
||||
let dependencies = graph.alg.dijkstra(this.dependencyTree, id);
|
||||
|
||||
return _.some(dependencies, (dependency, node) =>
|
||||
{
|
||||
if (!node || dependency.distance === Infinity)
|
||||
return false;
|
||||
|
||||
let l = this.dependencyTree.node(node) as INodeLabel | undefined;
|
||||
let dirty = l === undefined ? true : l.dirty;
|
||||
|
||||
if (dirty)
|
||||
this.context.debug(`import changed: ${id} -> ${node}`);
|
||||
|
||||
return dirty;
|
||||
});
|
||||
}
|
||||
|
||||
private makeName(id: string, snapshot: ts.IScriptSnapshot)
|
||||
{
|
||||
let data = snapshot.getText(0, snapshot.getLength());
|
||||
return hash.sha1({ data, id });
|
||||
}
|
||||
|
||||
private convert(data: ts.Diagnostic[]): IDiagnostics[]
|
||||
{
|
||||
return _.map(data, (diagnostic) =>
|
||||
{
|
||||
let entry: IDiagnostics =
|
||||
{
|
||||
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
|
||||
};
|
||||
|
||||
if (diagnostic.file)
|
||||
{
|
||||
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
entry.fileLine = `${diagnostic.file.fileName} (${line + 1},${character + 1})`;
|
||||
}
|
||||
|
||||
return entry;
|
||||
});
|
||||
}
|
||||
}
|
||||
61
src/context.ts
Normal file
61
src/context.ts
Normal file
@ -0,0 +1,61 @@
|
||||
interface Message
|
||||
{
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IRollupContext
|
||||
{
|
||||
warn(message: Message | string): void;
|
||||
error(message: Message | string): void;
|
||||
}
|
||||
|
||||
export interface IContext
|
||||
{
|
||||
warn(message: string): void;
|
||||
error(message: string): void;
|
||||
info(message: string): void;
|
||||
debug(message: string): void;
|
||||
}
|
||||
|
||||
export enum VerbosityLevel
|
||||
{
|
||||
Error = 0,
|
||||
Warning,
|
||||
Info,
|
||||
Debug,
|
||||
}
|
||||
|
||||
export class ConsoleContext implements IContext
|
||||
{
|
||||
constructor(private verbosity: VerbosityLevel, private prefix: string = "")
|
||||
{
|
||||
}
|
||||
|
||||
public warn(message: string): void
|
||||
{
|
||||
if (this.verbosity < VerbosityLevel.Warning)
|
||||
return;
|
||||
console.log(`${this.prefix}${message}`);
|
||||
}
|
||||
|
||||
public error(message: string): void
|
||||
{
|
||||
if (this.verbosity < VerbosityLevel.Error)
|
||||
return;
|
||||
console.log(`${this.prefix}${message}`);
|
||||
}
|
||||
|
||||
public info(message: string): void
|
||||
{
|
||||
if (this.verbosity < VerbosityLevel.Info)
|
||||
return;
|
||||
console.log(`${this.prefix}${message}`);
|
||||
}
|
||||
|
||||
public debug(message: string): void
|
||||
{
|
||||
if (this.verbosity < VerbosityLevel.Debug)
|
||||
return;
|
||||
console.log(`${this.prefix}${message}`);
|
||||
}
|
||||
}
|
||||
59
src/host.ts
Normal file
59
src/host.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import * as fs from "fs-extra";
|
||||
import * as ts from "typescript";
|
||||
import * as _ from "lodash";
|
||||
|
||||
export class LanguageServiceHost implements ts.LanguageServiceHost
|
||||
{
|
||||
private cwd = process.cwd();
|
||||
private snapshots: { [fileName: string]: ts.IScriptSnapshot } = {};
|
||||
|
||||
constructor(private parsedConfig: ts.ParsedCommandLine)
|
||||
{
|
||||
}
|
||||
|
||||
public setSnapshot(fileName: string, data: string): ts.IScriptSnapshot
|
||||
{
|
||||
let snapshot = ts.ScriptSnapshot.fromString(data);
|
||||
this.snapshots[fileName] = snapshot;
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
public getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined
|
||||
{
|
||||
if (_.has(this.snapshots, fileName))
|
||||
return this.snapshots[fileName];
|
||||
|
||||
if (fs.existsSync(fileName))
|
||||
{
|
||||
this.snapshots[fileName] = ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName));
|
||||
return this.snapshots[fileName];
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getCurrentDirectory()
|
||||
{
|
||||
return this.cwd;
|
||||
}
|
||||
|
||||
public getScriptVersion(_fileName: string)
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
|
||||
public getScriptFileNames()
|
||||
{
|
||||
return this.parsedConfig.fileNames;
|
||||
}
|
||||
|
||||
public getCompilationSettings(): ts.CompilerOptions
|
||||
{
|
||||
return this.parsedConfig.options;
|
||||
}
|
||||
|
||||
public getDefaultLibFileName(opts: ts.CompilerOptions)
|
||||
{
|
||||
return ts.getDefaultLibFilePath(opts);
|
||||
}
|
||||
}
|
||||
158
src/index.ts
158
src/index.ts
@ -1,9 +1,12 @@
|
||||
import { IContext, ConsoleContext, IRollupContext, VerbosityLevel } from "./context";
|
||||
import { LanguageServiceHost } from "./host";
|
||||
import { Cache, ICode, IDiagnostics } from "./cache";
|
||||
import * as ts from "typescript";
|
||||
import { createFilter } from "rollup-pluginutils";
|
||||
import * as fs from "fs";
|
||||
import * as fs from "fs-extra";
|
||||
import * as path from "path";
|
||||
import { existsSync } from "fs";
|
||||
import * as _ from "lodash";
|
||||
import * as colors from "colors/safe";
|
||||
|
||||
function getOptionsOverrides(): ts.CompilerOptions
|
||||
{
|
||||
@ -23,10 +26,8 @@ function findFile(cwd: string, filename: string)
|
||||
{
|
||||
let fp = cwd ? (cwd + "/" + filename) : filename;
|
||||
|
||||
if (existsSync(fp))
|
||||
{
|
||||
if (fs.existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
|
||||
const segs = cwd.split(path.sep);
|
||||
let len = segs.length;
|
||||
@ -35,10 +36,8 @@ function findFile(cwd: string, filename: string)
|
||||
{
|
||||
cwd = segs.slice(0, len).join("/");
|
||||
fp = cwd + "/" + filename;
|
||||
if (existsSync(fp))
|
||||
{
|
||||
if (fs.existsSync(fp))
|
||||
return fp;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -61,6 +60,9 @@ try
|
||||
function parseTsConfig()
|
||||
{
|
||||
const fileName = findFile(process.cwd(), "tsconfig.json");
|
||||
if (!fileName)
|
||||
throw new Error(`couldn't find 'tsconfig.json' in ${process.cwd()}`);
|
||||
|
||||
const text = ts.sys.readFile(fileName);
|
||||
const result = ts.parseConfigFileTextToJson(fileName, text);
|
||||
const configParseResult = ts.parseJsonConfigFileContent(result.config, ts.sys, path.dirname(fileName), getOptionsOverrides(), fileName);
|
||||
@ -68,58 +70,56 @@ function parseTsConfig()
|
||||
return configParseResult;
|
||||
}
|
||||
|
||||
interface Message
|
||||
function printDiagnostics(context: IContext, diagnostics: IDiagnostics[])
|
||||
{
|
||||
message: string;
|
||||
}
|
||||
interface Context
|
||||
{
|
||||
warn(message: Message): void;
|
||||
error(message: Message): void;
|
||||
}
|
||||
function printDiagnostics(context: Context, diagnostics: ts.Diagnostic[])
|
||||
{
|
||||
diagnostics.forEach((diagnostic) =>
|
||||
_.each(diagnostics, (diagnostic) =>
|
||||
{
|
||||
let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||
if (diagnostic.file)
|
||||
{
|
||||
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
context.warn({ message: `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}` });
|
||||
}
|
||||
if (diagnostic.fileLine)
|
||||
context.warn(`${diagnostic.fileLine}: ${colors.yellow(diagnostic.flatMessage)}`);
|
||||
else
|
||||
context.warn({ message });
|
||||
context.warn(colors.yellow(diagnostic.flatMessage));
|
||||
});
|
||||
};
|
||||
|
||||
export default function typescript (options: any)
|
||||
interface IOptions
|
||||
{
|
||||
include: string;
|
||||
exclude: string;
|
||||
check: boolean;
|
||||
verbosity: number;
|
||||
clean: boolean;
|
||||
cacheRoot: string;
|
||||
}
|
||||
|
||||
export default function typescript (options: IOptions)
|
||||
{
|
||||
options = { ... options };
|
||||
|
||||
const filter = createFilter(options.include || [ "*.ts+(|x)", "**/*.ts+(|x)" ], options.exclude || [ "*.d.ts", "**/*.d.ts" ]);
|
||||
_.defaults(options,
|
||||
{
|
||||
check: true,
|
||||
verbosity: VerbosityLevel.Info,
|
||||
clean: false,
|
||||
cacheRoot: `${process.cwd()}/.rts2_cache`,
|
||||
include: [ "*.ts+(|x)", "**/*.ts+(|x)" ],
|
||||
exclude: [ "*.d.ts", "**/*.d.ts" ],
|
||||
});
|
||||
|
||||
delete options.include;
|
||||
delete options.exclude;
|
||||
const filter = createFilter(options.include, options.exclude);
|
||||
|
||||
let parsedConfig = parseTsConfig();
|
||||
|
||||
const servicesHost: ts.LanguageServiceHost = {
|
||||
getScriptFileNames: () => parsedConfig.fileNames,
|
||||
getScriptVersion: (_fileName) => "0",
|
||||
getScriptSnapshot: (fileName) =>
|
||||
{
|
||||
if (!fs.existsSync(fileName))
|
||||
return undefined;
|
||||
|
||||
return ts.ScriptSnapshot.fromString(ts.sys.readFile(fileName));
|
||||
},
|
||||
getCurrentDirectory: () => process.cwd(),
|
||||
getCompilationSettings: () => parsedConfig.options,
|
||||
getDefaultLibFileName: (opts) => ts.getDefaultLibFilePath(opts),
|
||||
};
|
||||
const servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
|
||||
const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
|
||||
|
||||
const context = new ConsoleContext(options.verbosity, "rollup-plugin-typescript2: ");
|
||||
|
||||
const cache = new Cache(servicesHost, options.cacheRoot, parsedConfig.options, parsedConfig.fileNames, context);
|
||||
|
||||
if (options.clean)
|
||||
cache.clean();
|
||||
|
||||
return {
|
||||
|
||||
resolveId(importee: string, importer: string)
|
||||
@ -136,6 +136,9 @@ export default function typescript (options: any)
|
||||
|
||||
if (result.resolvedModule && result.resolvedModule.resolvedFileName)
|
||||
{
|
||||
if (filter(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
|
||||
if (_.endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
|
||||
@ -145,35 +148,68 @@ export default function typescript (options: any)
|
||||
return null;
|
||||
},
|
||||
|
||||
load(id: string): any
|
||||
load(id: string): string | undefined
|
||||
{
|
||||
if (id === "\0" + TSLIB)
|
||||
return tslibSource;
|
||||
|
||||
return undefined;
|
||||
},
|
||||
|
||||
transform(this: Context, _code: string, id: string): any
|
||||
transform(this: IRollupContext, code: string, id: string): ICode | undefined
|
||||
{
|
||||
if (!filter(id)) return null;
|
||||
if (!filter(id))
|
||||
return undefined;
|
||||
|
||||
let output = services.getEmitOutput(id);
|
||||
const snapshot = servicesHost.setSnapshot(id, code);
|
||||
let result = cache.getCompiled(id, snapshot, () =>
|
||||
{
|
||||
const output = services.getEmitOutput(id);
|
||||
|
||||
let allDiagnostics = services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
if (output.emitSkipped)
|
||||
this.error({ message: colors.red(`failed to transpile ${id}`)});
|
||||
|
||||
printDiagnostics(this, allDiagnostics);
|
||||
const transpiled = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".js") );
|
||||
const map = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".map") );
|
||||
|
||||
if (output.emitSkipped)
|
||||
this.error({ message: `failed to transpile ${id}`});
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
};
|
||||
});
|
||||
|
||||
const code: ts.OutputFile = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".js") );
|
||||
const map: ts.OutputFile = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".map") );
|
||||
return result;
|
||||
},
|
||||
|
||||
return {
|
||||
code: code ? code.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
};
|
||||
outro(): void
|
||||
{
|
||||
cache.compileDone();
|
||||
|
||||
if (options.check)
|
||||
{
|
||||
cache.walkTree((id: string) =>
|
||||
{
|
||||
const snapshot = servicesHost.getScriptSnapshot(id);
|
||||
|
||||
if (!snapshot)
|
||||
{
|
||||
context.error(colors.red(`failed lo load snapshot for ${id}`));
|
||||
return;
|
||||
}
|
||||
|
||||
const diagnostics = cache.getDiagnostics(id, snapshot, () =>
|
||||
{
|
||||
return services
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
});
|
||||
|
||||
printDiagnostics(context, diagnostics);
|
||||
});
|
||||
}
|
||||
|
||||
cache.diagnosticsDone();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
87
src/rollingcache.ts
Normal file
87
src/rollingcache.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import * as fs from "fs-extra";
|
||||
import * as _ from "lodash";
|
||||
|
||||
/**
|
||||
* Saves data in new cache folder or reads it from old one.
|
||||
* Avoids perpetually growing cache and situations when things need to consider changed and then reverted data to be changed.
|
||||
*/
|
||||
export class RollingCache <DataType>
|
||||
{
|
||||
private oldCacheRoot: string;
|
||||
private newCacheRoot: string;
|
||||
|
||||
/**
|
||||
* @param cacheRoot: root folder for the cache
|
||||
* @param checkNewCache: whether to also look in new cache when reading from cache
|
||||
*/
|
||||
constructor(private cacheRoot: string, private checkNewCache: boolean)
|
||||
{
|
||||
this.oldCacheRoot = `${this.cacheRoot}/cache`;
|
||||
this.newCacheRoot = `${this.cacheRoot}/cache_`;
|
||||
|
||||
fs.emptyDirSync(this.newCacheRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if name exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
public exists(name: string): boolean
|
||||
{
|
||||
if (this.checkNewCache && fs.existsSync(`${this.newCacheRoot}/${name}`))
|
||||
return true;
|
||||
|
||||
return fs.existsSync(`${this.oldCacheRoot}/${name}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if old cache contains all names and nothing more
|
||||
*/
|
||||
public match(names: string[]): boolean
|
||||
{
|
||||
if (!fs.existsSync(this.oldCacheRoot))
|
||||
return names.length === 0; // empty folder matches
|
||||
|
||||
return _.isEqual(fs.readdirSync(this.oldCacheRoot).sort(), names.sort());
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns data for name, must exist in old cache (or either old of new cache if checkNewCache is true)
|
||||
*/
|
||||
public read(name: string): DataType
|
||||
{
|
||||
if (this.checkNewCache && fs.existsSync(`${this.newCacheRoot}/${name}`))
|
||||
return fs.readJsonSync(`${this.newCacheRoot}/${name}`, "utf8");
|
||||
|
||||
return fs.readJsonSync(`${this.oldCacheRoot}/${name}`, "utf8");
|
||||
}
|
||||
|
||||
public write(name: string, data: DataType): void
|
||||
{
|
||||
if (data === undefined)
|
||||
return;
|
||||
|
||||
if (this.checkNewCache)
|
||||
fs.writeJsonSync(`${this.newCacheRoot}/${name}`, data);
|
||||
else // won't be reading it this run
|
||||
fs.writeJson(`${this.newCacheRoot}/${name}`, data, { encoding: "utf8" }, () => { ; });
|
||||
}
|
||||
|
||||
public touch(name: string)
|
||||
{
|
||||
if (this.checkNewCache)
|
||||
fs.ensureFileSync(`${this.newCacheRoot}/${name}`);
|
||||
else // won't be reading it this run
|
||||
fs.ensureFile(`${this.newCacheRoot}/${name}`, () => { ; });
|
||||
}
|
||||
|
||||
/**
|
||||
* clears old cache and moves new in its place
|
||||
*/
|
||||
public roll()
|
||||
{
|
||||
fs.remove(this.oldCacheRoot, () =>
|
||||
{
|
||||
fs.move(this.newCacheRoot, this.oldCacheRoot, () => { ; });
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,8 @@
|
||||
"listFiles": true,
|
||||
"pretty": true,
|
||||
"moduleResolution": "node",
|
||||
"noEmitOnError": true
|
||||
"noEmitOnError": true,
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"typings/**/*.d.ts",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user