@o3r/core
Version:
Core of the Otter Framework
169 lines (168 loc) • 8.05 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ngGenerateStoreAction = void 0;
const path = require("node:path");
const core_1 = require("@angular-devkit/core");
const schematics_1 = require("@angular-devkit/schematics");
const schematics_2 = require("@o3r/schematics");
const ts = require("typescript");
/**
* Compute action name based on action type and given name
* @param aType
* @param aName
*/
const computeActionName = (aType, aName) => {
const names = aType.split('-');
return `${names[0]}-${aName}` + (names[1] ? `-${names[1]}` : '');
};
/**
* Add an Action to an Otter Store
* @param options
*/
function ngGenerateStoreActionFn(options) {
/**
* Edit .actions.ts file
* @param actionFilePath
* @param tree
* @param context
*/
const editActionFile = (actionFilePath, tree, context) => {
const actionType = options.actionType.replace('-custom-', '');
const name = (actionType ? computeActionName(actionType, options.actionName) : options.actionName) + (options.isCallAction ? '-from-api' : '');
const actionName = core_1.strings.camelize(name);
// const actionClassName = strings.capitalize(actionName);
const description = options.description ? core_1.strings.capitalize(options.description) : '';
const storeName = core_1.strings.camelize(options.storeName);
const labelName = `ACTION_${core_1.strings.underscore(name).toUpperCase()}`;
const actionId = `[${core_1.strings.capitalize(storeName)}] ${core_1.strings.underscore(name).replace(/_/g, ' ')}`;
let actionDefinitionTemplate = '';
let payloadType = '';
switch (options.actionType) {
case 'set': {
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<object /* TODO: Define type */>());`;
break;
}
case 'set-entities': {
payloadType = `Set${options.isCallAction ? 'AsyncStoreItem' : ''}EntitiesActionPayload`;
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<${payloadType}<object /* TODO: Define type */>>());`;
break;
}
case 'upsert-entities': {
payloadType = `Set${options.isCallAction ? 'AsyncStoreItem' : ''}EntitiesActionPayload`;
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<${payloadType}<object /* TODO: Define type */>>());`;
break;
}
case 'update': {
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<Partial<object /* TODO: Define type */>>());`;
break;
}
case 'update-entities': {
payloadType = `Update${options.isCallAction ? 'AsyncStoreItem' : ''}EntitiesActionPayload`;
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<${payloadType}<object /* TODO: Define type */>>());`;
break;
}
case 'clear': {
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName});`;
break;
}
case 'fail': {
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<{error: any}>());`;
break;
}
default: {
actionDefinitionTemplate = `export const ${actionName} = createAction(${labelName}, props<object /* TODO: Define type */>());`;
}
}
const labelTemplate = `const ${labelName} = '${actionId}';`;
const actionTemplate = `
${labelTemplate}
/**
* ${description}
*/
${actionDefinitionTemplate}`;
const sourceFile = ts.createSourceFile(actionFilePath, tree.read(actionFilePath).toString(), ts.ScriptTarget.ES2015, true);
const lastImport = (0, schematics_2.findLastNodeOfKind)(sourceFile, ts.SyntaxKind.ImportDeclaration) || sourceFile.getFirstToken();
if (!lastImport) {
context.logger.warn(`Action can not be added in ${actionFilePath}`);
return;
}
const recorder = tree.beginUpdate(actionFilePath);
let actionDeclarationNode;
const regExpDeclaration = new RegExp('const ACTION_.*=');
sourceFile.forEachChild((node) => {
if (ts.isVariableStatement(node) && regExpDeclaration.test(node.getText())) {
actionDeclarationNode = node;
}
});
if (actionDeclarationNode) {
recorder.insertRight(actionDeclarationNode.end, actionTemplate);
context.logger.info(`Your new action has been inserted in ${actionFilePath}`);
}
else {
context.logger.warn(`available action list can not be found in ${actionFilePath}. Inserting the action after last import.`);
recorder.insertRight(lastImport.end, actionTemplate);
}
tree.commitUpdate(recorder);
};
/**
* Edit .reducer.ts file
* @param reducerFilePath
* @param tree
* @param context
*/
const editReducerFile = (reducerFilePath, tree, context) => {
const actionType = options.actionType.replace('-custom-', '');
const name = (actionType ? computeActionName(actionType, options.actionName) : options.actionName) + (options.isCallAction ? '-from-api' : '');
const actionName = core_1.strings.camelize(name);
const reducerTemplate = ` on(actions.${actionName}, (state, _payload) => /* TODO: implement reducer action */ state),`;
const sourceFile = ts.createSourceFile(reducerFilePath, tree.read(reducerFilePath).toString(), ts.ScriptTarget.ES2015, true);
let reducerList;
const regExpDeclaration = new RegExp(': ReducerTypes<.*>\\[\\] =');
sourceFile.forEachChild((node) => {
if (ts.isVariableStatement(node) && regExpDeclaration.test(node.getText())) {
reducerList = node;
}
});
if (!reducerList) {
context.logger.error('invalid reducer file: Reducer list missing');
return;
}
const lastReducerItem = (0, schematics_2.findLastNodeOfKind)(sourceFile, ts.SyntaxKind.CallExpression, reducerList);
if (!lastReducerItem) {
context.logger.error('invalid reducer file: Empty reducer list');
return;
}
const recorder = tree.beginUpdate(reducerFilePath);
recorder.insertLeft(lastReducerItem.end, ',\n\n' + reducerTemplate);
tree.commitUpdate(recorder);
};
/**
* Create a new action in an existing store
* @param tree
* @param context
*/
const generateFiles = (tree, context) => {
const destination = (0, schematics_2.getDestinationPath)('@o3r/core:store', options.storeDirectory, tree, options.projectName);
const storeName = core_1.strings.dasherize(options.storeName);
const storeFolder = path.join(destination, storeName);
const actionFilePath = path.join(storeFolder, `${storeName}.actions.ts`);
const reducerFilePath = path.join(storeFolder, `${storeName}.reducer.ts`);
if (!tree.exists(actionFilePath) || !tree.exists(reducerFilePath)) {
context.logger.error(`The store ${storeName} is not found in ${destination}`);
return tree;
}
editActionFile(actionFilePath, tree, context);
editReducerFile(reducerFilePath, tree, context);
return tree;
};
return (0, schematics_1.chain)([
generateFiles,
options.skipLinter ? (0, schematics_1.noop)() : (0, schematics_2.applyEsLintFix)()
]);
}
/**
* Add an Action to an Otter Store
* @param options
*/
exports.ngGenerateStoreAction = (0, schematics_2.createOtterSchematic)(ngGenerateStoreActionFn);
//# sourceMappingURL=index.js.map