/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {PluginCompilerHost, TscPlugin} from '@bazel/typescript/internal/tsc_wrapped/plugin_api'; import * as ts from 'typescript'; import {SyntheticFilesCompilerHost} from './synthetic_files_compiler_host'; // Copied from tsc_wrapped/plugin_api.ts to avoid a runtime dependency on the // @bazel/typescript package - it would be strange for non-Bazel users of // Angular to fetch that package. function createProxy(delegate: T): T { const proxy = Object.create(null); for (const k of Object.keys(delegate)) { proxy[k] = function() { return (delegate as any)[k].apply(delegate, arguments); }; } return proxy; } export class NgTscPlugin implements TscPlugin { constructor(private angularCompilerOptions: unknown) {} wrapHost(inputFiles: string[], compilerHost: ts.CompilerHost) { return new SyntheticFilesCompilerHost(inputFiles, compilerHost, (rootFiles: string[]) => { // For demo purposes, assume that the first .ts rootFile is the only // one that needs ngfactory.js/d.ts back-compat files produced. const tsInputs = rootFiles.filter(f => f.endsWith('.ts') && !f.endsWith('.d.ts')); const factoryPath: string = tsInputs[0].replace(/\.ts/, '.ngfactory.ts'); return { factoryPath: (host: ts.CompilerHost) => ts.createSourceFile(factoryPath, 'contents', ts.ScriptTarget.ES5), }; }); } wrap(program: ts.Program, config: {}, host: ts.CompilerHost) { const proxy = createProxy(program); proxy.getSemanticDiagnostics = (sourceFile: ts.SourceFile) => { const result: ts.Diagnostic[] = [...program.getSemanticDiagnostics(sourceFile)]; // For demo purposes, trigger a diagnostic when the sourcefile has a magic string if (sourceFile.text.indexOf('diag') >= 0) { const fake: ts.Diagnostic = { file: sourceFile, start: 0, length: 3, messageText: 'Example Angular Compiler Diagnostic', category: ts.DiagnosticCategory.Error, code: 12345, // source is the name of the plugin. source: 'ngtsc', }; result.push(fake); } return result; }; return proxy; } createTransformers(host: PluginCompilerHost) { const afterDeclarations: Array> = [(context: ts.TransformationContext) => (sf: ts.SourceFile | ts.Bundle) => { const visitor = (node: ts.Node): ts.Node => { if (node.kind === ts.SyntaxKind.ClassDeclaration) { const clz = node as ts.ClassDeclaration; // For demo purposes, transform the class name in the .d.ts output return ts.updateClassDeclaration( clz, clz.decorators, node.modifiers, ts.createIdentifier('NEWNAME'), clz.typeParameters, clz.heritageClauses, clz.members); } return ts.visitEachChild(node, visitor, context); }; return visitor(sf) as ts.SourceFile; }]; return {afterDeclarations}; } }