@workos/oagen 0.6.0 → 0.8.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 (53) hide show
  1. package/dist/cli/index.mjs +1339 -451
  2. package/dist/cli/index.mjs.map +1 -1
  3. package/dist/compat/index.d.mts +144 -57
  4. package/dist/compat/index.d.mts.map +1 -1
  5. package/dist/compat/index.mjs +365 -35
  6. package/dist/compat/index.mjs.map +1 -1
  7. package/dist/{diff-CltJMcwG.mjs → diff-BaH9qa8k.mjs} +100 -23
  8. package/dist/diff-BaH9qa8k.mjs.map +1 -0
  9. package/dist/differ-CTl98yoS.d.mts +116 -0
  10. package/dist/differ-CTl98yoS.d.mts.map +1 -0
  11. package/dist/index.d.mts +4 -2
  12. package/dist/index.d.mts.map +1 -1
  13. package/dist/index.mjs +177 -4
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/{differ-CG5ZErKl.mjs → overlay-TYxHOCow.mjs} +1112 -553
  16. package/dist/overlay-TYxHOCow.mjs.map +1 -0
  17. package/dist/scripts/smoke/baseline.mjs +176 -3
  18. package/dist/scripts/smoke/baseline.mjs.map +1 -1
  19. package/dist/smoke.d.mts +43 -0
  20. package/dist/smoke.d.mts.map +1 -1
  21. package/dist/smoke.mjs +176 -3
  22. package/dist/smoke.mjs.map +1 -1
  23. package/dist/tree-sitter-C53w_0WE.mjs.map +1 -1
  24. package/dist/{types-C7g5sLuX.d.mts → types-mTtkgy_h.d.mts} +213 -2
  25. package/dist/types-mTtkgy_h.d.mts.map +1 -0
  26. package/dist/verify/index.d.mts +4 -3
  27. package/dist/verify/index.d.mts.map +1 -1
  28. package/dist/verify/index.mjs +12 -10
  29. package/dist/verify/index.mjs.map +1 -1
  30. package/docs/architecture/emitter-contract.md +2 -2
  31. package/docs/architecture/extractor-contract.md +6 -5
  32. package/docs/architecture/pipeline.md +4 -3
  33. package/docs/architecture/workflows.md +5 -3
  34. package/docs/cli.md +148 -6
  35. package/docs/contributor/public-api.md +1 -1
  36. package/docs/core/compatibility-ir.md +200 -0
  37. package/docs/core/compatibility-policy.md +170 -0
  38. package/docs/core/compatibility.md +83 -0
  39. package/docs/core/index.md +5 -0
  40. package/docs/core/manifest-schema.md +76 -0
  41. package/docs/core/quickstart.md +9 -2
  42. package/docs/core/verify-compat.md +235 -0
  43. package/package.json +1 -1
  44. package/skills/generate-emitter/SKILL.md +12 -7
  45. package/skills/generate-emitter/references/project-scaffold.md +27 -6
  46. package/skills/generate-extractor/SKILL.md +14 -8
  47. package/skills/generate-sdk/SKILL.md +2 -2
  48. package/skills/generate-smoke-test/SKILL.md +9 -5
  49. package/skills/review-operations/SKILL.md +2 -2
  50. package/skills/verify-compat/SKILL.md +1 -1
  51. package/dist/diff-CltJMcwG.mjs.map +0 -1
  52. package/dist/differ-CG5ZErKl.mjs.map +0 -1
  53. package/dist/types-C7g5sLuX.d.mts.map +0 -1
