@fern-api/generator-cli 0.9.52 → 0.9.54
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.js +143 -13
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -41162,6 +41162,7 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
41162
41162
|
}
|
|
41163
41163
|
}
|
|
41164
41164
|
let processedContent = this.removeGoModulePathSuffixPairs(contentLines);
|
|
41165
|
+
processedContent = this.removeGoExplicitFieldBitConstantPairs(processedContent);
|
|
41165
41166
|
processedContent = this.removeVersionChangePairs(processedContent, mappedMagicVersion);
|
|
41166
41167
|
processedContent = this.removeRemainingMagicVersionLines(processedContent, mappedMagicVersion);
|
|
41167
41168
|
let hasChanges = false;
|
|
@@ -41366,6 +41367,90 @@ var AutoVersioningService = class _AutoVersioningService {
|
|
|
41366
41367
|
hasSuffix: suffixPattern.test(content)
|
|
41367
41368
|
};
|
|
41368
41369
|
}
|
|
41370
|
+
/**
|
|
41371
|
+
* Removes Go `explicitFields` bit-constant reindexing churn from a diff section.
|
|
41372
|
+
*
|
|
41373
|
+
* The Go SDK tracks which optional fields were explicitly set via a per-struct `big.Int`
|
|
41374
|
+
* bitmask. For each struct property it generates a private constant whose value is a single
|
|
41375
|
+
* bit at the property's positional index, e.g.
|
|
41376
|
+
*
|
|
41377
|
+
* var (
|
|
41378
|
+
* entityFieldGeoShape = big.NewInt(1 << 3)
|
|
41379
|
+
* entityFieldGeoDetails = big.NewInt(1 << 4)
|
|
41380
|
+
* )
|
|
41381
|
+
*
|
|
41382
|
+
* Inserting a new field earlier in the struct shifts every following constant's bit index by
|
|
41383
|
+
* one, producing a deletion/addition pair per field that differs only by the integer:
|
|
41384
|
+
*
|
|
41385
|
+
* - entityFieldGeoShape = big.NewInt(1 << 3)
|
|
41386
|
+
* + entityFieldGeoShape = big.NewInt(1 << 4)
|
|
41387
|
+
*
|
|
41388
|
+
* This is a purely mechanical artifact of the field addition: the bit is assigned and read
|
|
41389
|
+
* within the same generated version (the wire format is name-based JSON, not bit position),
|
|
41390
|
+
* so shifting it is not observable to consumers. Left in the diff, the AI analyzer reads the
|
|
41391
|
+
* shifted bit positions as a serialization-compatibility break and misclassifies an additive
|
|
41392
|
+
* change as a spurious MAJOR bump. The genuinely new field, its own new bit constant, and its
|
|
41393
|
+
* setter are all pure additions with no matching deletion, so they survive this pass and the
|
|
41394
|
+
* AI still sees (and correctly classifies) the field addition as MINOR.
|
|
41395
|
+
*/
|
|
41396
|
+
removeGoExplicitFieldBitConstantPairs(lines) {
|
|
41397
|
+
const additions = [];
|
|
41398
|
+
for (let index = 0; index < lines.length; index++) {
|
|
41399
|
+
const line = lines[index];
|
|
41400
|
+
if (line == null || !this.isAdditionLine(line)) {
|
|
41401
|
+
continue;
|
|
41402
|
+
}
|
|
41403
|
+
const info = this.analyzeGoBitConstantLine(line);
|
|
41404
|
+
if (info != null) {
|
|
41405
|
+
additions.push({ index, normalized: info.normalized });
|
|
41406
|
+
}
|
|
41407
|
+
}
|
|
41408
|
+
const removed = /* @__PURE__ */ new Set();
|
|
41409
|
+
const usedAdditions = /* @__PURE__ */ new Set();
|
|
41410
|
+
for (let index = 0; index < lines.length; index++) {
|
|
41411
|
+
const line = lines[index];
|
|
41412
|
+
if (line == null || !this.isDeletionLine(line)) {
|
|
41413
|
+
continue;
|
|
41414
|
+
}
|
|
41415
|
+
const info = this.analyzeGoBitConstantLine(line);
|
|
41416
|
+
if (info == null) {
|
|
41417
|
+
continue;
|
|
41418
|
+
}
|
|
41419
|
+
const match2 = additions.find(
|
|
41420
|
+
(addition) => !usedAdditions.has(addition.index) && addition.normalized === info.normalized
|
|
41421
|
+
);
|
|
41422
|
+
if (match2 != null) {
|
|
41423
|
+
usedAdditions.add(match2.index);
|
|
41424
|
+
removed.add(index);
|
|
41425
|
+
removed.add(match2.index);
|
|
41426
|
+
}
|
|
41427
|
+
}
|
|
41428
|
+
if (removed.size === 0) {
|
|
41429
|
+
return lines;
|
|
41430
|
+
}
|
|
41431
|
+
return lines.filter((_2, index) => !removed.has(index));
|
|
41432
|
+
}
|
|
41433
|
+
/**
|
|
41434
|
+
* If a diff line (with its leading +/- stripped) is a generated Go `explicitFields`
|
|
41435
|
+
* bit constant — `<name> = big.NewInt(1 << N)` or the >=63 form
|
|
41436
|
+
* `<name> = big.NewInt(0).Lsh(big.NewInt(1), N)` — returns a normalized key with the bit
|
|
41437
|
+
* index removed so a deletion and its reindexed addition compare equal. Requiring the exact
|
|
41438
|
+
* `big.NewInt` bit-shift shape keeps this from matching ordinary integer assignments.
|
|
41439
|
+
*/
|
|
41440
|
+
analyzeGoBitConstantLine(line) {
|
|
41441
|
+
const content = line.substring(1);
|
|
41442
|
+
const shiftMatch = content.match(/^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=\s*big\.NewInt\(1\s*<<\s*\d+\)\s*$/);
|
|
41443
|
+
if (shiftMatch?.[2] != null) {
|
|
41444
|
+
return { normalized: `${shiftMatch[2]}=big.NewInt(1<<#)` };
|
|
41445
|
+
}
|
|
41446
|
+
const lshMatch = content.match(
|
|
41447
|
+
/^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=\s*big\.NewInt\(0\)\.Lsh\(big\.NewInt\(1\),\s*\d+\)\s*$/
|
|
41448
|
+
);
|
|
41449
|
+
if (lshMatch?.[2] != null) {
|
|
41450
|
+
return { normalized: `${lshMatch[2]}=big.NewInt(0).Lsh(big.NewInt(1),#)` };
|
|
41451
|
+
}
|
|
41452
|
+
return void 0;
|
|
41453
|
+
}
|
|
41369
41454
|
/**
|
|
41370
41455
|
* Gets the latest semantic version from git tags in the given repository.
|
|
41371
41456
|
* Used as a fallback when the magic version is not embedded in any generated file
|
|
@@ -41758,11 +41843,20 @@ var SEMVER_PATTERN = /^(v)?(\d+)\.(\d+)\.(\d+)(?:-([\w.-]+))?(?:\+([\w.-]+))?$/;
|
|
|
41758
41843
|
function isValidSemver(version2) {
|
|
41759
41844
|
return SEMVER_PATTERN.test(version2);
|
|
41760
41845
|
}
|
|
41846
|
+
function isPlaceholderVersion(version2) {
|
|
41847
|
+
const withoutPrefix = version2.startsWith("v") ? version2.slice(1) : version2;
|
|
41848
|
+
return withoutPrefix === MAGIC_VERSION || withoutPrefix.startsWith(`${MAGIC_VERSION}.`) || withoutPrefix === MAGIC_VERSION_PYTHON || withoutPrefix.startsWith(`${MAGIC_VERSION_PYTHON}.`);
|
|
41849
|
+
}
|
|
41761
41850
|
function incrementVersion(currentVersion, versionBump) {
|
|
41762
41851
|
const matcher = currentVersion.match(SEMVER_PATTERN);
|
|
41763
41852
|
if (!matcher) {
|
|
41764
41853
|
throw new AutoVersioningException("Invalid semantic version format: " + currentVersion);
|
|
41765
41854
|
}
|
|
41855
|
+
if (isPlaceholderVersion(currentVersion)) {
|
|
41856
|
+
throw new AutoVersioningException(
|
|
41857
|
+
"Refusing to increment the magic placeholder version: " + currentVersion + ". A real previous version must be resolved first."
|
|
41858
|
+
);
|
|
41859
|
+
}
|
|
41766
41860
|
const prefix = matcher[1] ?? "";
|
|
41767
41861
|
const versionWithoutPrefix = currentVersion.slice(prefix.length);
|
|
41768
41862
|
const preRelease = matcher[5];
|
|
@@ -41833,7 +41927,8 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
41833
41927
|
}
|
|
41834
41928
|
async handleFirstGeneration(params) {
|
|
41835
41929
|
const { service, language, mappedMagicVersion, commit } = params;
|
|
41836
|
-
const
|
|
41930
|
+
const configuredBaseVersion = this.usableVersion(this.config.baseVersion, "baseVersion");
|
|
41931
|
+
const initialVersion = configuredBaseVersion ?? (mappedMagicVersion.startsWith("v") ? "v0.0.1" : "0.0.1");
|
|
41837
41932
|
if (!isValidSemver(initialVersion)) {
|
|
41838
41933
|
const errorMessage = `AutoVersionStep: baseVersion ${JSON.stringify(initialVersion)} is not a valid semver string (expected e.g. "1.2.3" or "v1.2.3"). Refusing to run.`;
|
|
41839
41934
|
this.logger.error(errorMessage);
|
|
@@ -42167,14 +42262,18 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
42167
42262
|
*/
|
|
42168
42263
|
async resolvePreviousVersionNonReplay(params) {
|
|
42169
42264
|
const { service, rawDiff, mappedMagicVersion, baseVersion } = params;
|
|
42170
|
-
|
|
42265
|
+
const usableBaseVersion = this.usableVersion(baseVersion, "baseVersion");
|
|
42266
|
+
if (usableBaseVersion != null && isValidSemver(usableBaseVersion)) {
|
|
42171
42267
|
this.logger.debug(
|
|
42172
|
-
`AutoVersionStep (non-replay): previous version from pipeline baseVersion: ${
|
|
42268
|
+
`AutoVersionStep (non-replay): previous version from pipeline baseVersion: ${usableBaseVersion}`
|
|
42173
42269
|
);
|
|
42174
|
-
return this.normalizeVersionPrefix(
|
|
42270
|
+
return this.normalizeVersionPrefix(usableBaseVersion, mappedMagicVersion);
|
|
42175
42271
|
}
|
|
42176
42272
|
try {
|
|
42177
|
-
const extracted =
|
|
42273
|
+
const extracted = this.usableVersion(
|
|
42274
|
+
service.extractPreviousVersion(rawDiff, mappedMagicVersion) ?? void 0,
|
|
42275
|
+
"diff"
|
|
42276
|
+
);
|
|
42178
42277
|
if (extracted != null) {
|
|
42179
42278
|
this.logger.debug(`AutoVersionStep (non-replay): previous version from diff: ${extracted}`);
|
|
42180
42279
|
return extracted;
|
|
@@ -42185,12 +42284,15 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
42185
42284
|
}
|
|
42186
42285
|
this.logger.info("AutoVersionStep (non-replay): magic version not in diff; trying metadata + git tags.");
|
|
42187
42286
|
}
|
|
42188
|
-
const metadataVersion = this.readVersionFromMetadataAtHead();
|
|
42287
|
+
const metadataVersion = this.usableVersion(this.readVersionFromMetadataAtHead(), "metadata.json");
|
|
42189
42288
|
if (metadataVersion != null) {
|
|
42190
42289
|
return this.normalizeVersionPrefix(metadataVersion, mappedMagicVersion);
|
|
42191
42290
|
}
|
|
42192
42291
|
try {
|
|
42193
|
-
const tagVersion =
|
|
42292
|
+
const tagVersion = this.usableVersion(
|
|
42293
|
+
await service.getLatestVersionFromGitTags(this.outputDir) ?? void 0,
|
|
42294
|
+
"git tags"
|
|
42295
|
+
);
|
|
42194
42296
|
if (tagVersion != null) {
|
|
42195
42297
|
return this.normalizeVersionPrefix(tagVersion, mappedMagicVersion);
|
|
42196
42298
|
}
|
|
@@ -42201,12 +42303,16 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
42201
42303
|
}
|
|
42202
42304
|
async resolvePreviousVersion(params) {
|
|
42203
42305
|
const { service, rawDiff, mappedMagicVersion, baseVersion } = params;
|
|
42204
|
-
|
|
42205
|
-
|
|
42206
|
-
|
|
42306
|
+
const usableBaseVersion = this.usableVersion(baseVersion, "baseVersion");
|
|
42307
|
+
if (usableBaseVersion != null && isValidSemver(usableBaseVersion)) {
|
|
42308
|
+
this.logger.debug(`AutoVersionStep: previous version from pipeline baseVersion: ${usableBaseVersion}`);
|
|
42309
|
+
return this.normalizeVersionPrefix(usableBaseVersion, mappedMagicVersion);
|
|
42207
42310
|
}
|
|
42208
42311
|
try {
|
|
42209
|
-
const extracted =
|
|
42312
|
+
const extracted = this.usableVersion(
|
|
42313
|
+
service.extractPreviousVersion(rawDiff, mappedMagicVersion) ?? void 0,
|
|
42314
|
+
"diff"
|
|
42315
|
+
);
|
|
42210
42316
|
if (extracted != null) {
|
|
42211
42317
|
this.logger.debug(`AutoVersionStep: previous version from diff: ${extracted}`);
|
|
42212
42318
|
return extracted;
|
|
@@ -42217,12 +42323,15 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
42217
42323
|
}
|
|
42218
42324
|
this.logger.info("AutoVersionStep: magic version not found in diff; falling back to metadata + git tags.");
|
|
42219
42325
|
}
|
|
42220
|
-
const metadataVersion = await this.readVersionFromMetadata();
|
|
42326
|
+
const metadataVersion = this.usableVersion(await this.readVersionFromMetadata(), "metadata.json");
|
|
42221
42327
|
if (metadataVersion != null) {
|
|
42222
42328
|
return this.normalizeVersionPrefix(metadataVersion, mappedMagicVersion);
|
|
42223
42329
|
}
|
|
42224
42330
|
try {
|
|
42225
|
-
const tagVersion =
|
|
42331
|
+
const tagVersion = this.usableVersion(
|
|
42332
|
+
await service.getLatestVersionFromGitTags(this.outputDir) ?? void 0,
|
|
42333
|
+
"git tags"
|
|
42334
|
+
);
|
|
42226
42335
|
if (tagVersion != null) {
|
|
42227
42336
|
return this.normalizeVersionPrefix(tagVersion, mappedMagicVersion);
|
|
42228
42337
|
}
|
|
@@ -42244,6 +42353,27 @@ var AutoVersionStep = class extends BaseStep {
|
|
|
42244
42353
|
return void 0;
|
|
42245
42354
|
}
|
|
42246
42355
|
}
|
|
42356
|
+
/**
|
|
42357
|
+
* Drops candidate previous versions that are the magic placeholder. SDK repos
|
|
42358
|
+
* that derive their published version at release time keep the placeholder
|
|
42359
|
+
* committed, so every resolution source (baseVersion, diff extraction,
|
|
42360
|
+
* metadata.json, git tags) can hand back the sentinel; incrementing it would
|
|
42361
|
+
* emit a mutated placeholder such as `0.0.0-fern-placeholder.0` instead of a
|
|
42362
|
+
* real version. Returning undefined lets the caller fall through to the next
|
|
42363
|
+
* source, and ultimately to the first-generation path.
|
|
42364
|
+
*/
|
|
42365
|
+
usableVersion(version2, source) {
|
|
42366
|
+
if (version2 == null) {
|
|
42367
|
+
return void 0;
|
|
42368
|
+
}
|
|
42369
|
+
if (isPlaceholderVersion(version2)) {
|
|
42370
|
+
this.logger.info(
|
|
42371
|
+
`AutoVersionStep: ignoring placeholder version ${version2} from ${source}; trying the next previous-version source.`
|
|
42372
|
+
);
|
|
42373
|
+
return void 0;
|
|
42374
|
+
}
|
|
42375
|
+
return version2;
|
|
42376
|
+
}
|
|
42247
42377
|
normalizeVersionPrefix(version2, mappedMagicVersion) {
|
|
42248
42378
|
const stripped = version2.startsWith("v") ? version2.slice(1) : version2;
|
|
42249
42379
|
return mappedMagicVersion.startsWith("v") ? `v${stripped}` : stripped;
|