Add semantic token highlighting for 'that' variable and comment file references in VS Code extension Add Phone_Text_Input and Currency_Input components with formatting utilities Implement client widgets, form standardization, and soft delete functionality Add modal scroll lock and update documentation Implement comprehensive modal system with form integration and validation Fix modal component instantiation using jQuery plugin API Implement modal system with responsive sizing, queuing, and validation support Implement form submission with validation, error handling, and loading states Implement country/state selectors with dynamic data loading and Bootstrap styling Revert Rsx::Route() highlighting in Blade/PHP files Target specific PHP scopes for Rsx::Route() highlighting in Blade Expand injection selector for Rsx::Route() highlighting Add custom syntax highlighting for Rsx::Route() and Rsx.Route() calls Update jqhtml packages to v2.2.165 Add bundle path validation for common mistakes (development mode only) Create Ajax_Select_Input widget and Rsx_Reference_Data controller Create Country_Select_Input widget with default country support Initialize Tom Select on Select_Input widgets Add Tom Select bundle for enhanced select dropdowns Implement ISO 3166 geographic data system for country/region selection Implement widget-based form system with disabled state support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
224 lines
8.0 KiB
JavaScript
224 lines
8.0 KiB
JavaScript
'use strict'
|
|
|
|
const {
|
|
MAX_SAFE_COMPONENT_LENGTH,
|
|
MAX_SAFE_BUILD_LENGTH,
|
|
MAX_LENGTH,
|
|
} = require('./constants')
|
|
const debug = require('./debug')
|
|
exports = module.exports = {}
|
|
|
|
// The actual regexps go on exports.re
|
|
const re = exports.re = []
|
|
const safeRe = exports.safeRe = []
|
|
const src = exports.src = []
|
|
const safeSrc = exports.safeSrc = []
|
|
const t = exports.t = {}
|
|
let R = 0
|
|
|
|
const LETTERDASHNUMBER = '[a-zA-Z0-9-]'
|
|
|
|
// Replace some greedy regex tokens to prevent regex dos issues. These regex are
|
|
// used internally via the safeRe object since all inputs in this library get
|
|
// normalized first to trim and collapse all extra whitespace. The original
|
|
// regexes are exported for userland consumption and lower level usage. A
|
|
// future breaking change could export the safer regex only with a note that
|
|
// all input should have extra whitespace removed.
|
|
const safeRegexReplacements = [
|
|
['\\s', 1],
|
|
['\\d', MAX_LENGTH],
|
|
[LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],
|
|
]
|
|
|
|
const makeSafeRegex = (value) => {
|
|
for (const [token, max] of safeRegexReplacements) {
|
|
value = value
|
|
.split(`${token}*`).join(`${token}{0,${max}}`)
|
|
.split(`${token}+`).join(`${token}{1,${max}}`)
|
|
}
|
|
return value
|
|
}
|
|
|
|
const createToken = (name, value, isGlobal) => {
|
|
const safe = makeSafeRegex(value)
|
|
const index = R++
|
|
debug(name, index, value)
|
|
t[name] = index
|
|
src[index] = value
|
|
safeSrc[index] = safe
|
|
re[index] = new RegExp(value, isGlobal ? 'g' : undefined)
|
|
safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)
|
|
}
|
|
|
|
// The following Regular Expressions can be used for tokenizing,
|
|
// validating, and parsing SemVer version strings.
|
|
|
|
// ## Numeric Identifier
|
|
// A single `0`, or a non-zero digit followed by zero or more digits.
|
|
|
|
createToken('NUMERICIDENTIFIER', '0|[1-9]\\d*')
|
|
createToken('NUMERICIDENTIFIERLOOSE', '\\d+')
|
|
|
|
// ## Non-numeric Identifier
|
|
// Zero or more digits, followed by a letter or hyphen, and then zero or
|
|
// more letters, digits, or hyphens.
|
|
|
|
createToken('NONNUMERICIDENTIFIER', `\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)
|
|
|
|
// ## Main Version
|
|
// Three dot-separated numeric identifiers.
|
|
|
|
createToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
`(${src[t.NUMERICIDENTIFIER]})\\.` +
|
|
`(${src[t.NUMERICIDENTIFIER]})`)
|
|
|
|
createToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
`(${src[t.NUMERICIDENTIFIERLOOSE]})\\.` +
|
|
`(${src[t.NUMERICIDENTIFIERLOOSE]})`)
|
|
|
|
// ## Pre-release Version Identifier
|
|
// A numeric identifier, or a non-numeric identifier.
|
|
// Non-numberic identifiers include numberic identifiers but can be longer.
|
|
// Therefore non-numberic identifiers must go first.
|
|
|
|
createToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]
|
|
}|${src[t.NUMERICIDENTIFIER]})`)
|
|
|
|
createToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]
|
|
}|${src[t.NUMERICIDENTIFIERLOOSE]})`)
|
|
|
|
// ## Pre-release Version
|
|
// Hyphen, followed by one or more dot-separated pre-release version
|
|
// identifiers.
|
|
|
|
createToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]
|
|
}(?:\\.${src[t.PRERELEASEIDENTIFIER]})*))`)
|
|
|
|
createToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]
|
|
}(?:\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)
|
|
|
|
// ## Build Metadata Identifier
|
|
// Any combination of digits, letters, or hyphens.
|
|
|
|
createToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)
|
|
|
|
// ## Build Metadata
|
|
// Plus sign, followed by one or more period-separated build metadata
|
|
// identifiers.
|
|
|
|
createToken('BUILD', `(?:\\+(${src[t.BUILDIDENTIFIER]
|
|
}(?:\\.${src[t.BUILDIDENTIFIER]})*))`)
|
|
|
|
// ## Full Version String
|
|
// A main version, followed optionally by a pre-release version and
|
|
// build metadata.
|
|
|
|
// Note that the only major, minor, patch, and pre-release sections of
|
|
// the version string are capturing groups. The build metadata is not a
|
|
// capturing group, because it should not ever be used in version
|
|
// comparison.
|
|
|
|
createToken('FULLPLAIN', `v?${src[t.MAINVERSION]
|
|
}${src[t.PRERELEASE]}?${
|
|
src[t.BUILD]}?`)
|
|
|
|
createToken('FULL', `^${src[t.FULLPLAIN]}$`)
|
|
|
|
// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.
|
|
// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty
|
|
// common in the npm registry.
|
|
createToken('LOOSEPLAIN', `[v=\\s]*${src[t.MAINVERSIONLOOSE]
|
|
}${src[t.PRERELEASELOOSE]}?${
|
|
src[t.BUILD]}?`)
|
|
|
|
createToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)
|
|
|
|
createToken('GTLT', '((?:<|>)?=?)')
|
|
|
|
// Something like "2.*" or "1.2.x".
|
|
// Note that "x.x" is a valid xRange identifer, meaning "any version"
|
|
// Only the first item is strictly required.
|
|
createToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\*`)
|
|
createToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\*`)
|
|
|
|
createToken('XRANGEPLAIN', `[v=\\s]*(${src[t.XRANGEIDENTIFIER]})` +
|
|
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
`(?:\\.(${src[t.XRANGEIDENTIFIER]})` +
|
|
`(?:${src[t.PRERELEASE]})?${
|
|
src[t.BUILD]}?` +
|
|
`)?)?`)
|
|
|
|
createToken('XRANGEPLAINLOOSE', `[v=\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
`(?:\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +
|
|
`(?:${src[t.PRERELEASELOOSE]})?${
|
|
src[t.BUILD]}?` +
|
|
`)?)?`)
|
|
|
|
createToken('XRANGE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAIN]}$`)
|
|
createToken('XRANGELOOSE', `^${src[t.GTLT]}\\s*${src[t.XRANGEPLAINLOOSE]}$`)
|
|
|
|
// Coercion.
|
|
// Extract anything that could conceivably be a part of a valid semver
|
|
createToken('COERCEPLAIN', `${'(^|[^\\d])' +
|
|
'(\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +
|
|
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +
|
|
`(?:\\.(\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)
|
|
createToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\d])`)
|
|
createToken('COERCEFULL', src[t.COERCEPLAIN] +
|
|
`(?:${src[t.PRERELEASE]})?` +
|
|
`(?:${src[t.BUILD]})?` +
|
|
`(?:$|[^\\d])`)
|
|
createToken('COERCERTL', src[t.COERCE], true)
|
|
createToken('COERCERTLFULL', src[t.COERCEFULL], true)
|
|
|
|
// Tilde ranges.
|
|
// Meaning is "reasonably at or greater than"
|
|
createToken('LONETILDE', '(?:~>?)')
|
|
|
|
createToken('TILDETRIM', `(\\s*)${src[t.LONETILDE]}\\s+`, true)
|
|
exports.tildeTrimReplace = '$1~'
|
|
|
|
createToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)
|
|
createToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)
|
|
|
|
// Caret ranges.
|
|
// Meaning is "at least and backwards compatible with"
|
|
createToken('LONECARET', '(?:\\^)')
|
|
|
|
createToken('CARETTRIM', `(\\s*)${src[t.LONECARET]}\\s+`, true)
|
|
exports.caretTrimReplace = '$1^'
|
|
|
|
createToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)
|
|
createToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)
|
|
|
|
// A simple gt/lt/eq thing, or just "" to indicate "any version"
|
|
createToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`)
|
|
createToken('COMPARATOR', `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`)
|
|
|
|
// An expression to strip any whitespace between the gtlt and the thing
|
|
// it modifies, so that `> 1.2.3` ==> `>1.2.3`
|
|
createToken('COMPARATORTRIM', `(\\s*)${src[t.GTLT]
|
|
}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)
|
|
exports.comparatorTrimReplace = '$1$2$3'
|
|
|
|
// Something like `1.2.3 - 1.2.4`
|
|
// Note that these all use the loose form, because they'll be
|
|
// checked against either the strict or loose comparator form
|
|
// later.
|
|
createToken('HYPHENRANGE', `^\\s*(${src[t.XRANGEPLAIN]})` +
|
|
`\\s+-\\s+` +
|
|
`(${src[t.XRANGEPLAIN]})` +
|
|
`\\s*$`)
|
|
|
|
createToken('HYPHENRANGELOOSE', `^\\s*(${src[t.XRANGEPLAINLOOSE]})` +
|
|
`\\s+-\\s+` +
|
|
`(${src[t.XRANGEPLAINLOOSE]})` +
|
|
`\\s*$`)
|
|
|
|
// Star ranges basically just allow anything at all.
|
|
createToken('STAR', '(<|>)?=?\\s*\\*')
|
|
// >=0.0.0 is like a star
|
|
createToken('GTE0', '^\\s*>=\\s*0\\.0\\.0\\s*$')
|
|
createToken('GTE0PRE', '^\\s*>=\\s*0\\.0\\.0-0\\s*$')
|