@tibco-tcstk/component-template
Version:
TIBCO Cloud Composer Component to create Schematics in your TIBCO Cloud Application
530 lines (498 loc) • 22.7 kB
text/typescript
import {
apply,
chain,
mergeWith,
Rule,
SchematicContext,
SchematicsException,
template,
Tree,
url
} from "@angular-devkit/schematics";
import {
getWorkspace,
getProjectFromWorkspace,
findModuleFromOptions,
parseName,
addEntryComponentToModule,
buildRelativePath,
InsertChange,
ModuleOptions,
addDeclarationToModule,
addExportToModule, getSourceFile, addPackageJsonDependency, NodeDependency, addImportToModule, NodeDependencyType
} from "schematics-utilities";
import {strings} from "@angular-devkit/core";
import {classify, dasherize} from "@angular-devkit/core/src/utils/strings";
// import {typescript} from "schematics-utilities/dist/cdk";
// import {addDeclarationToModule, addExportToModule} from "../schematics-angular-utils/ast-utils";
const stringUtils = {dasherize, classify};
export class AddToModuleContext {
source: any;
relativePath: string;
classifiedName: string;
}
export interface MyModuleOptions extends ModuleOptions {
module?: string;
name: string;
flat?: boolean;
path?: string;
skipImport?: boolean;
formRegistry?: string;
type?: string;
formRef?: string;
doAddRoutes?: boolean;
doAddConfig?: boolean;
doAddMapping?: boolean;
}
export function showHead(type: string, context: SchematicContext, options: any) {
// Show the options for this Schematics.
context.logger.info('-----------------------------------------------');
context.logger.info('--- ** TIBCO CLOUD COMPONENT GENERATOR ** ---');
context.logger.info('--- ** V3.3.0 ** ---');
context.logger.info('-----------------------------------------------');
context.logger.info('--- ** TYPE: ' + type.toUpperCase());
context.logger.info('-----------------------------------------------');
context.logger.info('Building TIBCO Cloud Component, with the following settings: ' + JSON.stringify(options));
}
export function addDependencies(options: any, context: SchematicContext, host: Tree) {
context.logger.log('info', "Name: " + options.name);
context.logger.info('Adding dependencies...');
const workspace = getWorkspace(host);
const project = getProjectFromWorkspace(
workspace,
// Takes the first project in case it's not provided by CLI
options.project ? options.project : Object.keys(workspace['projects'])[0]
);
const moduleName = options.name + 'Component';
const sourceLoc = './' + options.name + '/' + options.name + '.component';
context.logger.info('moduleName: ' + moduleName);
context.logger.info('sourceLoc: ' + sourceLoc);
context.logger.info('Project Root: ' + project.root);
if (!options.project) {
options.project = Object.keys(workspace.projects)[0];
}
if (options.path === undefined) {
const projectDirName = project.projectType === 'application' ? 'app' : 'lib';
options.path = `/${project.root}/src/${projectDirName}`;
}
options.module = findModuleFromOptions(host, options);
const moduleNameNew = options.name;
const parsedPath = parseName(options.path, moduleNameNew);
options.name = parsedPath.name;
context.logger.info('options.name: ' + options.name);
options.path = parsedPath.path;
context.logger.info('options.path: ' + options.path);
options.export = false;
context.logger.info('Installed Dependencies...');
return options;
}
// Function for form
export function formChain(options: any, type: string) {
return chain([
(_tree: Tree, context: SchematicContext) => {
showHead('CUSTOM FORM: ' + type, context, options);
},
// Adding dependencies
(host: Tree, context: SchematicContext) => {
context.logger.log('info', "Name: " + options.name);
context.logger.info('Adding dependencies...');
const workspace = getWorkspace(host);
const project = getProjectFromWorkspace(
workspace,
// Takes the first project in case it's not provided by CLI
options.project ? options.project : Object.keys(workspace['projects'])[0]
);
// updateFormRegistry(project, host, context);
const moduleName = options.name + 'Component';
const sourceLoc = './custom-forms/' + options.name + '/' + options.name + '.component';
context.logger.info('moduleName: ' + moduleName);
context.logger.info('sourceLoc: ' + sourceLoc);
context.logger.info('Project Root: ' + project.root);
if (!options.project) {
options.project = Object.keys(workspace.projects)[0];
}
if (options.path === undefined) {
const projectDirName = project.projectType === 'application' ? 'app' : 'lib';
options.path = `/${project.root}/src/${projectDirName}`;
}
options.module = findModuleFromOptions(host, options);
const moduleNameNew = options.name + '-' + type + '-form';
const parsedPath = parseName(options.path + '/custom-forms/', moduleNameNew);
console.log('parsedPath: ', parsedPath);
options.name = parsedPath.name;
context.logger.info('options.name: ' + options.name);
options.path = parsedPath.path;
context.logger.info('options.path: ' + options.path);
options.export = false;
// context.logger.info('Adding declaration: ' + options.export);
options.type = type;
console.warn('Options: ', options);
},
//Apply Template
mergeWith(apply(url('./files'), [
template({
...strings,
INDEX: options.index,
name: options.name,
}),
])),
addDeclarationToNgModule(options, false),
addEntryPointToNgModule(options),
() => {
options.module = options.module.replace('.ts', '.dev');
// console.warn('Options (DEV): ',options);
},
addDeclarationToNgModule(options, false),
addEntryPointToNgModule(options),
() => {
options.module = options.module.replace('.dev', '.build');
// console.warn('Options (BUILD): ',options);
},
addDeclarationToNgModule(options, false),
addEntryPointToNgModule(options),
() => {
options.formRegistry = '/src/app/form.registry.ts';
// console.warn('Options (Form Registry): ',options);
},
updateFormRegistry(options)
]);
}
// Function to update the form registry
export function updateFormRegistry(options: MyModuleOptions) {
return (host: Tree) => {
console.log('Updating form registry: ', options);
if (options.formRegistry && options.formRef && options.type && options.name) {
var fRegBuffer = host.read(options.formRegistry);
if (fRegBuffer) {
var content = fRegBuffer.toString();
// console.warn('Form Registry: ', content);
console.log('--- Updating Form Registry ---')
const recorder = host.beginUpdate(options.formRegistry);
console.log('- ID: ' + options.formRef);
console.log('- TYPE: ' + options.type);
console.log('- NAME: ' + options.name);
const toInsert = "\n new FormRecord('" + options.formRef + "', '" + options.type + "', '" + options.name + "', '" + options.name + " " + options.type + " Form', " + classify(options.name) + "Component),";
console.log('- INSERTING: ' + toInsert);
const searchString = 'FORM_REGISTRY = [';
recorder.insertRight(content.indexOf(searchString) + searchString.length, toInsert);
// Add the import statement
const importStatement = 'import {' + classify(options.name) + 'Component} from \'./custom-forms/' + dasherize(options.name) + '/' + dasherize(options.name) + '.component\';\n';
recorder.insertRight(0, importStatement);
host.commitUpdate(recorder);
}
}
return host;
};
}
// wrapper to create a rule
export function addEntryPointToNgModule(options: ModuleOptions): Rule {
return (host: Tree) => {
addEntryPoint(host, options);
return host;
};
}
// wrapper to create a rule
export function addDeclarationToNgModule(options: ModuleOptions, exports: boolean): Rule {
// console.log('addDeclarationToNgModule:' , options);
return (host: Tree) => {
addDeclaration(host, options);
if (exports) {
addExport(host, options);
}
return host;
};
}
// Function to add a declaration to a module
function addDeclaration(host: Tree, options: ModuleOptions) {
//console.log('Add Declaration', host);
// console.log('Adding Declaration:' , options.module);
const context = createAddToModuleContext(host, options);
const modulePath = options.module || '';
//console.log('context.source:',context.source);
//console.log('modulePath:',modulePath);
//console.log('context.classifiedName:',context.classifiedName);
//console.log('context.relativePath:',context.relativePath);
const declarationChanges = addDeclarationToModule(context.source,
modulePath,
context.classifiedName,
context.relativePath);
// console.log('declarationChanges:',declarationChanges);
const declarationRecorder = host.beginUpdate(modulePath);
// console.log('mp: ',modulePath);
for (const myChange of declarationChanges) {
// FIXED FOR ANGULAR 10; ADDED A CAST TO InsertChange
let newChange: InsertChange = <InsertChange>myChange;
//if (myChange instanceof InsertChange) {
declarationRecorder.insertLeft(newChange.pos, newChange.toAdd);
//console.log('change.pos:',newChange.pos , ' change.toAdd:',newChange.toAdd);
//}
}
// console.log('Commit Update: ' , declarationRecorder);
host.commitUpdate(declarationRecorder);
}
// Function to add an export to a module
function addExport(host: Tree, options: ModuleOptions) {
const context = createAddToModuleContext(host, options);
const modulePath = options.module || '';
const exportChanges = addExportToModule(context.source,
modulePath,
context.classifiedName,
context.relativePath);
const exportRecorder = host.beginUpdate(modulePath);
for (const change of exportChanges) {
// FIXED FOR ANGULAR 10; ADDED A CAST TO InsertChange
let newChange: InsertChange = <InsertChange>change;
//if (change instanceof InsertChange) {
exportRecorder.insertLeft(newChange.pos, newChange.toAdd);
//}
}
host.commitUpdate(exportRecorder);
}
// Function to add an Entry point to the module
function addEntryPoint(host: Tree, options: MyModuleOptions) {
const context = createAddToModuleContext(host, options);
const modulePath = options.module || '';
console.log('Adding Entry Point: ', modulePath);
// console.log('AE]context.source:',context.source);
// console.log('AE]modulePath:',modulePath);
// console.log('AE]context.classifiedName:',context.classifiedName);
// console.log('AE]context.relativePath:',context.relativePath);
const declarationChanges = addEntryComponentToModule(context.source,
modulePath,
context.classifiedName,
context.relativePath);
//console.log('declarationChanges:',declarationChanges);
const declarationRecorder = host.beginUpdate(modulePath);
// console.log('mp:',modulePath);
for (const change of declarationChanges) {
// FIXED FOR ANGULAR 10; ADDED A CAST TO InsertChange
let newChange: InsertChange = <InsertChange>change;
//if (change instanceof InsertChange) {
declarationRecorder.insertLeft(newChange.pos, newChange.toAdd);
// console.log('AE]change.pos:',change.pos , ' change.toAdd:',change.toAdd);
//}
}
host.commitUpdate(declarationRecorder);
}
//Function to build up the AddToModule Context class
function createAddToModuleContext(host: Tree, options: ModuleOptions): AddToModuleContext {
console.log('Create Add to Module Context: ', options.module);
const result = new AddToModuleContext();
console.log('options.module: ', options.module);
if (!options.module) {
throw new SchematicsException(`Module not found.`);
}
const text = host.read(options.module);
if (text === null) {
throw new SchematicsException(`File ${options.module} does not exist!`);
}
result.source = getSourceFile(host, options.module);
const componentPath = `${options.path}/`
+ stringUtils.dasherize(options.name) + '/'
+ stringUtils.dasherize(options.name)
+ '.component';
result.relativePath = buildRelativePath(options.module, componentPath);
result.classifiedName = stringUtils.classify(`${options.name}Component`);
return result;
}
export function addPackageDependencies(host: Tree, dependencies: NodeDependency[]): Tree {
//const dependencies: NodeDependency[] = [{ type: NodeDependencyType.Default, version: '4.17.10', name: 'lodash-es' }];
dependencies.forEach(dependency => addPackageJsonDependency(host, dependency));
return host;
}
// Function to import a library to node modules
function addImport(host: Tree, options: ModuleOptions, lib: string, importPath: string) {
if (!options.module) {
throw new SchematicsException(`Module not found.`);
}
const modulePath = options.module || '';
console.log('Adding Import to Point: ', modulePath);
console.log('Library to Import: ' + lib)
console.log(' Import Path: ' + importPath);
// @ts-ignore
const importChanges = addImportToModule(getSourceFile(host, options.module), modulePath, lib, importPath);
// TODO: Fix this to update to (schematics-utilities - 2.0.1)
/*
//const sourceFile:typescript.SourceFile = getSourceFile(host, options.module);
const sourceFile:any = getSourceFile(host, options.module);
console.log('ADDING SOURCE FILE: ' , sourceFile);
const importChanges = addImportToModule(sourceFile, modulePath, lib, importPath );
console.log('DONE ADDING SOURCE FILE: ' , importChanges);*/
const declarationRecorder = host.beginUpdate(modulePath);
for (const change of importChanges) {
// FIXED FOR ANGULAR 10; ADDED A CAST TO InsertChange
let newChange: InsertChange = <InsertChange>change;
//if (change instanceof InsertChange) {
declarationRecorder.insertLeft(newChange.pos, newChange.toAdd);
//console.log('change.pos:',change.pos , ' change.toAdd:',change.toAdd);
//}
}
host.commitUpdate(declarationRecorder);
}
export function addImportToNgModule(options: ModuleOptions, lib: string, importPath: string): Rule {
return (host: Tree) => {
addImport(host, options, lib, importPath);
return host;
};
}
export function addSpotfireLibs(): Rule {
return (host: Tree) => {
//console.log(' ' + host + ' ' + context);
console.log('Adding Spotfire Libraries...');
const dependencies: NodeDependency[] = [
//TODO: make versions configurable
{type: NodeDependencyType.Default, version: '^0.16.0', name: '@tibco/spotfire-wrapper'},
{type: NodeDependencyType.Default, version: '^3.3.0', name: '@tibco-tcstk/tc-spotfire-lib'}];
addPackageDependencies(host, dependencies);
console.log('Spotfire Libraries, added to package.json. Please run "npm install" to install them...');
return host;
}
}
export class routeConfig {
path: string;
component: string;
configResolverName: string;
resolver: string;
useClaimsResolver: boolean
}
/*
*/
const sFSettingImport = "import {SettingsSpotfireComponent, SpotfireConfigResolver} from \"@tibco-tcstk/tc-spotfire-lib\";\n";
const sFSettingsString = " {\n" +
" path: 'spotfire-settings',\n" +
" component: SettingsSpotfireComponent,\n" +
" resolve: {\n" +
" spotfireConfigHolder: SpotfireConfigResolver,\n" +
" claimsHolder: ClaimsResolver\n" +
" }\n" +
" },";
const sFMappingImport = "import {\n" +
" SettingsSpotfireCreateCaseMappingComponent,\n" +
" SpotfireMarkingLiveappsConfigResolver\n" +
"} from \"@tibco-tcstk/tc-spotfire-lib\";\n";
const sFMappingString = "\n" +
" {\n" +
" path: 'spotfire-create-live-apps-case-mapping',\n" +
" component: SettingsSpotfireCreateCaseMappingComponent,\n" +
" resolve: {\n" +
" spotfireMappingConfigHolder: SpotfireMarkingLiveappsConfigResolver,\n" +
" claimsHolder: ClaimsResolver\n" +
" }\n" +
" },";
const sfConfigResolver = "\n SpotfireConfigResolver,";
const sfConfigResolverDef = "\n ,spotfireConfigHolder: SpotfireConfigResolver";
const sfMarkingResolver = "\n SpotfireMarkingLiveappsConfigResolver,";
const sfMarkingResolverDef = "\n ,spotfireMappingConfigHolder: SpotfireMarkingLiveappsConfigResolver";
// import {SpotfireConfigResolver} from '@tibco-tcstk/tc-spotfire-lib';
const sFSettingResolverImport = "import {SpotfireConfigResolver} from '@tibco-tcstk/tc-spotfire-lib';\n";
// import {SpotfireMarkingLiveappsConfigResolver} from '@tibco-tcstk/tc-spotfire-lib';
const sFSettingMappingImport = "import {SpotfireMarkingLiveappsConfigResolver} from '@tibco-tcstk/tc-spotfire-lib';\n";
// Function to update the route configuration
export function addSFRoutes(options: MyModuleOptions) {
console.log('Spotfire Routes:');
return (host: Tree) => {
if (options.doAddRoutes) {
console.log('Adding Spotfire Routes...');
const doSFMapping = options.doAddMapping;
// Adding the configuration route
const configST = 'CONFIGURATION_ROUTE_CONFIG = [';
const routeLocation = 'src/app/route-config/starter-app-route-config/configuration-route-config/configuration-route-config.ts';
host = insertIntoFile(host, routeLocation, [''], sFSettingImport, 0);
host = insertIntoFile(host, routeLocation, [configST], sFSettingsString, 0);
if (doSFMapping) {
host = insertIntoFile(host, routeLocation, [''], sFMappingImport, 0);
host = insertIntoFile(host, routeLocation, [configST], sFMappingString, 0);
}
const providersST = 'CONFIGURATION_ROUTE_PROVIDERS = [';
host = insertIntoFile(host, routeLocation, [providersST], sfConfigResolver, 0);
if (doSFMapping) {
host = insertIntoFile(host, routeLocation, [providersST], sfMarkingResolver, 0);
}
const routeHomeLocation = 'src/app/route-config/starter-app-route-config/starter-app-route-config.ts';
const pathST = ["path: 'home',", "resolve: {", '}'];
host = insertIntoFile(host, routeHomeLocation, [''], sFSettingResolverImport, 0);
host = insertIntoFile(host, routeHomeLocation, pathST, sfConfigResolverDef, -1);
if (doSFMapping) {
host = insertIntoFile(host, routeHomeLocation, [''], sFSettingMappingImport, 0);
host = insertIntoFile(host, routeHomeLocation, pathST, sfMarkingResolverDef, -1);
}
} else {
console.log('Skipping Adding of Spotfire Routes......');
}
return host;
};
}
const sFMenuConfig = " ,{\n" +
" \"entry\": \"Spotfire\",\n" +
" \"icon\": \"tcs-spotfire-icon\",\n" +
" \"options\": [\n" +
" \"Settings\"\n" +
" ]\n" +
" }";
const sFMenuConfigMapping = ",{\n" +
" \"entry\": \"Spotfire\",\n" +
" \"icon\": \"tcs-spotfire-icon\",\n" +
" \"options\": [\n" +
" \"Settings\",\n" +
" \"Create Live Apps Case Mapping\"\n" +
" ]\n" +
" }\n";
// Function to update the MENU configuration
export function addSFMenuConfig(options: MyModuleOptions) {
console.log('Spotfire Menu Configurations:');
return (host: Tree) => {
if (options.doAddConfig) {
console.log('Adding Spotfire Menu Configurations');
const doSFMapping = options.doAddMapping;
const configMenuLocation = 'src/assets/config/configurationMenuConfig.json';
var fRegBuffer = host.read(configMenuLocation);
if (fRegBuffer) {
let content = fRegBuffer.toString();
let location = content.lastIndexOf("]") - 1;
const recorder = host.beginUpdate(configMenuLocation);
let toInsertAfter = sFMenuConfig;
if (doSFMapping) {
toInsertAfter = sFMenuConfigMapping;
}
recorder.insertRight(location, toInsertAfter);
host.commitUpdate(recorder);
}
} else {
console.log('Skipping Adding of Spotfire Menu Configurations...');
}
return host;
};
}
// Function to insert into a file
// Leave search string blank ("") to add to the beginning of the file
function insertIntoFile(host: Tree, fileName: string, searchString: string[], toInsertAfter: string, offset: number) {
var fRegBuffer = host.read(fileName);
if (fRegBuffer) {
var content = fRegBuffer.toString();
console.log('--- INSERTING INTO FILE (' + fileName + ') ---');
console.log('- SEARCH STRING: ' + searchString);
const recorder = host.beginUpdate(fileName);
console.log('- INSERTING: ' + toInsertAfter);
if (searchString[0] === "") {
recorder.insertRight(0, toInsertAfter);
} else {
let insertAt = offset;
let tempSearchString = content;
for (let st of searchString) {
console.log(st);
let tempLoc = tempSearchString.indexOf(st) + st.length;
tempSearchString = tempSearchString.substring(tempLoc);
insertAt += tempLoc;
}
recorder.insertRight(insertAt, toInsertAfter);
}
host.commitUpdate(recorder);
}
return host;
}
export function createFile(path: string, content: string): Rule {
return (tree: Tree, _context: SchematicContext) => {
tree.create(path, content);
return tree;
};
}