@mcp-consultant-tools/azure-devops 30.0.0-beta.15 → 30.0.0-beta.18

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 (66) hide show
  1. package/build/cli/commands/work-item-commands.d.ts.map +1 -1
  2. package/build/cli/commands/work-item-commands.js +34 -0
  3. package/build/cli/commands/work-item-commands.js.map +1 -1
  4. package/build/services/sync-service.d.ts.map +1 -1
  5. package/build/services/sync-service.js +67 -14
  6. package/build/services/sync-service.js.map +1 -1
  7. package/build/services/work-item-service.d.ts +25 -0
  8. package/build/services/work-item-service.d.ts.map +1 -1
  9. package/build/services/work-item-service.js +48 -0
  10. package/build/services/work-item-service.js.map +1 -1
  11. package/build/sync/annotation-parser.d.ts +49 -0
  12. package/build/sync/annotation-parser.d.ts.map +1 -0
  13. package/build/sync/annotation-parser.js +81 -0
  14. package/build/sync/annotation-parser.js.map +1 -0
  15. package/build/sync/field-aliases.d.ts +35 -0
  16. package/build/sync/field-aliases.d.ts.map +1 -0
  17. package/build/sync/field-aliases.js +76 -0
  18. package/build/sync/field-aliases.js.map +1 -0
  19. package/build/sync/html-converter.d.ts.map +1 -1
  20. package/build/sync/html-converter.js +12 -2
  21. package/build/sync/html-converter.js.map +1 -1
  22. package/build/sync/html-detection.d.ts +18 -65
  23. package/build/sync/html-detection.d.ts.map +1 -1
  24. package/build/sync/html-detection.js +72 -113
  25. package/build/sync/html-detection.js.map +1 -1
  26. package/build/sync/image-handler.d.ts +66 -0
  27. package/build/sync/image-handler.d.ts.map +1 -0
  28. package/build/sync/image-handler.js +135 -0
  29. package/build/sync/image-handler.js.map +1 -0
  30. package/build/sync/image-manifest.d.ts +66 -0
  31. package/build/sync/image-manifest.d.ts.map +1 -0
  32. package/build/sync/image-manifest.js +96 -0
  33. package/build/sync/image-manifest.js.map +1 -0
  34. package/build/sync/image-sync.d.ts +88 -0
  35. package/build/sync/image-sync.d.ts.map +1 -0
  36. package/build/sync/image-sync.js +274 -0
  37. package/build/sync/image-sync.js.map +1 -0
  38. package/build/sync/index.d.ts +7 -0
  39. package/build/sync/index.d.ts.map +1 -1
  40. package/build/sync/index.js +7 -0
  41. package/build/sync/index.js.map +1 -1
  42. package/build/sync/legacy-mappings.d.ts +37 -0
  43. package/build/sync/legacy-mappings.d.ts.map +1 -0
  44. package/build/sync/legacy-mappings.js +75 -0
  45. package/build/sync/legacy-mappings.js.map +1 -0
  46. package/build/sync/markdown-serializer.d.ts +54 -60
  47. package/build/sync/markdown-serializer.d.ts.map +1 -1
  48. package/build/sync/markdown-serializer.js +607 -554
  49. package/build/sync/markdown-serializer.js.map +1 -1
  50. package/build/sync/template-loader.d.ts +56 -0
  51. package/build/sync/template-loader.d.ts.map +1 -0
  52. package/build/sync/template-loader.js +138 -0
  53. package/build/sync/template-loader.js.map +1 -0
  54. package/build/sync/templates/bug.md +25 -0
  55. package/build/sync/templates/epic.md +23 -0
  56. package/build/sync/templates/feature.md +23 -0
  57. package/build/sync/templates/task.md +14 -0
  58. package/build/sync/templates/user-story.md +26 -0
  59. package/build/tool-examples.d.ts +4 -0
  60. package/build/tool-examples.d.ts.map +1 -1
  61. package/build/tool-examples.js +17 -0
  62. package/build/tool-examples.js.map +1 -1
  63. package/build/tools/work-item-tools.d.ts.map +1 -1
  64. package/build/tools/work-item-tools.js +31 -1
  65. package/build/tools/work-item-tools.js.map +1 -1
  66. package/package.json +2 -2
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Parse annotated body sections from a synced markdown file.
3
+ *
4
+ * Sections are `##`-level headings. A section is "annotated" (i.e. syncs to
5
+ * an ADO field) when the first non-empty line after the heading is an HTML
6
+ * comment of the form `<!-- ado-field: REFNAME -->`. Unannotated sections
7
+ * are preserved verbatim but never pushed to ADO.
8
+ */
9
+ const SECTION_HEADING_RE = /^##\s+(.+?)\s*$/;
10
+ const ANNOTATION_RE = /^<!--\s*ado-field:\s*([A-Za-z0-9_.\-]+)\s*-->$/;
11
+ /**
12
+ * Parse the body of a markdown file (everything after frontmatter) into
13
+ * annotated and local-only sections.
14
+ */
15
+ export function parseAnnotations(body) {
16
+ const lines = body.split('\n');
17
+ const annotated = [];
18
+ const localOnly = [];
19
+ // Find all section boundaries (## headings).
20
+ const sections = [];
21
+ for (let i = 0; i < lines.length; i++) {
22
+ const match = lines[i].match(SECTION_HEADING_RE);
23
+ if (match) {
24
+ sections.push({ lineIndex: i, heading: match[1].trim() });
25
+ }
26
+ }
27
+ // Everything before the first ## heading is preamble.
28
+ const preambleEnd = sections.length > 0 ? sections[0].lineIndex : lines.length;
29
+ const preamble = lines.slice(0, preambleEnd).join('\n').trim();
30
+ for (let idx = 0; idx < sections.length; idx++) {
31
+ const current = sections[idx];
32
+ const next = sections[idx + 1];
33
+ const bodyStart = current.lineIndex + 1;
34
+ const bodyEnd = next ? next.lineIndex : lines.length;
35
+ // Find first non-empty line in the body to check for annotation.
36
+ let firstNonEmpty = bodyStart;
37
+ while (firstNonEmpty < bodyEnd && lines[firstNonEmpty].trim() === '') {
38
+ firstNonEmpty++;
39
+ }
40
+ const annotationMatch = firstNonEmpty < bodyEnd ? lines[firstNonEmpty].trim().match(ANNOTATION_RE) : null;
41
+ if (annotationMatch) {
42
+ // Annotated section: content is everything AFTER the annotation line.
43
+ const content = lines.slice(firstNonEmpty + 1, bodyEnd).join('\n');
44
+ annotated.push({
45
+ refname: annotationMatch[1],
46
+ content: stripTrailingSeparators(content).trim(),
47
+ heading: current.heading,
48
+ lineIndex: current.lineIndex,
49
+ });
50
+ }
51
+ else {
52
+ // Local-only section: everything between this heading and the next.
53
+ const content = lines.slice(bodyStart, bodyEnd).join('\n');
54
+ localOnly.push({
55
+ heading: current.heading,
56
+ content: stripTrailingSeparators(content).trim(),
57
+ lineIndex: current.lineIndex,
58
+ });
59
+ }
60
+ }
61
+ return { annotated, localOnly, preamble };
62
+ }
63
+ /**
64
+ * Build an annotated `##` section as a string.
65
+ */
66
+ export function serializeAnnotatedSection(heading, refname, content) {
67
+ const body = content.trim() || '';
68
+ return `## ${heading}\n<!-- ado-field: ${refname} -->\n\n${body}\n`;
69
+ }
70
+ /**
71
+ * Check whether a body has any `<!-- ado-field: ... -->` annotations.
72
+ * Used to decide between annotated parsing and legacy fallback.
73
+ */
74
+ export function hasAnnotations(body) {
75
+ return /<!--\s*ado-field:\s*[A-Za-z0-9_.\-]+\s*-->/.test(body);
76
+ }
77
+ function stripTrailingSeparators(content) {
78
+ // Strip trailing `---` horizontal rules used as visual separators between sections.
79
+ return content.replace(/(\n\s*---\s*)+\s*$/, '');
80
+ }
81
+ //# sourceMappingURL=annotation-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-parser.js","sourceRoot":"","sources":["../../src/sync/annotation-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Frontmatter key → ADO reference name resolver.
3
+ *
4
+ * Frontmatter in synced markdown files uses raw ADO refnames as keys
5
+ * (e.g. `System.Title`, `Custom.ConsultancyProcess`). A small alias table
6
+ * provides friendly shortcuts for the most common fields so human-written
7
+ * files stay readable.
8
+ *
9
+ * Resolution rules:
10
+ * 1. Reserved keys (sync metadata) are returned as-is with a null refname.
11
+ * 2. Alias → refname lookup (case-sensitive).
12
+ * 3. Unknown keys are passed through unchanged (treated as refnames).
13
+ */
14
+ /** Keys that are sync metadata, never sent to ADO as field updates. */
15
+ export declare const RESERVED_FRONTMATTER_KEYS: Set<string>;
16
+ /**
17
+ * Friendly aliases → ADO reference names. Add entries here when a field is
18
+ * common enough across clients to deserve a short key.
19
+ */
20
+ export declare const FIELD_ALIASES: Record<string, string>;
21
+ /**
22
+ * Resolve a frontmatter key to its ADO refname, or null if the key is reserved
23
+ * sync metadata.
24
+ */
25
+ export declare function resolveRefname(key: string): string | null;
26
+ /**
27
+ * When writing frontmatter from ADO data, pick the friendliest key for a given
28
+ * refname (alias if one exists, else the refname itself).
29
+ */
30
+ export declare function preferredKey(refname: string): string;
31
+ /**
32
+ * True when a frontmatter key is reserved sync metadata (not an ADO field).
33
+ */
34
+ export declare function isReservedKey(key: string): boolean;
35
+ //# sourceMappingURL=field-aliases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-aliases.d.ts","sourceRoot":"","sources":["../../src/sync/field-aliases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,aASpC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAehD,CAAC;AAWF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAElD"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Frontmatter key → ADO reference name resolver.
3
+ *
4
+ * Frontmatter in synced markdown files uses raw ADO refnames as keys
5
+ * (e.g. `System.Title`, `Custom.ConsultancyProcess`). A small alias table
6
+ * provides friendly shortcuts for the most common fields so human-written
7
+ * files stay readable.
8
+ *
9
+ * Resolution rules:
10
+ * 1. Reserved keys (sync metadata) are returned as-is with a null refname.
11
+ * 2. Alias → refname lookup (case-sensitive).
12
+ * 3. Unknown keys are passed through unchanged (treated as refnames).
13
+ */
14
+ /** Keys that are sync metadata, never sent to ADO as field updates. */
15
+ export const RESERVED_FRONTMATTER_KEYS = new Set([
16
+ 'id',
17
+ 'type',
18
+ 'project',
19
+ 'parent',
20
+ 'parentTitle',
21
+ 'url',
22
+ 'lastSyncedRevision',
23
+ 'lastSyncedAt',
24
+ ]);
25
+ /**
26
+ * Friendly aliases → ADO reference names. Add entries here when a field is
27
+ * common enough across clients to deserve a short key.
28
+ */
29
+ export const FIELD_ALIASES = {
30
+ title: 'System.Title',
31
+ state: 'System.State',
32
+ assignedTo: 'System.AssignedTo',
33
+ areaPath: 'System.AreaPath',
34
+ iterationPath: 'System.IterationPath',
35
+ tags: 'System.Tags',
36
+ priority: 'Microsoft.VSTS.Common.Priority',
37
+ severity: 'Microsoft.VSTS.Common.Severity',
38
+ storyPoints: 'Microsoft.VSTS.Scheduling.StoryPoints',
39
+ remainingWork: 'Microsoft.VSTS.Scheduling.RemainingWork',
40
+ effort: 'Microsoft.VSTS.Scheduling.Effort',
41
+ originalEstimate: 'Microsoft.VSTS.Scheduling.OriginalEstimate',
42
+ completedWork: 'Microsoft.VSTS.Scheduling.CompletedWork',
43
+ moscow: 'Custom.MoSCoW',
44
+ };
45
+ /** Reverse lookup: refname → canonical alias (first alias that resolves back). */
46
+ const REFNAME_TO_ALIAS = (() => {
47
+ const map = {};
48
+ for (const [alias, refname] of Object.entries(FIELD_ALIASES)) {
49
+ if (!(refname in map))
50
+ map[refname] = alias;
51
+ }
52
+ return map;
53
+ })();
54
+ /**
55
+ * Resolve a frontmatter key to its ADO refname, or null if the key is reserved
56
+ * sync metadata.
57
+ */
58
+ export function resolveRefname(key) {
59
+ if (RESERVED_FRONTMATTER_KEYS.has(key))
60
+ return null;
61
+ return FIELD_ALIASES[key] ?? key;
62
+ }
63
+ /**
64
+ * When writing frontmatter from ADO data, pick the friendliest key for a given
65
+ * refname (alias if one exists, else the refname itself).
66
+ */
67
+ export function preferredKey(refname) {
68
+ return REFNAME_TO_ALIAS[refname] ?? refname;
69
+ }
70
+ /**
71
+ * True when a frontmatter key is reserved sync metadata (not an ADO field).
72
+ */
73
+ export function isReservedKey(key) {
74
+ return RESERVED_FRONTMATTER_KEYS.has(key);
75
+ }
76
+ //# sourceMappingURL=field-aliases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-aliases.js","sourceRoot":"","sources":["../../src/sync/field-aliases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAS;IACvD,IAAI;IACJ,MAAM;IACN,SAAS;IACT,QAAQ;IACR,aAAa;IACb,KAAK;IACL,oBAAoB;IACpB,cAAc;CACf,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,KAAK,EAAE,cAAc;IACrB,KAAK,EAAE,cAAc;IACrB,UAAU,EAAE,mBAAmB;IAC/B,QAAQ,EAAE,iBAAiB;IAC3B,aAAa,EAAE,sBAAsB;IACrC,IAAI,EAAE,aAAa;IACnB,QAAQ,EAAE,gCAAgC;IAC1C,QAAQ,EAAE,gCAAgC;IAC1C,WAAW,EAAE,uCAAuC;IACpD,aAAa,EAAE,yCAAyC;IACxD,MAAM,EAAE,kCAAkC;IAC1C,gBAAgB,EAAE,4CAA4C;IAC9D,aAAa,EAAE,yCAAyC;IACxD,MAAM,EAAE,eAAe;CACxB,CAAC;AAEF,kFAAkF;AAClF,MAAM,gBAAgB,GAA2B,CAAC,GAAG,EAAE;IACrD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7D,IAAI,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC;YAAE,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC,EAAE,CAAC;AAEL;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,gBAAgB,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,yBAAyB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC5C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"html-converter.d.ts","sourceRoot":"","sources":["../../src/sync/html-converter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2BH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0BnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE;IAAE,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,EACrG,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiCnB"}
1
+ {"version":3,"file":"html-converter.d.ts","sourceRoot":"","sources":["../../src/sync/html-converter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmCH;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA0BnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE;IAAE,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,EACrG,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,eAAe,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiCnB"}
@@ -18,10 +18,20 @@ turndown.addRule('adoSpan', {
18
18
  filter: ['span'],
19
19
  replacement: (content) => content,
20
20
  });
21
- // Remove empty divs that ADO sometimes creates
21
+ // Remove empty divs that ADO sometimes creates.
22
+ // IMPORTANT: do NOT strip divs whose only "content" is a meaningful element
23
+ // like <img>, <iframe>, <video> etc. — those have no text content but are
24
+ // not visually empty and stripping them silently deletes embedded media.
22
25
  turndown.addRule('emptyDiv', {
23
26
  filter: (node) => {
24
- return node.nodeName === 'DIV' && !node.textContent?.trim();
27
+ if (node.nodeName !== 'DIV')
28
+ return false;
29
+ if (node.textContent?.trim())
30
+ return false;
31
+ if (node.querySelector?.('img, iframe, video, audio, picture, embed, object, svg, canvas')) {
32
+ return false;
33
+ }
34
+ return true;
25
35
  },
26
36
  replacement: () => '',
27
37
  });
@@ -1 +1 @@
1
- {"version":3,"file":"html-converter.js","sourceRoot":"","sources":["../../src/sync/html-converter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html-converter.js","sourceRoot":"","sources":["../../src/sync/html-converter.ts"],"names":[],"mappings":"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"}
@@ -1,93 +1,46 @@
1
1
  /**
2
- * HTML Detection Utility
2
+ * HTML detection for ADO large-text fields.
3
3
  *
4
- * Detects whether ADO work item content is HTML (legacy) or Markdown format.
5
- * ADO supports both formats and we can only sync markdown fields.
6
- */
7
- /**
8
- * Additional custom fields that can be synced.
9
- * These are configurable via environment variables since field names may vary by organization.
4
+ * ADO supports both HTML and Markdown for long-text fields. Sync only
5
+ * works against markdown, so before pulling (or pushing) we auto-detect
6
+ * HTML and either convert it or report it as skipped.
10
7
  *
11
- * Default field names are based on typical ADO custom field patterns.
12
- * GUID-based fields (like pre/post deployment) may vary between organizations.
13
- */
14
- export interface AdditionalFieldConfig {
15
- howToTest: string;
16
- deploymentInformation: string;
17
- predeploymentSteps: string;
18
- postdeploymentSteps: string;
19
- }
20
- /**
21
- * Get additional field configuration from environment variables
22
- * Falls back to common default field names
23
- */
24
- export declare function getAdditionalFieldConfig(): AdditionalFieldConfig;
25
- /**
26
- * Human-readable names for additional fields (for display/logging)
27
- */
28
- export declare const ADDITIONAL_FIELD_DISPLAY_NAMES: Record<keyof AdditionalFieldConfig, string>;
29
- /**
30
- * Large text fields that support markdown format in Azure DevOps.
31
- * These are the standard ADO fields that can be set to markdown format.
8
+ * This module is intentionally generic it no longer maintains a fixed
9
+ * list of "additional" custom fields. Callers pass in the refname list
10
+ * they care about (usually derived from the loaded template).
32
11
  */
33
- export declare const LARGE_TEXT_FIELDS: readonly ["System.Description", "Microsoft.VSTS.Common.AcceptanceCriteria", "Microsoft.VSTS.TCM.ReproSteps"];
34
12
  /**
35
- * Get all large text fields including custom ones from config.
36
- * Used to determine which fields should have markdown format set.
13
+ * Standard ADO large-text fields with native markdown support.
37
14
  */
38
- export declare function getAllLargeTextFields(): string[];
15
+ export declare const STANDARD_LARGE_TEXT_FIELDS: readonly ["System.Description", "Microsoft.VSTS.Common.AcceptanceCriteria", "Microsoft.VSTS.TCM.ReproSteps"];
39
16
  /**
40
- * Check if content is HTML format (as opposed to markdown)
41
- *
42
- * @param content - The content string to check
43
- * @returns true if content appears to be HTML, false if markdown or empty
17
+ * Return the list of large-text fields to check for a work item. Combines
18
+ * the standard set with any caller-supplied custom refnames (from the
19
+ * loaded template).
44
20
  */
21
+ export declare function getAllLargeTextFields(customRefnames?: string[]): string[];
45
22
  export declare function isHtmlContent(content: string | null | undefined): boolean;
46
- /**
47
- * Field format result type
48
- */
49
23
  export type FieldFormat = 'markdown' | 'html' | 'not_present';
50
- /**
51
- * Result of checking additional field formats
52
- */
53
- export interface AdditionalFieldFormats {
54
- howToTest: FieldFormat;
55
- deploymentInformation: FieldFormat;
56
- predeploymentSteps: FieldFormat;
57
- postdeploymentSteps: FieldFormat;
58
- }
59
- /**
60
- * Full field format check result
61
- */
62
24
  export interface FieldFormatResult {
63
25
  description: 'markdown' | 'html';
64
26
  acceptanceCriteria: 'markdown' | 'html';
27
+ reproSteps: 'markdown' | 'html' | 'not_present';
65
28
  ready: boolean;
66
29
  warnings: string[];
67
- additionalFields: AdditionalFieldFormats;
30
+ /** Format for each custom body field, keyed by refname. */
31
+ additionalFields: Record<string, FieldFormat>;
68
32
  details: {
69
33
  descriptionLength: number;
70
34
  acceptanceCriteriaLength: number;
35
+ reproStepsLength: number;
71
36
  };
72
37
  }
73
- /**
74
- * Check field formats for a work item
75
- *
76
- * Primary fields (Description, Acceptance Criteria): If HTML, work item is not ready for sync.
77
- * Secondary fields (How to Test, Deployment fields): If HTML, warn but allow sync (skip those fields).
78
- *
79
- * @param workItem - The work item object from ADO API
80
- * @returns Object with field format information
81
- */
82
38
  export declare function checkFieldFormats(workItem: {
83
39
  fields?: {
84
40
  'System.Description'?: string;
85
41
  'Microsoft.VSTS.Common.AcceptanceCriteria'?: string;
86
42
  [key: string]: any;
87
43
  };
88
- }): FieldFormatResult;
89
- /**
90
- * Get human-readable conversion instructions
91
- */
44
+ }, additionalRefnames?: string[]): FieldFormatResult;
92
45
  export declare function getConversionInstructions(): string;
