jest-preset-angular
Version:
Jest preset configuration for Angular projects
207 lines (206 loc) • 9.54 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceResources = replaceResources;
const typescript_1 = __importDefault(require("typescript"));
const constants_1 = require("../constants");
const isAfterVersion = (targetMajor, targetMinor) => {
const [major, minor] = typescript_1.default.versionMajorMinor.split('.').map((part) => parseInt(part));
if (major < targetMajor) {
return false;
}
else if (major > targetMajor) {
return true;
}
else {
return minor >= targetMinor;
}
};
const IS_TS_48 = isAfterVersion(4, 8);
const IS_AFTER_TS_50 = isAfterVersion(5, 0);
const shouldTransform = (fileName) => !fileName.endsWith('.ngfactory.ts') && !fileName.endsWith('.ngstyle.ts');
function replaceResources(program) {
return (context) => {
const typeChecker = program.getTypeChecker();
const resourceImportDeclarations = [];
const moduleKind = context.getCompilerOptions().module;
const nodeFactory = context.factory;
const visitNode = (node) => {
if (typescript_1.default.isClassDeclaration(node)) {
return visitClassDeclaration(nodeFactory, typeChecker, node, resourceImportDeclarations, moduleKind);
}
return typescript_1.default.visitEachChild(node, visitNode, context);
};
return (sourceFile) => {
if (!shouldTransform(sourceFile.fileName)) {
return sourceFile;
}
const updatedSourceFile = typescript_1.default.visitNode(sourceFile, visitNode);
if (resourceImportDeclarations.length) {
return nodeFactory.updateSourceFile(updatedSourceFile, typescript_1.default.setTextRange(nodeFactory.createNodeArray([...resourceImportDeclarations, ...updatedSourceFile.statements]), updatedSourceFile.statements));
}
return updatedSourceFile;
};
};
}
function visitClassDeclaration(nodeFactory, typeChecker, node, resourceImportDeclarations, moduleKind) {
var _a, _b, _c;
let decorators;
let modifiers;
if (IS_TS_48) {
(_a = node.modifiers) === null || _a === void 0 ? void 0 : _a.forEach((modifier) => {
if (typescript_1.default.isDecorator(modifier)) {
decorators !== null && decorators !== void 0 ? decorators : (decorators = []);
decorators.push(modifier);
}
else {
modifiers = modifiers !== null && modifiers !== void 0 ? modifiers : (modifiers = []);
modifiers.push(modifier);
}
});
}
else {
decorators = [...((_b = typescript_1.default.getDecorators(node)) !== null && _b !== void 0 ? _b : [])];
modifiers = [...((_c = typescript_1.default.getModifiers(node)) !== null && _c !== void 0 ? _c : [])];
}
if (!decorators || !decorators.length) {
return node;
}
decorators = decorators.map((current) => visitDecorator(nodeFactory, current, typeChecker, resourceImportDeclarations, moduleKind));
return IS_TS_48
? nodeFactory.updateClassDeclaration(node, [...decorators, ...(modifiers !== null && modifiers !== void 0 ? modifiers : [])], node.name, node.typeParameters, node.heritageClauses, node.members)
: nodeFactory.updateClassDeclaration(node, decorators, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
}
function visitDecorator(nodeFactory, node, typeChecker, resourceImportDeclarations, moduleKind) {
if (!isComponentDecorator(node, typeChecker)) {
return node;
}
if (!typescript_1.default.isCallExpression(node.expression)) {
return node;
}
const decoratorFactory = node.expression;
const args = decoratorFactory.arguments;
if (args.length !== 1 || !typescript_1.default.isObjectLiteralExpression(args[0])) {
return node;
}
const objectExpression = args[0];
const styleReplacements = [];
let properties = typescript_1.default.visitNodes(objectExpression.properties, (objExpressionNode) => typescript_1.default.isObjectLiteralElementLike(objExpressionNode)
? visitComponentMetadata(nodeFactory, objExpressionNode, resourceImportDeclarations, moduleKind)
: objExpressionNode);
if (styleReplacements.length) {
const styleProperty = nodeFactory.createPropertyAssignment(nodeFactory.createIdentifier(constants_1.STYLES), nodeFactory.createArrayLiteralExpression(styleReplacements));
properties = nodeFactory.createNodeArray([...properties, styleProperty]);
}
return nodeFactory.updateDecorator(node, nodeFactory.updateCallExpression(decoratorFactory, decoratorFactory.expression, decoratorFactory.typeArguments, [
nodeFactory.updateObjectLiteralExpression(objectExpression, properties),
]));
}
function visitComponentMetadata(nodeFactory, node, resourceImportDeclarations, moduleKind) {
if (!typescript_1.default.isPropertyAssignment(node) || typescript_1.default.isComputedPropertyName(node.name)) {
return node;
}
const name = node.name.text;
switch (name) {
case 'moduleId':
return undefined;
case constants_1.TEMPLATE_URL:
const url = getResourceUrl(node.initializer);
if (!url) {
return node;
}
const importName = createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind);
if (!importName) {
return node;
}
return nodeFactory.updatePropertyAssignment(node, nodeFactory.createIdentifier(constants_1.TEMPLATE), importName);
case constants_1.STYLES:
if (!typescript_1.default.isArrayLiteralExpression(node.initializer) && !typescript_1.default.isStringLiteralLike(node.initializer)) {
return node;
}
return undefined;
case constants_1.STYLE_URLS:
if (!typescript_1.default.isArrayLiteralExpression(node.initializer)) {
return node;
}
return undefined;
case constants_1.STYLE_URL:
if (!typescript_1.default.isStringLiteralLike(node.initializer)) {
return node;
}
return undefined;
default:
return node;
}
}
function getResourceUrl(node) {
if (!typescript_1.default.isStringLiteral(node) && !typescript_1.default.isNoSubstitutionTemplateLiteral(node)) {
return null;
}
return `${/^\.?\.\//.test(node.text) ? '' : './'}${node.text}`;
}
function isComponentDecorator(node, typeChecker) {
if (!typescript_1.default.isDecorator(node)) {
return false;
}
const origin = getDecoratorOrigin(node, typeChecker);
return !!(origin && origin.module === '@angular/core' && origin.name === constants_1.COMPONENT);
}
function createResourceImport(nodeFactory, url, resourceImportDeclarations, moduleKind = typescript_1.default.ModuleKind.ES2015) {
const urlLiteral = nodeFactory.createStringLiteral(url);
if (moduleKind < typescript_1.default.ModuleKind.ES2015) {
return nodeFactory.createCallExpression(nodeFactory.createIdentifier(constants_1.REQUIRE), [], [urlLiteral]);
}
else {
const importName = nodeFactory.createIdentifier(`__NG_CLI_RESOURCE__${resourceImportDeclarations.length}`);
let importDeclaration;
if (IS_AFTER_TS_50) {
importDeclaration = nodeFactory.createImportDeclaration(undefined, nodeFactory.createImportClause(false, importName, undefined), urlLiteral);
}
else {
importDeclaration = nodeFactory.createImportDeclaration(undefined, undefined, nodeFactory.createImportClause(false, importName, undefined), urlLiteral);
}
resourceImportDeclarations.push(importDeclaration);
return importName;
}
}
function getDecoratorOrigin(decorator, typeChecker) {
if (!typescript_1.default.isCallExpression(decorator.expression)) {
return null;
}
let identifier;
let name = '';
if (typescript_1.default.isPropertyAccessExpression(decorator.expression.expression)) {
identifier = decorator.expression.expression.expression;
name = decorator.expression.expression.name.text;
}
else if (typescript_1.default.isIdentifier(decorator.expression.expression)) {
identifier = decorator.expression.expression;
}
else {
return null;
}
const symbol = typeChecker.getSymbolAtLocation(identifier);
if (symbol && symbol.declarations && symbol.declarations.length > 0) {
const declaration = symbol.declarations[0];
let module;
if (typescript_1.default.isImportSpecifier(declaration)) {
name = (declaration.propertyName || declaration.name).text;
module = declaration.parent.parent.parent.moduleSpecifier.text;
}
else if (typescript_1.default.isNamespaceImport(declaration)) {
module = declaration.parent.parent.moduleSpecifier.text;
}
else if (typescript_1.default.isImportClause(declaration)) {
name = declaration.name.text;
module = declaration.parent.moduleSpecifier.text;
}
else {
return null;
}
return { name, module };
}
return null;
}
;