Skip to content

Commit eb5a549

Browse files
Fix CustomizableValues in code blocks when the parser splits the markers across tokens (#2197)
* Fix CustomizableValues in code blocks when the parser splits the markers across tokens * Move test page away from pipelines tutorials
1 parent 91f60f2 commit eb5a549

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

docs/2.0/docs/pipelines/tutorials/test.md renamed to docs/test-customizable-value.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ import CodeBlock from '@theme/CodeBlock';
55
<CustomizableValue id="test" />
66
```bash
77
mkdir -p $$test$$/<region>/$$test$$/foo
8+
```
9+
10+
```hcl
11+
"${$$test$$}"
812
```

src/theme/CodeBlock/Line/index.tsx

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,82 @@ import { cloneElement } from 'react';
55
import styles from './styles.module.css';
66
import CustomizableValue from '../../../components/CustomizableValue';
77

8+
/**
9+
* replaceCustomizeableValues takes a list of tokens and identifies customizable values
10+
* marked by a start and end token, '$$'.
11+
* It returns a new list of tokens with the customizable values replaced with a CustomizableValue component.
12+
* If a customizable value begins or ends in the middle of a token, the token is split into two tokens.
13+
*/
814
function replaceCustomizeableValues(tokens) {
15+
// The list of tokens including the customizable value components
916
let newTokens = [];
17+
// A string that is being built up to capture the content of the current token, used to create a new token
1018
let captured = '';
11-
let capturing = false;
12-
for (let token of tokens) {
19+
// A boolean indicating that we are currently within a customizable value
20+
let withinCustomizableValue = false;
21+
22+
// A boolean indicating that we should skip the first character of the next token
23+
let skipFirstChar = false;
24+
25+
// Loop over each token
26+
for (let i = 0; i < tokens.length; i++) {
27+
let token = tokens[i];
28+
let nextToken = i < tokens.length - 1 ? tokens[i + 1] : null;
29+
1330
let content = token.props.children;
14-
for (let i = 0; i < content.length; i++) {
15-
if (content[i] === '$' && i < content.length - 1 && content[i + 1] === '$') {
16-
if (capturing) {
31+
32+
// Loop over each character in the token
33+
let initialIndex = 0;
34+
if (skipFirstChar) {
35+
// Start the loop at 1 to skip the first character
36+
initialIndex = 1;
37+
skipFirstChar = false;
38+
}
39+
40+
for (let j = initialIndex; j < content.length; j++) {
41+
// The current charcter and the next character
42+
// The next character may be in the next token, so we need to look ahead
43+
let currentChar = content[j];
44+
let nextChar = j < content.length - 1 ? content[j + 1] : null;
45+
// Track if we used the next token to get the next character
46+
let usedNextToken = false;
47+
if (nextChar == null && nextToken != null && nextToken.props.children.length > 0) {
48+
nextChar = nextToken.props.children[0];
49+
usedNextToken = true;
50+
}
51+
52+
// If the current and next characters are both '$', we have found the start or end of a customizable value
53+
if (currentChar === '$' && nextChar === '$') {
54+
if (withinCustomizableValue) {
55+
// We have found the end of a customizable value, create a new token for the customizable value
1756
newTokens.push(
1857
<CustomizableValue
1958
key={captured + newTokens.length}
2059
id={captured}
2160
/>
2261
);
23-
} else {
62+
} else if (captured.length > 0) {
63+
// We have found the start of a customizable value, if we have captured any content, create a new token
64+
// to preserve the previous content
2465
let newToken = cloneElement(token, {key: newTokens.length}, captured)
2566
newTokens.push(newToken)
2667
}
2768

69+
// Reset the captured content and toggle the withinCustomizableValue flag
2870
captured = '';
29-
capturing = !capturing;
30-
i += 2;
31-
if (i >= content.length) {
71+
withinCustomizableValue = !withinCustomizableValue;
72+
// Skip the next two characters in this token, which will be the opening or closing $$
73+
j += 2;
74+
// If the marker was split across two tokens, we need to skip the first character of the next token
75+
// to remove it from the output
76+
skipFirstChar = usedNextToken;
77+
if (j >= content.length) {
3278
break;
3379
}
3480
}
35-
captured += content[i];
81+
captured += content[j];
3682
}
37-
if (captured.length > 0 && !capturing) {
83+
if (captured.length > 0 && !withinCustomizableValue) {
3884
let newToken = cloneElement(token, {key: newTokens.length}, captured)
3985
newTokens.push(newToken)
4086
captured = '';

0 commit comments

Comments
 (0)