@crowdin/app-project-module 0.104.1 → 0.105.0

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.
@@ -229,7 +229,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
229
229
  const needsSnapshotForNewFiles = !integration.webhooks &&
230
230
  ((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[syncSettings.provider]) &&
231
231
  intConfig[`new-${syncSettings.provider}-files`];
232
- const needsIntegrationSnapshot = integration.forcePushSources || (needsSnapshotForNewFiles && syncSettings.provider !== types_1.Provider.CROWDIN);
232
+ const needsIntegrationSnapshot = needsSnapshotForNewFiles && syncSettings.provider !== types_1.Provider.CROWDIN;
233
233
  const needsCrowdinSnapshot = needsSnapshotForNewFiles && syncSettings.provider === types_1.Provider.CROWDIN;
234
234
  if (needsIntegrationSnapshot) {
235
235
  currentFileSnapshot = yield (0, snapshot_1.getIntegrationSnapshot)(integration, apiCredentials, intConfig);
@@ -280,9 +280,13 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
280
280
  const onlyTranslated = +intConfig.condition === types_1.SyncCondition.TRANSLATED;
281
281
  const onlyApproved = +intConfig.condition === types_1.SyncCondition.APPROVED;
282
282
  const all = +intConfig.condition === types_1.SyncCondition.ALL || intConfig.condition === undefined;
283
- const filesToProcess = all
284
- ? crowdinFiles
285
- : yield getOnlyTranslatedOrApprovedFiles({
283
+ let filesToProcess;
284
+ let deletedFileIds = [];
285
+ if (all) {
286
+ filesToProcess = crowdinFiles;
287
+ }
288
+ else {
289
+ const result = yield getOnlyTranslatedOrApprovedFiles({
286
290
  projectId,
287
291
  crowdinFiles,
288
292
  crowdinClient,
@@ -290,6 +294,18 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
290
294
  onlyTranslated,
291
295
  context,
292
296
  });
297
+ filesToProcess = result.filteredFiles;
298
+ deletedFileIds = result.deletedFiles;
299
+ }
300
+ if (deletedFileIds.length > 0) {
301
+ (0, logger_1.log)(`Removing ${deletedFileIds.length} deleted files from sync settings`);
302
+ const updatedFiles = Object.assign({}, files);
303
+ for (const fileId of deletedFileIds) {
304
+ delete updatedFiles[fileId];
305
+ }
306
+ yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(updatedFiles), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', types_1.Provider.CROWDIN);
307
+ files = updatedFiles;
308
+ }
293
309
  if (Object.keys(filesToProcess).length <= 0) {
294
310
  return;
295
311
  }
@@ -457,6 +473,7 @@ function getNewFoldersFile(folders, snapshotFiles) {
457
473
  }
458
474
  function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated, context, }) {
459
475
  return __awaiter(this, void 0, void 0, function* () {
476
+ const deletedFiles = [];
460
477
  (0, logger_1.log)(`Filtering files to process only ${onlyApproved ? 'approved' : 'translated'} files`);
461
478
  const filesInfo = yield Promise.all(Object.keys(crowdinFiles).map((fileId) => __awaiter(this, void 0, void 0, function* () {
462
479
  try {
@@ -470,7 +487,13 @@ function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClie
470
487
  }
471
488
  catch (e) {
472
489
  delete crowdinFiles[fileId];
473
- (0, logger_1.logError)(e, context);
490
+ if ((e === null || e === void 0 ? void 0 : e.status) === 404 || (e === null || e === void 0 ? void 0 : e.code) === 404) {
491
+ (0, logger_1.log)(`File ${fileId} not found in Crowdin (404), marking for removal from sync settings`);
492
+ deletedFiles.push(Number(fileId));
493
+ }
494
+ else {
495
+ (0, logger_1.logError)(e, context);
496
+ }
474
497
  }
475
498
  })));
476
499
  const filteredFiles = {};
@@ -511,7 +534,7 @@ function getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClie
511
534
  }
512
535
  });
513
536
  });
514
- return filteredFiles;
537
+ return { filteredFiles, deletedFiles };
515
538
  });
516
539
  }
