@dev-blinq/cucumber_client 1.0.1421-dev → 1.0.1421-stage

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.
Files changed (48) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +105 -105
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/toolbar.js +27 -29
  4. package/bin/assets/preload/unique_locators.js +1 -1
  5. package/bin/assets/preload/yaml.js +288 -275
  6. package/bin/assets/scripts/aria_snapshot.js +223 -220
  7. package/bin/assets/scripts/dom_attr.js +329 -329
  8. package/bin/assets/scripts/dom_parent.js +169 -174
  9. package/bin/assets/scripts/event_utils.js +94 -94
  10. package/bin/assets/scripts/pw.js +2050 -1949
  11. package/bin/assets/scripts/recorder.js +70 -45
  12. package/bin/assets/scripts/snapshot_capturer.js +147 -147
  13. package/bin/assets/scripts/unique_locators.js +163 -44
  14. package/bin/assets/scripts/yaml.js +796 -783
  15. package/bin/assets/templates/_hooks_template.txt +6 -2
  16. package/bin/assets/templates/utils_template.txt +16 -16
  17. package/bin/client/code_cleanup/find_step_definition_references.js +0 -1
  18. package/bin/client/code_gen/api_codegen.js +2 -2
  19. package/bin/client/code_gen/code_inversion.js +63 -2
  20. package/bin/client/code_gen/function_signature.js +4 -0
  21. package/bin/client/code_gen/page_reflection.js +823 -1003
  22. package/bin/client/code_gen/playwright_codeget.js +25 -3
  23. package/bin/client/cucumber/feature_data.js +2 -2
  24. package/bin/client/cucumber/project_to_document.js +8 -2
  25. package/bin/client/cucumber/steps_definitions.js +19 -3
  26. package/bin/client/cucumber_selector.js +4 -0
  27. package/bin/client/local_agent.js +3 -2
  28. package/bin/client/parse_feature_file.js +23 -26
  29. package/bin/client/playground/projects/env.json +2 -2
  30. package/bin/client/project.js +186 -202
  31. package/bin/client/recorderv3/bvt_init.js +363 -0
  32. package/bin/client/recorderv3/bvt_recorder.js +1008 -47
  33. package/bin/client/recorderv3/implemented_steps.js +2 -0
  34. package/bin/client/recorderv3/index.js +4 -283
  35. package/bin/client/recorderv3/scriptTest.js +1 -1
  36. package/bin/client/recorderv3/services.js +810 -142
  37. package/bin/client/recorderv3/step_runner.js +37 -11
  38. package/bin/client/recorderv3/step_utils.js +495 -39
  39. package/bin/client/recorderv3/update_feature.js +32 -13
  40. package/bin/client/recorderv3/wbr_entry.js +61 -0
  41. package/bin/client/recording.js +1 -0
  42. package/bin/client/upload-service.js +4 -2
  43. package/bin/client/utils/socket_logger.js +1 -1
  44. package/bin/index.js +4 -1
  45. package/bin/logger.js +3 -2
  46. package/bin/min/consoleApi.min.cjs +2 -3
  47. package/bin/min/injectedScript.min.cjs +16 -16
  48. package/package.json +19 -9
@@ -5,6 +5,8 @@ import path from "path";
5
5
  import { CodePage } from "./page_reflection.js";
6
6
  import { convertToIdentifier, escapeNonPrintables } from "./utils.js";
7
7
  import socketLogger from "../utils/socket_logger.js";
