@payloadcms/richtext-lexical 3.64.0-internal.deef021 → 3.64.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.
@@ -17,6 +17,8 @@ export declare const absoluteRegExp: RegExp;
17
17
  * - /privacy-policy
18
18
  * - /privacy-policy#primary-terms
19
19
  * - #primary-terms
20
+ * - /page?id=123
21
+ * - /page?id=123#section
20
22
  * */
21
23
  export declare const relativeOrAnchorRegExp: RegExp;
22
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lexical/utils/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe/C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,QACqK,CAAA;AAEhM;;;;;MAKM;AACN,eAAO,MAAM,sBAAsB,QAA6C,CAAA;AAEhF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMvD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA+BhD"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/lexical/utils/url.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe/C;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,QACqK,CAAA;AAEhM;;;;;;;MAOM;AACN,eAAO,MAAM,sBAAsB,QAA4D,CAAA;AAE/F;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMvD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA8ChD"}
@@ -26,8 +26,10 @@ export const absoluteRegExp = /^(?:[a-zA-Z][a-zA-Z\d+.-]*:(?:\/\/)?(?:[-;:&=+$,\
26
26
  * - /privacy-policy
27
27
  * - /privacy-policy#primary-terms
28
28
  * - #primary-terms
29
+ * - /page?id=123
30
+ * - /page?id=123#section
29
31
  * */
30
- export const relativeOrAnchorRegExp = /^(?:\/[\w\-./]*(?:#\w[\w-]*)?|#[\w\-]+)$/;
32
+ export const relativeOrAnchorRegExp = /^(?:\/[\w\-./]*(?:\?[-;&=%\w]*)?(?:#[\w-]+)?|#[\w\-]+)$/;
31
33
  /**
32
34
  * Prevents unreasonable URLs from being inserted into the editor.
33
35
  * @param url
@@ -46,6 +48,14 @@ export function validateUrl(url) {
46
48
  if (!url) {
47
49
  return false;
48
50
  }
51
+ // Reject URLs with spaces
52
+ if (url.includes(' ')) {
53
+ return false;
54
+ }
55
+ // Reject malformed protocol URLs (e.g., http:/example.com instead of http://example.com)
56
+ if (/^[a-z][a-z\d+.-]*:\/[^/]/i.test(url)) {
57
+ return false;
58
+ }
49
59
  if (url === 'https://') {
50
60
  return true;
51
61
  }
@@ -59,7 +69,13 @@ export function validateUrl(url) {
59
69
  }
60
70
  // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs
61
71
  try {
62
- new URL(url);
72
+ const urlObj = new URL(url);
73
+ // For http/https/ftp protocols, require a proper domain with at least one dot (for TLD)
74
+ if (['ftp:', 'http:', 'https:'].includes(urlObj.protocol)) {
75
+ if (!urlObj.hostname.includes('.')) {
76
+ return false;
77
+ }
78
+ }
63
79
  return true;
64
80
  } catch {
65
81
  /* empty */}
@@ -1 +1 @@
1
- {"version":3,"file":"url.js","names":["sanitizeUrl","url","SAFE_URL_PATTERN","DATA_URL_PATTERN","String","trim","match","absoluteRegExp","relativeOrAnchorRegExp","validateUrlMinimal","includes","validateUrl","test","URL"],"sources":["../../../src/lexical/utils/url.ts"],"sourcesContent":["export function sanitizeUrl(url: string): string {\n /** A pattern that matches safe URLs. */\n const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi\n\n /** A pattern that matches safe data URLs. */\n const DATA_URL_PATTERN =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z\\d+/]+=*$/i\n\n url = String(url).trim()\n\n if (url.match(SAFE_URL_PATTERN) != null || url.match(DATA_URL_PATTERN) != null) {\n return url\n }\n\n return 'https://'\n}\n\n/**\n * This regex checks for absolute URLs in a string. Tested for the following use cases:\n * - http://example.com\n * - https://example.com\n * - ftp://files.example.com\n * - http://example.com/resource\n * - https://example.com/resource?key=value\n * - http://example.com/resource#anchor\n * - http://www.example.com\n * - https://sub.example.com/path/file\n * - mailto:\n */\nexport const absoluteRegExp =\n /^(?:[a-zA-Z][a-zA-Z\\d+.-]*:(?:\\/\\/)?(?:[-;:&=+$,\\w]+@)?[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|www\\.[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|(?:tel|mailto):[\\w+.-]+)(?:\\/[+~%/\\w-]*)?(?:\\?[-;&=%\\w]*)?(?:#\\w+)?$/\n\n/**\n * This regex checks for relative URLs starting with / or anchor links starting with # in a string. Tested for the following use cases:\n * - /privacy-policy\n * - /privacy-policy#primary-terms\n * - #primary-terms\n * */\nexport const relativeOrAnchorRegExp = /^(?:\\/[\\w\\-./]*(?:#\\w[\\w-]*)?|#[\\w\\-]+)$/\n\n/**\n * Prevents unreasonable URLs from being inserted into the editor.\n * @param url\n */\nexport function validateUrlMinimal(url: string): boolean {\n if (!url) {\n return false\n }\n\n return !url.includes(' ')\n}\n\n// Do not keep validateUrl function too loose. This is run when pasting in text, to determine if links are in that text and if it should create AutoLinkNodes.\n// This is why we do not allow stuff like anchors here, as we don't want copied anchors to be turned into AutoLinkNodes.\nexport function validateUrl(url: string): boolean {\n // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.\n // Maybe show a dialog where they user can type the URL before inserting it.\n\n if (!url) {\n return false\n }\n\n if (url === 'https://') {\n return true\n }\n\n // This makes sure URLs starting with www. instead of https are valid too\n if (absoluteRegExp.test(url)) {\n return true\n }\n\n // Check relative or anchor links\n if (relativeOrAnchorRegExp.test(url)) {\n return true\n }\n\n // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs\n try {\n new URL(url)\n return true\n } catch {\n /* empty */\n }\n\n return false\n}\n"],"mappings":"AAAA,OAAO,SAASA,YAAYC,GAAW;EACrC,yCACA,MAAMC,gBAAA,GAAmB;EAEzB;EACA,MAAMC,gBAAA,GACJ;EAEFF,GAAA,GAAMG,MAAA,CAAOH,GAAA,EAAKI,IAAI;EAEtB,IAAIJ,GAAA,CAAIK,KAAK,CAACJ,gBAAA,KAAqB,QAAQD,GAAA,CAAIK,KAAK,CAACH,gBAAA,KAAqB,MAAM;IAC9E,OAAOF,GAAA;EACT;EAEA,OAAO;AACT;AAEA;;;;;;;;;;;;AAYA,OAAO,MAAMM,cAAA,GACX;AAEF;;;;;;AAMA,OAAO,MAAMC,sBAAA,GAAyB;AAEtC;;;;AAIA,OAAO,SAASC,mBAAmBR,GAAW;EAC5C,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,OAAO,CAACA,GAAA,CAAIS,QAAQ,CAAC;AACvB;AAEA;AACA;AACA,OAAO,SAASC,YAAYV,GAAW;EACrC;EACA;EAEA,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,IAAIA,GAAA,KAAQ,YAAY;IACtB,OAAO;EACT;EAEA;EACA,IAAIM,cAAA,CAAeK,IAAI,CAACX,GAAA,GAAM;IAC5B,OAAO;EACT;EAEA;EACA,IAAIO,sBAAA,CAAuBI,IAAI,CAACX,GAAA,GAAM;IACpC,OAAO;EACT;EAEA;EACA,IAAI;IACF,IAAIY,GAAA,CAAIZ,GAAA;IACR,OAAO;EACT,EAAE,MAAM;IACN;EAGF,OAAO;AACT","ignoreList":[]}
1
+ {"version":3,"file":"url.js","names":["sanitizeUrl","url","SAFE_URL_PATTERN","DATA_URL_PATTERN","String","trim","match","absoluteRegExp","relativeOrAnchorRegExp","validateUrlMinimal","includes","validateUrl","test","urlObj","URL","protocol","hostname"],"sources":["../../../src/lexical/utils/url.ts"],"sourcesContent":["export function sanitizeUrl(url: string): string {\n /** A pattern that matches safe URLs. */\n const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^&:/?#]*(?:[/?#]|$))/gi\n\n /** A pattern that matches safe data URLs. */\n const DATA_URL_PATTERN =\n /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z\\d+/]+=*$/i\n\n url = String(url).trim()\n\n if (url.match(SAFE_URL_PATTERN) != null || url.match(DATA_URL_PATTERN) != null) {\n return url\n }\n\n return 'https://'\n}\n\n/**\n * This regex checks for absolute URLs in a string. Tested for the following use cases:\n * - http://example.com\n * - https://example.com\n * - ftp://files.example.com\n * - http://example.com/resource\n * - https://example.com/resource?key=value\n * - http://example.com/resource#anchor\n * - http://www.example.com\n * - https://sub.example.com/path/file\n * - mailto:\n */\nexport const absoluteRegExp =\n /^(?:[a-zA-Z][a-zA-Z\\d+.-]*:(?:\\/\\/)?(?:[-;:&=+$,\\w]+@)?[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|www\\.[A-Za-z\\d]+(?:\\.[A-Za-z\\d]+)+|(?:tel|mailto):[\\w+.-]+)(?:\\/[+~%/\\w-]*)?(?:\\?[-;&=%\\w]*)?(?:#\\w+)?$/\n\n/**\n * This regex checks for relative URLs starting with / or anchor links starting with # in a string. Tested for the following use cases:\n * - /privacy-policy\n * - /privacy-policy#primary-terms\n * - #primary-terms\n * - /page?id=123\n * - /page?id=123#section\n * */\nexport const relativeOrAnchorRegExp = /^(?:\\/[\\w\\-./]*(?:\\?[-;&=%\\w]*)?(?:#[\\w-]+)?|#[\\w\\-]+)$/\n\n/**\n * Prevents unreasonable URLs from being inserted into the editor.\n * @param url\n */\nexport function validateUrlMinimal(url: string): boolean {\n if (!url) {\n return false\n }\n\n return !url.includes(' ')\n}\n\n// Do not keep validateUrl function too loose. This is run when pasting in text, to determine if links are in that text and if it should create AutoLinkNodes.\n// This is why we do not allow stuff like anchors here, as we don't want copied anchors to be turned into AutoLinkNodes.\nexport function validateUrl(url: string): boolean {\n // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://.\n // Maybe show a dialog where they user can type the URL before inserting it.\n if (!url) {\n return false\n }\n\n // Reject URLs with spaces\n if (url.includes(' ')) {\n return false\n }\n\n // Reject malformed protocol URLs (e.g., http:/example.com instead of http://example.com)\n if (/^[a-z][a-z\\d+.-]*:\\/[^/]/i.test(url)) {\n return false\n }\n\n if (url === 'https://') {\n return true\n }\n\n // This makes sure URLs starting with www. instead of https are valid too\n if (absoluteRegExp.test(url)) {\n return true\n }\n\n // Check relative or anchor links\n if (relativeOrAnchorRegExp.test(url)) {\n return true\n }\n\n // While this doesn't allow URLs starting with www (which is why we use the regex above), it does properly handle tel: URLs\n try {\n const urlObj = new URL(url)\n // For http/https/ftp protocols, require a proper domain with at least one dot (for TLD)\n if (['ftp:', 'http:', 'https:'].includes(urlObj.protocol)) {\n if (!urlObj.hostname.includes('.')) {\n return false\n }\n }\n return true\n } catch {\n /* empty */\n }\n\n return false\n}\n"],"mappings":"AAAA,OAAO,SAASA,YAAYC,GAAW;EACrC,yCACA,MAAMC,gBAAA,GAAmB;EAEzB;EACA,MAAMC,gBAAA,GACJ;EAEFF,GAAA,GAAMG,MAAA,CAAOH,GAAA,EAAKI,IAAI;EAEtB,IAAIJ,GAAA,CAAIK,KAAK,CAACJ,gBAAA,KAAqB,QAAQD,GAAA,CAAIK,KAAK,CAACH,gBAAA,KAAqB,MAAM;IAC9E,OAAOF,GAAA;EACT;EAEA,OAAO;AACT;AAEA;;;;;;;;;;;;AAYA,OAAO,MAAMM,cAAA,GACX;AAEF;;;;;;;;AAQA,OAAO,MAAMC,sBAAA,GAAyB;AAEtC;;;;AAIA,OAAO,SAASC,mBAAmBR,GAAW;EAC5C,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA,OAAO,CAACA,GAAA,CAAIS,QAAQ,CAAC;AACvB;AAEA;AACA;AACA,OAAO,SAASC,YAAYV,GAAW;EACrC;EACA;EACA,IAAI,CAACA,GAAA,EAAK;IACR,OAAO;EACT;EAEA;EACA,IAAIA,GAAA,CAAIS,QAAQ,CAAC,MAAM;IACrB,OAAO;EACT;EAEA;EACA,IAAI,4BAA4BE,IAAI,CAACX,GAAA,GAAM;IACzC,OAAO;EACT;EAEA,IAAIA,GAAA,KAAQ,YAAY;IACtB,OAAO;EACT;EAEA;EACA,IAAIM,cAAA,CAAeK,IAAI,CAACX,GAAA,GAAM;IAC5B,OAAO;EACT;EAEA;EACA,IAAIO,sBAAA,CAAuBI,IAAI,CAACX,GAAA,GAAM;IACpC,OAAO;EACT;EAEA;EACA,IAAI;IACF,MAAMY,MAAA,GAAS,IAAIC,GAAA,CAAIb,GAAA;IACvB;IACA,IAAI,CAAC,QAAQ,SAAS,SAAS,CAACS,QAAQ,CAACG,MAAA,CAAOE,QAAQ,GAAG;MACzD,IAAI,CAACF,MAAA,CAAOG,QAAQ,CAACN,QAAQ,CAAC,MAAM;QAClC,OAAO;MACT;IACF;IACA,OAAO;EACT,EAAE,MAAM;IACN;EAGF,OAAO;AACT","ignoreList":[]}
@@ -1,8 +1,8 @@
1
- import { absoluteRegExp, relativeOrAnchorRegExp } from './url.js';
1
+ import { absoluteRegExp, relativeOrAnchorRegExp, validateUrl } from './url.js';
2
2
  describe('Lexical URL Regex Matchers', () => {
3
- describe('relative URLs', () => {
3
+ describe('relativeOrAnchorRegExp', () => {
4
4
  it('validation for links it should match', async () => {
5
- const shouldMatch = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '#anchor', '#section-title', '/path#fragment'];
5
+ const shouldMatch = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '#anchor', '#section-title', '/path#fragment', '/page?id=123', '/page?id=123#section', '/search?q=test', '/?global=true'];
6
6
  shouldMatch.forEach(testCase => {
7
7
  expect(relativeOrAnchorRegExp.test(testCase)).toBe(true);
8
8
  });
@@ -14,7 +14,7 @@ describe('Lexical URL Regex Matchers', () => {
14
14
  });
15
15
  });
16
16
  });
17
- describe('absolute URLs', () => {
17
+ describe('absoluteRegExp', () => {
18
18
  it('validation for links it should match', async () => {
19
19
  const shouldMatch = ['http://example.com', 'https://example.com', 'ftp://files.example.com', 'http://example.com/resource', 'https://example.com/resource?key=value', 'http://example.com/resource#anchor', 'http://www.example.com', 'https://sub.example.com/path/file', 'mailto:email@example.com', 'tel:+1234567890', 'http://user:pass@example.com', 'www.example.com', 'www.example.com/resource', 'www.example.com/resource?query=1', 'www.example.com#fragment'];
20
20
  shouldMatch.forEach(testCase => {
@@ -28,5 +28,86 @@ describe('Lexical URL Regex Matchers', () => {
28
28
  });
29
29
  });
30
30
  });
31
+ describe('validateUrl', () => {
32
+ describe('absolute URLs', () => {
33
+ it('should validate http and https URLs', () => {
34
+ const validUrls = ['http://example.com', 'https://example.com', 'http://www.example.com', 'https://sub.example.com/path/file', 'http://example.com/resource', 'https://example.com/resource?key=value', 'http://example.com/resource#anchor'];
35
+ validUrls.forEach(url => {
36
+ expect(validateUrl(url)).toBe(true);
37
+ });
38
+ });
39
+ it('should validate other protocol URLs', () => {
40
+ const validUrls = ['ftp://files.example.com', 'mailto:email@example.com', 'tel:+1234567890'];
41
+ validUrls.forEach(url => {
42
+ expect(validateUrl(url)).toBe(true);
43
+ });
44
+ });
45
+ it('should validate www URLs without protocol', () => {
46
+ const validUrls = ['www.example.com', 'www.example.com/resource', 'www.example.com/resource?query=1', 'www.example.com#fragment'];
47
+ validUrls.forEach(url => {
48
+ expect(validateUrl(url)).toBe(true);
49
+ });
50
+ });
51
+ });
52
+ describe('relative URLs', () => {
53
+ it('should validate relative paths', () => {
54
+ const validUrls = ['/path/to/resource', '/file-name.html', '/', '/dir/', '/path.with.dots/', '/path#fragment'];
55
+ validUrls.forEach(url => {
56
+ expect(validateUrl(url)).toBe(true);
57
+ });
58
+ });
59
+ });
60
+ describe('anchor links', () => {
61
+ it('should validate anchor links', () => {
62
+ const validUrls = ['#anchor', '#section-title'];
63
+ validUrls.forEach(url => {
64
+ expect(validateUrl(url)).toBe(true);
65
+ });
66
+ });
67
+ });
68
+ describe('with query params', () => {
69
+ it('should validate relative URLs with query parameters', () => {
70
+ const validUrls = ['/page?id=123', '/search?q=test', '/products?category=electronics&sort=price', '/path?key=value&another=param', '/page?id=123&filter=active', '/?global=true'];
71
+ validUrls.forEach(url => {
72
+ expect(validateUrl(url)).toBe(true);
73
+ });
74
+ });
75
+ it('should validate absolute URLs with query parameters', () => {
76
+ const validUrls = ['https://example.com?id=123', 'http://example.com/page?key=value', 'www.example.com?search=query', 'https://example.com/path?a=1&b=2&c=3'];
77
+ validUrls.forEach(url => {
78
+ expect(validateUrl(url)).toBe(true);
79
+ });
80
+ });
81
+ it('should validate URLs with query parameters and anchors', () => {
82
+ const validUrls = ['/page?id=123#section', 'https://example.com?key=value#anchor', '/search?q=test#results'];
83
+ validUrls.forEach(url => {
84
+ expect(validateUrl(url)).toBe(true);
85
+ });
86
+ });
87
+ });
88
+ describe('edge cases', () => {
89
+ it('should handle the default https:// case', () => {
90
+ expect(validateUrl('https://')).toBe(true);
91
+ });
92
+ it('should return false for empty or invalid URLs', () => {
93
+ const invalidUrls = ['', 'not-a-url', 'example.com', 'relative/path', 'file.html', 'some#fragment', 'http://', 'http:/example.com', 'http//example.com'];
94
+ invalidUrls.forEach(url => {
95
+ expect(validateUrl(url)).toBe(false);
96
+ });
97
+ });
98
+ it('should return false for URLs with spaces', () => {
99
+ const invalidUrls = ['/path/with spaces', 'http://example.com/ spaces', 'https://example.com/path with spaces'];
100
+ invalidUrls.forEach(url => {
101
+ expect(validateUrl(url)).toBe(false);
102
+ });
103
+ });
104
+ it('should return false for malformed URLs', () => {
105
+ const invalidUrls = ['://missing.scheme', 'ftp://example .com', 'http://example', '#', '/#'];
106
+ invalidUrls.forEach(url => {
107
+ expect(validateUrl(url)).toBe(false);
108
+ });
109
+ });
110
+ });
111
+ });
31
112
  });
32
113
  //# sourceMappingURL=url.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url.spec.js","names":["absoluteRegExp","relativeOrAnchorRegExp","describe","it","shouldMatch","forEach","testCase","expect","test","toBe","shouldNotMatch","not"],"sources":["../../../src/lexical/utils/url.spec.ts"],"sourcesContent":["import { jest } from '@jest/globals'\nimport { absoluteRegExp, relativeOrAnchorRegExp } from './url.js'\n\ndescribe('Lexical URL Regex Matchers', () => {\n describe('relative URLs', () => {\n it('validation for links it should match', async () => {\n const shouldMatch = [\n '/path/to/resource',\n '/file-name.html',\n '/',\n '/dir/',\n '/path.with.dots/',\n '#anchor',\n '#section-title',\n '/path#fragment',\n ]\n\n shouldMatch.forEach((testCase) => {\n expect(relativeOrAnchorRegExp.test(testCase)).toBe(true)\n })\n })\n\n it('validation for links it should not match', async () => {\n const shouldNotMatch = [\n 'match',\n 'http://example.com',\n 'relative/path',\n 'file.html',\n 'some#fragment',\n '#',\n '/#',\n '/path/with spaces',\n '',\n 'ftp://example.com',\n ]\n\n shouldNotMatch.forEach((testCase) => {\n expect(relativeOrAnchorRegExp.test(testCase)).not.toBe(true)\n })\n })\n })\n\n describe('absolute URLs', () => {\n it('validation for links it should match', async () => {\n const shouldMatch = [\n 'http://example.com',\n 'https://example.com',\n 'ftp://files.example.com',\n 'http://example.com/resource',\n 'https://example.com/resource?key=value',\n 'http://example.com/resource#anchor',\n 'http://www.example.com',\n 'https://sub.example.com/path/file',\n 'mailto:email@example.com',\n 'tel:+1234567890',\n 'http://user:pass@example.com',\n 'www.example.com',\n 'www.example.com/resource',\n 'www.example.com/resource?query=1',\n 'www.example.com#fragment',\n ]\n\n shouldMatch.forEach((testCase) => {\n expect(absoluteRegExp.test(testCase)).toBe(true)\n })\n })\n\n it('validation for links it should not match', async () => {\n const shouldNotMatch = [\n '/relative/path',\n '#anchor',\n 'example.com',\n '://missing.scheme',\n 'http://',\n 'http:/example.com',\n 'ftp://example .com',\n 'http://example',\n 'not-a-url',\n 'http//example.com',\n 'https://example.com/ spaces',\n ]\n\n shouldNotMatch.forEach((testCase) => {\n expect(absoluteRegExp.test(testCase)).not.toBe(true)\n })\n })\n })\n})\n"],"mappings":"AACA,SAASA,cAAc,EAAEC,sBAAsB,QAAQ;AAEvDC,QAAA,CAAS,8BAA8B;EACrCA,QAAA,CAAS,iBAAiB;IACxBC,EAAA,CAAG,wCAAwC;MACzC,MAAMC,WAAA,GAAc,CAClB,qBACA,mBACA,KACA,SACA,oBACA,WACA,kBACA,iBACD;MAEDA,WAAA,CAAYC,OAAO,CAAEC,QAAA;QACnBC,MAAA,CAAON,sBAAA,CAAuBO,IAAI,CAACF,QAAA,GAAWG,IAAI,CAAC;MACrD;IACF;IAEAN,EAAA,CAAG,4CAA4C;MAC7C,MAAMO,cAAA,GAAiB,CACrB,SACA,sBACA,iBACA,aACA,iBACA,KACA,MACA,qBACA,IACA,oBACD;MAEDA,cAAA,CAAeL,OAAO,CAAEC,QAAA;QACtBC,MAAA,CAAON,sBAAA,CAAuBO,IAAI,CAACF,QAAA,GAAWK,GAAG,CAACF,IAAI,CAAC;MACzD;IACF;EACF;EAEAP,QAAA,CAAS,iBAAiB;IACxBC,EAAA,CAAG,wCAAwC;MACzC,MAAMC,WAAA,GAAc,CAClB,sBACA,uBACA,2BACA,+BACA,0CACA,sCACA,0BACA,qCACA,4BACA,mBACA,gCACA,mBACA,4BACA,oCACA,2BACD;MAEDA,WAAA,CAAYC,OAAO,CAAEC,QAAA;QACnBC,MAAA,CAAOP,cAAA,CAAeQ,IAAI,CAACF,QAAA,GAAWG,IAAI,CAAC;MAC7C;IACF;IAEAN,EAAA,CAAG,4CAA4C;MAC7C,MAAMO,cAAA,GAAiB,CACrB,kBACA,WACA,eACA,qBACA,WACA,qBACA,sBACA,kBACA,aACA,qBACA,8BACD;MAEDA,cAAA,CAAeL,OAAO,CAAEC,QAAA;QACtBC,MAAA,CAAOP,cAAA,CAAeQ,IAAI,CAACF,QAAA,GAAWK,GAAG,CAACF,IAAI,CAAC;MACjD;IACF;EACF;AACF","ignoreList":[]}
1
+ {"version":3,"file":"url.spec.js","names":["absoluteRegExp","relativeOrAnchorRegExp","validateUrl","describe","it","shouldMatch","forEach","testCase","expect","test","toBe","shouldNotMatch","not","validUrls","url","invalidUrls"],"sources":["../../../src/lexical/utils/url.spec.ts"],"sourcesContent":["import { jest } from '@jest/globals'\nimport { absoluteRegExp, relativeOrAnchorRegExp, validateUrl } from './url.js'\n\ndescribe('Lexical URL Regex Matchers', () => {\n describe('relativeOrAnchorRegExp', () => {\n it('validation for links it should match', async () => {\n const shouldMatch = [\n '/path/to/resource',\n '/file-name.html',\n '/',\n '/dir/',\n '/path.with.dots/',\n '#anchor',\n '#section-title',\n '/path#fragment',\n '/page?id=123',\n '/page?id=123#section',\n '/search?q=test',\n '/?global=true',\n ]\n\n shouldMatch.forEach((testCase) => {\n expect(relativeOrAnchorRegExp.test(testCase)).toBe(true)\n })\n })\n\n it('validation for links it should not match', async () => {\n const shouldNotMatch = [\n 'match',\n 'http://example.com',\n 'relative/path',\n 'file.html',\n 'some#fragment',\n '#',\n '/#',\n '/path/with spaces',\n '',\n 'ftp://example.com',\n ]\n\n shouldNotMatch.forEach((testCase) => {\n expect(relativeOrAnchorRegExp.test(testCase)).not.toBe(true)\n })\n })\n })\n\n describe('absoluteRegExp', () => {\n it('validation for links it should match', async () => {\n const shouldMatch = [\n 'http://example.com',\n 'https://example.com',\n 'ftp://files.example.com',\n 'http://example.com/resource',\n 'https://example.com/resource?key=value',\n 'http://example.com/resource#anchor',\n 'http://www.example.com',\n 'https://sub.example.com/path/file',\n 'mailto:email@example.com',\n 'tel:+1234567890',\n 'http://user:pass@example.com',\n 'www.example.com',\n 'www.example.com/resource',\n 'www.example.com/resource?query=1',\n 'www.example.com#fragment',\n ]\n\n shouldMatch.forEach((testCase) => {\n expect(absoluteRegExp.test(testCase)).toBe(true)\n })\n })\n\n it('validation for links it should not match', async () => {\n const shouldNotMatch = [\n '/relative/path',\n '#anchor',\n 'example.com',\n '://missing.scheme',\n 'http://',\n 'http:/example.com',\n 'ftp://example .com',\n 'http://example',\n 'not-a-url',\n 'http//example.com',\n 'https://example.com/ spaces',\n ]\n\n shouldNotMatch.forEach((testCase) => {\n expect(absoluteRegExp.test(testCase)).not.toBe(true)\n })\n })\n })\n\n describe('validateUrl', () => {\n describe('absolute URLs', () => {\n it('should validate http and https URLs', () => {\n const validUrls = [\n 'http://example.com',\n 'https://example.com',\n 'http://www.example.com',\n 'https://sub.example.com/path/file',\n 'http://example.com/resource',\n 'https://example.com/resource?key=value',\n 'http://example.com/resource#anchor',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n\n it('should validate other protocol URLs', () => {\n const validUrls = ['ftp://files.example.com', 'mailto:email@example.com', 'tel:+1234567890']\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n\n it('should validate www URLs without protocol', () => {\n const validUrls = [\n 'www.example.com',\n 'www.example.com/resource',\n 'www.example.com/resource?query=1',\n 'www.example.com#fragment',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n })\n\n describe('relative URLs', () => {\n it('should validate relative paths', () => {\n const validUrls = [\n '/path/to/resource',\n '/file-name.html',\n '/',\n '/dir/',\n '/path.with.dots/',\n '/path#fragment',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n })\n\n describe('anchor links', () => {\n it('should validate anchor links', () => {\n const validUrls = ['#anchor', '#section-title']\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n })\n\n describe('with query params', () => {\n it('should validate relative URLs with query parameters', () => {\n const validUrls = [\n '/page?id=123',\n '/search?q=test',\n '/products?category=electronics&sort=price',\n '/path?key=value&another=param',\n '/page?id=123&filter=active',\n '/?global=true',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n\n it('should validate absolute URLs with query parameters', () => {\n const validUrls = [\n 'https://example.com?id=123',\n 'http://example.com/page?key=value',\n 'www.example.com?search=query',\n 'https://example.com/path?a=1&b=2&c=3',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n\n it('should validate URLs with query parameters and anchors', () => {\n const validUrls = [\n '/page?id=123#section',\n 'https://example.com?key=value#anchor',\n '/search?q=test#results',\n ]\n\n validUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(true)\n })\n })\n })\n\n describe('edge cases', () => {\n it('should handle the default https:// case', () => {\n expect(validateUrl('https://')).toBe(true)\n })\n\n it('should return false for empty or invalid URLs', () => {\n const invalidUrls = [\n '',\n 'not-a-url',\n 'example.com',\n 'relative/path',\n 'file.html',\n 'some#fragment',\n 'http://',\n 'http:/example.com',\n 'http//example.com',\n ]\n\n invalidUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(false)\n })\n })\n\n it('should return false for URLs with spaces', () => {\n const invalidUrls = [\n '/path/with spaces',\n 'http://example.com/ spaces',\n 'https://example.com/path with spaces',\n ]\n\n invalidUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(false)\n })\n })\n\n it('should return false for malformed URLs', () => {\n const invalidUrls = ['://missing.scheme', 'ftp://example .com', 'http://example', '#', '/#']\n\n invalidUrls.forEach((url) => {\n expect(validateUrl(url)).toBe(false)\n })\n })\n })\n })\n})\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/richtext-lexical",
3
- "version": "3.64.0-internal.deef021",
3
+ "version": "3.64.0",
4
4
  "description": "The officially supported Lexical richtext adapter for Payload",
5
5
  "homepage": "https://payloadcms.com",
6
6
  "repository": {
@@ -374,8 +374,8 @@
374
374
  "react-error-boundary": "4.1.2",
375
375
  "ts-essentials": "10.0.3",
376
376
  "uuid": "10.0.0",
377
- "@payloadcms/ui": "3.64.0-internal.deef021",
378
- "@payloadcms/translations": "3.64.0-internal.deef021"
377
+ "@payloadcms/ui": "3.64.0",
378
+ "@payloadcms/translations": "3.64.0"
379
379
  },
380
380
  "devDependencies": {
381
381
  "@babel/cli": "7.27.2",
@@ -394,16 +394,16 @@
394
394
  "esbuild": "0.25.5",
395
395
  "esbuild-sass-plugin": "3.3.1",
396
396
  "swc-plugin-transform-remove-imports": "4.0.4",
397
- "@payloadcms/eslint-config": "3.28.0",
398
- "payload": "3.64.0-internal.deef021"
397
+ "payload": "3.64.0",
398
+ "@payloadcms/eslint-config": "3.28.0"
399
399
  },
400
400
  "peerDependencies": {
401
401
  "@faceless-ui/modal": "3.0.0",
402
402
  "@faceless-ui/scroll-info": "2.0.0",
403
403
  "react": "^19.0.0 || ^19.0.0-rc-65a56d0e-20241020",
404
404
  "react-dom": "^19.0.0 || ^19.0.0-rc-65a56d0e-20241020",
405
- "@payloadcms/next": "3.64.0-internal.deef021",
406
- "payload": "3.64.0-internal.deef021"
405
+ "@payloadcms/next": "3.64.0",
406
+ "payload": "3.64.0"
407
407
  },
408
408
  "engines": {
409
409
  "node": "^18.20.2 || >=20.9.0"