This commit is contained in:
Eugene Zolenko 2017-02-08 18:30:44 -07:00
parent 6633ef1414
commit b9b2172f62
6 changed files with 423 additions and 104 deletions

View File

@ -1,11 +1,13 @@
/* eslint-disable */
'use strict';
var ts = require('typescript');
var rollupPluginutils = require('rollup-pluginutils');
var fs = require('fs');
var path = require('path');
var ts = require('typescript');
var _ = require('lodash');
var graph = require('graphlib');
var hash = require('object-hash');
var rollupPluginutils = require('rollup-pluginutils');
var path = require('path');
const __assign = Object.assign || function (target) {
for (var source, i = 1; i < arguments.length; i++) {
@ -19,6 +21,113 @@ const __assign = Object.assign || function (target) {
return target;
};
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;
}());
var Cache = (function () {
function Cache(cacheRoot, options, rootFilenames) {
this.cacheRoot = cacheRoot;
this.options = options;
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.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
}
Cache.prototype.walkTree = function (cb) {
_.each(graph.alg.topsort(this.dependencyTree), function (id) { return cb(id); });
};
Cache.prototype.setDependency = function (importee, importer) {
// importer -> importee
this.dependencyTree.setEdge(importer, importee);
};
Cache.prototype.lastDependencySet = function () {
this.treeComplete = true;
};
Cache.prototype.markAsDirty = function (id, _snapshot) {
this.dependencyTree.setNode(id, { dirty: true });
};
// returns true if node or any of its imports changed
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
var _this = this;
var label = this.dependencyTree.node(id);
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; });
};
Cache.prototype.getCompiled = function (id, snapshot, transform) {
var path$$1 = this.makePath(id, snapshot);
if (!fs.existsSync(path$$1) || this.isDirty(id, snapshot, false)) {
var data = transform();
this.setCache(path$$1, id, snapshot, data);
return data;
}
return JSON.parse(fs.readFileSync(path$$1, "utf8"));
};
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();
this.setCache(path$$1, id, snapshot, data);
return data;
}
return JSON.parse(fs.readFileSync(path$$1, "utf8"));
};
Cache.prototype.setCache = function (path$$1, id, snapshot, data) {
if (data === undefined)
return;
fs.writeFileSync(path$$1, JSON.stringify(data));
this.markAsDirty(id, snapshot);
};
Cache.prototype.makePath = function (id, snapshot) {
var data = snapshot.getText(0, snapshot.getLength());
return this.cacheRoot + "/" + hash.sha1({ data: data, id: id });
};
return Cache;
}());
function getOptionsOverrides() {
return {
module: ts.ModuleKind.ES2015,
@ -66,15 +175,15 @@ function parseTsConfig() {
var configParseResult = ts.parseJsonConfigFileContent(result.config, ts.sys, path.dirname(fileName), getOptionsOverrides(), fileName);
return configParseResult;
}
function printDiagnostics(context, diagnostics) {
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;
context.warn({ message: diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message });
console.log(diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message);
}
else
context.warn({ message: message });
console.log(message);
});
}
@ -84,21 +193,12 @@ function typescript(options) {
delete options.include;
delete 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 cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
return {
resolveId: function (importee, importer) {
cache.setDependency(importee, importer);
if (importee === TSLIB)
return "\0" + TSLIB;
if (!importer)
@ -115,24 +215,41 @@ function typescript(options) {
load: function (id) {
if (id === "\0" + TSLIB)
return tslibSource;
return undefined;
},
transform: function (_code, id) {
transform: function (code, id) {
var _this = this;
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: "" },
};
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"); });
return {
code: transpiled ? transpiled.text : undefined,
map: map ? JSON.parse(map.text) : { mappings: "" },
};
});
return result;
},
outro: function () {
cache.lastDependencySet();
cache.walkTree(function (id) {
var snapshot = servicesHost.getScriptSnapshot(id);
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);
}
});
},
};
}

View File

