gtx-cli 2.1.19 → 2.1.21

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,17 @@
1
1
  # gtx-cli
2
2
 
3
+ ## 2.1.21
4
+
5
+ ### Patch Changes
6
+
7
+ - [#645](https://github.com/generaltranslation/gt/pull/645) [`58cfaee`](https://github.com/generaltranslation/gt/commit/58cfaee5cc1dcd187f0b72b2761f96c19b4f313e) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Escaping HTML to avoid parsing issues from MDX consumers
8
+
9
+ ## 2.1.20
10
+
11
+ ### Patch Changes
12
+
13
+ - [#643](https://github.com/generaltranslation/gt/pull/643) [`4f553c0`](https://github.com/generaltranslation/gt/commit/4f553c00c119f272edc5ccb3616f2d0effec8586) Thanks [@fernando-aviles](https://github.com/fernando-aviles)! - Removing custom configuration on remarkStringify
14
+
3
15
  ## 2.1.19
4
16
 
5
17
  ### Patch Changes
@@ -5,7 +5,7 @@ import remarkFrontmatter from 'remark-frontmatter';
5
5
  import remarkStringify from 'remark-stringify';
6
6
  import { visit } from 'unist-util-visit';
7
7
  import { logWarning } from '../console/logging.js';
8
- import { encodeAnglePlaceholders } from './encodePlaceholders.js';
8
+ import { escapeHtmlInTextNodes } from './escapeHtml.js';
9
9
  /**
10
10
  * Generates a slug from heading text
11
11
  */
@@ -159,13 +159,13 @@ function applyInlineIds(translatedContent, idMappings) {
159
159
  // Add the ID to the heading
160
160
  const lastChild = heading.children[heading.children.length - 1];
161
161
  if (lastChild?.type === 'text') {
162
- lastChild.value += ` {#${id}}`;
162
+ lastChild.value += ` \\{#${id}\\}`;
163
163
  }
164
164
  else {
165
165
  // If last child is not text, add a new text node
166
166
  heading.children.push({
167
167
  type: 'text',
168
- value: ` {#${id}}`,
168
+ value: ` \\{#${id}\\}`,
169
169
  });
170
170
  }
171
171
  }
@@ -176,14 +176,8 @@ function applyInlineIds(translatedContent, idMappings) {
176
176
  const stringifyProcessor = unified()
177
177
  .use(remarkFrontmatter, ['yaml', 'toml'])
178
178
  .use(remarkMdx)
179
- .use(encodeAnglePlaceholders)
179
+ .use(escapeHtmlInTextNodes)
180
180
  .use(remarkStringify, {
181
- bullet: '-',
182
- emphasis: '_',
183
- strong: '*',
184
- rule: '-',
185
- ruleRepetition: 3,
186
- ruleSpaces: false,
187
181
  handlers: {
188
182
  // Custom handler to prevent escaping of {#id} syntax
189
183
  text(node) {
@@ -0,0 +1,8 @@
1
+ import type { Plugin } from 'unified';
2
+ import type { Root } from 'mdast';
3
+ /**
4
+ * Escape HTML-sensitive characters (`&`, `<`, `>`, `"`, `'`) in text nodes,
5
+ * leaving code, math, MDX expressions, and front-matter untouched.
6
+ * Ensures literals render safely without altering already-escaped entities.
7
+ */
8
+ export declare const escapeHtmlInTextNodes: Plugin<[], Root>;
@@ -0,0 +1,32 @@
1
+ import { findAndReplace } from 'mdast-util-find-and-replace';
2
+ const IGNORE_PARENTS = [
3
+ 'code',
4
+ 'inlineCode',
5
+ 'mdxFlowExpression',
6
+ 'mdxTextExpression',
7
+ 'mdxjsEsm',
8
+ 'heading',
9
+ 'yaml',
10
+ 'toml',
11
+ 'math',
12
+ 'inlineMath',
13
+ ];
14
+ // & that is NOT already an entity: &word; &#123; &#x1A2B;
15
+ const AMP_NOT_ENTITY = /&(?![a-zA-Z][a-zA-Z0-9]*;|#\d+;|#x[0-9A-Fa-f]+;)/g;
16
+ /**
17
+ * Escape HTML-sensitive characters (`&`, `<`, `>`, `"`, `'`) in text nodes,
18
+ * leaving code, math, MDX expressions, and front-matter untouched.
19
+ * Ensures literals render safely without altering already-escaped entities.
20
+ */
21
+ export const escapeHtmlInTextNodes = function () {
22
+ return (tree) => {
23
+ findAndReplace(tree, [
24
+ // Order matters: & first (idempotency), then the rest
25
+ [AMP_NOT_ENTITY, '&amp;'],
26
+ [/</g, '&lt;'],
27
+ [/>/g, '&gt;'],
28
+ [/"/g, '&quot;'],
29
+ [/'/g, '&#39;'],
30
+ ], { ignore: IGNORE_PARENTS });
31
+ };
32
+ };
@@ -7,7 +7,7 @@ import remarkMdx from 'remark-mdx';
7
7
  import remarkFrontmatter from 'remark-frontmatter';
8
8
  import remarkStringify from 'remark-stringify';
9
9
  import { visit } from 'unist-util-visit';
10
- import { encodeAnglePlaceholders } from './encodePlaceholders.js';
10
+ import { escapeHtmlInTextNodes } from './escapeHtml.js';
11
11
  const { isMatch } = micromatch;
12
12
  /**
13
13
  * Localizes static urls in content files.
@@ -373,14 +373,8 @@ function transformMdxUrls(mdxContent, defaultLocale, targetLocale, hideDefaultLo
373
373
  const stringifyProcessor = unified()
374
374
  .use(remarkFrontmatter, ['yaml', 'toml'])
375
375
  .use(remarkMdx)
376
- .use(encodeAnglePlaceholders)
376
+ .use(escapeHtmlInTextNodes)
377
377
  .use(remarkStringify, {
378
- bullet: '-',
379
- emphasis: '_',
380
- strong: '*',
381
- rule: '-',
382
- ruleRepetition: 3,
383
- ruleSpaces: false,
384
378
  handlers: {
385
379
  // Handler to prevent escaping (avoids '&lt;' -> '\&lt;')
386
380
  text(node) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtx-cli",
3
- "version": "2.1.19",
3
+ "version": "2.1.21",
4
4
  "main": "dist/index.js",
5
5
  "bin": "dist/main.js",
6
6
  "files": [
@@ -1,11 +0,0 @@
1
- import type { Plugin } from 'unified';
2
- import type { Root } from 'mdast';
3
- /**
4
- * Re-encode angle-bracket placeholders like <accountName> -> &lt;accountName&gt;
5
- * in plain text, to prevent MDX JSX parsing on re-parse.
6
- *
7
- * - Only touches Text nodes.
8
- * - Idempotent: already-encoded entities are left unchanged.
9
- * - Does NOT affect actual MDX/JSX elements because those are not text nodes.
10
- */
11
- export declare const encodeAnglePlaceholders: Plugin<[], Root>;
@@ -1,30 +0,0 @@
1
- import { findAndReplace } from 'mdast-util-find-and-replace';
2
- const IGNORE_PARENTS = [
3
- 'code',
4
- 'inlineCode',
5
- 'mdxFlowExpression',
6
- 'mdxTextExpression',
7
- 'mdxjsEsm',
8
- 'yaml',
9
- 'toml',
10
- 'math',
11
- 'inlineMath',
12
- ];
13
- /**
14
- * Re-encode angle-bracket placeholders like <accountName> -> &lt;accountName&gt;
15
- * in plain text, to prevent MDX JSX parsing on re-parse.
16
- *
17
- * - Only touches Text nodes.
18
- * - Idempotent: already-encoded entities are left unchanged.
19
- * - Does NOT affect actual MDX/JSX elements because those are not text nodes.
20
- */
21
- export const encodeAnglePlaceholders = function () {
22
- return (tree) => {
23
- findAndReplace(tree, [
24
- [
25
- /<([A-Za-z][\w.-]*)>/g, // <content>, <con-tent>, <con.tent>, <con_tent>
26
- (_match, name) => `&lt;${name}&gt;`,
27
- ],
28
- ], { ignore: IGNORE_PARENTS });
29
- };
30
- };