@wix/patterns-fields 1.93.0 → 1.95.0
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/dist/cjs/components/address/input/address-input.st.css.js +3 -3
- package/dist/cjs/components/address/input/address-input.st.css.js.map +1 -1
- package/dist/cjs/components/audio/actions/actions-menu/actions-menu.st.css.js +3 -3
- package/dist/cjs/components/audio/actions/actions-menu/actions-menu.st.css.js.map +1 -1
- package/dist/cjs/components/audio/audio-field/form-audio-field.st.css.js +4 -4
- package/dist/cjs/components/audio/audio-field/form-audio-field.st.css.js.map +1 -1
- package/dist/cjs/components/audio/audio-player/audio-player.st.css.js +2 -2
- package/dist/cjs/components/audio/audio-player/audio-player.st.css.js.map +1 -1
- package/dist/cjs/components/color-view/cell-color-view.st.css.js +3 -3
- package/dist/cjs/components/color-view/cell-color-view.st.css.js.map +1 -1
- package/dist/cjs/components/color-view/color-view.st.css.js +4 -4
- package/dist/cjs/components/color-view/color-view.st.css.js.map +1 -1
- package/dist/cjs/components/delete-dialog/delete-dialog.st.css.js +3 -3
- package/dist/cjs/components/delete-dialog/delete-dialog.st.css.js.map +1 -1
- package/dist/cjs/components/document/form-document-field.st.css.js +7 -7
- package/dist/cjs/components/document/form-document-field.st.css.js.map +1 -1
- package/dist/cjs/components/exclamation/exclamation.st.css.js +5 -5
- package/dist/cjs/components/exclamation/exclamation.st.css.js.map +1 -1
- package/dist/cjs/components/field-validation-settings/field-validation-settings-input.js +9 -8
- package/dist/cjs/components/field-validation-settings/field-validation-settings-input.js.map +1 -1
- package/dist/cjs/components/highlighted-text/highlighted-text.st.css.js +5 -5
- package/dist/cjs/components/highlighted-text/highlighted-text.st.css.js.map +1 -1
- package/dist/cjs/components/image/thumbnail-replace-overlay.st.css.js +3 -3
- package/dist/cjs/components/image/thumbnail-replace-overlay.st.css.js.map +1 -1
- package/dist/cjs/components/media-control/cell-media-edit-shell.st.css.js +2 -2
- package/dist/cjs/components/media-control/cell-media-edit-shell.st.css.js.map +1 -1
- package/dist/cjs/components/media-control/paste-url-button.st.css.js +4 -4
- package/dist/cjs/components/media-control/paste-url-button.st.css.js.map +1 -1
- package/dist/cjs/components/media-gallery/form-media-gallery-field.st.css.js +10 -10
- package/dist/cjs/components/media-gallery/form-media-gallery-field.st.css.js.map +1 -1
- package/dist/cjs/components/media-image/media-image.st.css.js +4 -4
- package/dist/cjs/components/media-image/media-image.st.css.js.map +1 -1
- package/dist/cjs/components/media-image/overlays/overlay.st.css.js +3 -3
- package/dist/cjs/components/media-image/overlays/overlay.st.css.js.map +1 -1
- package/dist/cjs/components/media-loader/media-loader.st.css.js +3 -3
- package/dist/cjs/components/media-loader/media-loader.st.css.js.map +1 -1
- package/dist/cjs/components/media-tag/web-media-tag/media-tag.st.css.js +2 -2
- package/dist/cjs/components/media-tag/web-media-tag/media-tag.st.css.js.map +1 -1
- package/dist/cjs/components/multi-document/cell-multi-document-edit.st.css.js +3 -3
- package/dist/cjs/components/multi-document/cell-multi-document-edit.st.css.js.map +1 -1
- package/dist/cjs/components/multi-document/multi-document-input/form-multi-document.st.css.js +5 -5
- package/dist/cjs/components/multi-document/multi-document-input/form-multi-document.st.css.js.map +1 -1
- package/dist/cjs/components/reference/cell-multi-reference-input.st.css.js +2 -2
- package/dist/cjs/components/reference/cell-multi-reference-input.st.css.js.map +1 -1
- package/dist/cjs/components/reference/cell-reference-input.st.css.js +3 -3
- package/dist/cjs/components/reference/cell-reference-input.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js +4 -4
- package/dist/cjs/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js +3 -3
- package/dist/cjs/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js +2 -2
- package/dist/cjs/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js +3 -3
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js +3 -3
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js +2 -2
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js +7 -7
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js +5 -5
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js.map +1 -1
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js +4 -4
- package/dist/cjs/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js.map +1 -1
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js +18 -18
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js.map +1 -1
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js +4 -4
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js.map +1 -1
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js +18 -18
- package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js.map +1 -1
- package/dist/cjs/components/text/form-long-text.js +14 -6
- package/dist/cjs/components/text/form-long-text.js.map +1 -1
- package/dist/cjs/components/text/form-short-text.js +15 -7
- package/dist/cjs/components/text/form-short-text.js.map +1 -1
- package/dist/cjs/components/text/text-view.st.css.js +3 -3
- package/dist/cjs/components/text/text-view.st.css.js.map +1 -1
- package/dist/cjs/components/url/form-url.js +20 -8
- package/dist/cjs/components/url/form-url.js.map +1 -1
- package/dist/cjs/styles.global.css +1 -1
- package/dist/cjs/types/validation.js.map +1 -1
- package/dist/cjs/validations/field-validation-settings.js +21 -11
- package/dist/cjs/validations/field-validation-settings.js.map +1 -1
- package/dist/cjs/validations/regex-safety.js +255 -0
- package/dist/cjs/validations/regex-safety.js.map +1 -0
- package/dist/esm/components/address/input/address-input.st.css.js +2 -2
- package/dist/esm/components/audio/actions/actions-menu/actions-menu.st.css.js +2 -2
- package/dist/esm/components/audio/audio-field/form-audio-field.st.css.js +2 -2
- package/dist/esm/components/audio/audio-field/form-audio-field.st.css.js.map +1 -1
- package/dist/esm/components/audio/audio-player/audio-player.st.css.js +2 -2
- package/dist/esm/components/audio/audio-player/audio-player.st.css.js.map +1 -1
- package/dist/esm/components/color-view/cell-color-view.st.css.js +2 -2
- package/dist/esm/components/color-view/cell-color-view.st.css.js.map +1 -1
- package/dist/esm/components/color-view/color-view.st.css.js +2 -2
- package/dist/esm/components/color-view/color-view.st.css.js.map +1 -1
- package/dist/esm/components/delete-dialog/delete-dialog.st.css.js +2 -2
- package/dist/esm/components/delete-dialog/delete-dialog.st.css.js.map +1 -1
- package/dist/esm/components/document/form-document-field.st.css.js +2 -2
- package/dist/esm/components/document/form-document-field.st.css.js.map +1 -1
- package/dist/esm/components/exclamation/exclamation.st.css.js +2 -2
- package/dist/esm/components/field-validation-settings/field-validation-settings-input.js +8 -3
- package/dist/esm/components/field-validation-settings/field-validation-settings-input.js.map +1 -1
- package/dist/esm/components/highlighted-text/highlighted-text.st.css.js +3 -3
- package/dist/esm/components/image/thumbnail-replace-overlay.st.css.js +2 -2
- package/dist/esm/components/media-control/cell-media-edit-shell.st.css.js +2 -2
- package/dist/esm/components/media-control/paste-url-button.st.css.js +2 -2
- package/dist/esm/components/media-gallery/form-media-gallery-field.st.css.js +2 -2
- package/dist/esm/components/media-image/media-image.st.css.js +3 -3
- package/dist/esm/components/media-image/media-image.st.css.js.map +1 -1
- package/dist/esm/components/media-image/overlays/overlay.st.css.js +2 -2
- package/dist/esm/components/media-loader/media-loader.st.css.js +2 -2
- package/dist/esm/components/media-tag/web-media-tag/media-tag.st.css.js +2 -2
- package/dist/esm/components/multi-document/cell-multi-document-edit.st.css.js +2 -2
- package/dist/esm/components/multi-document/cell-multi-document-edit.st.css.js.map +1 -1
- package/dist/esm/components/multi-document/multi-document-input/form-multi-document.st.css.js +2 -2
- package/dist/esm/components/multi-document/multi-document-input/form-multi-document.st.css.js.map +1 -1
- package/dist/esm/components/reference/cell-multi-reference-input.st.css.js +2 -2
- package/dist/esm/components/reference/cell-multi-reference-input.st.css.js.map +1 -1
- package/dist/esm/components/reference/cell-reference-input.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js.map +1 -1
- package/dist/esm/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js.map +1 -1
- package/dist/esm/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js +2 -2
- package/dist/esm/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js +2 -2
- package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js +2 -2
- package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js +2 -2
- package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js +2 -2
- package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js.map +1 -1
- package/dist/esm/components/text/form-long-text.js +5 -0
- package/dist/esm/components/text/form-long-text.js.map +1 -1
- package/dist/esm/components/text/form-short-text.js +5 -0
- package/dist/esm/components/text/form-short-text.js.map +1 -1
- package/dist/esm/components/text/text-view.st.css.js +2 -2
- package/dist/esm/components/text/text-view.st.css.js.map +1 -1
- package/dist/esm/components/url/form-url.js +10 -2
- package/dist/esm/components/url/form-url.js.map +1 -1
- package/dist/esm/styles.global.css +1 -1
- package/dist/esm/validations/field-validation-settings.js +17 -11
- package/dist/esm/validations/field-validation-settings.js.map +1 -1
- package/dist/esm/validations/regex-safety.js +241 -0
- package/dist/esm/validations/regex-safety.js.map +1 -0
- package/dist/types/components/audio/audio-field/form-audio-field.st.css.d.ts.map +1 -1
- package/dist/types/components/audio/audio-player/audio-player.st.css.d.ts.map +1 -1
- package/dist/types/components/color-view/cell-color-view.st.css.d.ts.map +1 -1
- package/dist/types/components/color-view/color-view.st.css.d.ts.map +1 -1
- package/dist/types/components/delete-dialog/delete-dialog.st.css.d.ts.map +1 -1
- package/dist/types/components/document/form-document-field.st.css.d.ts.map +1 -1
- package/dist/types/components/field-validation-settings/field-validation-settings-input.d.ts.map +1 -1
- package/dist/types/components/media-image/media-image.st.css.d.ts.map +1 -1
- package/dist/types/components/multi-document/cell-multi-document-edit.st.css.d.ts.map +1 -1
- package/dist/types/components/multi-document/multi-document-input/form-multi-document.st.css.d.ts.map +1 -1
- package/dist/types/components/reference/cell-multi-reference-input.st.css.d.ts.map +1 -1
- package/dist/types/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.d.ts.map +1 -1
- package/dist/types/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.d.ts.map +1 -1
- package/dist/types/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.d.ts.map +1 -1
- package/dist/types/components/text/form-long-text.d.ts.map +1 -1
- package/dist/types/components/text/form-short-text.d.ts.map +1 -1
- package/dist/types/components/text/text-view.st.css.d.ts.map +1 -1
- package/dist/types/components/url/form-url.d.ts.map +1 -1
- package/dist/types/types/validation.d.ts +4 -1
- package/dist/types/types/validation.d.ts.map +1 -1
- package/dist/types/validations/field-validation-settings.d.ts +2 -0
- package/dist/types/validations/field-validation-settings.d.ts.map +1 -1
- package/dist/types/validations/regex-safety.d.ts +17 -0
- package/dist/types/validations/regex-safety.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/__tests__/components/field-validation-settings/field-validation-settings-input.spec.tsx +42 -1
- package/src/__tests__/components/field-validation-settings/pattern-round-trip.spec.tsx +37 -0
- package/src/__tests__/components/text/form-long-text.spec.tsx +55 -0
- package/src/__tests__/components/text/form-short-text.spec.tsx +85 -0
- package/src/__tests__/components/url/form-url.spec.tsx +44 -0
- package/src/__tests__/validations/field-validation-settings-pattern.spec.ts +87 -0
- package/src/__tests__/validations/regex-safety.spec.ts +71 -0
- package/src/components/address/input/address-input.st.css.ts +2 -2
- package/src/components/audio/actions/actions-menu/actions-menu.st.css.ts +2 -2
- package/src/components/audio/audio-field/form-audio-field.st.css.ts +2 -2
- package/src/components/audio/audio-player/audio-player.st.css.ts +2 -2
- package/src/components/color-view/cell-color-view.st.css.ts +2 -2
- package/src/components/color-view/color-view.st.css.ts +2 -2
- package/src/components/delete-dialog/delete-dialog.st.css.ts +2 -2
- package/src/components/document/form-document-field.st.css.ts +2 -2
- package/src/components/exclamation/exclamation.st.css.ts +2 -2
- package/src/components/field-validation-settings/field-validation-settings-input.tsx +10 -6
- package/src/components/highlighted-text/highlighted-text.st.css.ts +3 -3
- package/src/components/image/thumbnail-replace-overlay.st.css.ts +2 -2
- package/src/components/media-control/cell-media-edit-shell.st.css.ts +2 -2
- package/src/components/media-control/paste-url-button.st.css.ts +2 -2
- package/src/components/media-gallery/form-media-gallery-field.st.css.ts +2 -2
- package/src/components/media-image/media-image.st.css.ts +3 -3
- package/src/components/media-image/overlays/overlay.st.css.ts +2 -2
- package/src/components/media-loader/media-loader.st.css.ts +2 -2
- package/src/components/media-tag/web-media-tag/media-tag.st.css.ts +2 -2
- package/src/components/multi-document/cell-multi-document-edit.st.css.ts +2 -2
- package/src/components/multi-document/multi-document-input/form-multi-document.st.css.ts +2 -2
- package/src/components/reference/cell-multi-reference-input.st.css.ts +2 -2
- package/src/components/reference/cell-reference-input.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.ts +2 -2
- package/src/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.ts +2 -2
- package/src/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.ts +2 -2
- package/src/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.ts +2 -2
- package/src/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.ts +2 -2
- package/src/components/text/form-long-text.tsx +9 -0
- package/src/components/text/form-short-text.tsx +9 -0
- package/src/components/text/text-view.st.css.ts +2 -2
- package/src/components/url/form-url.tsx +18 -2
- package/src/styles.global.css +1 -1
- package/src/types/validation.ts +4 -1
- package/src/validations/field-validation-settings.ts +30 -12
- package/src/validations/regex-safety.ts +297 -0
|
@@ -45,6 +45,9 @@ export interface PatternFieldValidationRuleConfig {
|
|
|
45
45
|
tooltip: string;
|
|
46
46
|
inputLabel: string;
|
|
47
47
|
invalidError: string;
|
|
48
|
+
/** Shown for a pattern that compiles but is refused because matching it
|
|
49
|
+
* could hang the page. Falls back to `invalidError`. */
|
|
50
|
+
unsafeError?: string;
|
|
48
51
|
}
|
|
49
52
|
export type FieldValidationRuleConfig = RequiredFieldValidationRuleConfig | CharactersLimitFieldValidationRuleConfig | SpecificValuesFieldValidationRuleConfig | PatternFieldValidationRuleConfig;
|
|
50
53
|
export type FieldValidationRule = FieldValidationRuleConfig['type'];
|
|
@@ -75,7 +78,7 @@ export type FieldValidationViolation = {
|
|
|
75
78
|
type: 'exclusiveRules';
|
|
76
79
|
} | {
|
|
77
80
|
rule: 'pattern';
|
|
78
|
-
type: 'invalidPattern';
|
|
81
|
+
type: 'invalidPattern' | 'unsafePattern';
|
|
79
82
|
};
|
|
80
83
|
export type DataValidationRules = Partial<RequiredValidationRule & CharactersLimitValidationRule & SpecificValuesValidationRule & PatternValidationRule>;
|
|
81
84
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/types/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,WAAW,iCAAiC;IAChD,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACnD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uCAAuC;IACtD,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,yBAAyB,GACjC,iCAAiC,GACjC,wCAAwC,GACxC,uCAAuC,GACvC,gCAAgC,CAAC;AAErC,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAEpE,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,wBAAwB,GAChC;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,GACD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,aAAa,CAAA;CAAE,GAChD;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB,GACD;IACE,IAAI,EAAE,gBAAgB,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACvD,IAAI,EAAE,gBAAgB,CAAC;CACxB,GACD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/types/validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { FieldValidationRule, FieldValidationSettingsValue, FieldValidationViolation } from '../types/validation';
|
|
2
|
+
export declare const compilePattern: (pattern: string | undefined) => RegExp | undefined;
|
|
3
|
+
export declare const matchesPattern: (value: string, pattern: string | undefined) => boolean;
|
|
2
4
|
export interface FieldValidationSettingsOptions {
|
|
3
5
|
/** Whether `specificValues` rejects `charactersLimit`/`pattern` on the same
|
|
4
6
|
* field. Callers that let a field carry both (e.g. a stored
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-validation-settings.d.ts","sourceRoot":"","sources":["../../../src/validations/field-validation-settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,4BAA4B,EAC5B,wBAAwB,EACzB,MAAM,qBAAqB,CAAC;AA4B7B,MAAM,WAAW,8BAA8B;IAC7C;;+EAE2E;IAC3E,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,eAAO,MAAM,oCAAoC,GAC/C,OAAO,4BAA4B,EACnC,iBAAiB,SAAS,mBAAmB,EAAE,EAC/C,8BAAoC,8BAAmC,KACtE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"field-validation-settings.d.ts","sourceRoot":"","sources":["../../../src/validations/field-validation-settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,4BAA4B,EAC5B,wBAAwB,EACzB,MAAM,qBAAqB,CAAC;AA4B7B,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,GAAG,SAAS,KAC1B,MAAM,GAAG,SAC2D,CAAC;AAKxE,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,SAAS,MAAM,GAAG,SAAS,KAC1B,OAAuD,CAAC;AAE3D,MAAM,WAAW,8BAA8B;IAC7C;;+EAE2E;IAC3E,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,eAAO,MAAM,oCAAoC,GAC/C,OAAO,4BAA4B,EACnC,iBAAiB,SAAS,mBAAmB,EAAE,EAC/C,8BAAoC,8BAAmC,KACtE,wBAAwB,EAiG1B,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,OAAO,4BAA4B,EACnC,iBAAiB,SAAS,mBAAmB,EAAE,EAC/C,UAAU,8BAA8B,YAGvC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether `pattern` can backtrack catastrophically — an unbounded quantifier
|
|
3
|
+
* applied to a group that can divide the same input more than one way, as in
|
|
4
|
+
* `(a+)+`. That is the shape whose match time grows exponentially with input
|
|
5
|
+
* length, so a 7-character pattern can hang the tab on a 28-character value.
|
|
6
|
+
*
|
|
7
|
+
* A group is safe to repeat when each iteration must consume something fixed
|
|
8
|
+
* that the varying parts cannot also consume: `(?:-[a-z0-9]+)*` has to eat a
|
|
9
|
+
* literal `-` every time round, which pins the iterations apart and keeps
|
|
10
|
+
* matching linear. A mandatory atom the varying part could eat instead — the
|
|
11
|
+
* second `a` in `(a+a)+` — pins nothing.
|
|
12
|
+
*
|
|
13
|
+
* Conservative on purpose: it proves nothing about linearity, and rejects some
|
|
14
|
+
* patterns that would in fact have run fine.
|
|
15
|
+
*/
|
|
16
|
+
export declare const hasNestedQuantifier: (pattern: string) => boolean;
|
|
17
|
+
//# sourceMappingURL=regex-safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regex-safety.d.ts","sourceRoot":"","sources":["../../../src/validations/regex-safety.ts"],"names":[],"mappings":"AAuNA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,OAkErD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/patterns-fields",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.95.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kobi",
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"@wix/atlas": "^1.0.35",
|
|
125
125
|
"@wix/data": "^1.0.323",
|
|
126
126
|
"@wix/media": "^1.0.231",
|
|
127
|
-
"@wix/patterns-fields-utils": "1.
|
|
127
|
+
"@wix/patterns-fields-utils": "1.76.0",
|
|
128
128
|
"@wix/rich-content": "1.0.37",
|
|
129
129
|
"@wix/sdk": "^1.17.2",
|
|
130
130
|
"@wix/wix-ui-icons-common": "^3.189.0",
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
"@types/lodash": "^4.17.20",
|
|
153
153
|
"@types/react": "^16.14.68",
|
|
154
154
|
"@wix/babel-cli": "^1.11.0",
|
|
155
|
-
"@wix/bex-core": "2.
|
|
155
|
+
"@wix/bex-core": "2.373.0",
|
|
156
156
|
"@wix/design-system": "^1.319.0",
|
|
157
157
|
"@wix/eslint-config-yoshi": "^6.74.0",
|
|
158
158
|
"@wix/jest-yoshi-preset": "^6.74.0",
|
|
@@ -212,5 +212,5 @@
|
|
|
212
212
|
"optional": true
|
|
213
213
|
}
|
|
214
214
|
},
|
|
215
|
-
"falconPackageHash": "
|
|
215
|
+
"falconPackageHash": "9c2ac5fb91ff026ebe41371d62f5779cf05f0e651e888457449fe55d"
|
|
216
216
|
}
|
package/src/__tests__/components/field-validation-settings/field-validation-settings-input.spec.tsx
CHANGED
|
@@ -72,7 +72,12 @@ interface RenderInputOptions {
|
|
|
72
72
|
|
|
73
73
|
const renderInput = (
|
|
74
74
|
initialData: FieldValidationSettingsValue,
|
|
75
|
-
{
|
|
75
|
+
{
|
|
76
|
+
rules = allRules,
|
|
77
|
+
readOnly,
|
|
78
|
+
invalid,
|
|
79
|
+
disabledRules,
|
|
80
|
+
}: RenderInputOptions = {},
|
|
76
81
|
) => {
|
|
77
82
|
const onChange = jest.fn<void, [FieldValidationSettingsValue]>();
|
|
78
83
|
|
|
@@ -142,6 +147,42 @@ describe('FieldValidationSettingsInput', () => {
|
|
|
142
147
|
expect(await driver.getSpecificValuesToggle().exists()).toBe(false);
|
|
143
148
|
});
|
|
144
149
|
|
|
150
|
+
it('shows the invalid-pattern error for a pattern that cannot compile', async () => {
|
|
151
|
+
const { driver } = renderInput({ pattern: '[' }, { rules: [patternRule] });
|
|
152
|
+
|
|
153
|
+
expect(await driver.getPatternInput().hasStatus('error')).toBe(true);
|
|
154
|
+
expect(await driver.getPatternInput().getStatusMessage()).toBe(
|
|
155
|
+
'Enter a valid regular expression.',
|
|
156
|
+
);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('shows an error for a pattern that compiles but could hang the page', async () => {
|
|
160
|
+
const { driver } = renderInput(
|
|
161
|
+
{ pattern: '^(a+)+$' },
|
|
162
|
+
{
|
|
163
|
+
rules: [
|
|
164
|
+
{ ...patternRule, unsafeError: 'This expression is too complex.' },
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
expect(await driver.getPatternInput().hasStatus('error')).toBe(true);
|
|
170
|
+
expect(await driver.getPatternInput().getStatusMessage()).toBe(
|
|
171
|
+
'This expression is too complex.',
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('falls back to the invalid-pattern copy when no unsafe copy is given', async () => {
|
|
176
|
+
const { driver } = renderInput(
|
|
177
|
+
{ pattern: '^(a+)+$' },
|
|
178
|
+
{ rules: [patternRule] },
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect(await driver.getPatternInput().getStatusMessage()).toBe(
|
|
182
|
+
'Enter a valid regular expression.',
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
145
186
|
it('does not explain exclusivity when no conflicting rule is configured', async () => {
|
|
146
187
|
const { driver } = renderInput(
|
|
147
188
|
{ specificValues: [] },
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import '../../../testkit/test-polyfills';
|
|
2
|
+
|
|
3
|
+
import type { Field } from '@wix/bex-core';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
getFieldValidationSettingsViolations,
|
|
7
|
+
matchesPattern,
|
|
8
|
+
} from '../../../validations/field-validation-settings';
|
|
9
|
+
|
|
10
|
+
describe('pattern rule round trip', () => {
|
|
11
|
+
const pattern = '^[A-Z]{3}-\\d{4}$';
|
|
12
|
+
|
|
13
|
+
it('authors a pattern the field model can carry', () => {
|
|
14
|
+
expect(getFieldValidationSettingsViolations({ pattern })).toEqual([]);
|
|
15
|
+
|
|
16
|
+
const field: Field = {
|
|
17
|
+
id: 'sku',
|
|
18
|
+
displayName: 'SKU',
|
|
19
|
+
type: 'SHORT_TEXT',
|
|
20
|
+
validation: { required: false, pattern },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
expect(field.validation?.pattern).toBe(pattern);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('enforces the carried pattern against values', () => {
|
|
27
|
+
expect(matchesPattern('ABC-1234', pattern)).toBe(true);
|
|
28
|
+
expect(matchesPattern('abc-1234', pattern)).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('refuses to author a pattern the matcher would have to ignore', () => {
|
|
32
|
+
expect(
|
|
33
|
+
getFieldValidationSettingsViolations({ pattern: '[' }),
|
|
34
|
+
).toContainEqual({ rule: 'pattern', type: 'invalidPattern' });
|
|
35
|
+
expect(matchesPattern('anything', '[')).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -60,4 +60,59 @@ describe('FormLongText field', () => {
|
|
|
60
60
|
'cairo.fieldValidation.requiredField',
|
|
61
61
|
);
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
it('shows a pattern error when the value does not match', async () => {
|
|
65
|
+
const driver = setup({
|
|
66
|
+
field: makeField({
|
|
67
|
+
type: 'LONG_TEXT',
|
|
68
|
+
validation: { required: false, pattern: '^[A-Z]+$' },
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await driver.tk.enterText('abc');
|
|
73
|
+
|
|
74
|
+
expect(await driver.tk.hasError()).toBe(true);
|
|
75
|
+
expect(await driver.tk.getErrorMessage()).toBe(
|
|
76
|
+
'cairo.fieldValidation.patternMismatch',
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('accepts a value that matches the pattern', async () => {
|
|
81
|
+
const driver = setup({
|
|
82
|
+
field: makeField({
|
|
83
|
+
type: 'LONG_TEXT',
|
|
84
|
+
validation: { required: false, pattern: '^[A-Z]+$' },
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await driver.tk.enterText('ABC');
|
|
89
|
+
|
|
90
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('does not apply a pattern to an empty value', async () => {
|
|
94
|
+
const driver = setup({
|
|
95
|
+
field: makeField({
|
|
96
|
+
type: 'LONG_TEXT',
|
|
97
|
+
validation: { required: false, pattern: '^[A-Z]+$' },
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await driver.tk.enterText('');
|
|
102
|
+
|
|
103
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('enforces nothing when the pattern is refused', async () => {
|
|
107
|
+
const driver = setup({
|
|
108
|
+
field: makeField({
|
|
109
|
+
type: 'LONG_TEXT',
|
|
110
|
+
validation: { required: false, pattern: '^(a+)+$' },
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await driver.tk.enterText('a'.repeat(30));
|
|
115
|
+
|
|
116
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
117
|
+
});
|
|
63
118
|
});
|
|
@@ -167,4 +167,89 @@ describe('FormShortText field', () => {
|
|
|
167
167
|
'Title must be one of the allowed values',
|
|
168
168
|
);
|
|
169
169
|
});
|
|
170
|
+
|
|
171
|
+
it('shows a pattern error when the value does not match', async () => {
|
|
172
|
+
const driver = setup({
|
|
173
|
+
field: makeField({
|
|
174
|
+
validation: { required: false, pattern: '^[A-Z]{3}$' },
|
|
175
|
+
}),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
await driver.tk.enterText('abc');
|
|
179
|
+
|
|
180
|
+
expect(await driver.tk.hasError()).toBe(true);
|
|
181
|
+
expect(await driver.tk.getErrorMessage()).toBe(
|
|
182
|
+
'cairo.fieldValidation.patternMismatch',
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('accepts a value that matches the pattern', async () => {
|
|
187
|
+
const driver = setup({
|
|
188
|
+
field: makeField({
|
|
189
|
+
validation: { required: false, pattern: '^[A-Z]{3}$' },
|
|
190
|
+
}),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await driver.tk.enterText('ABC');
|
|
194
|
+
|
|
195
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('does not apply a pattern to an empty value', async () => {
|
|
199
|
+
const driver = setup({
|
|
200
|
+
field: makeField({
|
|
201
|
+
validation: { required: false, pattern: '^[A-Z]{3}$' },
|
|
202
|
+
}),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await driver.tk.enterText('');
|
|
206
|
+
|
|
207
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('reports the length error before the pattern error', async () => {
|
|
211
|
+
const driver = setup({
|
|
212
|
+
field: makeField({
|
|
213
|
+
validation: {
|
|
214
|
+
required: false,
|
|
215
|
+
stringLengthRange: { minLength: 5 },
|
|
216
|
+
pattern: '^[A-Z]+$',
|
|
217
|
+
},
|
|
218
|
+
}),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
await driver.tk.enterText('ab');
|
|
222
|
+
|
|
223
|
+
expect(await driver.tk.getErrorMessage()).toBe(
|
|
224
|
+
'cairo.fieldValidation.minCharacter{charMin=5}',
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('enforces nothing, and returns promptly, for a pattern that could hang', async () => {
|
|
229
|
+
const driver = setup({
|
|
230
|
+
field: makeField({
|
|
231
|
+
validation: { required: false, pattern: '^(a+)+$' },
|
|
232
|
+
}),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Must not match: a value the pattern accepts returns fast either way, so
|
|
236
|
+
// it would pass with the guard removed.
|
|
237
|
+
const startedAt = Date.now();
|
|
238
|
+
await driver.tk.enterText(`${'a'.repeat(30)}!`);
|
|
239
|
+
|
|
240
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
241
|
+
expect(Date.now() - startedAt).toBeLessThan(1000);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('enforces nothing when the pattern cannot compile', async () => {
|
|
245
|
+
const driver = setup({
|
|
246
|
+
field: makeField({
|
|
247
|
+
validation: { required: false, pattern: '[' },
|
|
248
|
+
}),
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
await driver.tk.enterText('anything');
|
|
252
|
+
|
|
253
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
254
|
+
});
|
|
170
255
|
});
|
|
@@ -79,4 +79,48 @@ describe('FormUrl field', () => {
|
|
|
79
79
|
'cairo.customFields.url-input.error',
|
|
80
80
|
);
|
|
81
81
|
});
|
|
82
|
+
|
|
83
|
+
it('shows a pattern error when a valid URL does not match', async () => {
|
|
84
|
+
const driver = setup({
|
|
85
|
+
field: makeField({
|
|
86
|
+
type: 'URL',
|
|
87
|
+
validation: { required: false, pattern: '^https://wix\\.com/.*$' },
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await driver.tk.enterText('https://example.com/page');
|
|
92
|
+
|
|
93
|
+
expect(await driver.tk.hasError()).toBe(true);
|
|
94
|
+
expect(await driver.tk.getErrorMessage()).toBe(
|
|
95
|
+
'cairo.fieldValidation.patternMismatch',
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('accepts a valid URL that matches the pattern', async () => {
|
|
100
|
+
const driver = setup({
|
|
101
|
+
field: makeField({
|
|
102
|
+
type: 'URL',
|
|
103
|
+
validation: { required: false, pattern: '^https://wix\\.com/.*$' },
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await driver.tk.enterText('https://wix.com/page');
|
|
108
|
+
|
|
109
|
+
expect(await driver.tk.hasError()).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('reports the malformed-URL error before the pattern error', async () => {
|
|
113
|
+
const driver = setup({
|
|
114
|
+
field: makeField({
|
|
115
|
+
type: 'URL',
|
|
116
|
+
validation: { required: false, pattern: '^https://wix\\.com/.*$' },
|
|
117
|
+
}),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
await driver.tk.enterText('not a url');
|
|
121
|
+
|
|
122
|
+
expect(await driver.tk.getErrorMessage()).toBe(
|
|
123
|
+
'cairo.customFields.url-input.error',
|
|
124
|
+
);
|
|
125
|
+
});
|
|
82
126
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compilePattern,
|
|
3
|
+
matchesPattern,
|
|
4
|
+
hasFieldValidationSettingsError,
|
|
5
|
+
getFieldValidationSettingsViolations,
|
|
6
|
+
} from '../../validations/field-validation-settings';
|
|
7
|
+
|
|
8
|
+
describe('matchesPattern', () => {
|
|
9
|
+
it('accepts a value that matches', () => {
|
|
10
|
+
expect(matchesPattern('ABC-1234', '^[A-Z]{3}-\\d{4}$')).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('rejects a value that does not match', () => {
|
|
14
|
+
expect(matchesPattern('nope', '^[A-Z]{3}-\\d{4}$')).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('enforces nothing when there is no pattern', () => {
|
|
18
|
+
expect(matchesPattern('anything', undefined)).toBe(true);
|
|
19
|
+
expect(matchesPattern('anything', '')).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('enforces nothing when the pattern cannot compile', () => {
|
|
23
|
+
expect(matchesPattern('anything', '[')).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('enforces nothing when the pattern exceeds the length cap', () => {
|
|
27
|
+
expect(matchesPattern('anything', '^'.repeat(501))).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('enforces nothing when the pattern can backtrack catastrophically', () => {
|
|
31
|
+
expect(matchesPattern('a'.repeat(30), '^(a+)+$')).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('anchors nothing implicitly', () => {
|
|
35
|
+
expect(matchesPattern('xxABCxx', 'ABC')).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('compilePattern', () => {
|
|
40
|
+
it('returns a reusable RegExp', () => {
|
|
41
|
+
const regex = compilePattern('^a+$');
|
|
42
|
+
|
|
43
|
+
expect(regex).toBeInstanceOf(RegExp);
|
|
44
|
+
expect(regex!.test('aaa')).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns undefined for an invalid pattern', () => {
|
|
48
|
+
expect(compilePattern('[')).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('refuses to compile a pattern that can backtrack catastrophically', () => {
|
|
52
|
+
expect(compilePattern('^(a+)+$')).toBeUndefined();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('still compiles a nested quantifier whose iterations are pinned apart', () => {
|
|
56
|
+
expect(compilePattern('^[a-z0-9]+(?:-[a-z0-9]+)*$')).toBeInstanceOf(RegExp);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('returns a stateless RegExp that can be reused', () => {
|
|
60
|
+
const regex = compilePattern('^a$')!;
|
|
61
|
+
|
|
62
|
+
expect(regex.test('a')).toBe(true);
|
|
63
|
+
expect(regex.test('a')).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('existing authoring validation still holds', () => {
|
|
68
|
+
it('treats an empty pattern as authorable, not invalid', () => {
|
|
69
|
+
expect(hasFieldValidationSettingsError({ pattern: '' })).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('still rejects an uncompilable pattern at authoring time', () => {
|
|
73
|
+
expect(hasFieldValidationSettingsError({ pattern: '[' })).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('reports a catastrophic pattern as unsafe, not invalid', () => {
|
|
77
|
+
expect(
|
|
78
|
+
getFieldValidationSettingsViolations({ pattern: '^(a+)+$' }),
|
|
79
|
+
).toEqual([{ rule: 'pattern', type: 'unsafePattern' }]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('still rejects an over-long pattern at authoring time', () => {
|
|
83
|
+
expect(hasFieldValidationSettingsError({ pattern: '^'.repeat(501) })).toBe(
|
|
84
|
+
true,
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { hasNestedQuantifier } from '../../validations/regex-safety';
|
|
2
|
+
|
|
3
|
+
describe('hasNestedQuantifier', () => {
|
|
4
|
+
it.each([
|
|
5
|
+
['^(a+)+$', 'the classic nested-quantifier blowup'],
|
|
6
|
+
['(a*)*', 'star over star'],
|
|
7
|
+
['(a+)*', 'star over plus'],
|
|
8
|
+
['([a-z]+)+', 'a quantified class inside a quantified group'],
|
|
9
|
+
['(\\d+){2,}', 'an open-ended counted quantifier over a quantified group'],
|
|
10
|
+
['((a+))+', 'nesting through an intermediate group'],
|
|
11
|
+
['(?:a+)+', 'a non-capturing group'],
|
|
12
|
+
['(a+|b)+', 'one elastic branch is enough'],
|
|
13
|
+
['(\\s*|\\t*)*', 'every branch is elastic'],
|
|
14
|
+
['(x+x+)+y', 'two elastic atoms in one branch'],
|
|
15
|
+
['^([a-zA-Z0-9]+\\s?)*$', 'an optional atom does not pin anything'],
|
|
16
|
+
['(a|a)*$', 'branches that can start with the same character overlap'],
|
|
17
|
+
['(a|ab)+', 'one branch is a prefix of the other'],
|
|
18
|
+
['(?:https|http)+', 'branches sharing a first character'],
|
|
19
|
+
['(.|x)+', 'a wildcard branch overlaps everything'],
|
|
20
|
+
[
|
|
21
|
+
'(?:\\d+|[a-z]+)+',
|
|
22
|
+
'an elastic branch is dangerous even beside a disjoint one',
|
|
23
|
+
],
|
|
24
|
+
['^x(?:\\w*)*y$', 'a quantified group in the middle of a pattern'],
|
|
25
|
+
['^(a+a)+$', 'a mandatory atom the elastic one can also eat pins nothing'],
|
|
26
|
+
[
|
|
27
|
+
'^((a+)a)+$',
|
|
28
|
+
'the overlapping mandatory atom sits outside the inner group',
|
|
29
|
+
],
|
|
30
|
+
['^(a{1,3})+$', 'a variable counted quantifier is elastic'],
|
|
31
|
+
['^(a{2,})+$', 'an open-ended counted quantifier is elastic'],
|
|
32
|
+
['^(a?)+$', 'an optional atom alone is elastic'],
|
|
33
|
+
['^(a+a?)+$', 'neither atom is fixed'],
|
|
34
|
+
])('rejects %s (%s)', (pattern) => {
|
|
35
|
+
expect(hasNestedQuantifier(pattern)).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it.each([
|
|
39
|
+
['^[A-Z]{3}-\\d{4}$', 'a bounded SKU pattern'],
|
|
40
|
+
['^https://wix\\.com/.*$', 'a URL prefix pattern'],
|
|
41
|
+
['(a)+', 'a quantified group with no inner quantifier'],
|
|
42
|
+
['(a|b)+', 'a quantified alternation of single characters'],
|
|
43
|
+
['a+b+', 'sibling quantifiers, not nested'],
|
|
44
|
+
['(a+)', 'an unquantified group holding a quantifier'],
|
|
45
|
+
['^\\(\\d+\\)$', 'escaped parentheses around a quantifier'],
|
|
46
|
+
['[(+*)]+', 'quantifier characters living inside a character class'],
|
|
47
|
+
['[]+]+', 'a leading literal bracket inside a class'],
|
|
48
|
+
['(a+){1,3}', 'a bounded quantifier over a quantified group'],
|
|
49
|
+
['(a+)?', 'an optional quantified group'],
|
|
50
|
+
[
|
|
51
|
+
'^[a-z0-9]+(?:-[a-z0-9]+)*$',
|
|
52
|
+
'a slug: each iteration must eat a literal -',
|
|
53
|
+
],
|
|
54
|
+
['^(?:-a+)+$', 'a leading literal pins the iterations apart'],
|
|
55
|
+
['(a+b)+', 'a mandatory trailing atom pins the iterations apart'],
|
|
56
|
+
[
|
|
57
|
+
'^(?:\\d{3}-)+\\d{4}$',
|
|
58
|
+
'a bounded atom plus a literal inside a quantified group',
|
|
59
|
+
],
|
|
60
|
+
['(?:foo|bar)+', 'branches with disjoint first characters'],
|
|
61
|
+
[
|
|
62
|
+
'^#?([0-9a-f]{6}|[0-9a-f]{3})$',
|
|
63
|
+
'an unquantified alternation is never repeated',
|
|
64
|
+
],
|
|
65
|
+
['(a{2})+', 'a fixed count does not vary, so it pins iterations apart'],
|
|
66
|
+
['^(?:\\w|\\s)+$', 'word and whitespace classes do not overlap'],
|
|
67
|
+
['', 'an empty pattern'],
|
|
68
|
+
])('accepts %s (%s)', (pattern) => {
|
|
69
|
+
expect(hasNestedQuantifier(pattern)).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -5,7 +5,7 @@ import { classesRuntime, statesRuntime } from "../../../stylable-esm-runtime.js"
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var _namespace_ = "
|
|
8
|
+
var _namespace_ = "addressinput2635111141";
|
|
9
9
|
var _style_ = classesRuntime.bind(null, _namespace_);
|
|
10
10
|
|
|
11
11
|
export var cssStates = statesRuntime.bind(null, _namespace_);
|
|
@@ -13,7 +13,7 @@ export var style: import("@stylable/runtime").STFunction = _style_;
|
|
|
13
13
|
export var st: import("@stylable/runtime").STFunction = _style_;
|
|
14
14
|
|
|
15
15
|
export var namespace = _namespace_;
|
|
16
|
-
export var classes = {"root":"
|
|
16
|
+
export var classes = {"root":"addressinput2635111141__root","tableAddressInput":"addressinput2635111141__tableAddressInput"};
|
|
17
17
|
export var keyframes = {};
|
|
18
18
|
export var layers = {};
|
|
19
19
|
export var containers = {};
|
|
@@ -5,7 +5,7 @@ import { classesRuntime, statesRuntime } from "../../../../stylable-esm-runtime.
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var _namespace_ = "
|
|
8
|
+
var _namespace_ = "actionsmenu2195877707";
|
|
9
9
|
var _style_ = classesRuntime.bind(null, _namespace_);
|
|
10
10
|
|
|
11
11
|
export var cssStates = statesRuntime.bind(null, _namespace_);
|
|
@@ -13,7 +13,7 @@ export var style: import("@stylable/runtime").STFunction = _style_;
|
|
|
13
13
|
export var st: import("@stylable/runtime").STFunction = _style_;
|
|
14
14
|
|
|
15
15
|
export var namespace = _namespace_;
|
|
16
|
-
export var classes = {"root":"
|
|
16
|
+
export var classes = {"root":"actionsmenu2195877707__root","action":"actionsmenu2195877707__action"};
|
|
17
17
|
export var keyframes = {};
|
|
18
18
|
export var layers = {};
|
|
19
19
|
export var containers = {};
|
|
@@ -5,7 +5,7 @@ import { classesRuntime, statesRuntime } from "../../../stylable-esm-runtime.js"
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var _namespace_ = "
|
|
8
|
+
var _namespace_ = "formaudiofield2679064113";
|
|
9
9
|
var _style_ = classesRuntime.bind(null, _namespace_);
|
|
10
10
|
|
|
11
11
|
export var cssStates = statesRuntime.bind(null, _namespace_);
|
|
@@ -13,7 +13,7 @@ export var style: import("@stylable/runtime").STFunction = _style_;
|
|
|
13
13
|
export var st: import("@stylable/runtime").STFunction = _style_;
|
|
14
14
|
|
|
15
15
|
export var namespace = _namespace_;
|
|
16
|
-
export var classes = {"root":"
|
|
16
|
+
export var classes = {"root":"formaudiofield2679064113__root","addItem":"formaudiofield2679064113__addItem","mediaTitle":"formaudiofield2679064113__mediaTitle"};
|
|
17
17
|
export var keyframes = {};
|
|
18
18
|
export var layers = {};
|
|
19
19
|
export var containers = {};
|
|
@@ -5,7 +5,7 @@ import { classesRuntime, statesRuntime } from "../../../stylable-esm-runtime.js"
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var _namespace_ = "
|
|
8
|
+
var _namespace_ = "audioplayer1268238730";
|
|
9
9
|
var _style_ = classesRuntime.bind(null, _namespace_);
|
|
10
10
|
|
|
11
11
|
export var cssStates = statesRuntime.bind(null, _namespace_);
|
|
@@ -13,7 +13,7 @@ export var style: import("@stylable/runtime").STFunction = _style_;
|
|
|
13
13
|
export var st: import("@stylable/runtime").STFunction = _style_;
|
|
14
14
|
|
|
15
15
|
export var namespace = _namespace_;
|
|
16
|
-
export var classes = {"root":"
|
|
16
|
+
export var classes = {"root":"audioplayer1268238730__root"};
|
|
17
17
|
export var keyframes = {};
|
|
18
18
|
export var layers = {};
|
|
19
19
|
export var containers = {};
|
|
@@ -5,7 +5,7 @@ import { classesRuntime, statesRuntime } from "../../stylable-esm-runtime.js";
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var _namespace_ = "
|
|
8
|
+
var _namespace_ = "cellcolorview3095201269";
|
|
9
9
|
var _style_ = classesRuntime.bind(null, _namespace_);
|
|
10
10
|
|
|
11
11
|
export var cssStates = statesRuntime.bind(null, _namespace_);
|
|
@@ -13,7 +13,7 @@ export var style: import("@stylable/runtime").STFunction = _style_;
|
|
|
13
13
|
export var st: import("@stylable/runtime").STFunction = _style_;
|
|
14
14
|
|
|
15
15
|
export var namespace = _namespace_;
|
|
16
|
-
export var classes = {"root":"
|
|
16
|
+
export var classes = {"root":"cellcolorview3095201269__root","hashPrefix":"cellcolorview3095201269__hashPrefix"};
|
|
17
17
|
export var keyframes = {};
|
|
18
18
|
export var layers = {};
|
|
19
19
|
export var containers = {};
|