appshot-cli 0.8.7 → 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.
- package/README.md +784 -15
- package/dist/cli.js +24 -5
- package/dist/cli.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +16 -2
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +382 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/order.d.ts +3 -0
- package/dist/commands/order.d.ts.map +1 -0
- package/dist/commands/order.js +321 -0
- package/dist/commands/order.js.map +1 -0
- package/dist/commands/preset.d.ts +5 -0
- package/dist/commands/preset.d.ts.map +1 -0
- package/dist/commands/preset.js +191 -0
- package/dist/commands/preset.js.map +1 -0
- package/dist/commands/quickstart.d.ts +3 -0
- package/dist/commands/quickstart.d.ts.map +1 -0
- package/dist/commands/quickstart.js +326 -0
- package/dist/commands/quickstart.js.map +1 -0
- package/dist/commands/style.d.ts.map +1 -1
- package/dist/commands/style.js +98 -0
- package/dist/commands/style.js.map +1 -1
- package/dist/commands/template.d.ts +3 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +399 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/core/compose.d.ts +16 -0
- package/dist/core/compose.d.ts.map +1 -1
- package/dist/core/compose.js +342 -83
- package/dist/core/compose.js.map +1 -1
- package/dist/services/doctor.js +1 -1
- package/dist/services/export-validator.d.ts +23 -0
- package/dist/services/export-validator.d.ts.map +1 -0
- package/dist/services/export-validator.js +209 -0
- package/dist/services/export-validator.js.map +1 -0
- package/dist/services/fastlane-config-generator.d.ts +17 -0
- package/dist/services/fastlane-config-generator.d.ts.map +1 -0
- package/dist/services/fastlane-config-generator.js +343 -0
- package/dist/services/fastlane-config-generator.js.map +1 -0
- package/dist/services/fastlane-language-mapper.d.ts +33 -0
- package/dist/services/fastlane-language-mapper.d.ts.map +1 -0
- package/dist/services/fastlane-language-mapper.js +167 -0
- package/dist/services/fastlane-language-mapper.js.map +1 -0
- package/dist/services/screenshot-order.d.ts +41 -0
- package/dist/services/screenshot-order.d.ts.map +1 -0
- package/dist/services/screenshot-order.js +211 -0
- package/dist/services/screenshot-order.js.map +1 -0
- package/dist/services/screenshot-organizer.d.ts +44 -0
- package/dist/services/screenshot-organizer.d.ts.map +1 -0
- package/dist/services/screenshot-organizer.js +234 -0
- package/dist/services/screenshot-organizer.js.map +1 -0
- package/dist/templates/registry.d.ts +73 -0
- package/dist/templates/registry.d.ts.map +1 -0
- package/dist/templates/registry.js +724 -0
- package/dist/templates/registry.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/validation.d.ts +36 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +143 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +3 -2
|
@@ -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"}
|