@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.
- package/dist/cli/index.mjs +1339 -451
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +144 -57
- package/dist/compat/index.d.mts.map +1 -1
- package/dist/compat/index.mjs +365 -35
- package/dist/compat/index.mjs.map +1 -1
- package/dist/{diff-CltJMcwG.mjs → diff-BaH9qa8k.mjs} +100 -23
- package/dist/diff-BaH9qa8k.mjs.map +1 -0
- package/dist/differ-CTl98yoS.d.mts +116 -0
- package/dist/differ-CTl98yoS.d.mts.map +1 -0
- package/dist/index.d.mts +4 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +177 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{differ-CG5ZErKl.mjs → overlay-TYxHOCow.mjs} +1112 -553
- package/dist/overlay-TYxHOCow.mjs.map +1 -0
- package/dist/scripts/smoke/baseline.mjs +176 -3
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +43 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +176 -3
- package/dist/smoke.mjs.map +1 -1
- package/dist/tree-sitter-C53w_0WE.mjs.map +1 -1
- package/dist/{types-C7g5sLuX.d.mts → types-mTtkgy_h.d.mts} +213 -2
- package/dist/types-mTtkgy_h.d.mts.map +1 -0
- package/dist/verify/index.d.mts +4 -3
- package/dist/verify/index.d.mts.map +1 -1
- package/dist/verify/index.mjs +12 -10
- package/dist/verify/index.mjs.map +1 -1
- package/docs/architecture/emitter-contract.md +2 -2
- package/docs/architecture/extractor-contract.md +6 -5
- package/docs/architecture/pipeline.md +4 -3
- package/docs/architecture/workflows.md +5 -3
- package/docs/cli.md +148 -6
- package/docs/contributor/public-api.md +1 -1
- package/docs/core/compatibility-ir.md +200 -0
- package/docs/core/compatibility-policy.md +170 -0
- package/docs/core/compatibility.md +83 -0
- package/docs/core/index.md +5 -0
- package/docs/core/manifest-schema.md +76 -0
- package/docs/core/quickstart.md +9 -2
- package/docs/core/verify-compat.md +235 -0
- package/package.json +1 -1
- package/skills/generate-emitter/SKILL.md +12 -7
- package/skills/generate-emitter/references/project-scaffold.md +27 -6
- package/skills/generate-extractor/SKILL.md +14 -8
- package/skills/generate-sdk/SKILL.md +2 -2
- package/skills/generate-smoke-test/SKILL.md +9 -5
- package/skills/review-operations/SKILL.md +2 -2
- package/skills/verify-compat/SKILL.md +1 -1
- package/dist/diff-CltJMcwG.mjs.map +0 -1
- package/dist/differ-CG5ZErKl.mjs.map +0 -1
- 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
|
-
|
|
1661
|
-
if (
|
|
1662
|
-
if (
|
|
1663
|
-
for (const inner of
|
|
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 (
|
|
1666
|
-
for (const inner of
|
|
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:
|
|
1890
|
-
end:
|
|
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
|
|
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:
|
|
1916
|
-
end:
|
|
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
|
|
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:
|
|
1969
|
-
end:
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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:
|
|
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 =
|
|
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-
|
|
3262
|
+
//# sourceMappingURL=diff-BaH9qa8k.mjs.map
|