Skip to content

Commit e156fa7

Browse files
fix(converter): parse attached SEQ format switches
1 parent 0c379b2 commit e156fa7

2 files changed

Lines changed: 73 additions & 9 deletions

File tree

packages/super-editor/src/editors/v1/core/super-converter/field-references/shared/seq-instruction.js

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { extractFieldKeyword } from '../field-keyword.js';
22
import { CASE_INSENSITIVE_GENERAL_FORMATS, GENERAL_FORMATS } from './page-number-field-switches.js';
33

4-
const TOKEN_PATTERN = /"((?:[^"\\]|\\.)*)"|\\[#*]|\\[^\s]+|[^\s]+/g;
4+
const TOKEN_PATTERN = /"((?:[^"\\]|\\.)*)"|\\[#*](?=\s|$)|\\[^\s]+|[^\s]+/g;
55

66
/**
77
* @typedef {'next' | 'current'} SeqMode
@@ -96,28 +96,30 @@ export function parseSeqInstruction(instruction) {
9696
continue;
9797
}
9898

99-
if (token === '\\*') {
100-
const value = tokens[index + 1]?.value;
101-
if (value != null && !value.startsWith('\\')) {
99+
const attachedGeneralFormat = parseAttachedGeneralFormatSwitch(token);
100+
if (normalized === '\\*' || attachedGeneralFormat != null) {
101+
const value = attachedGeneralFormat ?? tokens[index + 1]?.value;
102+
if (value != null && (attachedGeneralFormat != null || !value.startsWith('\\'))) {
102103
result.format = value;
103104
result.hasGeneralFormat = true;
104105
applyGeneralFormat(result, value);
105-
index += 1;
106+
if (attachedGeneralFormat == null) index += 1;
106107
} else {
107108
result.unknownSwitches.push(token);
108109
}
109110
continue;
110111
}
111112

112-
if (token === '\\#') {
113-
const value = tokens[index + 1]?.value;
114-
if (value != null && !value.startsWith('\\')) {
113+
const attachedNumericPicture = parseAttachedNumericPictureSwitch(token);
114+
if (normalized === '\\#' || attachedNumericPicture != null) {
115+
const value = attachedNumericPicture ?? tokens[index + 1]?.value;
116+
if (value != null && (attachedNumericPicture != null || !value.startsWith('\\'))) {
115117
if (result.numericPictureFormat == null) {
116118
result.numericPictureFormat = { picture: value };
117119
} else {
118120
result.unknownSwitches.push(token, value);
119121
}
120-
index += 1;
122+
if (attachedNumericPicture == null) index += 1;
121123
} else {
122124
result.unknownSwitches.push(token);
123125
}
@@ -240,6 +242,38 @@ function parseAttachedNumericSwitch(token) {
240242
};
241243
}
242244

245+
/**
246+
* Word can serialize general-format switches without a separating space
247+
* (`\*roman`). Normalize those into the same path as `\* roman`.
248+
*
249+
* @param {string} token
250+
*/
251+
function parseAttachedGeneralFormatSwitch(token) {
252+
const match = /^\\\*(\S+)$/.exec(token);
253+
return normalizeAttachedSwitchValue(match?.[1]);
254+
}
255+
256+
/**
257+
* Keep attached numeric picture switches (`\#00`) equivalent to `\# 00`.
258+
*
259+
* @param {string} token
260+
*/
261+
function parseAttachedNumericPictureSwitch(token) {
262+
const match = /^\\#(\S+)$/.exec(token);
263+
return normalizeAttachedSwitchValue(match?.[1]);
264+
}
265+
266+
/**
267+
* @param {string | undefined} value
268+
*/
269+
function normalizeAttachedSwitchValue(value) {
270+
if (value == null) return null;
271+
if (value.startsWith('"') && value.endsWith('"')) {
272+
return unescapeQuotedToken(value.slice(1, -1));
273+
}
274+
return value;
275+
}
276+
243277
/**
244278
* @param {ParsedSeqInstruction} result
245279
* @param {string} value

packages/super-editor/src/editors/v1/core/super-converter/field-references/shared/seq-instruction.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ describe('parseSeqInstruction', () => {
3131
pageNumberFieldFormat: { format: 'lowerRoman' },
3232
},
3333
],
34+
[
35+
'SEQ Figure \\*roman',
36+
{
37+
identifier: 'Figure',
38+
format: 'roman',
39+
hasGeneralFormat: true,
40+
pageNumberFieldFormat: { format: 'lowerRoman' },
41+
},
42+
],
43+
[
44+
'seq level2 \\*arabic',
45+
{
46+
keyword: 'seq',
47+
identifier: 'level2',
48+
format: 'arabic',
49+
hasGeneralFormat: true,
50+
pageNumberFieldFormat: { format: 'decimal' },
51+
},
52+
],
53+
[
54+
'SEQ Figure \\*"Roman"',
55+
{
56+
identifier: 'Figure',
57+
format: 'Roman',
58+
hasGeneralFormat: true,
59+
pageNumberFieldFormat: { format: 'upperRoman' },
60+
},
61+
],
3462
[
3563
'SEQ Figure \\* ALPHABETIC',
3664
{
@@ -50,6 +78,8 @@ describe('parseSeqInstruction', () => {
5078
},
5179
],
5280
['SEQ Figure \\# "00"', { identifier: 'Figure', numericPictureFormat: { picture: '00' } }],
81+
['SEQ Figure \\#00', { identifier: 'Figure', numericPictureFormat: { picture: '00' } }],
82+
['SEQ Figure \\#"00"', { identifier: 'Figure', numericPictureFormat: { picture: '00' } }],
5383
['SEQ Figure \\# "#,##0"', { identifier: 'Figure', numericPictureFormat: { picture: '#,##0' } }],
5484
[
5585
'SEQ Figure \\r 10 \\* roman \\h',

0 commit comments

Comments
 (0)