codeplay-common 1.5.1 → 1.5.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.
@@ -1,672 +1,673 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const plist = require('plist');
4
-
5
-
6
- // Expected plugin list with minimum versions
7
- const requiredPlugins = [
8
- { pattern: /backbutton-(\d+\.\d+)\.js$/, minVersion: '1.1', required: true },
9
- { pattern: /common-(\d+\.\d+)\.js$/, minVersion: '3.4', required: true },
10
- { pattern: /localization_settings-(\d+\.\d+)\.js$/, minVersion: '1.1', required: true },
11
- { pattern: /localization-(\d+\.\d+)\.js$/, minVersion: '1.2', required: true },
12
- { pattern: /localNotification-(\d+\.\d+)\.js$/, minVersion: '2.2', required: true },
13
- { pattern: /localNotification_AppSettings-(\d+\.\d+)\.js$/, minVersion: '1.0', required: true },
14
- { pattern: /onesignal-(\d+\.\d+)\.js$/, minVersion: '2.1', required: true },
15
- { pattern: /saveToGalleryAndSaveAnyFile-(\d+\.\d+)(-ios)?\.js$/, minVersion: '2.3', required: true },
16
- { pattern: /Ads[\/\\]IAP-(\d+\.\d+)$/, minVersion: '2.1', isFolder: true },
17
- { pattern: /Ads[\/\\]admob-emi-(\d+\.\d+)\.js$/, minVersion: '2.6', required: true }
18
- ];
19
-
20
-
21
-
22
-
23
-
24
-
25
- //Check codeplay-common latest version installed or not Start
26
- const { execSync } = require('child_process');
27
-
28
- function getInstalledVersion(packageName) {
29
- try {
30
- const packageJsonPath = path.join(process.cwd(), 'node_modules', packageName, 'package.json');
31
- if (fs.existsSync(packageJsonPath)) {
32
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
33
- return packageJson.version;
34
- }
35
- } catch (error) {
36
- return null;
37
- }
38
- return null;
39
- }
40
-
41
- function getLatestVersion(packageName) {
42
- try {
43
- return execSync(`npm view ${packageName} version`).toString().trim();
44
- } catch (error) {
45
- console.error(`Failed to fetch latest version for ${packageName}`);
46
- return null;
47
- }
48
- }
49
-
50
- function checkPackageVersion() {
51
- const packageName = 'codeplay-common';
52
- const installedVersion = getInstalledVersion(packageName);
53
- const latestVersion = getLatestVersion(packageName);
54
-
55
- if (!installedVersion) {
56
- console.error(`${packageName} is not installed. Please install it using "npm install ${packageName}".`);
57
- process.exit(1);
58
- }
59
-
60
- if (installedVersion !== latestVersion) {
61
- console.error(`\x1b[31m${packageName} is outdated (installed: ${installedVersion}, latest: ${latestVersion}). Please update it.\x1b[0m\n\x1b[33mUse 'npm uninstall codeplay-common ; npm i codeplay-common'\x1b[0m`);
62
- process.exit(1);
63
- }
64
-
65
- console.log(`${packageName} is up to date (version ${installedVersion}).`);
66
- }
67
-
68
- // Run package version check before executing the main script
69
- try {
70
- checkPackageVersion();
71
- } catch (error) {
72
- console.error(error.message);
73
- process.exit(1);
74
- }
75
-
76
- //Check codeplay-common latest version installed or not END
77
-
78
-
79
-
80
-
81
-
82
-
83
- // saveToGalleryAndSaveAnyFile-x.x-ios.js file check for android and return error if exists START
84
-
85
- const os = require('os');
86
-
87
- const saveToGalleryAndSaveFileCheck_iOS = () => {
88
- const ROOT_DIR = path.resolve(__dirname, '../src');
89
-
90
- const IOS_FILE_REGEX = /(?:import|require)?\s*\(?['"].*saveToGalleryAndSaveAnyFile-\d+(\.\d+)?-ios\.js['"]\)?/;
91
- const ALLOWED_EXTENSIONS = ['.js', '.f7'];
92
- const isMac = os.platform() === 'darwin';
93
-
94
- let iosImportFound = false;
95
-
96
- function scanDirectory(dir) {
97
- const entries = fs.readdirSync(dir, { withFileTypes: true });
98
-
99
- for (let entry of entries) {
100
- const fullPath = path.join(dir, entry.name);
101
-
102
- if (entry.isDirectory()) {
103
- if (entry.name === 'node_modules') continue;
104
- scanDirectory(fullPath);
105
- } else if (
106
- entry.isFile() &&
107
- ALLOWED_EXTENSIONS.some(ext => fullPath.endsWith(ext))
108
- ) {
109
- const content = fs.readFileSync(fullPath, 'utf8');
110
- const matches = content.match(IOS_FILE_REGEX);
111
- if (matches) {
112
- iosImportFound = true;
113
- console.error(`\n❌❌❌ BIG ERROR: iOS-specific import detected in: ${fullPath}`);
114
- console.error(`🔍 Matched: ${matches[0]}\n`);
115
- if (!isMac) {
116
- console.error(`🚫 STOPPED: This file should not be imported in Android/Windows/Linux builds.\n`);
117
- process.exit(1);
118
- }
119
- }
120
- }
121
- }
122
- }
123
-
124
- // Check if src folder exists first
125
- if (!fs.existsSync(ROOT_DIR)) {
126
- console.warn(`⚠️ Warning: 'src' directory not found at: ${ROOT_DIR}`);
127
- return;
128
- }
129
-
130
- scanDirectory(ROOT_DIR);
131
-
132
- if (isMac && !iosImportFound) {
133
- console.warn(`\x1b[31m\n⚠️⚠️⚠️ WARNING: You're on macOS but no iOS-specific file (saveToGalleryAndSaveAnyFile-x.x-ios.js) was found.\x1b[0m`);
134
- console.warn(`👉 You may want to double-check your imports for the iOS platform.\n`);
135
- } else if (isMac && iosImportFound) {
136
- console.log('✅ iOS file detected as expected for macOS.');
137
- } else if (!iosImportFound) {
138
- console.log('✅ No iOS-specific file imports detected for non-macOS.');
139
- }
140
- };
141
-
142
- saveToGalleryAndSaveFileCheck_iOS();
143
- // saveToGalleryAndSaveAnyFile-x.x-ios.js file check for android and return error if exists END
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
- /*
158
- // Clean up AppleDouble files (._*) created by macOS START
159
- if (process.platform === 'darwin') {
160
- try {
161
- console.log('🧹 Cleaning up AppleDouble files (._*)...');
162
- execSync(`find . -name '._*' -delete`);
163
- console.log('✅ AppleDouble files removed.');
164
- } catch (err) {
165
- console.warn('⚠️ Failed to remove AppleDouble files:', err.message);
166
- }
167
- } else {
168
- console.log('ℹ️ Skipping AppleDouble cleanup — not a macOS machine.');
169
- }
170
-
171
- // Clean up AppleDouble files (._*) created by macOS END
172
- */
173
-
174
-
175
-
176
-
177
-
178
-
179
- //In routes.js file check static import START
180
-
181
- const routesPath = path.join(process.cwd(), 'src', 'js', 'routes.js');
182
- const routesContent = fs.readFileSync(routesPath, 'utf-8');
183
-
184
- let inBlockComment = false;
185
- const lines = routesContent.split('\n');
186
-
187
- const allowedImport = `import HomePage from '../pages/home.f7';`;
188
- const badImportRegex = /^[ \t]*import\s+[\w{}*,\s]*\s+from\s+['"].+\.f7['"]\s*;/;
189
- const badImports = [];
190
-
191
- lines.forEach((line, index) => {
192
- const trimmed = line.trim();
193
-
194
- // Handle block comment start and end
195
- if (trimmed.startsWith('/*')) inBlockComment = true;
196
- if (inBlockComment && trimmed.endsWith('*/')) {
197
- inBlockComment = false;
198
- return;
199
- }
200
-
201
- // Skip if inside block comment or line comment
202
- if (inBlockComment || trimmed.startsWith('//')) return;
203
-
204
- // Match static .f7 import
205
- if (badImportRegex.test(trimmed) && trimmed !== allowedImport) {
206
- badImports.push({ line: trimmed, number: index + 1 });
207
- }
208
- });
209
-
210
- if (badImports.length > 0) {
211
- console.error('\n❌ ERROR: Detected disallowed static imports of .f7 files in routes.js\n');
212
- console.error(`⚠️ Only this static import is allowed:\n ${allowedImport}\n`);
213
- console.error(`🔧 Please convert other imports to async dynamic imports like this:\n`);
214
- console.error(`
215
-
216
- import HomePage from '../pages/home.f7';
217
-
218
- const routes = [
219
- {
220
- path: '/',
221
- component:HomePage,
222
- },
223
- {
224
- path: '/ProfilePage/',
225
- async async({ resolve }) {
226
- const page = await import('../pages/profile.f7');
227
- resolve({ component: page.default });
228
- },
229
- }]
230
- `);
231
-
232
- badImports.forEach(({ line, number }) => {
233
- console.error(`${number}: ${line}`);
234
- });
235
-
236
- process.exit(1);
237
- } else {
238
- console.log('✅ routes.js passed the .f7 import check.');
239
- }
240
-
241
- //In routes.js file check static import END
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
- // Check and change the "BridgeWebViewClient.java" file START
256
- /*
257
- For crash issue due to low memory problem, we need to modify the onRenderProcessGone method in BridgeWebViewClient.java.
258
- */
259
-
260
-
261
- const bridgeWebViewClientFilePath = path.join(process.cwd(), 'node_modules', '@capacitor/android/capacitor/src/main/java/com/getcapacitor', 'BridgeWebViewClient.java');
262
-
263
- // Read the file
264
- if (!fs.existsSync(bridgeWebViewClientFilePath)) {
265
- console.error('❌ Error: BridgeWebViewClient.java not found.');
266
- process.exit(1);
267
- }
268
-
269
- let fileContent = fs.readFileSync(bridgeWebViewClientFilePath, 'utf8');
270
-
271
- // Define old and new code
272
- const oldCodeStart = `@Override
273
- public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
274
- super.onRenderProcessGone(view, detail);
275
- boolean result = false;
276
-
277
- List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
278
- if (webViewListeners != null) {
279
- for (WebViewListener listener : bridge.getWebViewListeners()) {
280
- result = listener.onRenderProcessGone(view, detail) || result;
281
- }
282
- }
283
-
284
- return result;
285
- }`;
286
-
287
- const newCode = `@Override
288
- public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
289
- super.onRenderProcessGone(view, detail);
290
-
291
- boolean result = false;
292
-
293
- List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
294
- if (webViewListeners != null) {
295
- for (WebViewListener listener : bridge.getWebViewListeners()) {
296
- result = listener.onRenderProcessGone(view, detail) || result;
297
- }
298
- }
299
-
300
- if (!result) {
301
- // If no one handled it, handle it ourselves!
302
-
303
- /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
304
- if (detail.didCrash()) {
305
- //Log.e("CapacitorWebView", "WebView crashed internally!");
306
- } else {
307
- //Log.w("CapacitorWebView", "WebView was killed by system (low memory) internally!");
308
- }
309
- }*/
310
-
311
- view.post(() -> {
312
- Toast.makeText(view.getContext(), "Reloading due to low memory issue", Toast.LENGTH_SHORT).show();
313
- });
314
-
315
- view.reload(); // Safely reload WebView
316
-
317
- return true; // We handled it
318
- }
319
-
320
- return result;
321
- }`;
322
-
323
- // Step 1: Update method if needed
324
- let updated = false;
325
-
326
- if (fileContent.includes(oldCodeStart)) {
327
- console.log('✅ Found old onRenderProcessGone method. Replacing it...');
328
- fileContent = fileContent.replace(oldCodeStart, newCode);
329
- updated = true;
330
- } else if (fileContent.includes(newCode)) {
331
- console.log('ℹ️ Method already updated. No changes needed in "BridgeWebViewClient.java".');
332
- } else {
333
- console.error('❌ Error: Neither old nor new code found. Unexpected content.');
334
- process.exit(1);
335
- }
336
-
337
- // Step 2: Check and add import if missing
338
- const importToast = 'import android.widget.Toast;';
339
- if (!fileContent.includes(importToast)) {
340
- console.log('✅ Adding missing import for Toast...');
341
- const importRegex = /import\s+[^;]+;/g;
342
- const matches = [...fileContent.matchAll(importRegex)];
343
-
344
- if (matches.length > 0) {
345
- const lastImport = matches[matches.length - 1];
346
- const insertPosition = lastImport.index + lastImport[0].length;
347
- fileContent = fileContent.slice(0, insertPosition) + `\n${importToast}` + fileContent.slice(insertPosition);
348
- updated = true;
349
- } else {
350
- console.error('❌ Error: No import section found in file.');
351
- process.exit(1);
352
- }
353
- } else {
354
- console.log('ℹ️ Import for Toast already exists. No changes needed.');
355
- }
356
-
357
- // Step 3: Save if updated
358
- if (updated) {
359
- fs.writeFileSync(bridgeWebViewClientFilePath, fileContent, 'utf8');
360
- console.log('✅ File updated successfully.');
361
- } else {
362
- console.log('ℹ️ No changes needed.');
363
- }
364
-
365
-
366
-
367
-
368
- // Check and change the "BridgeWebViewClient.java" file END
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
- // To resolve the kotlin version issue, we need to update the kotlin version in the build.gradle file START
379
-
380
- // Build the path dynamically like you requested
381
- const gradlePath = path.join(
382
- process.cwd(),
383
- 'android',
384
- 'build.gradle'
385
- );
386
-
387
- // Read the existing build.gradle
388
- let gradleContent = fs.readFileSync(gradlePath, 'utf8');
389
-
390
- // Add `ext.kotlin_version` if it's not already there
391
- if (!gradleContent.includes('ext.kotlin_version')) {
392
- gradleContent = gradleContent.replace(
393
- /buildscript\s*{/,
394
- `buildscript {\n ext.kotlin_version = '2.1.0'`
395
- );
396
- }
397
-
398
- // Add Kotlin classpath if it's not already there
399
- if (!gradleContent.includes('org.jetbrains.kotlin:kotlin-gradle-plugin')) {
400
- gradleContent = gradleContent.replace(
401
- /dependencies\s*{([\s\S]*?)classpath 'com.android.tools.build:gradle:8.7.2'/,
402
- `dependencies {\n classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")\n$1classpath 'com.android.tools.build:gradle:8.7.2'`
403
- );
404
- }
405
-
406
- // Write back the modified content
407
- fs.writeFileSync(gradlePath, gradleContent, 'utf8');
408
-
409
- console.log('✅ Kotlin version updated in build.gradle.');
410
-
411
- // To resolve the kotlin version issue, we need to update the kotlin version in the build.gradle file END
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
- const configPath = path.join(process.cwd(), 'capacitor.config.json');
423
- const androidPlatformPath = path.join(process.cwd(), 'android');
424
- const iosPlatformPath = path.join(process.cwd(), 'ios');
425
- const pluginPath = path.join(process.cwd(), 'node_modules', 'emi-indo-cordova-plugin-admob', 'plugin.xml');
426
- const infoPlistPath = path.join(process.cwd(), 'ios', 'App', 'App', 'Info.plist');
427
- const resourcesPath = path.join(process.cwd(), 'resources', 'res');
428
- const androidResPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'res');
429
- const localNotificationsPluginPath = path.join(process.cwd(), 'node_modules', '@capacitor', 'local-notifications');
430
-
431
- function fileExists(filePath) {
432
- return fs.existsSync(filePath);
433
- }
434
-
435
- function copyFolderSync(source, target) {
436
- if (!fs.existsSync(target)) {
437
- fs.mkdirSync(target, { recursive: true });
438
- }
439
-
440
- fs.readdirSync(source).forEach(file => {
441
- const sourceFile = path.join(source, file);
442
- const targetFile = path.join(target, file);
443
-
444
- if (fs.lstatSync(sourceFile).isDirectory()) {
445
- copyFolderSync(sourceFile, targetFile);
446
- } else {
447
- fs.copyFileSync(sourceFile, targetFile);
448
- }
449
- });
450
- }
451
-
452
- function checkAndCopyResources() {
453
- if (fileExists(resourcesPath)) {
454
- copyFolderSync(resourcesPath, androidResPath);
455
- console.log('✅ Successfully copied resources/res to android/app/src/main/res.');
456
- } else {
457
- console.log('resources/res folder not found.');
458
-
459
- if (fileExists(localNotificationsPluginPath)) {
460
- throw new Error('❌ resources/res is required for @capacitor/local-notifications. Stopping execution.');
461
- }
462
- }
463
- }
464
-
465
-
466
-
467
- function getAdMobConfig() {
468
- if (!fileExists(configPath)) {
469
- throw new Error('❌ capacitor.config.json not found. Ensure this is a Capacitor project.');
470
- }
471
-
472
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
473
- const admobConfig = config.plugins?.AdMob;
474
-
475
- if (!admobConfig) {
476
- throw new Error('❌ AdMob configuration is missing in capacitor.config.json.');
477
- }
478
-
479
- // Default to true if ADMOB_ENABLED is not specified
480
- const isEnabled = admobConfig.ADMOB_ENABLED !== false;
481
-
482
- if (!isEnabled) {
483
- return { ADMOB_ENABLED: false }; // Skip further validation
484
- }
485
-
486
- if (!admobConfig.APP_ID_ANDROID || !admobConfig.APP_ID_IOS) {
487
- throw new Error(' ❌ AdMob configuration is incomplete. Ensure APP_ID_ANDROID and APP_ID_IOS are defined.');
488
- }
489
-
490
- return {
491
- ADMOB_ENABLED: true,
492
- APP_ID_ANDROID: admobConfig.APP_ID_ANDROID,
493
- APP_ID_IOS: admobConfig.APP_ID_IOS,
494
- USE_LITE_ADS: admobConfig.USE_LITE_ADS === "lite",
495
- };
496
- }
497
-
498
- function updatePluginXml(admobConfig) {
499
- if (!fileExists(pluginPath)) {
500
- console.error(' ❌ plugin.xml not found. Ensure the plugin is installed.');
501
- return;
502
- }
503
-
504
- let pluginContent = fs.readFileSync(pluginPath, 'utf8');
505
-
506
- pluginContent = pluginContent
507
- .replace(/<preference name="APP_ID_ANDROID" default=".*?" \/>/, `<preference name="APP_ID_ANDROID" default="${admobConfig.APP_ID_ANDROID}" />`)
508
- .replace(/<preference name="APP_ID_IOS" default=".*?" \/>/, `<preference name="APP_ID_IOS" default="${admobConfig.APP_ID_IOS}" />`);
509
-
510
- fs.writeFileSync(pluginPath, pluginContent, 'utf8');
511
- console.log('✅ AdMob IDs successfully updated in plugin.xml');
512
- }
513
-
514
- function updateInfoPlist(admobConfig) {
515
- if (!fileExists(infoPlistPath)) {
516
- console.error(' ❌ Info.plist not found. Ensure you have built the iOS project.');
517
- return;
518
- }
519
-
520
- const plistContent = fs.readFileSync(infoPlistPath, 'utf8');
521
- const plistData = plist.parse(plistContent);
522
-
523
- plistData.GADApplicationIdentifier = admobConfig.APP_ID_IOS;
524
- plistData.NSUserTrackingUsageDescription = 'This identifier will be used to deliver personalized ads to you.';
525
- plistData.GADDelayAppMeasurementInit = true;
526
-
527
- const updatedPlistContent = plist.build(plistData);
528
- fs.writeFileSync(infoPlistPath, updatedPlistContent, 'utf8');
529
- console.log('AdMob IDs and additional configurations successfully updated in Info.plist');
530
- }
531
-
532
- try {
533
- if (!fileExists(configPath)) {
534
- throw new Error(' ❌ capacitor.config.json not found. Skipping setup.');
535
- }
536
-
537
- if (!fileExists(androidPlatformPath) && !fileExists(iosPlatformPath)) {
538
- throw new Error('Neither Android nor iOS platforms are found. Ensure platforms are added to your Capacitor project.');
539
- }
540
-
541
- checkAndCopyResources();
542
-
543
- const admobConfig = getAdMobConfig();
544
-
545
-
546
- // Proceed only if ADMOB_ENABLED is true
547
- if (admobConfig.ADMOB_ENABLED) {
548
- if (fileExists(androidPlatformPath)) {
549
- updatePluginXml(admobConfig);
550
- }
551
-
552
- if (fileExists(iosPlatformPath)) {
553
- updateInfoPlist(admobConfig);
554
- }
555
- }
556
-
557
-
558
- } catch (error) {
559
- console.error(error.message);
560
- process.exit(1); // Stop execution if there's a critical error
561
- }
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
- // Check all the codeplays plugins version START
573
-
574
-
575
- const readline = require('readline');
576
-
577
-
578
- //const srcDir = path.join(__dirname, 'src');
579
- const srcDir = path.join(process.cwd(), 'src');
580
- let outdatedPlugins = [];
581
-
582
- function parseVersion(ver) {
583
- return ver.split('.').map(n => parseInt(n, 10));
584
- }
585
-
586
- function compareVersions(v1, v2) {
587
- const [a1, b1] = parseVersion(v1);
588
- const [a2, b2] = parseVersion(v2);
589
- if (a1 !== a2) return a1 - a2;
590
- return b1 - b2;
591
- }
592
-
593
- function walkSync(dir, filelist = []) {
594
- fs.readdirSync(dir).forEach(file => {
595
- const fullPath = path.join(dir, file);
596
- const stat = fs.statSync(fullPath);
597
- if (stat.isDirectory()) {
598
- walkSync(fullPath, filelist);
599
- } else {
600
- filelist.push(fullPath);
601
- }
602
- });
603
- return filelist;
604
- }
605
-
606
- function checkPlugins() {
607
- const files = walkSync(srcDir);
608
-
609
- for (const plugin of requiredPlugins) {
610
- if (plugin.isFolder) {
611
- const folderPath = path.join(srcDir, ...plugin.pattern.source.split(/[\/\\]/).slice(0, -1));
612
- if (fs.existsSync(folderPath)) {
613
- const versionMatch = plugin.pattern.exec(folderPath);
614
- if (versionMatch && compareVersions(versionMatch[1], plugin.minVersion) < 0) {
615
- outdatedPlugins.push({
616
- name: plugin.pattern,
617
- currentVersion: versionMatch[1],
618
- requiredVersion: plugin.minVersion
619
- });
620
- }
621
- }
622
- continue;
623
- }
624
-
625
- const matchedFile = files.find(file => plugin.pattern.test(file));
626
- if (matchedFile) {
627
- const match = plugin.pattern.exec(matchedFile);
628
- if (match) {
629
- const currentVersion = match[1];
630
- if (compareVersions(currentVersion, plugin.minVersion) < 0) {
631
- outdatedPlugins.push({
632
- name: path.relative(__dirname, matchedFile),
633
- currentVersion,
634
- requiredVersion: plugin.minVersion
635
- });
636
- }
637
- }
638
- }
639
- }
640
-
641
- if (outdatedPlugins.length > 0) {
642
- console.log('\n❗ The following plugins are outdated:');
643
- outdatedPlugins.forEach(p => {
644
- console.log(` ❌ - ${p.name} (Current: ${p.currentVersion}, Required: ${p.requiredVersion})`);
645
- });
646
-
647
- const rl = readline.createInterface({
648
- input: process.stdin,
649
- output: process.stdout
650
- });
651
-
652
- rl.question('\nAre you sure you want to continue without updating these plugins? (y/n): ', answer => {
653
- if (answer.toLowerCase() !== 'y') {
654
- console.log('\n❌ Build cancelled due to outdated plugins.');
655
- process.exit(1);
656
- } else {
657
- console.log('\n✅ Continuing build...');
658
- rl.close();
659
- }
660
- });
661
- } else {
662
- console.log('✅ All plugin versions are up to date.');
663
- }
664
- }
665
-
666
- // Run the validation
667
- checkPlugins();
668
-
669
-
670
-
671
-
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const plist = require('plist');
4
+
5
+
6
+ // Expected plugin list with minimum versions
7
+ const requiredPlugins = [
8
+ { pattern: /backbutton-(\d+\.\d+)\.js$/, minVersion: '1.1', required: true },
9
+ { pattern: /common-(\d+\.\d+)\.js$/, minVersion: '3.4', required: true },
10
+ { pattern: /localization_settings-(\d+\.\d+)\.js$/, minVersion: '1.1', required: true },
11
+ { pattern: /localization-(\d+\.\d+)\.js$/, minVersion: '1.2', required: true },
12
+ { pattern: /localNotification-(\d+\.\d+)\.js$/, minVersion: '2.2', required: true },
13
+ { pattern: /localNotification_AppSettings-(\d+\.\d+)\.js$/, minVersion: '1.0', required: true },
14
+ { pattern: /onesignal-(\d+\.\d+)\.js$/, minVersion: '2.1', required: true },
15
+ { pattern: /saveToGalleryAndSaveAnyFile-(\d+\.\d+)(-ios)?\.js$/, minVersion: '2.3', required: true },
16
+ { pattern: /Ads[\/\\]IAP-(\d+\.\d+)$/, minVersion: '2.1', isFolder: true },
17
+ { pattern: /Ads[\/\\]admob-emi-(\d+\.\d+)\.js$/, minVersion: '2.6', required: true }
18
+ ];
19
+
20
+
21
+
22
+
23
+
24
+
25
+ //Check codeplay-common latest version installed or not Start
26
+ const { execSync } = require('child_process');
27
+
28
+ function getInstalledVersion(packageName) {
29
+ try {
30
+ const packageJsonPath = path.join(process.cwd(), 'node_modules', packageName, 'package.json');
31
+ if (fs.existsSync(packageJsonPath)) {
32
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
33
+ return packageJson.version;
34
+ }
35
+ } catch (error) {
36
+ return null;
37
+ }
38
+ return null;
39
+ }
40
+
41
+ function getLatestVersion(packageName) {
42
+ try {
43
+ return execSync(`npm view ${packageName} version`).toString().trim();
44
+ } catch (error) {
45
+ console.error(`Failed to fetch latest version for ${packageName}`);
46
+ return null;
47
+ }
48
+ }
49
+
50
+ function checkPackageVersion() {
51
+ const packageName = 'codeplay-common';
52
+ const installedVersion = getInstalledVersion(packageName);
53
+ const latestVersion = getLatestVersion(packageName);
54
+
55
+ if (!installedVersion) {
56
+ console.error(`${packageName} is not installed. Please install it using "npm install ${packageName}".`);
57
+ process.exit(1);
58
+ }
59
+
60
+ if (installedVersion !== latestVersion) {
61
+ console.error(`\x1b[31m${packageName} is outdated (installed: ${installedVersion}, latest: ${latestVersion}). Please update it.\x1b[0m\n\x1b[33mUse 'npm uninstall codeplay-common ; npm i codeplay-common'\x1b[0m`);
62
+ process.exit(1);
63
+ }
64
+
65
+ console.log(`${packageName} is up to date (version ${installedVersion}).`);
66
+ }
67
+
68
+ // Run package version check before executing the main script
69
+ try {
70
+ checkPackageVersion();
71
+ } catch (error) {
72
+ console.error(error.message);
73
+ process.exit(1);
74
+ }
75
+
76
+ //Check codeplay-common latest version installed or not END
77
+
78
+
79
+
80
+
81
+
82
+
83
+ // saveToGalleryAndSaveAnyFile-x.x-ios.js file check for android and return error if exists START
84
+
85
+ const os = require('os');
86
+
87
+ const saveToGalleryAndSaveFileCheck_iOS = () => {
88
+ const ROOT_DIR = path.resolve(__dirname, '../src');
89
+
90
+ const IOS_FILE_REGEX = /(?:import|require)?\s*\(?['"].*saveToGalleryAndSaveAnyFile-\d+(\.\d+)?-ios\.js['"]\)?/;
91
+ const ALLOWED_EXTENSIONS = ['.js', '.f7'];
92
+ const isMac = os.platform() === 'darwin';
93
+
94
+ let iosImportFound = false;
95
+
96
+ function scanDirectory(dir) {
97
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
98
+
99
+ for (let entry of entries) {
100
+ const fullPath = path.join(dir, entry.name);
101
+
102
+ if (entry.isDirectory()) {
103
+ if (entry.name === 'node_modules') continue;
104
+ scanDirectory(fullPath);
105
+ } else if (
106
+ entry.isFile() &&
107
+ ALLOWED_EXTENSIONS.some(ext => fullPath.endsWith(ext))
108
+ ) {
109
+ const content = fs.readFileSync(fullPath, 'utf8');
110
+ const matches = content.match(IOS_FILE_REGEX);
111
+ if (matches) {
112
+ iosImportFound = true;
113
+ console.error(`\n❌❌❌ BIG ERROR: iOS-specific import detected in: ${fullPath}`);
114
+ console.error(`🔍 Matched: ${matches[0]}\n`);
115
+ if (!isMac) {
116
+ console.error(`🚫 STOPPED: This file should not be imported in Android/Windows/Linux builds.\n`);
117
+ process.exit(1);
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ // Check if src folder exists first
125
+ if (!fs.existsSync(ROOT_DIR)) {
126
+ console.warn(`⚠️ Warning: 'src' directory not found at: ${ROOT_DIR}`);
127
+ return;
128
+ }
129
+
130
+ scanDirectory(ROOT_DIR);
131
+
132
+ if (isMac && !iosImportFound) {
133
+ console.warn(`\x1b[31m\n⚠️⚠️⚠️ WARNING: You're on macOS but no iOS-specific file (saveToGalleryAndSaveAnyFile-x.x-ios.js) was found.\x1b[0m`);
134
+ console.warn(`👉 You may want to double-check your imports for the iOS platform.\n`);
135
+ process.exit(1);
136
+ } else if (isMac && iosImportFound) {
137
+ console.log('✅ iOS file detected as expected for macOS.');
138
+ } else if (!iosImportFound) {
139
+ console.log('✅ No iOS-specific file imports detected for non-macOS.');
140
+ }
141
+ };
142
+
143
+ saveToGalleryAndSaveFileCheck_iOS();
144
+ // saveToGalleryAndSaveAnyFile-x.x-ios.js file check for android and return error if exists END
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+ /*
159
+ // Clean up AppleDouble files (._*) created by macOS START
160
+ if (process.platform === 'darwin') {
161
+ try {
162
+ console.log('🧹 Cleaning up AppleDouble files (._*)...');
163
+ execSync(`find . -name '._*' -delete`);
164
+ console.log('✅ AppleDouble files removed.');
165
+ } catch (err) {
166
+ console.warn('⚠️ Failed to remove AppleDouble files:', err.message);
167
+ }
168
+ } else {
169
+ console.log('ℹ️ Skipping AppleDouble cleanup — not a macOS machine.');
170
+ }
171
+
172
+ // Clean up AppleDouble files (._*) created by macOS END
173
+ */
174
+
175
+
176
+
177
+
178
+
179
+
180
+ //In routes.js file check static import START
181
+
182
+ const routesPath = path.join(process.cwd(), 'src', 'js', 'routes.js');
183
+ const routesContent = fs.readFileSync(routesPath, 'utf-8');
184
+
185
+ let inBlockComment = false;
186
+ const lines = routesContent.split('\n');
187
+
188
+ const allowedImport = `import HomePage from '../pages/home.f7';`;
189
+ const badImportRegex = /^[ \t]*import\s+[\w{}*,\s]*\s+from\s+['"].+\.f7['"]\s*;/;
190
+ const badImports = [];
191
+
192
+ lines.forEach((line, index) => {
193
+ const trimmed = line.trim();
194
+
195
+ // Handle block comment start and end
196
+ if (trimmed.startsWith('/*')) inBlockComment = true;
197
+ if (inBlockComment && trimmed.endsWith('*/')) {
198
+ inBlockComment = false;
199
+ return;
200
+ }
201
+
202
+ // Skip if inside block comment or line comment
203
+ if (inBlockComment || trimmed.startsWith('//')) return;
204
+
205
+ // Match static .f7 import
206
+ if (badImportRegex.test(trimmed) && trimmed !== allowedImport) {
207
+ badImports.push({ line: trimmed, number: index + 1 });
208
+ }
209
+ });
210
+
211
+ if (badImports.length > 0) {
212
+ console.error('\n❌ ERROR: Detected disallowed static imports of .f7 files in routes.js\n');
213
+ console.error(`⚠️ Only this static import is allowed:\n ${allowedImport}\n`);
214
+ console.error(`🔧 Please convert other imports to async dynamic imports like this:\n`);
215
+ console.error(`
216
+
217
+ import HomePage from '../pages/home.f7';
218
+
219
+ const routes = [
220
+ {
221
+ path: '/',
222
+ component:HomePage,
223
+ },
224
+ {
225
+ path: '/ProfilePage/',
226
+ async async({ resolve }) {
227
+ const page = await import('../pages/profile.f7');
228
+ resolve({ component: page.default });
229
+ },
230
+ }]
231
+ `);
232
+
233
+ badImports.forEach(({ line, number }) => {
234
+ console.error(`${number}: ${line}`);
235
+ });
236
+
237
+ process.exit(1);
238
+ } else {
239
+ console.log('✅ routes.js passed the .f7 import check.');
240
+ }
241
+
242
+ //In routes.js file check static import END
243
+
244
+
245
+
246
+
247
+
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+ // Check and change the "BridgeWebViewClient.java" file START
257
+ /*
258
+ For crash issue due to low memory problem, we need to modify the onRenderProcessGone method in BridgeWebViewClient.java.
259
+ */
260
+
261
+
262
+ const bridgeWebViewClientFilePath = path.join(process.cwd(), 'node_modules', '@capacitor/android/capacitor/src/main/java/com/getcapacitor', 'BridgeWebViewClient.java');
263
+
264
+ // Read the file
265
+ if (!fs.existsSync(bridgeWebViewClientFilePath)) {
266
+ console.error('❌ Error: BridgeWebViewClient.java not found.');
267
+ process.exit(1);
268
+ }
269
+
270
+ let fileContent = fs.readFileSync(bridgeWebViewClientFilePath, 'utf8');
271
+
272
+ // Define old and new code
273
+ const oldCodeStart = `@Override
274
+ public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
275
+ super.onRenderProcessGone(view, detail);
276
+ boolean result = false;
277
+
278
+ List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
279
+ if (webViewListeners != null) {
280
+ for (WebViewListener listener : bridge.getWebViewListeners()) {
281
+ result = listener.onRenderProcessGone(view, detail) || result;
282
+ }
283
+ }
284
+
285
+ return result;
286
+ }`;
287
+
288
+ const newCode = `@Override
289
+ public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
290
+ super.onRenderProcessGone(view, detail);
291
+
292
+ boolean result = false;
293
+
294
+ List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
295
+ if (webViewListeners != null) {
296
+ for (WebViewListener listener : bridge.getWebViewListeners()) {
297
+ result = listener.onRenderProcessGone(view, detail) || result;
298
+ }
299
+ }
300
+
301
+ if (!result) {
302
+ // If no one handled it, handle it ourselves!
303
+
304
+ /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
305
+ if (detail.didCrash()) {
306
+ //Log.e("CapacitorWebView", "WebView crashed internally!");
307
+ } else {
308
+ //Log.w("CapacitorWebView", "WebView was killed by system (low memory) internally!");
309
+ }
310
+ }*/
311
+
312
+ view.post(() -> {
313
+ Toast.makeText(view.getContext(), "Reloading due to low memory issue", Toast.LENGTH_SHORT).show();
314
+ });
315
+
316
+ view.reload(); // Safely reload WebView
317
+
318
+ return true; // We handled it
319
+ }
320
+
321
+ return result;
322
+ }`;
323
+
324
+ // Step 1: Update method if needed
325
+ let updated = false;
326
+
327
+ if (fileContent.includes(oldCodeStart)) {
328
+ console.log('✅ Found old onRenderProcessGone method. Replacing it...');
329
+ fileContent = fileContent.replace(oldCodeStart, newCode);
330
+ updated = true;
331
+ } else if (fileContent.includes(newCode)) {
332
+ console.log('ℹ️ Method already updated. No changes needed in "BridgeWebViewClient.java".');
333
+ } else {
334
+ console.error('❌ Error: Neither old nor new code found. Unexpected content.');
335
+ process.exit(1);
336
+ }
337
+
338
+ // Step 2: Check and add import if missing
339
+ const importToast = 'import android.widget.Toast;';
340
+ if (!fileContent.includes(importToast)) {
341
+ console.log('✅ Adding missing import for Toast...');
342
+ const importRegex = /import\s+[^;]+;/g;
343
+ const matches = [...fileContent.matchAll(importRegex)];
344
+
345
+ if (matches.length > 0) {
346
+ const lastImport = matches[matches.length - 1];
347
+ const insertPosition = lastImport.index + lastImport[0].length;
348
+ fileContent = fileContent.slice(0, insertPosition) + `\n${importToast}` + fileContent.slice(insertPosition);
349
+ updated = true;
350
+ } else {
351
+ console.error('❌ Error: No import section found in file.');
352
+ process.exit(1);
353
+ }
354
+ } else {
355
+ console.log('ℹ️ Import for Toast already exists. No changes needed.');
356
+ }
357
+
358
+ // Step 3: Save if updated
359
+ if (updated) {
360
+ fs.writeFileSync(bridgeWebViewClientFilePath, fileContent, 'utf8');
361
+ console.log('✅ File updated successfully.');
362
+ } else {
363
+ console.log('ℹ️ No changes needed.');
364
+ }
365
+
366
+
367
+
368
+
369
+ // Check and change the "BridgeWebViewClient.java" file END
370
+
371
+
372
+
373
+
374
+
375
+
376
+
377
+
378
+
379
+ // To resolve the kotlin version issue, we need to update the kotlin version in the build.gradle file START
380
+
381
+ // Build the path dynamically like you requested
382
+ const gradlePath = path.join(
383
+ process.cwd(),
384
+ 'android',
385
+ 'build.gradle'
386
+ );
387
+
388
+ // Read the existing build.gradle
389
+ let gradleContent = fs.readFileSync(gradlePath, 'utf8');
390
+
391
+ // Add `ext.kotlin_version` if it's not already there
392
+ if (!gradleContent.includes('ext.kotlin_version')) {
393
+ gradleContent = gradleContent.replace(
394
+ /buildscript\s*{/,
395
+ `buildscript {\n ext.kotlin_version = '2.1.0'`
396
+ );
397
+ }
398
+
399
+ // Add Kotlin classpath if it's not already there
400
+ if (!gradleContent.includes('org.jetbrains.kotlin:kotlin-gradle-plugin')) {
401
+ gradleContent = gradleContent.replace(
402
+ /dependencies\s*{([\s\S]*?)classpath 'com.android.tools.build:gradle:8.7.2'/,
403
+ `dependencies {\n classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")\n$1classpath 'com.android.tools.build:gradle:8.7.2'`
404
+ );
405
+ }
406
+
407
+ // Write back the modified content
408
+ fs.writeFileSync(gradlePath, gradleContent, 'utf8');
409
+
410
+ console.log('✅ Kotlin version updated in build.gradle.');
411
+
412
+ // To resolve the kotlin version issue, we need to update the kotlin version in the build.gradle file END
413
+
414
+
415
+
416
+
417
+
418
+
419
+
420
+
421
+
422
+
423
+ const configPath = path.join(process.cwd(), 'capacitor.config.json');
424
+ const androidPlatformPath = path.join(process.cwd(), 'android');
425
+ const iosPlatformPath = path.join(process.cwd(), 'ios');
426
+ const pluginPath = path.join(process.cwd(), 'node_modules', 'emi-indo-cordova-plugin-admob', 'plugin.xml');
427
+ const infoPlistPath = path.join(process.cwd(), 'ios', 'App', 'App', 'Info.plist');
428
+ const resourcesPath = path.join(process.cwd(), 'resources', 'res');
429
+ const androidResPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'res');
430
+ const localNotificationsPluginPath = path.join(process.cwd(), 'node_modules', '@capacitor', 'local-notifications');
431
+
432
+ function fileExists(filePath) {
433
+ return fs.existsSync(filePath);
434
+ }
435
+
436
+ function copyFolderSync(source, target) {
437
+ if (!fs.existsSync(target)) {
438
+ fs.mkdirSync(target, { recursive: true });
439
+ }
440
+
441
+ fs.readdirSync(source).forEach(file => {
442
+ const sourceFile = path.join(source, file);
443
+ const targetFile = path.join(target, file);
444
+
445
+ if (fs.lstatSync(sourceFile).isDirectory()) {
446
+ copyFolderSync(sourceFile, targetFile);
447
+ } else {
448
+ fs.copyFileSync(sourceFile, targetFile);
449
+ }
450
+ });
451
+ }
452
+
453
+ function checkAndCopyResources() {
454
+ if (fileExists(resourcesPath)) {
455
+ copyFolderSync(resourcesPath, androidResPath);
456
+ console.log('✅ Successfully copied resources/res to android/app/src/main/res.');
457
+ } else {
458
+ console.log('resources/res folder not found.');
459
+
460
+ if (fileExists(localNotificationsPluginPath)) {
461
+ throw new Error('❌ resources/res is required for @capacitor/local-notifications. Stopping execution.');
462
+ }
463
+ }
464
+ }
465
+
466
+
467
+
468
+ function getAdMobConfig() {
469
+ if (!fileExists(configPath)) {
470
+ throw new Error('❌ capacitor.config.json not found. Ensure this is a Capacitor project.');
471
+ }
472
+
473
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
474
+ const admobConfig = config.plugins?.AdMob;
475
+
476
+ if (!admobConfig) {
477
+ throw new Error('❌ AdMob configuration is missing in capacitor.config.json.');
478
+ }
479
+
480
+ // Default to true if ADMOB_ENABLED is not specified
481
+ const isEnabled = admobConfig.ADMOB_ENABLED !== false;
482
+
483
+ if (!isEnabled) {
484
+ return { ADMOB_ENABLED: false }; // Skip further validation
485
+ }
486
+
487
+ if (!admobConfig.APP_ID_ANDROID || !admobConfig.APP_ID_IOS) {
488
+ throw new Error(' ❌ AdMob configuration is incomplete. Ensure APP_ID_ANDROID and APP_ID_IOS are defined.');
489
+ }
490
+
491
+ return {
492
+ ADMOB_ENABLED: true,
493
+ APP_ID_ANDROID: admobConfig.APP_ID_ANDROID,
494
+ APP_ID_IOS: admobConfig.APP_ID_IOS,
495
+ USE_LITE_ADS: admobConfig.USE_LITE_ADS === "lite",
496
+ };
497
+ }
498
+
499
+ function updatePluginXml(admobConfig) {
500
+ if (!fileExists(pluginPath)) {
501
+ console.error(' ❌ plugin.xml not found. Ensure the plugin is installed.');
502
+ return;
503
+ }
504
+
505
+ let pluginContent = fs.readFileSync(pluginPath, 'utf8');
506
+
507
+ pluginContent = pluginContent
508
+ .replace(/<preference name="APP_ID_ANDROID" default=".*?" \/>/, `<preference name="APP_ID_ANDROID" default="${admobConfig.APP_ID_ANDROID}" />`)
509
+ .replace(/<preference name="APP_ID_IOS" default=".*?" \/>/, `<preference name="APP_ID_IOS" default="${admobConfig.APP_ID_IOS}" />`);
510
+
511
+ fs.writeFileSync(pluginPath, pluginContent, 'utf8');
512
+ console.log('✅ AdMob IDs successfully updated in plugin.xml');
513
+ }
514
+
515
+ function updateInfoPlist(admobConfig) {
516
+ if (!fileExists(infoPlistPath)) {
517
+ console.error(' ❌ Info.plist not found. Ensure you have built the iOS project.');
518
+ return;
519
+ }
520
+
521
+ const plistContent = fs.readFileSync(infoPlistPath, 'utf8');
522
+ const plistData = plist.parse(plistContent);
523
+
524
+ plistData.GADApplicationIdentifier = admobConfig.APP_ID_IOS;
525
+ plistData.NSUserTrackingUsageDescription = 'This identifier will be used to deliver personalized ads to you.';
526
+ plistData.GADDelayAppMeasurementInit = true;
527
+
528
+ const updatedPlistContent = plist.build(plistData);
529
+ fs.writeFileSync(infoPlistPath, updatedPlistContent, 'utf8');
530
+ console.log('AdMob IDs and additional configurations successfully updated in Info.plist');
531
+ }
532
+
533
+ try {
534
+ if (!fileExists(configPath)) {
535
+ throw new Error(' ❌ capacitor.config.json not found. Skipping setup.');
536
+ }
537
+
538
+ if (!fileExists(androidPlatformPath) && !fileExists(iosPlatformPath)) {
539
+ throw new Error('Neither Android nor iOS platforms are found. Ensure platforms are added to your Capacitor project.');
540
+ }
541
+
542
+ checkAndCopyResources();
543
+
544
+ const admobConfig = getAdMobConfig();
545
+
546
+
547
+ // Proceed only if ADMOB_ENABLED is true
548
+ if (admobConfig.ADMOB_ENABLED) {
549
+ if (fileExists(androidPlatformPath)) {
550
+ updatePluginXml(admobConfig);
551
+ }
552
+
553
+ if (fileExists(iosPlatformPath)) {
554
+ updateInfoPlist(admobConfig);
555
+ }
556
+ }
557
+
558
+
559
+ } catch (error) {
560
+ console.error(error.message);
561
+ process.exit(1); // Stop execution if there's a critical error
562
+ }
563
+
564
+
565
+
566
+
567
+
568
+
569
+
570
+
571
+
572
+
573
+ // Check all the codeplays plugins version START
574
+
575
+
576
+ const readline = require('readline');
577
+
578
+
579
+ //const srcDir = path.join(__dirname, 'src');
580
+ const srcDir = path.join(process.cwd(), 'src');
581
+ let outdatedPlugins = [];
582
+
583
+ function parseVersion(ver) {
584
+ return ver.split('.').map(n => parseInt(n, 10));
585
+ }
586
+
587
+ function compareVersions(v1, v2) {
588
+ const [a1, b1] = parseVersion(v1);
589
+ const [a2, b2] = parseVersion(v2);
590
+ if (a1 !== a2) return a1 - a2;
591
+ return b1 - b2;
592
+ }
593
+
594
+ function walkSync(dir, filelist = []) {
595
+ fs.readdirSync(dir).forEach(file => {
596
+ const fullPath = path.join(dir, file);
597
+ const stat = fs.statSync(fullPath);
598
+ if (stat.isDirectory()) {
599
+ walkSync(fullPath, filelist);
600
+ } else {
601
+ filelist.push(fullPath);
602
+ }
603
+ });
604
+ return filelist;
605
+ }
606
+
607
+ function checkPlugins() {
608
+ const files = walkSync(srcDir);
609
+
610
+ for (const plugin of requiredPlugins) {
611
+ if (plugin.isFolder) {
612
+ const folderPath = path.join(srcDir, ...plugin.pattern.source.split(/[\/\\]/).slice(0, -1));
613
+ if (fs.existsSync(folderPath)) {
614
+ const versionMatch = plugin.pattern.exec(folderPath);
615
+ if (versionMatch && compareVersions(versionMatch[1], plugin.minVersion) < 0) {
616
+ outdatedPlugins.push({
617
+ name: plugin.pattern,
618
+ currentVersion: versionMatch[1],
619
+ requiredVersion: plugin.minVersion
620
+ });
621
+ }
622
+ }
623
+ continue;
624
+ }
625
+
626
+ const matchedFile = files.find(file => plugin.pattern.test(file));
627
+ if (matchedFile) {
628
+ const match = plugin.pattern.exec(matchedFile);
629
+ if (match) {
630
+ const currentVersion = match[1];
631
+ if (compareVersions(currentVersion, plugin.minVersion) < 0) {
632
+ outdatedPlugins.push({
633
+ name: path.relative(__dirname, matchedFile),
634
+ currentVersion,
635
+ requiredVersion: plugin.minVersion
636
+ });
637
+ }
638
+ }
639
+ }
640
+ }
641
+
642
+ if (outdatedPlugins.length > 0) {
643
+ console.log('\n❗ The following plugins are outdated:');
644
+ outdatedPlugins.forEach(p => {
645
+ console.log(` ❌ - ${p.name} (Current: ${p.currentVersion}, Required: ${p.requiredVersion})`);
646
+ });
647
+
648
+ const rl = readline.createInterface({
649
+ input: process.stdin,
650
+ output: process.stdout
651
+ });
652
+
653
+ rl.question('\nAre you sure you want to continue without updating these plugins? (y/n): ', answer => {
654
+ if (answer.toLowerCase() !== 'y') {
655
+ console.log('\n❌ Build cancelled due to outdated plugins.');
656
+ process.exit(1);
657
+ } else {
658
+ console.log('\n✅ Continuing build...');
659
+ rl.close();
660
+ }
661
+ });
662
+ } else {
663
+ console.log('✅ All plugin versions are up to date.');
664
+ }
665
+ }
666
+
667
+ // Run the validation
668
+ checkPlugins();
669
+
670
+
671
+
672
+
672
673
  // Check all the codeplays plugins version START