517
540
  function filterFilesFromIntegrationRequest({ config, integration, projectId, crowdinClient, crowdinFiles, }) {
@@ -125,6 +125,10 @@ function createDumpForMigration(config) {
125
125
  modifiedContent = modifiedContent.replace(/varchar not null primary key/gi, 'varchar primary key');
126
126
  // 6. Remove SQLite-specific function replace()
127
127
  modifiedContent = modifiedContent.replace(/replace\s*\(\s*'([^']*(?:'{2}[^']*)*)',\s*'\\n',\s*char\s*\(\s*10\s*\)\s*\)/gi, "'$1'");
128
+ // 7. Convert SQLite backticks to PostgreSQL double quotes
129
+ modifiedContent = modifiedContent.replace(/`([^`]+)`/g, '"$1"');
130
+ // 8. Remove VARCHAR length restrictions (VARCHAR(255) -> VARCHAR)
131
+ modifiedContent = modifiedContent.replace(/VARCHAR\(\d+\)/gi, 'VARCHAR');
128
132
  fs_1.default.writeFileSync(dumpFilePath, modifiedContent, { encoding: 'utf8', flag: 'w' });
129
133
  }
130
134
  fs_1.default.renameSync(sqliteFilePath, backupFilePath);
@@ -600,41 +600,63 @@
600
600
 
601
601
  {{#if progressiveCrowdinFilesLoading}}
602
602
  checkOrigin()
603
- .then(restParams => fetch('api/crowdin/files' + restParams + '&mode=directories'))
604
- .then(checkResponse)
605
- .then((directories) => {
606
- const dirTree = directories.map(transformCrowdinItemToTree);
607
- crowdinData = dirTree;
608
- appComponent.setCrowdinFilesData(dirTree);
609
- return checkOrigin();
603
+ .then(restParams => {
604
+ const dirPromise = fetch('api/crowdin/files' + restParams + '&mode=directories')
605
+ .then(checkResponse)
606
+ .then((directories) => {
607
+ const dirTree = directories.map(transformCrowdinItemToTree);
608
+ crowdinData = dirTree;
609
+ appComponent.setCrowdinFilesData(dirTree);
610
+ return dirTree;
611
+ });
612
+
613
+ const filesPromise = fetch('api/crowdin/files' + restParams + '&mode=files')
614
+ .then(checkResponse);
615
+
616
+ const projectPromise = fetch('api/crowdin/project' + restParams)
617
+ .then(checkResponse);
618
+
619
+ return Promise.all([dirPromise, filesPromise, projectPromise]);
610
620
  })
611
- .then(restParams => fetch('api/crowdin/files' + restParams + '&mode=files'))
612
- .then(checkResponse)
613
- .then((files) => {
621
+ .then(([dirTree, files, projectData]) => {
614
622
  const fileTree = files.map(transformCrowdinItemToTree);
615
- crowdinData = [...crowdinData, ...fileTree];
623
+ crowdinData = [...dirTree, ...fileTree];
616
624
  appComponent.setCrowdinFilesData(crowdinData);
617
- return checkOrigin();
625
+
626
+ project = projectData;
627
+ const languagesSorted = project.targetLanguages.map(language => ({
628
+ sourceLanguageId: projectData.sourceLanguage.editorCode,
629
+ projectEditorLink: projectData.projectEditorLink,
630
+ ...language,
631
+ })).sort((a, b) => a.name.localeCompare(b.name));
632
+
633
+ if (project.inContext && config?.inContext) {
634
+ languagesSorted.push({...project.inContextPseudoLanguage, inContext: true});
635
+ }
636
+
637
+ setLanguagesForTranslation(languagesSorted);
638
+ appComponent.setCrowdinLanguagesData(languagesSorted);
618
639
  })
619
- .then(restParams => fetch('api/crowdin/project' + restParams))
620
640
  {{else}}
621
641
  checkOrigin()
622
- .then(restParams => fetch('api/crowdin/files' + restParams))
623
- .then(checkResponse)
624
- .then((res) => {
625
- const tree = res.map(transformCrowdinItemToTree);
642
+ .then(restParams => {
643
+ const filesPromise = fetch('api/crowdin/files' + restParams)
644
+ .then(checkResponse);
645
+
646
+ const projectPromise = fetch('api/crowdin/project' + restParams)
647
+ .then(checkResponse);
648
+
649
+ return Promise.all([filesPromise, projectPromise]);
650
+ })
651
+ .then(([files, projectData]) => {
652
+ const tree = files.map(transformCrowdinItemToTree);
626
653
  crowdinData = tree;
627
654
  appComponent.setCrowdinFilesData(tree);
628
- return checkOrigin();
629
- })
630
- .then(restParams => fetch('api/crowdin/project' + restParams))
631
- {{/if}}
632
- .then(checkResponse)
633
- .then((res) => {
634
- project = res;
655
+
656
+ project = projectData;
635
657
  const languagesSorted = project.targetLanguages.map(language => ({
636
- sourceLanguageId: res.sourceLanguage.editorCode,
637
- projectEditorLink: res.projectEditorLink,
658
+ sourceLanguageId: projectData.sourceLanguage.editorCode,
659
+ projectEditorLink: projectData.projectEditorLink,
638
660
  ...language,
639
661
  })).sort((a, b) => a.name.localeCompare(b.name));
640
662
 
@@ -643,9 +665,9 @@
643
665
  }
644
666
 
645
667
  setLanguagesForTranslation(languagesSorted);
646
-
647
- appComponent.setCrowdinLanguagesData(languagesSorted)
668
+ appComponent.setCrowdinLanguagesData(languagesSorted);
648
669
  })
670
+ {{/if}}
649
671
  {{#or withCronSync webhooks}}
650
672
  .then(() => getSyncSettings('crowdin'))
651
673
  {{/or}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.104.1",
3
+ "version": "0.105.0",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",