93
46
  //# sourceMappingURL=html-detection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-detection.d.ts","sourceRoot":"","sources":["../../src/sync/html-detection.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,qBAAqB,CAOhE;AAED;;GAEG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,MAAM,qBAAqB,EAAE,MAAM,CAKtF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,8GAIpB,CAAC;AAEX;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAShD;AA8BD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAsBzE;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,WAAW,CAAC;IACvB,qBAAqB,EAAE,WAAW,CAAC;IACnC,kBAAkB,EAAE,WAAW,CAAC;IAChC,mBAAmB,EAAE,WAAW,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,kBAAkB,EAAE,UAAU,GAAG,MAAM,CAAC;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,gBAAgB,EAAE,sBAAsB,CAAC;IACzC,OAAO,EAAE;QACP,iBAAiB,EAAE,MAAM,CAAC;QAC1B,wBAAwB,EAAE,MAAM,CAAC;KAClC,CAAC;CACH;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE;IAC1C,MAAM,CAAC,EAAE;QACP,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,0CAA0C,CAAC,EAAE,MAAM,CAAC;QACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH,GAAG,iBAAiB,CAmDpB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAUlD"}
1
+ {"version":3,"file":"html-detection.d.ts","sourceRoot":"","sources":["../../src/sync/html-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,eAAO,MAAM,0BAA0B,8GAI7B,CAAC;AAEX;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,GAAE,MAAM,EAAO,GAAG,MAAM,EAAE,CAG7E;AAgCD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CASzE;AAMD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,UAAU,GAAG,MAAM,CAAC;IACjC,kBAAkB,EAAE,UAAU,GAAG,MAAM,CAAC;IACxC,UAAU,EAAE,UAAU,GAAG,MAAM,GAAG,aAAa,CAAC;IAChD,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC9C,OAAO,EAAE;QACP,iBAAiB,EAAE,MAAM,CAAC;QAC1B,wBAAwB,EAAE,MAAM,CAAC;QACjC,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE;IACR,MAAM,CAAC,EAAE;QACP,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,0CAA0C,CAAC,EAAE,MAAM,CAAC;QACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;CACH,EACD,kBAAkB,GAAE,MAAM,EAAO,GAChC,iBAAiB,CAqDnB;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAUlD"}
@@ -1,160 +1,119 @@
1
1
  /**
2
- * HTML Detection Utility
2
+ * HTML detection for ADO large-text fields.
3
3
  *
4
- * Detects whether ADO work item content is HTML (legacy) or Markdown format.
5
- * ADO supports both formats and we can only sync markdown fields.
6
- */
7
- /**
8
- * Get additional field configuration from environment variables
9
- * Falls back to common default field names
10
- */
11
- export function getAdditionalFieldConfig() {
12
- return {
13
- howToTest: process.env.AZUREDEVOPS_SYNC_FIELD_HOW_TO_TEST || 'Custom.Howtotest',
14
- deploymentInformation: process.env.AZUREDEVOPS_SYNC_FIELD_DEPLOYMENT_INFO || 'Custom.Deploymentinformation',
15
- predeploymentSteps: process.env.AZUREDEVOPS_SYNC_FIELD_PREDEPLOY || 'Custom.7519d1bc-5305-4905-822b-2b380e61b154',
16
- postdeploymentSteps: process.env.AZUREDEVOPS_SYNC_FIELD_POSTDEPLOY || 'Custom.abd6763f-a242-4938-85ed-bda419e34e7e',
17
- };
18
- }
19
- /**
20
- * Human-readable names for additional fields (for display/logging)
4
+ * ADO supports both HTML and Markdown for long-text fields. Sync only
5
+ * works against markdown, so before pulling (or pushing) we auto-detect
6
+ * HTML and either convert it or report it as skipped.
7
+ *
8
+ * This module is intentionally generic it no longer maintains a fixed
9
+ * list of "additional" custom fields. Callers pass in the refname list
10
+ * they care about (usually derived from the loaded template).
21
11
  */
22
- export const ADDITIONAL_FIELD_DISPLAY_NAMES = {
23
- howToTest: 'How to Test',
24
- deploymentInformation: 'Deployment Information',
25
- predeploymentSteps: 'Predeployment Steps',
26
- postdeploymentSteps: 'Postdeployment Steps',
27
- };
28
12
  /**
29
- * Large text fields that support markdown format in Azure DevOps.
30
- * These are the standard ADO fields that can be set to markdown format.
13
+ * Standard ADO large-text fields with native markdown support.
31
14
  */
32
- export const LARGE_TEXT_FIELDS = [
15
+ export const STANDARD_LARGE_TEXT_FIELDS = [
33
16
  'System.Description',
34
17
  'Microsoft.VSTS.Common.AcceptanceCriteria',
35
18
  'Microsoft.VSTS.TCM.ReproSteps',
36
19
  ];
37
20
  /**
38
- * Get all large text fields including custom ones from config.
39
- * Used to determine which fields should have markdown format set.
21
+ * Return the list of large-text fields to check for a work item. Combines
22
+ * the standard set with any caller-supplied custom refnames (from the
23
+ * loaded template).
40
24
  */
41
- export function getAllLargeTextFields() {
42
- const config = getAdditionalFieldConfig();
43
- return [
44
- ...LARGE_TEXT_FIELDS,
45
- config.howToTest,
46
- config.deploymentInformation,
47
- config.predeploymentSteps,
48
- config.postdeploymentSteps,
49
- ];
25
+ export function getAllLargeTextFields(customRefnames = []) {
26
+ const set = new Set([...STANDARD_LARGE_TEXT_FIELDS, ...customRefnames]);
27
+ return [...set];
50
28
  }
51
- // Structural HTML patterns that indicate the content is HTML (not markdown)
29
+ // ---------------------------------------------------------------------------
30
+ // HTML detection (pattern-based heuristic)
31
+ // ---------------------------------------------------------------------------
52
32
  const HTML_STRUCTURAL_PATTERNS = [
53
- /<div[^>]*>/i, // <div> tags
54
- /<p[^>]*>/i, // <p> tags
55
- /<h[1-6][^>]*>/i, // HTML heading tags
56
- /<strong[^>]*>/i, // <strong> tags (instead of **)
57
- /<em[^>]*>/i, // <em> tags (instead of *)
58
- /<ul[^>]*>/i, // HTML unordered lists
59
- /<ol[^>]*>/i, // HTML ordered lists
60
- /<li[^>]*>/i, // List items in HTML
61
- /<table[^>]*>/i, // HTML tables
62
- /<tr[^>]*>/i, // Table rows
63
- /<td[^>]*>/i, // Table cells
64
- /<span[^>]*>/i, // Span elements (ADO often uses these)
33
+ /<div[^>]*>/i,
34
+ /<p[^>]*>/i,
35
+ /<h[1-6][^>]*>/i,
36
+ /<strong[^>]*>/i,
37
+ /<em[^>]*>/i,
38
+ /<ul[^>]*>/i,
39
+ /<ol[^>]*>/i,
40
+ /<li[^>]*>/i,
41
+ /<table[^>]*>/i,
42
+ /<tr[^>]*>/i,
43
+ /<td[^>]*>/i,
44
+ /<span[^>]*>/i,
65
45
  ];
66
- // Markdown patterns that indicate the content is already markdown
67
46
  const MARKDOWN_PATTERNS = [
68
- /^#{1,6}\s+/m, // Markdown headings (# Heading)
69
- /\*\*[^*]+\*\*/, // Bold text with **
70
- /^\s*[-*+]\s+/m, // Unordered list items (-, *, +)
71
- /^\s*\d+\.\s+/m, // Numbered list items (1. item)
72
- /\[.+?\]\(.+?\)/, // Markdown links [text](url)
73
- /```[\s\S]*?```/, // Fenced code blocks
74
- /`[^`]+`/, // Inline code
75
- /^\s*>\s+/m, // Block quotes
47
+ /^#{1,6}\s+/m,
48
+ /\*\*[^*]+\*\*/,
49
+ /^\s*[-*+]\s+/m,
50
+ /^\s*\d+\.\s+/m,
51
+ /\[.+?\]\(.+?\)/,
52
+ /```[\s\S]*?```/,
53
+ /`[^`]+`/,
54
+ /^\s*>\s+/m,
76
55
  ];
77
- /**
78
- * Check if content is HTML format (as opposed to markdown)
79
- *
80
- * @param content - The content string to check
81
- * @returns true if content appears to be HTML, false if markdown or empty
82
- */
83
56
  export function isHtmlContent(content) {
84
- if (!content?.trim()) {
57
+ if (!content?.trim())
85
58
  return false;
86
- }
87
- // If clear markdown syntax is present, treat as markdown (even if some inline HTML exists)
88
- // This handles cases where users mix markdown with allowed inline HTML
89
59
  for (const pattern of MARKDOWN_PATTERNS) {
90
- if (pattern.test(content)) {
60
+ if (pattern.test(content))
91
61
  return false;
92
- }
93
62
  }
94
- // Check for structural HTML patterns that indicate this is HTML content
95
63
  for (const pattern of HTML_STRUCTURAL_PATTERNS) {
96
- if (pattern.test(content)) {
64
+ if (pattern.test(content))
97
65
  return true;
98
- }
99
66
  }
100
- // Default to markdown (plain text is valid markdown)
101
67
  return false;
102
68
  }
103
- /**
104
- * Check field formats for a work item
105
- *
106
- * Primary fields (Description, Acceptance Criteria): If HTML, work item is not ready for sync.
107
- * Secondary fields (How to Test, Deployment fields): If HTML, warn but allow sync (skip those fields).
108
- *
109
- * @param workItem - The work item object from ADO API
110
- * @returns Object with field format information
111
- */
112
- export function checkFieldFormats(workItem) {
69
+ export function checkFieldFormats(workItem, additionalRefnames = []) {
113
70
  const fields = workItem.fields || {};
114
- const fieldConfig = getAdditionalFieldConfig();
115
71
  const description = fields['System.Description'] || '';
116
72
  const acceptanceCriteria = fields['Microsoft.VSTS.Common.AcceptanceCriteria'] || '';
73
+ const reproSteps = fields['Microsoft.VSTS.TCM.ReproSteps'] || '';
117
74
  const descriptionIsHtml = isHtmlContent(description);
118
75
  const acceptanceCriteriaIsHtml = isHtmlContent(acceptanceCriteria);
119
- // Check additional fields
76
+ const reproStepsIsHtml = isHtmlContent(reproSteps);
120
77
  const warnings = [];
121
- const additionalFields = {
122
- howToTest: 'not_present',
123
- deploymentInformation: 'not_present',
124
- predeploymentSteps: 'not_present',
125
- postdeploymentSteps: 'not_present',
126
- };
127
- // Helper to check an additional field
128
- const checkAdditionalField = (fieldName, configKey) => {
129
- const content = fields[fieldName];
130
- if (!content || !content.trim()) {
131
- return 'not_present';
78
+ const additionalFields = {};
79
+ for (const refname of additionalRefnames) {
80
+ if (refname === 'System.Description' ||
81
+ refname === 'Microsoft.VSTS.Common.AcceptanceCriteria' ||
82
+ refname === 'Microsoft.VSTS.TCM.ReproSteps') {
83
+ // Covered by the dedicated slots above.
84
+ continue;
132
85
  }
133
- if (isHtmlContent(content)) {
134
- warnings.push(`${ADDITIONAL_FIELD_DISPLAY_NAMES[configKey]} is HTML - will be skipped`);
135
- return 'html';
86
+ const content = fields[refname];
87
+ if (!content || (typeof content === 'string' && !content.trim())) {
88
+ additionalFields[refname] = 'not_present';
89
+ continue;
136
90
  }
137
- return 'markdown';
138
- };
139
- additionalFields.howToTest = checkAdditionalField(fieldConfig.howToTest, 'howToTest');
140
- additionalFields.deploymentInformation = checkAdditionalField(fieldConfig.deploymentInformation, 'deploymentInformation');
141
- additionalFields.predeploymentSteps = checkAdditionalField(fieldConfig.predeploymentSteps, 'predeploymentSteps');
142
- additionalFields.postdeploymentSteps = checkAdditionalField(fieldConfig.postdeploymentSteps, 'postdeploymentSteps');
91
+ if (typeof content === 'string' && isHtmlContent(content)) {
92
+ warnings.push(`${refname} is HTML - will be skipped`);
93
+ additionalFields[refname] = 'html';
94
+ }
95
+ else {
96
+ additionalFields[refname] = 'markdown';
97
+ }
98
+ }
99
+ let reproStepsFormat = 'not_present';
100
+ if (reproSteps && reproSteps.trim()) {
101
+ reproStepsFormat = reproStepsIsHtml ? 'html' : 'markdown';
102
+ }
143
103
  return {
144
104
  description: descriptionIsHtml ? 'html' : 'markdown',
145
105
  acceptanceCriteria: acceptanceCriteriaIsHtml ? 'html' : 'markdown',
146
- ready: !descriptionIsHtml && !acceptanceCriteriaIsHtml,
106
+ reproSteps: reproStepsFormat,
107
+ ready: !descriptionIsHtml && !acceptanceCriteriaIsHtml && reproStepsFormat !== 'html',
147
108
  warnings,
148
109
  additionalFields,
149
110
  details: {
150
111
  descriptionLength: description.length,
151
112
  acceptanceCriteriaLength: acceptanceCriteria.length,
152
- }
113
+ reproStepsLength: reproSteps.length,
114
+ },
153
115
  };
154
116
  }
155
- /**
156
- * Get human-readable conversion instructions
157
- */
158
117
  export function getConversionInstructions() {
159
118
  return `To convert HTML fields to markdown in Azure DevOps:
160
119
  1. Open the work item in Azure DevOps
@@ -1 +1 @@
1
- {"version":3,"file":"html-detection.js","sourceRoot":"","sources":["../../src/sync/html-detection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html-detection.js","sourceRoot":"","sources":["../../src/sync/html-detection.ts"],"names":[],"mappings":"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"}