@dev-blinq/cucumber_client 1.0.1353-dev → 1.0.1354-dev

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.
@@ -1,17 +1,15 @@
1
-
2
1
  const validateCLIArg = (arg, name) => {
3
2
  if (!arg) {
4
- throw new Error(`${name} is required`)
3
+ throw new Error(`${name} is required`);
5
4
  }
6
- }
5
+ };
7
6
  const showUsage = (error, usage) => {
8
- console.error(error.message)
9
- console.info(usage)
10
- process.exit(1)
11
- }
12
- const loadArgs = ()=>{
13
- const args = process.argv.slice(2)
14
- return args
15
- }
16
-
17
- export { validateCLIArg, loadArgs, showUsage };
7
+ console.error(error.message);
8
+ console.info(usage);
9
+ process.exit(1);
10
+ };
11
+ const loadArgs = () => {
12
+ const args = process.argv.slice(2);
13
+ return args;
14
+ };
15
+ export { validateCLIArg, loadArgs, showUsage };
@@ -1,11 +1,11 @@
1
1
  import { loadConfiguration, loadSupport, runCucumber } from "@dev-blinq/cucumber-js/api";
2
2
  import fs from "fs";
3
-
3
+ import os from "os";
4
+ import path from "path";
4
5
  import { parseStepTextParameters, toCucumberExpression, unEscapeNonPrintables } from "./utils.js";
5
- import { AstBuilder, GherkinClassicTokenMatcher, Parser, compile } from "@cucumber/gherkin";
6
- import { IdGenerator } from "@cucumber/messages";
6
+ import stream from "stream";
7
7
  import { testStringForRegex } from "../recorderv3/update_feature.js";
