@akatan/date-to-festive 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AkatanHQ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Date To Festive
2
+
3
+ A standalone, reusable module for resolving themes based on dates. Zero dependencies, simple API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @akatan/date-to-festive
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Simple Example
14
+
15
+ ```typescript
16
+ import { resolvePrimaryThemeForDate } from '@akatanhq/date-to-festive';
17
+
18
+ // Get today's theme
19
+ const theme = resolvePrimaryThemeForDate(new Date());
20
+ console.log(theme);
21
+ // { name: 'winter', category: 'seasonal', metadata: { description: '...' } }
22
+ ```
23
+
24
+ ### Get All Matching Themes
25
+
26
+ ```typescript
27
+ import { resolveThemesForDate } from '@akatan/date-to-festive';
28
+
29
+ // Get all themes for Christmas
30
+ const themes = resolveThemesForDate(new Date('2025-12-25'));
31
+ // [{ name: 'christmas', category: 'seasonal', metadata: {...} }]
32
+ ```
33
+
34
+ ### With Cultural Themes
35
+
36
+ ```typescript
37
+ const themes = resolveThemesForDate(
38
+ new Date('2025-10-23'),
39
+ {
40
+ enabledCultures: ['diwali'],
41
+ userRegion: 'india'
42
+ }
43
+ );
44
+ // [{ name: 'diwali', category: 'cultural', ... }, ...]
45
+ ```
46
+
47
+ ## API
48
+
49
+ ### `resolvePrimaryThemeForDate(date, options?)`
50
+
51
+ Returns the most specific theme for a given date.
52
+
53
+ **Parameters:**
54
+ - `date: Date` - The date to resolve
55
+ - `options?: ResolverOptions`
56
+ - `enabledCultures?: string[]` - Cultural themes to enable
57
+ - `userRegion?: string` - User's region
58
+
59
+ **Returns:** `ResolvedTheme | null`
60
+
61
+ ### `resolveThemesForDate(date, options?)`
62
+
63
+ Returns all matching themes for a given date, sorted by specificity.
64
+
65
+ **Parameters:** Same as above
66
+
67
+ **Returns:** `ResolvedTheme[]`
68
+
69
+ ## Theme Types
70
+
71
+ The module includes:
72
+ - **Seasonal**: winter, spring, summer, autumn, etc.
73
+ - **Holidays**: christmas, halloween, easter, thanksgiving, etc.
74
+ - **Cultural**: diwali, chinese-new-year, hanukkah, ramadan, etc. (opt-in)
75
+ - **Everyday**: fallback theme when nothing matches
76
+
77
+ ## Features
78
+
79
+ - ✅ Zero dependencies
80
+ - ✅ TypeScript support
81
+ - ✅ Simple API - just pass a date
82
+ - ✅ Handles year wrap-around (e.g., New Year)
83
+ - ✅ Calculated holidays (Easter, Thanksgiving)
84
+ - ✅ Cultural theme support with opt-in
85
+ - ✅ Specificity sorting (shorter duration = higher priority)
86
+
87
+ ## License
88
+
89
+ MIT
90
+
91
+ ## Repository
92
+
93
+ https://github.com/akatanhq/date-to-festive
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Theme Resolver Per Day
3
+ *
4
+ * A standalone, reusable module for resolving themes based on dates.
5
+ * Just pass a date and get matching themes - configuration is handled internally.
6
+ */
7
+ export * from './resolver';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Theme Resolver Per Day
3
+ *
4
+ * A standalone, reusable module for resolving themes based on dates.
5
+ * Just pass a date and get matching themes - configuration is handled internally.
6
+ */
7
+ export * from './resolver';
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Theme Resolver Per Day - Standalone Module
3
+ *
4
+ * A reusable module for resolving themes based on dates.
5
+ * Configuration is included internally - just pass a date and get themes.
6
+ */
7
+ export type DateRule = {
8
+ kind: 'range';
9
+ from: string;
10
+ to: string;
11
+ } | {
12
+ kind: 'holiday-offset';
13
+ holiday: 'easter';
14
+ start: number;
15
+ end: number;
16
+ } | {
17
+ kind: 'nth-weekday';
18
+ month: number;
19
+ weekday: number;
20
+ n: number;
21
+ duration?: number;
22
+ } | {
23
+ kind: 'always';
24
+ };
25
+ export interface ThemeRule {
26
+ name: string;
27
+ rule: DateRule;
28
+ enabled?: boolean;
29
+ region?: string[];
30
+ metadata?: {
31
+ actualDate?: string;
32
+ description?: string;
33
+ };
34
+ }
35
+ export interface ThemeRulesConfig {
36
+ seasonal: ThemeRule[];
37
+ holidays: ThemeRule[];
38
+ cultural: ThemeRule[];
39
+ everyday: ThemeRule[];
40
+ }
41
+ export interface ResolverOptions {
42
+ enabledCultures?: string[];
43
+ userRegion?: string;
44
+ }
45
+ export interface ResolvedTheme {
46
+ name: string;
47
+ category: 'seasonal' | 'holidays' | 'cultural' | 'everyday';
48
+ rule: DateRule;
49
+ metadata?: {
50
+ actualDate?: string;
51
+ description?: string;
52
+ };
53
+ }
54
+ /**
55
+ * Resolve themes for a specific date
56
+ *
57
+ * @param date - The date to resolve themes for
58
+ * @param options - Optional filters for cultural themes and region
59
+ * @returns Array of resolved themes, sorted by specificity (shortest duration first)
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const themes = resolveThemesForDate(
64
+ * new Date('2025-12-25'),
65
+ * { enabledCultures: ['diwali'], userRegion: 'india' }
66
+ * );
67
+ * // Returns: [{ name: 'christmas', category: 'seasonal', metadata: {...} }]
68
+ * ```
69
+ */
70
+ export declare function resolveThemesForDate(date: Date, options?: ResolverOptions): ResolvedTheme[];
71
+ /**
72
+ * Get the primary (most specific) theme for a date
73
+ *
74
+ * @param date - The date to resolve theme for
75
+ * @param options - Optional filters for cultural themes and region
76
+ * @returns The most specific matching theme, or null if none found
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const theme = resolvePrimaryThemeForDate(new Date('2025-10-31'));
81
+ * // Returns: { name: 'halloween', category: 'holidays', metadata: {...} }
82
+ * ```
83
+ */
84
+ export declare function resolvePrimaryThemeForDate(date: Date, options?: ResolverOptions): ResolvedTheme | null;
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Theme Resolver Per Day - Standalone Module
3
+ *
4
+ * A reusable module for resolving themes based on dates.
5
+ * Configuration is included internally - just pass a date and get themes.
6
+ */
7
+ import themeRulesConfigJson from './themeRules.json';
8
+ const themeRulesConfig = themeRulesConfigJson;
9
+ /**
10
+ * Resolve themes for a specific date
11
+ *
12
+ * @param date - The date to resolve themes for
13
+ * @param options - Optional filters for cultural themes and region
14
+ * @returns Array of resolved themes, sorted by specificity (shortest duration first)
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const themes = resolveThemesForDate(
19
+ * new Date('2025-12-25'),
20
+ * { enabledCultures: ['diwali'], userRegion: 'india' }
21
+ * );
22
+ * // Returns: [{ name: 'christmas', category: 'seasonal', metadata: {...} }]
23
+ * ```
24
+ */
25
+ export function resolveThemesForDate(date, options = {}) {
26
+ const { enabledCultures = [], userRegion } = options;
27
+ const year = date.getFullYear();
28
+ // Use internal config and flatten with category
29
+ const config = themeRulesConfig;
30
+ const allRules = [
31
+ ...config.seasonal.map(rule => ({ ...rule, category: 'seasonal' })),
32
+ ...config.holidays.map(rule => ({ ...rule, category: 'holidays' })),
33
+ ...config.cultural.map(rule => ({ ...rule, category: 'cultural' })),
34
+ ...config.everyday.map(rule => ({ ...rule, category: 'everyday' }))
35
+ ];
36
+ // Filter available themes based on enabled cultures and region
37
+ const availableRules = allRules.filter(rule => {
38
+ // Skip everyday theme in first pass
39
+ if (rule.name === 'everyday') {
40
+ return false;
41
+ }
42
+ // Always include non-cultural themes (enabled undefined or true)
43
+ if (rule.enabled === undefined || rule.enabled === true) {
44
+ return true;
45
+ }
46
+ // For cultural themes, check if they're enabled
47
+ if (rule.enabled === false) {
48
+ return enabledCultures.includes(rule.name) ||
49
+ (rule.region && userRegion && rule.region.includes(userRegion));
50
+ }
51
+ return false;
52
+ });
53
+ // Find all matching themes
54
+ const matchingThemes = [];
55
+ for (const rule of availableRules) {
56
+ if (isRuleActive(rule.rule, date, year)) {
57
+ matchingThemes.push({
58
+ name: rule.name,
59
+ category: rule.category,
60
+ rule: rule.rule,
61
+ metadata: rule.metadata
62
+ });
63
+ }
64
+ }
65
+ // Sort by duration (shortest first = most specific)
66
+ matchingThemes.sort((a, b) => {
67
+ const ruleA = allRules.find(r => r.name === a.name);
68
+ const ruleB = allRules.find(r => r.name === b.name);
69
+ const durationA = getThemeDuration(ruleA.rule, year);
70
+ const durationB = getThemeDuration(ruleB.rule, year);
71
+ return durationA - durationB;
72
+ });
73
+ // If no themes match, return everyday theme
74
+ if (matchingThemes.length === 0) {
75
+ const everydayRule = config.everyday.find(r => r.name === 'everyday');
76
+ if (everydayRule) {
77
+ matchingThemes.push({
78
+ name: 'everyday',
79
+ category: 'everyday',
80
+ rule: everydayRule.rule,
81
+ metadata: everydayRule.metadata
82
+ });
83
+ }
84
+ }
85
+ return matchingThemes;
86
+ }
87
+ /**
88
+ * Get the primary (most specific) theme for a date
89
+ *
90
+ * @param date - The date to resolve theme for
91
+ * @param options - Optional filters for cultural themes and region
92
+ * @returns The most specific matching theme, or null if none found
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const theme = resolvePrimaryThemeForDate(new Date('2025-10-31'));
97
+ * // Returns: { name: 'halloween', category: 'holidays', metadata: {...} }
98
+ * ```
99
+ */
100
+ export function resolvePrimaryThemeForDate(date, options = {}) {
101
+ const themes = resolveThemesForDate(date, options);
102
+ return themes.length > 0 ? themes[0] : null;
103
+ }
104
+ /**
105
+ * Check if a date rule is active for a given date
106
+ */
107
+ function isRuleActive(rule, date, year) {
108
+ switch (rule.kind) {
109
+ case 'range':
110
+ return isInRange(rule.from, rule.to, date);
111
+ case 'holiday-offset':
112
+ return isHolidayOffsetActive(rule.holiday, rule.start, rule.end, date, year);
113
+ case 'nth-weekday':
114
+ return isNthWeekdayActive(rule.month, rule.weekday, rule.n, rule.duration || 1, date);
115
+ case 'always':
116
+ return true;
117
+ default:
118
+ return false;
119
+ }
120
+ }
121
+ /**
122
+ * Check if a date falls within a range
123
+ */
124
+ function isInRange(from, to, date) {
125
+ const month = date.getMonth() + 1;
126
+ const day = date.getDate();
127
+ const currentDate = `${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
128
+ // Handle year wrap-around (e.g., Christmas: 12-26 to 01-07)
129
+ if (from <= to) {
130
+ return currentDate >= from && currentDate <= to;
131
+ }
132
+ else {
133
+ return currentDate >= from || currentDate <= to;
134
+ }
135
+ }
136
+ /**
137
+ * Check if a date is within a holiday offset range
138
+ */
139
+ function isHolidayOffsetActive(holiday, startOffset, endOffset, date, year) {
140
+ let holidayDate;
141
+ switch (holiday) {
142
+ case 'easter':
143
+ holidayDate = calculateEaster(year);
144
+ break;
145
+ default:
146
+ return false;
147
+ }
148
+ const startDate = new Date(holidayDate);
149
+ startDate.setDate(startDate.getDate() + startOffset);
150
+ const endDate = new Date(holidayDate);
151
+ endDate.setDate(endDate.getDate() + endOffset);
152
+ return date >= startDate && date <= endDate;
153
+ }
154
+ /**
155
+ * Check if a date matches the nth weekday of a month
156
+ */
157
+ function isNthWeekdayActive(month, weekday, n, duration = 1, date) {
158
+ const year = date.getFullYear();
159
+ // Find the nth occurrence of the weekday in the month
160
+ let count = 0;
161
+ let targetDate = null;
162
+ for (let day = 1; day <= 31; day++) {
163
+ const testDate = new Date(year, month - 1, day);
164
+ if (testDate.getMonth() !== month - 1)
165
+ break;
166
+ if (testDate.getDay() === weekday) {
167
+ count++;
168
+ if (count === n) {
169
+ targetDate = testDate;
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ if (!targetDate)
175
+ return false;
176
+ // If duration is specified, check if date is within the duration window
177
+ if (duration > 1) {
178
+ const halfDuration = Math.floor(duration / 2);
179
+ const startDate = new Date(targetDate);
180
+ startDate.setDate(startDate.getDate() - halfDuration);
181
+ const endDate = new Date(targetDate);
182
+ endDate.setDate(endDate.getDate() + (duration - halfDuration - 1));
183
+ return date >= startDate && date <= endDate;
184
+ }
185
+ // Single day event - exact match
186
+ return date.toDateString() === targetDate.toDateString();
187
+ }
188
+ /**
189
+ * Calculate Easter date using Gauss algorithm
190
+ */
191
+ function calculateEaster(year) {
192
+ const a = year % 19;
193
+ const b = Math.floor(year / 100);
194
+ const c = year % 100;
195
+ const d = Math.floor(b / 4);
196
+ const e = b % 4;
197
+ const f = Math.floor((b + 8) / 25);
198
+ const g = Math.floor((b - f + 1) / 3);
199
+ const h = (19 * a + b - d - g + 15) % 30;
200
+ const i = Math.floor(c / 4);
201
+ const k = c % 4;
202
+ const l = (32 + 2 * e + 2 * i - h - k) % 7;
203
+ const m = Math.floor((a + 11 * h + 22 * l) / 451);
204
+ const month = Math.floor((h + l - 7 * m + 114) / 31);
205
+ const day = ((h + l - 7 * m + 114) % 31) + 1;
206
+ return new Date(year, month - 1, day);
207
+ }
208
+ /**
209
+ * Calculate theme duration in days
210
+ */
211
+ function getThemeDuration(rule, year) {
212
+ switch (rule.kind) {
213
+ case 'range': {
214
+ const [fromMonth, fromDay] = rule.from.split('-').map(Number);
215
+ const [toMonth, toDay] = rule.to.split('-').map(Number);
216
+ const startDate = new Date(year, fromMonth - 1, fromDay);
217
+ const endDate = new Date(year, toMonth - 1, toDay);
218
+ // Handle year wrap-around
219
+ if (endDate < startDate) {
220
+ endDate.setFullYear(year + 1);
221
+ }
222
+ const diffTime = endDate.getTime() - startDate.getTime();
223
+ return Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1;
224
+ }
225
+ case 'holiday-offset': {
226
+ return Math.abs(rule.end - rule.start) + 1;
227
+ }
228
+ case 'nth-weekday': {
229
+ return rule.duration || 1;
230
+ }
231
+ case 'always': {
232
+ return Infinity;
233
+ }
234
+ default:
235
+ return Infinity;
236
+ }
237
+ }
@@ -0,0 +1,247 @@
1
+ {
2
+ "seasonal": [
3
+ {
4
+ "name": "new-year",
5
+ "rule": {
6
+ "kind": "range",
7
+ "from": "12-26",
8
+ "to": "01-07"
9
+ },
10
+ "metadata": {
11
+ "actualDate": "01-01",
12
+ "description": "New Year celebration period"
13
+ }
14
+ },
15
+ {
16
+ "name": "christmas",
17
+ "rule": {
18
+ "kind": "range",
19
+ "from": "11-25",
20
+ "to": "12-25"
21
+ },
22
+ "metadata": {
23
+ "actualDate": "12-25",
24
+ "description": "Christmas season"
25
+ }
26
+ },
27
+ {
28
+ "name": "winter",
29
+ "rule": {
30
+ "kind": "range",
31
+ "from": "01-08",
32
+ "to": "02-28"
33
+ },
34
+ "metadata": {
35
+ "description": "Winter season after New Year"
36
+ }
37
+ },
38
+ {
39
+ "name": "spring-beginning",
40
+ "rule": {
41
+ "kind": "range",
42
+ "from": "03-01",
43
+ "to": "03-20"
44
+ },
45
+ "metadata": {
46
+ "description": "Early spring period"
47
+ }
48
+ },
49
+ {
50
+ "name": "spring",
51
+ "rule": {
52
+ "kind": "range",
53
+ "from": "03-21",
54
+ "to": "05-31"
55
+ },
56
+ "metadata": {
57
+ "description": "Spring season"
58
+ }
59
+ },
60
+ {
61
+ "name": "summer-beginning",
62
+ "rule": {
63
+ "kind": "range",
64
+ "from": "06-01",
65
+ "to": "06-20"
66
+ },
67
+ "metadata": {
68
+ "description": "Early summer period"
69
+ }
70
+ },
71
+ {
72
+ "name": "summer-holiday",
73
+ "rule": {
74
+ "kind": "range",
75
+ "from": "06-21",
76
+ "to": "08-31"
77
+ },
78
+ "metadata": {
79
+ "description": "Summer vacation period"
80
+ }
81
+ },
82
+ {
83
+ "name": "back-to-school",
84
+ "rule": {
85
+ "kind": "range",
86
+ "from": "08-15",
87
+ "to": "09-15"
88
+ },
89
+ "metadata": {
90
+ "description": "Back to school season"
91
+ }
92
+ },
93
+ {
94
+ "name": "autumn",
95
+ "rule": {
96
+ "kind": "range",
97
+ "from": "09-16",
98
+ "to": "11-24"
99
+ },
100
+ "metadata": {
101
+ "description": "Autumn/Fall season"
102
+ }
103
+ }
104
+ ],
105
+ "holidays": [
106
+ {
107
+ "name": "halloween",
108
+ "rule": {
109
+ "kind": "range",
110
+ "from": "10-20",
111
+ "to": "10-31"
112
+ },
113
+ "metadata": {
114
+ "actualDate": "10-31",
115
+ "description": "Halloween celebration"
116
+ }
117
+ },
118
+ {
119
+ "name": "thanksgiving",
120
+ "rule": {
121
+ "kind": "nth-weekday",
122
+ "month": 11,
123
+ "weekday": 4,
124
+ "n": 4,
125
+ "duration": 7
126
+ },
127
+ "metadata": {
128
+ "description": "Thanksgiving (4th Thursday of November)"
129
+ }
130
+ },
131
+ {
132
+ "name": "easter",
133
+ "rule": {
134
+ "kind": "holiday-offset",
135
+ "holiday": "easter",
136
+ "start": -7,
137
+ "end": 1
138
+ },
139
+ "metadata": {
140
+ "description": "Easter celebration (calculated date)"
141
+ }
142
+ },
143
+ {
144
+ "name": "carnival",
145
+ "rule": {
146
+ "kind": "holiday-offset",
147
+ "holiday": "easter",
148
+ "start": -49,
149
+ "end": -46
150
+ },
151
+ "metadata": {
152
+ "description": "Carnival/Mardi Gras (before Easter)"
153
+ }
154
+ }
155
+ ],
156
+ "cultural": [
157
+ {
158
+ "name": "diwali",
159
+ "rule": {
160
+ "kind": "range",
161
+ "from": "10-20",
162
+ "to": "10-25"
163
+ },
164
+ "enabled": false,
165
+ "region": ["india", "global"],
166
+ "metadata": {
167
+ "description": "Festival of Lights (approximate dates)"
168
+ }
169
+ },
170
+ {
171
+ "name": "chinese-new-year",
172
+ "rule": {
173
+ "kind": "range",
174
+ "from": "01-21",
175
+ "to": "02-20"
176
+ },
177
+ "enabled": false,
178
+ "region": ["china", "global"],
179
+ "metadata": {
180
+ "description": "Chinese New Year (approximate dates)"
181
+ }
182
+ },
183
+ {
184
+ "name": "hanukkah",
185
+ "rule": {
186
+ "kind": "range",
187
+ "from": "11-25",
188
+ "to": "12-31"
189
+ },
190
+ "enabled": false,
191
+ "region": ["global"],
192
+ "metadata": {
193
+ "description": "Hanukkah (approximate dates)"
194
+ }
195
+ },
196
+ {
197
+ "name": "ramadan",
198
+ "rule": {
199
+ "kind": "range",
200
+ "from": "03-01",
201
+ "to": "04-30"
202
+ },
203
+ "enabled": false,
204
+ "region": ["global"],
205
+ "metadata": {
206
+ "description": "Ramadan (approximate dates, varies by lunar calendar)"
207
+ }
208
+ },
209
+ {
210
+ "name": "eid-celebration",
211
+ "rule": {
212
+ "kind": "range",
213
+ "from": "04-01",
214
+ "to": "05-15"
215
+ },
216
+ "enabled": false,
217
+ "region": ["global"],
218
+ "metadata": {
219
+ "description": "Eid celebration (approximate dates)"
220
+ }
221
+ },
222
+ {
223
+ "name": "holi",
224
+ "rule": {
225
+ "kind": "range",
226
+ "from": "02-25",
227
+ "to": "03-25"
228
+ },
229
+ "enabled": false,
230
+ "region": ["india", "global"],
231
+ "metadata": {
232
+ "description": "Holi - Festival of Colors (approximate dates)"
233
+ }
234
+ }
235
+ ],
236
+ "everyday": [
237
+ {
238
+ "name": "everyday",
239
+ "rule": {
240
+ "kind": "always"
241
+ },
242
+ "metadata": {
243
+ "description": "Default fallback theme"
244
+ }
245
+ }
246
+ ]
247
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@akatan/date-to-festive",
3
+ "version": "1.0.6",
4
+ "description": "A standalone, reusable module for resolving themes based on dates",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsc --watch",
16
+ "clean": "rimraf dist",
17
+ "prepublishOnly": "npm run clean && npm run build"
18
+ },
19
+ "keywords": [
20
+ "theme",
21
+ "date",
22
+ "resolver",
23
+ "seasonal",
24
+ "holidays",
25
+ "cultural"
26
+ ],
27
+ "author": "AkatanHQ",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+ssh://git@github.com/AkatanHQ/date-to-festive.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/AkatanHQ/date-to-festive/issues"
35
+ },
36
+ "homepage": "https://github.com/AkatanHQ/date-to-festive#readme",
37
+ "devDependencies": {
38
+ "rimraf": "^6.1.3",
39
+ "typescript": "^5.0.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=14.0.0"
43
+ }
44
+ }