ado-sync 0.1.2 → 0.1.4
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.
- package/dist/azure/test-cases.d.ts +16 -3
- package/dist/azure/test-cases.js +258 -19
- package/dist/azure/test-cases.js.map +1 -1
- package/dist/cli.js +23 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.js +50 -2
- package/dist/config.js.map +1 -1
- package/dist/parsers/gherkin.d.ts +9 -14
- package/dist/parsers/gherkin.js +94 -34
- package/dist/parsers/gherkin.js.map +1 -1
- package/dist/parsers/markdown.d.ts +7 -6
- package/dist/parsers/markdown.js +30 -9
- package/dist/parsers/markdown.js.map +1 -1
- package/dist/parsers/shared.d.ts +20 -0
- package/dist/parsers/shared.js +81 -0
- package/dist/parsers/shared.js.map +1 -0
- package/dist/sync/cache.d.ts +24 -0
- package/dist/sync/cache.js +83 -0
- package/dist/sync/cache.js.map +1 -0
- package/dist/sync/engine.d.ts +0 -2
- package/dist/sync/engine.js +200 -30
- package/dist/sync/engine.js.map +1 -1
- package/dist/types.d.ts +57 -2
- package/package.json +2 -2
package/dist/config.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.CONFIG_TEMPLATE_JSON = void 0;
|
|
37
37
|
exports.resolveConfigPath = resolveConfigPath;
|
|
38
38
|
exports.loadConfig = loadConfig;
|
|
39
|
+
exports.applyOverrides = applyOverrides;
|
|
39
40
|
const fs = __importStar(require("fs"));
|
|
40
41
|
const yaml = __importStar(require("js-yaml"));
|
|
41
42
|
const path = __importStar(require("path"));
|
|
@@ -79,6 +80,9 @@ function loadConfig(configPath) {
|
|
|
79
80
|
// Default values
|
|
80
81
|
cfg.sync = cfg.sync ?? {};
|
|
81
82
|
cfg.sync.tagPrefix = cfg.sync.tagPrefix ?? 'tc';
|
|
83
|
+
cfg.sync.titleField = cfg.sync.titleField ?? 'System.Title';
|
|
84
|
+
cfg.sync.conflictAction = cfg.sync.conflictAction ?? 'overwrite';
|
|
85
|
+
cfg.sync.disableLocalChanges = cfg.sync.disableLocalChanges ?? false;
|
|
82
86
|
return cfg;
|
|
83
87
|
}
|
|
84
88
|
function validateConfig(cfg, filePath) {
|
|
@@ -97,13 +101,52 @@ function validateConfig(cfg, filePath) {
|
|
|
97
101
|
if (cfg.auth.type === 'managedIdentity' && !cfg.auth.applicationIdURI) {
|
|
98
102
|
err('"auth.applicationIdURI" is required when auth.type is "managedIdentity"');
|
|
99
103
|
}
|
|
100
|
-
if (!cfg.testPlan?.id)
|
|
101
|
-
err('"testPlan.id" is required');
|
|
104
|
+
if (!cfg.testPlan?.id && !cfg.testPlans?.length) {
|
|
105
|
+
err('"testPlan.id" or "testPlans" array is required');
|
|
106
|
+
}
|
|
102
107
|
if (!cfg.local?.type)
|
|
103
108
|
err('"local.type" is required (gherkin | markdown)');
|
|
104
109
|
if (!cfg.local?.include)
|
|
105
110
|
err('"local.include" is required');
|
|
106
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Apply CLI --config-override values to a loaded config.
|
|
114
|
+
* Each override is a string like "sync.tagPrefix=mytag" or "testPlan.id=42".
|
|
115
|
+
* Dot-path navigation sets nested values. Numbers are coerced automatically.
|
|
116
|
+
*/
|
|
117
|
+
function applyOverrides(cfg, overrides) {
|
|
118
|
+
for (const override of overrides) {
|
|
119
|
+
const eqIdx = override.indexOf('=');
|
|
120
|
+
if (eqIdx === -1) {
|
|
121
|
+
throw new Error(`Invalid --config-override "${override}": expected format "path=value"`);
|
|
122
|
+
}
|
|
123
|
+
const dotPath = override.slice(0, eqIdx).trim();
|
|
124
|
+
const rawValue = override.slice(eqIdx + 1);
|
|
125
|
+
const segments = dotPath.split('.');
|
|
126
|
+
let obj = cfg;
|
|
127
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
128
|
+
const seg = segments[i];
|
|
129
|
+
if (obj[seg] === undefined || obj[seg] === null)
|
|
130
|
+
obj[seg] = {};
|
|
131
|
+
obj = obj[seg];
|
|
132
|
+
}
|
|
133
|
+
const lastKey = segments[segments.length - 1];
|
|
134
|
+
// Coerce: number if parseable, boolean if 'true'/'false', else string
|
|
135
|
+
const numVal = Number(rawValue);
|
|
136
|
+
if (rawValue === 'true') {
|
|
137
|
+
obj[lastKey] = true;
|
|
138
|
+
}
|
|
139
|
+
else if (rawValue === 'false') {
|
|
140
|
+
obj[lastKey] = false;
|
|
141
|
+
}
|
|
142
|
+
else if (!isNaN(numVal) && rawValue.trim() !== '') {
|
|
143
|
+
obj[lastKey] = numVal;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
obj[lastKey] = rawValue;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
107
150
|
exports.CONFIG_TEMPLATE_JSON = JSON.stringify({
|
|
108
151
|
orgUrl: 'https://dev.azure.com/YOUR_ORG',
|
|
109
152
|
project: 'YOUR_PROJECT',
|
|
@@ -114,6 +157,7 @@ exports.CONFIG_TEMPLATE_JSON = JSON.stringify({
|
|
|
114
157
|
testPlan: {
|
|
115
158
|
id: 0,
|
|
116
159
|
suiteId: 0,
|
|
160
|
+
suiteMapping: 'flat',
|
|
117
161
|
},
|
|
118
162
|
local: {
|
|
119
163
|
type: 'gherkin',
|
|
@@ -122,8 +166,12 @@ exports.CONFIG_TEMPLATE_JSON = JSON.stringify({
|
|
|
122
166
|
},
|
|
123
167
|
sync: {
|
|
124
168
|
tagPrefix: 'tc',
|
|
169
|
+
titleField: 'System.Title',
|
|
125
170
|
areaPath: '',
|
|
126
171
|
iterationPath: '',
|
|
172
|
+
disableLocalChanges: false,
|
|
173
|
+
conflictAction: 'overwrite',
|
|
174
|
+
links: [],
|
|
127
175
|
},
|
|
128
176
|
}, null, 2);
|
|
129
177
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,8CAgBC;AAED,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* playwright-bdd). This produces both the GherkinDocument (AST) and Pickles
|
|
6
6
|
* (compiled, example-substituted scenarios) in a single pass.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* For regular Scenarios: uses Pickles (background-merged, already correct).
|
|
9
|
+
* For Scenario Outlines: uses the AST directly to produce ONE ParsedTest
|
|
10
|
+
* with template steps and an outlineParameters table,
|
|
11
|
+
* so Azure gets a single parametrized TC instead of
|
|
12
|
+
* one TC per example row.
|
|
13
13
|
*
|
|
14
14
|
* ID tag convention: @tc:12345 (prefix configurable via sync.tagPrefix)
|
|
15
15
|
*
|
|
@@ -17,14 +17,9 @@
|
|
|
17
17
|
* Directory segments prefixed with @ are added as tags automatically.
|
|
18
18
|
* e.g. specs/@smoke/@regression/login.feature → tags: ['smoke', 'regression']
|
|
19
19
|
*/
|
|
20
|
-
import { ParsedTest } from '../types';
|
|
20
|
+
import { LinkConfig, ParsedTest } from '../types';
|
|
21
|
+
import { extractPathTags } from './shared';
|
|
22
|
+
export { extractPathTags };
|
|
21
23
|
/** Extract Azure Test Case ID from a list of tag names. e.g. ['tc:123', 'smoke'] → 123 */
|
|
22
24
|
export declare function extractAzureId(tags: string[], tagPrefix: string): number | undefined;
|
|
23
|
-
|
|
24
|
-
* Extract auto-tags from directory segments that start with '@'.
|
|
25
|
-
*
|
|
26
|
-
* Given /project/specs/@smoke/@regression/login.feature
|
|
27
|
-
* returns ['smoke', 'regression']
|
|
28
|
-
*/
|
|
29
|
-
export declare function extractPathTags(filePath: string): string[];
|
|
30
|
-
export declare function parseGherkinFile(filePath: string, tagPrefix: string): ParsedTest[];
|
|
25
|
+
export declare function parseGherkinFile(filePath: string, tagPrefix: string, linkConfigs?: LinkConfig[]): ParsedTest[];
|
package/dist/parsers/gherkin.js
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
* playwright-bdd). This produces both the GherkinDocument (AST) and Pickles
|
|
7
7
|
* (compiled, example-substituted scenarios) in a single pass.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* For regular Scenarios: uses Pickles (background-merged, already correct).
|
|
10
|
+
* For Scenario Outlines: uses the AST directly to produce ONE ParsedTest
|
|
11
|
+
* with template steps and an outlineParameters table,
|
|
12
|
+
* so Azure gets a single parametrized TC instead of
|
|
13
|
+
* one TC per example row.
|
|
14
14
|
*
|
|
15
15
|
* ID tag convention: @tc:12345 (prefix configurable via sync.tagPrefix)
|
|
16
16
|
*
|
|
@@ -52,13 +52,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
52
52
|
};
|
|
53
53
|
})();
|
|
54
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.extractPathTags = void 0;
|
|
55
56
|
exports.extractAzureId = extractAzureId;
|
|
56
|
-
exports.extractPathTags = extractPathTags;
|
|
57
57
|
exports.parseGherkinFile = parseGherkinFile;
|
|
58
58
|
const gherkin_1 = require("@cucumber/gherkin");
|
|
59
59
|
const messages_1 = require("@cucumber/messages");
|
|
60
60
|
const fs = __importStar(require("fs"));
|
|
61
|
-
const
|
|
61
|
+
const shared_1 = require("./shared");
|
|
62
|
+
Object.defineProperty(exports, "extractPathTags", { enumerable: true, get: function () { return shared_1.extractPathTags; } });
|
|
62
63
|
// ─── Step type → keyword mapping ─────────────────────────────────────────────
|
|
63
64
|
const STEP_TYPE_KEYWORD = {
|
|
64
65
|
Context: 'Given',
|
|
@@ -83,26 +84,6 @@ function extractAzureId(tags, tagPrefix) {
|
|
|
83
84
|
}
|
|
84
85
|
return undefined;
|
|
85
86
|
}
|
|
86
|
-
/**
|
|
87
|
-
* Extract auto-tags from directory segments that start with '@'.
|
|
88
|
-
*
|
|
89
|
-
* Given /project/specs/@smoke/@regression/login.feature
|
|
90
|
-
* returns ['smoke', 'regression']
|
|
91
|
-
*/
|
|
92
|
-
function extractPathTags(filePath) {
|
|
93
|
-
const segments = filePath.split(path.sep);
|
|
94
|
-
const tags = [];
|
|
95
|
-
// Walk directory segments (not the filename itself)
|
|
96
|
-
for (let i = 0; i < segments.length - 1; i++) {
|
|
97
|
-
const seg = segments[i];
|
|
98
|
-
// A segment may contain multiple @tags separated by spaces or be just one tag
|
|
99
|
-
const matches = seg.match(/@[^\s@/\\]+/g);
|
|
100
|
-
if (matches) {
|
|
101
|
-
tags.push(...matches.map(stripAt));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return tags;
|
|
105
|
-
}
|
|
106
87
|
/**
|
|
107
88
|
* Given a GherkinDocument and a pickle, find the source line of the
|
|
108
89
|
* scenario that produced this pickle (using astNodeIds).
|
|
@@ -129,8 +110,45 @@ function pickleStepToParsedStep(step) {
|
|
|
129
110
|
text: step.text.trim(),
|
|
130
111
|
};
|
|
131
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Build a ParsedTest from a ScenarioOutline AST node.
|
|
115
|
+
* Produces one TC with template step text (keeping <param> angle brackets)
|
|
116
|
+
* and an outlineParameters table for Azure's parametrized TC format.
|
|
117
|
+
*/
|
|
118
|
+
function scenarioOutlineToParsedTest(scenario, filePath, pathTags, tagPrefix, linkConfigs) {
|
|
119
|
+
const scenarioTags = scenario.tags.map((t) => stripAt(t.name));
|
|
120
|
+
const allTags = [...new Set([...pathTags, ...scenarioTags])];
|
|
121
|
+
// Template steps keep <param> angle-bracket syntax as-is
|
|
122
|
+
const steps = scenario.steps.map((s) => ({
|
|
123
|
+
keyword: (s.keyword ?? '').trim(),
|
|
124
|
+
text: s.text.trim(),
|
|
125
|
+
}));
|
|
126
|
+
// Merge all Examples tables (may be multiple blocks)
|
|
127
|
+
let headers = [];
|
|
128
|
+
const rows = [];
|
|
129
|
+
for (const examples of scenario.examples ?? []) {
|
|
130
|
+
if (!examples.tableHeader)
|
|
131
|
+
continue;
|
|
132
|
+
const exHeaders = examples.tableHeader.cells.map((c) => c.value);
|
|
133
|
+
if (!headers.length)
|
|
134
|
+
headers = exHeaders;
|
|
135
|
+
for (const bodyRow of examples.tableBody) {
|
|
136
|
+
rows.push(bodyRow.cells.map((c) => c.value));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
filePath,
|
|
141
|
+
title: scenario.name.trim(),
|
|
142
|
+
steps,
|
|
143
|
+
tags: allTags,
|
|
144
|
+
azureId: extractAzureId(allTags, tagPrefix),
|
|
145
|
+
line: scenario.location?.line ?? 1,
|
|
146
|
+
outlineParameters: headers.length ? { headers, rows } : undefined,
|
|
147
|
+
linkRefs: (0, shared_1.extractLinkRefs)(allTags, linkConfigs),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
132
150
|
// ─── Public parser ────────────────────────────────────────────────────────────
|
|
133
|
-
function parseGherkinFile(filePath, tagPrefix) {
|
|
151
|
+
function parseGherkinFile(filePath, tagPrefix, linkConfigs) {
|
|
134
152
|
const source = fs.readFileSync(filePath, 'utf8');
|
|
135
153
|
const newId = messages_1.IdGenerator.uuid();
|
|
136
154
|
let messages;
|
|
@@ -159,19 +177,61 @@ function parseGherkinFile(filePath, tagPrefix) {
|
|
|
159
177
|
.filter((m) => m.pickle)
|
|
160
178
|
.map((m) => m.pickle);
|
|
161
179
|
// Tags from directory path segments (e.g. specs/@smoke/ → 'smoke')
|
|
162
|
-
const pathTags = extractPathTags(filePath);
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
const pathTags = (0, shared_1.extractPathTags)(filePath);
|
|
181
|
+
const results = [];
|
|
182
|
+
// Collect all Scenario nodes from the AST (including inside Rules)
|
|
183
|
+
const allScenarios = [];
|
|
184
|
+
for (const child of doc.feature?.children ?? []) {
|
|
185
|
+
if (child.scenario)
|
|
186
|
+
allScenarios.push(child.scenario);
|
|
187
|
+
if (child.rule) {
|
|
188
|
+
for (const rc of child.rule.children ?? []) {
|
|
189
|
+
if (rc.scenario)
|
|
190
|
+
allScenarios.push(rc.scenario);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Identify outline scenarios (have at least one non-empty examples table)
|
|
195
|
+
const outlineIds = new Set(allScenarios
|
|
196
|
+
.filter((s) => s.examples?.some((ex) => (ex.tableBody?.length ?? 0) > 0))
|
|
197
|
+
.map((s) => s.id));
|
|
198
|
+
// For Scenario Outlines: one ParsedTest per outline (not per example row)
|
|
199
|
+
for (const scenario of allScenarios) {
|
|
200
|
+
if (outlineIds.has(scenario.id)) {
|
|
201
|
+
results.push(scenarioOutlineToParsedTest(scenario, filePath, pathTags, tagPrefix, linkConfigs));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Build set of all AST node IDs that belong to outlines (scenario + example rows)
|
|
205
|
+
const outlineAstNodeIds = new Set();
|
|
206
|
+
for (const scenario of allScenarios) {
|
|
207
|
+
if (!outlineIds.has(scenario.id))
|
|
208
|
+
continue;
|
|
209
|
+
outlineAstNodeIds.add(scenario.id);
|
|
210
|
+
for (const ex of scenario.examples ?? []) {
|
|
211
|
+
for (const row of ex.tableBody ?? []) {
|
|
212
|
+
outlineAstNodeIds.add(row.id);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// For regular Scenarios: use pickles (background steps merged, correct keywords)
|
|
217
|
+
for (const pickle of pickles) {
|
|
218
|
+
// Skip pickles that originate from an outline
|
|
219
|
+
if (pickle.astNodeIds.some((id) => outlineAstNodeIds.has(id)))
|
|
220
|
+
continue;
|
|
165
221
|
const pickleTags = pickle.tags.map((t) => stripAt(t.name));
|
|
166
222
|
const allTags = [...new Set([...pathTags, ...pickleTags])];
|
|
167
|
-
|
|
223
|
+
results.push({
|
|
168
224
|
filePath,
|
|
169
225
|
title: pickle.name.trim(),
|
|
170
226
|
steps: pickle.steps.map(pickleStepToParsedStep),
|
|
171
227
|
tags: allTags,
|
|
172
228
|
azureId: extractAzureId(allTags, tagPrefix),
|
|
173
229
|
line: findScenarioLine(doc, pickle),
|
|
174
|
-
|
|
175
|
-
|
|
230
|
+
linkRefs: (0, shared_1.extractLinkRefs)(allTags, linkConfigs),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
// Sort by line number to preserve file order
|
|
234
|
+
results.sort((a, b) => a.line - b.line);
|
|
235
|
+
return results;
|
|
176
236
|
}
|
|
177
237
|
//# sourceMappingURL=gherkin.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gherkin.js","sourceRoot":"","sources":["../../src/parsers/gherkin.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG
|
|
1
|
+
{"version":3,"file":"gherkin.js","sourceRoot":"","sources":["../../src/parsers/gherkin.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ### 1. Scenario title ← H3 heading = one test case
|
|
11
11
|
*
|
|
12
|
+
* <!-- tags: @smoke, @regression --> ← optional tags (Gap 5)
|
|
13
|
+
* <!-- tc: 12345 --> ← written back after first push
|
|
14
|
+
*
|
|
12
15
|
* Assumption: ... ← optional prose, used as description
|
|
13
16
|
*
|
|
14
17
|
* Steps:
|
|
@@ -19,13 +22,11 @@
|
|
|
19
22
|
* - Result A
|
|
20
23
|
* - Result B
|
|
21
24
|
*
|
|
22
|
-
* <!-- azure-tc: 12345 --> ← written back after first push
|
|
23
|
-
*
|
|
24
25
|
* --- ← separator between scenarios
|
|
25
26
|
*
|
|
26
27
|
* ID tag convention: <!-- {tagPrefix}: 12345 --> anywhere within the scenario block
|
|
27
|
-
*
|
|
28
|
-
*
|
|
28
|
+
* Tags convention: <!-- tags: @tag1, @tag2 --> anywhere within the scenario block
|
|
29
|
+
* Path-based auto-tagging: same as Gherkin (directory segments starting with @)
|
|
29
30
|
*/
|
|
30
|
-
import { ParsedTest } from '../types';
|
|
31
|
-
export declare function parseMarkdownFile(filePath: string, tagPrefix: string): ParsedTest[];
|
|
31
|
+
import { LinkConfig, ParsedTest } from '../types';
|
|
32
|
+
export declare function parseMarkdownFile(filePath: string, tagPrefix: string, linkConfigs?: LinkConfig[]): ParsedTest[];
|
package/dist/parsers/markdown.js
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
*
|
|
11
11
|
* ### 1. Scenario title ← H3 heading = one test case
|
|
12
12
|
*
|
|
13
|
+
* <!-- tags: @smoke, @regression --> ← optional tags (Gap 5)
|
|
14
|
+
* <!-- tc: 12345 --> ← written back after first push
|
|
15
|
+
*
|
|
13
16
|
* Assumption: ... ← optional prose, used as description
|
|
14
17
|
*
|
|
15
18
|
* Steps:
|
|
@@ -20,13 +23,11 @@
|
|
|
20
23
|
* - Result A
|
|
21
24
|
* - Result B
|
|
22
25
|
*
|
|
23
|
-
* <!-- azure-tc: 12345 --> ← written back after first push
|
|
24
|
-
*
|
|
25
26
|
* --- ← separator between scenarios
|
|
26
27
|
*
|
|
27
28
|
* ID tag convention: <!-- {tagPrefix}: 12345 --> anywhere within the scenario block
|
|
28
|
-
*
|
|
29
|
-
*
|
|
29
|
+
* Tags convention: <!-- tags: @tag1, @tag2 --> anywhere within the scenario block
|
|
30
|
+
* Path-based auto-tagging: same as Gherkin (directory segments starting with @)
|
|
30
31
|
*/
|
|
31
32
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
32
33
|
if (k2 === undefined) k2 = k;
|
|
@@ -64,6 +65,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
64
65
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
66
|
exports.parseMarkdownFile = parseMarkdownFile;
|
|
66
67
|
const fs = __importStar(require("fs"));
|
|
68
|
+
const shared_1 = require("./shared");
|
|
67
69
|
// ─── Regexes ─────────────────────────────────────────────────────────────────
|
|
68
70
|
const H3_RE = /^###\s+(?:\d+\.\s+)?(.+)$/; // ### N. Title or ### Title
|
|
69
71
|
const STEPS_HEADING_RE = /^steps\s*:/i;
|
|
@@ -72,6 +74,7 @@ const NUMBERED_STEP_RE = /^\s*\d+\.\s+(.+)$/;
|
|
|
72
74
|
const BULLET_STEP_RE = /^\s*[-*]\s+(.+)$/;
|
|
73
75
|
const SEPARATOR_RE = /^---+\s*$/;
|
|
74
76
|
const mdTcCommentRe = (prefix) => new RegExp(`<!--\\s*${prefix}\\s*:\\s*(\\d+)\\s*-->`, 'i');
|
|
77
|
+
const TAGS_COMMENT_RE = /<!--\s*tags\s*:\s*([^>]+)-->/i;
|
|
75
78
|
function splitIntoScenarios(lines) {
|
|
76
79
|
const blocks = [];
|
|
77
80
|
let current = null;
|
|
@@ -97,15 +100,28 @@ function splitIntoScenarios(lines) {
|
|
|
97
100
|
blocks.push(current);
|
|
98
101
|
return blocks;
|
|
99
102
|
}
|
|
100
|
-
function parseScenarioBlock(block, filePath, tagPrefix) {
|
|
103
|
+
function parseScenarioBlock(block, filePath, tagPrefix, pathTags, linkConfigs) {
|
|
101
104
|
const lines = block.lines;
|
|
105
|
+
const blockText = lines.join('\n');
|
|
102
106
|
const tcRe = mdTcCommentRe(tagPrefix);
|
|
103
107
|
// Find ID comment
|
|
104
108
|
let azureId;
|
|
105
|
-
const tcComment =
|
|
109
|
+
const tcComment = blockText.match(tcRe);
|
|
106
110
|
if (tcComment) {
|
|
107
111
|
azureId = parseInt(tcComment[1], 10);
|
|
108
112
|
}
|
|
113
|
+
// Find <!-- tags: @smoke, @regression --> comment (Gap 5)
|
|
114
|
+
const blockTags = [...pathTags];
|
|
115
|
+
const tagsComment = blockText.match(TAGS_COMMENT_RE);
|
|
116
|
+
if (tagsComment) {
|
|
117
|
+
const rawTags = tagsComment[1]
|
|
118
|
+
.split(',')
|
|
119
|
+
.map((t) => t.trim())
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.map((t) => (t.startsWith('@') ? t.slice(1) : t));
|
|
122
|
+
blockTags.push(...rawTags);
|
|
123
|
+
}
|
|
124
|
+
const allTags = [...new Set(blockTags)];
|
|
109
125
|
// Extract sections
|
|
110
126
|
let section = 'description';
|
|
111
127
|
const descLines = [];
|
|
@@ -114,6 +130,8 @@ function parseScenarioBlock(block, filePath, tagPrefix) {
|
|
|
114
130
|
for (const line of lines) {
|
|
115
131
|
if (tcRe.test(line))
|
|
116
132
|
continue; // skip ID comment lines
|
|
133
|
+
if (TAGS_COMMENT_RE.test(line))
|
|
134
|
+
continue; // skip tags comment lines
|
|
117
135
|
if (STEPS_HEADING_RE.test(line.trim())) {
|
|
118
136
|
section = 'steps';
|
|
119
137
|
continue;
|
|
@@ -171,15 +189,18 @@ function parseScenarioBlock(block, filePath, tagPrefix) {
|
|
|
171
189
|
title: block.title,
|
|
172
190
|
description,
|
|
173
191
|
steps: parsedSteps,
|
|
174
|
-
tags:
|
|
192
|
+
tags: allTags,
|
|
175
193
|
azureId,
|
|
176
194
|
line: block.startLine,
|
|
195
|
+
linkRefs: (0, shared_1.extractLinkRefs)(allTags, linkConfigs),
|
|
177
196
|
};
|
|
178
197
|
}
|
|
179
|
-
function parseMarkdownFile(filePath, tagPrefix) {
|
|
198
|
+
function parseMarkdownFile(filePath, tagPrefix, linkConfigs) {
|
|
180
199
|
const source = fs.readFileSync(filePath, 'utf8');
|
|
181
200
|
const lines = source.split('\n');
|
|
182
201
|
const blocks = splitIntoScenarios(lines);
|
|
183
|
-
|
|
202
|
+
// Path-based auto-tags (same as Gherkin)
|
|
203
|
+
const pathTags = (0, shared_1.extractPathTags)(filePath);
|
|
204
|
+
return blocks.map((b) => parseScenarioBlock(b, filePath, tagPrefix, pathTags, linkConfigs));
|
|
184
205
|
}
|
|
185
206
|
//# sourceMappingURL=markdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/parsers/markdown.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/parsers/markdown.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiKH,8CAWC;AA1KD,uCAAyB;AAGzB,qCAA4D;AAE5D,gFAAgF;AAEhF,MAAM,KAAK,GAAG,2BAA2B,CAAC,CAAY,8BAA8B;AACpF,MAAM,gBAAgB,GAAG,aAAa,CAAC;AACvC,MAAM,mBAAmB,GAAG,2BAA2B,CAAC;AACxD,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAC7C,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAC1C,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,aAAa,GAAG,CAAC,MAAc,EAAE,EAAE,CACvC,IAAI,MAAM,CAAC,WAAW,MAAM,wBAAwB,EAAE,GAAG,CAAC,CAAC;AAC7D,MAAM,eAAe,GAAG,+BAA+B,CAAC;AAUxD,SAAS,kBAAkB,CAAC,KAAe;IACzC,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,IAAI,OAAO,GAAyB,IAAI,CAAC;IAEzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAElC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,OAAO;gBAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,OAAO,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QACtE,CAAC;aAAM,IAAI,OAAO,EAAE,CAAC;YACnB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC5B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CACzB,KAAoB,EACpB,QAAgB,EAChB,SAAiB,EACjB,QAAkB,EAClB,WAAqC;IAErC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEnC,MAAM,IAAI,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAEtC,kBAAkB;IAClB,IAAI,OAA2B,CAAC;IAChC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,0DAA0D;IAC1D,MAAM,SAAS,GAAa,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC1C,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACrD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC;aAC3B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAExC,mBAAmB;IACnB,IAAI,OAAO,GAAmD,aAAa,CAAC;IAC5E,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,aAAa,GAAa,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS,CAAO,wBAAwB;QAC7D,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,0BAA0B;QAEpE,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,OAAO,CAAC;YAClB,SAAS;QACX,CAAC;QACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1C,OAAO,GAAG,UAAU,CAAC;YACrB,SAAS;QACX,CAAC;QACD,+CAA+C;QAC/C,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,OAAO,CAAC;QACpB,CAAC;QAED,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,aAAa;gBAChB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrB,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnF,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvF,MAAM;QACV,CAAC;IACH,CAAC;IAED,cAAc;IACd,MAAM,WAAW,GAAiB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpD,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,kEAAkE;IAClE,sEAAsE;IACtE,MAAM,YAAY,GAAG,aAAa;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/D,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,GAAG,YAAY,CAAC;QAC9D,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,MAAM,WAAW,GAAG,SAAS;SAC1B,IAAI,CAAC,IAAI,CAAC;SACV,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,IAAI,EAAE,IAAI,SAAS,CAAC;IAEvB,OAAO;QACL,QAAQ;QACR,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,WAAW;QACX,KAAK,EAAE,WAAW;QAClB,IAAI,EAAE,OAAO;QACb,OAAO;QACP,IAAI,EAAE,KAAK,CAAC,SAAS;QACrB,QAAQ,EAAE,IAAA,wBAAe,EAAC,OAAO,EAAE,WAAW,CAAC;KAChD,CAAC;AACJ,CAAC;AAED,SAAgB,iBAAiB,CAC/B,QAAgB,EAChB,SAAiB,EACjB,WAA0B;IAE1B,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACzC,yCAAyC;IACzC,MAAM,QAAQ,GAAG,IAAA,wBAAe,EAAC,QAAQ,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parser utilities used by both gherkin.ts and markdown.ts.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Extract auto-tags from directory segments that start with '@'.
|
|
6
|
+
*
|
|
7
|
+
* Given /project/specs/@smoke/@regression/login.feature
|
|
8
|
+
* returns ['smoke', 'regression']
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractPathTags(filePath: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Parse link references from a list of tags given a set of configured link prefixes.
|
|
13
|
+
* e.g. tags=['story:123','smoke'], prefixes=['story'] → [{ prefix:'story', id:123 }]
|
|
14
|
+
*/
|
|
15
|
+
export declare function extractLinkRefs(tags: string[], linkConfigs: Array<{
|
|
16
|
+
prefix: string;
|
|
17
|
+
}> | undefined): Array<{
|
|
18
|
+
prefix: string;
|
|
19
|
+
id: number;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared parser utilities used by both gherkin.ts and markdown.ts.
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.extractPathTags = extractPathTags;
|
|
40
|
+
exports.extractLinkRefs = extractLinkRefs;
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
/**
|
|
43
|
+
* Extract auto-tags from directory segments that start with '@'.
|
|
44
|
+
*
|
|
45
|
+
* Given /project/specs/@smoke/@regression/login.feature
|
|
46
|
+
* returns ['smoke', 'regression']
|
|
47
|
+
*/
|
|
48
|
+
function extractPathTags(filePath) {
|
|
49
|
+
const segments = filePath.split(path.sep);
|
|
50
|
+
const tags = [];
|
|
51
|
+
// Walk directory segments (not the filename itself)
|
|
52
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
53
|
+
const seg = segments[i];
|
|
54
|
+
const matches = seg.match(/@[^\s@/\\]+/g);
|
|
55
|
+
if (matches) {
|
|
56
|
+
tags.push(...matches.map((t) => (t.startsWith('@') ? t.slice(1) : t)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return tags;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse link references from a list of tags given a set of configured link prefixes.
|
|
63
|
+
* e.g. tags=['story:123','smoke'], prefixes=['story'] → [{ prefix:'story', id:123 }]
|
|
64
|
+
*/
|
|
65
|
+
function extractLinkRefs(tags, linkConfigs) {
|
|
66
|
+
if (!linkConfigs?.length)
|
|
67
|
+
return [];
|
|
68
|
+
const refs = [];
|
|
69
|
+
for (const cfg of linkConfigs) {
|
|
70
|
+
const pfx = cfg.prefix + ':';
|
|
71
|
+
for (const tag of tags) {
|
|
72
|
+
if (tag.startsWith(pfx)) {
|
|
73
|
+
const n = parseInt(tag.slice(pfx.length), 10);
|
|
74
|
+
if (!isNaN(n))
|
|
75
|
+
refs.push({ prefix: cfg.prefix, id: n });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return refs;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/parsers/shared.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUH,0CAYC;AAMD,0CAgBC;AA1CD,2CAA6B;AAE7B;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,oDAAoD;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC1C,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAC7B,IAAc,EACd,WAAkD;IAElD,IAAI,CAAC,WAAW,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,IAAI,GAA0C,EAAE,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC9C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local state cache (.ado-sync-state.json).
|
|
3
|
+
*
|
|
4
|
+
* Stores the last-synced state of each Azure Test Case, enabling:
|
|
5
|
+
* - Conflict detection: remote was changed since we last pushed
|
|
6
|
+
* - Faster status checks: skip Azure API call when nothing changed
|
|
7
|
+
*
|
|
8
|
+
* Commit this file to version control so all team members and CI
|
|
9
|
+
* share the same last-synced state.
|
|
10
|
+
*/
|
|
11
|
+
import { AzureStep, ParsedStep } from '../types';
|
|
12
|
+
export interface CacheEntry {
|
|
13
|
+
title: string;
|
|
14
|
+
stepsHash: string;
|
|
15
|
+
descriptionHash: string;
|
|
16
|
+
/** ISO changedDate from Azure at time of last sync */
|
|
17
|
+
changedDate: string;
|
|
18
|
+
filePath: string;
|
|
19
|
+
}
|
|
20
|
+
export type SyncCache = Record<number, CacheEntry>;
|
|
21
|
+
export declare function loadCache(configDir: string): SyncCache;
|
|
22
|
+
export declare function saveCache(configDir: string, cache: SyncCache): void;
|
|
23
|
+
export declare function hashSteps(steps: ParsedStep[] | AzureStep[]): string;
|
|
24
|
+
export declare function hashString(s: string | undefined): string;
|