appshot-cli 0.9.0 → 0.9.1

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.
Files changed (33) hide show
  1. package/README.md +305 -1
  2. package/dist/cli.js +6 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/export.d.ts +3 -0
  5. package/dist/commands/export.d.ts.map +1 -0
  6. package/dist/commands/export.js +382 -0
  7. package/dist/commands/export.js.map +1 -0
  8. package/dist/commands/order.d.ts +3 -0
  9. package/dist/commands/order.d.ts.map +1 -0
  10. package/dist/commands/order.js +321 -0
  11. package/dist/commands/order.js.map +1 -0
  12. package/dist/services/doctor.js +1 -1
  13. package/dist/services/export-validator.d.ts +23 -0
  14. package/dist/services/export-validator.d.ts.map +1 -0
  15. package/dist/services/export-validator.js +209 -0
  16. package/dist/services/export-validator.js.map +1 -0
  17. package/dist/services/fastlane-config-generator.d.ts +17 -0
  18. package/dist/services/fastlane-config-generator.d.ts.map +1 -0
  19. package/dist/services/fastlane-config-generator.js +343 -0
  20. package/dist/services/fastlane-config-generator.js.map +1 -0
  21. package/dist/services/fastlane-language-mapper.d.ts +33 -0
  22. package/dist/services/fastlane-language-mapper.d.ts.map +1 -0
  23. package/dist/services/fastlane-language-mapper.js +167 -0
  24. package/dist/services/fastlane-language-mapper.js.map +1 -0
  25. package/dist/services/screenshot-order.d.ts +41 -0
  26. package/dist/services/screenshot-order.d.ts.map +1 -0
  27. package/dist/services/screenshot-order.js +211 -0
  28. package/dist/services/screenshot-order.js.map +1 -0
  29. package/dist/services/screenshot-organizer.d.ts +44 -0
  30. package/dist/services/screenshot-organizer.d.ts.map +1 -0
  31. package/dist/services/screenshot-organizer.js +234 -0
  32. package/dist/services/screenshot-organizer.js.map +1 -0
  33. package/package.json +1 -1
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Generate a Deliverfile for Fastlane
3
+ */
4
+ export function generateDeliverfile(languages, screenshotsPath = './screenshots') {
5
+ const timestamp = new Date().toISOString();
6
+ return `# Generated by appshot export
7
+ # ${timestamp}
8
+
9
+ # Screenshot configuration
10
+ screenshots_path "${screenshotsPath}"
11
+ overwrite_screenshots true
12
+
13
+ # Languages to process
14
+ languages([
15
+ ${languages.map(l => `'${l}'`).join(',\n ')}
16
+ ])
17
+
18
+ # Skip other deliverables (screenshots only)
19
+ skip_metadata true
20
+ skip_binary_upload true
21
+ skip_app_version_update true
22
+
23
+ # Submission configuration
24
+ submit_for_review false
25
+ automatic_release false
26
+ phased_release false
27
+
28
+ # Optional: Add your app configuration
29
+ # app_identifier "com.example.app"
30
+ # team_id "YOUR_TEAM_ID"
31
+
32
+ # Optional: Authentication
33
+ # You can use App Store Connect API keys:
34
+ # app_store_connect_api_key(
35
+ # key_id: "YOUR_KEY_ID",
36
+ # issuer_id: "YOUR_ISSUER_ID",
37
+ # key_filepath: "./AuthKey_YOUR_KEY_ID.p8"
38
+ # )
39
+ `;
40
+ }
41
+ /**
42
+ * Generate a Fastlane lane for appshot integration
43
+ */
44
+ export function generateFastfileLane() {
45
+ return `# Add these lanes to your Fastfile for appshot integration
46
+ # Generated by appshot export
47
+
48
+ desc "Generate and upload screenshots using appshot"
49
+ lane :screenshots do
50
+ # Ensure we're in the right directory
51
+ ensure_git_status_clean
52
+
53
+ # Generate screenshots with appshot
54
+ UI.message "Generating screenshots with appshot..."
55
+ sh "cd .. && appshot build --preset iphone-6-9,ipad-13"
56
+
57
+ # Export to Fastlane structure
58
+ UI.message "Exporting screenshots for Fastlane..."
59
+ sh "cd .. && appshot export fastlane --clean"
60
+
61
+ # Upload to App Store Connect
62
+ UI.message "Uploading screenshots to App Store Connect..."
63
+ deliver(
64
+ screenshots_path: "./screenshots",
65
+ overwrite_screenshots: true,
66
+ skip_metadata: true,
67
+ skip_binary_upload: true,
68
+ force: true, # Skip HTML preview
69
+
70
+ # Optional: specify app if not in Deliverfile
71
+ # app_identifier: "com.example.app"
72
+ )
73
+
74
+ UI.success "Screenshots uploaded successfully!"
75
+ end
76
+
77
+ desc "Generate screenshots only (no upload)"
78
+ lane :generate_screenshots do
79
+ # Generate screenshots with appshot
80
+ UI.message "Generating screenshots with appshot..."
81
+ sh "cd .. && appshot build --preset iphone-6-9,ipad-13"
82
+
83
+ # Export to Fastlane structure
84
+ UI.message "Exporting screenshots for Fastlane..."
85
+ sh "cd .. && appshot export fastlane --clean"
86
+
87
+ UI.success "Screenshots ready in fastlane/screenshots/"
88
+ UI.message "Run 'fastlane deliver' to upload when ready"
89
+ end
90
+
91
+ desc "Validate screenshots before upload"
92
+ lane :validate_screenshots do
93
+ # Generate and export screenshots
94
+ sh "cd .. && appshot build --preset iphone-6-9,ipad-13 --dry-run"
95
+ sh "cd .. && appshot export fastlane --dry-run"
96
+
97
+ # Validate with deliver
98
+ deliver(
99
+ screenshots_path: "./screenshots",
100
+ skip_metadata: true,
101
+ skip_binary_upload: true,
102
+ verify_only: true # Only validate, don't upload
103
+ )
104
+
105
+ UI.success "Screenshots validated successfully!"
106
+ end
107
+
108
+ desc "Download current screenshots from App Store Connect"
109
+ lane :download_screenshots do
110
+ # Download current screenshots
111
+ deliver(
112
+ screenshots_path: "./screenshots_backup",
113
+ download_screenshots: true,
114
+ skip_metadata: true,
115
+ skip_binary_upload: true
116
+ )
117
+
118
+ UI.success "Current screenshots downloaded to ./screenshots_backup/"
119
+ end
120
+
121
+ # Alternative upload method using staging to handle nested directories
122
+ # Use this if the standard upload fails with nested directories
123
+ desc "Upload screenshots using staging approach (handles nested dirs)"
124
+ lane :upload_screenshots_staged do
125
+ require 'fileutils'
126
+
127
+ UI.message "Preparing screenshots with staging approach..."
128
+
129
+ source_root = File.expand_path("screenshots", __dir__)
130
+ staging_root = File.expand_path("screenshots_staging", __dir__)
131
+
132
+ # Clean staging directory
133
+ FileUtils.rm_rf(staging_root)
134
+ FileUtils.mkdir_p(staging_root)
135
+
136
+ # Process each language directory
137
+ Dir.glob(File.join(source_root, "*")).each do |language_dir|
138
+ next unless File.directory?(language_dir)
139
+
140
+ language = File.basename(language_dir)
141
+ dest_language_dir = File.join(staging_root, language)
142
+ FileUtils.mkdir_p(dest_language_dir)
143
+
144
+ # Flatten nested structure (device/screenshot.png -> device__screenshot.png)
145
+ Dir.glob(File.join(language_dir, '**', '*.{png,jpg,jpeg}')).each do |image_path|
146
+ rel = Pathname.new(image_path).relative_path_from(Pathname.new(language_dir)).to_s
147
+
148
+ # Replace directory separators with double underscores
149
+ sanitized = rel.gsub(File::SEPARATOR, '__')
150
+
151
+ FileUtils.cp(image_path, File.join(dest_language_dir, sanitized))
152
+ end
153
+ end
154
+
155
+ UI.message "Uploading screenshots from staging directory..."
156
+
157
+ deliver(
158
+ screenshots_path: staging_root,
159
+ overwrite_screenshots: true,
160
+ skip_metadata: true,
161
+ skip_binary_upload: true,
162
+ force: true
163
+ )
164
+
165
+ # Clean up staging
166
+ FileUtils.rm_rf(staging_root)
167
+
168
+ UI.success "Screenshots uploaded successfully using staging approach!"
169
+ end
170
+
171
+ # Helper lane to set up App Store Connect API authentication
172
+ desc "Configure App Store Connect API authentication"
173
+ private_lane :setup_app_store_connect_api do
174
+ app_store_connect_api_key(
175
+ key_id: ENV["APP_STORE_CONNECT_KEY_ID"],
176
+ issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"],
177
+ key_filepath: ENV["APP_STORE_CONNECT_KEY_FILEPATH"] || "./AuthKey.p8",
178
+
179
+ # Optional parameters
180
+ duration: 1200, # 20 minutes (max allowed)
181
+ in_house: false # Set to true for Enterprise accounts
182
+ )
183
+ end
184
+ `;
185
+ }
186
+ /**
187
+ * Generate a README for Fastlane integration
188
+ */
189
+ export function generateFastlaneReadme(languages) {
190
+ return `# Fastlane Integration for AppShot
191
+
192
+ This directory contains the Fastlane configuration for uploading screenshots generated by AppShot to App Store Connect.
193
+
194
+ ## Setup
195
+
196
+ ### 1. Install Fastlane
197
+
198
+ \`\`\`bash
199
+ # Using RubyGems
200
+ gem install fastlane
201
+
202
+ # Or using Homebrew (macOS)
203
+ brew install fastlane
204
+ \`\`\`
205
+
206
+ ### 2. App Store Connect API Key
207
+
208
+ 1. Go to [App Store Connect](https://appstoreconnect.apple.com)
209
+ 2. Navigate to Users and Access → Keys
210
+ 3. Create a new API key with "App Manager" role
211
+ 4. Download the .p8 key file (can only be downloaded once!)
212
+ 5. Note your Issuer ID and Key ID
213
+
214
+ ### 3. Configure Authentication
215
+
216
+ Set environment variables in your shell profile or CI/CD:
217
+
218
+ \`\`\`bash
219
+ export APP_STORE_CONNECT_KEY_ID="YOUR_KEY_ID"
220
+ export APP_STORE_CONNECT_ISSUER_ID="YOUR_ISSUER_ID"
221
+ export APP_STORE_CONNECT_KEY_FILEPATH="./AuthKey.p8"
222
+ \`\`\`
223
+
224
+ Or add to \`Deliverfile\`:
225
+
226
+ \`\`\`ruby
227
+ app_store_connect_api_key(
228
+ key_id: "YOUR_KEY_ID",
229
+ issuer_id: "YOUR_ISSUER_ID",
230
+ key_filepath: "./AuthKey.p8"
231
+ )
232
+ \`\`\`
233
+
234
+ ## Usage
235
+
236
+ ### Generate and Upload Screenshots
237
+
238
+ \`\`\`bash
239
+ # Full workflow
240
+ fastlane screenshots
241
+
242
+ # Generate only (no upload)
243
+ fastlane generate_screenshots
244
+
245
+ # Validate before upload
246
+ fastlane validate_screenshots
247
+
248
+ # Download existing screenshots
249
+ fastlane download_screenshots
250
+ \`\`\`
251
+
252
+ ### Manual Steps
253
+
254
+ \`\`\`bash
255
+ # 1. Generate screenshots with AppShot
256
+ appshot build --preset iphone-6-9,ipad-13
257
+
258
+ # 2. Export for Fastlane
259
+ appshot export fastlane --clean
260
+
261
+ # 3. Upload to App Store Connect
262
+ fastlane deliver
263
+ \`\`\`
264
+
265
+ ## Supported Languages
266
+
267
+ The following languages are configured for upload:
268
+ ${languages.map(l => `- ${l}`).join('\n')}
269
+
270
+ ## Directory Structure
271
+
272
+ \`\`\`
273
+ fastlane/
274
+ ├── Deliverfile # Delivery configuration
275
+ ├── Fastfile # Lane definitions
276
+ ├── README.md # This file
277
+ └── screenshots/ # Exported screenshots
278
+ ├── ${languages[0] || 'en-US'}/
279
+ │ ├── iPhone_*.png
280
+ │ ├── iPad_*.png
281
+ │ └── ...
282
+ └── ${languages[1] || 'es-ES'}/
283
+ └── ...
284
+ \`\`\`
285
+
286
+ ## Troubleshooting
287
+
288
+ ### Missing Screenshots
289
+ - Ensure \`appshot build\` completed successfully
290
+ - Check that \`appshot export\` created the screenshots directory
291
+ - Verify language codes match App Store Connect settings
292
+
293
+ ### Authentication Errors
294
+ - Verify API key permissions (needs "App Manager" role)
295
+ - Check key file path is correct
296
+ - Ensure key hasn't expired
297
+
298
+ ### Upload Failures
299
+ - Verify image dimensions match App Store requirements
300
+ - Check that all required device types are present
301
+ - Ensure network connectivity to App Store Connect
302
+
303
+ ## Additional Resources
304
+
305
+ - [Fastlane Documentation](https://docs.fastlane.tools)
306
+ - [App Store Screenshot Specifications](https://developer.apple.com/help/app-store-connect/reference/screenshot-specifications)
307
+ - [AppShot Documentation](https://github.com/chrisvanbuskirk/appshot)
308
+ `;
309
+ }
310
+ /**
311
+ * Generate a .gitignore for Fastlane directory
312
+ */
313
+ export function generateFastlaneGitignore() {
314
+ return `# Fastlane
315
+ report.xml
316
+ Preview.html
317
+ screenshots/
318
+ screenshots_backup/
319
+
320
+ # App Store Connect API Keys
321
+ *.p8
322
+ AuthKey_*.p8
323
+
324
+ # Environment variables
325
+ .env
326
+ .env.local
327
+
328
+ # Temporary files
329
+ *.tmp
330
+ .DS_Store
331
+ Thumbs.db
332
+
333
+ # Build artifacts
334
+ build/
335
+ DerivedData/
336
+
337
+ # Fastlane specific
338
+ fastlane/report.xml
339
+ fastlane/Preview.html
340
+ fastlane/test_output/
341
+ `;
342
+ }
343
+ //# sourceMappingURL=fastlane-config-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastlane-config-generator.js","sourceRoot":"","sources":["../../src/services/fastlane-config-generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAmB,EACnB,kBAA0B,eAAe;IAEzC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,OAAO;IACL,SAAS;;;oBAGO,eAAe;;;;;IAK/B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAwB7C,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2IR,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAmB;IACxD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8EP,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;UAU/B,SAAS,CAAC,CAAC,CAAC,IAAI,OAAO;;;;UAIvB,SAAS,CAAC,CAAC,CAAC,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BhC,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BR,CAAC;AACF,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Fastlane-supported language codes
3
+ * Source: https://docs.fastlane.tools/actions/deliver/
4
+ */
5
+ export declare const FASTLANE_LANGUAGES: Set<string>;
6
+ /**
7
+ * Default language code mappings from appshot to Fastlane
8
+ */
9
+ export declare const DEFAULT_MAPPINGS: Record<string, string>;
10
+ export interface LanguageMappingConfig {
11
+ languageMappings?: Record<string, string>;
12
+ }
13
+ /**
14
+ * Load user-defined language mappings from config file
15
+ */
16
+ export declare function loadUserMappings(configPath?: string): Promise<Record<string, string> | undefined>;
17
+ /**
18
+ * Map a language code to Fastlane-compatible format
19
+ */
20
+ export declare function mapToFastlaneCode(lang: string, userMappings?: Record<string, string>): string;
21
+ /**
22
+ * Validate if a language code is supported by Fastlane
23
+ */
24
+ export declare function isValidFastlaneCode(code: string): boolean;
25
+ /**
26
+ * Get all supported Fastlane language codes
27
+ */
28
+ export declare function getSupportedLanguages(): string[];
29
+ /**
30
+ * Map multiple language codes with validation
31
+ */
32
+ export declare function mapLanguages(languages: string[], configPath?: string): Promise<Map<string, string>>;
33
+ //# sourceMappingURL=fastlane-language-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastlane-language-mapper.d.ts","sourceRoot":"","sources":["../../src/services/fastlane-language-mapper.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,kBAAkB,aAM7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6DnD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAYvG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAuD7F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAU9B"}
@@ -0,0 +1,167 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * Fastlane-supported language codes
5
+ * Source: https://docs.fastlane.tools/actions/deliver/
6
+ */
7
+ export const FASTLANE_LANGUAGES = new Set([
8
+ 'da', 'de-DE', 'el', 'en-AU', 'en-CA', 'en-GB', 'en-US',
9
+ 'es-ES', 'es-MX', 'fi', 'fr-CA', 'fr-FR', 'id', 'it', 'ja',
10
+ 'ko', 'ms', 'nl-NL', 'no', 'pt-BR', 'pt-PT', 'ru', 'sv',
11
+ 'th', 'tr', 'vi', 'zh-Hans', 'zh-Hant', 'hi', 'hr', 'hu',
12
+ 'pl', 'ro', 'sk', 'uk', 'ca', 'cs', 'he'
13
+ ]);
14
+ /**
15
+ * Default language code mappings from appshot to Fastlane
16
+ */
17
+ export const DEFAULT_MAPPINGS = {
18
+ // Common two-letter codes
19
+ 'en': 'en-US',
20
+ 'es': 'es-ES',
21
+ 'fr': 'fr-FR',
22
+ 'de': 'de-DE',
23
+ 'pt': 'pt-PT',
24
+ 'nl': 'nl-NL',
25
+ 'it': 'it',
26
+ 'ja': 'ja',
27
+ 'ko': 'ko',
28
+ 'ru': 'ru',
29
+ 'da': 'da',
30
+ 'fi': 'fi',
31
+ 'no': 'no',
32
+ 'sv': 'sv',
33
+ 'pl': 'pl',
34
+ 'tr': 'tr',
35
+ 'th': 'th',
36
+ 'vi': 'vi',
37
+ 'id': 'id',
38
+ 'ms': 'ms',
39
+ 'el': 'el',
40
+ 'hi': 'hi',
41
+ 'hr': 'hr',
42
+ 'hu': 'hu',
43
+ 'ro': 'ro',
44
+ 'sk': 'sk',
45
+ 'uk': 'uk',
46
+ 'ca': 'ca',
47
+ 'cs': 'cs',
48
+ 'he': 'he',
49
+ // Chinese variants
50
+ 'zh': 'zh-Hans',
51
+ 'zh-cn': 'zh-Hans',
52
+ 'zh-hans': 'zh-Hans',
53
+ 'zh-tw': 'zh-Hant',
54
+ 'zh-hant': 'zh-Hant',
55
+ 'zh-hk': 'zh-Hant',
56
+ // Regional variants
57
+ 'en-gb': 'en-GB',
58
+ 'en-au': 'en-AU',
59
+ 'en-ca': 'en-CA',
60
+ 'es-mx': 'es-MX',
61
+ 'fr-ca': 'fr-CA',
62
+ 'pt-br': 'pt-BR',
63
+ // Alternative codes
64
+ 'english': 'en-US',
65
+ 'spanish': 'es-ES',
66
+ 'french': 'fr-FR',
67
+ 'german': 'de-DE',
68
+ 'portuguese': 'pt-PT',
69
+ 'chinese': 'zh-Hans',
70
+ 'dutch': 'nl-NL',
71
+ 'italian': 'it',
72
+ 'japanese': 'ja',
73
+ 'korean': 'ko',
74
+ 'russian': 'ru'
75
+ };
76
+ /**
77
+ * Load user-defined language mappings from config file
78
+ */
79
+ export async function loadUserMappings(configPath) {
80
+ const defaultPath = path.join(process.cwd(), '.appshot', 'export-config.json');
81
+ const targetPath = configPath || defaultPath;
82
+ try {
83
+ const content = await fs.readFile(targetPath, 'utf-8');
84
+ const config = JSON.parse(content);
85
+ return config.languageMappings;
86
+ }
87
+ catch {
88
+ // Config file is optional
89
+ return undefined;
90
+ }
91
+ }
92
+ /**
93
+ * Map a language code to Fastlane-compatible format
94
+ */
95
+ export function mapToFastlaneCode(lang, userMappings) {
96
+ const normalized = lang.toLowerCase();
97
+ // Priority 1: User-defined mapping
98
+ if (userMappings?.[normalized]) {
99
+ return userMappings[normalized];
100
+ }
101
+ // Priority 2: Already a valid Fastlane code (case-sensitive check)
102
+ if (FASTLANE_LANGUAGES.has(lang)) {
103
+ return lang;
104
+ }
105
+ // Check with normalized case for region codes
106
+ const withRegion = lang.match(/^([a-z]{2,3})-([A-Z]{2,4})$/i);
107
+ if (withRegion) {
108
+ const formatted = `${withRegion[1].toLowerCase()}-${withRegion[2].toUpperCase()}`;
109
+ if (FASTLANE_LANGUAGES.has(formatted)) {
110
+ return formatted;
111
+ }
112
+ }
113
+ // Priority 3: Default mapping
114
+ const mapped = DEFAULT_MAPPINGS[normalized];
115
+ if (mapped) {
116
+ return mapped;
117
+ }
118
+ // Priority 4: Try to construct valid code for two-letter codes
119
+ if (normalized.match(/^[a-z]{2}$/)) {
120
+ // Common region mappings
121
+ const commonRegions = {
122
+ 'en': 'US',
123
+ 'es': 'ES',
124
+ 'fr': 'FR',
125
+ 'de': 'DE',
126
+ 'pt': 'PT',
127
+ 'zh': 'Hans',
128
+ 'nl': 'NL'
129
+ };
130
+ const region = commonRegions[normalized];
131
+ if (region) {
132
+ const constructed = region === 'Hans' || region === 'Hant'
133
+ ? `zh-${region}`
134
+ : `${normalized}-${region}`;
135
+ if (FASTLANE_LANGUAGES.has(constructed)) {
136
+ return constructed;
137
+ }
138
+ }
139
+ }
140
+ // Priority 5: Return as-is (may not be valid for Fastlane)
141
+ return lang;
142
+ }
143
+ /**
144
+ * Validate if a language code is supported by Fastlane
145
+ */
146
+ export function isValidFastlaneCode(code) {
147
+ return FASTLANE_LANGUAGES.has(code);
148
+ }
149
+ /**
150
+ * Get all supported Fastlane language codes
151
+ */
152
+ export function getSupportedLanguages() {
153
+ return Array.from(FASTLANE_LANGUAGES).sort();
154
+ }
155
+ /**
156
+ * Map multiple language codes with validation
157
+ */
158
+ export async function mapLanguages(languages, configPath) {
159
+ const userMappings = await loadUserMappings(configPath);
160
+ const mapped = new Map();
161
+ for (const lang of languages) {
162
+ const fastlaneCode = mapToFastlaneCode(lang, userMappings);
163
+ mapped.set(lang, fastlaneCode);
164
+ }
165
+ return mapped;
166
+ }
167
+ //# sourceMappingURL=fastlane-language-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fastlane-language-mapper.js","sourceRoot":"","sources":["../../src/services/fastlane-language-mapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ export interface ScreenshotOrder {
2
+ iphone?: string[];
3
+ ipad?: string[];
4
+ mac?: string[];
5
+ watch?: string[];
6
+ }
7
+ export interface OrderConfig {
8
+ version: string;
9
+ orders: ScreenshotOrder;
10
+ created: string;
11
+ modified: string;
12
+ }
13
+ /**
14
+ * Load screenshot order configuration
15
+ */
16
+ export declare function loadOrderConfig(projectPath?: string): Promise<OrderConfig | null>;
17
+ /**
18
+ * Save screenshot order configuration
19
+ */
20
+ export declare function saveOrderConfig(orders: ScreenshotOrder, projectPath?: string): Promise<void>;
21
+ /**
22
+ * Apply ordering to screenshots based on saved configuration
23
+ */
24
+ export declare function applyOrder(screenshots: string[], device: string, orderConfig: OrderConfig | null): string[];
25
+ /**
26
+ * Get available screenshots for a device
27
+ */
28
+ export declare function getAvailableScreenshots(device: string, sourcePath?: string, language?: string): Promise<string[]>;
29
+ /**
30
+ * Add numeric prefixes to filenames based on order
31
+ */
32
+ export declare function addNumericPrefixes(filenames: string[], startFrom?: number): string[];
33
+ /**
34
+ * Remove numeric prefixes from filenames
35
+ */
36
+ export declare function removeNumericPrefixes(filenames: string[]): string[];
37
+ /**
38
+ * Display current order for review
39
+ */
40
+ export declare function displayOrder(screenshots: string[], device: string): void;
41
+ //# sourceMappingURL=screenshot-order.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot-order.d.ts","sourceRoot":"","sources":["../../src/services/screenshot-order.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAKD;;GAEG;AACH,wBAAsB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAYvF;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,eAAe,EACvB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,MAAM,EAAE,CAuCV;AAqGD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAa,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAYnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,MAAU,GAAG,MAAM,EAAE,CAWvF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAMxE"}