opsx-gherkin 1.0.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 (32) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/CONTRIBUTING.md +53 -0
  3. package/LICENSE +21 -0
  4. package/README.md +99 -0
  5. package/SECURITY.md +14 -0
  6. package/dist/cli.mjs +50 -0
  7. package/dist/cli.mjs.map +1 -0
  8. package/dist/converter-CFtzcfoM.mjs +977 -0
  9. package/dist/converter-CFtzcfoM.mjs.map +1 -0
  10. package/dist/mdg-to-opsx.mjs +8 -0
  11. package/dist/mdg-to-opsx.mjs.map +1 -0
  12. package/dist/official-99qBUZpr.mjs +91 -0
  13. package/dist/official-99qBUZpr.mjs.map +1 -0
  14. package/dist/opsx-to-feature.mjs +8 -0
  15. package/dist/opsx-to-feature.mjs.map +1 -0
  16. package/dist/opsx-to-mdg.mjs +8 -0
  17. package/dist/opsx-to-mdg.mjs.map +1 -0
  18. package/dist/validate-spec.mjs +56 -0
  19. package/dist/validate-spec.mjs.map +1 -0
  20. package/package.json +87 -0
  21. package/skills/opsx-gherkin/SKILL.md +144 -0
  22. package/skills/opsx-gherkin/references/OPENSPEC_MDG_PROFILE.feature.md +372 -0
  23. package/skills/opsx-gherkin/references/examples/account.feature +85 -0
  24. package/skills/opsx-gherkin/references/examples/account.feature.md +96 -0
  25. package/skills/opsx-gherkin/references/examples/account.openspec.md +109 -0
  26. package/skills/opsx-gherkin/references/examples/authentication-delta.feature +41 -0
  27. package/skills/opsx-gherkin/references/examples/authentication-delta.feature.md +45 -0
  28. package/skills/opsx-gherkin/references/examples/authentication-delta.openspec.md +52 -0
  29. package/skills/opsx-gherkin/references/examples/minimal.feature +17 -0
  30. package/skills/opsx-gherkin/references/examples/minimal.feature.md +19 -0
  31. package/skills/opsx-gherkin/references/examples/minimal.openspec.md +24 -0
  32. package/skills/opsx-gherkin/references/profile-access.feature.md +34 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converter-CFtzcfoM.mjs","names":[],"sources":["../src/model.ts","../src/constants.ts","../src/syntax.ts","../src/parsers/mdg.ts","../src/parsers/feature.ts","../src/parsers/openspec.ts","../src/renderers/feature.ts","../src/renderers/mdg.ts","../src/renderers/openspec.ts","../src/validation/profile.ts","../src/convert.ts","../src/cli/converter.ts"],"sourcesContent":["import { isDeepStrictEqual } from 'node:util'\nimport { ConversionError } from './errors.js'\n\nexport type DocumentKind = 'main' | 'delta'\nexport type Operation = 'ADDED' | 'MODIFIED' | 'REMOVED' | 'RENAMED'\nexport type Direction = 'mdg-to-opsx' | 'opsx-to-mdg' | 'opsx-to-feature'\nexport interface ConversionOptions {\n sourcePath?: string\n name?: string\n projectRoot?: string\n}\nexport interface StepModel {\n keyword: string\n text: string\n table: string[][] | null\n docString: { mediaType: string; content: string } | null\n}\nexport interface BackgroundModel {\n name: string\n description: string\n steps: StepModel[]\n}\nexport interface ExamplesModel {\n name: string\n description: string\n tags: string[]\n rows: string[][]\n}\nexport interface ScenarioModel extends BackgroundModel {\n kind: 'scenario' | 'outline'\n tags: string[]\n examples: ExamplesModel[]\n}\nexport interface RuleModel {\n name: string\n description: string\n tags: string[]\n operation: Operation | undefined\n rename: { from: string; to: string } | null\n background: BackgroundModel | null\n scenarios: ScenarioModel[]\n}\nexport interface DocumentModel {\n kind: DocumentKind\n name: string\n description: string\n tags: string[]\n background: BackgroundModel | null\n featureScenarios: ScenarioModel[]\n rules: RuleModel[]\n}\n\n/** Rename Rules are structural wrappers; their FROM and TO names carry the identity. */\nexport function normalizedModel(model: DocumentModel): DocumentModel {\n return {\n ...model,\n rules: model.rules.map((rule) => ({\n ...rule,\n name: rule.operation === 'RENAMED' ? 'Rename requirement' : rule.name,\n })),\n }\n}\n\nexport function assertPreserved(source: DocumentModel, destination: DocumentModel): void {\n if (!isDeepStrictEqual(normalizedModel(source), normalizedModel(destination))) {\n throw new ConversionError('Conversion would change the normalized document model', [\n 'The destination was not emitted. Check supported structure, ordering, and literal values.',\n ])\n }\n}\n","import type { Operation } from './model.js'\n\nexport const OPERATION_TAGS = new Map<string, Operation>([\n ['@openspec-added', 'ADDED'],\n ['@openspec-modified', 'MODIFIED'],\n ['@openspec-removed', 'REMOVED'],\n ['@openspec-renamed', 'RENAMED'],\n])\nexport const RESERVED_PREFIXES = ['@openspec-', '@mdg-']\nexport const SYNTHETIC_TAG = '@mdg-feature-scenarios'\nexport const DELTA_TAG = '@openspec-delta'\n","import { basename, dirname } from 'node:path'\nimport { ConversionError } from './errors.js'\nimport type { ConversionOptions, StepModel } from './model.js'\n\nexport interface Heading {\n index: number\n title: string\n}\nexport interface Section {\n start: number\n end: number\n}\nexport type Located = { location: { line: number } }\nexport type LocatedChild =\n | Located\n | { background?: Located; scenario?: Located; rule?: Located; examples?: Located }\n\nexport function pushDescriptionAndSteps(\n output: string[],\n node: { description: string; steps: StepModel[] },\n mdg = false,\n): void {\n if (node.description) output.push(node.description, '')\n for (const step of node.steps) {\n const keyword = mdg ? titleCase(step.keyword) : `**${step.keyword}**`\n output.push(`${mdg ? '*' : '-'} ${keyword} ${step.text}`)\n if (step.table) pushTable(output, step.table, false, !mdg)\n if (step.docString) {\n output.push('', ` \\`\\`\\`${step.docString.mediaType || ''}`)\n for (const line of step.docString.content.split('\\n')) output.push(` ${line}`)\n output.push(' ```')\n }\n }\n output.push('')\n}\n\nexport function pushTable(\n output: string[],\n rows: string[][],\n blankAfter = true,\n separator = true,\n): void {\n if (!rows?.length) return\n output.push(` | ${rows[0].map(escapeCell).join(' | ')} |`)\n if (separator) output.push(` | ${rows[0].map(() => '---').join(' | ')} |`)\n for (const row of rows.slice(1)) output.push(` | ${row.map(escapeCell).join(' | ')} |`)\n if (blankAfter) output.push('')\n}\n\nexport function parseTable(lines: string[]): string[][] {\n const rows = lines.filter((line) => /^\\s{2,}\\|/.test(line)).map(parseTableRow)\n if (rows.length >= 2 && rows[1].every((cell) => /^:?-+:?$/.test(cell))) rows.splice(1, 1)\n if (!rows.length) throw new ConversionError('Empty table')\n const width = rows[0].length\n if (rows.some((row) => row.length !== width))\n throw new ConversionError('Inconsistent table column count')\n return rows\n}\n\nexport function parseTableRow(line: string): string[] {\n const content = line.trim().replace(/^\\|/, '').replace(/\\|$/, '')\n const cells = []\n let cell = ''\n let escaped = false\n for (const char of content) {\n if (escaped) {\n cell += char === 'n' ? '\\n' : char\n escaped = false\n } else if (char === '\\\\') escaped = true\n else if (char === '|') {\n cells.push(cell.trim())\n cell = ''\n } else cell += char\n }\n cells.push(cell.trim())\n return cells\n}\n\nexport function normalizeLines(text: string): string[] {\n return text\n .replace(/^\\uFEFF/, '')\n .replace(/\\r\\n?/g, '\\n')\n .split('\\n')\n}\n\nexport function fenceMask(lines: string[]): boolean[] {\n const mask = []\n let fence: string | null = null\n for (let index = 0; index < lines.length; index += 1) {\n const match = lines[index].match(/^\\s*(`{3,}|~{3,})/)\n mask[index] = Boolean(fence)\n if (match && !fence) {\n fence = match[1][0]\n mask[index] = true\n } else if (match && fence === match[1][0]) {\n mask[index] = true\n fence = null\n }\n }\n return mask\n}\n\nexport function findHeading(lines: string[], mask: boolean[], level: number): Heading | null {\n for (let index = 0; index < lines.length; index += 1) {\n const match = !mask[index] && lines[index].match(new RegExp(`^#{${level}}\\\\s+(.+?)\\\\s*$`))\n if (match) return { index, title: match[1].trim() }\n }\n return null\n}\n\nexport function headingsInRange(\n lines: string[],\n mask: boolean[],\n level: number,\n start: number,\n end: number,\n): Heading[] {\n const result = []\n for (let index = start; index < end; index += 1) {\n const match = !mask[index] && lines[index].match(new RegExp(`^#{${level}}\\\\s+(.+?)\\\\s*$`))\n if (match) result.push({ index, title: match[1].trim() })\n }\n return result\n}\n\nexport function findSection(lines: string[], mask: boolean[], title: string): Section {\n const section = findSectionOptional(lines, mask, title)\n if (!section) throw new ConversionError(`Missing OpenSpec section: ## ${title}`)\n return section\n}\n\nexport function findSectionOptional(\n lines: string[],\n mask: boolean[],\n title: string,\n): Section | null {\n for (let index = 0; index < lines.length; index += 1) {\n if (!mask[index] && new RegExp(`^##\\\\s+${escapeRegex(title)}\\\\s*$`, 'i').test(lines[index])) {\n let end = lines.length\n for (let next = index + 1; next < lines.length; next += 1) {\n if (!mask[next] && /^##\\s+/.test(lines[next])) {\n end = next\n break\n }\n }\n return { start: index, end }\n }\n }\n return null\n}\n\nexport function sectionContent(lines: string[], mask: boolean[], title: string): string | null {\n const section = findSectionOptional(lines, mask, title)\n return section ? trimBlank(lines.slice(section.start + 1, section.end)).join('\\n') : null\n}\n\nexport function precedingTags(lines: string[], headingIndex: number): string[] {\n let index = headingIndex - 1\n while (index >= 0 && !lines[index].trim()) index -= 1\n const blocks = []\n while (index >= 0 && isTagLine(lines[index])) {\n blocks.unshift(...extractTags(lines[index]))\n index -= 1\n while (index >= 0 && !lines[index].trim()) index -= 1\n }\n return blocks\n}\n\nexport function tagBlockStart(lines: string[], headingIndex: number): number {\n let index = headingIndex - 1\n while (index >= 0 && !lines[index].trim()) index -= 1\n while (index >= 0 && isTagLine(lines[index])) {\n index -= 1\n while (index >= 0 && !lines[index].trim()) index -= 1\n }\n return index + 1\n}\n\nexport function tagStartLine(lines: string[], node: LocatedChild): number {\n return tagBlockStart(lines, nodeLine(node) - 1) + 1\n}\n\nexport function isTagLine(line: string): boolean {\n const matches = [...line.matchAll(/`(@[^`]+)`/g)]\n return matches.length > 0 && line.replace(/`(@[^`]+)`/g, '').trim() === ''\n}\n\nexport function extractTags(line: string): string[] {\n return [...line.matchAll(/`(@[^`]+)`/g)].map((match) => match[1])\n}\n\nexport function proseBetween(lines: string[], startLine: number, endLine: number): string {\n const slice = lines.slice(Math.max(0, startLine - 1), Math.max(0, endLine - 1))\n while (slice.length && (!slice[slice.length - 1].trim() || isTagLine(slice[slice.length - 1])))\n slice.pop()\n return trimBlank(slice).join('\\n')\n}\n\nexport function nextSiblingLine(line: number, siblings: LocatedChild[], fallback: number): number {\n return (\n siblings\n .map(nodeLine)\n .filter((candidate) => candidate > line)\n .sort((a, b) => a - b)[0] || fallback\n )\n}\n\nexport function nodeLine(child: LocatedChild): number {\n if ('location' in child) return child.location.line\n const value = child.background ?? child.scenario ?? child.rule ?? child.examples\n if (!value) throw new ConversionError('Missing Gherkin node location')\n return value.location.line\n}\n\nexport function trimBlank(lines: string[]): string[] {\n const copy = [...lines]\n while (copy.length && !copy[0].trim()) copy.shift()\n while (copy.length && !copy[copy.length - 1].trim()) copy.pop()\n return copy\n}\n\nexport function pushTags(output: string[], tags: string[]): void {\n if (tags?.length) output.push(tags.map((tag) => `\\`${tag}\\``).join(' '))\n}\n\nexport function resolveOpenSpecName(text: string, options: ConversionOptions): string {\n const lines = normalizeLines(text)\n const mask = fenceMask(lines)\n const h1 = findHeading(lines, mask, 1)\n if (h1) return h1.title.replace(/^Feature:\\s*/i, '').trim()\n if (options.name) return options.name\n if (options.sourcePath) {\n const parent = basename(dirname(options.sourcePath))\n if (parent && parent !== '.') return parent\n }\n throw new ConversionError('OpenSpec text without an H1 title requires --name')\n}\n\nexport function slugify(value: string): string {\n return (\n value\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '') || 'spec'\n )\n}\n\nexport function titleCase(keyword: string): string {\n return keyword[0] + keyword.slice(1).toLowerCase()\n}\n\nexport function escapeCell(value: string): string {\n return String(value).replace(/\\\\/g, '\\\\\\\\').replace(/\\|/g, '\\\\|').replace(/\\n/g, '\\\\n')\n}\n\nexport function escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import type {\n Background,\n Examples,\n GherkinDocument,\n Rule,\n Scenario,\n Step,\n} from '@cucumber/messages'\nimport { DELTA_TAG, OPERATION_TAGS } from '../constants.js'\nimport { ConversionError } from '../errors.js'\nimport type {\n BackgroundModel,\n DocumentModel,\n ExamplesModel,\n Operation,\n RuleModel,\n ScenarioModel,\n StepModel,\n} from '../model.js'\nimport type { LocatedChild } from '../syntax.js'\nimport { nextSiblingLine, nodeLine, normalizeLines, proseBetween, tagStartLine } from '../syntax.js'\n\nexport function parseMdgModel(text: string, document: GherkinDocument): DocumentModel {\n const feature = document.feature\n if (!feature) throw new ConversionError('Gherkin document has no Feature')\n const lines = normalizeLines(text)\n const featureChildren = [...feature.children].sort((a, b) => nodeLine(a) - nodeLine(b))\n const firstFeatureChild = featureChildren[0]\n ? tagStartLine(lines, featureChildren[0])\n : lines.length + 1\n const description = proseBetween(lines, feature.location.line + 1, firstFeatureChild)\n const featureTags = feature.tags.map((tag) => tag.name)\n const isDelta = featureTags.includes(DELTA_TAG)\n const model: DocumentModel = {\n kind: isDelta ? 'delta' : 'main',\n name: feature.name.trim(),\n description,\n tags: featureTags.filter((tag) => tag !== DELTA_TAG),\n background: null,\n featureScenarios: [],\n rules: [],\n }\n\n for (let index = 0; index < featureChildren.length; index += 1) {\n const child = featureChildren[index]\n const boundary = featureChildren[index + 1]\n ? tagStartLine(lines, featureChildren[index + 1])\n : lines.length + 1\n if (child.background)\n model.background = mapMdgBackground(child.background, lines, featureChildren)\n if (child.scenario) model.featureScenarios.push(mapMdgScenario(child.scenario, lines))\n if (child.rule) model.rules.push(mapMdgRule(child.rule, lines, isDelta, boundary))\n }\n return model\n}\n\nexport function mapMdgRule(\n rule: Rule,\n lines: string[],\n isDelta: boolean,\n boundary: number,\n): RuleModel {\n const children = [...rule.children].sort((a, b) => nodeLine(a) - nodeLine(b))\n const firstChild = children[0] ? tagStartLine(lines, children[0]) : lines.length + 1\n const tags = rule.tags.map((tag) => tag.name)\n const operationTags = tags.filter((tag) => OPERATION_TAGS.has(tag))\n let operation: Operation | undefined\n if (isDelta) {\n if (operationTags.length !== 1) {\n throw new ConversionError(\n `Delta Rule \"${rule.name}\" must have exactly one @openspec operation tag`,\n )\n }\n operation = OPERATION_TAGS.get(operationTags[0])\n } else if (operationTags.length) {\n throw new ConversionError(\n `Main-spec Rule \"${rule.name}\" cannot use OpenSpec delta operation tags`,\n )\n }\n const description = proseBetween(\n lines,\n rule.location.line + 1,\n children.length ? firstChild : boundary,\n )\n const mapped: RuleModel = {\n name: rule.name.trim(),\n description,\n tags: tags.filter((tag) => !OPERATION_TAGS.has(tag)),\n operation,\n rename: null,\n background: null,\n scenarios: [],\n }\n for (const child of children) {\n if (child.background) mapped.background = mapMdgBackground(child.background, lines, children)\n if (child.scenario) mapped.scenarios.push(mapMdgScenario(child.scenario, lines))\n }\n if (operation === 'RENAMED') {\n const from = description.match(/^FROM:\\s*`### Requirement:\\s*(.+?)`\\s*$/im)?.[1]\n const to = description.match(/^TO:\\s*`### Requirement:\\s*(.+?)`\\s*$/im)?.[1]\n if (!from || !to)\n throw new ConversionError(`RENAMED Rule \"${rule.name}\" requires FROM and TO lines`)\n const extra = description\n .replace(/^FROM:.*$/gim, '')\n .replace(/^TO:.*$/gim, '')\n .trim()\n if (extra || mapped.background || mapped.scenarios.length)\n throw new ConversionError('RENAMED Rule contains unsupported content')\n mapped.rename = { from: from.trim(), to: to.trim() }\n mapped.description = ''\n }\n return mapped\n}\n\nexport function mapMdgBackground(\n background: Background,\n lines: string[],\n siblings: LocatedChild[],\n): BackgroundModel {\n const firstStep =\n background.steps[0]?.location.line ||\n nextSiblingLine(background.location.line, siblings, lines.length + 1)\n return {\n name: background.name.trim(),\n description: proseBetween(lines, background.location.line + 1, firstStep),\n steps: background.steps.map(mapMdgStep),\n }\n}\n\nexport function mapMdgScenario(scenario: Scenario, lines: string[]): ScenarioModel {\n const firstContent = Math.min(\n scenario.steps[0]?.location.line || Infinity,\n scenario.examples[0] ? tagStartLine(lines, { examples: scenario.examples[0] }) : Infinity,\n )\n return {\n kind: /outline/i.test(scenario.keyword) ? 'outline' : 'scenario',\n name: scenario.name.trim(),\n description: proseBetween(\n lines,\n scenario.location.line + 1,\n Number.isFinite(firstContent) ? firstContent : lines.length + 1,\n ),\n tags: scenario.tags.map((tag) => tag.name),\n steps: scenario.steps.map(mapMdgStep),\n examples: scenario.examples.map((examples) => mapMdgExamples(examples, lines)),\n }\n}\n\nexport function mapMdgExamples(examples: Examples, lines: string[]): ExamplesModel {\n const tableLine = examples.tableHeader?.location.line || lines.length + 1\n const rows = []\n if (examples.tableHeader) rows.push(examples.tableHeader.cells.map((cell) => cell.value))\n rows.push(...examples.tableBody.map((row) => row.cells.map((cell) => cell.value)))\n return {\n name: examples.name.trim(),\n description: proseBetween(lines, examples.location.line + 1, tableLine),\n tags: examples.tags.map((tag) => tag.name),\n rows,\n }\n}\n\nexport function mapMdgStep(step: Step): StepModel {\n return {\n keyword: step.keyword.trim().toUpperCase(),\n text: step.text,\n table: step.dataTable\n ? step.dataTable.rows.map((row) => row.cells.map((cell) => cell.value))\n : null,\n docString: step.docString\n ? { mediaType: step.docString.mediaType || '', content: step.docString.content }\n : null,\n }\n}\n","import type { GherkinDocument, Rule } from '@cucumber/messages'\nimport { DELTA_TAG, OPERATION_TAGS } from '../constants.js'\nimport { ConversionError } from '../errors.js'\nimport type { BackgroundModel, DocumentModel, RuleModel, ScenarioModel } from '../model.js'\nimport { trimBlank } from '../syntax.js'\nimport { mapMdgStep } from './mdg.js'\n\ntype Background = NonNullable<Rule['children'][number]['background']>\ntype Scenario = NonNullable<Rule['children'][number]['scenario']>\n\nfunction description(value: { description: string; location: { column?: number } }): string {\n const prefix = ' '.repeat((value.location.column ?? 1) + 1)\n return trimBlank(\n value.description\n .split('\\n')\n .map((line) => (line.startsWith(prefix) ? line.slice(prefix.length) : line)),\n ).join('\\n')\n}\n\nfunction background(value: Background): BackgroundModel {\n return {\n name: value.name.trim(),\n description: description(value),\n steps: value.steps.map(mapMdgStep),\n }\n}\nfunction scenario(value: Scenario): ScenarioModel {\n return {\n ...background(value),\n kind: /outline/i.test(value.keyword) ? 'outline' : 'scenario',\n tags: value.tags.map((tag) => tag.name),\n examples: value.examples.map((group) => ({\n name: group.name.trim(),\n description: description(group),\n tags: group.tags.map((tag) => tag.name),\n rows: [\n ...(group.tableHeader ? [group.tableHeader.cells.map((cell) => cell.value)] : []),\n ...group.tableBody.map((row) => row.cells.map((cell) => cell.value)),\n ],\n })),\n }\n}\nexport function parseFeatureModel(document: GherkinDocument): DocumentModel {\n const feature = document.feature\n if (!feature) throw new ConversionError('Gherkin document has no Feature')\n const tags = feature.tags.map((tag) => tag.name)\n const model: DocumentModel = {\n name: feature.name.trim(),\n description: description(feature),\n kind: tags.includes(DELTA_TAG) ? 'delta' : 'main',\n tags: tags.filter((tag) => tag !== DELTA_TAG),\n background: null,\n featureScenarios: [],\n rules: [],\n }\n for (const child of feature.children) {\n if (child.background) model.background = background(child.background)\n if (child.scenario) model.featureScenarios.push(scenario(child.scenario))\n if (child.rule) {\n const value = child.rule\n const tags = value.tags.map((tag) => tag.name)\n const operationTag = tags.find((tag) => OPERATION_TAGS.has(tag))\n const rule: RuleModel = {\n name: value.name.trim(),\n description: description(value),\n tags: tags.filter((tag) => !OPERATION_TAGS.has(tag)),\n operation: operationTag ? OPERATION_TAGS.get(operationTag) : undefined,\n rename: null,\n background: null,\n scenarios: [],\n }\n for (const item of value.children) {\n if (item.background) rule.background = background(item.background)\n if (item.scenario) rule.scenarios.push(scenario(item.scenario))\n }\n if (rule.operation === 'RENAMED') {\n const from = rule.description.match(/^FROM:\\s*### Requirement:\\s*(.+)$/m)?.[1]\n const to = rule.description.match(/^TO:\\s*### Requirement:\\s*(.+)$/m)?.[1]\n if (!from || !to) throw new ConversionError('RENAMED Rule requires FROM and TO')\n rule.rename = { from: from.trim(), to: to.trim() }\n rule.description = ''\n }\n model.rules.push(rule)\n }\n }\n return model\n}\n","import { DELTA_TAG, SYNTHETIC_TAG } from '../constants.js'\nimport { ConversionError } from '../errors.js'\nimport type {\n BackgroundModel,\n DocumentKind,\n DocumentModel,\n Operation,\n RuleModel,\n ScenarioModel,\n StepModel,\n} from '../model.js'\nimport type { Heading } from '../syntax.js'\nimport {\n fenceMask,\n findHeading,\n findSection,\n findSectionOptional,\n headingsInRange,\n normalizeLines,\n parseTable,\n precedingTags,\n sectionContent,\n tagBlockStart,\n trimBlank,\n} from '../syntax.js'\n\nexport function detectOpenSpecKind(text: string): DocumentKind {\n const lines = text\n .replace(/^\\uFEFF/, '')\n .replace(/\\r\\n?/g, '\\n')\n .split('\\n')\n const mask = fenceMask(lines)\n const main = lines.some((line, index) => !mask[index] && /^##\\s+Requirements\\s*$/i.test(line))\n const delta = lines.some(\n (line, index) =>\n !mask[index] && /^##\\s+(ADDED|MODIFIED|REMOVED|RENAMED) Requirements\\s*$/i.test(line),\n )\n if (main && delta)\n throw new ConversionError('OpenSpec input mixes main and delta requirement sections')\n if (!main && !delta)\n throw new ConversionError('OpenSpec input has no Requirements or delta sections')\n return delta ? 'delta' : 'main'\n}\n\nexport function parseOpenSpecModel(\n text: string,\n { kind, name }: { kind: DocumentKind; name: string },\n): DocumentModel {\n const lines = normalizeLines(text)\n const mask = fenceMask(lines)\n const h1 = findHeading(lines, mask, 1)\n const title = h1 ? h1.title : name\n const tags = h1 ? precedingTags(lines, h1.index) : []\n const purpose = sectionContent(lines, mask, 'Purpose')\n const model: DocumentModel = {\n kind,\n name: title,\n description: purpose?.trim() || '',\n tags: tags.filter((tag) => tag !== DELTA_TAG),\n background: null,\n featureScenarios: [],\n rules: [],\n }\n\n if (kind === 'main') parseMainOpenSpec(lines, mask, model)\n else parseDeltaOpenSpec(lines, mask, model)\n return model\n}\n\nexport function parseMainOpenSpec(lines: string[], mask: boolean[], model: DocumentModel): void {\n const section = findSection(lines, mask, 'Requirements')\n const requirements = headingsInRange(lines, mask, 3, section.start + 1, section.end).filter(\n (heading) => /^Requirement:\\s*/i.test(heading.title),\n )\n const firstRequirementStart = requirements[0]\n ? tagBlockStart(lines, requirements[0].index)\n : section.end\n const preamble = trimBlank(lines.slice(section.start + 1, firstRequirementStart))\n if (preamble.length) model.background = parseOpenSpecBackground(preamble, 'feature')\n\n for (let index = 0; index < requirements.length; index += 1) {\n const heading = requirements[index]\n const end =\n index + 1 < requirements.length\n ? tagBlockStart(lines, requirements[index + 1].index)\n : section.end\n const rule = parseOpenSpecRequirement(lines, mask, heading, end)\n if (rule.tags.includes(SYNTHETIC_TAG)) {\n rule.tags = rule.tags.filter((tag) => tag !== SYNTHETIC_TAG)\n if (rule.background && !model.background) model.background = rule.background\n model.featureScenarios.push(...rule.scenarios)\n } else {\n model.rules.push(rule)\n }\n }\n}\n\nexport function parseDeltaOpenSpec(lines: string[], mask: boolean[], model: DocumentModel): void {\n model.tags = model.tags.filter((tag) => tag !== DELTA_TAG)\n const operations = headingsInRange(lines, mask, 2, 0, lines.length).flatMap((heading) => {\n const match = heading.title.match(/^(ADDED|MODIFIED|REMOVED|RENAMED) Requirements$/i)\n return match ? [match[1].toUpperCase() as Operation] : []\n })\n if (new Set(operations).size !== operations.length)\n throw new ConversionError('Repeated delta operation section is unsupported')\n for (const operation of operations) {\n const section = findSectionOptional(lines, mask, `${operation} Requirements`)\n if (!section) continue\n if (operation === 'RENAMED') {\n for (let index = section.start + 1; index < section.end; index += 1) {\n const from = lines[index].match(/^\\s*-?\\s*FROM:\\s*`?### Requirement:\\s*(.+?)`?\\s*$/i)\n if (!from) continue\n let toIndex = index + 1\n while (toIndex < section.end && !lines[toIndex].trim()) toIndex += 1\n const to = lines[toIndex]?.match(/^\\s*-?\\s*TO:\\s*`?### Requirement:\\s*(.+?)`?\\s*$/i)\n if (!to) throw new ConversionError(`RENAMED entry for \"${from[1].trim()}\" has no TO line`)\n model.rules.push({\n name: 'Rename requirement',\n description: '',\n tags: precedingTags(lines, index),\n operation,\n rename: { from: from[1].trim(), to: to[1].trim() },\n background: null,\n scenarios: [],\n })\n index = toIndex\n }\n continue\n }\n const headings = headingsInRange(lines, mask, 3, section.start + 1, section.end).filter(\n (heading) => /^Requirement:\\s*/i.test(heading.title),\n )\n for (let index = 0; index < headings.length; index += 1) {\n const heading = headings[index]\n const end =\n index + 1 < headings.length ? tagBlockStart(lines, headings[index + 1].index) : section.end\n const rule = parseOpenSpecRequirement(lines, mask, heading, end)\n rule.operation = operation\n model.rules.push(rule)\n }\n }\n}\n\nexport function parseOpenSpecRequirement(\n lines: string[],\n mask: boolean[],\n heading: Heading,\n end: number,\n): RuleModel {\n const childHeadings = headingsInRange(lines, mask, 4, heading.index + 1, end).filter((item) =>\n /^(Scenario(?: Outline)?|Background):/i.test(item.title),\n )\n const firstChild = childHeadings[0] ? tagBlockStart(lines, childHeadings[0].index) : end\n const headerBody = trimBlank(lines.slice(heading.index + 1, firstChild))\n let background = null\n let descriptionLines = headerBody\n const marker = headerBody.findIndex((line) => /^\\*\\*Background:/i.test(line))\n if (marker >= 0) {\n descriptionLines = trimBlank(headerBody.slice(0, marker))\n background = parseOpenSpecBackground(headerBody.slice(marker), 'rule')\n }\n const rule: RuleModel = {\n name: heading.title.replace(/^Requirement:\\s*/i, '').trim(),\n description: descriptionLines.join('\\n').trim(),\n tags: precedingTags(lines, heading.index),\n operation: undefined,\n rename: null,\n background,\n scenarios: [],\n }\n for (let index = 0; index < childHeadings.length; index += 1) {\n const child = childHeadings[index]\n const childEnd =\n index + 1 < childHeadings.length ? tagBlockStart(lines, childHeadings[index + 1].index) : end\n if (/^Background:/i.test(child.title))\n rule.background = parseOpenSpecScenario(lines, mask, child, childEnd, true)\n else\n rule.scenarios.push(\n parseOpenSpecScenario(lines, mask, child, childEnd, false) as ScenarioModel,\n )\n }\n return rule\n}\n\nexport function parseOpenSpecBackground(lines: string[], scope: string): BackgroundModel {\n const marker = lines[0]?.match(/^\\*\\*Background:(.*?)\\*\\*\\s*$/i)\n if (!marker)\n throw new ConversionError(\n `Unsupported ${scope} Requirements preamble; expected **Background:**`,\n )\n const parsed = parseOpenSpecBody(lines.slice(1))\n return { name: marker[1].trim(), description: parsed.description, steps: parsed.steps }\n}\n\nexport function parseOpenSpecScenario(\n lines: string[],\n mask: boolean[],\n heading: Heading,\n end: number,\n background: boolean,\n): ScenarioModel | BackgroundModel {\n const examplesHeadings = headingsInRange(lines, mask, 5, heading.index + 1, end).filter((item) =>\n /^Examples:/i.test(item.title),\n )\n const bodyEnd = examplesHeadings[0] ? tagBlockStart(lines, examplesHeadings[0].index) : end\n const body = parseOpenSpecBody(lines.slice(heading.index + 1, bodyEnd))\n if (background)\n return {\n name: heading.title.replace(/^Background:\\s*/i, '').trim(),\n description: body.description,\n steps: body.steps,\n }\n const scenario: ScenarioModel = {\n kind: /^Scenario Outline:/i.test(heading.title) ? 'outline' : 'scenario',\n name: heading.title.replace(/^Scenario(?: Outline)?:\\s*/i, '').trim(),\n description: body.description,\n tags: precedingTags(lines, heading.index),\n steps: body.steps,\n examples: [],\n }\n for (let index = 0; index < examplesHeadings.length; index += 1) {\n const example = examplesHeadings[index]\n const exampleEnd =\n index + 1 < examplesHeadings.length\n ? tagBlockStart(lines, examplesHeadings[index + 1].index)\n : end\n const exampleLines = trimBlank(lines.slice(example.index + 1, exampleEnd))\n const tableIndex = exampleLines.findIndex((line) => /^\\s{2,}\\|/.test(line))\n if (tableIndex < 0) throw new ConversionError(`Examples \"${example.title}\" has no table`)\n scenario.examples.push({\n name: example.title.replace(/^Examples:\\s*/i, '').trim(),\n description: trimBlank(exampleLines.slice(0, tableIndex)).join('\\n'),\n tags: precedingTags(lines, example.index),\n rows: parseTable(exampleLines.slice(tableIndex)),\n })\n }\n return scenario\n}\n\nexport function parseOpenSpecBody(rawLines: string[]): { description: string; steps: StepModel[] } {\n const lines = trimBlank(rawLines)\n const firstStep = lines.findIndex((line) =>\n /^\\s*[-*+]\\s+\\*\\*(GIVEN|WHEN|THEN|AND|BUT)\\*\\*/i.test(line),\n )\n const description =\n firstStep < 0 ? lines.join('\\n').trim() : trimBlank(lines.slice(0, firstStep)).join('\\n')\n const steps: StepModel[] = []\n if (firstStep < 0) return { description, steps }\n let index = firstStep\n while (index < lines.length) {\n if (!lines[index].trim()) {\n index += 1\n continue\n }\n const match = lines[index].match(/^\\s*[-*+]\\s+\\*\\*(GIVEN|WHEN|THEN|AND|BUT)\\*\\*\\s+(.+)$/i)\n if (!match) throw new ConversionError(`Unsupported OpenSpec scenario line: ${lines[index]}`)\n const step: StepModel = {\n keyword: match[1].toUpperCase(),\n text: match[2],\n table: null,\n docString: null,\n }\n index += 1\n while (index < lines.length && !lines[index].trim()) index += 1\n if (index < lines.length && /^\\s*```/.test(lines[index])) {\n const opener = /^(\\s*)```(.*)$/.exec(lines[index])\n if (!opener) throw new ConversionError('Invalid DocString opener')\n const indent = opener[1].length\n const content = []\n index += 1\n while (index < lines.length && !/^\\s*```\\s*$/.test(lines[index])) {\n content.push(lines[index].slice(Math.min(indent, lines[index].length)))\n index += 1\n }\n if (index >= lines.length) throw new ConversionError('Unclosed OpenSpec DocString')\n index += 1\n step.docString = { mediaType: opener[2].trim(), content: content.join('\\n') }\n } else if (index < lines.length && /^\\s{2,}\\|/.test(lines[index])) {\n const tableLines = []\n while (index < lines.length && /^\\s{2,}\\|/.test(lines[index])) tableLines.push(lines[index++])\n step.table = parseTable(tableLines)\n }\n steps.push(step)\n }\n return { description, steps }\n}\n","import { DELTA_TAG, OPERATION_TAGS } from '../constants.js'\nimport type {\n BackgroundModel,\n DocumentModel,\n RuleModel,\n ScenarioModel,\n StepModel,\n} from '../model.js'\nimport { escapeCell, titleCase, trimBlank } from '../syntax.js'\n\nexport function serializeFeature(model: DocumentModel): string {\n const output: string[] = []\n const featureTags = model.kind === 'delta' ? [...model.tags, DELTA_TAG] : model.tags\n pushFeatureTags(output, featureTags, 0)\n output.push(`Feature: ${model.name}`)\n pushFeatureDescription(output, model.description, 2)\n if (model.background) serializeFeatureBackground(output, model.background, 2)\n for (const scenario of model.featureScenarios) serializeFeatureScenario(output, scenario, 2)\n for (const rule of model.rules) serializeFeatureRule(output, rule)\n return `${trimBlank(output).join('\\n')}\\n`\n}\n\nexport function serializeFeatureRule(output: string[], rule: RuleModel): void {\n const operationTag = rule.operation\n ? [...OPERATION_TAGS].find(([, operation]) => operation === rule.operation)?.[0]\n : null\n output.push('')\n pushFeatureTags(output, [...rule.tags, ...(operationTag ? [operationTag] : [])], 2)\n output.push(` Rule: ${rule.operation === 'RENAMED' ? 'Rename requirement' : rule.name}`)\n if (rule.operation === 'RENAMED') {\n pushFeatureDescription(\n output,\n `FROM: ### Requirement: ${rule.rename?.from}\\nTO: ### Requirement: ${rule.rename?.to}`,\n 4,\n )\n return\n }\n pushFeatureDescription(output, rule.description, 4)\n if (rule.background) serializeFeatureBackground(output, rule.background, 4)\n for (const scenario of rule.scenarios) serializeFeatureScenario(output, scenario, 4)\n}\n\nexport function serializeFeatureBackground(\n output: string[],\n background: BackgroundModel,\n indent: number,\n): void {\n output.push('', `${' '.repeat(indent)}Background:${background.name ? ` ${background.name}` : ''}`)\n pushFeatureDescription(output, background.description, indent + 2)\n pushFeatureSteps(output, background.steps, indent + 2)\n}\n\nexport function serializeFeatureScenario(\n output: string[],\n scenario: ScenarioModel,\n indent: number,\n): void {\n output.push('')\n pushFeatureTags(output, scenario.tags, indent)\n output.push(\n `${' '.repeat(indent)}${scenario.kind === 'outline' ? 'Scenario Outline' : 'Scenario'}: ${scenario.name}`,\n )\n pushFeatureDescription(output, scenario.description, indent + 2)\n pushFeatureSteps(output, scenario.steps, indent + 2)\n for (const examples of scenario.examples) {\n output.push('')\n pushFeatureTags(output, examples.tags, indent + 2)\n output.push(`${' '.repeat(indent + 2)}Examples: ${examples.name}`)\n pushFeatureDescription(output, examples.description, indent + 4)\n pushFeatureTable(output, examples.rows, indent + 4)\n }\n}\n\nexport function pushFeatureSteps(output: string[], steps: StepModel[], indent: number): void {\n const prefix = ' '.repeat(indent)\n for (const step of steps) {\n output.push(`${prefix}${titleCase(step.keyword)} ${step.text}`)\n if (step.table) pushFeatureTable(output, step.table, indent + 2)\n if (step.docString) {\n const fence = step.docString.content.split('\\n').some((line) => line.trim() === '\"\"\"')\n ? '```'\n : '\"\"\"'\n output.push(`${' '.repeat(indent + 2)}${fence}${step.docString.mediaType || ''}`)\n for (const line of step.docString.content.split('\\n'))\n output.push(`${' '.repeat(indent + 2)}${line}`)\n output.push(`${' '.repeat(indent + 2)}${fence}`)\n }\n }\n}\n\nexport function pushFeatureTable(output: string[], rows: string[][], indent: number): void {\n if (!rows?.length) return\n const prefix = ' '.repeat(indent)\n for (const row of rows) output.push(`${prefix}| ${row.map(escapeCell).join(' | ')} |`)\n}\n\nexport function pushFeatureDescription(\n output: string[],\n description: string,\n indent: number,\n): void {\n if (!description) return\n const prefix = ' '.repeat(indent)\n output.push('')\n for (const line of description.split('\\n')) output.push(line ? `${prefix}${line}` : '')\n}\n\nexport function pushFeatureTags(output: string[], tags: string[], indent: number): void {\n if (tags?.length) output.push(`${' '.repeat(indent)}${tags.join(' ')}`)\n}\n","import { DELTA_TAG, OPERATION_TAGS } from '../constants.js'\nimport type { BackgroundModel, DocumentModel, RuleModel, ScenarioModel } from '../model.js'\nimport { pushDescriptionAndSteps, pushTable, pushTags, trimBlank } from '../syntax.js'\n\nexport function serializeMdg(model: DocumentModel): string {\n const output: string[] = []\n const featureTags = model.kind === 'delta' ? [...model.tags, DELTA_TAG] : model.tags\n pushTags(output, featureTags)\n output.push(`# Feature: ${model.name}`, '')\n if (model.description) output.push(model.description, '')\n if (model.background) serializeMdgBackground(output, model.background, 2)\n for (const scenario of model.featureScenarios) serializeMdgScenario(output, scenario, 3)\n for (const rule of model.rules) serializeMdgRule(output, rule)\n return `${trimBlank(output).join('\\n')}\\n`\n}\n\nexport function serializeMdgRule(output: string[], rule: RuleModel): void {\n const operationTag = rule.operation\n ? [...OPERATION_TAGS].find(([, operation]) => operation === rule.operation)?.[0]\n : null\n pushTags(output, [...rule.tags, ...(operationTag ? [operationTag] : [])])\n output.push(`## Rule: ${rule.operation === 'RENAMED' ? 'Rename requirement' : rule.name}`, '')\n if (rule.operation === 'RENAMED') {\n output.push(\n `FROM: \\`### Requirement: ${rule.rename?.from}\\``,\n `TO: \\`### Requirement: ${rule.rename?.to}\\``,\n '',\n )\n return\n }\n if (rule.description) output.push(rule.description, '')\n if (rule.background) serializeMdgBackground(output, rule.background, 3)\n for (const scenario of rule.scenarios) serializeMdgScenario(output, scenario, 3)\n}\n\nexport function serializeMdgBackground(\n output: string[],\n background: BackgroundModel,\n level: number,\n): void {\n output.push(`${'#'.repeat(level)} Background:${background.name ? ` ${background.name}` : ''}`, '')\n pushDescriptionAndSteps(output, background, true)\n}\n\nexport function serializeMdgScenario(\n output: string[],\n scenario: ScenarioModel,\n level: number,\n): void {\n pushTags(output, scenario.tags)\n output.push(\n `${'#'.repeat(level)} ${scenario.kind === 'outline' ? 'Scenario Outline' : 'Scenario'}: ${scenario.name}`,\n '',\n )\n pushDescriptionAndSteps(output, scenario, true)\n for (const examples of scenario.examples) {\n pushTags(output, examples.tags)\n output.push(`${'#'.repeat(level + 1)} Examples: ${examples.name}`, '')\n if (examples.description) output.push(examples.description, '')\n pushTable(output, examples.rows, true, false)\n }\n}\n","import { DELTA_TAG, SYNTHETIC_TAG } from '../constants.js'\nimport type { DocumentModel, RuleModel, ScenarioModel } from '../model.js'\nimport { pushDescriptionAndSteps, pushTable, pushTags, trimBlank } from '../syntax.js'\n\nexport function serializeOpenSpec(model: DocumentModel): string {\n const output: string[] = []\n pushTags(output, model.tags)\n if (model.kind === 'delta') pushTags(output, [DELTA_TAG])\n output.push(`# ${model.name}`, '')\n if (model.description) output.push('## Purpose', '', model.description, '')\n if (model.kind === 'delta') serializeOpenSpecDelta(output, model)\n else serializeOpenSpecMain(output, model)\n return `${trimBlank(output).join('\\n')}\\n`\n}\n\nexport function serializeOpenSpecMain(output: string[], model: DocumentModel): void {\n output.push('## Requirements', '')\n if (model.background) {\n output.push(`**Background:${model.background.name ? ` ${model.background.name}` : ''}**`, '')\n pushDescriptionAndSteps(output, model.background)\n }\n if (model.featureScenarios.length) {\n pushTags(output, [SYNTHETIC_TAG])\n output.push(\n '### Requirement: Feature-level scenarios',\n '',\n 'The system SHALL exhibit the feature-level behavior defined by the following scenarios.',\n '',\n )\n for (const scenario of model.featureScenarios) serializeOpenSpecScenario(output, scenario)\n }\n for (const rule of model.rules) serializeOpenSpecRule(output, rule)\n}\n\nexport function serializeOpenSpecDelta(output: string[], model: DocumentModel): void {\n for (const operation of new Set(model.rules.map((rule) => rule.operation))) {\n const rules = model.rules.filter((rule) => rule.operation === operation)\n if (!rules.length) continue\n output.push(`## ${operation} Requirements`, '')\n if (operation === 'RENAMED') {\n for (const rule of rules) {\n pushTags(output, rule.tags)\n output.push(\n `- FROM: \\`### Requirement: ${rule.rename?.from}\\``,\n `- TO: \\`### Requirement: ${rule.rename?.to}\\``,\n '',\n )\n }\n } else if (operation === 'REMOVED') {\n for (const rule of rules) {\n pushTags(output, rule.tags)\n output.push(`### Requirement: ${rule.name}`, '')\n }\n } else {\n for (const rule of rules) serializeOpenSpecRule(output, rule)\n }\n }\n}\n\nexport function serializeOpenSpecRule(output: string[], rule: RuleModel): void {\n pushTags(output, rule.tags)\n output.push(`### Requirement: ${rule.name}`, '', rule.description, '')\n if (rule.background) {\n output.push(`#### Background: ${rule.background.name}`.trimEnd(), '')\n pushDescriptionAndSteps(output, rule.background)\n }\n for (const scenario of rule.scenarios) serializeOpenSpecScenario(output, scenario)\n}\n\nexport function serializeOpenSpecScenario(output: string[], scenario: ScenarioModel): void {\n pushTags(output, scenario.tags)\n output.push(\n `#### ${scenario.kind === 'outline' ? 'Scenario Outline' : 'Scenario'}: ${scenario.name}`,\n '',\n )\n pushDescriptionAndSteps(output, scenario)\n for (const examples of scenario.examples) {\n pushTags(output, examples.tags)\n output.push(`##### Examples: ${examples.name}`, '')\n if (examples.description) output.push(examples.description, '')\n pushTable(output, examples.rows)\n }\n}\n","import { RESERVED_PREFIXES } from '../constants.js'\nimport { ConversionError } from '../errors.js'\nimport type { DocumentModel } from '../model.js'\n\nexport function validateProfile(model: DocumentModel, sourceKind: string): void {\n if (!model.name) throw new ConversionError('Feature/spec name is required')\n if (!model.description && model.kind === 'main')\n throw new ConversionError('Feature Purpose/description is required')\n const allTags = [\n ...model.tags,\n ...model.rules.flatMap((rule) => [\n ...rule.tags,\n ...rule.scenarios.flatMap((scenario) => [\n ...scenario.tags,\n ...scenario.examples.flatMap((examples) => examples.tags),\n ]),\n ]),\n ...model.featureScenarios.flatMap((scenario) => scenario.tags),\n ]\n for (const tag of allTags) {\n if (RESERVED_PREFIXES.some((prefix) => tag.startsWith(prefix))) {\n throw new ConversionError(`Reserved tag is not allowed as user metadata: ${tag}`)\n }\n }\n if (model.kind === 'main') {\n if (!model.rules.length && !model.featureScenarios.length)\n throw new ConversionError('Feature has no behavior to convert')\n for (const rule of model.rules) {\n if (!/\\b(?:SHALL|MUST)\\b/.test(rule.description)) {\n throw new ConversionError(`Rule/Requirement \"${rule.name}\" must contain SHALL or MUST`)\n }\n if (!rule.scenarios.length && !rule.background) {\n throw new ConversionError(`Rule/Requirement \"${rule.name}\" has no scenarios or Background`)\n }\n }\n } else {\n if (model.background || model.featureScenarios.length)\n throw new ConversionError(\n 'Delta Features cannot contain feature-level Background or scenarios',\n )\n for (const rule of model.rules) {\n if (\n (rule.operation === 'ADDED' || rule.operation === 'MODIFIED') &&\n !/\\b(?:SHALL|MUST)\\b/.test(rule.description)\n ) {\n throw new ConversionError(\n `${rule.operation} Rule \"${rule.name}\" must contain SHALL or MUST`,\n )\n }\n if (\n (rule.operation === 'ADDED' || rule.operation === 'MODIFIED') &&\n !rule.scenarios.length &&\n !rule.background\n ) {\n throw new ConversionError(`${rule.operation} Rule \"${rule.name}\" requires behavior`)\n }\n if (\n rule.operation === 'REMOVED' &&\n (rule.description || rule.scenarios.length || rule.background)\n ) {\n throw new ConversionError(`REMOVED Rule \"${rule.name}\" must contain only its name`)\n }\n if (rule.operation === 'RENAMED' && !rule.rename)\n throw new ConversionError('RENAMED Rule requires FROM and TO')\n }\n }\n for (const scenario of [\n ...model.featureScenarios,\n ...model.rules.flatMap((rule) => rule.scenarios),\n ]) {\n if (!scenario.steps.length)\n throw new ConversionError(`Scenario \"${scenario.name}\" has no steps`)\n if (scenario.kind === 'outline' && !scenario.examples.length)\n throw new ConversionError(`Scenario Outline \"${scenario.name}\" has no Examples`)\n if (scenario.kind === 'scenario' && scenario.examples.length)\n throw new ConversionError(`Scenario \"${scenario.name}\" cannot contain Examples`)\n }\n if (sourceKind === 'openspec' && model.kind === 'delta' && !model.rules.length) {\n throw new ConversionError('Delta has no operations')\n }\n}\n","import { ConversionError } from './errors.js'\nimport type { ConversionOptions } from './model.js'\nimport { assertPreserved } from './model.js'\nimport { parseFeatureModel } from './parsers/feature.js'\nimport { parseMdgModel } from './parsers/mdg.js'\nimport { detectOpenSpecKind, parseOpenSpecModel } from './parsers/openspec.js'\nimport { serializeFeature } from './renderers/feature.js'\nimport { serializeMdg } from './renderers/mdg.js'\nimport { serializeOpenSpec } from './renderers/openspec.js'\nimport { resolveOpenSpecName, slugify } from './syntax.js'\nimport {\n gherkinDiagnostics,\n openSpecDiagnostics,\n parseAndValidateFeature,\n parseAndValidateMdg,\n validateOpenSpec,\n} from './validation/official.js'\nimport { validateProfile } from './validation/profile.js'\n\nexport async function mdgToOpsx(text: string, options: ConversionOptions = {}): Promise<string> {\n const source = parseAndValidateMdg(text, options.sourcePath)\n if (!source.valid || !source.document)\n throw new ConversionError('Invalid Markdown with Gherkin input', gherkinDiagnostics(source))\n const model = parseMdgModel(text, source.document)\n validateProfile(model, 'mdg')\n const output = serializeOpenSpec(model)\n const name = options.name || slugify(model.name)\n const report = await validateOpenSpec(output, {\n kind: model.kind,\n name,\n projectRoot: options.projectRoot,\n })\n if (!report.valid)\n throw new ConversionError(\n 'Generated OpenSpec failed official validation',\n openSpecDiagnostics(report),\n )\n assertPreserved(model, parseOpenSpecModel(output, { kind: model.kind, name }))\n return output\n}\n\nasync function openSpecModel(text: string, options: ConversionOptions) {\n const kind = detectOpenSpecKind(text)\n const name = resolveOpenSpecName(text, options)\n const report = await validateOpenSpec(text, { kind, name, projectRoot: options.projectRoot })\n if (!report.valid)\n throw new ConversionError('Invalid OpenSpec input', openSpecDiagnostics(report))\n const model = parseOpenSpecModel(text, { kind, name })\n validateProfile(model, 'openspec')\n return model\n}\n\nexport async function opsxToMdg(text: string, options: ConversionOptions = {}): Promise<string> {\n const model = await openSpecModel(text, options)\n const output = serializeMdg(model)\n const target = parseAndValidateMdg(output)\n if (!target.valid || !target.document)\n throw new ConversionError(\n 'Generated Markdown with Gherkin failed official validation',\n gherkinDiagnostics(target),\n )\n assertPreserved(model, parseMdgModel(output, target.document))\n return output\n}\n\nexport async function opsxToFeature(\n text: string,\n options: ConversionOptions = {},\n): Promise<string> {\n const model = await openSpecModel(text, options)\n const output = serializeFeature(model)\n const target = parseAndValidateFeature(output)\n if (!target.valid || !target.document)\n throw new ConversionError(\n 'Generated Gherkin feature failed official validation',\n gherkinDiagnostics(target),\n )\n assertPreserved(model, parseFeatureModel(target.document))\n return output\n}\n","import type { Readable } from 'node:stream'\nimport type { Direction } from '../model.js'\n\ninterface Options {\n force: boolean\n help: boolean\n text?: string\n input?: string\n output?: string\n name?: string\n projectRoot?: string\n}\n\nimport { link, mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { basename, dirname, resolve } from 'node:path'\nimport { mdgToOpsx, opsxToFeature, opsxToMdg } from '../convert.js'\nimport { ConversionError, isFsError } from '../errors.js'\n\nexport async function runConverterCli(\n direction: Direction,\n argv = process.argv.slice(2),\n): Promise<number> {\n try {\n const options = parseArgs(argv, direction)\n if (options.help) {\n process.stdout.write(usage(direction))\n return 0\n }\n const input = await readInput(options)\n const converters = {\n 'mdg-to-opsx': mdgToOpsx,\n 'opsx-to-mdg': opsxToMdg,\n 'opsx-to-feature': opsxToFeature,\n }\n const convert = converters[direction]\n const output = await convert(input.text, {\n sourcePath: input.path,\n name: options.name,\n projectRoot: options.projectRoot ? resolve(options.projectRoot) : undefined,\n })\n if (options.output) await writeAtomic(resolve(options.output), output, options.force)\n else process.stdout.write(output)\n return 0\n } catch (error) {\n if (error instanceof ConversionError) {\n process.stderr.write(`${error.message}\\n`)\n for (const diagnostic of error.diagnostics) process.stderr.write(`- ${diagnostic}\\n`)\n return 1\n }\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`)\n return 2\n }\n}\n\nfunction parseArgs(argv: string[], direction: Direction): Options {\n const options: Options = { force: false, help: false }\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index]\n if (argument === '--help' || argument === '-h') options.help = true\n else if (argument === '--force') options.force = true\n else if (argument === '--text') options.text = requiredValue(argv, ++index, argument)\n else if (argument === '--output' || argument === '-o')\n options.output = requiredValue(argv, ++index, argument)\n else if (argument === '--name') options.name = requiredValue(argv, ++index, argument)\n else if (argument === '--project-root')\n options.projectRoot = requiredValue(argv, ++index, argument)\n else if (argument.startsWith('-'))\n throw new Error(`Unknown option: ${argument}\\n${usage(direction)}`)\n else if (!options.input) options.input = argument\n else throw new Error(`Only one input path is allowed\\n${usage(direction)}`)\n }\n if (options.input && options.text !== undefined)\n throw new Error(`Use either an input path or --text, not both\\n${usage(direction)}`)\n if (options.force && !options.output) throw new Error('--force requires --output')\n return options\n}\n\nasync function readInput(options: Options) {\n if (options.text !== undefined) return { text: options.text, path: undefined }\n if (options.input) {\n const path = resolve(options.input)\n return { text: await readFile(path, 'utf8'), path }\n }\n if (process.stdin.isTTY) throw new Error('No input: pass a path, --text, or pipe text on stdin')\n return { text: await readStream(process.stdin), path: undefined }\n}\n\nasync function readStream(stream: Readable): Promise<string> {\n stream.setEncoding('utf8')\n let result = ''\n for await (const chunk of stream) result += chunk\n return result\n}\n\nexport async function writeAtomic(path: string, content: string, force: boolean): Promise<void> {\n await mkdir(dirname(path), { recursive: true })\n const temporary = resolve(dirname(path), `.${basename(path)}.${process.pid}.${Date.now()}.tmp`)\n await writeFile(temporary, content, { encoding: 'utf8', flag: 'wx' })\n try {\n if (force) await rename(temporary, path)\n else {\n try {\n await link(temporary, path)\n } catch (error) {\n if (isFsError(error, 'EEXIST'))\n throw new Error(`Output already exists: ${path} (use --force to replace it)`)\n throw error\n }\n await unlink(temporary)\n }\n } catch (error) {\n await unlink(temporary).catch(() => {})\n throw error\n }\n}\n\nfunction requiredValue(argv: string[], index: number, option: string): string {\n if (index >= argv.length) throw new Error(`Missing value for ${option}`)\n return argv[index]\n}\n\nfunction usage(direction: Direction): string {\n return `Usage: ${direction} [input] [--text content] [-o output] [--force] [--name name] [--project-root path]\\n`\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { t as runConverterCli } from "./converter-CFtzcfoM.mjs";
3
+ //#region src/bin/mdg-to-opsx.ts
4
+ process.exitCode = await runConverterCli("mdg-to-opsx");
5
+ //#endregion
6
+ export {};
7
+
8
+ //# sourceMappingURL=mdg-to-opsx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mdg-to-opsx.mjs","names":[],"sources":["../src/bin/mdg-to-opsx.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runConverterCli } from '../cli/converter.js'\n\nprocess.exitCode = await runConverterCli('mdg-to-opsx')\n"],"mappings":";;;AAGA,QAAQ,WAAW,MAAM,gBAAgB,aAAa"}
@@ -0,0 +1,91 @@
1
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import { generateMessages } from "@cucumber/gherkin";
5
+ import { IdGenerator, SourceMediaType } from "@cucumber/messages";
6
+ //#region src/errors.ts
7
+ var ConversionError = class extends Error {
8
+ diagnostics;
9
+ constructor(message, diagnostics = []) {
10
+ super(message);
11
+ this.diagnostics = diagnostics;
12
+ this.name = "ConversionError";
13
+ }
14
+ };
15
+ function errorMessage(error) {
16
+ return error instanceof Error ? error.message : String(error);
17
+ }
18
+ function isFsError(error, code) {
19
+ return error instanceof Error && "code" in error && error.code === code;
20
+ }
21
+ //#endregion
22
+ //#region src/validation/official.ts
23
+ let validatorClass;
24
+ async function validator() {
25
+ if (!validatorClass) {
26
+ const entry = import.meta.resolve("@fission-ai/openspec");
27
+ validatorClass = (await import(new URL("./core/validation/validator.js", entry).href)).Validator;
28
+ }
29
+ return new validatorClass(true);
30
+ }
31
+ async function validateOpenSpec(text, { kind, name = "spec", projectRoot }) {
32
+ const instance = await validator();
33
+ if (kind === "main") return instance.validateSpecContent(name, text);
34
+ const temporaryRoot = await mkdtemp(join(tmpdir(), "opsx-gherkin-"));
35
+ try {
36
+ const changeDir = join(temporaryRoot, "change");
37
+ if (name.split(/[\\/]/).some((part) => part === ".." || part === ".")) return {
38
+ valid: false,
39
+ issues: [{
40
+ level: "ERROR",
41
+ message: "Invalid capability name"
42
+ }]
43
+ };
44
+ const specDir = join(changeDir, "specs", ...name.split("/"));
45
+ await mkdir(specDir, { recursive: true });
46
+ await writeFile(join(specDir, "spec.md"), text, "utf8");
47
+ return await instance.validateChangeDeltaSpecs(changeDir, projectRoot ? { mainSpecsDir: join(projectRoot, "openspec", "specs") } : {});
48
+ } finally {
49
+ await rm(temporaryRoot, {
50
+ recursive: true,
51
+ force: true
52
+ });
53
+ }
54
+ }
55
+ async function validateOpenSpecFile(path) {
56
+ return (await validator()).validateSpec(path);
57
+ }
58
+ function parseAndValidateMdg(text, uri = "memory.feature.md") {
59
+ return parseGherkin(text, uri, SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_MARKDOWN);
60
+ }
61
+ function parseAndValidateFeature(text, uri = "memory.feature") {
62
+ return parseGherkin(text, uri, SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN);
63
+ }
64
+ function parseGherkin(text, uri, mediaType) {
65
+ const envelopes = generateMessages(text, uri, mediaType, {
66
+ defaultDialect: "en",
67
+ includeSource: false,
68
+ includeGherkinDocument: true,
69
+ includePickles: true,
70
+ newId: IdGenerator.incrementing()
71
+ });
72
+ const errors = envelopes.flatMap((envelope) => envelope.parseError ? [envelope.parseError] : []);
73
+ const document = envelopes.find((envelope) => envelope.gherkinDocument)?.gherkinDocument;
74
+ const pickles = envelopes.flatMap((envelope) => envelope.pickle ? [envelope.pickle] : []);
75
+ return {
76
+ valid: errors.length === 0 && Boolean(document?.feature),
77
+ errors,
78
+ document,
79
+ pickles
80
+ };
81
+ }
82
+ function openSpecDiagnostics(report) {
83
+ return report.issues.map((issue) => `${issue.line ? `line ${issue.line}` : issue.path || "document"}: ${issue.message}`);
84
+ }
85
+ function gherkinDiagnostics(report) {
86
+ return report.errors.map((issue) => `line ${issue.source.location?.line ?? 1}:${issue.source.location?.column ?? 1}: ${issue.message}`);
87
+ }
88
+ //#endregion
89
+ export { validateOpenSpec as a, errorMessage as c, parseAndValidateMdg as i, isFsError as l, openSpecDiagnostics as n, validateOpenSpecFile as o, parseAndValidateFeature as r, ConversionError as s, gherkinDiagnostics as t };
90
+
91
+ //# sourceMappingURL=official-99qBUZpr.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"official-99qBUZpr.mjs","names":[],"sources":["../src/errors.ts","../src/validation/official.ts"],"sourcesContent":["export class ConversionError extends Error {\n constructor(\n message: string,\n public readonly diagnostics: readonly string[] = [],\n ) {\n super(message)\n this.name = 'ConversionError'\n }\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nexport function isFsError(error: unknown, code: string): boolean {\n return error instanceof Error && 'code' in error && error.code === code\n}\n","import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { generateMessages } from '@cucumber/gherkin'\nimport { IdGenerator, SourceMediaType } from '@cucumber/messages'\nimport type { DocumentKind } from '../model.js'\n\nexport interface ValidationIssue {\n message: string\n level: string\n path?: string\n line?: number\n}\nexport interface ValidationReport {\n valid: boolean\n issues: ValidationIssue[]\n}\ninterface OpenSpecValidator {\n validateSpecContent(name: string, text: string): Promise<ValidationReport>\n validateSpec(path: string): Promise<ValidationReport>\n validateChangeDeltaSpecs(\n path: string,\n options: { mainSpecsDir?: string },\n ): Promise<ValidationReport>\n}\ntype ValidatorConstructor = new (strict: boolean) => OpenSpecValidator\nlet validatorClass: ValidatorConstructor | undefined\n\nasync function validator(): Promise<OpenSpecValidator> {\n if (!validatorClass) {\n const entry = import.meta.resolve('@fission-ai/openspec')\n const module = await import(new URL('./core/validation/validator.js', entry).href)\n validatorClass = module.Validator as ValidatorConstructor\n }\n return new validatorClass(true)\n}\n\nexport async function validateOpenSpec(\n text: string,\n { kind, name = 'spec', projectRoot }: { kind: DocumentKind; name?: string; projectRoot?: string },\n): Promise<ValidationReport> {\n const instance = await validator()\n if (kind === 'main') return instance.validateSpecContent(name, text)\n const temporaryRoot = await mkdtemp(join(tmpdir(), 'opsx-gherkin-'))\n try {\n const changeDir = join(temporaryRoot, 'change')\n // A capability name may be nested, but may never escape the private change directory.\n if (name.split(/[\\\\/]/).some((part) => part === '..' || part === '.')) {\n return { valid: false, issues: [{ level: 'ERROR', message: 'Invalid capability name' }] }\n }\n const specDir = join(changeDir, 'specs', ...name.split('/'))\n await mkdir(specDir, { recursive: true })\n await writeFile(join(specDir, 'spec.md'), text, 'utf8')\n return await instance.validateChangeDeltaSpecs(\n changeDir,\n projectRoot ? { mainSpecsDir: join(projectRoot, 'openspec', 'specs') } : {},\n )\n } finally {\n await rm(temporaryRoot, { recursive: true, force: true })\n }\n}\n\nexport async function validateOpenSpecFile(path: string): Promise<ValidationReport> {\n return (await validator()).validateSpec(path)\n}\n\nexport function parseAndValidateMdg(text: string, uri = 'memory.feature.md') {\n return parseGherkin(text, uri, SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_MARKDOWN)\n}\nexport function parseAndValidateFeature(text: string, uri = 'memory.feature') {\n return parseGherkin(text, uri, SourceMediaType.TEXT_X_CUCUMBER_GHERKIN_PLAIN)\n}\nfunction parseGherkin(text: string, uri: string, mediaType: SourceMediaType) {\n const envelopes = generateMessages(text, uri, mediaType, {\n defaultDialect: 'en',\n includeSource: false,\n includeGherkinDocument: true,\n includePickles: true,\n newId: IdGenerator.incrementing(),\n })\n const errors = envelopes.flatMap((envelope) => (envelope.parseError ? [envelope.parseError] : []))\n const document = envelopes.find((envelope) => envelope.gherkinDocument)?.gherkinDocument\n const pickles = envelopes.flatMap((envelope) => (envelope.pickle ? [envelope.pickle] : []))\n return { valid: errors.length === 0 && Boolean(document?.feature), errors, document, pickles }\n}\n\nexport function openSpecDiagnostics(report: ValidationReport): string[] {\n return report.issues.map(\n (issue) => `${issue.line ? `line ${issue.line}` : issue.path || 'document'}: ${issue.message}`,\n )\n}\nexport function gherkinDiagnostics(report: ReturnType<typeof parseAndValidateMdg>): string[] {\n return report.errors.map(\n (issue) =>\n `line ${issue.source.location?.line ?? 1}:${issue.source.location?.column ?? 1}: ${issue.message}`,\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { t as runConverterCli } from "./converter-CFtzcfoM.mjs";
3
+ //#region src/bin/opsx-to-feature.ts
4
+ process.exitCode = await runConverterCli("opsx-to-feature");
5
+ //#endregion
6
+ export {};
7
+
8
+ //# sourceMappingURL=opsx-to-feature.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opsx-to-feature.mjs","names":[],"sources":["../src/bin/opsx-to-feature.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runConverterCli } from '../cli/converter.js'\n\nprocess.exitCode = await runConverterCli('opsx-to-feature')\n"],"mappings":";;;AAGA,QAAQ,WAAW,MAAM,gBAAgB,iBAAiB"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { t as runConverterCli } from "./converter-CFtzcfoM.mjs";
3
+ //#region src/bin/opsx-to-mdg.ts
4
+ process.exitCode = await runConverterCli("opsx-to-mdg");
5
+ //#endregion
6
+ export {};
7
+
8
+ //# sourceMappingURL=opsx-to-mdg.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opsx-to-mdg.mjs","names":[],"sources":["../src/bin/opsx-to-mdg.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runConverterCli } from '../cli/converter.js'\n\nprocess.exitCode = await runConverterCli('opsx-to-mdg')\n"],"mappings":";;;AAGA,QAAQ,WAAW,MAAM,gBAAgB,aAAa"}
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+ import { c as errorMessage, i as parseAndValidateMdg, o as validateOpenSpecFile, r as parseAndValidateFeature } from "./official-99qBUZpr.mjs";
3
+ import { readFile } from "node:fs/promises";
4
+ import { resolve } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ //#region src/cli/validator.ts
7
+ const usage = "Usage: validate-spec [--format openspec|mdg|feature] <file>";
8
+ async function runValidatorCli(args = process.argv.slice(2)) {
9
+ try {
10
+ let format;
11
+ let file;
12
+ for (let index = 0; index < args.length; index++) if (args[index] === "--format") {
13
+ format = args[++index];
14
+ if (!format) throw new Error(usage);
15
+ } else if (!file && !args[index].startsWith("-")) file = args[index];
16
+ else throw new Error(usage);
17
+ if (!file || format && ![
18
+ "openspec",
19
+ "mdg",
20
+ "feature",
21
+ "gherkin"
22
+ ].includes(format)) throw new Error(usage);
23
+ const path = resolve(file);
24
+ format ??= path.endsWith(".feature.md") ? "mdg" : path.endsWith(".feature") ? "feature" : "openspec";
25
+ if (format === "gherkin") format = path.endsWith(".feature.md") ? "mdg" : "feature";
26
+ const text = await readFile(path, "utf8");
27
+ if (format === "openspec") {
28
+ const report = await validateOpenSpecFile(path);
29
+ process.stdout.write(`${JSON.stringify({
30
+ format,
31
+ file: path,
32
+ valid: report.valid,
33
+ issues: report.issues
34
+ }, null, 2)}\n`);
35
+ return report.valid ? 0 : 1;
36
+ }
37
+ const report = (format === "mdg" ? parseAndValidateMdg : parseAndValidateFeature)(text, pathToFileURL(path).href);
38
+ process.stdout.write(`${JSON.stringify({
39
+ format,
40
+ file: path,
41
+ valid: report.valid,
42
+ errors: report.errors
43
+ }, null, 2)}\n`);
44
+ return report.valid ? 0 : 1;
45
+ } catch (error) {
46
+ process.stderr.write(`${errorMessage(error)}\n`);
47
+ return 2;
48
+ }
49
+ }
50
+ //#endregion
51
+ //#region src/bin/validate-spec.ts
52
+ process.exitCode = await runValidatorCli();
53
+ //#endregion
54
+ export {};
55
+
56
+ //# sourceMappingURL=validate-spec.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-spec.mjs","names":[],"sources":["../src/cli/validator.ts","../src/bin/validate-spec.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { errorMessage } from '../errors.js'\nimport {\n parseAndValidateFeature,\n parseAndValidateMdg,\n validateOpenSpecFile,\n} from '../validation/official.js'\n\nconst usage = 'Usage: validate-spec [--format openspec|mdg|feature] <file>'\n\nexport async function runValidatorCli(args = process.argv.slice(2)): Promise<number> {\n try {\n let format: string | undefined\n let file: string | undefined\n for (let index = 0; index < args.length; index++) {\n if (args[index] === '--format') {\n format = args[++index]\n if (!format) throw new Error(usage)\n } else if (!file && !args[index].startsWith('-')) file = args[index]\n else throw new Error(usage)\n }\n if (!file || (format && !['openspec', 'mdg', 'feature', 'gherkin'].includes(format)))\n throw new Error(usage)\n const path = resolve(file)\n format ??= path.endsWith('.feature.md')\n ? 'mdg'\n : path.endsWith('.feature')\n ? 'feature'\n : 'openspec'\n if (format === 'gherkin') format = path.endsWith('.feature.md') ? 'mdg' : 'feature'\n const text = await readFile(path, 'utf8')\n if (format === 'openspec') {\n const report = await validateOpenSpecFile(path)\n process.stdout.write(\n `${JSON.stringify({ format, file: path, valid: report.valid, issues: report.issues }, null, 2)}\\n`,\n )\n return report.valid ? 0 : 1\n }\n const parse = format === 'mdg' ? parseAndValidateMdg : parseAndValidateFeature\n const report = parse(text, pathToFileURL(path).href)\n process.stdout.write(\n `${JSON.stringify({ format, file: path, valid: report.valid, errors: report.errors }, null, 2)}\\n`,\n )\n return report.valid ? 0 : 1\n } catch (error) {\n process.stderr.write(`${errorMessage(error)}\\n`)\n return 2\n }\n}\n","#!/usr/bin/env node\nimport { runValidatorCli } from '../cli/validator.js'\n\nprocess.exitCode = await runValidatorCli()\n"],"mappings":";;;;;;AAUA,MAAM,QAAQ;AAEd,eAAsB,gBAAgB,OAAO,QAAQ,KAAK,MAAM,CAAC,GAAoB;CACnF,IAAI;EACF,IAAI;EACJ,IAAI;EACJ,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SACvC,IAAI,KAAK,WAAW,YAAY;GAC9B,SAAS,KAAK,EAAE;GAChB,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,KAAK;EACpC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,WAAW,GAAG,GAAG,OAAO,KAAK;OACzD,MAAM,IAAI,MAAM,KAAK;EAE5B,IAAI,CAAC,QAAS,UAAU,CAAC;GAAC;GAAY;GAAO;GAAW;EAAS,CAAC,CAAC,SAAS,MAAM,GAChF,MAAM,IAAI,MAAM,KAAK;EACvB,MAAM,OAAO,QAAQ,IAAI;EACzB,WAAW,KAAK,SAAS,aAAa,IAClC,QACA,KAAK,SAAS,UAAU,IACtB,YACA;EACN,IAAI,WAAW,WAAW,SAAS,KAAK,SAAS,aAAa,IAAI,QAAQ;EAC1E,MAAM,OAAO,MAAM,SAAS,MAAM,MAAM;EACxC,IAAI,WAAW,YAAY;GACzB,MAAM,SAAS,MAAM,qBAAqB,IAAI;GAC9C,QAAQ,OAAO,MACb,GAAG,KAAK,UAAU;IAAE;IAAQ,MAAM;IAAM,OAAO,OAAO;IAAO,QAAQ,OAAO;GAAO,GAAG,MAAM,CAAC,EAAE,GACjG;GACA,OAAO,OAAO,QAAQ,IAAI;EAC5B;EAEA,MAAM,UADQ,WAAW,QAAQ,sBAAsB,wBAAA,CAClC,MAAM,cAAc,IAAI,CAAC,CAAC,IAAI;EACnD,QAAQ,OAAO,MACb,GAAG,KAAK,UAAU;GAAE;GAAQ,MAAM;GAAM,OAAO,OAAO;GAAO,QAAQ,OAAO;EAAO,GAAG,MAAM,CAAC,EAAE,GACjG;EACA,OAAO,OAAO,QAAQ,IAAI;CAC5B,SAAS,OAAO;EACd,QAAQ,OAAO,MAAM,GAAG,aAAa,KAAK,EAAE,GAAG;EAC/C,OAAO;CACT;AACF;;;AC/CA,QAAQ,WAAW,MAAM,gBAAgB"}
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "opsx-gherkin",
3
+ "version": "1.0.0",
4
+ "description": "Deterministic OpenSpec and Gherkin conversion with a self-contained syntax compatibility skill.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/aquine-kujaruk/opsx-gherkin.git"
8
+ },
9
+ "homepage": "https://github.com/aquine-kujaruk/opsx-gherkin#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/aquine-kujaruk/opsx-gherkin/issues"
12
+ },
13
+ "keywords": [
14
+ "openspec",
15
+ "gherkin",
16
+ "markdown",
17
+ "cli",
18
+ "specification",
19
+ "conversion"
20
+ ],
21
+ "license": "MIT",
22
+ "type": "module",
23
+ "engines": {
24
+ "node": ">=22.18.0"
25
+ },
26
+ "packageManager": "pnpm@11.22.0",
27
+ "bin": {
28
+ "opsx-gherkin": "./dist/cli.mjs",
29
+ "mdg-to-opsx": "./dist/mdg-to-opsx.mjs",
30
+ "opsx-to-mdg": "./dist/opsx-to-mdg.mjs",
31
+ "opsx-to-feature": "./dist/opsx-to-feature.mjs",
32
+ "validate-spec": "./dist/validate-spec.mjs"
33
+ },
34
+ "exports": {
35
+ "./package.json": "./package.json"
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "skills/opsx-gherkin",
40
+ "README.md",
41
+ "LICENSE",
42
+ "CHANGELOG.md",
43
+ "CONTRIBUTING.md",
44
+ "SECURITY.md"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "provenance": true
49
+ },
50
+ "scripts": {
51
+ "build": "tsdown",
52
+ "check": "biome check .",
53
+ "check:fix": "biome check --write .",
54
+ "typecheck": "tsc --noEmit",
55
+ "test": "pnpm build && vitest run",
56
+ "test:coverage": "pnpm build && vitest run --coverage",
57
+ "test:package": "pnpm build && node scripts/smoke-package.mjs",
58
+ "verify": "pnpm check && pnpm typecheck && pnpm test:coverage && pnpm exec publint && node scripts/smoke-package.mjs",
59
+ "prepack": "npm run build",
60
+ "release": "semantic-release"
61
+ },
62
+ "dependencies": {
63
+ "@cucumber/gherkin": "42.0.1",
64
+ "@cucumber/messages": "34.2.0",
65
+ "@fission-ai/openspec": "1.11.0"
66
+ },
67
+ "devDependencies": {
68
+ "@biomejs/biome": "2.5.9",
69
+ "@commitlint/cli": "21.2.2",
70
+ "@commitlint/config-conventional": "21.2.2",
71
+ "@semantic-release/changelog": "7.0.0",
72
+ "@semantic-release/commit-analyzer": "13.0.1",
73
+ "@semantic-release/git": "11.0.1",
74
+ "@semantic-release/github": "12.0.9",
75
+ "@semantic-release/npm": "13.1.5",
76
+ "@semantic-release/release-notes-generator": "14.1.1",
77
+ "@types/node": "22.20.1",
78
+ "@vitest/coverage-v8": "4.1.11",
79
+ "conventional-changelog-conventionalcommits": "10.4.0",
80
+ "publint": "0.3.24",
81
+ "semantic-release": "25.0.9",
82
+ "tsdown": "0.22.14",
83
+ "typescript": "5.9.3",
84
+ "vitest": "4.1.11",
85
+ "yaml": "2.8.3"
86
+ }
87
+ }