8
+ import fs from "fs";
9
+
8
10
  const findElementIdentifier = (node, step, userData, elements) => {
9
11
  if (node.key) {
10
12
  // incase of rerunning implemented steps
@@ -105,6 +107,11 @@ const _generateCodeFromCommand = (step, elements, userData) => {
105
107
  // handle element
106
108
  let element_name = null;
107
109
  let allStrategyLocators = null;
110
+ const codeLines = [];
111
+
112
+ if (_isCodeGenerationStep(step) === false)
113
+ return { codeLines, elements: elementsChanged ? elements : null, elementIdentifier, allStrategyLocators };
114
+
108
115
  if (_isCodeGenerationStep(step) && step.type !== Types.VERIFY_PAGE_SNAPSHOT) {
109
116
  allStrategyLocators = step.allStrategyLocators ?? splitToLocatorsGroups(step.locators);
110
117
  let node = null;
@@ -167,8 +174,6 @@ const _generateCodeFromCommand = (step, elements, userData) => {
167
174
  }
168
175
  }
169
176
 
170
- const codeLines = [];
171
-
172
177
  let line = null;
173
178
  let comment = null;
174
179
  let input = null;
@@ -363,7 +368,7 @@ const _generateCodeFromCommand = (step, elements, userData) => {
363
368
  codeLines.push(line);
364
369
  break;
365
370
  }
366
- case Types.VERIFY_PAGE_SNAPSHOT:
371
+ case Types.VERIFY_PAGE_SNAPSHOT: {
367
372
  comment = step.nestFrmLoc
368
373
  ? `// Verify page snapshot ${step.parameters[0]} in the frame ${step.selectors.iframe_src}`
369
374
  : `// Verify page snapshot ${step.parameters[0]}`;
@@ -372,7 +377,24 @@ const _generateCodeFromCommand = (step, elements, userData) => {
372
377
  codeLines.push(line);
373
378
  line = `await context.web.snapshotValidation(frameLocator, _param_0 , _params, ${JSON.stringify(options)}, this);`;
374
379
  codeLines.push(line);
380
+
381
+ const data = step.data;
382
+ if (data) {
383
+ try {
384
+ const { snapshot, fileName, filePath } = data;
385
+ const folderPath = process.env.BVT_TEMP_SNAPSHOTS_FOLDER ?? filePath;
386
+ const filePathWithName = path.join(folderPath, fileName);
387
+ if (!fs.existsSync(folderPath)) {
388
+ fs.mkdirSync(folderPath, { recursive: true });
389
+ }
390
+ fs.writeFileSync(filePathWithName, snapshot, "utf-8");
391
+ } catch (e) {
392
+ console.log(`Error saving snapshot file: ${e}`);
393
+ throw e;
394
+ }
395
+ }
375
396
  break;
397
+ }
376
398
  case Types.VERIFY_PAGE_CONTAINS_TEXT:
377
399
  line = "await context.web.verifyTextExistInPage( ";
378
400
  input = `${escapeNonPrintables(JSON.stringify(step.parameters[0]))}`;
@@ -41,10 +41,10 @@ const generateTestData = (featureFile) => {
41
41
  try {
42
42
  const fake = faker.helpers.fake(match[0]);
43
43
 
44
- if(fake === match[0]){
44
+ if (fake === match[0]) {
45
45
  continue;
46
46
  }
47
-
47
+
48
48
  otherFakeData.push({
49
49
  var: match[0],
50
50
  fake,
@@ -4,7 +4,13 @@ import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherki
4
4
  import { Feature } from "./feature.js";
5
5
  import { StepsDefinitions } from "./steps_definitions.js";
6
6
 
7
- export const projectDocument = (folder, featureName = null, scenarioName = null, supressErrors = false, errors = []) => {
7
+ export const projectDocument = (
8
+ folder,
9
+ featureName = null,
10
+ scenarioName = null,
11
+ supressErrors = false,
12
+ errors = []
13
+ ) => {
8
14
  const uuidFn = () => (23212).toString(16);
9
15
  const builder = new AstBuilder(uuidFn);
10
16
  const matcher = new GherkinClassicTokenMatcher();
@@ -59,4 +65,4 @@ export const projectDocument = (folder, featureName = null, scenarioName = null,
59
65
  // const documents = projectDocument(projectDir, featureName, scenarioName, true, errors);
60
66
  // const args = process.argv.slice(2);
61
67
 
62
- // console.log(JSON.stringify(documents));
68
+ // console.log(JSON.stringify(documents));
@@ -36,6 +36,19 @@ class StepsDefinitions {
36
36
  // }
37
37
  // });
38
38
  const { expressions, methods } = codePage;
39
+
40
+ if (codePage.fileContent.includes('from "./utils.mjs"')) {
41
+ const filePath = path.join(
42
+ this.baseFolder,
43
+ this.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features",
44
+ "step_definitions",
45
+ "utils.mjs"
46
+ );
47
+ const utilsCodePage = new CodePage(filePath);
48
+ utilsCodePage.generateModel();
49
+ methods.push(...utilsCodePage.methods);
50
+ }
51
+
39
52
  for (let i = 0; i < expressions.length; i++) {
40
53
  const expression = expressions[i];
41
54
  const pattern = expression.pattern;
@@ -45,7 +58,10 @@ class StepsDefinitions {
45
58
  if (method && expression.keyword && pattern && expression.methodName) {
46
59
  this.steps[pattern] = {
47
60
  // file: path.join(this.isTemp ? "__temp_features" : "features", mjsFile),
48
- file: path.join(this.isTemp ? process.env.tempFeaturesFolderPath ?? "__temp_features" : "features", mjsFile),
61
+ file: path.join(
62
+ this.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features",
63
+ mjsFile
64
+ ),
49
65
  functionName: expression.methodName,
50
66
  name: pattern,
51
67
  source: this.findKey(method.codePart, "source"),
@@ -56,7 +72,7 @@ class StepsDefinitions {
56
72
  }
57
73
  load(print = true, supressErrors = false, errors = []) {
58
74
  const mjsFiles = findFilesWithExtension(
59
- path.join(this.baseFolder, this.isTemp ? process.env.tempFeaturesFolderPath ?? "__temp_features" : "features"),
75
+ path.join(this.baseFolder, this.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features"),
60
76
  "mjs"
61
77
  );
62
78
  // console.log({ mjsFiles });
@@ -64,7 +80,7 @@ class StepsDefinitions {
64
80
  const mjsFile = mjsFiles[i];
65
81
  const filePath = path.join(
66
82
  this.baseFolder,
67
- this.isTemp ? process.env.tempFeaturesFolderPath ?? "__temp_features" : "features",
83
+ this.isTemp ? (process.env.tempFeaturesFolderPath ?? "__temp_features") : "features",
68
84
  mjsFile
69
85
  );
70
86
  const codePage = new CodePage(filePath);
@@ -117,6 +117,10 @@ if (deleteMjsFiles) {
117
117
  const utilsPath = path.join(__dirname, "../assets/templates/utils_template.txt");
118
118
  const utilsContent = fs.readFileSync(utilsPath, "utf8");
119
119
  const utilsFileName = stepsPath + "/utils.mjs";
120
+ // if stepsPath directory doesn't exist create it
121
+ if (!fs.existsSync(stepsPath)) {
122
+ fs.mkdirSync(stepsPath, { recursive: true });
123
+ }
120
124
  fs.writeFileSync(utilsFileName, utilsContent, "utf8");
121
125
  // copy hooks file to the steps directory
122
126
  const hooksTemplateFilePath = path.join(__dirname, "../assets/templates/_hooks_template.txt");
@@ -696,6 +696,7 @@ class LocalAgent {
696
696
  stepDiff: stepResult,
697
697
  });
698
698
  page.removeUnusedElements();
699
+ page.mergeSimilarElements();
699
700
  agent.scenarioReport.updateLastStep({
700
701
  code: {
701
702
  cleanFileNames: page.cleanFileNames,
@@ -809,12 +810,12 @@ class LocalAgent {
809
810
  } catch (err) {
810
811
  logger.error("Error reading memory file: " + err.message);
811
812
  }
812
- const screenshot = await agent.getScreenshot(agent.context);
813
+ //const screenshot = await agent.getScreenshot(agent.context);
813
814
  // check if the popup is open
814
815
  const popupResult = await agent.context.web.closeUnexpectedPopups(null, null);
815
816
  if (nodes) {
816
817
  nodes.memory = memory;
817
- nodes.screenshot = screenshot;
818
+ //nodes.screenshot = screenshot;
818
819
  if (popupResult.rerun === true) {
819
820
  nodes.rerun = true;
820
821
  }
@@ -1,37 +1,34 @@
1
- import {
2
- AstBuilder,
3
- GherkinClassicTokenMatcher,
4
- Parser,
5
- } from '@cucumber/gherkin'
6
- import { readFileSync, writeFileSync } from 'fs'
7
- import { loadArgs, showUsage, validateCLIArg } from './cli_helpers.js'
8
- let id =0;
9
- const uuidFn = () => (++id).toString(16)
10
- const builder = new AstBuilder(uuidFn)
11
- const matcher = new GherkinClassicTokenMatcher()
1
+ import { AstBuilder, GherkinClassicTokenMatcher, Parser } from "@cucumber/gherkin";
2
+ import { readFileSync, writeFileSync } from "fs";
3
+ import { loadArgs, showUsage, validateCLIArg } from "./cli_helpers.js";
4
+ let id = 0;
5
+ const uuidFn = () => (++id).toString(16);
6
+ const builder = new AstBuilder(uuidFn);
7
+ const matcher = new GherkinClassicTokenMatcher();
12
8
 
13
- const parser = new Parser(builder, matcher)
9
+ const parser = new Parser(builder, matcher);
14
10
 
15
11
  const parseFeatureFile = (featureFilePath) => {
16
- const source = readFileSync(featureFilePath, 'utf8')
17
- const gherkinDocument = parser.parse(source)
18
- return gherkinDocument
19
- }
12
+ const source = readFileSync(featureFilePath, "utf8");
13
+ const gherkinDocument = parser.parse(source);
14
+ return gherkinDocument;
15
+ };
20
16
 
21
- const args = loadArgs()
22
- const featureFilePath = args[0]
23
- const outputFilePath = args[1]
24
- const usage = 'Usage: node parse_feature_file.js <featureFilePath> [<outputFilePath>] \n\nExample: node parseFeatureFile.js ./features/my.feature ./features/my.feature.json\n\n'
17
+ const args = loadArgs();
18
+ const featureFilePath = args[0];
19
+ const outputFilePath = args[1];
20
+ const usage =
21
+ "Usage: node parse_feature_file.js <featureFilePath> [<outputFilePath>] \n\nExample: node parseFeatureFile.js ./features/my.feature ./features/my.feature.json\n\n";
25
22
  try {
26
- validateCLIArg(featureFilePath, 'featureFilePath')
23
+ validateCLIArg(featureFilePath, "featureFilePath");
27
24
  } catch (error) {
28
- showUsage(error, usage)
25
+ showUsage(error, usage);
29
26
  }
30
- const gherkinDocument = parseFeatureFile(featureFilePath)
27
+ const gherkinDocument = parseFeatureFile(featureFilePath);
31
28
  if (outputFilePath) {
32
- writeFileSync(outputFilePath, JSON.stringify(gherkinDocument, null, 2))
29
+ writeFileSync(outputFilePath, JSON.stringify(gherkinDocument, null, 2));
33
30
  } else {
34
- console.log(JSON.stringify(gherkinDocument, null, 2))
31
+ console.log(JSON.stringify(gherkinDocument, null, 2));
35
32
  }
36
33
 
37
- export { parseFeatureFile }
34
+ export { parseFeatureFile };
@@ -1,3 +1,3 @@
1
1
  {
2
- "baseUrl": "https://google.com"
3
- }
2
+ "baseUrl": "https://google.com"
3
+ }
@@ -1,220 +1,204 @@
1
+ // project.ts
1
2
  import { writeFileSync, readFileSync, readdirSync, existsSync, mkdirSync } from "fs";
2
- import { CodePage } from "./code_gen/page_reflection.js";
3
-
4
- import logger from "../logger.js";
5
3
  import path from "path";
6
4
  import { fileURLToPath } from "url";
5
+ // Keep the .js extensions because the compiled runtime modules are ESM .js files.
6
+ import { CodePage } from "./code_gen/page_reflection.js";
7
+ import logger from "../logger.js";
7
8
  import { findFilesWithExtension } from "./cucumber/steps_definitions.js";
8
9
  const __filename = fileURLToPath(import.meta.url);
9
10
  const __dirname = path.dirname(__filename);
10
-
11
- class Project {
12
- environment = null;
13
- pages = [];
14
- constructor(rootFolder) {
15
- this.rootFolder = rootFolder;
16
- this.stepsFolder = path.join(rootFolder, "features", "step_definitions");
17
- }
18
-
19
- async load() {
20
- this.pages = [];
21
- // load env.json from the project root folder
22
- let envFile = "";
23
- const envArgVal = checkForEnvArg();
24
- if (envArgVal) {
25
- envFile = envArgVal;
26
- } else if (process.env["BLINQ_ENV"]) {
27
- envFile = process.env["BLINQ_ENV"];
28
- } else if (existsSync(path.join(this.rootFolder, "env.json"))) {
29
- envFile = path.join(this.rootFolder, "env.json");
30
- } else {
31
- //list all the files in the environments directory use the first json file
32
- let files = readdirSync(path.join(this.rootFolder, "environments"));
33
- for (let i = 0; i < files.length; i++) {
34
- let file = files[i];
35
- if (file.endsWith(".json")) {
36
- envFile = path.join(this.rootFolder, "environments", file);
37
- break;
38
- }
39
- }
40
- }
41
- // const envFile = path.join(this.rootFolder, "env.json");
42
- if (!existsSync(envFile) || envFile === "") {
43
- throw new Error(
44
- `
45
- ======================================================
46
- env.json file not found in the project root folder
47
- or in the environments folder
48
- ======================================================
49
- `
50
- );
51
- }
52
- let envFileContent = readFileSync(envFile, "utf8");
53
- try {
54
- this.environment = JSON.parse(envFileContent);
55
- } catch (e) {
56
- throw new Error(
57
- `
58
- ======================================================
59
- unable to parse environment file
60
- ${e}
61
- ======================================================
62
- `
63
- );
11
+ function checkForEnvArg() {
12
+ for (const arg of process.argv.slice(2)) {
13
+ if (arg.startsWith("--")) {
14
+ const [key, value] = arg.split("=");
15
+ if (key.slice(2) === "env") {
16
+ return value ?? null;
17
+ }
18
+ }
64
19
  }
65
- if (!this.environment.baseUrl) {
66
- throw new Error(
67
- `
68
- ======================================================
69
- baseUrl not found in env.json file
70
- or in the environments folder
71
- ======================================================
72
- `
73
- );
20
+ return null;
21
+ }
22
+ function generatePrompt(promptFile, parameters, chat = true) {
23
+ let promptFileContent = readFileSync(promptFile, "utf8");
24
+ for (const key in parameters) {
25
+ const value = parameters[key];
26
+ promptFileContent = promptFileContent.replaceAll(`{${key}}`, value);
74
27
  }
75
- // list all the files in the project /features/step_definitions folder with mjs extension
76
- if (!existsSync(this.stepsFolder)) {
77
- return;
28
+ if (!chat)
29
+ return { promptFileContent };
30
+ const messages = [];
31
+ const parts = promptFileContent.split("####");
32
+ for (let i = 0; i < parts.length; i++) {
33
+ if (!parts[i].trim())
34
+ continue;
35
+ const role = parts[i];
36
+ const prompt = parts[i + 1];
37
+ messages.push({ role, content: (prompt ?? "").trim() });
38
+ i++;
78
39
  }
79
- try {
80
- // load the utils_template and save it to the project step_definitions folder
81
- const utilsPath = path.join(__dirname, "../assets/templates/utils_template.txt");
82
- const utilsContent = readFileSync(utilsPath, "utf8");
83
- const utilsFileName = this.stepsFolder + "/utils.mjs";
84
- writeFileSync(utilsFileName, utilsContent, "utf8");
85
- const hooksTemplateFilePath = path.join(__dirname, "../assets", "templates", "_hooks_template.txt");
86
- if (existsSync(hooksTemplateFilePath)) {
87
- const hooksFilePath = path.join(this.stepsFolder, "_hooks.mjs");
88
- const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
89
- writeFileSync(hooksFilePath, hooksContent, "utf8");
90
- }
91
- } catch (e) {
92
- logger.error("Error loading utils_template");
40
+ return { messages, promptFileContent };
41
+ }
42
+ class Project {
43
+ rootFolder;
44
+ stepsFolder;
45
+ environment = null;
46
+ pages = [];
47
+ constructor(rootFolder) {
48
+ this.rootFolder = rootFolder;
49
+ this.stepsFolder = path.join(rootFolder, "features", "step_definitions");
93
50
  }
94
-
95
- const files = findFilesWithExtension(this.stepsFolder, "mjs");
96
-
97
- //let files = readdirSync(this.stepsFolder);
98
-
99
- for (let i = 0; i < files.length; i++) {
100
- let file = files[i];
101
- if (file.startsWith("_")) {
102
- continue;
103
- }
104
- if (file.endsWith(".mjs")) {
105
- let fullFileName = this.rootFolder + "/features/step_definitions/" + file;
106
-
107
- // create a new CodePage object for each file
108
- let page = new CodePage(fullFileName);
109
- page.generateModel();
110
- this.pages.push(page);
111
- }
51
+ async load() {
52
+ this.pages = [];
53
+ // Resolve env file path
54
+ let envFile = "";
55
+ const envArgVal = checkForEnvArg();
56
+ if (envArgVal) {
57
+ envFile = envArgVal;
58
+ }
59
+ else if (process.env["BLINQ_ENV"]) {
60
+ envFile = process.env["BLINQ_ENV"];
61
+ }
62
+ else if (existsSync(path.join(this.rootFolder, "env.json"))) {
63
+ envFile = path.join(this.rootFolder, "env.json");
64
+ }
65
+ else {
66
+ // pick the first .json from environments/
67
+ const envDir = path.join(this.rootFolder, "environments");
68
+ const files = existsSync(envDir) ? readdirSync(envDir) : [];
69
+ for (let i = 0; i < files.length; i++) {
70
+ const file = files[i];
71
+ if (file.endsWith(".json")) {
72
+ envFile = path.join(envDir, file);
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ if (!existsSync(envFile) || envFile === "") {
78
+ throw new Error(`
79
+ ======================================================
80
+ env.json file not found in the project root folder
81
+ or in the environments folder
82
+ ======================================================
83
+ `);
84
+ }
85
+ const envFileContent = readFileSync(envFile, "utf8");
86
+ try {
87
+ this.environment = JSON.parse(envFileContent);
88
+ }
89
+ catch (e) {
90
+ throw new Error(`
91
+ ======================================================
92
+ unable to parse environment file
93
+ ${e}
94
+ ======================================================
95
+ `);
96
+ }
97
+ if (!this.environment.baseUrl) {
98
+ throw new Error(`
99
+ ======================================================
100
+ baseUrl not found in env.json file
101
+ or in the environments folder
102
+ ======================================================
103
+ `);
104
+ }
105
+ // Prepare step_definitions utilities
106
+ if (!existsSync(this.stepsFolder)) {
107
+ return this.environment.name;
108
+ }
109
+ try {
110
+ const utilsPath = path.join(__dirname, "../assets/templates/utils_template.txt");
111
+ const utilsContent = readFileSync(utilsPath, "utf8");
112
+ const utilsFileName = path.join(this.stepsFolder, "utils.mjs");
113
+ writeFileSync(utilsFileName, utilsContent, "utf8");
114
+ const hooksTemplateFilePath = path.join(__dirname, "../assets", "templates", "_hooks_template.txt");
115
+ if (existsSync(hooksTemplateFilePath)) {
116
+ const hooksFilePath = path.join(this.stepsFolder, "_hooks.mjs");
117
+ const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
118
+ writeFileSync(hooksFilePath, hooksContent, "utf8");
119
+ }
120
+ }
121
+ catch {
122
+ logger.error("Error loading utils_template");
123
+ }
124
+ const files = findFilesWithExtension(this.stepsFolder, "mjs");
125
+ for (let i = 0; i < files.length; i++) {
126
+ const file = files[i];
127
+ if (file.startsWith("_"))
128
+ continue;
129
+ if (file.endsWith(".mjs")) {
130
+ const fullFileName = path.join(this.rootFolder, "features", "step_definitions", file);
131
+ const page = new CodePage(fullFileName);
132
+ page.generateModel();
133
+ this.pages.push(page);
134
+ }
135
+ }
136
+ return this.environment.name;
112
137
  }
113
- return this.environment.name;
114
- }
115
- getPagesNames() {
116
- let result = [];
117
- this.pages.forEach((page) => {
118
- result.push(page.getName());
119
- });
120
- return result;
121
- }
122
- findMethodInPages(methodName) {
123
- for (const page of this.pages) {
124
- for (const method of page.methods) {
125
- if (method.name === methodName) {
126
- return { page, method };
127
- }
128
- }
138
+ getPagesNames() {
139
+ const result = [];
140
+ this.pages.forEach((page) => result.push(page.getName()));
141
+ return result;
129
142
  }
130
- return { page: null, method: null };
131
- }
132
-
133
- getProjectSignature() {
134
- let result = [];
135
- this.pages.forEach((page) => {
136
- page.getMethodsNames().forEach((methodName) => {
137
- result.push(page.getMethodInCommandFormat(methodName));
138
- });
139
- });
140
- return result;
141
- }
142
- getPage(pageName, createEmpty = false) {
143
- for (let i = 0; i < this.pages.length; i++) {
144
- if (this.pages[i].getName().toLowerCase() === pageName.toLowerCase()) {
145
- return this.pages[i];
146
- }
143
+ findMethodInPages(methodName) {
144
+ for (const page of this.pages) {
145
+ for (const method of page.methods) {
146
+ if (method.name === methodName) {
147
+ return { page, method };
148
+ }
149
+ }
150
+ }
151
+ return { page: null, method: null };
147
152
  }
148
- if (createEmpty) {
149
- let distFileName = this.stepsFolder + "/" + pageName + "_page.mjs";
150
- let page = new CodePage(distFileName);
151
- page.generateModel();
152
- this.setPage(pageName, page);
153
- return page;
153
+ getProjectSignature() {
154
+ const result = [];
155
+ this.pages.forEach((page) => {
156
+ page.getMethodsNames().forEach((methodName) => {
157
+ result.push(page.getMethodInCommandFormat(methodName));
158
+ });
159
+ });
160
+ return result;
154
161
  }
155
- return null;
156
- }
157
- setPage(pageName, page) {
158
- for (let i = 0; i < this.pages.length; i++) {
159
- if (this.pages[i].getName().toLowerCase() === pageName.toLowerCase()) {
160
- this.pages[i] = page;
161
- }
162
+ getPage(pageName, createEmpty = false) {
163
+ for (let i = 0; i < this.pages.length; i++) {
164
+ if (this.pages[i].getName().toLowerCase() === pageName.toLowerCase()) {
165
+ return this.pages[i];
166
+ }
167
+ }
168
+ if (createEmpty) {
169
+ const distFileName = path.join(this.stepsFolder, `${pageName}_page.mjs`);
170
+ const page = new CodePage(distFileName);
171
+ page.generateModel();
172
+ this.setPage(pageName, page);
173
+ return page;
174
+ }
175
+ return null;
162
176
  }
163
- }
164
- createNewPage(name, _path) {
165
- let distFileName = this.stepsFolder + "/" + name + "_page.mjs";
166
- if (existsSync(distFileName)) {
167
- logger.error("Page already exists: " + distFileName);
168
- throw new Error("Page already exists: " + name + " - " + name + "_page.mjs");
177
+ setPage(pageName, page) {
178
+ for (let i = 0; i < this.pages.length; i++) {
179
+ if (this.pages[i].getName().toLowerCase() === pageName.toLowerCase()) {
180
+ this.pages[i] = page;
181
+ }
182
+ }
169
183
  }
170
- if (!existsSync(this.stepsFolder)) {
171
- mkdirSync(this.stepsFolder, { recursive: true });
184
+ createNewPage(name, _path) {
185
+ const distFileName = path.join(this.stepsFolder, `${name}_page.mjs`);
186
+ if (existsSync(distFileName)) {
187
+ logger.error("Page already exists: " + distFileName);
188
+ throw new Error(`Page already exists: ${name} - ${name}_page.mjs`);
189
+ }
190
+ if (!existsSync(this.stepsFolder)) {
191
+ mkdirSync(this.stepsFolder, { recursive: true });
192
+ }
193
+ const map = {
194
+ name,
195
+ path: _path ? `"${_path}"` : "null",
196
+ name_upper: name.charAt(0).toUpperCase() + name.slice(1),
197
+ };
198
+ const { promptFileContent } = generatePrompt(path.join(__dirname, "../assets/templates/page_template.txt"), map, false);
199
+ writeFileSync(distFileName, promptFileContent, "utf8");
200
+ // refresh pages list
201
+ void this.load();
172
202
  }
173
- let map = {
174
- name,
175
- path: _path ? `"${_path}"` : "null",
176
- name_upper: name.charAt(0).toUpperCase() + name.slice(1),
177
- };
178
-
179
- let content = generatePrompt(
180
- path.join(__dirname, "../assets/templates/page_template.txt"),
181
- map,
182
- false
183
- ).promptFileContent;
184
- writeFileSync(distFileName, content, "utf8");
185
- this.load();
186
- }
187
203
  }
188
- const generatePrompt = (promptFile, parameters, chat = true) => {
189
- let promptFileContent = readFileSync(promptFile, "utf8");
190
- for (const key in parameters) {
191
- const value = parameters[key];
192
- promptFileContent = promptFileContent.replaceAll(`{${key}}`, value);
193
- }
194
- if (!chat) return { promptFileContent };
195
- const messages = [];
196
- const parts = promptFileContent.split("####");
197
- for (let i = 0; i < parts.length; i++) {
198
- if (!parts[i].trim()) continue;
199
- const role = parts[i];
200
- const prompt = parts[i + 1];
201
- messages.push({ role, content: prompt.trim() });
202
- // console.error("####prompt####", `role ${role}ֿֿ`);
203
- // console.error(prompt.trim());
204
- i++;
205
- }
206
- return { messages, promptFileContent };
207
- };
208
-
209
- const checkForEnvArg = () => {
210
- for (let arg of process.argv.slice(2)) {
211
- if (arg.startsWith("--")) {
212
- const [key, value] = arg.split("=");
213
- if (key.slice(2) === "env") {
214
- return value;
215
- }
216
- }
217
- }
218
- return null;
219
- };
220
- export { Project };
204
+ export { Project, generatePrompt, checkForEnvArg };