@ -1,13 +1,17 @@
/* eslint-disable */
import { existsSync, mkdirSync, 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 * as _ from 'lodash';
import { Graph, alg, json } 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';
const __assign = Object.assign || function (target) {
for (var source, i = 1; i < arguments.length; i++) {
@ -21,6 +25,113 @@ const __assign = Object.assign || function (target) {
return target;
};
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;
}());
var Cache = (function () {
function Cache(cacheRoot, options, rootFilenames) {
this.cacheRoot = cacheRoot;
this.options = options;
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.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
}
Cache.prototype.walkTree = function (cb) {
each(alg.topsort(this.dependencyTree), function (id) { return cb(id); });
};
Cache.prototype.setDependency = function (importee, importer) {
// importer -> importee
this.dependencyTree.setEdge(importer, importee);
};
Cache.prototype.lastDependencySet = function () {
this.treeComplete = true;
};
Cache.prototype.markAsDirty = function (id, _snapshot) {
this.dependencyTree.setNode(id, { dirty: true });
};
// returns true if node or any of its imports changed
Cache.prototype.isDirty = function (id, _snapshot, checkImports) {
var _this = this;
var label = this.dependencyTree.node(id);
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; });
};
Cache.prototype.getCompiled = function (id, snapshot, transform) {
var path$$1 = this.makePath(id, snapshot);
if (!existsSync(path$$1) || this.isDirty(id, snapshot, false)) {
var data = transform();
this.setCache(path$$1, id, snapshot, data);
return data;
}
return JSON.parse(readFileSync(path$$1, "utf8"));
};
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();
this.setCache(path$$1, id, snapshot, data);
return data;
}
return JSON.parse(readFileSync(path$$1, "utf8"));
};
Cache.prototype.setCache = function (path$$1, id, snapshot, data) {
if (data === undefined)
return;
writeFileSync(path$$1, JSON.stringify(data));
this.markAsDirty(id, snapshot);
};
Cache.prototype.makePath = function (id, snapshot) {
var data = snapshot.getText(0, snapshot.getLength());
return this.cacheRoot + "/" + sha1({ data: data, id: id });
};
return Cache;
}());
function getOptionsOverrides() {
return {
module: ModuleKind.ES2015,
@ -68,15 +179,15 @@ function parseTsConfig() {
var configParseResult = parseJsonConfigFileContent(result.config, sys, dirname(fileName), getOptionsOverrides(), fileName);
return configParseResult;
}
function printDiagnostics(context, diagnostics) {
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;
context.warn({ message: diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message });
console.log(diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + "): " + message);
}
else
context.warn({ message: message });
console.log(message);
});
}
@ -86,21 +197,12 @@ function typescript(options) {
delete options.include;
delete 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 cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
return {
resolveId: function (importee, importer) {
cache.setDependency(importee, importer);
if (importee === TSLIB)
return "\0" + TSLIB;
if (!importer)
@ -117,24 +219,41 @@ function typescript(options) {
load: function (id) {
if (id === "\0" + TSLIB)
return tslibSource;
return undefined;
},
transform: function (_code, id) {
transform: function (code, id) {
var _this = this;
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: "" },
};
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"); });
return {
code: transpiled ? transpiled.text : undefined,
map: map ? JSON.parse(map.text) : { mappings: "" },
};
});
return result;
},
outro: function () {
cache.lastDependencySet();
cache.walkTree(function (id) {
var snapshot = servicesHost.getScriptSnapshot(id);
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);
}
});
},
};
}

View File

@ -28,16 +28,17 @@
"lodash": "^4.17.4",
"graphlib": "^2.1.1",
"object-hash": "^1.1.5",
"rollup-pluginutils": "^2.0.1",
"rollup-pluginutils": "^2.0.1"
},
"peerDependencies": {
"typescript": "^2.0"
},
"devDependencies": {
"@alexlur/rollup-plugin-typescript": "^0.8.1",
"@types/graphlib": "^2.1.3",
"@types/lodash": "^4.14.52",
"@types/node": "^6.0.53",
"@types/graphlib": "^2.1.3",
"@types/object-hash": "^0.5.28",
"rimraf": "^2.5.4",
"rollup": "^0.41.4",
"tslint": "^4.4.2",

View File

@ -4,7 +4,7 @@ import * as hash from "object-hash";
import * as fs from "fs";
import * as _ from "lodash";
interface ICode
export interface ICode
{
code: string;
map: string;
@ -39,6 +39,11 @@ export class Cache
this.dependencyTree.setDefaultNodeLabel((_node: string) => { return { dirty: false }; });
}
public walkTree(cb: (id: string) => void | false)
{
_.each(graph.alg.topsort(this.dependencyTree), (id: string) => cb(id));
}
public setDependency(importee: string, importer: string): void
{
// importer -> importee

59
src/host.ts Normal file
View File

@ -0,0 +1,59 @@
import * as fs from "fs";
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);
}
}

View File

@ -1,3 +1,5 @@
import { LanguageServiceHost } from "./host";
import { Cache, ICode } from "./cache";
import * as ts from "typescript";
import { createFilter } from "rollup-pluginutils";
import * as fs from "fs";
@ -77,7 +79,7 @@ interface Context
warn(message: Message): void;
error(message: Message): void;
}
function printDiagnostics(context: Context, diagnostics: ts.Diagnostic[])
function printDiagnostics(diagnostics: ts.Diagnostic[])
{
diagnostics.forEach((diagnostic) =>
{
@ -85,10 +87,10 @@ function printDiagnostics(context: Context, diagnostics: ts.Diagnostic[])
if (diagnostic.file)
{
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
context.warn({ message: `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}` });
console.log(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
}
else
context.warn({ message });
console.log(message);
});
};
@ -103,27 +105,18 @@ export default function typescript (options: any)
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 cache = new Cache(process.cwd(), parsedConfig.options, parsedConfig.fileNames);
return {
resolveId(importee: string, importer: string)
{
cache.setDependency(importee, importer);
if (importee === TSLIB)
return "\0" + TSLIB;
@ -145,35 +138,60 @@ 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: Context, code: string, id: string): ICode | null
{
if (!filter(id)) return null;
if (!filter(id))
return null;
let output = services.getEmitOutput(id);
const snapshot = servicesHost.setSnapshot(id, code);
let allDiagnostics = services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
let result = cache.getCompiled(id, snapshot, () =>
{
const output = services.getEmitOutput(id);
printDiagnostics(this, allDiagnostics);
if (output.emitSkipped)
this.error({ message: `failed to transpile ${id}`});
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 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 {
code: transpiled ? transpiled.text : undefined,
map: map ? JSON.parse(map.text) : { mappings: "" },
};
});
return {
code: code ? code.text : undefined,
map: map ? JSON.parse(map.text) : { mappings: "" },
};
return result;
},
outro(): void
{
cache.lastDependencySet();
cache.walkTree((id: string) =>
{
const snapshot = servicesHost.getScriptSnapshot(id);
const diagnostics = cache.getDiagnostics(id, snapshot, () =>
{
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
});
if (diagnostics.length !== 0)
{
console.log(id);
printDiagnostics(diagnostics);
}
});
},
};
}