optikit 1.4.1 → 1.4.2

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/CHANGELOG.md CHANGED
@@ -12,6 +12,14 @@ We follow **Semantic Versioning (SemVer)**:
12
12
 
13
13
  ---
14
14
 
15
+ ### 🛠 [1.4.2] - Fix bump-ios Overwriting Manually Set iOS Version
16
+
17
+ - 🔴 Fixed `bump-ios` / `tf` overwriting a manually set `MARKETING_VERSION` in `project.pbxproj` with the stale version from `pubspec.yaml`
18
+ - 🆕 Added `getCurrentIosMarketingVersion()` helper that reads `MARKETING_VERSION` directly from `project.pbxproj` (falls back to `pubspec.yaml` if iOS file is missing)
19
+ - 🔄 `bumpIosBuildOnly()` now uses the iOS marketing version as source of truth instead of `pubspec.yaml`, so calling `flutter-update-version --app-version X --ios-build N` followed by `bump-ios` / `tf` correctly preserves the manually set version
20
+
21
+ ---
22
+
15
23
  ### 🛠 [1.4.1] - Fix Generate Module Command
16
24
 
17
25
  - 🔴 Fixed `generate module` routing to repo handler instead of module handler
@@ -1,7 +1,7 @@
1
1
  import { createInterface } from "readline";
2
2
  import { validateFlutterProject } from "../../utils/validators/validation.js";
3
3
  import { LoggerHelpers } from "../../utils/services/logger.js";
4
- import { getCurrentVersion, incrementVersion, formatVersion, getCurrentIosBuildNumber } from "../../utils/helpers/version.js";
4
+ import { getCurrentVersion, incrementVersion, formatVersion, getCurrentIosBuildNumber, getCurrentIosMarketingVersion } from "../../utils/helpers/version.js";
5
5
  import { handleCommandError } from "../../utils/helpers/error.js";
6
6
  import { updateFlutterVersion } from "./update.js";
7
7
  import chalk from "chalk";
@@ -79,22 +79,22 @@ async function bumpIosBuildOnly(skipConfirm = false) {
79
79
  }
80
80
  try {
81
81
  const current = getCurrentVersion();
82
- const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
82
+ const iosVersionString = getCurrentIosMarketingVersion();
83
83
  const currentIosBuild = getCurrentIosBuildNumber();
84
84
  const nextIosBuild = currentIosBuild + 1;
85
- LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
85
+ LoggerHelpers.info(`Current iOS version: ${iosVersionString} (build ${currentIosBuild})`);
86
86
  LoggerHelpers.info("Incrementing iOS build number only (for TestFlight)...");
87
87
  console.log(chalk.cyan("\nBuild number changes:"));
88
- console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
88
+ console.log(chalk.gray(" Version:"), chalk.white(`${iosVersionString} (unchanged)`));
89
89
  console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} (unchanged)`));
90
90
  console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
91
- showDiffPreview(currentVersionString, currentVersionString, current.buildNumber, "", currentIosBuild, nextIosBuild);
91
+ showDiffPreview(iosVersionString, iosVersionString, current.buildNumber, "", currentIosBuild, nextIosBuild);
92
92
  const confirmed = await confirmAction("Proceed?", skipConfirm);
93
93
  if (!confirmed) {
94
94
  LoggerHelpers.info("Bump cancelled.");
95
95
  return;
96
96
  }
97
- await updateFlutterVersion(currentVersionString, "", nextIosBuild.toString());
97
+ await updateFlutterVersion(iosVersionString, "", nextIosBuild.toString());
98
98
  LoggerHelpers.success(`iOS build number incremented to ${nextIosBuild}`);
99
99
  }
100
100
  catch (error) {
@@ -2,7 +2,7 @@ import fs from "fs";
2
2
  import path from "path";
3
3
  import { LoggerHelpers } from "../services/logger.js";
4
4
  import { PROJECT_PATHS } from "../../constants.js";
5
- export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber };
5
+ export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber, getCurrentIosMarketingVersion };
6
6
  /**
7
7
  * Parses a version string in format "X.Y.Z+B"
8
8
  * @param versionString - Version string (e.g., "1.2.3+45")
@@ -80,6 +80,31 @@ export function getNextBuildNumber() {
80
80
  const current = getCurrentVersion();
81
81
  return current.buildNumber + 1;
82
82
  }
83
+ /**
84
+ * Gets the current iOS marketing version (MARKETING_VERSION) from project.pbxproj.
85
+ * Falls back to pubspec.yaml version when the iOS file is not found.
86
+ */
87
+ function getCurrentIosMarketingVersion() {
88
+ try {
89
+ const projectPbxProjPath = path.join(process.cwd(), PROJECT_PATHS.IOS_PROJECT_PBXPROJ);
90
+ if (!fs.existsSync(projectPbxProjPath)) {
91
+ const fallback = getCurrentVersion();
92
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
93
+ }
94
+ const projectContent = fs.readFileSync(projectPbxProjPath, 'utf8');
95
+ const match = projectContent.match(/MARKETING_VERSION\s*=\s*([^;]+);/);
96
+ if (!match) {
97
+ const fallback = getCurrentVersion();
98
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
99
+ }
100
+ return match[1].trim();
101
+ }
102
+ catch (error) {
103
+ LoggerHelpers.warning(`Error reading iOS marketing version: ${error instanceof Error ? error.message : error}. Falling back to pubspec.yaml.`);
104
+ const fallback = getCurrentVersion();
105
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
106
+ }
107
+ }
83
108
  /**
84
109
  * Gets the current iOS build number from project.pbxproj
85
110
  * @returns Current iOS build number, or 1 if not found
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "optikit",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "OptiKit CLI",
5
5
  "main": "src/cli.ts",
6
6
  "type": "module",
@@ -6,7 +6,8 @@ import {
6
6
  incrementVersion,
7
7
  formatVersion,
8
8
  getNextBuildNumber,
9
- getCurrentIosBuildNumber
9
+ getCurrentIosBuildNumber,
10
+ getCurrentIosMarketingVersion
10
11
  } from "../../utils/helpers/version.js";
11
12
  import { handleCommandError } from "../../utils/helpers/error.js";
12
13
  import { updateFlutterVersion } from "./update.js";
@@ -122,19 +123,19 @@ async function bumpIosBuildOnly(skipConfirm: boolean = false): Promise<void> {
122
123
 
123
124
  try {
124
125
  const current = getCurrentVersion();
125
- const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
126
+ const iosVersionString = getCurrentIosMarketingVersion();
126
127
  const currentIosBuild = getCurrentIosBuildNumber();
127
128
  const nextIosBuild = currentIosBuild + 1;
128
129
 
129
- LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
130
+ LoggerHelpers.info(`Current iOS version: ${iosVersionString} (build ${currentIosBuild})`);
130
131
  LoggerHelpers.info("Incrementing iOS build number only (for TestFlight)...");
131
132
 
132
133
  console.log(chalk.cyan("\nBuild number changes:"));
133
- console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
134
+ console.log(chalk.gray(" Version:"), chalk.white(`${iosVersionString} (unchanged)`));
134
135
  console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} (unchanged)`));
