diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cd7a456..a1d2b2f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,20 @@ - 🛠️ 修复(fix) - 🧹 琐事(Chore) +## v2.3.0 + +- 🪄 功能(feature) + + 🇨🇳 + + - 支持全局插件 #165 + - 支持全局配置 #165 + + 🇺🇸 + + - support global plugin #165 + - support global configuration #165 + ## v2.2.3 - 🛠️ 修复(fix) diff --git a/package.json b/package.json index 6655507b..984482f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iztro", - "version": "2.2.3", + "version": "2.3.0", "description": "轻量级紫微斗数星盘生成库。可以通过出生年月日获取到紫微斗数星盘信息、生肖、星座等信息。A lightweight kit to astrolabe generator of The Purple Star Astrology (Zi Wei Dou Shu). The Purple Star Astrology(Zi Wei Dou Shu) is a Chinese ancient astrology. You're able to get your horoscope and personality from the astrolabe", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -71,6 +71,6 @@ "dependencies": { "dayjs": "^1.11.10", "i18next": "^23.5.1", - "lunar-lite": "^0.1.1" + "lunar-lite": "^0.1.2" } } diff --git a/src/__tests__/astro/plugin.test.ts b/src/__tests__/astro/plugin.test.ts new file mode 100644 index 00000000..4fdc7bd5 --- /dev/null +++ b/src/__tests__/astro/plugin.test.ts @@ -0,0 +1,74 @@ +import { astro } from '../..'; +import FunctionalAstrolabe from '../../astro/FunctionalAstrolabe'; + +export interface IAstrolabe extends FunctionalAstrolabe { + myNewFunc: () => string; + majorStar: () => string; +} + +// 创建一个插件函数 +export function myTestPlugin(this: IAstrolabe): void { + // 实现插件应用逻辑 + this.myNewFunc = () => { + return this.fiveElementsClass; + }; +} + +// 创建二个插件函数 +export function myTestPlugin2(this: IAstrolabe): void { + // 实现插件应用逻辑 + this.majorStar = () => { + let stars = this.palace('命宫') + ?.majorStars.filter((item) => item.type === 'major' && !['禄存', '天马'].includes(item.name)) + .map((item) => item.name) + .join(','); + + if (!stars) { + stars = this.palace('迁移') + ?.majorStars.filter((item) => item.type === 'major' && !['禄存', '天马'].includes(item.name)) + .map((item) => item.name) + .join(','); + } + + return stars ?? ''; + }; +} + +astro.loadPlugins([myTestPlugin]); +astro.loadPlugin(myTestPlugin2); + +astro.config({ + mutagens: { 庚: ['太阳', '武曲', '天同', '天相'] }, + brightness: { + 贪狼: ['旺', '旺', '旺', '旺', '旺', '旺', '旺', '旺', '旺', '旺', '旺', '旺'], + }, +}); + +describe('plugin test', () => { + test('plugin', () => { + const astrolabe = astro.bySolar('2023-10-18', 4, 'female'); + + expect(astrolabe.myNewFunc()).toEqual('火六局'); + expect(astrolabe.majorStar()).toEqual('七杀'); + }); + + test('changed configuration', () => { + const astrolabe = astro.bySolar('2010-10-18', 4, 'female'); + + expect(astrolabe.palace('命宫')?.hasMutagen('忌')).toBeFalsy(); + expect(astrolabe.palace('夫妻')?.hasMutagen('忌')).toBeTruthy(); + expect(astrolabe.star('贪狼').withBrightness('旺')).toBeTruthy(); + }); + + test('not changed configuration', () => { + const astrolabe = astro.bySolar('2011-10-18', 4, 'female'); + + expect(astrolabe.palace('命宫')?.hasMutagen('权')).toBeTruthy(); + expect(astrolabe.palace('命宫')?.hasMutagen('忌')).toBeTruthy(); + expect(astrolabe.palace('福德')?.hasMutagen('科')).toBeTruthy(); + expect(astrolabe.palace('田宅')?.hasMutagen('禄')).toBeFalsy(); + expect(astrolabe.palace('财帛')?.fliesTo('夫妻', '科')).toBeTruthy(); + expect(astrolabe.palace('财帛')?.fliesTo('仆役', '忌')).toBeTruthy(); + expect(astrolabe.star('紫微').withBrightness('旺')).toBeTruthy(); + }); +}); diff --git a/src/astro/FunctionalAstrolabe.ts b/src/astro/FunctionalAstrolabe.ts index 32baefb0..0b9ab7ff 100644 --- a/src/astro/FunctionalAstrolabe.ts +++ b/src/astro/FunctionalAstrolabe.ts @@ -1,7 +1,7 @@ import dayjs from 'dayjs'; import { getHeavenlyStemAndEarthlyBranchBySolarDate, normalizeDateStr, solar2lunar } from 'lunar-lite'; import { EARTHLY_BRANCHES } from '../data'; -import { Astrolabe, Horoscope } from '../data/types'; +import { Astrolabe, Horoscope, Plugin } from '../data/types'; import { EarthlyBranchKey, EarthlyBranchName, HeavenlyStemName, kot, PalaceName, StarKey, StarName, t } from '../i18n'; import { getHoroscopeStar, getYearly12 } from '../star'; import { IFunctionalStar } from '../star/FunctionalStar'; @@ -192,6 +192,14 @@ const _getHoroscopeBySolarDate = ( * 文档地址:https://docs.iztro.com/posts/astrolabe.html#functionalastrolabe */ export interface IFunctionalAstrolabe extends Astrolabe { + /** + * 插件注入方法 + * + * @version v2.3.0 + * + * @param plugin 插件函数 + */ + use(plugin: Plugin): void; /** * 获取运限数据 * @@ -292,6 +300,9 @@ export default class FunctionalAstrolabe implements IFunctionalAstrolabe { fiveElementsClass; palaces; + // 保存插件列表 + private plugins: Plugin[] = []; + constructor(data: Astrolabe) { this.gender = data.gender; this.solarDate = data.solarDate; @@ -312,6 +323,11 @@ export default class FunctionalAstrolabe implements IFunctionalAstrolabe { return this; } + use(plugin: Plugin): void { + this.plugins.push(plugin); + plugin.apply(this); + } + star = (starName: StarName): IFunctionalStar => { let targetStar: IFunctionalStar | undefined; diff --git a/src/astro/astro.ts b/src/astro/astro.ts index 7814e52c..fadc9c06 100644 --- a/src/astro/astro.ts +++ b/src/astro/astro.ts @@ -1,13 +1,75 @@ import { getHeavenlyStemAndEarthlyBranchBySolarDate, getSign, getZodiac, lunar2solar, solar2lunar } from 'lunar-lite'; import { CHINESE_TIME, EARTHLY_BRANCHES, HEAVENLY_STEMS, TIME_RANGE, earthlyBranches } from '../data'; -import { Language } from '../data/types'; -import { EarthlyBranchKey, EarthlyBranchName, GenderName, HeavenlyStemKey, kot, setLanguage, t } from '../i18n'; +import { Config, Language, Plugin } from '../data/types'; +import { + BrightnessKey, + EarthlyBranchKey, + EarthlyBranchName, + GenderName, + HeavenlyStemKey, + StarKey, + kot, + setLanguage, + t, +} from '../i18n'; import { getAdjectiveStar, getBoShi12, getchangsheng12, getMajorStar, getMinorStar, getYearly12 } from '../star'; import { fixIndex, translateChineseDate } from '../utils'; import FunctionalAstrolabe from './FunctionalAstrolabe'; import FunctionalPalace, { IFunctionalPalace } from './FunctionalPalace'; import { getPalaceNames, getSoulAndBody, getHoroscope, getFiveElementsClass } from './palace'; +const _plugins = [] as Plugin[]; +const _mutagens: Partial> = {}; +const _brightness: Partial> = {}; + +/** + * 批量加载插件 + * + * @version v2.3.0 + * + * @param plugins 插件方法数组 + */ +export const loadPlugins = (plugins: Plugin[]) => { + Array.prototype.push.apply(_plugins, plugins); +}; + +/** + * 加载单个插件 + * + * @version v2.3.0 + * + * @param plugin 插件方法 + */ +export const loadPlugin = (plugin: Plugin) => { + _plugins.push(plugin); +}; + +/** + * 全局配置四化和亮度 + * + * 由于key和value都有可能是不同语言传进来的, + * 所以需会将key和value转化为对应的i18n key。 + * + * @version 2.3.0 + * + * @param {Config} param0 自定义配置 + */ +export const config = ({ mutagens, brightness }: Config) => { + if (mutagens) { + Object.entries(mutagens).forEach(([key, value]) => { + _mutagens[kot(key)] = value.map((item) => kot(item)) ?? []; + }); + } + + if (brightness) { + Object.entries(brightness).forEach(([key, value]) => { + _brightness[kot(key)] = value.map((item) => kot(item)) ?? []; + }); + } +}; + +export const getConfig = () => ({ mutagens: _mutagens, brightness: _brightness }); + /** * 通过阳历获取星盘信息 * @@ -40,13 +102,13 @@ export const astrolabeBySolarDate = ( * @param language 输出语言 * @returns 星盘信息 */ -export const bySolar = ( +export function bySolar( solarDateStr: string, timeIndex: number, gender: GenderName, fixLeap: boolean = true, language?: Language, -) => { +): T { language && setLanguage(language); const palaces: IFunctionalPalace[] = []; @@ -121,8 +183,10 @@ export const bySolar = ( palaces, }); - return result; -}; + _plugins.map((plugin) => result.use(plugin)); + + return result as T; +} /** * 通过农历获取星盘信息 diff --git a/src/data/types/astro.ts b/src/data/types/astro.ts index 6e862e2d..ad42c3a9 100644 --- a/src/data/types/astro.ts +++ b/src/data/types/astro.ts @@ -1,5 +1,12 @@ import { IFunctionalPalace } from '../../astro/FunctionalPalace'; -import { EarthlyBranchName, FiveElementsClassName, HeavenlyStemName, PalaceName, StarName } from '../../i18n'; +import { + Brightness, + EarthlyBranchName, + FiveElementsClassName, + HeavenlyStemName, + PalaceName, + StarName, +} from '../../i18n'; import FunctionalStar from '../../star/FunctionalStar'; import { HeavenlyStemAndEarthlyBranchDate, LunarDate } from 'lunar-lite/lib/types'; @@ -150,3 +157,16 @@ export type Astrolabe = { /** 十二宫数据 */ palaces: IFunctionalPalace[]; }; + +/** + * 定义一个接口,表示插件函数的类型 + * */ +export type Plugin = () => void; + +export type ConfigMutagens = Partial>; +export type ConfigBrightness = Partial>; + +export type Config = { + mutagens?: ConfigMutagens; + brightness?: ConfigBrightness; +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index 55014f8e..9d4d230f 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -15,6 +15,20 @@ import { import FunctionalStar from '../star/FunctionalStar'; import { HeavenlyStemAndEarthlyBranchDate } from 'lunar-lite/lib/types'; import { solar2lunar } from 'lunar-lite'; +import { getConfig } from '../astro'; + +const getTargetMutagens = (heavenlyStem: HeavenlyStemKey) => { + const { mutagens } = getConfig(); + let result; + + if (mutagens && mutagens[heavenlyStem]) { + result = mutagens[heavenlyStem] ?? []; + } else { + result = heavenlyStems[heavenlyStem].mutagen ?? []; + } + + return result; +}; /** * 用于处理索引,将索引锁定在 0~max 范围内 @@ -58,21 +72,29 @@ export const earthlyBranchIndexToPalaceIndex = (earthlyBranchName: EarthlyBranch */ export const getBrightness = (starName: StarName, index: number): Brightness => { const star = kot(starName); + const { brightness } = getConfig(); + const targetBrightness = brightness[star] ? brightness[star] : STARS_INFO[star]?.brightness; + + if (!targetBrightness) { + return ''; + } - return t(STARS_INFO[star]?.brightness[fixIndex(index)]); + return t(targetBrightness[fixIndex(index)]); }; export const getMutagen = (starName: StarName, heavenlyStemName: HeavenlyStemName): Mutagen => { const heavenlyStem = kot(heavenlyStemName, 'Heavenly'); const starKey = kot(starName); + const target = getTargetMutagens(heavenlyStem); - return t(MUTAGEN[heavenlyStems[heavenlyStem].mutagen.indexOf(starKey as never)]); + return t(MUTAGEN[target.indexOf(starKey as never)]); }; export const getMutagensByHeavenlyStem = (heavenlyStemName: HeavenlyStemName): StarName[] => { const heavenlyStem = kot(heavenlyStemName, 'Heavenly'); + const target = getTargetMutagens(heavenlyStem); - return heavenlyStems[heavenlyStem].mutagen.map((star) => t(star)); + return target.map((star) => t(star)); }; /** diff --git a/yarn.lock b/yarn.lock index 8922be87..278e2c93 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3870,17 +3870,17 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lunar-lite@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/lunar-lite/-/lunar-lite-0.1.1.tgz#c2c114b95eae24b84ebc0702f616ed573772c244" - integrity sha512-ttdkDY4uZg6LtE8r4m/Vt+z48ReT8StYXPY2eXqJ6tOG3C4I11g/f/gAJXplJIRTZd+F1xOFa52tUiP2UIkqzQ== +lunar-lite@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/lunar-lite/-/lunar-lite-0.1.2.tgz#a66b08cbc6c8df3a31d4e166052593662f489144" + integrity sha512-3SKo8zTDdbS1Ynn4qHUPNOW9oviqL8d2qdHSMS9jfNbmIdh6DbYKaY9dnXpMS5I1dzG9ztAuwVJ8MBAupv89aA== dependencies: - lunar-typescript "^1.6.13" + lunar-typescript "^1.7.3" -lunar-typescript@^1.6.13: - version "1.6.13" - resolved "https://registry.npmjs.org/lunar-typescript/-/lunar-typescript-1.6.13.tgz#99c9975f8ba4bc43af813e0155db0926d024cbcf" - integrity sha512-6gBJepWWRiCvpbxxeiogsd/ZIggBbH1xmS090Kat/FiM0AGFnso0bmYXL1q/opr8qrMdnjsBlMZqBvNiRKACGA== +lunar-typescript@^1.7.3: + version "1.7.3" + resolved "https://registry.npmjs.org/lunar-typescript/-/lunar-typescript-1.7.3.tgz#841d997687a0145a1fe9f65db735675f66d06660" + integrity sha512-VXMdgh2Psrn3vtfrai4lPug3Mt7ijYGVTICDARA8tLzqGv3Io/OvS23wxzFi/AbSzxt93u2wWhgv3VGKPSbUgQ== make-dir@^4.0.0: version "4.0.0"