@workos/oagen 0.6.0 → 0.7.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 +224 -23
- package/dist/cli/index.mjs.map +1 -1
- package/dist/compat/index.d.mts +1 -1
- package/dist/compat/index.mjs +11 -2
- package/dist/compat/index.mjs.map +1 -1
- package/dist/{diff-CltJMcwG.mjs → diff-BYadQQV7.mjs} +90 -22
- package/dist/diff-BYadQQV7.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +136 -3
- package/dist/index.mjs.map +1 -1
- package/dist/scripts/smoke/baseline.mjs +135 -2
- package/dist/scripts/smoke/baseline.mjs.map +1 -1
- package/dist/smoke.d.mts +33 -0
- package/dist/smoke.d.mts.map +1 -1
- package/dist/smoke.mjs +135 -2
- package/dist/smoke.mjs.map +1 -1
- package/dist/tree-sitter-C53w_0WE.mjs.map +1 -1
- package/dist/{types-C7g5sLuX.d.mts → types-DJMbCtIO.d.mts} +35 -2
- package/dist/{types-C7g5sLuX.d.mts.map → types-DJMbCtIO.d.mts.map} +1 -1
- package/dist/verify/index.d.mts +1 -1
- package/dist/verify/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/diff-CltJMcwG.mjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -600,7 +600,7 @@ function findSchemaByName(pascalName, schemas) {
|
|
|
600
600
|
for (const [k, v] of Object.entries(schemas)) if (resolveSchemaName(k) === pascalName) return v;
|
|
601
601
|
return null;
|
|
602
602
|
}
|
|
603
|
-
/** Walk into a schema to find a field's sub-schema, resolving allOf. */
|
|
603
|
+
/** Walk into a schema to find a field's sub-schema, resolving allOf and oneOf/anyOf. */
|
|
604
604
|
function findNestedFieldSchema(fieldName, parentSchema, schemas) {
|
|
605
605
|
if (parentSchema.properties?.[fieldName]) return parentSchema.properties[fieldName];
|
|
606
606
|
if (parentSchema.allOf) for (const sub of parentSchema.allOf) {
|
|
@@ -612,6 +612,15 @@ function findNestedFieldSchema(fieldName, parentSchema, schemas) {
|
|
|
612
612
|
}
|
|
613
613
|
if (resolved.properties?.[fieldName]) return resolved.properties[fieldName];
|
|
614
614
|
}
|
|
615
|
+
for (const variant of [...parentSchema.oneOf ?? [], ...parentSchema.anyOf ?? []]) {
|
|
616
|
+
let resolved = variant;
|
|
617
|
+
if (variant.$ref) {
|
|
618
|
+
const segments = variant.$ref.split("/");
|
|
619
|
+
const refName = segments[segments.length - 1];
|
|
620
|
+
if (refName && schemas[refName]) resolved = schemas[refName];
|
|
621
|
+
}
|
|
622
|
+
if (resolved.properties?.[fieldName]) return resolved.properties[fieldName];
|
|
623
|
+
}
|
|
615
624
|
return null;
|
|
616
625
|
}
|
|
617
626
|
/** Extract a model (and nested models) from an inline field schema. */
|
|
@@ -777,6 +786,19 @@ function extractModel(name, schema, schemas) {
|
|
|
777
786
|
if (!fieldSchema) continue;
|
|
778
787
|
fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, requiredSet));
|
|
779
788
|
}
|
|
789
|
+
if (fields.length === 0 && (schema.oneOf || schema.anyOf)) {
|
|
790
|
+
const variants = schema.oneOf ?? schema.anyOf ?? [];
|
|
791
|
+
const emptyRequired = /* @__PURE__ */ new Set();
|
|
792
|
+
const seenFieldNames = /* @__PURE__ */ new Set();
|
|
793
|
+
for (const variant of variants) {
|
|
794
|
+
if (!variant.properties) continue;
|
|
795
|
+
for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {
|
|
796
|
+
if (!fieldSchema || seenFieldNames.has(fieldName)) continue;
|
|
797
|
+
seenFieldNames.add(fieldName);
|
|
798
|
+
fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, emptyRequired));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
780
802
|
if (schema.additionalProperties && typeof schema.additionalProperties === "object" && schema.properties) {
|
|
781
803
|
if (Object.keys(schema.additionalProperties).length > 0) {
|
|
782
804
|
const valueType = schemaToTypeRef(schema.additionalProperties, "additionalProperties", name);
|
|
@@ -816,6 +838,18 @@ function extractAllOfModel(name, schema, schemas) {
|
|
|
816
838
|
});
|
|
817
839
|
if (f.required) requiredSet.add(f.name);
|
|
818
840
|
}
|
|
841
|
+
} else if (resolved.oneOf || resolved.anyOf) {
|
|
842
|
+
const variants = resolved.oneOf ?? resolved.anyOf ?? [];
|
|
843
|
+
const emptyRequired = /* @__PURE__ */ new Set();
|
|
844
|
+
const seenFieldNames = new Set(fields.map((f) => f.name));
|
|
845
|
+
for (const variant of variants) {
|
|
846
|
+
if (!variant.properties) continue;
|
|
847
|
+
for (const [fieldName, fieldSchema] of Object.entries(variant.properties)) {
|
|
848
|
+
if (!fieldSchema || seenFieldNames.has(fieldName)) continue;
|
|
849
|
+
seenFieldNames.add(fieldName);
|
|
850
|
+
fields.push(buildFieldFromSchema(fieldName, fieldSchema, name, emptyRequired));
|
|
851
|
+
}
|
|
852
|
+
}
|
|
819
853
|
} else {
|
|
820
854
|
if (resolved.required) for (const r of resolved.required) requiredSet.add(r);
|
|
821
855
|
if (resolved.properties) {
|
|
@@ -1672,6 +1706,94 @@ function inferDeeperContext(path) {
|
|
|
1672
1706
|
if (nonParams.length >= 3) return toPascalCase(nonParams.slice(1, -1).join("_"));
|
|
1673
1707
|
return null;
|
|
1674
1708
|
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Extract mutually-exclusive parameter groups from the `x-mutually-exclusive-parameter-groups`
|
|
1711
|
+
* operation extension. Cross-references grouped parameter names against the already-extracted
|
|
1712
|
+
* IR parameter arrays so emitters get object-identity references.
|
|
1713
|
+
*/
|
|
1714
|
+
function extractParameterGroups(op, allIRParams, operationContext) {
|
|
1715
|
+
const raw = op["x-mutually-exclusive-parameter-groups"];
|
|
1716
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
1717
|
+
const paramByName = /* @__PURE__ */ new Map();
|
|
1718
|
+
for (const p of allIRParams) paramByName.set(p.name, p);
|
|
1719
|
+
const groups = [];
|
|
1720
|
+
for (const [groupName, groupDef] of Object.entries(raw)) {
|
|
1721
|
+
if (!groupDef || typeof groupDef !== "object") throw new Error(`Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: expected an object with "optional" and "variants".`);
|
|
1722
|
+
if (typeof groupDef.optional !== "boolean") throw new Error(`Malformed x-mutually-exclusive-parameter-groups.${groupName}.optional in ${operationContext}: expected a boolean.`);
|
|
1723
|
+
if (!groupDef.variants || typeof groupDef.variants !== "object") throw new Error(`Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants in ${operationContext}: expected an object mapping variant names to parameter name arrays.`);
|
|
1724
|
+
if (Object.keys(groupDef.variants).length === 0) throw new Error(`Malformed x-mutually-exclusive-parameter-groups.${groupName} in ${operationContext}: group has zero variants.`);
|
|
1725
|
+
const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {
|
|
1726
|
+
if (!Array.isArray(paramNames) || paramNames.length === 0) throw new Error(`Malformed x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`);
|
|
1727
|
+
return {
|
|
1728
|
+
name: variantName,
|
|
1729
|
+
parameters: paramNames.map((pName) => {
|
|
1730
|
+
const irParam = paramByName.get(pName);
|
|
1731
|
+
if (!irParam) throw new Error(`x-mutually-exclusive-parameter-groups.${groupName}.variants.${variantName} references parameter "${pName}" which does not exist in the operation's parameters[] (${operationContext}).`);
|
|
1732
|
+
return irParam;
|
|
1733
|
+
})
|
|
1734
|
+
};
|
|
1735
|
+
});
|
|
1736
|
+
groups.push({
|
|
1737
|
+
name: groupName,
|
|
1738
|
+
optional: groupDef.optional,
|
|
1739
|
+
variants
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
return groups.length > 0 ? groups : void 0;
|
|
1743
|
+
}
|
|
1744
|
+
/**
|
|
1745
|
+
* Extract mutually-exclusive body parameter groups from the
|
|
1746
|
+
* `x-mutually-exclusive-body-groups` operation extension. Unlike query
|
|
1747
|
+
* parameter groups (whose parameters live in operation.queryParams), body
|
|
1748
|
+
* group parameters are synthetic — built from the oneOf variant schemas in
|
|
1749
|
+
* the request body. Emitters use the group's presence to generate sum-type
|
|
1750
|
+
* interfaces and custom JSON marshalling instead of flat optional fields.
|
|
1751
|
+
*/
|
|
1752
|
+
function extractBodyParameterGroups(op, operationContext) {
|
|
1753
|
+
const raw = op["x-mutually-exclusive-body-groups"];
|
|
1754
|
+
if (!raw || typeof raw !== "object") return void 0;
|
|
1755
|
+
const bodySchema = op.requestBody?.content?.["application/json"]?.schema;
|
|
1756
|
+
const variantFieldSchemas = /* @__PURE__ */ new Map();
|
|
1757
|
+
if (bodySchema) {
|
|
1758
|
+
for (const sub of bodySchema.allOf ?? []) for (const variant of sub.oneOf ?? []) if (variant.properties) {
|
|
1759
|
+
for (const [name, fieldSchema] of Object.entries(variant.properties)) if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);
|
|
1760
|
+
}
|
|
1761
|
+
for (const variant of bodySchema.oneOf ?? []) if (variant.properties) {
|
|
1762
|
+
for (const [name, fieldSchema] of Object.entries(variant.properties)) if (fieldSchema) variantFieldSchemas.set(name, fieldSchema);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
const groups = [];
|
|
1766
|
+
for (const [groupName, groupDef] of Object.entries(raw)) {
|
|
1767
|
+
if (!groupDef || typeof groupDef !== "object") continue;
|
|
1768
|
+
if (typeof groupDef.optional !== "boolean") continue;
|
|
1769
|
+
if (!groupDef.variants || typeof groupDef.variants !== "object") continue;
|
|
1770
|
+
if (Object.keys(groupDef.variants).length === 0) continue;
|
|
1771
|
+
const variants = Object.entries(groupDef.variants).map(([variantName, paramNames]) => {
|
|
1772
|
+
if (!Array.isArray(paramNames) || paramNames.length === 0) throw new Error(`Malformed x-mutually-exclusive-body-groups.${groupName}.variants.${variantName} in ${operationContext}: expected a non-empty array of parameter names.`);
|
|
1773
|
+
return {
|
|
1774
|
+
name: variantName,
|
|
1775
|
+
parameters: paramNames.map((pName) => {
|
|
1776
|
+
const fieldSchema = variantFieldSchemas.get(pName);
|
|
1777
|
+
return {
|
|
1778
|
+
name: pName,
|
|
1779
|
+
type: fieldSchema ? schemaToTypeRef(fieldSchema, toPascalCase(pName)) : {
|
|
1780
|
+
kind: "primitive",
|
|
1781
|
+
type: "string"
|
|
1782
|
+
},
|
|
1783
|
+
required: false,
|
|
1784
|
+
description: fieldSchema?.description
|
|
1785
|
+
};
|
|
1786
|
+
})
|
|
1787
|
+
};
|
|
1788
|
+
});
|
|
1789
|
+
groups.push({
|
|
1790
|
+
name: groupName,
|
|
1791
|
+
optional: groupDef.optional,
|
|
1792
|
+
variants
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
return groups.length > 0 ? groups : void 0;
|
|
1796
|
+
}
|
|
1675
1797
|
function buildOperation(method, path, op, pathLevelParams, operationIdTransform, serviceName) {
|
|
1676
1798
|
const allParams = [...pathLevelParams, ...op.parameters ?? []];
|
|
1677
1799
|
const hasIdempotencyHeader = allParams.some((p) => p.in === "header" && p.name.toLowerCase() === "idempotency-key");
|
|
@@ -1697,6 +1819,16 @@ function buildOperation(method, path, op, pathLevelParams, operationIdTransform,
|
|
|
1697
1819
|
};
|
|
1698
1820
|
} else if (paginationFromParams) pagination = paginationFromParams;
|
|
1699
1821
|
const security = extractOperationSecurity(op.security);
|
|
1822
|
+
const allIRParams = [
|
|
1823
|
+
...pathParams,
|
|
1824
|
+
...queryParams,
|
|
1825
|
+
...headerParams,
|
|
1826
|
+
...cookieParams
|
|
1827
|
+
];
|
|
1828
|
+
const opLabel = op.operationId ?? `${method.toUpperCase()} ${path}`;
|
|
1829
|
+
const queryParamGroups = extractParameterGroups(op, allIRParams, opLabel);
|
|
1830
|
+
const bodyParamGroups = extractBodyParameterGroups(op, opLabel);
|
|
1831
|
+
const parameterGroups = queryParamGroups || bodyParamGroups ? [...queryParamGroups ?? [], ...bodyParamGroups ?? []] : void 0;
|
|
1700
1832
|
return {
|
|
1701
1833
|
operation: {
|
|
1702
1834
|
name: inferOperationName(method, path, op.operationId, operationIdTransform),
|
|
@@ -1716,7 +1848,8 @@ function buildOperation(method, path, op, pathLevelParams, operationIdTransform,
|
|
|
1716
1848
|
injectIdempotencyKey: hasIdempotencyHeader,
|
|
1717
1849
|
deprecated: op.deprecated || void 0,
|
|
1718
1850
|
async: op["x-oagen-async"],
|
|
1719
|
-
security
|
|
1851
|
+
security,
|
|
1852
|
+
parameterGroups
|
|
1720
1853
|
},
|
|
1721
1854
|
inlineModels
|
|
1722
1855
|
};
|
|
@@ -2971,6 +3104,7 @@ const nodeMergeAdapter = {
|
|
|
2971
3104
|
const newText = newMembers.map((m) => m.text).join("\n");
|
|
2972
3105
|
for (const match of newText.matchAll(/this\.(\w+)/g)) {
|
|
2973
3106
|
const propName = match[1];
|
|
3107
|
+
if (propName === "workos") continue;
|
|
2974
3108
|
if (propName && !existingMemberKeys.has(propName)) return true;
|
|
2975
3109
|
}
|
|
2976
3110
|
return false;
|
|
@@ -3627,6 +3761,40 @@ function buildIgnoredSymbolNames(docstrings, regions) {
|
|
|
3627
3761
|
for (const [name, info] of docstrings) if (regions.some((r) => info.declStartIndex >= r.startIndex && info.declStartIndex <= r.endIndex)) ignored.add(name);
|
|
3628
3762
|
return ignored;
|
|
3629
3763
|
}
|
|
3764
|
+
function clampIndex(value, contentLength) {
|
|
3765
|
+
if (!Number.isFinite(value)) return 0;
|
|
3766
|
+
if (value < 0) return 0;
|
|
3767
|
+
if (value > contentLength) return contentLength;
|
|
3768
|
+
return value;
|
|
3769
|
+
}
|
|
3770
|
+
/**
|
|
3771
|
+
* Resolve the declaration line start for insertion using the current content,
|
|
3772
|
+
* instead of relying on parser column arithmetic. This avoids misplaced inserts
|
|
3773
|
+
* when parser columns/offsets drift.
|
|
3774
|
+
*/
|
|
3775
|
+
function declarationLineStart(content, declStartIndex) {
|
|
3776
|
+
const idx = clampIndex(declStartIndex, content.length);
|
|
3777
|
+
const prevNewline = content.lastIndexOf("\n", Math.max(0, idx - 1));
|
|
3778
|
+
return prevNewline === -1 ? 0 : prevNewline + 1;
|
|
3779
|
+
}
|
|
3780
|
+
/**
|
|
3781
|
+
* Resolve a docstring range by searching for the nearest matching text before
|
|
3782
|
+
* the declaration start. Falls back to parser-provided offsets when search fails.
|
|
3783
|
+
*/
|
|
3784
|
+
function resolveDocRange(content, docText, declStartIndex, fallbackStart, fallbackEnd) {
|
|
3785
|
+
const safeDecl = clampIndex(declStartIndex, content.length);
|
|
3786
|
+
const safeFallbackStart = clampIndex(fallbackStart, content.length);
|
|
3787
|
+
const safeFallbackEnd = clampIndex(fallbackEnd, content.length);
|
|
3788
|
+
const found = content.lastIndexOf(docText, safeDecl);
|
|
3789
|
+
if (found !== -1) return {
|
|
3790
|
+
start: found,
|
|
3791
|
+
end: found + docText.length
|
|
3792
|
+
};
|
|
3793
|
+
return {
|
|
3794
|
+
start: safeFallbackStart,
|
|
3795
|
+
end: safeFallbackEnd
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3630
3798
|
/**
|
|
3631
3799
|
* Check if a tree-sitter grammar is configured for the given language.
|
|
3632
3800
|
*/
|
|
@@ -3675,15 +3843,17 @@ async function extractClassEndLines(source, language) {
|
|
|
3675
3843
|
if (source[body ? body.endIndex - 1 : node.endIndex - 1] === "}") map.set(name, { bodyEndLine: endRow });
|
|
3676
3844
|
else map.set(name, { bodyEndLine: endRow + 1 });
|
|
3677
3845
|
}
|
|
3678
|
-
|
|
3679
|
-
if (
|
|
3680
|
-
if (
|
|
3681
|
-
for (const inner of
|
|
3846
|
+
function walk(node) {
|
|
3847
|
+
if (node.type === "class" || node.type === "class_definition" || node.type === "class_declaration") processClassNode(node);
|
|
3848
|
+
if (node.type === "decorated_definition") {
|
|
3849
|
+
for (const inner of node.namedChildren) if (inner.type === "class_definition") processClassNode(inner);
|
|
3682
3850
|
}
|
|
3683
|
-
if (
|
|
3684
|
-
for (const inner of
|
|
3851
|
+
if (node.type === "export_statement") {
|
|
3852
|
+
for (const inner of node.namedChildren) if (inner.type === "class_declaration") processClassNode(inner);
|
|
3685
3853
|
}
|
|
3854
|
+
for (const child of node.namedChildren) walk(child);
|
|
3686
3855
|
}
|
|
3856
|
+
for (const child of tree.rootNode.children) walk(child);
|
|
3687
3857
|
return map;
|
|
3688
3858
|
}
|
|
3689
3859
|
/**
|
|
@@ -3903,15 +4073,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
|
|
|
3903
4073
|
if (genDoc) if (existInfo.docstring) {
|
|
3904
4074
|
if (!existInfo.docstring.text.includes("@oagen-ignore") && existInfo.docstring.text !== genDoc.text) {
|
|
3905
4075
|
const newText = preserveDeprecatedTags(existInfo.docstring.text, genDoc.text);
|
|
4076
|
+
const range = resolveDocRange(result, existInfo.docstring.text, existInfo.declStartIndex, existInfo.docstring.startIndex, existInfo.docstring.endIndex);
|
|
3906
4077
|
edits.push({
|
|
3907
|
-
start:
|
|
3908
|
-
end:
|
|
4078
|
+
start: range.start,
|
|
4079
|
+
end: range.end,
|
|
3909
4080
|
newText
|
|
3910
4081
|
});
|
|
3911
4082
|
docstringUpdates++;
|
|
3912
4083
|
}
|
|
3913
4084
|
} else {
|
|
3914
|
-
const lineStart = existInfo.declStartIndex
|
|
4085
|
+
const lineStart = declarationLineStart(result, existInfo.declStartIndex);
|
|
3915
4086
|
const indent = " ".repeat(existInfo.declColumn);
|
|
3916
4087
|
edits.push({
|
|
3917
4088
|
start: lineStart,
|
|
@@ -3929,15 +4100,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
|
|
|
3929
4100
|
if (existMember.docstring) {
|
|
3930
4101
|
if (!existMember.docstring.text.includes("@oagen-ignore") && existMember.docstring.text !== genMember.docstring.text) {
|
|
3931
4102
|
const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);
|
|
4103
|
+
const range = resolveDocRange(result, existMember.docstring.text, existMember.declStartIndex, existMember.docstring.startIndex, existMember.docstring.endIndex);
|
|
3932
4104
|
edits.push({
|
|
3933
|
-
start:
|
|
3934
|
-
end:
|
|
4105
|
+
start: range.start,
|
|
4106
|
+
end: range.end,
|
|
3935
4107
|
newText
|
|
3936
4108
|
});
|
|
3937
4109
|
docstringUpdates++;
|
|
3938
4110
|
}
|
|
3939
4111
|
} else {
|
|
3940
|
-
const lineStart = existMember.declStartIndex
|
|
4112
|
+
const lineStart = declarationLineStart(result, existMember.declStartIndex);
|
|
3941
4113
|
const indent = " ".repeat(existMember.declColumn);
|
|
3942
4114
|
edits.push({
|
|
3943
4115
|
start: lineStart,
|
|
@@ -3982,15 +4154,16 @@ async function mergeIntoExisting(existingContent, generatedContent, language, he
|
|
|
3982
4154
|
if (existMember.docstring.text.includes("@oagen-ignore")) continue;
|
|
3983
4155
|
if (existMember.docstring.text !== genMember.docstring.text) {
|
|
3984
4156
|
const newText = preserveDeprecatedTags(existMember.docstring.text, genMember.docstring.text);
|
|
4157
|
+
const range = resolveDocRange(result, existMember.docstring.text, existMember.declStartIndex, existMember.docstring.startIndex, existMember.docstring.endIndex);
|
|
3985
4158
|
edits.push({
|
|
3986
|
-
start:
|
|
3987
|
-
end:
|
|
4159
|
+
start: range.start,
|
|
4160
|
+
end: range.end,
|
|
3988
4161
|
newText
|
|
3989
4162
|
});
|
|
3990
4163
|
docstringUpdates++;
|
|
3991
4164
|
}
|
|
3992
4165
|
} else {
|
|
3993
|
-
const lineStart = existMember.declStartIndex
|
|
4166
|
+
const lineStart = declarationLineStart(result, existMember.declStartIndex);
|
|
3994
4167
|
const indent = " ".repeat(existMember.declColumn);
|
|
3995
4168
|
edits.push({
|
|
3996
4169
|
start: lineStart,
|
|
@@ -4163,7 +4336,7 @@ async function overwriteWithPreservedRegions(existingContent, generatedContent,
|
|
|
4163
4336
|
});
|
|
4164
4337
|
}
|
|
4165
4338
|
if (blocks.length === 0) return generatedContent;
|
|
4166
|
-
const result =
|
|
4339
|
+
const result = stripIgnoreRegions(generatedLines);
|
|
4167
4340
|
spliceExtraImports(existingLines, result);
|
|
4168
4341
|
const classEndLines = await extractClassEndLines(result.join("\n"), language);
|
|
4169
4342
|
const blocksByClass = /* @__PURE__ */ new Map();
|
|
@@ -4230,10 +4403,33 @@ async function overwriteWithPreservedRegions(existingContent, generatedContent,
|
|
|
4230
4403
|
for (const ins of insertions) result.splice(ins.line, 0, ...ins.content);
|
|
4231
4404
|
return result.join("\n");
|
|
4232
4405
|
}
|
|
4406
|
+
/**
|
|
4407
|
+
* Remove every `@oagen-ignore-start`..`@oagen-ignore-end` region from the
|
|
4408
|
+
* supplied lines, collapsing stretches of blank lines that get left behind.
|
|
4409
|
+
* Used to drop generator-emitted seed blocks before splicing the on-disk
|
|
4410
|
+
* versions back in — otherwise every regen doubles up.
|
|
4411
|
+
*/
|
|
4412
|
+
function stripIgnoreRegions(lines) {
|
|
4413
|
+
const out = [];
|
|
4414
|
+
let skipping = false;
|
|
4415
|
+
for (const line of lines) {
|
|
4416
|
+
if (!skipping && line.includes("@oagen-ignore-start")) {
|
|
4417
|
+
skipping = true;
|
|
4418
|
+
while (out.length > 0 && out[out.length - 1].trim() === "") out.pop();
|
|
4419
|
+
continue;
|
|
4420
|
+
}
|
|
4421
|
+
if (skipping) {
|
|
4422
|
+
if (line.includes("@oagen-ignore-end")) skipping = false;
|
|
4423
|
+
continue;
|
|
4424
|
+
}
|
|
4425
|
+
out.push(line);
|
|
4426
|
+
}
|
|
4427
|
+
return out;
|
|
4428
|
+
}
|
|
4233
4429
|
/** Scan backwards from `lineIdx` to find the nearest class declaration name. */
|
|
4234
4430
|
function findContainingClass(lines, lineIdx) {
|
|
4235
4431
|
for (let j = lineIdx - 1; j >= 0; j--) {
|
|
4236
|
-
const m = lines[j].match(
|
|
4432
|
+
const m = lines[j].match(/^\s*(?:export\s+)?class\s+(\w+)/);
|
|
4237
4433
|
if (m) return m[1];
|
|
4238
4434
|
}
|
|
4239
4435
|
return "";
|
|
@@ -4243,7 +4439,7 @@ function findContainingClass(lines, lineIdx) {
|
|
|
4243
4439
|
* by scanning backwards from `beforeLine`.
|
|
4244
4440
|
*/
|
|
4245
4441
|
function findClassDeclarationStart(lines, className, beforeLine) {
|
|
4246
|
-
const classPattern = new RegExp(
|
|
4442
|
+
const classPattern = new RegExp(`^\\s*(?:export\\s+)?class\\s+${className}\\b`);
|
|
4247
4443
|
for (let i = beforeLine - 1; i >= 0; i--) {
|
|
4248
4444
|
if (!classPattern.test(lines[i])) continue;
|
|
4249
4445
|
let start = i;
|
|
@@ -4712,7 +4908,8 @@ async function resolveFileToDirectoryConflicts(files, targetDir) {
|
|
|
4712
4908
|
};
|
|
4713
4909
|
}
|
|
4714
4910
|
async function integrateGeneratedFiles(opts) {
|
|
4715
|
-
const
|
|
4911
|
+
const mapped = mapFilesForTargetIntegration(opts.files, opts.language);
|
|
4912
|
+
const { files: resolved, removals } = await resolveFileToDirectoryConflicts(await treeShakeFiles(mapped, opts.language), opts.targetDir);
|
|
4716
4913
|
const result = await writeFiles(resolved, opts.targetDir, {
|
|
4717
4914
|
language: opts.language,
|
|
4718
4915
|
header: opts.header
|
|
@@ -4722,7 +4919,7 @@ async function integrateGeneratedFiles(opts) {
|
|
|
4722
4919
|
} catch {}
|
|
4723
4920
|
return {
|
|
4724
4921
|
...result,
|
|
4725
|
-
emittedPaths:
|
|
4922
|
+
emittedPaths: mapped.map((f) => f.path)
|
|
4726
4923
|
};
|
|
4727
4924
|
}
|
|
4728
4925
|
//#endregion
|
|
@@ -4746,6 +4943,7 @@ async function formatTargetFiles(emitter, targetDir, filePaths) {
|
|
|
4746
4943
|
if (!formatCmd) return;
|
|
4747
4944
|
const absolutePaths = filePaths.map((f) => path$1.resolve(targetDir, f));
|
|
4748
4945
|
const batchSize = formatCmd.batchSize ?? 100;
|
|
4946
|
+
process.stderr.write(`[oagen] formatting ${absolutePaths.length} file(s) with ${formatCmd.cmd} (batch ${batchSize})\n`);
|
|
4749
4947
|
for (let i = 0; i < absolutePaths.length; i += batchSize) {
|
|
4750
4948
|
const batch = absolutePaths.slice(i, i + batchSize);
|
|
4751
4949
|
try {
|
|
@@ -4754,7 +4952,10 @@ async function formatTargetFiles(emitter, targetDir, filePaths) {
|
|
|
4754
4952
|
maxBuffer: 10 * 1024 * 1024,
|
|
4755
4953
|
timeout: 12e4
|
|
4756
4954
|
});
|
|
4757
|
-
} catch {
|
|
4955
|
+
} catch (err) {
|
|
4956
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4957
|
+
process.stderr.write(`[oagen] formatter batch failed: ${msg}\n`);
|
|
4958
|
+
}
|
|
4758
4959
|
}
|
|
4759
4960
|
}
|
|
4760
4961
|
//#endregion
|