UNPKG

lunisolar

Version:

专业农历库,支持公历阴历互转,支持各类黄历数据查询,如八字四柱、阴历、神煞宜忌、时辰吉凶、建除十二神、胎神占方、五行纳音等。支持自定义插件。

231 lines (215 loc) 7.2 kB
import { C8God } from './../class/c8God' import { Pillar } from './../class/pillar' import type { Char8Ex } from '../class/char8ex' import { godDict, godKeys, godKeysSet } from '../constants/godDict' import type { GodRuleItem, GodRule } from '../constants/godDict' type CheckResItem = (YMDH | 'null')[] type RuleRes = [CheckResItem, CheckResItem, CheckResItem, CheckResItem] type CheckC8GodReturn = { luckLevel: number res: RuleRes isHasTrue: boolean } const ymdhList: YMDH[] = ['year', 'month', 'day', 'hour'] export const checkC8God = (c8ex: Char8Ex, godKey: string): CheckC8GodReturn => { if (!godKeysSet.has(godKey)) throw new Error(`Error C8God key: ${godKey}`) const { luckLevel, rules } = godDict[godKey] const allRes: RuleRes = [[], [], [], []] let hasTrue = false for (const rule of rules) { const { res, isHasTrue } = checkC8RuleItem(c8ex, rule) if (rules.length === 1) return { luckLevel, res, isHasTrue } for (let i = 0; i < allRes.length; i++) { allRes[i].push(...res[i]) } hasTrue = hasTrue || isHasTrue } return { luckLevel, res: allRes, isHasTrue: hasTrue } } export const checkC8RuleItem = (c8ex: Char8Ex, ruleItem: GodRuleItem) => { const { startPillar, startAO } = ruleItem const isAnd = startAO === 'and' const res: RuleRes = [[], [], [], []] const resTemp: [{ [key in YMDH[number]]: boolean }, boolean][] = [] let isAllTrue = true let isHasTrue = false for (const sp of startPillar) { const [spRes, isSpAllTrue, isSpHasTrue] = checkPerStartPillar(c8ex, ruleItem, sp) resTemp.push([spRes, isSpAllTrue]) isAllTrue = isAllTrue && isSpAllTrue isHasTrue = isHasTrue || isSpHasTrue } for (let i = 0; i < resTemp.length; i++) { const [spRes] = resTemp[i] const sp = startPillar[i] const spSplit = sp.split(':') const startP = spSplit[0] as YMDH | 'null' if (isAnd && !isAllTrue) break for (let j = 0; j < 4; j++) { const ymdh = ymdhList[j] if (spRes[ymdh]) { res[j].push(startP) } } } return { res, isAllTrue, isHasTrue } } export const checkPerStartPillar = ( c8ex: Char8Ex, ruleItem: GodRuleItem, sp: string ): [{ [key in YMDH[number]]: boolean }, boolean, boolean] => { const { startBy, startMapping, findBy, sbFormatter, ruleParams, rule } = ruleItem const spSplit = sp.split(':') const startP = spSplit[0] as YMDH | 'null' const endPs = (spSplit[1] ? [spSplit[1]] : ymdhList) as YMDH[] let resDict: { [key in YMDH[number]]: boolean } = { year: false, month: false, day: false, hour: false } let isAllTrue = false let isHasTrue = false let ruleRes: GodRule if (typeof rule === 'function') { const params = getRuleParams(c8ex, ruleParams) ruleRes = rule(...params) } else { ruleRes = rule } if (startP === 'null') { // 当startP为null时,只要endP合rull即可 const ruleSet = new Set(ruleRes) return getPillarCheckRes(c8ex, endPs, findBy, ruleSet) } else { const startPO = c8ex[startP] let startValue: number if (startBy === 'season') startValue = c8ex.lsr.getSeasonIndex() else if (startBy === 'takeSoundE5') startValue = startPO.takeSoundE5.valueOf() else if (startBy === 'sb') startValue = startPO.value else if (startBy === 'stem' || startBy === 'branch') { let [sv, bv] = [startPO.stem.value, startPO.branch.value] if (typeof sbFormatter === 'function') [sv, bv] = sbFormatter(sv, bv) startValue = startBy === 'stem' ? sv : bv } else { throw new Error(`Error value RuleItem.startBy: ${startBy}`) } // 如果存在startMapping则跟据startMapping取值 if (startMapping) startValue = useStartMappingValue(startValue, startMapping) const ruleHit = ruleRes[startValue] if (ruleHit === null) return [resDict, isAllTrue, isHasTrue] const ruleSet = Array.isArray(ruleHit) ? new Set(ruleHit) : new Set([ruleHit]) return getPillarCheckRes(c8ex, endPs, findBy, ruleSet) } } export const useStartMappingValue = ( startValue: number, startMapping: number[] | number[][] ): number => { for (let i = 0; i < startMapping.length; i++) { const mapItem = startMapping[i] if (typeof mapItem === 'number') { if (startValue === mapItem) return i } else if (Array.isArray(mapItem)) { if ((mapItem as number[]).includes(startValue)) return i } } return startValue } export const getRuleParams = (c8ex: Char8Ex, ruleParams?: string[] | null) => { if (ruleParams === null || ruleParams === void 0) return [] return ruleParams.map(item => getObjectProperties(c8ex, item)) } export const getObjectProperties = (obj: Object, propsString: string): unknown => { const props = propsString.split('.') let res: any = obj while (props.length > 0) { const curr = props.shift() if (curr === void 0 || res[curr] === void 0) return undefined res = res[curr] } return res } export const getEndTarget = ( endPO: Pillar, findBy: 'branch' | 'stem' | 's,b' | 'sb' ): number | [string, string] => { let target: number | [string, string] if (findBy === 's,b') target = [`s${endPO.stem.value}`, `b${endPO.branch.value}`] else if (findBy === 'sb') target = endPO.value else if (findBy === 'stem') target = endPO.stem.value else if (findBy === 'branch') target = endPO.branch.value else throw new Error(`Error godDict prop: findBy ${findBy}`) return target } export const getPillarCheckRes = ( c8ex: Char8Ex, endPs: YMDH[], findBy: 'branch' | 'stem' | 's,b' | 'sb', ruleSet: Set<number | number[] | null | string> ): [{ [key in YMDH[number]]: boolean }, boolean, boolean] => { const resDict = { year: false, month: false, day: false, hour: false } let allTrue = true let hasTrue = false for (const endP of endPs) { const endPO = c8ex[endP] const target = getEndTarget(endPO, findBy) let isHit = false if (Array.isArray(target)) { for (const t of target) { if (ruleSet.has(t)) { resDict[endP] = true isHit = true break } } } else if (ruleSet.has(target)) { isHit = true resDict[endP] = true } if (!isHit) allTrue = false else hasTrue = true } return [resDict, allTrue, hasTrue] } export const getGodLuckLevel = (godKey: string) => { if (!godKeysSet.has(godKey)) throw new Error(`Error C8God key: ${godKey}`) const { luckLevel } = godDict[godKey] return luckLevel } export const createAllC8Gods = (c8ex: Char8Ex) => { const allGodsRes: { [x in YMDH]: C8God[] } = { year: [], month: [], day: [], hour: [] } const godSet: { [x in YMDH]: Set<string> } = { year: new Set<string>(), month: new Set<string>(), day: new Set<string>(), hour: new Set<string>() } for (const key of godKeys) { const { res } = checkC8God(c8ex, key) for (let i = 0; i < 4; i++) { const ymdh = ymdhList[i] if (res[i].length > 0 && !godSet[ymdh].has(key)) { const god = new C8God(key, { lang: c8ex.lsr.getConfig().lang }) godSet[ymdh].add(key) allGodsRes[ymdh].push(god) } } } return allGodsRes }