@workos/oagen 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,9 +72,7 @@ import {
72
72
  diffSpecs,
73
73
  generate,
74
74
  generateFiles,
75
- generateIncremental,
76
75
  getEmitter,
77
- mapChangesToFiles,
78
76
  parseSpec,
79
77
  planOperation,
80
78
  registerEmitter,
@@ -147,7 +145,7 @@ Start with:
147
145
  | `oagen parse` | Parse a spec and print IR JSON |
148
146
  | `oagen init` | Scaffold an emitter project |
149
147
  | `oagen generate` | Run a registered emitter |
150
- | `oagen diff` | Review spec changes or incrementally regenerate |
148
+ | `oagen diff` | Compare two specs and output a diff report |
151
149
  | `oagen extract` | Advanced: extract an SDK API surface for compat use |
152
150
  | `oagen verify` | Advanced: smoke-test output and run compat checks |
153
151
 
@@ -44,10 +44,6 @@ function generateFiles(spec, emitter, options) {
44
44
  return { files: applyFileHeaders(files, header), ctx, header };
45
45
  }
46
46
 
47
- // src/engine/integrate.ts
48
- import * as fs2 from "fs";
49
- import * as path2 from "path";
50
-
51
47
  // src/engine/writer.ts
52
48
  import * as fs from "fs/promises";
53
49
  import * as path from "path";
@@ -95,11 +91,11 @@ function declarationKey(node) {
95
91
  function importEntries(node, source) {
96
92
  const entries = [];
97
93
  const collect = (spec) => {
98
- const path3 = spec.childForFieldName("path")?.text ?? spec.text;
94
+ const path2 = spec.childForFieldName("path")?.text ?? spec.text;
99
95
  const name = spec.childForFieldName("name")?.text ?? "";
100
96
  const text = source.slice(spec.startIndex, spec.endIndex);
101
97
  entries.push({
102
- key: `${name}:${path3.replace(/^"|"$/g, "")}`,
98
+ key: `${name}:${path2.replace(/^"|"$/g, "")}`,
103
99
  text
104
100
  });
105
101
  };
@@ -896,75 +892,11 @@ async function extractStatements(source, language) {
896
892
  const tree = safeParse(parser, source);
897
893
  return adapter.parseStatements(tree, source);
898
894
  }
899
- async function mergeIntoExisting(existingContent, generatedContent, language, header, options) {
895
+ async function mergeIntoExisting(existingContent, generatedContent, language, header) {
900
896
  const adapter = getMergeAdapter(language);
901
897
  if (!adapter) {
902
898
  throw new Error(`No merge adapter configured for language "${language}"`);
903
899
  }
904
- if (options?.docstringOnly) {
905
- let result2 = existingContent;
906
- let docstringUpdates2 = 0;
907
- const parser = await getParser(language);
908
- const resultTree = safeParse(parser, result2);
909
- const generatedTree = safeParse(parser, generatedContent);
910
- const resultDocs = adapter.extractDocstrings(resultTree, result2);
911
- const generatedDocs = adapter.extractDocstrings(generatedTree, generatedContent);
912
- const ignoredRegions = findIgnoredRegions(result2);
913
- const ignoredSymbols = buildIgnoredSymbolNames(resultDocs, ignoredRegions);
914
- const headerLine2 = header.trim();
915
- const edits = [];
916
- for (const [symbolName, genInfo] of generatedDocs) {
917
- const existInfo = resultDocs.get(symbolName);
918
- if (!existInfo) continue;
919
- if (ignoredSymbols.has(symbolName)) continue;
920
- const genDoc = genInfo.docstring && genInfo.docstring.text.trim() !== headerLine2 ? genInfo.docstring : null;
921
- if (genDoc) {
922
- if (existInfo.docstring) {
923
- const isPreserved = existInfo.docstring.text.includes("@oagen-ignore");
924
- if (!isPreserved && existInfo.docstring.text !== genDoc.text) {
925
- edits.push({
926
- start: existInfo.docstring.startIndex,
927
- end: existInfo.docstring.endIndex,
928
- newText: genDoc.text
929
- });
930
- docstringUpdates2++;
931
- }
932
- } else {
933
- const lineStart = existInfo.declStartIndex - existInfo.declColumn;
934
- const indent = " ".repeat(existInfo.declColumn);
935
- edits.push({ start: lineStart, end: lineStart, newText: indent + genDoc.text + "\n" });
936
- docstringUpdates2++;
937
- }
938
- }
939
- for (const [memberName, genMember] of genInfo.members) {
940
- const existMember = existInfo.members.get(memberName);
941
- if (!existMember || !genMember.docstring) continue;
942
- if (existMember.docstring) {
943
- const isPreserved = existMember.docstring.text.includes("@oagen-ignore");
944
- if (!isPreserved && existMember.docstring.text !== genMember.docstring.text) {
945
- edits.push({
946
- start: existMember.docstring.startIndex,
947
- end: existMember.docstring.endIndex,
948
- newText: genMember.docstring.text
949
- });
950
- docstringUpdates2++;
951
- }
952
- } else {
953
- const lineStart = existMember.declStartIndex - existMember.declColumn;
954
- const indent = " ".repeat(existMember.declColumn);
955
- edits.push({ start: lineStart, end: lineStart, newText: indent + genMember.docstring.text + "\n" });
956
- docstringUpdates2++;
957
- }
958
- }
959
- }
960
- if (edits.length > 0) {
961
- edits.sort((a, b) => b.start - a.start);
962
- for (const edit of edits) {
963
- result2 = result2.slice(0, edit.start) + edit.newText + result2.slice(edit.end);
964
- }
965
- }
966
- return { content: result2, added: 0, preserved: 0, changed: docstringUpdates2 > 0 };
967
- }
968
900
  const existingStatements = await extractStatements(existingContent, language);
969
901
  const generatedStatements = await extractStatements(generatedContent, language);
970
902
  const existingKeys = /* @__PURE__ */ new Set();
@@ -1237,22 +1169,6 @@ async function writeFiles(files, outputDir, options) {
1237
1169
  }
1238
1170
  if (language && hasGrammar(language)) {
1239
1171
  try {
1240
- if (file.mergeMode === "docstring-only") {
1241
- const mergeResult2 = await mergeIntoExisting(existingContent, file.content, language, header, {
1242
- docstringOnly: true
1243
- });
1244
- let finalContent2 = mergeResult2.content;
1245
- if (header && !finalContent2.startsWith(header)) {
1246
- finalContent2 = header + "\n\n" + finalContent2;
1247
- }
1248
- if (finalContent2 === existingContent) {
1249
- result.identical.push(file.path);
1250
- } else {
1251
- await fs.writeFile(fullPath, finalContent2, "utf-8");
1252
- result.merged.push(file.path);
1253
- }
1254
- continue;
1255
- }
1256
1172
  const mergeResult = await mergeIntoExisting(existingContent, file.content, language, header);
1257
1173
  let finalContent = mergeResult.content;
1258
1174
  if (header && !finalContent.startsWith(header)) {
@@ -1280,22 +1196,20 @@ async function writeFiles(files, outputDir, options) {
1280
1196
  }
1281
1197
 
1282
1198
  // src/engine/integrate.ts
1283
- function mapFilesForTargetIntegration(files, language, targetDir) {
1199
+ function mapFilesForTargetIntegration(files, language) {
1284
1200
  const langPrefix = `${language}/`;
1285
1201
  return files.filter((f) => f.integrateTarget !== false).map((f) => {
1286
1202
  const stripped = f.path.startsWith(langPrefix) ? f.path.replace(langPrefix, "") : f.path;
1287
- const existsInTarget = targetDir ? fs2.existsSync(path2.join(targetDir, stripped)) : false;
1288
1203
  return {
1289
1204
  ...f,
1290
1205
  skipIfExists: false,
1291
1206
  // Always merge in target — never hard-skip
1292
- mergeMode: existsInTarget ? "docstring-only" : "full",
1293
1207
  path: stripped
1294
1208
  };
1295
1209
  });
1296
1210
  }
1297
1211
  async function integrateGeneratedFiles(opts) {
1298
- return writeFiles(mapFilesForTargetIntegration(opts.files, opts.language, opts.targetDir), opts.targetDir, {
1212
+ return writeFiles(mapFilesForTargetIntegration(opts.files, opts.language), opts.targetDir, {
1299
1213
  language: opts.language,
1300
1214
  header: opts.header
1301
1215
  });
@@ -1734,7 +1648,6 @@ function summarize(changes) {
1734
1648
  }
1735
1649
 
1736
1650
  export {
1737
- writeFiles,
1738
1651
  buildEmitterContext,
1739
1652
  generateAllFiles,
1740
1653
  applyFileHeaders,