Website Structure
This commit is contained in:
parent
62812f2090
commit
71f0676a62
22365 changed files with 4265753 additions and 791 deletions
260
Frontend-Learner/node_modules/dot-prop/index.d.ts
generated
vendored
Normal file
260
Frontend-Learner/node_modules/dot-prop/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
import {type Get} from 'type-fest';
|
||||
|
||||
/**
|
||||
Get the value of the property at the given path.
|
||||
|
||||
@param object - Object or array to get the `path` value.
|
||||
@param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (`'users[0].name'`) or dot notation (`'users.0.name'`). Both syntaxes are equivalent and will create arrays when setting values. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers. When using array paths, numeric strings are normalized to numbers for simplicity (treating `['users', '0']` the same as `['users', 0]`).
|
||||
@param defaultValue - Default value.
|
||||
|
||||
@example
|
||||
```
|
||||
import {getProperty} from 'dot-prop';
|
||||
|
||||
getProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep');
|
||||
//=> undefined
|
||||
|
||||
getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
|
||||
//=> 'default value'
|
||||
|
||||
getProperty({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: [{bar: 'unicorn'}]}, 'foo[0].bar');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: [{bar: 'unicorn'}]}, 'foo.0.bar');
|
||||
//=> 'unicorn'
|
||||
```
|
||||
*/
|
||||
export function getProperty<ObjectType, PathType extends string, DefaultValue = undefined>(
|
||||
object: ObjectType,
|
||||
path: PathType | ReadonlyArray<string | number>,
|
||||
defaultValue?: DefaultValue
|
||||
): ObjectType extends Record<string, unknown> | unknown[]
|
||||
? (unknown extends Get<ObjectType, PathType> ? DefaultValue : Get<ObjectType, PathType>)
|
||||
: DefaultValue extends undefined ? unknown : DefaultValue;
|
||||
|
||||
/**
|
||||
Set the property at the given path to the given value.
|
||||
|
||||
@param object - Object or array to set the `path` value.
|
||||
@param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (`'users[0].name'`) or dot notation (`'users.0.name'`). Both syntaxes are equivalent and will create arrays when setting values. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers. When using array paths, numeric strings are normalized to numbers for simplicity (treating `['users', '0']` the same as `['users', 0]`).
|
||||
@param value - Value to set at `path`.
|
||||
@returns The object.
|
||||
|
||||
@example
|
||||
```
|
||||
import {setProperty} from 'dot-prop';
|
||||
|
||||
const object = {foo: {bar: 'a'}};
|
||||
setProperty(object, 'foo.bar', 'b');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b'}}
|
||||
|
||||
const foo = setProperty({}, 'foo.bar', 'c');
|
||||
console.log(foo);
|
||||
//=> {foo: {bar: 'c'}}
|
||||
|
||||
setProperty(object, 'foo.baz', 'x');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x'}}
|
||||
|
||||
setProperty(object, 'foo.biz[0]', 'a');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x', biz: ['a']}}
|
||||
|
||||
setProperty(object, 'foo.items.0', 'first');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x', biz: ['a'], items: ['first']}}
|
||||
```
|
||||
*/
|
||||
export function setProperty<ObjectType extends (Record<string, any> | unknown[])>(
|
||||
object: ObjectType,
|
||||
path: string | ReadonlyArray<string | number>,
|
||||
value: unknown
|
||||
): ObjectType;
|
||||
|
||||
/**
|
||||
Check whether the property at the given path exists.
|
||||
|
||||
@param object - Object or array to test the `path` value.
|
||||
@param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (`'users[0].name'`) or dot notation (`'users.0.name'`). Both syntaxes are equivalent and will create arrays when setting values. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers. When using array paths, numeric strings are normalized to numbers for simplicity (treating `['users', '0']` the same as `['users', 0]`).
|
||||
|
||||
@example
|
||||
```
|
||||
import {hasProperty} from 'dot-prop';
|
||||
|
||||
hasProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
|
||||
//=> true
|
||||
```
|
||||
*/
|
||||
export function hasProperty(object: Record<string, any> | unknown[] | undefined, path: string | ReadonlyArray<string | number>): boolean;
|
||||
|
||||
/**
|
||||
Delete the property at the given path.
|
||||
|
||||
@param object - Object or array to delete the `path` value.
|
||||
@param path - Path of the property in the object, using `.` to separate each nested key. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (`'users[0].name'`) or dot notation (`'users.0.name'`). Both syntaxes are equivalent and will create arrays when setting values. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers. When using array paths, numeric strings are normalized to numbers for simplicity (treating `['users', '0']` the same as `['users', 0]`).
|
||||
@returns A boolean of whether the property existed before being deleted.
|
||||
|
||||
@example
|
||||
```
|
||||
import {deleteProperty} from 'dot-prop';
|
||||
|
||||
const object = {foo: {bar: 'a'}};
|
||||
deleteProperty(object, 'foo.bar');
|
||||
console.log(object);
|
||||
//=> {foo: {}}
|
||||
|
||||
object.foo.bar = {x: 'y', y: 'x'};
|
||||
deleteProperty(object, 'foo.bar.x');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: {y: 'x'}}}
|
||||
```
|
||||
*/
|
||||
export function deleteProperty(object: Record<string, any> | unknown[], path: string | ReadonlyArray<string | number>): boolean;
|
||||
|
||||
/**
|
||||
Escape special characters in a path. Useful for sanitizing user input.
|
||||
|
||||
@param path - The dot path to sanitize.
|
||||
|
||||
@example
|
||||
```
|
||||
import {getProperty, escapePath} from 'dot-prop';
|
||||
|
||||
const object = {
|
||||
foo: {
|
||||
bar: '👸🏻 You found me Mario!',
|
||||
},
|
||||
'foo.bar' : '🍄 The princess is in another castle!',
|
||||
};
|
||||
const escapedPath = escapePath('foo.bar');
|
||||
|
||||
console.log(getProperty(object, escapedPath));
|
||||
//=> '🍄 The princess is in another castle!'
|
||||
```
|
||||
*/
|
||||
export function escapePath(path: string): string;
|
||||
|
||||
/**
|
||||
Parse a dot path into an array of path segments.
|
||||
|
||||
@param path - Path to parse. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (`'users[0].name'`) or dot notation (`'users.0.name'`). Both syntaxes are equivalent. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers.
|
||||
@returns An array of path segments where numbers represent array indices and strings represent object keys.
|
||||
|
||||
@example
|
||||
```
|
||||
import {parsePath} from 'dot-prop';
|
||||
|
||||
parsePath('foo.bar');
|
||||
//=> ['foo', 'bar']
|
||||
|
||||
parsePath('foo[0].bar');
|
||||
//=> ['foo', 0, 'bar']
|
||||
|
||||
parsePath('foo.0.bar');
|
||||
//=> ['foo', 0, 'bar']
|
||||
|
||||
parsePath('foo\\.bar');
|
||||
//=> ['foo.bar']
|
||||
|
||||
// Use case: Iterate over path segments to build up a nested object
|
||||
const path = 'users[0].profile.settings.theme';
|
||||
const segments = parsePath(path);
|
||||
//=> ['users', 0, 'profile', 'settings', 'theme']
|
||||
```
|
||||
*/
|
||||
export function parsePath(path: string): Array<string | number>;
|
||||
|
||||
/**
|
||||
Convert an array of path segments back into a path string.
|
||||
|
||||
@param pathSegments - Array of path segments where numbers represent array indices and strings represent object keys.
|
||||
@param options - Options for stringifying the path.
|
||||
|
||||
@example
|
||||
```
|
||||
import {stringifyPath} from 'dot-prop';
|
||||
|
||||
stringifyPath(['foo', 'bar']);
|
||||
//=> 'foo.bar'
|
||||
|
||||
stringifyPath(['foo', 0, 'bar']);
|
||||
//=> 'foo[0].bar'
|
||||
|
||||
stringifyPath(['foo', '0', 'bar']);
|
||||
//=> 'foo[0].bar'
|
||||
|
||||
// With preferDotForIndices option
|
||||
stringifyPath(['foo', 0, 'bar'], {preferDotForIndices: true});
|
||||
//=> 'foo.0.bar'
|
||||
```
|
||||
*/
|
||||
export function stringifyPath(pathSegments: ReadonlyArray<string | number>, options?: {preferDotForIndices?: boolean}): string;
|
||||
|
||||
/**
|
||||
Returns an array of every path. Non-empty plain objects and arrays are deeply recursed and are not themselves included.
|
||||
|
||||
This can be useful to help flatten an object for an API that only accepts key-value pairs or for a tagged template literal.
|
||||
|
||||
@param object - The object to iterate through.
|
||||
|
||||
@example
|
||||
```
|
||||
import {getProperty, deepKeys} from 'dot-prop';
|
||||
|
||||
const user = {
|
||||
name: {
|
||||
first: 'Richie',
|
||||
last: 'Bendall',
|
||||
},
|
||||
activeTasks: [],
|
||||
currentProject: null
|
||||
};
|
||||
|
||||
for (const property of deepKeys(user)) {
|
||||
console.log(`${property}: ${getProperty(user, property)}`);
|
||||
//=> name.first: Richie
|
||||
//=> name.last: Bendall
|
||||
//=> activeTasks: []
|
||||
//=> currentProject: null
|
||||
}
|
||||
```
|
||||
*/
|
||||
export function deepKeys(object: unknown): string[];
|
||||
|
||||
/**
|
||||
Convert an object with dot paths into a nested object.
|
||||
|
||||
Uses the same path rules and escaping as the rest of the API.
|
||||
|
||||
@param object - A plain object mapping paths to values.
|
||||
@returns A new nested object.
|
||||
|
||||
@example
|
||||
```
|
||||
import {unflatten} from 'dot-prop';
|
||||
|
||||
const flat = {
|
||||
'unicorn.name': 'Rainbow Dash',
|
||||
'unicorn.color': '🦄',
|
||||
'unicorn.treasures[0]': 'sparkles',
|
||||
'unicorn.treasures[1]': 'glitter',
|
||||
};
|
||||
|
||||
unflatten(flat);
|
||||
//=> {
|
||||
//=> unicorn: {
|
||||
//=> name: 'Rainbow Dash',
|
||||
//=> color: '🦄',
|
||||
//=> treasures: ['sparkles', 'glitter']
|
||||
//=> }
|
||||
//=> }
|
||||
```
|
||||
*/
|
||||
export function unflatten(object: Record<string, unknown>): Record<string, unknown>;
|
||||
498
Frontend-Learner/node_modules/dot-prop/index.js
generated
vendored
Normal file
498
Frontend-Learner/node_modules/dot-prop/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
const isObject = value => {
|
||||
const type = typeof value;
|
||||
return value !== null && (type === 'object' || type === 'function');
|
||||
};
|
||||
|
||||
// Optimized empty check without creating an array.
|
||||
const isEmptyObject = value => {
|
||||
if (!isObject(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const key in value) {
|
||||
if (Object.hasOwn(value, key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const disallowedKeys = new Set([
|
||||
'__proto__',
|
||||
'prototype',
|
||||
'constructor',
|
||||
]);
|
||||
|
||||
// Maximum allowed array index to prevent DoS via memory exhaustion.
|
||||
const MAX_ARRAY_INDEX = 1_000_000;
|
||||
|
||||
// Optimized digit check without Set overhead.
|
||||
const isDigit = character => character >= '0' && character <= '9';
|
||||
|
||||
// Check if a segment should be coerced to a number.
|
||||
function shouldCoerceToNumber(segment) {
|
||||
// Only coerce valid non-negative integers without leading zeros.
|
||||
if (segment === '0') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (/^[1-9]\d*$/.test(segment)) {
|
||||
const parsedNumber = Number.parseInt(segment, 10);
|
||||
// Check within safe integer range and under MAX_ARRAY_INDEX to prevent DoS.
|
||||
return parsedNumber <= Number.MAX_SAFE_INTEGER && parsedNumber <= MAX_ARRAY_INDEX;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper to process a path segment (eliminates duplication).
|
||||
function processSegment(segment, parts) {
|
||||
if (disallowedKeys.has(segment)) {
|
||||
return false; // Signal to return empty array.
|
||||
}
|
||||
|
||||
if (segment && shouldCoerceToNumber(segment)) {
|
||||
parts.push(Number.parseInt(segment, 10));
|
||||
} else {
|
||||
parts.push(segment);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function parsePath(path) { // eslint-disable-line complexity
|
||||
if (typeof path !== 'string') {
|
||||
throw new TypeError(`Expected a string, got ${typeof path}`);
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
let currentSegment = '';
|
||||
let currentPart = 'start';
|
||||
let isEscaping = false;
|
||||
let position = 0;
|
||||
|
||||
for (const character of path) {
|
||||
position++;
|
||||
|
||||
// Handle escaping.
|
||||
if (isEscaping) {
|
||||
currentSegment += character;
|
||||
isEscaping = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle escape character.
|
||||
if (character === '\\') {
|
||||
if (currentPart === 'index') {
|
||||
throw new Error(`Invalid character '${character}' in an index at position ${position}`);
|
||||
}
|
||||
|
||||
if (currentPart === 'indexEnd') {
|
||||
throw new Error(`Invalid character '${character}' after an index at position ${position}`);
|
||||
}
|
||||
|
||||
isEscaping = true;
|
||||
currentPart = currentPart === 'start' ? 'property' : currentPart;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (character) {
|
||||
case '.': {
|
||||
if (currentPart === 'index') {
|
||||
throw new Error(`Invalid character '${character}' in an index at position ${position}`);
|
||||
}
|
||||
|
||||
if (currentPart === 'indexEnd') {
|
||||
currentPart = 'property';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!processSegment(currentSegment, parts)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
currentSegment = '';
|
||||
currentPart = 'property';
|
||||
break;
|
||||
}
|
||||
|
||||
case '[': {
|
||||
if (currentPart === 'index') {
|
||||
throw new Error(`Invalid character '${character}' in an index at position ${position}`);
|
||||
}
|
||||
|
||||
if (currentPart === 'indexEnd') {
|
||||
currentPart = 'index';
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentPart === 'property' || currentPart === 'start') {
|
||||
// Only push if we have content OR if we're in 'property' mode (not 'start')
|
||||
if ((currentSegment || currentPart === 'property') && !processSegment(currentSegment, parts)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
currentSegment = '';
|
||||
}
|
||||
|
||||
currentPart = 'index';
|
||||
break;
|
||||
}
|
||||
|
||||
case ']': {
|
||||
if (currentPart === 'index') {
|
||||
if (currentSegment === '') {
|
||||
// Empty brackets - backtrack and treat as literal
|
||||
const lastSegment = parts.pop() || '';
|
||||
currentSegment = lastSegment + '[]';
|
||||
currentPart = 'property';
|
||||
} else {
|
||||
// Index must be digits only (enforced by default case)
|
||||
const parsedNumber = Number.parseInt(currentSegment, 10);
|
||||
const isValidInteger = !Number.isNaN(parsedNumber)
|
||||
&& Number.isFinite(parsedNumber)
|
||||
&& parsedNumber >= 0
|
||||
&& parsedNumber <= Number.MAX_SAFE_INTEGER
|
||||
&& parsedNumber <= MAX_ARRAY_INDEX
|
||||
&& currentSegment === String(parsedNumber);
|
||||
|
||||
if (isValidInteger) {
|
||||
parts.push(parsedNumber);
|
||||
} else {
|
||||
// Keep as string if not a valid integer representation or exceeds MAX_ARRAY_INDEX
|
||||
parts.push(currentSegment);
|
||||
}
|
||||
|
||||
currentSegment = '';
|
||||
currentPart = 'indexEnd';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentPart === 'indexEnd') {
|
||||
throw new Error(`Invalid character '${character}' after an index at position ${position}`);
|
||||
}
|
||||
|
||||
// In property context, treat ] as literal character
|
||||
currentSegment += character;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (currentPart === 'index' && !isDigit(character)) {
|
||||
throw new Error(`Invalid character '${character}' in an index at position ${position}`);
|
||||
}
|
||||
|
||||
if (currentPart === 'indexEnd') {
|
||||
throw new Error(`Invalid character '${character}' after an index at position ${position}`);
|
||||
}
|
||||
|
||||
if (currentPart === 'start') {
|
||||
currentPart = 'property';
|
||||
}
|
||||
|
||||
currentSegment += character;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle unfinished escaping (trailing backslash)
|
||||
if (isEscaping) {
|
||||
currentSegment += '\\';
|
||||
}
|
||||
|
||||
// Handle end of path
|
||||
switch (currentPart) {
|
||||
case 'property': {
|
||||
if (!processSegment(currentSegment, parts)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'index': {
|
||||
throw new Error('Index was not closed');
|
||||
}
|
||||
|
||||
case 'start': {
|
||||
parts.push('');
|
||||
break;
|
||||
}
|
||||
// No default
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
function normalizePath(path) {
|
||||
if (typeof path === 'string') {
|
||||
return parsePath(path);
|
||||
}
|
||||
|
||||
if (Array.isArray(path)) {
|
||||
const normalized = [];
|
||||
|
||||
for (const [index, segment] of path.entries()) {
|
||||
// Type validation.
|
||||
if (typeof segment !== 'string' && typeof segment !== 'number') {
|
||||
throw new TypeError(`Expected a string or number for path segment at index ${index}, got ${typeof segment}`);
|
||||
}
|
||||
|
||||
// Validate numbers are finite (reject NaN, Infinity, -Infinity).
|
||||
if (typeof segment === 'number' && !Number.isFinite(segment)) {
|
||||
throw new TypeError(`Path segment at index ${index} must be a finite number, got ${segment}`);
|
||||
}
|
||||
|
||||
// Check for disallowed keys.
|
||||
if (disallowedKeys.has(segment)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Normalize numeric strings to numbers for simplicity.
|
||||
// This treats ['items', '0'] the same as ['items', 0].
|
||||
if (typeof segment === 'string' && shouldCoerceToNumber(segment)) {
|
||||
normalized.push(Number.parseInt(segment, 10));
|
||||
} else {
|
||||
normalized.push(segment);
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getProperty(object, path, value) {
|
||||
if (!isObject(object) || (typeof path !== 'string' && !Array.isArray(path))) {
|
||||
return value === undefined ? object : value;
|
||||
}
|
||||
|
||||
const pathArray = normalizePath(path);
|
||||
if (pathArray.length === 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
for (let index = 0; index < pathArray.length; index++) {
|
||||
const key = pathArray[index];
|
||||
object = object[key];
|
||||
|
||||
if (object === undefined || object === null) {
|
||||
// Return default value if we hit undefined/null before the end of the path.
|
||||
// This ensures get({foo: null}, 'foo.bar') returns the default value, not null.
|
||||
if (index !== pathArray.length - 1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return object === undefined ? value : object;
|
||||
}
|
||||
|
||||
export function setProperty(object, path, value) {
|
||||
if (!isObject(object) || (typeof path !== 'string' && !Array.isArray(path))) {
|
||||
return object;
|
||||
}
|
||||
|
||||
const root = object;
|
||||
const pathArray = normalizePath(path);
|
||||
|
||||
if (pathArray.length === 0) {
|
||||
return object;
|
||||
}
|
||||
|
||||
for (let index = 0; index < pathArray.length; index++) {
|
||||
const key = pathArray[index];
|
||||
|
||||
if (index === pathArray.length - 1) {
|
||||
object[key] = value;
|
||||
} else if (!isObject(object[key])) {
|
||||
const nextKey = pathArray[index + 1];
|
||||
// Create arrays for numeric indices, objects for string keys
|
||||
const shouldCreateArray = typeof nextKey === 'number';
|
||||
object[key] = shouldCreateArray ? [] : {};
|
||||
}
|
||||
|
||||
object = object[key];
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
export function deleteProperty(object, path) {
|
||||
if (!isObject(object) || (typeof path !== 'string' && !Array.isArray(path))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pathArray = normalizePath(path);
|
||||
|
||||
if (pathArray.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let index = 0; index < pathArray.length; index++) {
|
||||
const key = pathArray[index];
|
||||
|
||||
if (index === pathArray.length - 1) {
|
||||
const existed = Object.hasOwn(object, key);
|
||||
if (!existed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete object[key];
|
||||
return true;
|
||||
}
|
||||
|
||||
object = object[key];
|
||||
|
||||
if (!isObject(object)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function hasProperty(object, path) {
|
||||
if (!isObject(object) || (typeof path !== 'string' && !Array.isArray(path))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pathArray = normalizePath(path);
|
||||
if (pathArray.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const key of pathArray) {
|
||||
if (!isObject(object) || !(key in object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
object = object[key];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function escapePath(path) {
|
||||
if (typeof path !== 'string') {
|
||||
throw new TypeError(`Expected a string, got ${typeof path}`);
|
||||
}
|
||||
|
||||
// Escape special characters in one pass
|
||||
return path.replaceAll(/[\\.[]/g, String.raw`\$&`);
|
||||
}
|
||||
|
||||
function normalizeEntries(value) {
|
||||
const entries = Object.entries(value);
|
||||
if (Array.isArray(value)) {
|
||||
return entries.map(([key, entryValue]) => {
|
||||
// Use shouldCoerceToNumber for consistency with parsePath
|
||||
const normalizedKey = shouldCoerceToNumber(key)
|
||||
? Number.parseInt(key, 10)
|
||||
: key;
|
||||
return [normalizedKey, entryValue];
|
||||
});
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
export function stringifyPath(pathSegments, options = {}) {
|
||||
if (!Array.isArray(pathSegments)) {
|
||||
throw new TypeError(`Expected an array, got ${typeof pathSegments}`);
|
||||
}
|
||||
|
||||
const {preferDotForIndices = false} = options;
|
||||
const parts = [];
|
||||
|
||||
for (const [index, segment] of pathSegments.entries()) {
|
||||
// Validate segment types at runtime
|
||||
if (typeof segment !== 'string' && typeof segment !== 'number') {
|
||||
throw new TypeError(`Expected a string or number for path segment at index ${index}, got ${typeof segment}`);
|
||||
}
|
||||
|
||||
if (typeof segment === 'number') {
|
||||
// Handle numeric indices
|
||||
if (!Number.isInteger(segment) || segment < 0) {
|
||||
// Non-integer or negative numbers are treated as string keys
|
||||
const escaped = escapePath(String(segment));
|
||||
parts.push(index === 0 ? escaped : `.${escaped}`);
|
||||
} else if (preferDotForIndices && index > 0) {
|
||||
parts.push(`.${segment}`);
|
||||
} else {
|
||||
parts.push(`[${segment}]`);
|
||||
}
|
||||
} else if (typeof segment === 'string') {
|
||||
if (segment === '') {
|
||||
// Empty string handling
|
||||
if (index === 0) {
|
||||
// Start with empty string, no prefix needed
|
||||
} else {
|
||||
parts.push('.');
|
||||
}
|
||||
} else if (shouldCoerceToNumber(segment)) {
|
||||
// Numeric strings are normalized to numbers
|
||||
const numericValue = Number.parseInt(segment, 10);
|
||||
if (preferDotForIndices && index > 0) {
|
||||
parts.push(`.${numericValue}`);
|
||||
} else {
|
||||
parts.push(`[${numericValue}]`);
|
||||
}
|
||||
} else {
|
||||
// Regular strings use dot notation
|
||||
const escaped = escapePath(segment);
|
||||
parts.push(index === 0 ? escaped : `.${escaped}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
function * deepKeysIterator(object, currentPath = [], ancestors = new Set()) {
|
||||
if (!isObject(object) || isEmptyObject(object)) {
|
||||
if (currentPath.length > 0) {
|
||||
yield stringifyPath(currentPath);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this object is already in the current path (circular reference)
|
||||
if (ancestors.has(object)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to ancestors, recurse, then remove (backtrack)
|
||||
ancestors.add(object);
|
||||
|
||||
// Reuse currentPath array by push/pop instead of creating new arrays
|
||||
for (const [key, value] of normalizeEntries(object)) {
|
||||
currentPath.push(key);
|
||||
yield * deepKeysIterator(value, currentPath, ancestors);
|
||||
currentPath.pop();
|
||||
}
|
||||
|
||||
ancestors.delete(object);
|
||||
}
|
||||
|
||||
export function deepKeys(object) {
|
||||
return [...deepKeysIterator(object)];
|
||||
}
|
||||
|
||||
export function unflatten(object) {
|
||||
const result = {};
|
||||
if (!isObject(object)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const [path, value] of Object.entries(object)) {
|
||||
setProperty(result, path, value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
9
Frontend-Learner/node_modules/dot-prop/license
generated
vendored
Normal file
9
Frontend-Learner/node_modules/dot-prop/license
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
58
Frontend-Learner/node_modules/dot-prop/package.json
generated
vendored
Normal file
58
Frontend-Learner/node_modules/dot-prop/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"name": "dot-prop",
|
||||
"version": "10.1.0",
|
||||
"description": "Get, set, or delete a property from a nested object using a dot path",
|
||||
"license": "MIT",
|
||||
"repository": "sindresorhus/dot-prop",
|
||||
"funding": "https://github.com/sponsors/sindresorhus",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "https://sindresorhus.com"
|
||||
},
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"types": "./index.d.ts",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && ava && tsc",
|
||||
"bench": "node benchmark.js",
|
||||
"coverage": "c8 ava"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"keywords": [
|
||||
"object",
|
||||
"prop",
|
||||
"property",
|
||||
"dot",
|
||||
"path",
|
||||
"get",
|
||||
"set",
|
||||
"delete",
|
||||
"access",
|
||||
"notation",
|
||||
"dotty",
|
||||
"dottie",
|
||||
"unflatten",
|
||||
"expand"
|
||||
],
|
||||
"dependencies": {
|
||||
"type-fest": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^6.4.1",
|
||||
"benchmark": "^2.1.4",
|
||||
"c8": "^10.1.3",
|
||||
"expect-type": "^1.2.2",
|
||||
"typescript": "^5.9.2",
|
||||
"xo": "^1.2.2"
|
||||
}
|
||||
}
|
||||
304
Frontend-Learner/node_modules/dot-prop/readme.md
generated
vendored
Normal file
304
Frontend-Learner/node_modules/dot-prop/readme.md
generated
vendored
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
# dot-prop
|
||||
|
||||
> Get, set, or delete a property from a nested object using a dot path
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
npm install dot-prop
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import {getProperty, setProperty, hasProperty, deleteProperty} from 'dot-prop';
|
||||
|
||||
// Getter
|
||||
getProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep');
|
||||
//=> undefined
|
||||
|
||||
getProperty({foo: {bar: 'a'}}, 'foo.notDefined.deep', 'default value');
|
||||
//=> 'default value'
|
||||
|
||||
getProperty({foo: {'dot.dot': 'unicorn'}}, 'foo.dot\\.dot');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: [{bar: 'unicorn'}]}, 'foo[0].bar');
|
||||
//=> 'unicorn'
|
||||
|
||||
getProperty({foo: [{bar: 'unicorn'}]}, 'foo.0.bar');
|
||||
//=> 'unicorn'
|
||||
|
||||
// Setter
|
||||
const object = {foo: {bar: 'a'}};
|
||||
setProperty(object, 'foo.bar', 'b');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b'}}
|
||||
|
||||
const foo = setProperty({}, 'foo.bar', 'c');
|
||||
console.log(foo);
|
||||
//=> {foo: {bar: 'c'}}
|
||||
|
||||
setProperty(object, 'foo.baz', 'x');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x'}}
|
||||
|
||||
setProperty(object, 'foo.biz[0]', 'a');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x', biz: ['a']}}
|
||||
|
||||
setProperty(object, 'foo.items.0', 'first');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: 'b', baz: 'x', biz: ['a'], items: ['first']}}
|
||||
|
||||
// Has
|
||||
hasProperty({foo: {bar: 'unicorn'}}, 'foo.bar');
|
||||
//=> true
|
||||
|
||||
// Deleter
|
||||
const object = {foo: {bar: 'a'}};
|
||||
deleteProperty(object, 'foo.bar');
|
||||
console.log(object);
|
||||
//=> {foo: {}}
|
||||
|
||||
object.foo.bar = {x: 'y', y: 'x'};
|
||||
deleteProperty(object, 'foo.bar.x');
|
||||
console.log(object);
|
||||
//=> {foo: {bar: {y: 'x'}}}
|
||||
```
|
||||
|
||||
### Array paths
|
||||
|
||||
For improved performance and interoperability with other libraries, you can also pass paths as arrays instead of strings. This avoids the overhead of parsing string paths.
|
||||
|
||||
```js
|
||||
import {getProperty, setProperty} from 'dot-prop';
|
||||
|
||||
const object = {
|
||||
users: [
|
||||
{name: 'Alice', role: 'admin'},
|
||||
{name: 'Bob', role: 'user'}
|
||||
]
|
||||
};
|
||||
|
||||
// Using array paths - no parsing overhead
|
||||
getProperty(object, ['users', 0, 'name']);
|
||||
//=> 'Alice'
|
||||
|
||||
setProperty(object, ['users', 1, 'role'], 'moderator');
|
||||
console.log(object.users[1].role);
|
||||
//=> 'moderator'
|
||||
|
||||
// Useful for interoperability with libraries that return paths as arrays
|
||||
const pathFromOtherLib = ['users', 0, 'profile', 'settings'];
|
||||
setProperty(object, pathFromOtherLib, {theme: 'dark'});
|
||||
```
|
||||
|
||||
Array paths:
|
||||
- Avoid the parse/stringify cycle when you already have path segments
|
||||
- Work with all functions: `getProperty`, `setProperty`, `hasProperty`, `deleteProperty`
|
||||
- Numeric strings are automatically normalized to numbers for simplicity
|
||||
|
||||
## API
|
||||
|
||||
### getProperty(object, path, defaultValue?)
|
||||
|
||||
Get the value of the property at the given path.
|
||||
|
||||
Returns the value if any.
|
||||
|
||||
### setProperty(object, path, value)
|
||||
|
||||
Set the property at the given path to the given value.
|
||||
|
||||
Returns the object.
|
||||
|
||||
### hasProperty(object, path)
|
||||
|
||||
Check whether the property at the given path exists.
|
||||
|
||||
Returns a boolean.
|
||||
|
||||
### deleteProperty(object, path)
|
||||
|
||||
Delete the property at the given path.
|
||||
|
||||
Returns a boolean of whether the property existed before being deleted.
|
||||
|
||||
### escapePath(path)
|
||||
|
||||
Escape special characters in a path. Useful for sanitizing user input.
|
||||
|
||||
```js
|
||||
import {getProperty, escapePath} from 'dot-prop';
|
||||
|
||||
const object = {
|
||||
foo: {
|
||||
bar: '👸🏻 You found me Mario!',
|
||||
},
|
||||
'foo.bar' : '🍄 The princess is in another castle!',
|
||||
};
|
||||
const escapedPath = escapePath('foo.bar');
|
||||
|
||||
console.log(getProperty(object, escapedPath));
|
||||
//=> '🍄 The princess is in another castle!'
|
||||
```
|
||||
|
||||
### parsePath(path)
|
||||
|
||||
Parse a dot path into an array of path segments.
|
||||
|
||||
Returns an array of path segments where numbers represent array indices and strings represent object keys.
|
||||
|
||||
```js
|
||||
import {parsePath} from 'dot-prop';
|
||||
|
||||
parsePath('foo.bar');
|
||||
//=> ['foo', 'bar']
|
||||
|
||||
parsePath('foo[0].bar');
|
||||
//=> ['foo', 0, 'bar']
|
||||
|
||||
parsePath('foo.0.bar');
|
||||
//=> ['foo', 0, 'bar']
|
||||
|
||||
parsePath('foo\\.bar');
|
||||
//=> ['foo.bar']
|
||||
|
||||
// Use case: Iterate over path segments to build up a nested object
|
||||
const path = 'users[0].profile.settings.theme';
|
||||
const segments = parsePath(path);
|
||||
//=> ['users', 0, 'profile', 'settings', 'theme']
|
||||
```
|
||||
|
||||
### stringifyPath(pathSegments, options?)
|
||||
|
||||
Convert an array of path segments back into a path string.
|
||||
|
||||
Returns a string path that can be used with other dot-prop functions.
|
||||
|
||||
```js
|
||||
import {stringifyPath} from 'dot-prop';
|
||||
|
||||
stringifyPath(['foo', 'bar']);
|
||||
//=> 'foo.bar'
|
||||
|
||||
stringifyPath(['foo', 0, 'bar']);
|
||||
//=> 'foo[0].bar'
|
||||
|
||||
stringifyPath(['foo', '0', 'bar']);
|
||||
//=> 'foo[0].bar'
|
||||
|
||||
// With preferDotForIndices option
|
||||
stringifyPath(['foo', 0, 'bar'], {preferDotForIndices: true});
|
||||
//=> 'foo.0.bar'
|
||||
```
|
||||
|
||||
#### pathSegments
|
||||
|
||||
Type: `Array<string | number>`
|
||||
|
||||
Array of path segments where numbers represent array indices and strings represent object keys.
|
||||
|
||||
#### options
|
||||
|
||||
Type: `object`
|
||||
|
||||
##### preferDotForIndices
|
||||
|
||||
Type: `boolean`\
|
||||
Default: `false`
|
||||
|
||||
When `true`, numeric indices will use dot notation instead of bracket notation when not the first segment.
|
||||
|
||||
### deepKeys(object)
|
||||
|
||||
Returns an array of every path. Non-empty plain objects and arrays are deeply recursed and are not themselves included.
|
||||
|
||||
This can be useful to help flatten an object for an API that only accepts key-value pairs or for a tagged template literal.
|
||||
|
||||
```js
|
||||
import {getProperty, deepKeys} from 'dot-prop';
|
||||
|
||||
const user = {
|
||||
name: {
|
||||
first: 'Richie',
|
||||
last: 'Bendall',
|
||||
},
|
||||
activeTasks: [],
|
||||
currentProject: null
|
||||
};
|
||||
|
||||
for (const property of deepKeys(user)) {
|
||||
console.log(`${property}: ${getProperty(user, property)}`);
|
||||
//=> name.first: Richie
|
||||
//=> name.last: Bendall
|
||||
//=> activeTasks: []
|
||||
//=> currentProject: null
|
||||
}
|
||||
```
|
||||
|
||||
Sparse arrays are supported. In general, [avoid using sparse arrays](https://github.com/sindresorhus/dot-prop/issues/109#issuecomment-1614819869).
|
||||
|
||||
#### object
|
||||
|
||||
Type: `object | array`
|
||||
|
||||
Object or array to get, set, or delete the `path` value.
|
||||
|
||||
You are allowed to pass in `undefined` as the object to the `get` and `has` functions.
|
||||
|
||||
#### path
|
||||
|
||||
Type: `string | Array<string | number>`
|
||||
|
||||
Path of the property in the object.
|
||||
|
||||
**String paths**: Use `.` to separate each nested key. Use `\\.` if you have a `.` in the key. Array indices can be accessed using bracket notation (like `'users[0].name'`) or dot notation (like `'users.0.name'`). Both syntaxes are equivalent and will create arrays when setting values. Numeric strings in dot notation (like `'users.0.name'`) are automatically coerced to numbers.
|
||||
|
||||
**Array paths**: Pass an array of path segments for better performance and interoperability. Numbers create arrays (like `['users', 0, 'name']`). Numeric strings are normalized to numbers for simplicity. No parsing overhead.
|
||||
|
||||
The following path components are invalid and results in `undefined` being returned: `__proto__`, `prototype`, `constructor`.
|
||||
|
||||
#### value
|
||||
|
||||
Type: `unknown`
|
||||
|
||||
Value to set at `path`.
|
||||
|
||||
#### defaultValue
|
||||
|
||||
Type: `unknown`
|
||||
|
||||
Default value.
|
||||
|
||||
### unflatten(object)
|
||||
|
||||
Convert an object with dot paths into a nested object.
|
||||
|
||||
Uses the same path rules and escaping as the rest of the API.
|
||||
|
||||
```js
|
||||
import {unflatten} from 'dot-prop';
|
||||
|
||||
const flat = {
|
||||
'unicorn.name': 'Rainbow Dash',
|
||||
'unicorn.color': '🦄',
|
||||
'unicorn.treasures[0]': 'sparkles',
|
||||
'unicorn.treasures[1]': 'glitter',
|
||||
};
|
||||
|
||||
unflatten(flat);
|
||||
/*
|
||||
{
|
||||
unicorn: {
|
||||
name: 'Rainbow Dash',
|
||||
color: '🦄',
|
||||
treasures: ['sparkles', 'glitter']
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue