gtx-cli 2.1.14 → 2.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.1.15
4
+
5
+ ### Patch Changes
6
+
7
+ - [#622](https://github.com/generaltranslation/gt/pull/622) [`f5f888d`](https://github.com/generaltranslation/gt/commit/f5f888d79319ac79f3cde12588d1e24ec2003b25) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Skipping invalid (cannot be parsed by AST) MDX files when generating translations
8
+
3
9
  ## 2.1.14
4
10
 
5
11
  ### Patch Changes
@@ -1,10 +1,11 @@
1
- import { logError } from '../../console/logging.js';
1
+ import { logError, logWarning } from '../../console/logging.js';
2
2
  import { getRelative, readFile } from '../../fs/findFilepath.js';
3
3
  import { SUPPORTED_FILE_EXTENSIONS } from './supportedFiles.js';
4
4
  import sanitizeFileContent from '../../utils/sanitizeFileContent.js';
5
5
  import { parseJson } from '../json/parseJson.js';
6
6
  import parseYaml from '../yaml/parseYaml.js';
7
7
  import { determineLibrary } from '../../fs/determineFramework.js';
8
+ import { isValidMdx } from '../../utils/validateMdx.js';
8
9
  export const SUPPORTED_DATA_FORMATS = ['JSX', 'ICU', 'I18NEXT'];
9
10
  export async function aggregateFiles(settings) {
10
11
  // Aggregate all files to translate
@@ -65,16 +66,26 @@ export async function aggregateFiles(settings) {
65
66
  if (fileType === 'json' || fileType === 'yaml')
66
67
  continue;
67
68
  if (filePaths[fileType]) {
68
- const files = filePaths[fileType].map((filePath) => {
69
+ const files = filePaths[fileType]
70
+ .map((filePath) => {
69
71
  const content = readFile(filePath);
70
- const sanitizedContent = sanitizeFileContent(content);
71
72
  const relativePath = getRelative(filePath);
73
+ if (fileType === 'mdx') {
74
+ const validation = isValidMdx(content, filePath);
75
+ if (!validation.isValid) {
76
+ const errorMsg = validation.error ? `: ${validation.error}` : '';
77
+ logWarning(`Skipping ${relativePath}: MDX file is not AST parsable${errorMsg}`);
78
+ return null;
79
+ }
80
+ }
81
+ const sanitizedContent = sanitizeFileContent(content);
72
82
  return {
73
83
  content: sanitizedContent,
74
84
  fileName: relativePath,
75
85
  fileFormat: fileType.toUpperCase(),
76
86
  };
77
- });
87
+ })
88
+ .filter((file) => file !== null);
78
89
  allFiles.push(...files);
79
90
  }
80
91
  }
@@ -70,6 +70,10 @@ export default async function localizeStaticUrls(settings, targetLocales) {
70
70
  const targetFiles = Object.values(filesMap).filter((path) => path.endsWith('.md') || path.endsWith('.mdx'));
71
71
  // Replace the placeholder path with the target path
72
72
  await Promise.all(targetFiles.map(async (filePath) => {
73
+ // Check if file exists before processing
74
+ if (!fs.existsSync(filePath)) {
75
+ return;
76
+ }
73
77
  // Get file content
74
78
  const fileContent = await fs.promises.readFile(filePath, 'utf8');
75
79
  // Localize the file (handles both URLs and hrefs in single AST pass)
@@ -19,6 +19,10 @@ export default async function processAnchorIds(settings) {
19
19
  const translatedFiles = Object.values(filesMap).filter((path) => path && (path.endsWith('.md') || path.endsWith('.mdx')));
20
20
  for (const translatedPath of translatedFiles) {
21
21
  try {
22
+ // Check if translated file exists before processing
23
+ if (!fs.existsSync(translatedPath)) {
24
+ continue;
25
+ }
22
26
  // Find the corresponding source file
23
27
  const sourcePath = Object.keys(filesMap).find((key) => filesMap[key] === translatedPath);
24
28
  if (!sourcePath) {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Validates if an MDX file content can be parsed as a valid AST
3
+ * @param content - The MDX file content to validate
4
+ * @param filePath - The file path for error reporting
5
+ * @returns object with isValid boolean and optional error message
6
+ */
7
+ export declare function isValidMdx(content: string, filePath: string): {
8
+ isValid: boolean;
9
+ error?: string;
10
+ };
@@ -0,0 +1,25 @@
1
+ import { unified } from 'unified';
2
+ import remarkParse from 'remark-parse';
3
+ import remarkMdx from 'remark-mdx';
4
+ import remarkFrontmatter from 'remark-frontmatter';
5
+ /**
6
+ * Validates if an MDX file content can be parsed as a valid AST
7
+ * @param content - The MDX file content to validate
8
+ * @param filePath - The file path for error reporting
9
+ * @returns object with isValid boolean and optional error message
10
+ */
11
+ export function isValidMdx(content, filePath) {
12
+ try {
13
+ const parseProcessor = unified()
14
+ .use(remarkParse)
15
+ .use(remarkFrontmatter, ['yaml', 'toml'])
16
+ .use(remarkMdx);
17
+ const ast = parseProcessor.parse(content);
18
+ parseProcessor.runSync(ast);
19
+ return { isValid: true };
20
+ }
21
+ catch (error) {
22
+ const errorMessage = error instanceof Error ? error.message : String(error);
23
+ return { isValid: false, error: errorMessage };
24
+ }
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.1.14",
3
+ "version": "2.1.15",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [