220 lines
6.3 KiB
TypeScript
220 lines
6.3 KiB
TypeScript
/**
|
|
* Adapted from the original ng-packagr source.
|
|
*
|
|
* Changes made:
|
|
* - Changed filePath passed to the StylesheetProcessor.parse when is a .ts file and inlineStyleLanguage is set.
|
|
*/
|
|
|
|
import type { CompilerHost, CompilerOptions } from '@angular/compiler-cli';
|
|
import { createHash } from 'crypto';
|
|
import { FileCache } from 'ng-packagr/lib/file-system/file-cache';
|
|
import { BuildGraph } from 'ng-packagr/lib/graph/build-graph';
|
|
import { Node } from 'ng-packagr/lib/graph/node';
|
|
import { EntryPointNode, fileUrl } from 'ng-packagr/lib/ng-package/nodes';
|
|
import { ensureUnixPath } from 'ng-packagr/lib/utils/path';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
import {
|
|
InlineStyleLanguage,
|
|
StylesheetProcessor,
|
|
} from '../styles/stylesheet-processor';
|
|
|
|
export function cacheCompilerHost(
|
|
graph: BuildGraph,
|
|
entryPoint: EntryPointNode,
|
|
compilerOptions: CompilerOptions,
|
|
moduleResolutionCache: ts.ModuleResolutionCache,
|
|
stylesheetProcessor?: StylesheetProcessor,
|
|
inlineStyleLanguage?: InlineStyleLanguage,
|
|
sourcesFileCache: FileCache = entryPoint.cache.sourcesFileCache
|
|
): CompilerHost {
|
|
const compilerHost = ts.createIncrementalCompilerHost(compilerOptions);
|
|
|
|
const getNode = (fileName: string) => {
|
|
const nodeUri = fileUrl(ensureUnixPath(fileName));
|
|
let node = graph.get(nodeUri);
|
|
|
|
if (!node) {
|
|
node = new Node(nodeUri);
|
|
graph.put(node);
|
|
}
|
|
|
|
return node;
|
|
};
|
|
|
|
const addDependee = (fileName: string) => {
|
|
const node = getNode(fileName);
|
|
entryPoint.dependsOn(node);
|
|
};
|
|
|
|
return {
|
|
...compilerHost,
|
|
|
|
// ts specific
|
|
fileExists: (fileName: string) => {
|
|
const cache = sourcesFileCache.getOrCreate(fileName);
|
|
if (cache.exists === undefined) {
|
|
cache.exists = compilerHost.fileExists.call(this, fileName);
|
|
}
|
|
|
|
return cache.exists;
|
|
},
|
|
|
|
getSourceFile: (fileName: string, languageVersion: ts.ScriptTarget) => {
|
|
addDependee(fileName);
|
|
const cache = sourcesFileCache.getOrCreate(fileName);
|
|
if (!cache.sourceFile) {
|
|
cache.sourceFile = compilerHost.getSourceFile.call(
|
|
this,
|
|
fileName,
|
|
languageVersion
|
|
);
|
|
}
|
|
|
|
return cache.sourceFile;
|
|
},
|
|
|
|
writeFile: (
|
|
fileName: string,
|
|
data: string,
|
|
writeByteOrderMark: boolean,
|
|
onError?: (message: string) => void,
|
|
sourceFiles?: ReadonlyArray<ts.SourceFile>
|
|
) => {
|
|
if (fileName.endsWith('.d.ts')) {
|
|
sourceFiles.forEach((source) => {
|
|
const cache = sourcesFileCache.getOrCreate(source.fileName);
|
|
if (!cache.declarationFileName) {
|
|
cache.declarationFileName = ensureUnixPath(fileName);
|
|
}
|
|
});
|
|
} else {
|
|
fileName = fileName.replace(/\.js(\.map)?$/, '.mjs$1');
|
|
const outputCache = entryPoint.cache.outputCache;
|
|
|
|
outputCache.set(fileName, {
|
|
content: data,
|
|
version: createHash('sha256').update(data).digest('hex'),
|
|
});
|
|
}
|
|
|
|
compilerHost.writeFile.call(
|
|
this,
|
|
fileName,
|
|
data,
|
|
writeByteOrderMark,
|
|
onError,
|
|
sourceFiles
|
|
);
|
|
},
|
|
|
|
readFile: (fileName: string) => {
|
|
addDependee(fileName);
|
|
const cache = sourcesFileCache.getOrCreate(fileName);
|
|
if (cache.content === undefined) {
|
|
cache.content = compilerHost.readFile.call(this, fileName);
|
|
}
|
|
|
|
return cache.content;
|
|
},
|
|
|
|
resolveModuleNames: (moduleNames: string[], containingFile: string) => {
|
|
return moduleNames.map((moduleName) => {
|
|
const { resolvedModule } = ts.resolveModuleName(
|
|
moduleName,
|
|
ensureUnixPath(containingFile),
|
|
compilerOptions,
|
|
compilerHost,
|
|
moduleResolutionCache
|
|
);
|
|
|
|
return resolvedModule;
|
|
});
|
|
},
|
|
|
|
resourceNameToFileName: (
|
|
resourceName: string,
|
|
containingFilePath: string
|
|
) => {
|
|
const resourcePath = path.resolve(
|
|
path.dirname(containingFilePath),
|
|
resourceName
|
|
);
|
|
const containingNode = getNode(containingFilePath);
|
|
const resourceNode = getNode(resourcePath);
|
|
containingNode.dependsOn(resourceNode);
|
|
|
|
return resourcePath;
|
|
},
|
|
|
|
readResource: async (fileName: string) => {
|
|
addDependee(fileName);
|
|
|
|
const cache = sourcesFileCache.getOrCreate(fileName);
|
|
if (cache.content === undefined) {
|
|
if (/(?:html?|svg)$/.test(path.extname(fileName))) {
|
|
// template
|
|
cache.content = compilerHost.readFile.call(this, fileName);
|
|
} else {
|
|
// stylesheet
|
|
cache.content = await stylesheetProcessor.process({
|
|
filePath: fileName,
|
|
content: compilerHost.readFile.call(this, fileName),
|
|
});
|
|
}
|
|
|
|
if (cache.content === undefined) {
|
|
throw new Error(`Cannot read file ${fileName}.`);
|
|
}
|
|
|
|
cache.exists = true;
|
|
}
|
|
|
|
return cache.content;
|
|
},
|
|
transformResource: async (data, context) => {
|
|
if (context.resourceFile || context.type !== 'style') {
|
|
return null;
|
|
}
|
|
|
|
if (inlineStyleLanguage) {
|
|
const key = createHash('sha1').update(data).digest('hex');
|
|
const fileName = `${context.containingFile}-${key}.${inlineStyleLanguage}`;
|
|
const cache = sourcesFileCache.getOrCreate(fileName);
|
|
if (cache.content === undefined) {
|
|
cache.content = await stylesheetProcessor.process({
|
|
filePath: context.containingFile, // @leosvelperez: changed from fileName
|
|
content: data,
|
|
});
|
|
|
|
const virtualFileNode = getNode(fileName);
|
|
const containingFileNode = getNode(context.containingFile);
|
|
virtualFileNode.dependsOn(containingFileNode);
|
|
}
|
|
|
|
cache.exists = true;
|
|
|
|
return { content: cache.content };
|
|
}
|
|
|
|
return null;
|
|
},
|
|
};
|
|
}
|
|
|
|
export function augmentProgramWithVersioning(program: ts.Program): void {
|
|
const baseGetSourceFiles = program.getSourceFiles;
|
|
program.getSourceFiles = function (...parameters) {
|
|
const files: readonly (ts.SourceFile & { version?: string })[] =
|
|
baseGetSourceFiles(...parameters);
|
|
|
|
for (const file of files) {
|
|
if (file.version === undefined) {
|
|
file.version = createHash('sha256').update(file.text).digest('hex');
|
|
}
|
|
}
|
|
|
|
return files;
|
|
};
|
|
}
|