135
136
  console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
136
137
 
137
- showDiffPreview(currentVersionString, currentVersionString, current.buildNumber, "", currentIosBuild, nextIosBuild);
138
+ showDiffPreview(iosVersionString, iosVersionString, current.buildNumber, "", currentIosBuild, nextIosBuild);
138
139
 
139
140
  const confirmed = await confirmAction("Proceed?", skipConfirm);
140
141
  if (!confirmed) {
@@ -142,7 +143,7 @@ async function bumpIosBuildOnly(skipConfirm: boolean = false): Promise<void> {
142
143
  return;
143
144
  }
144
145
 
145
- await updateFlutterVersion(currentVersionString, "", nextIosBuild.toString());
146
+ await updateFlutterVersion(iosVersionString, "", nextIosBuild.toString());
146
147
 
147
148
  LoggerHelpers.success(`iOS build number incremented to ${nextIosBuild}`);
148
149
 
@@ -3,7 +3,7 @@ import path from "path";
3
3
  import { LoggerHelpers } from "../services/logger.js";
4
4
  import { PROJECT_PATHS } from "../../constants.js";
5
5
 
6
- export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber, VersionInfo };
6
+ export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber, getCurrentIosMarketingVersion, VersionInfo };
7
7
 
8
8
  /**
9
9
  * Version information structure
@@ -109,6 +109,35 @@ export function getNextBuildNumber(): number {
109
109
  return current.buildNumber + 1;
110
110
  }
111
111
 
112
+ /**
113
+ * Gets the current iOS marketing version (MARKETING_VERSION) from project.pbxproj.
114
+ * Falls back to pubspec.yaml version when the iOS file is not found.
115
+ */
116
+ function getCurrentIosMarketingVersion(): string {
117
+ try {
118
+ const projectPbxProjPath = path.join(process.cwd(), PROJECT_PATHS.IOS_PROJECT_PBXPROJ);
119
+
120
+ if (!fs.existsSync(projectPbxProjPath)) {
121
+ const fallback = getCurrentVersion();
122
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
123
+ }
124
+
125
+ const projectContent = fs.readFileSync(projectPbxProjPath, 'utf8');
126
+ const match = projectContent.match(/MARKETING_VERSION\s*=\s*([^;]+);/);
127
+
128
+ if (!match) {
129
+ const fallback = getCurrentVersion();
130
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
131
+ }
132
+
133
+ return match[1].trim();
134
+ } catch (error) {
135
+ LoggerHelpers.warning(`Error reading iOS marketing version: ${error instanceof Error ? error.message : error}. Falling back to pubspec.yaml.`);
136
+ const fallback = getCurrentVersion();
137
+ return `${fallback.major}.${fallback.minor}.${fallback.patch}`;
138
+ }
139
+ }
140
+
112
141
  /**
113
142
  * Gets the current iOS build number from project.pbxproj
114
143
  * @returns Current iOS build number, or 1 if not found