parseObject = obj => {
	const info = new Map();
	let dynamicInfo;
	/**
	 * @param {string} p path
	 * @returns {Partial<ObjectParsedPropertyEntry>} object parsed property entry
	 */
	const getInfo = p => {
		const entry = info.get(p);
		if (entry !== undefined) return entry;
		const newEntry = {
			base: undefined,
			byProperty: undefined,
			byValues: undefined
		};
		info.set(p, newEntry);
		return newEntry;
	};
	for (const key of Object.keys(obj)) {
		if (key.startsWith("by")) {
			const byProperty = /** @type {keyof T} */ (key);
			const byObj = /** @type {TODO} */ (obj[byProperty]);
			if (typeof byObj === "object") {
				for (const byValue of Object.keys(byObj)) {
					const obj = byObj[/** @type {keyof (keyof T)} */ (byValue)];
					for (const key of Object.keys(obj)) {
						const entry = getInfo(key);
						if (entry.byProperty === undefined) {
							entry.byProperty = /** @type {string} */ (byProperty);
							entry.byValues = new Map();
						} else if (entry.byProperty !== byProperty) {
							throw new Error(
								`${/** @type {string} */ (byProperty)} and ${entry.byProperty} for a single property is not supported`
							);
						}
						/** @type {ByValues<V>} */
						(entry.byValues).set(
							byValue,
							obj[/** @type {keyof (keyof T)} */ (key)]
						);
						if (byValue === "default") {
							for (const otherByValue of Object.keys(byObj)) {
								if (
									!(
										/** @type {ByValues<V>} */
										(entry.byValues).has(otherByValue)
									)
								)
									/** @type {ByValues<V>} */
									(entry.byValues).set(otherByValue, undefined);
							}
						}
					}
				}
			} else if (typeof byObj === "function") {
				if (dynamicInfo === undefined) {
					dynamicInfo = {
						byProperty: key,
						fn: byObj
					};
				} else {
					throw new Error(
						`${key} and ${dynamicInfo.byProperty} when both are functions is not supported`
					);
				}
			} else {
				const entry = getInfo(key);
				entry.base = obj[/** @type {keyof T} */ (key)];
			}
		} else {
			const entry = getInfo(key);
			entry.base = obj[/** @type {keyof T} */ (key)];
		}
	}
	return {
		static: info,
		dynamic: dynamicInfo
	};
}
@template {object} T
@template V
@param {T} obj the object
@returns {ParsedObject} parsed object