mirror of
https://github.com/ezolenko/rollup-plugin-typescript2.git
synced 2025-12-08 19:06:16 +00:00
- cache
This commit is contained in:
parent
b9b2172f62
commit
3cc2c6a8e2
90
dist/rollup-plugin-typescript2.cjs.js
vendored
90
dist/rollup-plugin-typescript2.cjs.js
vendored
@ -6,6 +6,7 @@ var ts = require('typescript');
|
||||
var _ = require('lodash');
|
||||
var graph = require('graphlib');
|
||||
var hash = require('object-hash');
|
||||
var mkdirp = require('mkdirp');
|
||||
var rollupPluginutils = require('rollup-pluginutils');
|
||||
var path = require('path');
|
||||
|
||||
@ -63,23 +64,25 @@ var Cache = (function () {
|
||||
function Cache(cacheRoot, options, rootFilenames) {
|
||||
this.cacheRoot = cacheRoot;
|
||||
this.options = options;
|
||||
this.cacheVersion = "0";
|
||||
this.treeComplete = false;
|
||||
this.cacheRoot = this.cacheRoot + "/" + hash.sha1({ rootFilenames: rootFilenames, options: this.options });
|
||||
fs.mkdirSync(this.cacheRoot);
|
||||
var dependencyTreeFile = this.cacheRoot + "/tree";
|
||||
if (fs.existsSync(dependencyTreeFile)) {
|
||||
var data = fs.readFileSync(this.cacheRoot + "/tree", "utf8");
|
||||
this.dependencyTree = graph.json.read(JSON.parse(data));
|
||||
}
|
||||
else
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
this.cacheRoot = this.cacheRoot + "/" + hash.sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
|
||||
mkdirp.sync(this.cacheRoot);
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
|
||||
}
|
||||
Cache.prototype.walkTree = function (cb) {
|
||||
_.each(graph.alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
var acyclic = graph.alg.isAcyclic(this.dependencyTree);
|
||||
if (acyclic) {
|
||||
_.each(graph.alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
return;
|
||||
}
|
||||
// console.log("cycles detected in dependency graph, not sorting");
|
||||
_.each(this.dependencyTree.nodes(), function (id) { return cb(id); });
|
||||
};
|
||||
Cache.prototype.setDependency = function (importee, importer) {
|
||||
// importer -> importee
|
||||
// console.log(importer, "->", importee);
|
||||
// importee -> importer
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
};
|
||||
Cache.prototype.lastDependencySet = function () {
|
||||
@ -92,14 +95,25 @@ var Cache = (function () {
|
||||
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
|
||||
var _this = this;
|
||||
var label = this.dependencyTree.node(id);
|
||||
if (checkImports || label.dirty)
|
||||
if (!label)
|
||||
return false;
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
var dependencies = graph.alg.dijkstra(this.dependencyTree, id);
|
||||
return _.some(_.keys(dependencies), function (dependencyId) { return _this.dependencyTree.node(dependencyId).dirty; });
|
||||
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)
|
||||
console.log("dirty: " + id + " -> " + node);
|
||||
return dirty;
|
||||
});
|
||||
};
|
||||
Cache.prototype.getCompiled = function (id, snapshot, transform) {
|
||||
var path$$1 = this.makePath(id, snapshot);
|
||||
if (!fs.existsSync(path$$1) || this.isDirty(id, snapshot, false)) {
|
||||
// console.log(`compile cache miss: ${id}`);
|
||||
var data = transform();
|
||||
this.setCache(path$$1, id, snapshot, data);
|
||||
return data;
|
||||
@ -109,7 +123,8 @@ var Cache = (function () {
|
||||
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
|
||||
var path$$1 = this.makePath(id, snapshot) + ".diagnostics";
|
||||
if (!fs.existsSync(path$$1) || this.isDirty(id, snapshot, true)) {
|
||||
var data = check();
|
||||
// console.log(`diagnostics cache miss: ${id}`);
|
||||
var data = this.convert(check());
|
||||
this.setCache(path$$1, id, snapshot, data);
|
||||
return data;
|
||||
}
|
||||
@ -125,6 +140,18 @@ var Cache = (function () {
|
||||
var data = snapshot.getText(0, snapshot.getLength());
|
||||
return this.cacheRoot + "/" + 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;
|
||||
}());
|
||||
|
||||
@ -170,35 +197,31 @@ 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(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;
|
||||
console.log(diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message);
|
||||
}
|
||||
_.each(diagnostics, function (diagnostic) {
|
||||
if (diagnostic.fileLine)
|
||||
console.log(diagnostic.fileLine + ": " + diagnostic.flatMessage);
|
||||
else
|
||||
console.log(message);
|
||||
console.log(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;
|
||||
var parsedConfig = parseTsConfig();
|
||||
var servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
var services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
|
||||
var cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
|
||||
var cache = new Cache(process.cwd() + "/.rts2_cache", parsedConfig.options, parsedConfig.fileNames);
|
||||
return {
|
||||
resolveId: function (importee, importer) {
|
||||
cache.setDependency(importee, importer);
|
||||
if (importee === TSLIB)
|
||||
return "\0" + TSLIB;
|
||||
if (!importer)
|
||||
@ -208,6 +231,8 @@ function typescript(options) {
|
||||
if (result.resolvedModule && result.resolvedModule.resolvedFileName) {
|
||||
if (_.endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
if (filter(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
return result.resolvedModule.resolvedFileName;
|
||||
}
|
||||
return null;
|
||||
@ -220,17 +245,17 @@ function typescript(options) {
|
||||
transform: function (code, id) {
|
||||
var _this = this;
|
||||
if (!filter(id))
|
||||
return null;
|
||||
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: "failed to transpile " + id });
|
||||
var transpiled = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".js"); });
|
||||
var map = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".map"); });
|
||||
var map$$1 = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
|
||||
};
|
||||
});
|
||||
return result;
|
||||
@ -239,16 +264,17 @@ function typescript(options) {
|
||||
cache.lastDependencySet();
|
||||
cache.walkTree(function (id) {
|
||||
var snapshot = servicesHost.getScriptSnapshot(id);
|
||||
if (!snapshot) {
|
||||
console.log("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));
|
||||
});
|
||||
if (diagnostics.length !== 0) {
|
||||
console.log(id);
|
||||
printDiagnostics(diagnostics);
|
||||
}
|
||||
printDiagnostics(diagnostics);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
97
dist/rollup-plugin-typescript2.es.js
vendored
97
dist/rollup-plugin-typescript2.es.js
vendored
@ -1,14 +1,16 @@
|
||||
/* eslint-disable */
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import * as fs from 'fs';
|
||||
import { ModuleKind, ScriptSnapshot, createDocumentRegistry, createLanguageService, flattenDiagnosticMessageText, getDefaultLibFilePath, nodeModuleNameResolver, parseConfigFileTextToJson, parseJsonConfigFileContent, sys } from 'typescript';
|
||||
import * as ts from 'typescript';
|
||||
import { each, endsWith, find, has, keys, some } from 'lodash';
|
||||
import { each, endsWith, find, has, map, some } from 'lodash';
|
||||
import * as _ from 'lodash';
|
||||
import { Graph, alg, json } from 'graphlib';
|
||||
import { Graph, alg } from 'graphlib';
|
||||
import * as graph from 'graphlib';
|
||||
import { sha1 } from 'object-hash';
|
||||
import * as hash from 'object-hash';
|
||||
import { sync } from 'mkdirp';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import { createFilter } from 'rollup-pluginutils';
|
||||
import { dirname, sep } from 'path';
|
||||
import * as path from 'path';
|
||||
@ -67,23 +69,25 @@ var Cache = (function () {
|
||||
function Cache(cacheRoot, options, rootFilenames) {
|
||||
this.cacheRoot = cacheRoot;
|
||||
this.options = options;
|
||||
this.cacheVersion = "0";
|
||||
this.treeComplete = false;
|
||||
this.cacheRoot = this.cacheRoot + "/" + sha1({ rootFilenames: rootFilenames, options: this.options });
|
||||
mkdirSync(this.cacheRoot);
|
||||
var dependencyTreeFile = this.cacheRoot + "/tree";
|
||||
if (existsSync(dependencyTreeFile)) {
|
||||
var data = readFileSync(this.cacheRoot + "/tree", "utf8");
|
||||
this.dependencyTree = json.read(JSON.parse(data));
|
||||
}
|
||||
else
|
||||
this.dependencyTree = new Graph({ directed: true });
|
||||
this.cacheRoot = this.cacheRoot + "/" + sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
|
||||
sync(this.cacheRoot);
|
||||
this.dependencyTree = new Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
|
||||
}
|
||||
Cache.prototype.walkTree = function (cb) {
|
||||
each(alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
var acyclic = alg.isAcyclic(this.dependencyTree);
|
||||
if (acyclic) {
|
||||
each(alg.topsort(this.dependencyTree), function (id) { return cb(id); });
|
||||
return;
|
||||
}
|
||||
// console.log("cycles detected in dependency graph, not sorting");
|
||||
each(this.dependencyTree.nodes(), function (id) { return cb(id); });
|
||||
};
|
||||
Cache.prototype.setDependency = function (importee, importer) {
|
||||
// importer -> importee
|
||||
// console.log(importer, "->", importee);
|
||||
// importee -> importer
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
};
|
||||
Cache.prototype.lastDependencySet = function () {
|
||||
@ -96,14 +100,25 @@ var Cache = (function () {
|
||||
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
|
||||
var _this = this;
|
||||
var label = this.dependencyTree.node(id);
|
||||
if (checkImports || label.dirty)
|
||||
if (!label)
|
||||
return false;
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
var dependencies = alg.dijkstra(this.dependencyTree, id);
|
||||
return some(keys(dependencies), function (dependencyId) { return _this.dependencyTree.node(dependencyId).dirty; });
|
||||
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)
|
||||
console.log("dirty: " + id + " -> " + node);
|
||||
return dirty;
|
||||
});
|
||||
};
|
||||
Cache.prototype.getCompiled = function (id, snapshot, transform) {
|
||||
var path$$1 = this.makePath(id, snapshot);
|
||||
if (!existsSync(path$$1) || this.isDirty(id, snapshot, false)) {
|
||||
// console.log(`compile cache miss: ${id}`);
|
||||
var data = transform();
|
||||
this.setCache(path$$1, id, snapshot, data);
|
||||
return data;
|
||||
@ -113,7 +128,8 @@ var Cache = (function () {
|
||||
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
|
||||
var path$$1 = this.makePath(id, snapshot) + ".diagnostics";
|
||||
if (!existsSync(path$$1) || this.isDirty(id, snapshot, true)) {
|
||||
var data = check();
|
||||
// console.log(`diagnostics cache miss: ${id}`);
|
||||
var data = this.convert(check());
|
||||
this.setCache(path$$1, id, snapshot, data);
|
||||
return data;
|
||||
}
|
||||
@ -129,6 +145,18 @@ var Cache = (function () {
|
||||
var data = snapshot.getText(0, snapshot.getLength());
|
||||
return this.cacheRoot + "/" + 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;
|
||||
}());
|
||||
|
||||
@ -174,35 +202,31 @@ 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(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;
|
||||
console.log(diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message);
|
||||
}
|
||||
each(diagnostics, function (diagnostic) {
|
||||
if (diagnostic.fileLine)
|
||||
console.log(diagnostic.fileLine + ": " + diagnostic.flatMessage);
|
||||
else
|
||||
console.log(message);
|
||||
console.log(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;
|
||||
var parsedConfig = parseTsConfig();
|
||||
var servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
var services = createLanguageService(servicesHost, createDocumentRegistry());
|
||||
var cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
|
||||
var cache = new Cache(process.cwd() + "/.rts2_cache", parsedConfig.options, parsedConfig.fileNames);
|
||||
return {
|
||||
resolveId: function (importee, importer) {
|
||||
cache.setDependency(importee, importer);
|
||||
if (importee === TSLIB)
|
||||
return "\0" + TSLIB;
|
||||
if (!importer)
|
||||
@ -212,6 +236,8 @@ function typescript(options) {
|
||||
if (result.resolvedModule && result.resolvedModule.resolvedFileName) {
|
||||
if (endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
if (filter(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
return result.resolvedModule.resolvedFileName;
|
||||
}
|
||||
return null;
|
||||
@ -224,17 +250,17 @@ function typescript(options) {
|
||||
transform: function (code, id) {
|
||||
var _this = this;
|
||||
if (!filter(id))
|
||||
return null;
|
||||
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: "failed to transpile " + id });
|
||||
var transpiled = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".js"); });
|
||||
var map = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".map"); });
|
||||
var map$$1 = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".map"); });
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
map: map ? JSON.parse(map.text) : { mappings: "" },
|
||||
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
|
||||
};
|
||||
});
|
||||
return result;
|
||||
@ -243,16 +269,17 @@ function typescript(options) {
|
||||
cache.lastDependencySet();
|
||||
cache.walkTree(function (id) {
|
||||
var snapshot = servicesHost.getScriptSnapshot(id);
|
||||
if (!snapshot) {
|
||||
console.log("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));
|
||||
});
|
||||
if (diagnostics.length !== 0) {
|
||||
console.log(id);
|
||||
printDiagnostics(diagnostics);
|
||||
}
|
||||
printDiagnostics(diagnostics);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@ -24,11 +24,12 @@
|
||||
"postinstall": "typings install"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^1.5.0",
|
||||
"lodash": "^4.17.4",
|
||||
"graphlib": "^2.1.1",
|
||||
"lodash": "^4.17.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"object-hash": "^1.1.5",
|
||||
"rollup-pluginutils": "^2.0.1"
|
||||
"rollup-pluginutils": "^2.0.1",
|
||||
"tslib": "^1.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^2.0"
|
||||
@ -37,6 +38,7 @@
|
||||
"@alexlur/rollup-plugin-typescript": "^0.8.1",
|
||||
"@types/graphlib": "^2.1.3",
|
||||
"@types/lodash": "^4.14.52",
|
||||
"@types/mkdirp": "^0.3.29",
|
||||
"@types/node": "^6.0.53",
|
||||
"@types/object-hash": "^0.5.28",
|
||||
"rimraf": "^2.5.4",
|
||||
|
||||
@ -13,7 +13,8 @@ export default {
|
||||
'typescript',
|
||||
'lodash',
|
||||
'graphlib',
|
||||
'object-hash'
|
||||
'object-hash',
|
||||
'mkdirp'
|
||||
],
|
||||
|
||||
plugins: [
|
||||
|
||||
94
src/cache.ts
94
src/cache.ts
@ -3,11 +3,12 @@ import * as graph from "graphlib";
|
||||
import * as hash from "object-hash";
|
||||
import * as fs from "fs";
|
||||
import * as _ from "lodash";
|
||||
import * as mkdirp from "mkdirp";
|
||||
|
||||
export interface ICode
|
||||
{
|
||||
code: string;
|
||||
map: string;
|
||||
code: string | undefined;
|
||||
map: string | undefined;
|
||||
}
|
||||
|
||||
interface INodeLabel
|
||||
@ -16,46 +17,55 @@ interface INodeLabel
|
||||
hash?: string;
|
||||
}
|
||||
|
||||
export interface IDiagnostics
|
||||
{
|
||||
flatMessage: string;
|
||||
fileLine?: string;
|
||||
}
|
||||
|
||||
export class Cache
|
||||
{
|
||||
private cacheVersion = "0";
|
||||
private dependencyTree: graph.Graph;
|
||||
private treeComplete: boolean = false;
|
||||
|
||||
constructor(private cacheRoot: string, private options: ts.CompilerOptions, rootFilenames: string[])
|
||||
{
|
||||
this.cacheRoot = `${this.cacheRoot}/${hash.sha1({ rootFilenames, options: this.options })}`;
|
||||
fs.mkdirSync(this.cacheRoot);
|
||||
this.cacheRoot = `${this.cacheRoot}/${hash.sha1({ version: this.cacheVersion, rootFilenames, options: this.options })}`;
|
||||
|
||||
let dependencyTreeFile = `${this.cacheRoot}/tree`;
|
||||
if (fs.existsSync(dependencyTreeFile))
|
||||
{
|
||||
let data = fs.readFileSync(`${this.cacheRoot}/tree`, "utf8");
|
||||
|
||||
this.dependencyTree = graph.json.read(JSON.parse(data));
|
||||
}
|
||||
else
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
mkdirp.sync(this.cacheRoot);
|
||||
|
||||
this.dependencyTree = new graph.Graph({ directed: true });
|
||||
this.dependencyTree.setDefaultNodeLabel((_node: string) => { return { dirty: false }; });
|
||||
}
|
||||
|
||||
public walkTree(cb: (id: string) => void | false)
|
||||
public walkTree(cb: (id: string) => void | false): void
|
||||
{
|
||||
_.each(graph.alg.topsort(this.dependencyTree), (id: string) => cb(id));
|
||||
const acyclic = graph.alg.isAcyclic(this.dependencyTree);
|
||||
|
||||
if (acyclic)
|
||||
{
|
||||
_.each(graph.alg.topsort(this.dependencyTree), (id: string) => cb(id));
|
||||
return;
|
||||
}
|
||||
|
||||
// console.log("cycles detected in dependency graph, not sorting");
|
||||
_.each(this.dependencyTree.nodes(), (id: string) => cb(id));
|
||||
}
|
||||
|
||||
public setDependency(importee: string, importer: string): void
|
||||
{
|
||||
// importer -> importee
|
||||
// console.log(importer, "->", importee);
|
||||
// importee -> importer
|
||||
this.dependencyTree.setEdge(importer, importee);
|
||||
}
|
||||
|
||||
public lastDependencySet()
|
||||
public lastDependencySet(): void
|
||||
{
|
||||
this.treeComplete = true;
|
||||
}
|
||||
|
||||
public markAsDirty(id: string, _snapshot: ts.IScriptSnapshot)
|
||||
public markAsDirty(id: string, _snapshot: ts.IScriptSnapshot): void
|
||||
{
|
||||
this.dependencyTree.setNode(id, { dirty: true });
|
||||
}
|
||||
@ -65,12 +75,27 @@ export class Cache
|
||||
{
|
||||
let label = this.dependencyTree.node(id) as INodeLabel;
|
||||
|
||||
if (checkImports || label.dirty)
|
||||
if (!label)
|
||||
return false;
|
||||
|
||||
if (!checkImports || label.dirty)
|
||||
return label.dirty;
|
||||
|
||||
let dependencies = graph.alg.dijkstra(this.dependencyTree, id);
|
||||
|
||||
return _.some(_.keys(dependencies), (dependencyId: string) => (this.dependencyTree.node(dependencyId) as INodeLabel).dirty);
|
||||
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)
|
||||
console.log(`dirty: ${id} -> ${node}`);
|
||||
|
||||
return dirty;
|
||||
});
|
||||
}
|
||||
|
||||
public getCompiled(id: string, snapshot: ts.IScriptSnapshot, transform: () => ICode | undefined): ICode | undefined
|
||||
@ -79,6 +104,7 @@ export class Cache
|
||||
|
||||
if (!fs.existsSync(path) || this.isDirty(id, snapshot, false))
|
||||
{
|
||||
// console.log(`compile cache miss: ${id}`);
|
||||
let data = transform();
|
||||
this.setCache(path, id, snapshot, data);
|
||||
return data;
|
||||
@ -87,21 +113,22 @@ export class Cache
|
||||
return JSON.parse(fs.readFileSync(path, "utf8")) as ICode;
|
||||
}
|
||||
|
||||
public getDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): ts.Diagnostic[]
|
||||
public getDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
|
||||
{
|
||||
let path = `${this.makePath(id, snapshot)}.diagnostics`;
|
||||
|
||||
if (!fs.existsSync(path) || this.isDirty(id, snapshot, true))
|
||||
{
|
||||
let data = check();
|
||||
// console.log(`diagnostics cache miss: ${id}`);
|
||||
let data = this.convert(check());
|
||||
this.setCache(path, id, snapshot, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
return JSON.parse(fs.readFileSync(path, "utf8")) as ts.Diagnostic[];
|
||||
return JSON.parse(fs.readFileSync(path, "utf8")) as IDiagnostics[];
|
||||
}
|
||||
|
||||
private setCache(path: string, id: string, snapshot: ts.IScriptSnapshot, data: ts.Diagnostic[] | ICode | undefined): void
|
||||
private setCache(path: string, id: string, snapshot: ts.IScriptSnapshot, data: IDiagnostics[] | ICode | undefined): void
|
||||
{
|
||||
if (data === undefined)
|
||||
return;
|
||||
@ -116,4 +143,23 @@ export class Cache
|
||||
let data = snapshot.getText(0, snapshot.getLength());
|
||||
return `${this.cacheRoot}/${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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
60
src/index.ts
60
src/index.ts
@ -1,5 +1,5 @@
|
||||
import { LanguageServiceHost } from "./host";
|
||||
import { Cache, ICode } from "./cache";
|
||||
import { Cache, ICode, IDiagnostics } from "./cache";
|
||||
import * as ts from "typescript";
|
||||
import { createFilter } from "rollup-pluginutils";
|
||||
import * as fs from "fs";
|
||||
@ -63,6 +63,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);
|
||||
@ -79,44 +82,41 @@ interface Context
|
||||
warn(message: Message): void;
|
||||
error(message: Message): void;
|
||||
}
|
||||
function printDiagnostics(diagnostics: ts.Diagnostic[])
|
||||
function printDiagnostics(diagnostics: IDiagnostics[])
|
||||
{
|
||||
diagnostics.forEach((diagnostic) =>
|
||||
_.each(diagnostics, (diagnostic) =>
|
||||
{
|
||||
let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
||||
if (diagnostic.file)
|
||||
{
|
||||
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
||||
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
|
||||
}
|
||||
if (diagnostic.fileLine)
|
||||
console.log(`${diagnostic.fileLine}: ${diagnostic.flatMessage}`);
|
||||
else
|
||||
console.log(message);
|
||||
console.log(diagnostic.flatMessage);
|
||||
});
|
||||
};
|
||||
|
||||
export default function typescript (options: any)
|
||||
interface IOptions
|
||||
{
|
||||
include?: string;
|
||||
exclude?: string;
|
||||
}
|
||||
|
||||
export default function typescript (options: IOptions)
|
||||
{
|
||||
options = { ... options };
|
||||
|
||||
const filter = createFilter(options.include || [ "*.ts+(|x)", "**/*.ts+(|x)" ], options.exclude || [ "*.d.ts", "**/*.d.ts" ]);
|
||||
|
||||
delete options.include;
|
||||
delete options.exclude;
|
||||
|
||||
let parsedConfig = parseTsConfig();
|
||||
|
||||
const servicesHost = new LanguageServiceHost(parsedConfig);
|
||||
|
||||
const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
|
||||
|
||||
const cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
|
||||
const cache = new Cache(`${process.cwd()}/.rts2_cache`, parsedConfig.options, parsedConfig.fileNames);
|
||||
|
||||
return {
|
||||
|
||||
resolveId(importee: string, importer: string)
|
||||
{
|
||||
cache.setDependency(importee, importer);
|
||||
|
||||
if (importee === TSLIB)
|
||||
return "\0" + TSLIB;
|
||||
|
||||
@ -132,6 +132,9 @@ export default function typescript (options: any)
|
||||
if (_.endsWith(result.resolvedModule.resolvedFileName, ".d.ts"))
|
||||
return null;
|
||||
|
||||
if (filter(result.resolvedModule.resolvedFileName))
|
||||
cache.setDependency(result.resolvedModule.resolvedFileName, importer);
|
||||
|
||||
return result.resolvedModule.resolvedFileName;
|
||||
}
|
||||
|
||||
@ -146,13 +149,12 @@ export default function typescript (options: any)
|
||||
return undefined;
|
||||
},
|
||||
|
||||
transform(this: Context, code: string, id: string): ICode | null
|
||||
transform(this: Context, code: string, id: string): ICode | undefined
|
||||
{
|
||||
if (!filter(id))
|
||||
return null;
|
||||
return undefined;
|
||||
|
||||
const snapshot = servicesHost.setSnapshot(id, code);
|
||||
|
||||
let result = cache.getCompiled(id, snapshot, () =>
|
||||
{
|
||||
const output = services.getEmitOutput(id);
|
||||
@ -160,8 +162,8 @@ export default function typescript (options: any)
|
||||
if (output.emitSkipped)
|
||||
this.error({ message: `failed to transpile ${id}`});
|
||||
|
||||
const transpiled: 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") );
|
||||
const transpiled = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".js") );
|
||||
const map = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".map") );
|
||||
|
||||
return {
|
||||
code: transpiled ? transpiled.text : undefined,
|
||||
@ -179,6 +181,13 @@ export default function typescript (options: any)
|
||||
cache.walkTree((id: string) =>
|
||||
{
|
||||
const snapshot = servicesHost.getScriptSnapshot(id);
|
||||
|
||||
if (!snapshot)
|
||||
{
|
||||
console.log(`failed lo load snapshot for ${id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const diagnostics = cache.getDiagnostics(id, snapshot, () =>
|
||||
{
|
||||
return services
|
||||
@ -186,11 +195,8 @@ export default function typescript (options: any)
|
||||
.concat(services.getSyntacticDiagnostics(id))
|
||||
.concat(services.getSemanticDiagnostics(id));
|
||||
});
|
||||
if (diagnostics.length !== 0)
|
||||
{
|
||||
console.log(id);
|
||||
printDiagnostics(diagnostics);
|
||||
}
|
||||
|
||||
printDiagnostics(diagnostics);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@ -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