@simplysf/simply-utam-core 0.0.0 → 0.1.0

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 (64) hide show
  1. package/LICENSE.txt +206 -0
  2. package/README.md +98 -12
  3. package/lib/discovery/index.d.ts +1 -0
  4. package/lib/discovery/index.js +17 -0
  5. package/lib/discovery/index.js.map +1 -0
  6. package/lib/discovery/project-discovery.d.ts +55 -0
  7. package/lib/discovery/project-discovery.js +180 -0
  8. package/lib/discovery/project-discovery.js.map +1 -0
  9. package/lib/index.d.ts +8 -2
  10. package/lib/index.js +8 -2
  11. package/lib/index.js.map +1 -1
  12. package/lib/namespaces/index.d.ts +1 -0
  13. package/lib/namespaces/index.js +17 -0
  14. package/lib/namespaces/index.js.map +1 -0
  15. package/lib/namespaces/namespace-rewriter.d.ts +50 -0
  16. package/lib/namespaces/namespace-rewriter.js +223 -0
  17. package/lib/namespaces/namespace-rewriter.js.map +1 -0
  18. package/lib/navigator.d.ts +133 -5
  19. package/lib/navigator.js +224 -12
  20. package/lib/navigator.js.map +1 -1
  21. package/lib/overrides/index.d.ts +1 -0
  22. package/lib/overrides/index.js +17 -0
  23. package/lib/overrides/index.js.map +1 -0
  24. package/lib/overrides/overrides-merger.d.ts +63 -0
  25. package/lib/overrides/overrides-merger.js +280 -0
  26. package/lib/overrides/overrides-merger.js.map +1 -0
  27. package/lib/rules/index.d.ts +1 -0
  28. package/lib/rules/index.js +17 -0
  29. package/lib/rules/index.js.map +1 -0
  30. package/lib/rules/rules-generator.d.ts +49 -0
  31. package/lib/rules/rules-generator.js +199 -0
  32. package/lib/rules/rules-generator.js.map +1 -0
  33. package/lib/scaffold/index.d.ts +1 -0
  34. package/lib/scaffold/index.js +17 -0
  35. package/lib/scaffold/index.js.map +1 -0
  36. package/lib/scaffold/project-scaffolder.d.ts +148 -0
  37. package/lib/scaffold/project-scaffolder.js +313 -0
  38. package/lib/scaffold/project-scaffolder.js.map +1 -0
  39. package/lib/steps/expression-matcher.d.ts +42 -0
  40. package/lib/steps/expression-matcher.js +106 -0
  41. package/lib/steps/expression-matcher.js.map +1 -0
  42. package/lib/steps/gherkin-parser.d.ts +27 -0
  43. package/lib/steps/gherkin-parser.js +98 -0
  44. package/lib/steps/gherkin-parser.js.map +1 -0
  45. package/lib/steps/index.d.ts +4 -0
  46. package/lib/steps/index.js +20 -0
  47. package/lib/steps/index.js.map +1 -0
  48. package/lib/steps/snippet-generator.d.ts +34 -0
  49. package/lib/steps/snippet-generator.js +101 -0
  50. package/lib/steps/snippet-generator.js.map +1 -0
  51. package/lib/steps/step-scaffolder.d.ts +49 -0
  52. package/lib/steps/step-scaffolder.js +225 -0
  53. package/lib/steps/step-scaffolder.js.map +1 -0
  54. package/lib/test-environment.d.ts +99 -4
  55. package/lib/test-environment.js +302 -4
  56. package/lib/test-environment.js.map +1 -1
  57. package/package.json +34 -4
  58. package/templates/generator.config.json +13 -0
  59. package/templates/hello.feature +4 -0
  60. package/templates/hello.steps.mjs +7 -0
  61. package/templates/namespace-map.json +3 -0
  62. package/templates/utam.config.json +9 -0
  63. package/templates/wdio.conf.mjs +68 -0
  64. package/templates/wireit.json +37 -0
