ph-dev-tools
Version:
Development Tools for PHibernate
132 lines (113 loc) • 4 kB
text/typescript
/**
* Created by Papa on 3/30/2016.
*/
import * as fs from "fs";
import * as ts from "typescript";
import {generateEntityDefinitions} from "./parser/EntityDefinitionGenerator";
import {EntityCandidate} from "./parser/EntityCandidate";
import {Configuration} from "./options/Options";
import {QEntityFileBuilder} from "./builder/entity/QEntityFileBuilder";
import {PathBuilder} from "./builder/PathBuilder";
export function watchFiles(
configuration:Configuration,
options:ts.CompilerOptions,
rootFileNames:string[]
) {
const files:ts.Map<{ version:number }> = {};
const pathBuilder = new PathBuilder(configuration);
// initialize the list of files
rootFileNames.forEach(
fileName => {
files[fileName] = {version: 0};
});
// Create the language service host to allow the LS to communicate with the host
const servicesHost:ts.LanguageServiceHost = {
getCompilationSettings: () => options,
getScriptFileNames: () => rootFileNames,
getScriptVersion: ( fileName ) => files[fileName] && files[fileName].version.toString(),
getScriptSnapshot: ( fileName ) => {
if (!fs.existsSync(fileName)) {
return undefined;
}
return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
},
getCurrentDirectory: () => process.cwd(),
getDefaultLibFileName: ( options ) => ts.getDefaultLibFilePath(options)
};
// Create the language service files
const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
// First time around, process all files
processFiles(rootFileNames, options);
// Now let's watch the files
rootFileNames.forEach(
fileName => {
// Add a watch on the file to handle next change
fs.watchFile(fileName,
{persistent: true, interval: 250},
(
curr,
prev
) => {
// Check timestamp
if (+curr.mtime <= +prev.mtime) {
return;
}
// Update the version to signal a change in the file
files[fileName].version++;
// process file
processFiles([fileName], options);
});
});
function processFiles(
rootFileNames:string[],
options:ts.CompilerOptions
):void {
options.target = ts.ScriptTarget.ES5;
let entities:EntityCandidate[] = generateEntityDefinitions(rootFileNames, options);
emitFiles(entities);
}
function emitFiles(
entities:EntityCandidate[]
):void {
entities.forEach((
entity:EntityCandidate
) => {
// TODO: work here next - read all of the configured templates and generate all of the artifacts
let fullGenerationPath = pathBuilder.getFullPathToGeneratedSource(entity.path);
let entityFileBuilder = new QEntityFileBuilder(entity, fullGenerationPath, pathBuilder.workingDirPath);
let generationPath = pathBuilder.setupFileForGeneration(entity.path);
var entitySourceString = entityFileBuilder.build();
fs.writeFileSync(generationPath, entitySourceString);
});
}
function emitFile( fileName:string ) {
let output = services.getEmitOutput(fileName);
if (!output.emitSkipped) {
console.log(`Emitting ${fileName}`);
}
else {
console.log(`Emitting ${fileName} failed`);
logErrors(fileName);
}
output.outputFiles.forEach(
o => {
fs.writeFileSync(o.name, o.text, "utf8");
});
}
function logErrors( fileName:string ) {
let allDiagnostics = services.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(fileName))
.concat(services.getSemanticDiagnostics(fileName));
allDiagnostics.forEach(
diagnostic => {
let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
if (diagnostic.file) {
let {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
console.log(` Error ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
}
else {
console.log(` Error: ${message}`);
}
});
}
}