| ... | @@ -20,7 +20,21 @@ export interface CollectComposerInlineTokensOptions { | ... | @@ -20,7 +20,21 @@ export interface CollectComposerInlineTokensOptions { |
| 20 | | 20 | |
| 21 | const SKILL_TOKEN_REGEX = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s)/g; | 21 | const SKILL_TOKEN_REGEX = /(^|\s)\$([a-zA-Z][a-zA-Z0-9:_-]*)(?=\s)/g; |
| 22 | const MENTION_TOKEN_REGEX = /(^|\s)@(?:"((?:\\.|[^"\\])*)"|([^\s@"]+))(?=\s)/g; | 22 | const MENTION_TOKEN_REGEX = /(^|\s)@(?:"((?:\\.|[^"\\])*)"|([^\s@"]+))(?=\s)/g; |
| 23 | const FILE_LINK_TOKEN_REGEX = /(^|\s)\[((?:\\.|[^\]\\])*)\]\(([^)\s]+)\)(?=\s)/g; | 23 | /** |
| | 24 | * The label body is bounded rather than `*`. Unbounded, every whitespace in |
| | 25 | * the composer is a candidate start: the engine scans the rest of the text for |
| | 26 | * a closing `]`, fails, and rescans from the next whitespace — quadratic on |
| | 27 | * input like " [[[[[…". A cap makes each attempt constant-bounded. |
| | 28 | * |
| | 29 | * Only a basename ever survives the `label !== basename` check below, so this |
| | 30 | * cannot reject a link a user could meaningfully write; the longest filename |
| | 31 | * any common filesystem allows is 255. |
| | 32 | */ |
| | 33 | const MAX_FILE_LINK_LABEL_LENGTH = 512; |
| | 34 | const FILE_LINK_TOKEN_REGEX = new RegExp( |
| | 35 | `(^|\\s)\\[((?:\\\\.|[^\\]\\\\]){0,${MAX_FILE_LINK_LABEL_LENGTH}})\\]\\(([^)\\s]+)\\)(?=\\s)`, |
| | 36 | "g", |
| | 37 | ); |
| 24 | const URI_SCHEME_REGEX = /^[A-Za-z][A-Za-z0-9+.-]*:/; | 38 | const URI_SCHEME_REGEX = /^[A-Za-z][A-Za-z0-9+.-]*:/; |
| 25 | const WINDOWS_DRIVE_PATH_REGEX = /^[A-Za-z]:[\\/]/; | 39 | const WINDOWS_DRIVE_PATH_REGEX = /^[A-Za-z]:[\\/]/; |
| 26 | // Autocomplete emits canonical file links, so ambiguous bare @scope/package text stays a package. | 40 | // Autocomplete emits canonical file links, so ambiguous bare @scope/package text stays a package. |