yini-parser
Version:
Readable configuration without YAML foot-guns or JSON noise. The official Node.js parser for YINI config format — An INI-inspired configuration format with clear nesting, explicit types, and predictable parsing.
125 lines • 3.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeUndefinedDeep = exports.removeUndefinedShallow = exports.sortObjectKeys = void 0;
const isPlainObject = (value) => {
return (typeof value === 'object' &&
value !== null &&
!Array.isArray(value) &&
Object.prototype.toString.call(value) === '[object Object]');
};
/**
* Returns a new object with keys sorted alphabetically.
* Arrays and non-plain objects are preserved as-is (unless deep + they contain plain objects).
*/
const sortObjectKeys = (obj, options = {}) => {
const { deep = false, comparator } = options;
if (!isPlainObject(obj)) {
// If it's not a plain object (array, Date, null, primitive), return as-is.
return obj;
}
const keys = Object.keys(obj).sort(comparator ?? ((a, b) => a.localeCompare(b)));
const sortedEntries = keys.map((k) => {
const value = obj[k];
if (deep) {
if (isPlainObject(value)) {
return [k, (0, exports.sortObjectKeys)(value, options)];
}
if (Array.isArray(value)) {
// Deep-sort any plain objects inside arrays, leave others as-is.
return [
k,
value.map((item) => isPlainObject(item)
? (0, exports.sortObjectKeys)(item, options)
: item),
];
}
}
return [k, value];
});
// Preserve the original type T structurally.
return Object.fromEntries(sortedEntries);
};
exports.sortObjectKeys = sortObjectKeys;
/**
* Removes top-level properties with value `undefined`.
* Does not recurse into nested objects or arrays.
*
* @param obj Any JS object
* @returns A shallow copy with undefined properties removed,
* except in nested objects or arrays.
*
* @example
* Input:
* const input = {
* a: 1,
* b: undefined,
* c: { d: undefined, e: 2 },
* f: [1, undefined, 2]
* };
*
* Output:
* {
* a: 1,
* c: { d: undefined, e: 2 },
* f: [1, undefined, 2]
* }
*/
const removeUndefinedShallow = (obj) => {
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
if (value !== undefined) {
cleaned[key] = value;
}
}
return cleaned;
};
exports.removeUndefinedShallow = removeUndefinedShallow;
/**
* Recursively removes properties with value `undefined` from objects
* and arrays.
*
* @param obj Any JS value (object, array, primitive)
* @returns A deep-cloned copy with all `undefined` removed, including in
* nested objects and arrays.
*
* @example
* Input:
* const input = {
* a: 1,
* b: undefined,
* c: {
* d: undefined,
* e: 2,
* f: [1, undefined, { g: undefined, h: 42 }]
* }
* };
*
* Output:
* {
* a: 1,
* c: {
* e: 2,
* f: [1, { h: 42 }]
* }
* }
*/
const removeUndefinedDeep = (obj) => {
if (obj === null || typeof obj !== 'object') {
return obj; // primitive value
}
if (Array.isArray(obj)) {
// Clean each element, and filter out undefined entries
return obj
.map((item) => (0, exports.removeUndefinedDeep)(item))
.filter((item) => item !== undefined);
}
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
if (value !== undefined) {
cleaned[key] = (0, exports.removeUndefinedDeep)(value);
}
}
return cleaned;
};
exports.removeUndefinedDeep = removeUndefinedDeep;
//# sourceMappingURL=object.js.map