@@ -960,6 +960,7 @@ const nodeMergeAdapter = {
960
960
  const newText = newMembers.map((m) => m.text).join("\n");
961
961
  for (const match of newText.matchAll(/this\.(\w+)/g)) {
962
962
  const propName = match[1];
963
+ if (propName === "workos") continue;
963
964
  if (propName && !existingMemberKeys.has(propName)) return true;
964
965
  }
965
966
  return false;
@@ -1609,6 +1610,40 @@ function buildIgnoredSymbolNames(docstrings, regions) {
1609
1610
  for (const [name, info] of docstrings) if (regions.some((r) => info.declStartIndex >= r.startIndex && info.declStartIndex <= r.endIndex)) ignored.add(name);
1610
1611
  return ignored;
1611
1612
  }
1613
+ function clampIndex(value, contentLength) {
1614
+ if (!Number.isFinite(value)) return 0;
1615
+ if (value < 0) return 0;
1616
+ if (value > contentLength) return contentLength;
1617
+ return value;
1618
+ }
1619
+ /**
1620
+ * Resolve the declaration line start for insertion using the current content,
1621
+ * instead of relying on parser column arithmetic. This avoids misplaced inserts
1622
+ * when parser columns/offsets drift.
1623
+ */
1624
+ function declarationLineStart(content, declStartIndex) {
1625
+ const idx = clampIndex(declStartIndex, content.length);
1626
+ const prevNewline = content.lastIndexOf("\n", Math.max(0, idx - 1));
1627
+ return prevNewline === -1 ? 0 : prevNewline + 1;
1628
+ }
1629
+ /**
1630
+ * Resolve a docstring range by searching for the nearest matching text before
1631
+ * the declaration start. Falls back to parser-provided offsets when search fails.
1632
+ */
1633
+ function resolveDocRange(content, docText, declStartIndex, fallbackStart, fallbackEnd) {
1634
+ const safeDecl = clampIndex(declStartIndex, content.length);
1635
+ const safeFallbackStart = clampIndex(fallbackStart, content.length);
1636
+ const safeFallbackEnd = clampIndex(fallbackEnd, content.length);
1637
+ const found = content.lastIndexOf(docText, safeDecl);
1638
+ if (found !== -1) return {
1639
+ start: found,
1640
+ end: found + docText.length
1641
+ };
1642
+ return {
1643
+ start: safeFallbackStart,
1644
+ end: safeFallbackEnd
1645
+ };
1646
+ }
1612
1647
  /**
1613
1648
  * Check if a tree-sitter grammar is configured for the given language.
1614
1649
  */
@@ -1657,15 +1692,17 @@ async function extractClassEndLines(source, language) {
1657
1692
  if (source[body ? body.endIndex - 1 : node.endIndex - 1] === "}") map.set(name, { bodyEndLine: endRow });
1658
1693
  else map.set(name, { bodyEndLine: endRow + 1 });
1659
1694
  }
1660
- for (const child of tree.rootNode.children) {
1661
- if (child.type === "class_definition" || child.type === "class_declaration") processClassNode(child);
1662
- if (child.type === "decorated_definition") {
1663
- for (const inner of child.namedChildren) if (inner.type === "class_definition") processClassNode(inner);
1695
+ function walk(node) {
1696
+ if (node.type === "class" || node.type === "class_definition" || node.type === "class_declaration") processClassNode(node);
1697
+ if (node.type === "decorated_definition") {
1698
+ for (const inner of node.namedChildren) if (inner.type === "class_definition") processClassNode(inner);
1664
1699
  }
1665
- if (child.type === "export_statement") {
1666
- for (const inner of child.namedChildren) if (inner.type === "class_declaration") processClassNode(inner);
1700
+ if (node.type === "export_statement") {
1701
+ for (const inner of node.namedChildren) if (inner.type === "class_declaration") processClassNode(inner);
1667
1702
  }
1703
+ for (const child of node.namedChildren) walk(child);
1668
1704
  }
1705
+ for (const child of tree.rootNode.children) walk(child);
1669
1706
  return map;
1670
1707
  }
1671
1708
  /**
@@ -1885,15 +1922,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
1885
1922
  if (genDoc) if (existInfo.docstring) {
1886
1923
  if (!existInfo.docstring.text.includes("@oagen-ignore") && existInfo.docstring.text !== genDoc.text) {
1887
1924
  const newText = preserveDeprecatedTags(existInfo.docstring.text, genDoc.text);
1925
+ const range = resolveDocRange(result, existInfo.docstring.text, existInfo.declStartIndex, existInfo.docstring.startIndex, existInfo.docstring.endIndex);
1888
1926
  edits.push({
1889
- start: existInfo.docstring.startIndex,
1890
- end: existInfo.docstring.endIndex,
1927
+ start: range.start,
1928
+ end: range.end,
1891
1929
  newText
1892
1930
  });
1893
1931
  docstringUpdates++;
1894
1932
  }
1895
1933
  } else {
1896
- const lineStart = existInfo.declStartIndex - existInfo.declColumn;
1934
+ const lineStart = declarationLineStart(result, existInfo.declStartIndex);
1897
1935
  const indent = " ".repeat(existInfo.declColumn);
1898
1936
  edits.push({
1899
1937
  start: lineStart,
@@ -1911,15 +1949,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
1911
1949
  if (existMember.docstring) {
1912
1950
  if (!existMember.docstring.text.includes("@oagen-ignore") && existMember.docstring.text !== genMember.docstring.text) {
1913
1951
  const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);
1952
+ const range = resolveDocRange(result, existMember.docstring.text, existMember.declStartIndex, existMember.docstring.startIndex, existMember.docstring.endIndex);
1914
1953
  edits.push({
1915
- start: existMember.docstring.startIndex,
1916
- end: existMember.docstring.endIndex,
1954
+ start: range.start,
1955
+ end: range.end,
1917
1956
  newText
1918
1957
  });
1919
1958
  docstringUpdates++;
1920
1959
  }
1921
1960
  } else {
1922
- const lineStart = existMember.declStartIndex - existMember.declColumn;
1961
+ const lineStart = declarationLineStart(result, existMember.declStartIndex);
1923
1962
  const indent = " ".repeat(existMember.declColumn);
1924
1963
  edits.push({
1925
1964
  start: lineStart,
@@ -1964,15 +2003,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
1964
2003
  if (existMember.docstring.text.includes("@oagen-ignore")) continue;
1965
2004
  if (existMember.docstring.text !== genMember.docstring.text) {
1966
2005
  const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);
2006
+ const range = resolveDocRange(result, existMember.docstring.text, existMember.declStartIndex, existMember.docstring.startIndex, existMember.docstring.endIndex);
1967
2007
  edits.push({
1968
- start: existMember.docstring.startIndex,
1969
- end: existMember.docstring.endIndex,
2008
+ start: range.start,
2009
+ end: range.end,
1970
2010
  newText
1971
2011
  });
1972
2012
  docstringUpdates++;
1973
2013
  }
1974
2014
  } else {
1975
- const lineStart = existMember.declStartIndex - existMember.declColumn;
2015
+ const lineStart = declarationLineStart(result, existMember.declStartIndex);
1976
2016
  const indent = " ".repeat(existMember.declColumn);
1977
2017
  edits.push({
1978
2018
  start: lineStart,
@@ -2145,7 +2185,7 @@ async function overwriteWithPreservedRegions(existingContent, generatedContent,
2145
2185
  });
2146
2186
  }
2147
2187
  if (blocks.length === 0) return generatedContent;
2148
- const result = [...generatedLines];
2188
+ const result = stripIgnoreRegions(generatedLines);
2149
2189
  spliceExtraImports(existingLines, result);
2150
2190
  const classEndLines = await extractClassEndLines(result.join("\n"), language);
2151
2191
  const blocksByClass = /* @__PURE__ */ new Map();
@@ -2212,10 +2252,33 @@ async function overwriteWithPreservedRegions(existingContent, generatedContent,
2212
2252
  for (const ins of insertions) result.splice(ins.line, 0, ...ins.content);
2213
2253
  return result.join("\n");
2214
2254
  }
2255
+ /**
2256
+ * Remove every `@oagen-ignore-start`..`@oagen-ignore-end` region from the
2257
+ * supplied lines, collapsing stretches of blank lines that get left behind.
2258
+ * Used to drop generator-emitted seed blocks before splicing the on-disk
2259
+ * versions back in — otherwise every regen doubles up.
2260
+ */
2261
+ function stripIgnoreRegions(lines) {
2262
+ const out = [];
2263
+ let skipping = false;
2264
+ for (const line of lines) {
2265
+ if (!skipping && line.includes("@oagen-ignore-start")) {
2266
+ skipping = true;
2267
+ while (out.length > 0 && out[out.length - 1].trim() === "") out.pop();
2268
+ continue;
2269
+ }
2270
+ if (skipping) {
2271
+ if (line.includes("@oagen-ignore-end")) skipping = false;
2272
+ continue;
2273
+ }
2274
+ out.push(line);
2275
+ }
2276
+ return out;
2277
+ }
2215
2278
  /** Scan backwards from `lineIdx` to find the nearest class declaration name. */
2216
2279
  function findContainingClass(lines, lineIdx) {
2217
2280
  for (let j = lineIdx - 1; j >= 0; j--) {
2218
- const m = lines[j].match(/^(?:export\s+)?class\s+(\w+)/);
2281
+ const m = lines[j].match(/^\s*(?:export\s+)?class\s+(\w+)/);
2219
2282
  if (m) return m[1];
2220
2283
  }
2221
2284
  return "";
@@ -2225,7 +2288,7 @@ function findContainingClass(lines, lineIdx) {
2225
2288
  * by scanning backwards from `beforeLine`.
2226
2289
  */
2227
2290
  function findClassDeclarationStart(lines, className, beforeLine) {
2228
- const classPattern = new RegExp(`^(?:export\\s+)?class\\s+${className}\\b`);
2291
+ const classPattern = new RegExp(`^\\s*(?:export\\s+)?class\\s+${className}\\b`);
2229
2292
  for (let i = beforeLine - 1; i >= 0; i--) {
2230
2293
  if (!classPattern.test(lines[i])) continue;
2231
2294
  let start = i;
@@ -2554,7 +2617,8 @@ async function resolveFileToDirectoryConflicts(files, targetDir) {
2554
2617
  };
2555
2618
  }
2556
2619
  async function integrateGeneratedFiles(opts) {
2557
- const { files: resolved, removals } = await resolveFileToDirectoryConflicts(await treeShakeFiles(mapFilesForTargetIntegration(opts.files, opts.language), opts.language), opts.targetDir);
2620
+ const mapped = mapFilesForTargetIntegration(opts.files, opts.language);
2621
+ const { files: resolved, removals } = await resolveFileToDirectoryConflicts(await treeShakeFiles(mapped, opts.language), opts.targetDir);
2558
2622
  const result = await writeFiles(resolved, opts.targetDir, {
2559
2623
  language: opts.language,
2560
2624
  header: opts.header
@@ -2564,7 +2628,7 @@ async function integrateGeneratedFiles(opts) {
2564
2628
  } catch {}
2565
2629
  return {
2566
2630
  ...result,
2567
- emittedPaths: resolved.map((f) => f.path)
2631
+ emittedPaths: mapped.map((f) => f.path)
2568
2632
  };
2569
2633
  }
2570
2634
  //#endregion
@@ -2588,6 +2652,7 @@ async function formatTargetFiles(emitter, targetDir, filePaths) {
2588
2652
  if (!formatCmd) return;
2589
2653
  const absolutePaths = filePaths.map((f) => path$1.resolve(targetDir, f));
2590
2654
  const batchSize = formatCmd.batchSize ?? 100;
2655
+ process.stderr.write(`[oagen] formatting ${absolutePaths.length} file(s) with ${formatCmd.cmd} (batch ${batchSize})\n`);
2591
2656
  for (let i = 0; i < absolutePaths.length; i += batchSize) {
2592
2657
  const batch = absolutePaths.slice(i, i + batchSize);
2593
2658
  try {
@@ -2596,7 +2661,10 @@ async function formatTargetFiles(emitter, targetDir, filePaths) {
2596
2661
  maxBuffer: 10 * 1024 * 1024,
2597
2662
  timeout: 12e4
2598
2663
  });
2599
- } catch {}
2664
+ } catch (err) {
2665
+ const msg = err instanceof Error ? err.message : String(err);
2666
+ process.stderr.write(`[oagen] formatter batch failed: ${msg}\n`);
2667
+ }
2600
2668
  }
2601
2669
  }
2602
2670
  //#endregion
@@ -2621,7 +2689,7 @@ async function formatTargetFiles(emitter, targetDir, filePaths) {
2621
2689
  * one-line notice is printed — no surprise deletions.
2622
2690
  */
2623
2691
  const MANIFEST_FILENAME = ".oagen-manifest.json";
2624
- const MANIFEST_VERSION = 1;
2692
+ const MANIFEST_VERSION = 2;
2625
2693
  /** Read `.oagen-manifest.json` from a directory. Returns null if absent or malformed. */
2626
2694
  async function readManifest(dir) {
2627
2695
  const manifestPath = path$1.join(dir, MANIFEST_FILENAME);
@@ -2648,7 +2716,14 @@ async function writeManifest(dir, opts) {
2648
2716
  const manifest = {
2649
2717
  version: MANIFEST_VERSION,
2650
2718
  language: opts.language,
2719
+ ...opts.sdkName !== void 0 ? { sdkName: opts.sdkName } : {},
2651
2720
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2721
+ ...opts.specSha !== void 0 ? { specSha: opts.specSha } : {},
2722
+ ...opts.specPath !== void 0 ? { specPath: opts.specPath } : {},
2723
+ ...opts.emitterSha !== void 0 ? { emitterSha: opts.emitterSha } : {},
2724
+ ...opts.emitterVersion !== void 0 ? { emitterVersion: opts.emitterVersion } : {},
2725
+ ...opts.configSha !== void 0 ? { configSha: opts.configSha } : {},
2726
+ ...opts.compatSchemaVersion !== void 0 ? { compatSchemaVersion: opts.compatSchemaVersion } : {},
2652
2727
  files: [...new Set(opts.files)].sort()
2653
2728
  };
2654
2729
  const manifestPath = path$1.join(dir, MANIFEST_FILENAME);
@@ -2759,6 +2834,8 @@ async function generate(spec, emitter, options) {
2759
2834
  header,
2760
2835
  noPrune: options.noPrune
2761
2836
  });
2837
+ const allOutputFiles = [...writeResult.written, ...writeResult.merged];
2838
+ if (allOutputFiles.length > 0) await formatTargetFiles(emitter, options.outputDir, allOutputFiles);
2762
2839
  if (options.target) {
2763
2840
  const targetPrevManifest = targetManifestForCtx;
2764
2841
  const targetResult = await integrateGeneratedFiles({
@@ -3182,4 +3259,4 @@ function summarize(changes) {
3182
3259
  //#endregion
3183
3260
  export { integrateGeneratedFiles as a, applyFileHeaders as c, generateAllFiles as d, generateFiles as f, generate as i, buildEmitterContext as l, resolveOperations as m, getEmitter as n, mapFilesForTargetIntegration as o, deriveMethodName as p, registerEmitter as r, treeShakeFiles as s, diffSpecs as t, collectReferencedNames as u };
3184
3261
 
3185
- //# sourceMappingURL=diff-CltJMcwG.mjs.map
3262
+ //# sourceMappingURL=diff-BaH9qa8k.mjs.map