Skip to content

Commit

Permalink
fix(FieldFormatters): normalize ^ and $ in regex
Browse files Browse the repository at this point in the history
  • Loading branch information
maxpatiiuk committed Jul 21, 2024
1 parent 5403155 commit 9b664c9
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { theories } from '../../../tests/utils';
import { exportsForTests } from '../spec';

const { trimRegexString, normalizeRegexString } = exportsForTests;

theories(trimRegexString, [
[[''], ''],
[['[a-z]{3,}.*'], '[a-z]{3,}.*'],
[['/^[a-z]{3,}.*$/'], '[a-z]{3,}.*'],
[['^\\d{3}$'], '\\d{3}'],
[['/^(KUI|KUBI|NHM)$/'], 'KUI|KUBI|NHM'],
]);

theories(normalizeRegexString, [
[[''], '/^$/'],
[['[a-z]{3,}.*'], '/^[a-z]{3,}.*$/'],
[['/^[a-z]{3,}.*$/'], '/^[a-z]{3,}.*$/'],
[['^\\d{3}$'], '/^\\d{3}$/'],
[['\\d{3}'], '/^\\d{3}$/'],
[['/\\d{3}/'], '/^\\d{3}$/'],
[['KUI|KUBI|NHM'], '/^(KUI|KUBI|NHM)$/'],
[['(KUI|KUBI)|NHM'], '/^((KUI|KUBI)|NHM)$/'],
]);
13 changes: 11 additions & 2 deletions specifyweb/frontend/js_src/lib/components/FieldFormatters/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Parse and use Specify 6 UI Formatters
* Parse and use field formatters
*/

import type { LocalizedString } from 'typesafe-i18n';
Expand Down Expand Up @@ -255,7 +255,16 @@ class RegexPart extends Part {
public readonly type = 'regex';

public get regex(): LocalizedString {
return this.placeholder;
let pattern: string = this.placeholder;
/*
* In UiFormatter.getRegex() we are adding ^ and $ as necessary, so trim
* them if they were present here
*/
if (pattern.startsWith('/')) pattern = pattern.slice(1);
if (pattern.startsWith('^')) pattern = pattern.slice(1);
if (pattern.endsWith('/')) pattern = pattern.slice(0, -1);
if (pattern.endsWith('$')) pattern = pattern.slice(0, -1);
return pattern as LocalizedString;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,56 @@ const formatterSpec = f.store(() =>
),
parts: pipe(
syncers.xmlChildren('field'),
syncers.map(syncers.object(partSpec()))
syncers.map(
pipe(
syncers.object(partSpec()),
syncer(
(part) => ({
...part,
placeholder:
part.type === 'regex'
? localized(trimRegexString(part.placeholder))
: part.placeholder,
}),
(part) => ({
...part,
placeholder:
part.type === 'regex'
? localized(normalizeRegexString(part.placeholder))
: part.placeholder,
})
)
)
)
),
})
);

/**
* Specify 6 expects the regex pattern to start with "/^" and end with "$/"
* because it parts each field part individually.
* In Specify 7, we construct a combined regex that parts all field parts at
* once.
* Thus we do not want the "^" and "$" to be part of the pattern as far as
* Specify 7 front-end is concerned, but we want it to be part of the pattern
* in the .xml to work with Specify 6.
*/
function trimRegexString(regexString: string): string {
let pattern = regexString;
if (pattern.startsWith('/')) pattern = pattern.slice(1);
if (pattern.startsWith('^')) pattern = pattern.slice(1);
if (pattern.endsWith('/')) pattern = pattern.slice(0, -1);
if (pattern.endsWith('$')) pattern = pattern.slice(0, -1);
if (pattern.startsWith('(') && pattern.endsWith(')'))
pattern = pattern.slice(1, -1);
return pattern;
}
function normalizeRegexString(regexString: string): string {
let pattern: string = trimRegexString(regexString);
if (pattern.includes('|')) pattern = `(${pattern})`;
return `/^${pattern}$/`;
}

const partSpec = f.store(() =>
createXmlSpec({
type: pipe(
Expand Down Expand Up @@ -179,3 +224,5 @@ function parseField(
return undefined;
} else return field;
}

export const exportsForTests = { trimRegexString, normalizeRegexString };
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ export async function scanUsages(
),
'Value:\n',
instances.at(-1)?.originalValue ?? valueString,
'\n',
].join('')
);
})
Expand Down
11 changes: 10 additions & 1 deletion specifyweb/specify/uiformatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,16 @@ def value_regexp(self) -> str:

class RegexField(Field):
def value_regexp(self) -> str:
return self.value
pattern = self.value
if pattern.startswith('/'):
pattern = pattern[1:]
if pattern.startswith('^'):
pattern = pattern[1:]
if pattern.endswith('/'):
pattern = pattern[:-1]
if pattern.endswith('$'):
pattern = pattern[:-1]
return pattern

class AlphaField(Field):
def value_regexp(self) -> str:
Expand Down

0 comments on commit 9b664c9

Please sign in to comment.