autoforce 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,241 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import context from "./context.js";
11
+ import { logError, logStep } from "./color.js";
12
+ import fs from "fs";
13
+ import { getFiles, filterJson } from "./util.js";
14
+ import { validateCommand, validateFunction, executeFunction, executeCommand, taskFunctions } from "./taskFunctions.js";
15
+ import prompts from "prompts";
16
+ export const TASKS_FOLDER = process.cwd() + "/commands/tasks";
17
+ export const SUBTASKS_FOLDER = process.cwd() + "/commands/subtasks";
18
+ export const NEW_FOLDER = process.cwd() + "/commands/new";
19
+ export function getTaskFolder(command) {
20
+ const folders = {
21
+ 'task': TASKS_FOLDER,
22
+ 'subtask': SUBTASKS_FOLDER,
23
+ 'tasks': TASKS_FOLDER,
24
+ 'subtasks': SUBTASKS_FOLDER,
25
+ 'new': NEW_FOLDER
26
+ };
27
+ return folders[command.toLowerCase()] || folders.tasks;
28
+ }
29
+ function getTaskLists(folder) {
30
+ const files = getFiles(folder, filterJson);
31
+ return files.map(filename => filename.split(".")[0]);
32
+ }
33
+ export function getTasks(folder = TASKS_FOLDER) {
34
+ const tasks = {};
35
+ for (const taskName of getTaskLists(folder)) {
36
+ tasks[taskName] = getTask(taskName, folder);
37
+ }
38
+ return tasks;
39
+ }
40
+ function getTask(taskName, folder) {
41
+ const filename = folder + "/" + taskName + ".json";
42
+ const content = fs.readFileSync(filename, "utf8");
43
+ try {
44
+ return JSON.parse(content);
45
+ }
46
+ catch (_a) {
47
+ throw new Error(`Verifique que el ${filename} sea json valido`);
48
+ }
49
+ }
50
+ function isCriteriaMet(criteria) {
51
+ if (!criteria) {
52
+ return true;
53
+ }
54
+ const { field, value } = criteria;
55
+ // si no viene valor solo verifica que tenga no este vacio
56
+ if (typeof value == 'undefined') {
57
+ return context.get(field);
58
+ ;
59
+ }
60
+ const result = context[field] == value;
61
+ return result;
62
+ }
63
+ export function helpTask(task) {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ console.log('Nombre:', task.name);
66
+ console.log('Descripcion:', task.description);
67
+ console.log('Guards:', task.guards);
68
+ console.log('Argumentos:', task.arguments);
69
+ return true;
70
+ });
71
+ }
72
+ export function validateTask(task) {
73
+ if (task.guards) {
74
+ // Valida que sea
75
+ }
76
+ // Pide datos de entrada y los deja en context
77
+ if (task.arguments) {
78
+ // Valida que sea
79
+ }
80
+ for (const step of task.steps) {
81
+ if (step.criteria) {
82
+ // Valida que sea
83
+ }
84
+ let validateStep = false;
85
+ if (typeof step.command === 'string') {
86
+ validateStep = validateCommand(step);
87
+ }
88
+ else if (typeof step.function === 'string') {
89
+ validateStep = validateFunction(step);
90
+ }
91
+ else if (typeof step.subtask === 'string') {
92
+ const subtask = getTask(step.subtask, SUBTASKS_FOLDER);
93
+ validateStep = validateTask(subtask);
94
+ }
95
+ else {
96
+ console.log('Step no tiene command ni function ni subtask');
97
+ }
98
+ if (!validateStep) {
99
+ return false;
100
+ }
101
+ }
102
+ return true;
103
+ }
104
+ export function runTask(task, taskContext, tabs = '') {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ // Valida que este ya esten las variables de enotorno y configuracion
107
+ if (task.guards) {
108
+ yield context.validate(task.guards);
109
+ }
110
+ // Pide datos de entrada y los deja en context
111
+ if (task.arguments) {
112
+ if (taskContext) {
113
+ context.setObject(taskContext);
114
+ }
115
+ yield context.askForArguments(task.arguments);
116
+ }
117
+ logStep(`[INICIO] ${task.name}`, tabs);
118
+ for (const step of task.steps) {
119
+ if (isCriteriaMet(step.criteria)) {
120
+ if (!(yield executeStep(step, tabs + '\t'))) {
121
+ return false;
122
+ }
123
+ }
124
+ }
125
+ logStep(`[FIN] ${task.name}`, tabs);
126
+ return true;
127
+ });
128
+ }
129
+ export function previewTask(task, tabs = '') {
130
+ return __awaiter(this, void 0, void 0, function* () {
131
+ logStep(`${task.name}: ${task.description}`, tabs);
132
+ for (const step of task.steps) {
133
+ previewStep(step, tabs);
134
+ }
135
+ });
136
+ }
137
+ function previewStep(step, tabs = '') {
138
+ if (step.criteria) {
139
+ logStep(`Si ${step.criteria.field} ${step.criteria.operator || '=='} ${step.criteria.value}`, tabs);
140
+ tabs += '\t';
141
+ }
142
+ if (step.subtask) {
143
+ tabs += '\t';
144
+ const subtask = getTask(step.subtask, SUBTASKS_FOLDER);
145
+ previewTask(subtask, tabs);
146
+ }
147
+ else {
148
+ logStep(`${step.name}`, tabs);
149
+ }
150
+ }
151
+ export function createObject(fields, values) {
152
+ const fieldArray = Array.isArray(fields) ? fields : Object.keys(fields);
153
+ const argsObject = {};
154
+ for (const value of values) {
155
+ const field = fieldArray.shift();
156
+ if (field) {
157
+ argsObject[field] = value;
158
+ }
159
+ }
160
+ return argsObject;
161
+ }
162
+ function runStep(step, tabs) {
163
+ return __awaiter(this, void 0, void 0, function* () {
164
+ if (typeof step.command === 'string') {
165
+ return executeCommand(step);
166
+ }
167
+ else if (typeof step.function === 'string') {
168
+ return yield executeFunction(step);
169
+ }
170
+ else if (typeof step.subtask === 'string') {
171
+ const subtask = getTask(step.subtask, SUBTASKS_FOLDER);
172
+ let stepContext = context.mergeArgs(step.arguments);
173
+ if (Array.isArray(stepContext)) {
174
+ stepContext = createObject(subtask.arguments, stepContext);
175
+ }
176
+ return yield runTask(subtask, stepContext, tabs);
177
+ }
178
+ throw new Error(`No se pudo ejecutar el step ${step.name} porque no tiene command, function o subtasks`);
179
+ });
180
+ }
181
+ function askForContinueOrRetry() {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ if (!context.isVerbose) {
184
+ return 'quit';
185
+ }
186
+ const answer = yield prompts([
187
+ {
188
+ type: "select",
189
+ name: "continue",
190
+ message: "No se pudo ejecutar el step, ¿que quiere hacer? ",
191
+ choices: [{ title: 'Salir', value: 'quit' }, { title: 'Continuar', value: 'continue' }, { title: 'Reintentar', value: 'retry' }],
192
+ }
193
+ ]);
194
+ return answer.continue;
195
+ });
196
+ }
197
+ function getStepError(step, stepName) {
198
+ return step.errorMessage ? context.merge(step.errorMessage) : stepName ? `Fallo el step ${stepName}` : '';
199
+ }
200
+ function executeStep(step, tabs) {
201
+ return __awaiter(this, void 0, void 0, function* () {
202
+ const stepName = step.name ? context.merge(step.name) : undefined;
203
+ if (stepName) {
204
+ logStep(`[INICIO] ${stepName}`, tabs);
205
+ }
206
+ let retry = false;
207
+ let success = false;
208
+ do {
209
+ try {
210
+ success = yield runStep(step, tabs);
211
+ if (!success) {
212
+ logError(getStepError(step, stepName), tabs);
213
+ // Si tiene un custom handler cuando hay un error
214
+ if (step.onError) {
215
+ const errorHandler = taskFunctions[step.onError];
216
+ if (typeof errorHandler === 'function') {
217
+ success = yield errorHandler();
218
+ }
219
+ }
220
+ }
221
+ }
222
+ catch (error) {
223
+ if (error instanceof Error) {
224
+ logError(error.message, tabs);
225
+ }
226
+ }
227
+ if (!success) {
228
+ const result = yield askForContinueOrRetry();
229
+ retry = result == 'retry';
230
+ success = result == 'continue';
231
+ }
232
+ } while (!success && retry);
233
+ if (stepName) {
234
+ logStep(`[FIN] ${stepName}`, tabs);
235
+ }
236
+ if (!success) {
237
+ process.exit(!context.isVerbose ? -1 : 0);
238
+ }
239
+ return success;
240
+ });
241
+ }
@@ -0,0 +1,14 @@
1
+ /// <reference types="handlebars" />
2
+ declare class TemplateEngine<T> {
3
+ _template: HandlebarsTemplateDelegate | undefined;
4
+ _rendered: string | undefined;
5
+ _extension: string;
6
+ _sourceFolder: string;
7
+ constructor(source: string, extension: string);
8
+ getTemplates(): string[];
9
+ read(templateName: string): void;
10
+ render(context: object, options?: RuntimeOptions): void;
11
+ save(filename: string, folder: string, options?: SaveTemplateOptions): void;
12
+ }
13
+ declare const _default: (source: string, extension: string) => TemplateEngine<unknown>;
14
+ export default _default;
@@ -0,0 +1,86 @@
1
+ import fs from "fs";
2
+ import Handlebars from "handlebars";
3
+ import { merge } from "./merge.js";
4
+ import { getFiles } from "./util.js";
5
+ const TEMPLATE_ROOT_FOLDER = process.cwd() + "/templates";
6
+ function isObjectEmpty(objectName) {
7
+ return (objectName &&
8
+ Object.keys(objectName).length === 0 &&
9
+ objectName.constructor === Object);
10
+ }
11
+ // Abre el archivo, y antes de devolver el contenido busca si tiene tags {{import subarchivos}} y los incorpora al mismo
12
+ function openTemplate(sourceFolder, templateName, extension) {
13
+ const source = `${sourceFolder}/${templateName}.${extension}`;
14
+ let content = fs.readFileSync(source, "utf8");
15
+ const regexp = /{{[ ]*(import)[ ]*([^}]+)}}/gi;
16
+ const matches = content.matchAll(regexp);
17
+ if (matches !== null) {
18
+ for (const match of matches) {
19
+ const [subfile, subextension] = match[2].trim().split(".");
20
+ const subcontent = openTemplate(sourceFolder, subfile, subextension || extension);
21
+ content = content.replace(match[0], subcontent);
22
+ }
23
+ }
24
+ return content;
25
+ }
26
+ class TemplateEngine {
27
+ constructor(source, extension) {
28
+ this._sourceFolder = `${TEMPLATE_ROOT_FOLDER}/${source}`;
29
+ if (!fs.existsSync(this._sourceFolder)) {
30
+ throw new Error(`La carpeta source ${this._sourceFolder} no existe!`);
31
+ }
32
+ this._extension = extension;
33
+ }
34
+ ;
35
+ getTemplates() {
36
+ const filterThisExtension = (file) => file.endsWith(`.${this._extension}`);
37
+ const templates = [];
38
+ const files = getFiles(this._sourceFolder, filterThisExtension, true, ['dictionary']);
39
+ for (const filename of files) {
40
+ const [name] = filename.split(".");
41
+ templates.push(name);
42
+ }
43
+ return templates;
44
+ }
45
+ read(templateName) {
46
+ const rawTemplate = openTemplate(this._sourceFolder, templateName, this._extension);
47
+ this._template = Handlebars.compile(rawTemplate);
48
+ }
49
+ render(context, options = {}) {
50
+ if (isObjectEmpty(context) || this._template === undefined) {
51
+ return;
52
+ }
53
+ this._rendered = this._template(context, options);
54
+ }
55
+ save(filename, folder, options = { create: true, overwrite: true }) {
56
+ let accion = "creo";
57
+ if (folder && !fs.existsSync(folder)) {
58
+ if (options.create) {
59
+ fs.mkdirSync(folder);
60
+ }
61
+ else {
62
+ throw new Error(`La carpeta ${folder} no existe!`);
63
+ }
64
+ }
65
+ if (!filename.endsWith("." + this._extension)) {
66
+ filename += "." + this._extension;
67
+ }
68
+ const destination = folder ? `${folder}/${filename}` : `${filename}`;
69
+ let content = this._rendered;
70
+ if (content) {
71
+ if (fs.existsSync(destination)) {
72
+ if (!options.overwrite) {
73
+ throw new Error(`El archivo ${folder} ya existe!`);
74
+ }
75
+ accion = "combino";
76
+ const existingContent = fs.readFileSync(destination, "utf8");
77
+ content = merge(content, existingContent, false);
78
+ }
79
+ fs.writeFileSync(destination, content);
80
+ console.log(`Se ${accion} el archivo ${filename} con exito!`);
81
+ }
82
+ }
83
+ }
84
+ export default (source, extension) => {
85
+ return new TemplateEngine(source, extension);
86
+ };
@@ -0,0 +1,31 @@
1
+ export declare const DOCS_FOLDER: string;
2
+ export declare const DICTIONARY_FOLDER: string;
3
+ export declare const WORKING_FOLDER: string;
4
+ export declare function sortByName(objA: {
5
+ Name: string;
6
+ }, objB: {
7
+ Name: string;
8
+ }): 0 | 1 | -1;
9
+ export declare function sortByLabel(objA: {
10
+ label?: string | null;
11
+ }, objB: {
12
+ label?: string | null;
13
+ }): 0 | 1 | -1;
14
+ export declare function verFecha(this: Date): string | Date;
15
+ export declare function getNamesByExtension(folder: string, extension: string): string[];
16
+ export declare function splitFilename(fullname: string, defaultFolder?: string): {
17
+ filename: string;
18
+ folder: string;
19
+ };
20
+ export declare const filterJson: (fullPath: string) => boolean;
21
+ export declare const filterDirectory: (fullPath: string) => boolean;
22
+ export declare const filterFiles: (fullPath: string) => boolean;
23
+ /**
24
+ * Agrega los elementos de newArray a baseArray, si no existen previamente en baseArray.
25
+ * @param {string[]} baseArray El array donde se agregan los elementos
26
+ * @param {string[]} newArray El array de elementos a agregar
27
+ */
28
+ export declare function addNewItems(baseArray: string[], newArray: string[]): void;
29
+ export declare function getFiles(source: string, filter?: (file: string) => boolean, recursive?: boolean, ignoreList?: string[]): string[];
30
+ export declare function convertNameToKey(name: string): string;
31
+ export declare function convertKeyToName(key: string): string;
@@ -0,0 +1,85 @@
1
+ import fs from "fs";
2
+ export const DOCS_FOLDER = process.cwd() + "/docs";
3
+ export const DICTIONARY_FOLDER = process.cwd() + "/docs/diccionarios";
4
+ export const WORKING_FOLDER = process.env.INIT_CWD || ".";
5
+ export function sortByName(objA, objB) {
6
+ return objA.Name > objB.Name ? 1 : objA.Name < objB.Name ? -1 : 0;
7
+ }
8
+ export function sortByLabel(objA, objB) {
9
+ return (objA.label && objB.label && objA.label > objB.label || !objB.label) ? 1 : (objA.label && objB.label && objA.label < objB.label || !objA.label) ? -1 : 0;
10
+ }
11
+ export function verFecha() {
12
+ try {
13
+ const fecha = new Date(this);
14
+ return fecha.toLocaleString("es", {
15
+ day: "numeric",
16
+ year: "2-digit",
17
+ month: "long"
18
+ });
19
+ }
20
+ catch (e) {
21
+ console.error(e);
22
+ return this;
23
+ }
24
+ }
25
+ // Devuelve la lista de nombres de archivos de una extension de una carpeta, sin la extension.
26
+ export function getNamesByExtension(folder, extension) {
27
+ const allFiles = fs.readdirSync(folder);
28
+ const filterFiles = [];
29
+ for (const fullname in allFiles) {
30
+ if (fullname.endsWith(extension)) {
31
+ filterFiles.push(fullname.replace("." + extension, ""));
32
+ }
33
+ }
34
+ return filterFiles;
35
+ }
36
+ export function splitFilename(fullname, defaultFolder = '') {
37
+ let filename = fullname;
38
+ let folder = defaultFolder;
39
+ const separatorIndex = fullname.lastIndexOf("/");
40
+ if (separatorIndex !== -1) {
41
+ folder = fullname.substring(0, separatorIndex);
42
+ filename = fullname.substring(separatorIndex + 1);
43
+ }
44
+ return { filename, folder };
45
+ }
46
+ export const filterJson = (fullPath) => fullPath.endsWith(".json");
47
+ export const filterDirectory = (fullPath) => fs.lstatSync(fullPath).isDirectory();
48
+ export const filterFiles = (fullPath) => !fs.lstatSync(fullPath).isDirectory();
49
+ /**
50
+ * Agrega los elementos de newArray a baseArray, si no existen previamente en baseArray.
51
+ * @param {string[]} baseArray El array donde se agregan los elementos
52
+ * @param {string[]} newArray El array de elementos a agregar
53
+ */
54
+ export function addNewItems(baseArray, newArray) {
55
+ for (const item of newArray) {
56
+ if (!baseArray.includes(item)) {
57
+ baseArray.push(item);
58
+ }
59
+ }
60
+ }
61
+ export function getFiles(source, filter = (file) => file !== undefined, recursive = false, ignoreList = []) {
62
+ const files = [];
63
+ for (const file of fs.readdirSync(source)) {
64
+ const fullPath = source + "/" + file;
65
+ const filtered = filter(fullPath);
66
+ if (!ignoreList.includes(file)) {
67
+ if (filtered) {
68
+ files.push(file);
69
+ }
70
+ if (fs.lstatSync(fullPath).isDirectory() && recursive) {
71
+ getFiles(fullPath, filter, recursive, ignoreList).forEach((x) => files.push(file + "/" + x));
72
+ }
73
+ }
74
+ }
75
+ return files;
76
+ }
77
+ export function convertNameToKey(name) {
78
+ return name.toLowerCase().replaceAll(/[ /]/g, '-');
79
+ }
80
+ export function convertKeyToName(key) {
81
+ return key.replaceAll('-', ' ')
82
+ .split(' ')
83
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
84
+ .join(' ');
85
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/lib/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import main from "./auto.js";
2
+ main();
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "autoforce",
3
+ "homepage": "https://sebastianclaros.github.io/autoforce",
4
+ "private": false,
5
+ "version": "0.1.1",
6
+ "description": "Developer Automation tool for Github / Gitlab and Salesforce projects.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/sebastianclaros/autoforce"
10
+ },
11
+ "main": "./lib/index.js",
12
+ "files": [
13
+ "lib/**/*"
14
+ ],
15
+ "type": "module",
16
+ "scripts": {
17
+ "prebuild": "rm -rf ./lib/",
18
+ "build": "tsc --project tsconfig.build.json",
19
+ "prettier": "prettier --write \"**/*.{css,html,js,json,ts,md,xml,yaml,yml}\"",
20
+ "test": "jest --config jest.config.js"
21
+ },
22
+ "dependencies": {
23
+ "@eslint/js": "^9.9.1",
24
+ "@types/jest": "29.4.0",
25
+ "@typescript-eslint/eslint-plugin": "5.54.0",
26
+ "@typescript-eslint/parser": "5.52.0",
27
+ "eslint": "^9.9.1",
28
+ "eslint-plugin-import": "^2.25.4",
29
+ "eslint-plugin-jest": "^26.1.2",
30
+ "husky": "^7.0.4",
31
+ "jest": "29.4.3",
32
+ "lint-staged": "^12.3.7",
33
+ "prettier": "^2.6.0",
34
+ "ts-jest": "29.0.5",
35
+ "ts-node": "^10.9.2",
36
+ "typescript": "4.9.5",
37
+ "typescript-eslint": "^8.3.0"
38
+ },
39
+ "devDependencies": {
40
+ "@octokit/graphql": "^8.1.1",
41
+ "@types/graphql": "^14.5.0",
42
+ "@types/jsforce": "^1.11.5",
43
+ "@types/prompts": "^2.4.9",
44
+ "graphql": "^16.9.0",
45
+ "graphql-request": "^7.1.0",
46
+ "gray-matter": "^4.0.3",
47
+ "handlebars": "^4.7.8",
48
+ "jsforce": "^3.4.1",
49
+ "octokit": "^4.0.2",
50
+ "openai": "^4.54.0",
51
+ "prompts": "^2.4.2"
52
+ },
53
+ "author": "Sebastian Claros <sclaros@gmail.com>",
54
+ "license": "MIT"
55
+ }