optikit 1.4.0 โ 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 +16 -0
- package/dist/commands/project/commands.js +29 -21
- package/dist/commands/version/bump.js +6 -6
- package/dist/constants.js +1 -1
- package/dist/utils/helpers/version.js +26 -1
- package/package.json +1 -1
- package/src/commands/project/commands.ts +27 -19
- package/src/commands/version/bump.ts +7 -6
- package/src/constants.ts +1 -1
- package/src/utils/helpers/version.ts +30 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,22 @@ 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
|
+
|
|
23
|
+
### ๐ [1.4.1] - Fix Generate Module Command
|
|
24
|
+
|
|
25
|
+
- ๐ด Fixed `generate module` routing to repo handler instead of module handler
|
|
26
|
+
- ๐ Restructured `generate` as parent command with `module` and `repo` subcommands
|
|
27
|
+
- ๐งน Removed stale `repo/` directory from module scaffolding structure
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
15
31
|
### ๐ [1.4.0] - Interactive Repo Picker & Module Cleanup
|
|
16
32
|
|
|
17
33
|
- ๐ Interactive arrow-key directory picker for `gen repo` โ browse, open, go back, or create folders
|
|
@@ -6,30 +6,38 @@ import { runDoctor } from "./doctor.js";
|
|
|
6
6
|
import { showStatus } from "./status.js";
|
|
7
7
|
export const projectCommands = [
|
|
8
8
|
{
|
|
9
|
-
command: "generate
|
|
10
|
-
aliases: ["gen
|
|
11
|
-
describe: "Generate
|
|
9
|
+
command: "generate",
|
|
10
|
+
aliases: ["gen"],
|
|
11
|
+
describe: "Generate module or repository scaffolding",
|
|
12
12
|
builder: (yargs) => {
|
|
13
13
|
return yargs
|
|
14
|
-
.
|
|
15
|
-
|
|
14
|
+
.command({
|
|
15
|
+
command: "module <moduleName>",
|
|
16
|
+
describe: "Generate a module with full BLoC structure",
|
|
17
|
+
builder: (y) => {
|
|
18
|
+
return y
|
|
19
|
+
.positional("moduleName", { describe: "The name of the module to generate", type: "string" })
|
|
20
|
+
.option("with-route", { alias: "r", type: "boolean", default: false, description: "Also register a route in app_router.dart" });
|
|
21
|
+
},
|
|
22
|
+
handler: (argv) => {
|
|
23
|
+
const moduleName = argv.moduleName;
|
|
24
|
+
generateModule(moduleName);
|
|
25
|
+
if (argv.withRoute) {
|
|
26
|
+
addRoute(moduleName);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
.command({
|
|
31
|
+
command: "repo <moduleName>",
|
|
32
|
+
describe: "Generate a repository file for an existing module",
|
|
33
|
+
builder: (y) => {
|
|
34
|
+
return y.positional("moduleName", { describe: "The module name", type: "string" });
|
|
35
|
+
},
|
|
36
|
+
handler: async (argv) => { await generateRepoModule(argv.moduleName); },
|
|
37
|
+
})
|
|
38
|
+
.demandCommand(1, "Specify a subcommand: module or repo");
|
|
16
39
|
},
|
|
17
|
-
handler: (
|
|
18
|
-
const moduleName = argv.moduleName;
|
|
19
|
-
generateModule(moduleName);
|
|
20
|
-
if (argv.withRoute) {
|
|
21
|
-
addRoute(moduleName);
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
command: "generate repo <moduleName>",
|
|
27
|
-
aliases: ["gen repo"],
|
|
28
|
-
describe: "Generate a repository file for an existing module",
|
|
29
|
-
builder: (yargs) => {
|
|
30
|
-
return yargs.positional("moduleName", { describe: "The module name", type: "string" });
|
|
31
|
-
},
|
|
32
|
-
handler: async (argv) => { await generateRepoModule(argv.moduleName); },
|
|
40
|
+
handler: () => { },
|
|
33
41
|
},
|
|
34
42
|
{
|
|
35
43
|
command: "add-route <moduleName>",
|
|
@@ -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
|
|
82
|
+
const iosVersionString = getCurrentIosMarketingVersion();
|
|
83
83
|
const currentIosBuild = getCurrentIosBuildNumber();
|
|
84
84
|
const nextIosBuild = currentIosBuild + 1;
|
|
85
|
-
LoggerHelpers.info(`Current version: ${
|
|
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(`${
|
|
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(
|
|
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(
|
|
97
|
+
await updateFlutterVersion(iosVersionString, "", nextIosBuild.toString());
|
|
98
98
|
LoggerHelpers.success(`iOS build number incremented to ${nextIosBuild}`);
|
|
99
99
|
}
|
|
100
100
|
catch (error) {
|
package/dist/constants.js
CHANGED
|
@@ -44,7 +44,7 @@ export const BACKUP_CONFIG = {
|
|
|
44
44
|
};
|
|
45
45
|
// Module generation
|
|
46
46
|
export const MODULE_STRUCTURE = {
|
|
47
|
-
DIRECTORIES: ["bloc", "event", "state", "screen", "import", "factory"
|
|
47
|
+
DIRECTORIES: ["bloc", "event", "state", "screen", "import", "factory"],
|
|
48
48
|
NAME_PATTERN: /^[a-z0-9_]+$/,
|
|
49
49
|
};
|
|
50
50
|
// Flutter commands
|
|
@@ -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
|
@@ -8,28 +8,36 @@ import { showStatus } from "./status.js";
|
|
|
8
8
|
|
|
9
9
|
export const projectCommands: CommandModule[] = [
|
|
10
10
|
{
|
|
11
|
-
command: "generate
|
|
12
|
-
aliases: ["gen
|
|
13
|
-
describe: "Generate
|
|
11
|
+
command: "generate",
|
|
12
|
+
aliases: ["gen"],
|
|
13
|
+
describe: "Generate module or repository scaffolding",
|
|
14
14
|
builder: (yargs) => {
|
|
15
15
|
return yargs
|
|
16
|
-
.
|
|
17
|
-
|
|
16
|
+
.command({
|
|
17
|
+
command: "module <moduleName>",
|
|
18
|
+
describe: "Generate a module with full BLoC structure",
|
|
19
|
+
builder: (y) => {
|
|
20
|
+
return y
|
|
21
|
+
.positional("moduleName", { describe: "The name of the module to generate", type: "string" as const })
|
|
22
|
+
.option("with-route", { alias: "r", type: "boolean", default: false, description: "Also register a route in app_router.dart" });
|
|
23
|
+
},
|
|
24
|
+
handler: (argv) => {
|
|
25
|
+
const moduleName = argv.moduleName as string;
|
|
26
|
+
generateModule(moduleName);
|
|
27
|
+
if (argv.withRoute) { addRoute(moduleName); }
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
.command({
|
|
31
|
+
command: "repo <moduleName>",
|
|
32
|
+
describe: "Generate a repository file for an existing module",
|
|
33
|
+
builder: (y) => {
|
|
34
|
+
return y.positional("moduleName", { describe: "The module name", type: "string" as const });
|
|
35
|
+
},
|
|
36
|
+
handler: async (argv) => { await generateRepoModule(argv.moduleName as string); },
|
|
37
|
+
})
|
|
38
|
+
.demandCommand(1, "Specify a subcommand: module or repo");
|
|
18
39
|
},
|
|
19
|
-
handler: (
|
|
20
|
-
const moduleName = argv.moduleName as string;
|
|
21
|
-
generateModule(moduleName);
|
|
22
|
-
if (argv.withRoute) { addRoute(moduleName); }
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
command: "generate repo <moduleName>",
|
|
27
|
-
aliases: ["gen repo"],
|
|
28
|
-
describe: "Generate a repository file for an existing module",
|
|
29
|
-
builder: (yargs) => {
|
|
30
|
-
return yargs.positional("moduleName", { describe: "The module name", type: "string" as const });
|
|
31
|
-
},
|
|
32
|
-
handler: async (argv) => { await generateRepoModule(argv.moduleName as string); },
|
|
40
|
+
handler: () => { /* handled by subcommands */ },
|
|
33
41
|
},
|
|
34
42
|
{
|
|
35
43
|
command: "add-route <moduleName>",
|
|
@@ -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
|
|
126
|
+
const iosVersionString = getCurrentIosMarketingVersion();
|
|
126
127
|
const currentIosBuild = getCurrentIosBuildNumber();
|
|
127
128
|
const nextIosBuild = currentIosBuild + 1;
|
|
128
129
|
|
|
129
|
-
LoggerHelpers.info(`Current version: ${
|
|
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(`${
|
|
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(
|
|
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(
|
|
146
|
+
await updateFlutterVersion(iosVersionString, "", nextIosBuild.toString());
|
|
146
147
|
|
|
147
148
|
LoggerHelpers.success(`iOS build number incremented to ${nextIosBuild}`);
|
|
148
149
|
|
package/src/constants.ts
CHANGED
|
@@ -48,7 +48,7 @@ export const BACKUP_CONFIG = {
|
|
|
48
48
|
|
|
49
49
|
// Module generation
|
|
50
50
|
export const MODULE_STRUCTURE = {
|
|
51
|
-
DIRECTORIES: ["bloc", "event", "state", "screen", "import", "factory"
|
|
51
|
+
DIRECTORIES: ["bloc", "event", "state", "screen", "import", "factory"],
|
|
52
52
|
NAME_PATTERN: /^[a-z0-9_]+$/,
|
|
53
53
|
} as const;
|
|
54
54
|
|
|
@@ -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
|