@@ -0,0 +1,313 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import * as fs from 'node:fs';
17
+ import * as path from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { discoverProject } from '../discovery/index.js';
20
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
21
+ /**
22
+ * Default location of external scaffold template files.
23
+ * Resolves to the templates directory in @simplysf/simply-utam-core whether in src or lib.
24
+ */
25
+ export const DEFAULT_TEMPLATES_DIR = path.resolve(currentDir, '..', '..', 'templates');
26
+ /**
27
+ * Standard recommended devDependencies for consuming UTAM with SimplyUTAM.
28
+ */
29
+ export const DEFAULT_REQUIRED_DEV_DEPENDENCIES = [
30
+ 'wireit',
31
+ 'utam',
32
+ 'salesforce-pageobjects',
33
+ 'wdio-utam-service',
34
+ 'chromedriver',
35
+ '@wdio/cli',
36
+ '@wdio/local-runner',
37
+ '@wdio/cucumber-framework',
38
+ '@wdio/spec-reporter',
39
+ '@wdio/allure-reporter',
40
+ 'allure-commandline',
41
+ '@salesforce/core',
42
+ '@simplysf/simply-utam',
43
+ ];
44
+ /**
45
+ * Loads an external template file from disk, performing token replacements.
46
+ *
47
+ * @param templateName - The filename of the template to load.
48
+ * @param templatesDir - The directory containing template files.
49
+ * @param tokens - Key-value replacements for {{token}} placeholders.
50
+ * @returns The resolved template content string.
51
+ * @throws If the template file does not exist.
52
+ */
53
+ export function loadTemplate(templateName, templatesDir = DEFAULT_TEMPLATES_DIR, tokens = {}) {
54
+ const filePath = path.join(templatesDir, templateName);
55
+ if (!fs.existsSync(filePath)) {
56
+ throw new Error(`Scaffold template not found: '${filePath}'`);
57
+ }
58
+ let content = fs.readFileSync(filePath, 'utf-8');
59
+ for (const [key, value] of Object.entries(tokens)) {
60
+ const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
61
+ content = content.replace(pattern, value);
62
+ }
63
+ return content;
64
+ }
65
+ /**
66
+ * Generates the generator.config.json content by loading its external template.
67
+ *
68
+ * @param sourceDir - The Salesforce source directory.
69
+ * @param appName - The application namespace name.
70
+ * @param templatesDir - Optional custom directory containing the template file.
71
+ * @returns Parsed JSON object for generator.config.json.
72
+ */
73
+ export function generateGeneratorConfig(sourceDir, appName, templatesDir = DEFAULT_TEMPLATES_DIR) {
74
+ const normalizedSource = sourceDir.replace(/^[./\\]+/, '').replace(/\\/g, '/');
75
+ const raw = loadTemplate('generator.config.json', templatesDir, {
76
+ sourceDir: normalizedSource,
77
+ appName,
78
+ });
79
+ return JSON.parse(raw);
80
+ }
81
+ /**
82
+ * Generates the utam.config.json content by loading its external template.
83
+ *
84
+ * @param templatesDir - Optional custom directory containing the template file.
85
+ * @returns Parsed JSON object for utam.config.json.
86
+ */
87
+ export function generateUtamConfig(templatesDir = DEFAULT_TEMPLATES_DIR) {
88
+ const raw = loadTemplate('utam.config.json', templatesDir);
89
+ return JSON.parse(raw);
90
+ }
91
+ /**
92
+ * Generates the wdio.conf.mjs configuration script content by loading its external template.
93
+ *
94
+ * @param sourceDir - The primary Salesforce source directory.
95
+ * @param templatesDir - Optional custom directory containing the template file.
96
+ * @returns Formatted JavaScript module text for wdio.conf.mjs.
97
+ */
98
+ export function generateWdioConfig(sourceDir, templatesDir = DEFAULT_TEMPLATES_DIR) {
99
+ const normalizedSource = sourceDir.replace(/^[./\\]+/, '').replace(/\\/g, '/');
100
+ return loadTemplate('wdio.conf.mjs', templatesDir, {
101
+ sourceDir: normalizedSource,
102
+ });
103
+ }
104
+ /**
105
+ * Generates the .utam/namespace-map.json content by loading its external template.
106
+ *
107
+ * @param appName - The application namespace name.
108
+ * @param templatesDir - Optional custom directory containing the template file.
109
+ * @returns Parsed JSON object for namespace-map.json.
110
+ */
111
+ export function generateNamespaceMap(appName, templatesDir = DEFAULT_TEMPLATES_DIR) {
112
+ const raw = loadTemplate('namespace-map.json', templatesDir, {
113
+ appName,
114
+ });
115
+ return JSON.parse(raw);
116
+ }
117
+ /**
118
+ * Generates the hello.feature starter Gherkin feature file content by loading its external template.
119
+ *
120
+ * @param templatesDir - Optional custom directory containing the template file.
121
+ * @returns Formatted Gherkin feature file text for hello.feature.
122
+ */
123
+ export function generateHelloFeature(templatesDir = DEFAULT_TEMPLATES_DIR) {
124
+ try {
125
+ return loadTemplate('hello.feature', templatesDir);
126
+ }
127
+ catch {
128
+ return `Feature: Salesforce UI Smoke Test\n\n Scenario: Log in and navigate to Salesforce Home\n Given I open the Salesforce application "Sales"\n`;
129
+ }
130
+ }
131
+ /**
132
+ * Generates the hello.steps.mjs starter Cucumber step definition script content by loading its external template.
133
+ *
134
+ * @param templatesDir - Optional custom directory containing the template file.
135
+ * @returns Formatted JavaScript module text for hello.steps.mjs.
136
+ */
137
+ export function generateHelloSteps(templatesDir = DEFAULT_TEMPLATES_DIR) {
138
+ try {
139
+ return loadTemplate('hello.steps.mjs', templatesDir);
140
+ }
141
+ catch {
142
+ return `import { Given } from '@wdio/cucumber-framework';\nimport { goToApplication } from '@simplysf/simply-utam';\n\nGiven('I open the Salesforce application {string}', async (appName) => {\n // Authenticates via Salesforce CLI frontdoor URL and opens the application home page\n await goToApplication(appName);\n});\n`;
143
+ }
144
+ }
145
+ /**
146
+ * Non-destructively injects standard UTAM Wireit scripts and task configurations into a package.json object.
147
+ * Loads task definitions from external wireit.json template.
148
+ *
149
+ * @param packageJson - The existing package.json object.
150
+ * @param templatesDir - Optional custom directory containing the template file.
151
+ * @returns An object containing the modified package.json and lists of added keys.
152
+ */
153
+ export function injectWireitConfiguration(packageJson, templatesDir = DEFAULT_TEMPLATES_DIR) {
154
+ const result = JSON.parse(JSON.stringify(packageJson));
155
+ result['scripts'] ??= {};
156
+ result['wireit'] ??= {};
157
+ const scripts = result['scripts'];
158
+ const wireit = result['wireit'];
159
+ const rawWireitTemplate = loadTemplate('wireit.json', templatesDir);
160
+ const wireitConfig = JSON.parse(rawWireitTemplate);
161
+ const standardScripts = wireitConfig.scripts ?? {};
162
+ const standardTasks = wireitConfig.wireit ?? {};
163
+ const addedScripts = [];
164
+ for (const [scriptName, scriptCommand] of Object.entries(standardScripts)) {
165
+ if (!scripts[scriptName]) {
166
+ scripts[scriptName] = scriptCommand;
167
+ addedScripts.push(scriptName);
168
+ }
169
+ }
170
+ const addedTasks = [];
171
+ for (const [taskName, taskConfig] of Object.entries(standardTasks)) {
172
+ if (!wireit[taskName]) {
173
+ wireit[taskName] = taskConfig;
174
+ addedTasks.push(taskName);
175
+ }
176
+ }
177
+ const updated = addedScripts.length > 0 || addedTasks.length > 0;
178
+ return { updated, packageJson: result, addedScripts, addedTasks };
179
+ }
180
+ /**
181
+ * Checks a package.json object for missing recommended devDependencies.
182
+ *
183
+ * @param packageJson - The target package.json object.
184
+ * @param requiredDependencies - Optional list of required dependency names.
185
+ * @returns Array of dependency names missing from both devDependencies and dependencies.
186
+ */
187
+ export function checkMissingDependencies(packageJson, requiredDependencies = DEFAULT_REQUIRED_DEV_DEPENDENCIES) {
188
+ const devDeps = packageJson['devDependencies'] || {};
189
+ const deps = packageJson['dependencies'] || {};
190
+ return requiredDependencies.filter((dep) => !devDeps[dep] && !deps[dep]);
191
+ }
192
+ function resolveSourceDir(projectDir, explicitSourceDir) {
193
+ if (explicitSourceDir) {
194
+ return explicitSourceDir;
195
+ }
196
+ const discovery = discoverProject(projectDir);
197
+ if (discovery.sfdxProjectFile && discovery.packageDirectories.length > 0) {
198
+ return discovery.defaultPackageDirectory ?? discovery.packageDirectories[0];
199
+ }
200
+ if (discovery.packageDirectories.length > 0) {
201
+ return discovery.packageDirectories[0];
202
+ }
203
+ return 'force-app';
204
+ }
205
+ function resolveAppName(packageJsonData, explicitAppName) {
206
+ if (explicitAppName) {
207
+ return explicitAppName;
208
+ }
209
+ if (typeof packageJsonData?.['name'] === 'string') {
210
+ return packageJsonData['name'].replace(/^@[^/]+\//, '');
211
+ }
212
+ return 'salesforce-app';
213
+ }
214
+ function writeScaffoldFiles(projectDir, filesToCreate, force, dryRun) {
215
+ const createdFiles = [];
216
+ const skippedFiles = [];
217
+ for (const item of filesToCreate) {
218
+ const targetPath = path.join(projectDir, item.relativePath);
219
+ if (fs.existsSync(targetPath) && !force) {
220
+ skippedFiles.push(item.relativePath);
221
+ }
222
+ else {
223
+ createdFiles.push(item.relativePath);
224
+ if (!dryRun) {
225
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
226
+ fs.writeFileSync(targetPath, item.content, 'utf-8');
227
+ }
228
+ }
229
+ }
230
+ return { createdFiles, skippedFiles };
231
+ }
232
+ /**
233
+ * Scaffolds standard UTAM configurations, Wireit tasks, and namespace maps in a project directory.
234
+ *
235
+ * @param options - Scaffolding options.
236
+ * @returns Results describing created, skipped, and modified files.
237
+ */
238
+ export function scaffoldProject(options) {
239
+ const projectDir = path.resolve(options?.projectDir ?? process.cwd());
240
+ const templatesDir = options?.templatesDir ?? DEFAULT_TEMPLATES_DIR;
241
+ const dryRun = options?.dryRun ?? false;
242
+ const force = options?.force ?? false;
243
+ const sourceDir = resolveSourceDir(projectDir, options?.sourceDir);
244
+ const packageJsonPath = path.join(projectDir, 'package.json');
245
+ let packageJsonData = null;
246
+ if (fs.existsSync(packageJsonPath)) {
247
+ try {
248
+ packageJsonData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
249
+ }
250
+ catch {
251
+ // Continue on read error
252
+ }
253
+ }
254
+ const appName = resolveAppName(packageJsonData, options?.appName);
255
+ const filesToCreate = [
256
+ {
257
+ relativePath: 'generator.config.json',
258
+ content: JSON.stringify(generateGeneratorConfig(sourceDir, appName, templatesDir), null, 2) + '\n',
259
+ },
260
+ {
261
+ relativePath: 'utam.config.json',
262
+ content: JSON.stringify(generateUtamConfig(templatesDir), null, 2) + '\n',
263
+ },
264
+ {
265
+ relativePath: 'wdio.conf.mjs',
266
+ content: generateWdioConfig(sourceDir, templatesDir),
267
+ },
268
+ {
269
+ relativePath: path.join('.utam', 'namespace-map.json'),
270
+ content: JSON.stringify(generateNamespaceMap(appName, templatesDir), null, 2) + '\n',
271
+ },
272
+ ];
273
+ const candidateUtamDirs = [
274
+ path.join(projectDir, sourceDir, 'test', 'utam'),
275
+ path.join(projectDir, sourceDir, 'tests', 'utam'),
276
+ path.join(projectDir, 'test', 'utam'),
277
+ path.join(projectDir, 'tests', 'utam'),
278
+ ];
279
+ const utamTestDirExists = candidateUtamDirs.some((dir) => fs.existsSync(dir));
280
+ if (!utamTestDirExists || force) {
281
+ filesToCreate.push({
282
+ relativePath: path.join(sourceDir, 'test', 'utam', 'features', 'hello.feature'),
283
+ content: generateHelloFeature(templatesDir),
284
+ }, {
285
+ relativePath: path.join(sourceDir, 'test', 'utam', 'step_definitions', 'hello.steps.mjs'),
286
+ content: generateHelloSteps(templatesDir),
287
+ });
288
+ }
289
+ const { createdFiles, skippedFiles } = writeScaffoldFiles(projectDir, filesToCreate, force, dryRun);
290
+ const modifiedFiles = [];
291
+ let updatedPackageJson;
292
+ if (packageJsonData) {
293
+ const injection = injectWireitConfiguration(packageJsonData, templatesDir);
294
+ if (injection.updated) {
295
+ modifiedFiles.push('package.json');
296
+ updatedPackageJson = injection.packageJson;
297
+ if (!dryRun) {
298
+ fs.writeFileSync(packageJsonPath, JSON.stringify(injection.packageJson, null, 2) + '\n', 'utf-8');
299
+ }
300
+ }
301
+ }
302
+ const missingDependencies = packageJsonData
303
+ ? checkMissingDependencies(packageJsonData)
304
+ : [...DEFAULT_REQUIRED_DEV_DEPENDENCIES];
305
+ return Promise.resolve({
306
+ createdFiles,
307
+ skippedFiles,
308
+ modifiedFiles,
309
+ updatedPackageJson,
310
+ missingDependencies,
311
+ });
312
+ }
313
+ //# sourceMappingURL=project-scaffolder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-scaffolder.js","sourceRoot":"","sources":["../../src/scaffold/project-scaffolder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { ParameterTypeRegistry, Expression } from '@cucumber/cucumber-expressions';
2
+ export interface RawExtractedExpression {
3
+ pattern: string;
4
+ isRegex: boolean;
5
+ flags?: string;
6
+ }
7
+ export interface CompiledStepExpression {
8
+ source: string;
9
+ isRegex: boolean;
10
+ expression: Expression;
11
+ }
12
+ /**
13
+ * Normalizes expression strings to eliminate trivial escaping variations when comparing.
14
+ *
15
+ * @param expr - Raw expression string.
16
+ * @returns Normalized expression string.
17
+ */
18
+ export declare function normalizeExpression(expr: string): string;
19
+ /**
20
+ * Statically parses step definition file content to extract registered step expressions
21
+ * without executing the file or loading modules at runtime.
22
+ *
23
+ * @param content - File content of step definitions.
24
+ * @returns Array of raw extracted string and regexp patterns.
25
+ */
26
+ export declare function extractStepExpressionsFromContent(content: string): RawExtractedExpression[];
27
+ /**
28
+ * Compiles raw extracted expressions into official Cucumber expression matchers.
29
+ *
30
+ * @param rawExpressions - Raw extracted expression definitions.
31
+ * @param registry - Optional Cucumber parameter type registry.
32
+ * @returns Array of compiled step expressions ready for matching.
33
+ */
34
+ export declare function compileStepExpressions(rawExpressions: RawExtractedExpression[], registry?: ParameterTypeRegistry): CompiledStepExpression[];
35
+ /**
36
+ * Checks if a given Gherkin step text matches any registered step definition expression.
37
+ *
38
+ * @param stepText - Raw step phrase text from a feature file.
39
+ * @param compiledExpressions - Compiled step expressions to test against.
40
+ * @returns True if a match is found, false otherwise.
41
+ */
42
+ export declare function matchStepAgainstExpressions(stepText: string, compiledExpressions: CompiledStepExpression[]): boolean;
@@ -0,0 +1,106 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { ParameterTypeRegistry, CucumberExpression, RegularExpression, } from '@cucumber/cucumber-expressions';
17
+ /**
18
+ * Normalizes expression strings to eliminate trivial escaping variations when comparing.
19
+ *
20
+ * @param expr - Raw expression string.
21
+ * @returns Normalized expression string.
22
+ */
23
+ export function normalizeExpression(expr) {
24
+ return expr.trim().replace(/\\'/g, "'").replace(/\\"/g, '"').replace(/\\\\/g, '\\');
25
+ }
26
+ /**
27
+ * Statically parses step definition file content to extract registered step expressions
28
+ * without executing the file or loading modules at runtime.
29
+ *
30
+ * @param content - File content of step definitions.
31
+ * @returns Array of raw extracted string and regexp patterns.
32
+ */
33
+ export function extractStepExpressionsFromContent(content) {
34
+ const expressions = [];
35
+ // Match string step definitions: Given('...', ...), When("...", ...), Then(`...`, ...)
36
+ const stringRegex = /(?:Given|When|Then|Step|DefineStep)\s*\(\s*(['"`])([\s\S]*?)\1\s*,/g;
37
+ let match;
38
+ while ((match = stringRegex.exec(content)) !== null) {
39
+ expressions.push({
40
+ pattern: match[2],
41
+ isRegex: false,
42
+ });
43
+ }
44
+ // Match RegExp step definitions: Given(/^...$/, ...), When(/.../i, ...)
45
+ const regexRegex = /(?:Given|When|Then|Step|DefineStep)\s*\(\s*\/((?:\\\/|[^/\r\n])+)\/([a-z]*)\s*,/g;
46
+ while ((match = regexRegex.exec(content)) !== null) {
47
+ expressions.push({
48
+ pattern: match[1],
49
+ isRegex: true,
50
+ flags: match[2],
51
+ });
52
+ }
53
+ return expressions;
54
+ }
55
+ /**
56
+ * Compiles raw extracted expressions into official Cucumber expression matchers.
57
+ *
58
+ * @param rawExpressions - Raw extracted expression definitions.
59
+ * @param registry - Optional Cucumber parameter type registry.
60
+ * @returns Array of compiled step expressions ready for matching.
61
+ */
62
+ export function compileStepExpressions(rawExpressions, registry = new ParameterTypeRegistry()) {
63
+ const compiled = [];
64
+ for (const raw of rawExpressions) {
65
+ try {
66
+ if (raw.isRegex) {
67
+ const regex = new RegExp(raw.pattern, raw.flags ?? '');
68
+ const regExpr = new RegularExpression(regex, registry);
69
+ compiled.push({
70
+ source: raw.pattern,
71
+ isRegex: true,
72
+ expression: regExpr,
73
+ });
74
+ }
75
+ else {
76
+ const cucExpr = new CucumberExpression(raw.pattern, registry);
77
+ compiled.push({
78
+ source: raw.pattern,
79
+ isRegex: false,
80
+ expression: cucExpr,
81
+ });
82
+ }
83
+ }
84
+ catch {
85
+ // Gracefully ignore expressions with invalid syntax
86
+ }
87
+ }
88
+ return compiled;
89
+ }
90
+ /**
91
+ * Checks if a given Gherkin step text matches any registered step definition expression.
92
+ *
93
+ * @param stepText - Raw step phrase text from a feature file.
94
+ * @param compiledExpressions - Compiled step expressions to test against.
95
+ * @returns True if a match is found, false otherwise.
96
+ */
97
+ export function matchStepAgainstExpressions(stepText, compiledExpressions) {
98
+ for (const item of compiledExpressions) {
99
+ const args = item.expression.match(stepText);
100
+ if (args !== null) {
101
+ return true;
102
+ }
103
+ }
104
+ return false;
105
+ }
106
+ //# sourceMappingURL=expression-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expression-matcher.js","sourceRoot":"","sources":["../../src/steps/expression-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAElB,MAAM,gCAAgC,CAAC;AAcxC;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACtF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iCAAiC,CAAC,OAAe;IAC/D,MAAM,WAAW,GAA6B,EAAE,CAAC;IAEjD,uFAAuF;IACvF,MAAM,WAAW,GAAG,qEAAqE,CAAC;IAC1F,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,WAAW,CAAC,IAAI,CAAC;YACf,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YACjB,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,MAAM,UAAU,GAAG,kFAAkF,CAAC;IACtG,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnD,WAAW,CAAC,IAAI,CAAC;YACf,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YACjB,OAAO,EAAE,IAAI;YACb,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;SAChB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CACpC,cAAwC,EACxC,WAAkC,IAAI,qBAAqB,EAAE;IAE7D,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAE9C,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAChB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACvD,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBACvD,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,GAAG,CAAC,OAAO;oBACnB,OAAO,EAAE,IAAI;oBACb,UAAU,EAAE,OAAO;iBACpB,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAC9D,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,GAAG,CAAC,OAAO;oBACnB,OAAO,EAAE,KAAK;oBACd,UAAU,EAAE,OAAO;iBACpB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oDAAoD;QACtD,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,QAAgB,EAAE,mBAA6C;IACzG,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { Parser } from '@cucumber/gherkin';
2
+ export type StepSemanticKeyword = 'Given' | 'When' | 'Then';
3
+ export interface ParsedGherkinStep {
4
+ keyword: StepSemanticKeyword;
5
+ rawKeyword: string;
6
+ text: string;
7
+ filePath: string;
8
+ line: number;
9
+ hasDataTable: boolean;
10
+ hasDocString: boolean;
11
+ }
12
+ /**
13
+ * Parses Gherkin source text into an AST using the official @cucumber/gherkin parser.
14
+ *
15
+ * @param content - Gherkin feature source text.
16
+ * @returns Parsed AST document representation.
17
+ */
18
+ export declare function parseGherkinDocument(content: string): ReturnType<Parser<unknown>['parse']>;
19
+ /**
20
+ * Traverses a Gherkin document AST and extracts all scenario, background, and rule steps,
21
+ * normalizing 'And' and 'But' keywords to their semantic parent keyword (Given, When, Then).
22
+ *
23
+ * @param content - Gherkin feature file content.
24
+ * @param filePath - Path to the feature file for error and location reporting.
25
+ * @returns Extracted steps with normalized semantic keywords.
26
+ */
27
+ export declare function extractStepsFromGherkin(content: string, filePath?: string): ParsedGherkinStep[];
@@ -0,0 +1,98 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import { Parser, AstBuilder, GherkinClassicTokenMatcher } from '@cucumber/gherkin';
17
+ import { IdGenerator } from '@cucumber/messages';
18
+ /**
19
+ * Parses Gherkin source text into an AST using the official @cucumber/gherkin parser.
20
+ *
21
+ * @param content - Gherkin feature source text.
22
+ * @returns Parsed AST document representation.
23
+ */
24
+ export function parseGherkinDocument(content) {
25
+ const builder = new AstBuilder(IdGenerator.uuid());
26
+ const matcher = new GherkinClassicTokenMatcher();
27
+ const parser = new Parser(builder, matcher);
28
+ return parser.parse(content);
29
+ }
30
+ /**
31
+ * Traverses a Gherkin document AST and extracts all scenario, background, and rule steps,
32
+ * normalizing 'And' and 'But' keywords to their semantic parent keyword (Given, When, Then).
33
+ *
34
+ * @param content - Gherkin feature file content.
35
+ * @param filePath - Path to the feature file for error and location reporting.
36
+ * @returns Extracted steps with normalized semantic keywords.
37
+ */
38
+ export function extractStepsFromGherkin(content, filePath = 'unknown.feature') {
39
+ let gherkinDocument;
40
+ try {
41
+ gherkinDocument = parseGherkinDocument(content);
42
+ }
43
+ catch {
44
+ // If parsing fails (e.g. invalid feature syntax), return empty list
45
+ return [];
46
+ }
47
+ if (!gherkinDocument?.feature) {
48
+ return [];
49
+ }
50
+ const steps = [];
51
+ function processSteps(stepNodes) {
52
+ let currentKeyword = 'Given';
53
+ for (const stepNode of stepNodes) {
54
+ const rawKeyword = stepNode.keyword ? stepNode.keyword.trim() : 'Given';
55
+ const text = stepNode.text ? stepNode.text.trim() : '';
56
+ if (rawKeyword === 'Given') {
57
+ currentKeyword = 'Given';
58
+ }
59
+ else if (rawKeyword === 'When') {
60
+ currentKeyword = 'When';
61
+ }
62
+ else if (rawKeyword === 'Then') {
63
+ currentKeyword = 'Then';
64
+ }
65
+ // 'And' or 'But' inherit currentKeyword
66
+ steps.push({
67
+ keyword: currentKeyword,
68
+ rawKeyword,
69
+ text,
70
+ filePath,
71
+ line: stepNode.location?.line ?? 0,
72
+ hasDataTable: Boolean(stepNode.dataTable?.rows && stepNode.dataTable.rows.length > 0),
73
+ hasDocString: Boolean(stepNode.docString?.content),
74
+ });
75
+ }
76
+ }
77
+ const children = gherkinDocument.feature.children ?? [];
78
+ for (const child of children) {
79
+ if (Array.isArray(child.background?.steps)) {
80
+ processSteps(child.background.steps);
81
+ }
82
+ if (Array.isArray(child.scenario?.steps)) {
83
+ processSteps(child.scenario.steps);
84
+ }
85
+ if (Array.isArray(child.rule?.children)) {
86
+ for (const ruleChild of child.rule.children) {
87
+ if (Array.isArray(ruleChild.background?.steps)) {
88
+ processSteps(ruleChild.background.steps);
89
+ }
90
+ if (Array.isArray(ruleChild.scenario?.steps)) {
91
+ processSteps(ruleChild.scenario.steps);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ return steps;
97
+ }
98
+ //# sourceMappingURL=gherkin-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gherkin-parser.js","sourceRoot":"","sources":["../../src/steps/gherkin-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './gherkin-parser.js';
2
+ export * from './expression-matcher.js';
3
+ export * from './snippet-generator.js';
4
+ export * from './step-scaffolder.js';
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright (c) 2026, SimplySF.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ export * from './gherkin-parser.js';
17
+ export * from './expression-matcher.js';
18
+ export * from './snippet-generator.js';
19
+ export * from './step-scaffolder.js';
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/steps/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC"}