Comparing version 3.7.0 to 3.8.0
@@ -1,2 +0,11 @@ | ||
export declare function joinName(flag: null, ...parts: unknown[]): string[]; | ||
export declare function joinName(...parts: unknown[]): string; | ||
/** @internal */ | ||
declare function escape(string: string): string; | ||
/** @internal */ | ||
declare function unescape(string: string): string; | ||
declare function joinNameImpl(flag: null, ...parts: unknown[]): string[]; | ||
declare function joinNameImpl(...parts: unknown[]): string; | ||
export declare const joinName: typeof joinNameImpl & { | ||
escape: typeof escape; | ||
unescape: typeof unescape; | ||
}; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.joinName = void 0; | ||
function joinName(...parts) { | ||
const escapeMatch = /[.[\]]/; | ||
const escapeRegex = /"/g; | ||
/** @internal */ | ||
function escape(string) { | ||
return string === '' || escapeMatch.test(string) | ||
? `["${string.replace(escapeRegex, '\\"')}"]` | ||
: string; | ||
} | ||
/** @internal */ | ||
function escapeToJoin(string, index) { | ||
const escaped = escape(string); | ||
return escaped === string ? (index ? `.${string}` : string) : escaped; | ||
} | ||
const unescapeMatch = /^\["(.*)"]$/; | ||
const unescapeRegex = /\\"/g; | ||
/** @internal */ | ||
function unescape(string) { | ||
const match = unescapeMatch.exec(string); | ||
return match ? match[1].replace(unescapeRegex, '"') : string; | ||
} | ||
// This regular expression splits the string into three parts: | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
// | ||
// All three parts can be empty! | ||
const nameRegex = /^([^.[\]]*(?:\.[^.[\]]+)*)(?:\.?(\["(?:[^"]|\\")*?(?<!\\)"])\.?(.*))?$/; | ||
// eslint-disable-next-line complexity -- The complexity of it _is_ high. | ||
function joinNameImpl(...parts) { | ||
// If the first argument is `null`, then we return an escaped array of parts. | ||
// Otherwise, an escaped string is returned. As we may modify `parts` later, | ||
// this has to be checked now. | ||
const returnAsParts = parts[0] === null; | ||
// Result parts (not escaped). | ||
const name = []; | ||
// This cannot be transformed into a `.forEach` loop and the length of it | ||
// can not be memoized, as we modify `parts` as we go for performance reasons. | ||
for (let index = 0; index !== parts.length; ++index) { | ||
const part = parts[index]; | ||
// All falsy values except `0` are ignored. | ||
if (part || part === 0) { | ||
if (typeof part === 'string') { | ||
if (part.indexOf('.') !== -1) { | ||
name.push(...part.split('.')); | ||
// Strings are matched against the regular expression that split it into | ||
// three parts (all can be empty): | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
const match = nameRegex.exec(part); | ||
if (match) { | ||
const [, prefix, subscript, rest] = match; | ||
if (prefix) { | ||
// We could always `.split` the `prefix`, but it results in a severe | ||
// performance hit. | ||
if (prefix.includes('.')) { | ||
name.push(...prefix.split('.')); | ||
} | ||
else { | ||
name.push(prefix); | ||
} | ||
} | ||
if (subscript) { | ||
// We could adjust the `nameRegex` to skip brackets and `unescape` | ||
// to skip this check, but then every other call (e.g., a one in the | ||
// bridge) would have to know that. The performance is not affected | ||
// much by it anyway. | ||
name.push(unescape(subscript)); | ||
// The `rest` is inlined in place as it is a single string. | ||
if (rest) { | ||
parts[index--] = rest; | ||
} | ||
} | ||
} | ||
else { | ||
// If a string is not matching the pattern, we leave it as it is. We | ||
// may want to raise a warning here as it should not happen. Most | ||
// likely it is something that should have been escaped (e.g., `[`). | ||
name.push(part); | ||
@@ -18,5 +92,18 @@ } | ||
else if (Array.isArray(part)) { | ||
parts.splice(index--, 1, ...part); | ||
// Arrays are flattened in place but only if needed, i.e., they are not | ||
// empty. We calculate the length of the overlapping parts to reuse the | ||
// `parts` array as much as possible: | ||
// [[], ...] -> [[], ...] // No change. | ||
// [['a'], ...] -> ['a', ...] // Inline in place. | ||
// [['a', 'b'], ...] -> ['a', 'b', ...] // Inline with extension. | ||
// ['a', ['b'], ...] -> ['a', 'b', ...] // Inline in place. | ||
// ['a', ['b', 'c'], ...] -> ['b', 'c', ...] // Inline with overlap. | ||
if (part.length) { | ||
const length = Math.min(index + 1, part.length); | ||
index -= length; | ||
parts.splice(index + 1, length, ...part); | ||
} | ||
} | ||
else { | ||
// Other values -- most likely numbers and `true` -- are stringified. | ||
name.push('' + part); | ||
@@ -26,4 +113,5 @@ } | ||
} | ||
return parts[0] === null ? name : name.join('.'); | ||
// We cannot escape the parts earlier as `escapeToJoin` depends on the index. | ||
return returnAsParts ? name.map(escape) : name.map(escapeToJoin).join(''); | ||
} | ||
exports.joinName = joinName; | ||
exports.joinName = Object.assign(joinNameImpl, { escape, unescape }); |
@@ -1,2 +0,11 @@ | ||
export declare function joinName(flag: null, ...parts: unknown[]): string[]; | ||
export declare function joinName(...parts: unknown[]): string; | ||
/** @internal */ | ||
declare function escape(string: string): string; | ||
/** @internal */ | ||
declare function unescape(string: string): string; | ||
declare function joinNameImpl(flag: null, ...parts: unknown[]): string[]; | ||
declare function joinNameImpl(...parts: unknown[]): string; | ||
export declare const joinName: typeof joinNameImpl & { | ||
escape: typeof escape; | ||
unescape: typeof unescape; | ||
}; | ||
export {}; |
@@ -1,11 +0,85 @@ | ||
export function joinName(...parts) { | ||
const escapeMatch = /[.[\]]/; | ||
const escapeRegex = /"/g; | ||
/** @internal */ | ||
function escape(string) { | ||
return string === '' || escapeMatch.test(string) | ||
? `["${string.replace(escapeRegex, '\\"')}"]` | ||
: string; | ||
} | ||
/** @internal */ | ||
function escapeToJoin(string, index) { | ||
const escaped = escape(string); | ||
return escaped === string ? (index ? `.${string}` : string) : escaped; | ||
} | ||
const unescapeMatch = /^\["(.*)"]$/; | ||
const unescapeRegex = /\\"/g; | ||
/** @internal */ | ||
function unescape(string) { | ||
const match = unescapeMatch.exec(string); | ||
return match ? match[1].replace(unescapeRegex, '"') : string; | ||
} | ||
// This regular expression splits the string into three parts: | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
// | ||
// All three parts can be empty! | ||
const nameRegex = /^([^.[\]]*(?:\.[^.[\]]+)*)(?:\.?(\["(?:[^"]|\\")*?(?<!\\)"])\.?(.*))?$/; | ||
// eslint-disable-next-line complexity -- The complexity of it _is_ high. | ||
function joinNameImpl(...parts) { | ||
// If the first argument is `null`, then we return an escaped array of parts. | ||
// Otherwise, an escaped string is returned. As we may modify `parts` later, | ||
// this has to be checked now. | ||
const returnAsParts = parts[0] === null; | ||
// Result parts (not escaped). | ||
const name = []; | ||
// This cannot be transformed into a `.forEach` loop and the length of it | ||
// can not be memoized, as we modify `parts` as we go for performance reasons. | ||
for (let index = 0; index !== parts.length; ++index) { | ||
const part = parts[index]; | ||
// All falsy values except `0` are ignored. | ||
if (part || part === 0) { | ||
if (typeof part === 'string') { | ||
if (part.indexOf('.') !== -1) { | ||
name.push(...part.split('.')); | ||
// Strings are matched against the regular expression that split it into | ||
// three parts (all can be empty): | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
const match = nameRegex.exec(part); | ||
if (match) { | ||
const [, prefix, subscript, rest] = match; | ||
if (prefix) { | ||
// We could always `.split` the `prefix`, but it results in a severe | ||
// performance hit. | ||
if (prefix.includes('.')) { | ||
name.push(...prefix.split('.')); | ||
} | ||
else { | ||
name.push(prefix); | ||
} | ||
} | ||
if (subscript) { | ||
// We could adjust the `nameRegex` to skip brackets and `unescape` | ||
// to skip this check, but then every other call (e.g., a one in the | ||
// bridge) would have to know that. The performance is not affected | ||
// much by it anyway. | ||
name.push(unescape(subscript)); | ||
// The `rest` is inlined in place as it is a single string. | ||
if (rest) { | ||
parts[index--] = rest; | ||
} | ||
} | ||
} | ||
else { | ||
// If a string is not matching the pattern, we leave it as it is. We | ||
// may want to raise a warning here as it should not happen. Most | ||
// likely it is something that should have been escaped (e.g., `[`). | ||
name.push(part); | ||
@@ -15,5 +89,18 @@ } | ||
else if (Array.isArray(part)) { | ||
parts.splice(index--, 1, ...part); | ||
// Arrays are flattened in place but only if needed, i.e., they are not | ||
// empty. We calculate the length of the overlapping parts to reuse the | ||
// `parts` array as much as possible: | ||
// [[], ...] -> [[], ...] // No change. | ||
// [['a'], ...] -> ['a', ...] // Inline in place. | ||
// [['a', 'b'], ...] -> ['a', 'b', ...] // Inline with extension. | ||
// ['a', ['b'], ...] -> ['a', 'b', ...] // Inline in place. | ||
// ['a', ['b', 'c'], ...] -> ['b', 'c', ...] // Inline with overlap. | ||
if (part.length) { | ||
const length = Math.min(index + 1, part.length); | ||
index -= length; | ||
parts.splice(index + 1, length, ...part); | ||
} | ||
} | ||
else { | ||
// Other values -- most likely numbers and `true` -- are stringified. | ||
name.push('' + part); | ||
@@ -23,3 +110,5 @@ } | ||
} | ||
return parts[0] === null ? name : name.join('.'); | ||
// We cannot escape the parts earlier as `escapeToJoin` depends on the index. | ||
return returnAsParts ? name.map(escape) : name.map(escapeToJoin).join(''); | ||
} | ||
export const joinName = Object.assign(joinNameImpl, { escape, unescape }); |
{ | ||
"name": "uniforms", | ||
"version": "3.7.0", | ||
"version": "3.8.0", | ||
"license": "MIT", | ||
@@ -44,3 +44,3 @@ "main": "./cjs/index.js", | ||
}, | ||
"gitHead": "80b6a389a1f6271e844bf350a2b6f22592a7fcf6" | ||
"gitHead": "dbd09e1ab889be7814894e47e3ee3840947d5c7b" | ||
} |
@@ -1,17 +0,119 @@ | ||
export function joinName(flag: null, ...parts: unknown[]): string[]; | ||
export function joinName(...parts: unknown[]): string; | ||
export function joinName(...parts: unknown[]) { | ||
const escapeMatch = /[.[\]]/; | ||
const escapeRegex = /"/g; | ||
/** @internal */ | ||
function escape(string: string) { | ||
return string === '' || escapeMatch.test(string) | ||
? `["${string.replace(escapeRegex, '\\"')}"]` | ||
: string; | ||
} | ||
/** @internal */ | ||
function escapeToJoin(string: string, index: number) { | ||
const escaped = escape(string); | ||
return escaped === string ? (index ? `.${string}` : string) : escaped; | ||
} | ||
const unescapeMatch = /^\["(.*)"]$/; | ||
const unescapeRegex = /\\"/g; | ||
/** @internal */ | ||
function unescape(string: string) { | ||
const match = unescapeMatch.exec(string); | ||
return match ? match[1].replace(unescapeRegex, '"') : string; | ||
} | ||
// This regular expression splits the string into three parts: | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
// | ||
// All three parts can be empty! | ||
const nameRegex = | ||
/^([^.[\]]*(?:\.[^.[\]]+)*)(?:\.?(\["(?:[^"]|\\")*?(?<!\\)"])\.?(.*))?$/; | ||
// We cannot use `joinName` as we export a function with assigned internal | ||
// helpers and the symbol has to stay free until then. | ||
function joinNameImpl(flag: null, ...parts: unknown[]): string[]; | ||
function joinNameImpl(...parts: unknown[]): string; | ||
// eslint-disable-next-line complexity -- The complexity of it _is_ high. | ||
function joinNameImpl(...parts: unknown[]) { | ||
// If the first argument is `null`, then we return an escaped array of parts. | ||
// Otherwise, an escaped string is returned. As we may modify `parts` later, | ||
// this has to be checked now. | ||
const returnAsParts = parts[0] === null; | ||
// Result parts (not escaped). | ||
const name: string[] = []; | ||
// This cannot be transformed into a `.forEach` loop and the length of it | ||
// can not be memoized, as we modify `parts` as we go for performance reasons. | ||
for (let index = 0; index !== parts.length; ++index) { | ||
const part = parts[index]; | ||
// All falsy values except `0` are ignored. | ||
if (part || part === 0) { | ||
if (typeof part === 'string') { | ||
if (part.indexOf('.') !== -1) { | ||
name.push(...part.split('.')); | ||
// Strings are matched against the regular expression that split it into | ||
// three parts (all can be empty): | ||
// `prefix` is a dotted name, e.g., `object.nested.2.field` at the | ||
// front (hence prefix). It covers most standard usecases. | ||
// `subscript` is a `["..."]` subscript after the prefix. The content | ||
// within should be escaped by the user, e.g., `["\\""]`. | ||
// `rest` is anything following the subscript. The leading dot (`.`) | ||
// is stripped (`.a` -> `a`) if there is one. It is empty if | ||
// `subscript` is empty. | ||
const match = nameRegex.exec(part); | ||
if (match) { | ||
const [, prefix, subscript, rest] = match; | ||
if (prefix) { | ||
// We could always `.split` the `prefix`, but it results in a severe | ||
// performance hit. | ||
if (prefix.includes('.')) { | ||
name.push(...prefix.split('.')); | ||
} else { | ||
name.push(prefix); | ||
} | ||
} | ||
if (subscript) { | ||
// We could adjust the `nameRegex` to skip brackets and `unescape` | ||
// to skip this check, but then every other call (e.g., a one in the | ||
// bridge) would have to know that. The performance is not affected | ||
// much by it anyway. | ||
name.push(unescape(subscript)); | ||
// The `rest` is inlined in place as it is a single string. | ||
if (rest) { | ||
parts[index--] = rest; | ||
} | ||
} | ||
} else { | ||
// If a string is not matching the pattern, we leave it as it is. We | ||
// may want to raise a warning here as it should not happen. Most | ||
// likely it is something that should have been escaped (e.g., `[`). | ||
name.push(part); | ||
} | ||
} else if (Array.isArray(part)) { | ||
parts.splice(index--, 1, ...part); | ||
// Arrays are flattened in place but only if needed, i.e., they are not | ||
// empty. We calculate the length of the overlapping parts to reuse the | ||
// `parts` array as much as possible: | ||
// [[], ...] -> [[], ...] // No change. | ||
// [['a'], ...] -> ['a', ...] // Inline in place. | ||
// [['a', 'b'], ...] -> ['a', 'b', ...] // Inline with extension. | ||
// ['a', ['b'], ...] -> ['a', 'b', ...] // Inline in place. | ||
// ['a', ['b', 'c'], ...] -> ['b', 'c', ...] // Inline with overlap. | ||
if (part.length) { | ||
const length = Math.min(index + 1, part.length); | ||
index -= length; | ||
parts.splice(index + 1, length, ...part); | ||
} | ||
} else { | ||
// Other values -- most likely numbers and `true` -- are stringified. | ||
name.push('' + part); | ||
@@ -22,3 +124,6 @@ } | ||
return parts[0] === null ? name : name.join('.'); | ||
// We cannot escape the parts earlier as `escapeToJoin` depends on the index. | ||
return returnAsParts ? name.map(escape) : name.map(escapeToJoin).join(''); | ||
} | ||
export const joinName = Object.assign(joinNameImpl, { escape, unescape }); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
216767
5052