8
- import path from 'path';
8
+ import { generateTestData } from "./feature_data.js";
9
9
  class DataTable {
10
10
  constructor(dataTableDocument) {
11
11
  if (!dataTableDocument) {
@@ -453,43 +453,75 @@ const scenarioResolution = async (featureFilePath) => {
453
453
  if (!fs.existsSync(featureFilePath)) {
454
454
  throw new Error(`Feature file ${featureFilePath} does not exist`);
455
455
  }
456
- const newId = IdGenerator.uuid();
457
- const builder = new AstBuilder(newId);
458
- const matcher = new GherkinClassicTokenMatcher();
459
-
460
- const parser = new Parser(builder, matcher);
461
-
462
- // normalize the path to start with featuers/ if it's not cut the featureFielPath to only the part after features/
463
- let uri = featureFilePath.startsWith("features/")
464
- ? featureFilePath
465
- : "features/" + featureFilePath.split("features/")[1];
466
-
467
456
  const featureFileContent = fs.readFileSync(featureFilePath, "utf8");
468
- const gherkinDocument = parser.parse(featureFileContent, newId);
469
-
470
- const feature = new Feature(gherkinDocument, featureFileContent);
471
- //const scenario = feature.getScenario(scenarioName);
472
- //return scenario;
473
- return feature;
474
- };
475
- const getDocumentAndPickel = (featureName, featureContent, scenarioName) => {
476
- const newId = IdGenerator.uuid();
477
- const builder = new AstBuilder(newId);
478
- const matcher = new GherkinClassicTokenMatcher();
479
-
480
- const parser = new Parser(builder, matcher);
481
-
482
- // normalize the path to start with featuers/ if it's not cut the featureFielPath to only the part after features/
483
- let uri = `features/${featureName}.feature`;
484
-
485
- const gherkinDocument = parser.parse(featureContent, newId);
486
- const pickles = compile(gherkinDocument, uri, newId);
457
+ let tmpDir = null;
458
+ try {
459
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "ai-qa"));
460
+ const tmpFeaturePath = path.join(tmpDir, "features");
461
+ fs.mkdirSync(tmpFeaturePath);
462
+ const tmpFeatureFilePath = path.join(tmpFeaturePath, path.basename(featureFilePath));
463
+ let result = generateTestData(featureFilePath);
464
+ if (result.changed) {
465
+ fs.writeFileSync(tmpFeatureFilePath, result.newContent);
466
+ console.log("Fake data was generated for this scenario");
467
+ console.log("Variables:");
468
+ for (let key in result.variables) {
469
+ console.log(`${key}: ${result.variables[key].fake}`);
470
+ }
471
+ console.log("Other fake data:");
472
+ for (let i = 0; i < result.otherFakeData.length; i++) {
473
+ console.log(`${result.otherFakeData[i].var}: ${result.otherFakeData[i].fake}`);
474
+ }
475
+ } else {
476
+ fs.copyFileSync(featureFilePath, tmpFeatureFilePath);
477
+ }
478
+ const writable = new stream.Writable({
479
+ write: function (chunk, encoding, next) {
480
+ //console.log(chunk.toString());
481
+ next();
482
+ },
483
+ });
484
+ const environment = { cwd: tmpDir, stdout: writable, stderr: writable };
485
+ // load configuration from a particular file, and override a specific option
486
+ const provided = {
487
+ default: "--publish-quiet",
488
+ require: [tmpDir],
489
+ failFast: false,
490
+ };
487
491
 
488
- // Step 3: Find the specific scenario Pickle
489
- const pickle = pickles.find((pickle) => {
490
- return pickle.name === scenarioName;
491
- });
492
- return { gherkinDocument, pickle };
492
+ let gherkinDocument = null;
493
+ const { runConfiguration } = await loadConfiguration({ provided }, environment);
494
+ // load the support code upfront
495
+ const support = await loadSupport(runConfiguration, environment);
496
+ // run cucumber, using the support code we loaded already
497
+ await runCucumber({ ...runConfiguration, support }, environment, function (event) {
498
+ // if (event.source) {
499
+ // scenarioInfo.source = event.source.data;
500
+ // }
501
+ // if (event.pickle && event.pickle.name === scenarioName) {
502
+ // scenarioInfo.pickle = event.pickle;
503
+ // }
504
+ if (event.gherkinDocument) {
505
+ gherkinDocument = event.gherkinDocument;
506
+ }
507
+ //console.log(event);
508
+ //console.log(JSON.stringify(event, null, 2));
509
+ // console.log("");
510
+ });
511
+ const feature = new Feature(gherkinDocument, featureFileContent);
512
+ //const scenario = feature.getScenario(scenarioName);
513
+ //return scenario;
514
+ return feature;
515
+ } finally {
516
+ try {
517
+ if (tmpDir) {
518
+ fs.rmSync(tmpDir, { recursive: true });
519
+ }
520
+ } catch (e) {
521
+ console.error(
522
+ `An error has occurred while removing the temp folder at ${tmpDir}. Please remove it manually. Error: ${e}`
523
+ );
524
+ }
525
+ }
493
526
  };
494
-
495
- export { Feature, Scenario, Step, DataTable, Examples, scenarioResolution, getDocumentAndPickel };
527
+ export { Feature, Scenario, Step, DataTable, Examples, scenarioResolution };
@@ -971,7 +971,7 @@ class LocalAgent {
971
971
  async createNewStepLocal(
972
972
  featureName,
973
973
  cucumberStep,
974
- feature,
974
+ comments,
975
975
  userData,
976
976
  firstStep,
977
977
  previousTasks,
@@ -1087,7 +1087,7 @@ class LocalAgent {
1087
1087
  previousTasks,
1088
1088
  scenarioDocument,
1089
1089
  scenarioStepIndex,
1090
- comments: feature.comments,
1090
+ comments,
1091
1091
  featureFileText,
1092
1092
  recover,
1093
1093
  dumpConfig: this.dumpConfig,
@@ -104,7 +104,7 @@ class Project {
104
104
  this.pages.push(page);
105
105
  }
106
106
  }
107
- return envFile;
107
+ return this.environment.name;
108
108
  }
109
109
  getPagesNames() {
110
110
  let result = [];
@@ -50,7 +50,7 @@ async function findNestedFrameSelector(frame, obj) {
50
50
  const frameElement = await frame.frameElement();
51
51
  if (!frameElement) return;
52
52
  const selectors = await parent.evaluate((element) => {
53
- return window.getPWLocators(element);
53
+ return window.__bvt_Recorder.locatorGenerator.getElementLocators(element, { excludeText: true }).locators;
54
54
  }, frameElement);
55
55
  return findNestedFrameSelector(parent, { children: obj, selectors });
56
56
  } catch (e) {
@@ -269,7 +269,6 @@ export class BVTRecorder {
269
269
  const locator = await this.web.page.locator(selector);
270
270
  const snapshot = await locator.ariaSnapshot();
271
271
  return snapshot;
272
- // Triggering workflow
273
272
  };
274
273
 
275
274
  processObject = async ({ type, action, value }) => {
@@ -335,6 +334,7 @@ export class BVTRecorder {
335
334
  console.error("Error reading ai_config.json", error);
336
335
  }
337
336
  }
337
+ this.config = ai_config;
338
338
  const initScripts = {
339
339
  // recorderCjs: injectedScriptSource,
340
340
  scripts: [
@@ -623,6 +623,7 @@ export class BVTRecorder {
623
623
  this.pageSet.add(page);
624
624
 
625
625
  await page.waitForLoadState("domcontentloaded");
626
+
626
627
  // add listener for frame navigation on new tab
627
628
  this._addFrameNavigateListener(page);
628
629
  } catch (error) {
@@ -712,7 +713,6 @@ export class BVTRecorder {
712
713
  if (this.shouldTakeScreenshot) {
713
714
  await this.storeScreenshot(event);
714
715
  }
715
-
716
716
  this.sendEvent(this.events.onNewCommand, cmdEvent);
717
717
  this._updateUrlPath();
718
718
  }
@@ -852,6 +852,7 @@ export class BVTRecorder {
852
852
  parametersMap,
853
853
  envPath: this.envName,
854
854
  tags,
855
+ config: this.config,
855
856
  },
856
857
  this.bvtContext,
857
858
  {
@@ -906,6 +907,7 @@ export class BVTRecorder {
906
907
  // map: this.scenariosStepsMap,
907
908
  // });
908
909
  }
910
+
909
911
  async generateStepName({ commands, stepsNames, parameters, map }) {
910
912
  return await this.namesService.generateStepName({ commands, stepsNames, parameters, map });
911
913
  }
@@ -1189,8 +1191,8 @@ export class BVTRecorder {
1189
1191
  }
1190
1192
  async resetExecution({ tags = [] }) {
1191
1193
  // run after hooks followed by before hooks
1192
- await this.runAfterHooks({ tags });
1193
- await this.runBeforeHooks({ tags });
1194
+ await this.cleanupExecution({ tags });
1195
+ await this.initExecution({ tags });
1194
1196
  }
1195
1197
  }
1196
1198
 
@@ -13,7 +13,6 @@ const uuidFn = () => (++id).toString(16);
13
13
  const builder = new AstBuilder(uuidFn);
14
14
  const matcher = new GherkinClassicTokenMatcher();
15
15
  const parser = new Parser(builder, matcher);
16
-
17
16
  let i = 0;
18
17
  const getImplId = () => {
19
18
  return `I-${i++}`;
@@ -289,17 +288,17 @@ export const getImplementedSteps = async (projectDir) => {
289
288
  for (const tag of scenario.tags) {
290
289
  delete tag.location;
291
290
  }
292
- // for (const scenario of scenarios) {
293
- // for (const step of scenario.steps) {
294
- // if (step.templateIndex === undefined) {
295
- // const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
296
- // const index = implementedSteps.findIndex((istep) => {
297
- // return cleanStepName === istep.pattern;
298
- // });
299
- // step.templateIndex = index;
300
- // }
301
- // }
302
- // }
291
+ for (const scenario of scenarios) {
292
+ for (const step of scenario.steps) {
293
+ if (step.templateIndex === undefined) {
294
+ const cleanStepName = stepsDefinitions._stepNameToTemplate(step.text);
295
+ const index = implementedSteps.findIndex((istep) => {
296
+ return cleanStepName === istep.pattern;
297
+ });
298
+ step.templateIndex = index;
299
+ }
300
+ }
301
+ }
303
302
  }
304
303
  if (foundErrors.length > 0) {
305
304
  console.log("foundErrors", foundErrors);
@@ -1,8 +1,18 @@
1
+ /**
2
+ * @typedef {Object} NetworkEvent
3
+ * @property {import('playwright').Request} request
4
+ * @property {import('playwright').Response|null} response
5
+ * @property {string} id
6
+ * @property {number} timestamp
7
+ * @property {string} status - 'completed', 'failed'
8
+ */
9
+
1
10
  class NetworkMonitor {
2
11
  constructor() {
3
12
  this.networkId = 0;
4
- this.networkEvents = new Map();
13
+ /** @type {Map<string, NetworkEvent>} */
5
14
  this.requestIdMap = new Map();
15
+ this.networkEvents = new Map();
6
16
  /** @type {Map<import('playwright').Page, {responseListener: Function, requestFailedListener: Function}>} */
7
17
  this.pageListeners = new Map();
8
18
  }
@@ -12,7 +22,6 @@ class NetworkMonitor {
12
22
  * @param {import('playwright').Page} page
13
23
  */
14
24
  addNetworkEventListener(page) {
15
-
16
25
  // Create the listener functions
17
26
  const responseListener = async (response) => {
18
27
  const request = response.request();
@@ -201,7 +210,6 @@ class NetworkMonitor {
201
210
  // Try to get response body safely (only for successful responses)
202
211
  if (response && networkEvent.status === "completed") {
203
212
  try {
204
-
205
213
  const isBinary =
206
214
  !response.headers()["content-type"]?.includes("application/json") &&
207
215
  !response.headers()["content-type"]?.includes("text");
@@ -229,7 +237,6 @@ class NetworkMonitor {
229
237
  marshalledEvent.failureReason = request.failure()?.errorText || "Unknown error";
230
238
  }
231
239
 
232
-
233
240
  console.log("Marshalled network event:", marshalledEvent);
234
241
 
235
242
  return marshalledEvent;
@@ -246,7 +253,18 @@ class NetworkMonitor {
246
253
  }
247
254
  }
248
255
 
256
+ /**
257
+ *@returns {Promise<Object[]>}
258
+ * Get all marshalled network events
259
+ * This is useful for sending to the server or saving to a file.
260
+ * */
261
+ async getAllMarshalledNetworkEvents() {
262
+ const events = this.getAllNetworkEvents();
263
+ const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
264
+ return marshalledEvents;
265
+ }
249
266
 
267
+ /**
250
268
  * Get marshalled network events since this ID
251
269
  * @returns {Promise<Object[]>}
252
270
  * @param {number} sinceId
@@ -263,7 +281,6 @@ class NetworkMonitor {
263
281
  * @param {number} endId
264
282
  * @returns {Promise<Object[]>}
265
283
  */
266
-
267
284
  async getMarshalledNetworkEventsInRange(startId, endId) {
268
285
  const events = this.getNetworkEventsInRange(startId, endId);
269
286
  const marshalledEvents = await Promise.all(events.map((event) => this.marshallNetworkEvent(event)));
@@ -1,6 +1,5 @@
1
1
  import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
2
2
  import path from "path";
3
- import fs from "fs";
4
3
  import { generatePageName } from "../code_gen/playwright_codeget.js";
5
4
  import {
6
5
  executeStep,
@@ -12,6 +11,7 @@ import {
12
11
  saveRoutes,
13
12
  } from "./step_utils.js";
14
13
  import { escapeString, getExamplesContent } from "./update_feature.js";
14
+ import fs from "fs";
15
15
  import { locateDefinitionPath } from "../cucumber/steps_definitions.js";
16
16
  import { tmpdir } from "os";
17
17
 
@@ -78,7 +78,7 @@ export class BVTStepRunner {
78
78
  return tFilePath;
79
79
  }
80
80
 
81
- executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText }, options) => {
81
+ executeStepRemote = async ({ feature_file_path, scenario, tempFolderPath, stepText, config }, options) => {
82
82
  const { skipAfter = true, skipBefore = true } = options || {};
83
83
  const environment = {
84
84
  ...process.env,
@@ -110,7 +110,7 @@ export class BVTStepRunner {
110
110
  // ignore afterAll/after hooks
111
111
  support.afterTestCaseHookDefinitions = [];
112
112
  }
113
- if (skipBefore) {
113
+ if (skipBefore && !config.legacySyntax) {
114
114
  // ignore beforeAll/before hooks
115
115
  support.beforeTestCaseHookDefinitions = support.beforeTestCaseHookDefinitions.filter((hook) => {
116
116
  return hook.uri.endsWith("utils.mjs");
@@ -135,9 +135,7 @@ export class BVTStepRunner {
135
135
  }
136
136
  if (testStepResult.status === "UNDEFINED") {
137
137
  if (!errorMesssage) {
138
- errorMesssage = stepText
139
- ? `step ${JSON.stringify(stepText)} is ${testStepResult.status}`
140
- : testStepResult.message;
138
+ errorMesssage = `step ${JSON.stringify(stepText)} is ${testStepResult.status}`;
141
139
  if (info) {
142
140
  errInfo = info;
143
141
  }
@@ -193,7 +191,7 @@ export class BVTStepRunner {
193
191
  }
194
192
  };
195
193
 
196
- async runStep({ step, parametersMap, envPath, tags }, bvtContext, options) {
194
+ async runStep({ step, parametersMap, envPath, tags, config }, bvtContext, options) {
197
195
  let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
198
196
  if (bvtContext.web) {
199
197
  bvtContext.web.getCmdId = () => {
@@ -250,7 +248,7 @@ export class BVTStepRunner {
250
248
  } else {
251
249
  let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
252
250
  if (process.env.TEMP_RUN === "true") {
253
- console.log("Save routes in temp folder for running:", routesPath);
251
+ // console.log("Save routes in temp folder for running:", routesPath);
254
252
  if (existsSync(routesPath)) {
255
253
  console.log("Removing existing temp_routes_folder:", routesPath);
256
254
  rmSync(routesPath, { recursive: true });
@@ -283,12 +281,13 @@ export class BVTStepRunner {
283
281
  const stepExecController = new AbortController();
284
282
  this.#currentStepController = stepExecController;
285
283
  const { result, info } = await withAbort(async () => {
286
- return this.executeStepRemote(
284
+ return await this.executeStepRemote(
287
285
  {
288
286
  feature_file_path,
289
287
  tempFolderPath,
290
288
  stepText: step.text,
291
289
  scenario: "Temp Scenario",
290
+ config,
292
291
  },
293
292
  options
294
293
  );
@@ -213,14 +213,12 @@ const GherkinToObject = (gherkin) => {
213
213
  steps: [],
214
214
  };
215
215
  while (idx < lines.length && lines[idx].startsWith("@")) {
216
- skipEmptyLines();
217
216
  const tags = [...lines[idx].matchAll(/@([^@]+)/g)].map((match) => match[1].trim());
218
217
  scenario.tags.push(...(tags ?? []));
219
218
  idx++;
219
+ skipEmptyLines();
220
220
  }
221
221
 
222
- skipEmptyLines();
223
-
224
222
  if (idx < lines.length && (lines[idx].startsWith("Scenario:") || lines[idx].startsWith("Scenario Outline:"))) {
225
223
  scenario.name = lines[idx].substring(lines[idx].indexOf(":") + 1).trim();
226
224
  idx++;
@@ -243,32 +241,32 @@ const GherkinToObject = (gherkin) => {
243
241
  !lines[idx].startsWith("@")
244
242
  ) {
245
243
  const line = lines[idx++];
246
- if (line.startsWith("#")) {
247
- const comment = line;
248
- if (comment) {
249
- const command = {
250
- type: "comment",
251
- text: comment,
252
- };
253
- scenario.steps.push(command);
254
- }
255
- } else if (line.startsWith("Examples:")) {
256
- obj.hasParams = true;
257
- const command = {
244
+ let command;
245
+ if (line.startsWith("Examples:")) {
246
+ scenario.hasParams = true;
247
+ command = {
258
248
  type: "examples",
259
249
  lines: [],
260
250
  };
261
-
262
251
  while (idx < lines.length && lines[idx].startsWith("|")) {
263
252
  const line = lines[idx++];
264
253
  command.lines.push(line);
265
254
  }
266
255
  } else {
267
- scenario.steps.push({
268
- type: "step",
269
- text: line,
270
- });
256
+ if (line.startsWith("#")) {
257
+ command = {
258
+ type: "comment",
259
+ text: line,
260
+ };
261
+ } else {
262
+ command = {
263
+ type: "step",
264
+ text: line,
265
+ };
266
+ }
271
267
  }
268
+ scenario.steps.push(command);
269
+ skipEmptyLines();
272
270
  }
273
271
 
274
272
  return scenario;
@@ -277,7 +275,6 @@ const GherkinToObject = (gherkin) => {
277
275
  while (idx < lines.length) {
278
276
  const scenario = getScenario();
279
277
  if (scenario === -1) break;
280
-
281
278
  if (scenario.error) {
282
279
  return {
283
280
  error: scenario.error,
@@ -303,8 +300,7 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
303
300
  skipScenarioIndex = i;
304
301
  continue;
305
302
  }
306
- let scenarioContent = `${featureFileObject.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
307
-
303
+ let scenarioContent = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
308
304
  let tagsLine;
309
305
  if (scenario.tags?.length > 0) {
310
306
  tagsLine = `${scenario.tags.map((t) => `@${t}`).join(" ")}`;
@@ -327,7 +323,6 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
327
323
  if (skipScenarioIndex !== -1) {
328
324
  finalContent = results.join("\n") + "\n" + scenarioContent;
329
325
  }
330
-
331
326
  return finalContent;
332
327
  }
333
328
  export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
@@ -359,7 +359,7 @@ const runCucumber = async (
359
359
  await aiAgent.createNewStepLocal(
360
360
  featureName,
361
361
  cucumberStep,
362
- feature,
362
+ feature.comments,
363
363
  userData,
364
364
  first,
365
365
  previousTasks,
@@ -33,17 +33,12 @@ const findNextIdInFolder = (folder) => {
33
33
  // get temp file path from --temp-file arg
34
34
  const getTempFilePath = () => {
35
35
  let tempFilePath = null;
36
-
37
36
  for (const arg of process.argv) {
38
37
  const [key, path] = arg.split("=");
39
38
  if (key === "--temp-file" && !!path) {
40
39
  tempFilePath = path;
41
40
  }
42
41
  }
43
-
44
- if (tempFilePath === null) {
45
- tempFilePath = process.env.TEMP_FILE_PATH;
46
- }
47
42
  return tempFilePath;
48
43
  };
49
44
 
@@ -267,7 +267,6 @@ try {
267
267
  }
268
268
  if (validatePath !== "null") {
269
269
  await prevrunResult.context.stable.verifyPagePath(validatePath);
270
-
271
270
  }
272
271
  //finalCompare = true;
273
272
  } catch (e) {
package/bin/index.js CHANGED
@@ -13,4 +13,5 @@ export * from "./client/cucumber/feature_data.js";
13
13
  export * from "./client/cucumber/steps_definitions.js";
14
14
  export * from "./client/profiler.js";
15
15
  export * from "./client/code_cleanup/utils.js";
16
+
16
17
  export * from "./client/code_cleanup/find_step_definition_references.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1353-dev",
4
- "description": "",
3
+ "version": "1.0.1354-dev",
4
+ "description": " ",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
7
7
  "type": "module",
@@ -53,6 +53,7 @@
53
53
  "socket.io-client": "^4.7.5",
54
54
  "tunnel": "^0.0.6",
55
55
  "unzipper": "^0.12.3",
56
+ "win-ca": "^3.5.1",
56
57
  "winston": "^3.10.0",
57
58
  "winston-daily-rotate-file": "^4.7.1",
58
59
  "ws": "^8.16.0",
@@ -65,7 +66,6 @@
65
66
  "mocha": "^10.2.0",
66
67
  "readline-sync": "^1.4.10",
67
68
  "tsup": "^8.5.0",
68
- "typescript": "^5.8.3",
69
- "win-ca": "^3.5.1"
69
+ "typescript": "^5.8.3"
70
70
  }
71
71
  }