@weborigami/async-tree 0.0.71-beta.1 → 0.0.71
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/main.js +1 -0
- package/package.json +2 -2
- package/src/SiteTree.js +8 -10
- package/src/calendarTree.js +151 -54
- package/test/calendarTree.test.js +77 -67
package/main.js
CHANGED
|
@@ -5,6 +5,7 @@ export { default as FileTree } from "./src/FileTree.js";
|
|
|
5
5
|
export { default as FunctionTree } from "./src/FunctionTree.js";
|
|
6
6
|
export { default as MapTree } from "./src/MapTree.js";
|
|
7
7
|
// Skip BrowserFileTree.js, which is browser-only.
|
|
8
|
+
export { default as calendarTree } from "./src/calendarTree.js";
|
|
8
9
|
export { default as DeepMapTree } from "./src/DeepMapTree.js";
|
|
9
10
|
export { default as ExplorableSiteTree } from "./src/ExplorableSiteTree.js";
|
|
10
11
|
export { DeepObjectTree, ObjectTree, Tree } from "./src/internal.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weborigami/async-tree",
|
|
3
|
-
"version": "0.0.71
|
|
3
|
+
"version": "0.0.71",
|
|
4
4
|
"description": "Asynchronous tree drivers based on standard JavaScript classes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./main.js",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"typescript": "5.6.2"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@weborigami/types": "0.0.71
|
|
14
|
+
"@weborigami/types": "0.0.71"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"test": "node --test --test-reporter=spec",
|
package/src/SiteTree.js
CHANGED
|
@@ -87,17 +87,15 @@ export default class SiteTree {
|
|
|
87
87
|
const { type, subtype } = match.groups;
|
|
88
88
|
if (type === "text") {
|
|
89
89
|
return true;
|
|
90
|
-
} else if (type === "application") {
|
|
91
|
-
return (
|
|
92
|
-
subtype === "json" ||
|
|
93
|
-
subtype.endsWith("+json") ||
|
|
94
|
-
subtype.endsWith(".json") ||
|
|
95
|
-
subtype === "xml" ||
|
|
96
|
-
subtype.endsWith("+xml") ||
|
|
97
|
-
subtype.endsWith(".xml")
|
|
98
|
-
);
|
|
99
90
|
}
|
|
100
|
-
return
|
|
91
|
+
return (
|
|
92
|
+
subtype === "json" ||
|
|
93
|
+
subtype.endsWith("+json") ||
|
|
94
|
+
subtype.endsWith(".json") ||
|
|
95
|
+
subtype === "xml" ||
|
|
96
|
+
subtype.endsWith("+xml") ||
|
|
97
|
+
subtype.endsWith(".xml")
|
|
98
|
+
);
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
get path() {
|
package/src/calendarTree.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as trailingSlash from "./trailingSlash.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Return a tree of years, months, and days from a start date to an end date.
|
|
3
5
|
*
|
|
@@ -10,68 +12,163 @@
|
|
|
10
12
|
*
|
|
11
13
|
* If a start date is omitted, today will be used, likewise for the end date.
|
|
12
14
|
*
|
|
13
|
-
* @
|
|
14
|
-
*
|
|
15
|
-
* @param {
|
|
15
|
+
* @typedef {string|undefined} CalendarOptionsDate
|
|
16
|
+
* @typedef {( year: string, month: string, day: string ) => any} CalendarOptionsFn
|
|
17
|
+
* @param {{ end?: CalendarOptionsDate, start?: CalendarOptionsDate, value: CalendarOptionsFn }} options
|
|
16
18
|
*/
|
|
17
|
-
export default function calendarTree(
|
|
18
|
-
const
|
|
19
|
-
const
|
|
19
|
+
export default function calendarTree(options) {
|
|
20
|
+
const start = dateParts(options.start);
|
|
21
|
+
const end = dateParts(options.end);
|
|
22
|
+
const valueFn = options.value;
|
|
20
23
|
|
|
24
|
+
// Fill in the missing parts of the start and end dates.
|
|
21
25
|
const today = new Date();
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
?
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
?
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
? 12
|
|
42
|
-
: today.getMonth() + 1;
|
|
43
|
-
const endDay = endParts[2]
|
|
44
|
-
? parseInt(endParts[2])
|
|
45
|
-
: endParts[1]
|
|
46
|
-
? daysInMonth(endYear, endMonth)
|
|
47
|
-
: today.getDate();
|
|
48
|
-
|
|
49
|
-
let years = {};
|
|
50
|
-
for (let year = startYear; year <= endYear; year++) {
|
|
51
|
-
let months = new Map();
|
|
52
|
-
const firstMonth = year === startYear ? startMonth : 1;
|
|
53
|
-
const lastMonth = year === endYear ? endMonth : 12;
|
|
54
|
-
for (let month = firstMonth; month <= lastMonth; month++) {
|
|
55
|
-
const monthPadded = month.toString().padStart(2, "0");
|
|
56
|
-
let days = new Map();
|
|
57
|
-
const firstDay =
|
|
58
|
-
year === startYear && month === startMonth ? startDay : 1;
|
|
59
|
-
const lastDay =
|
|
60
|
-
year === endYear && month === endMonth
|
|
61
|
-
? endDay
|
|
62
|
-
: daysInMonth(year, month);
|
|
63
|
-
for (let day = firstDay; day <= lastDay; day++) {
|
|
64
|
-
const dayPadded = day.toString().padStart(2, "0");
|
|
65
|
-
days.set(dayPadded, null);
|
|
66
|
-
}
|
|
67
|
-
months.set(monthPadded, days);
|
|
68
|
-
}
|
|
69
|
-
years[year] = months;
|
|
27
|
+
if (start.day === undefined) {
|
|
28
|
+
start.day = start.year ? 1 : today.getDate();
|
|
29
|
+
}
|
|
30
|
+
if (start.month === undefined) {
|
|
31
|
+
start.month = start.year ? 1 : today.getMonth() + 1;
|
|
32
|
+
}
|
|
33
|
+
if (start.year === undefined) {
|
|
34
|
+
start.year = today.getFullYear();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (end.day === undefined) {
|
|
38
|
+
end.day = end.month
|
|
39
|
+
? daysInMonth(end.year, end.month)
|
|
40
|
+
: end.year
|
|
41
|
+
? 31 // Last day of December
|
|
42
|
+
: today.getDate();
|
|
43
|
+
}
|
|
44
|
+
if (end.month === undefined) {
|
|
45
|
+
end.month = end.year ? 12 : today.getMonth() + 1;
|
|
70
46
|
}
|
|
47
|
+
if (end.year === undefined) {
|
|
48
|
+
end.year = today.getFullYear();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return yearsTree(start, end, valueFn);
|
|
52
|
+
}
|
|
71
53
|
|
|
72
|
-
|
|
54
|
+
function dateParts(date) {
|
|
55
|
+
let year;
|
|
56
|
+
let month;
|
|
57
|
+
let day;
|
|
58
|
+
if (typeof date === "string") {
|
|
59
|
+
const parts = date.split("-");
|
|
60
|
+
year = parts[0] ? parseInt(parts[0]) : undefined;
|
|
61
|
+
month = parts[1] ? parseInt(parts[1]) : undefined;
|
|
62
|
+
day = parts[2] ? parseInt(parts[2]) : undefined;
|
|
63
|
+
}
|
|
64
|
+
return { year, month, day };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function daysForMonthTree(year, month, start, end, valueFn) {
|
|
68
|
+
return {
|
|
69
|
+
async get(day) {
|
|
70
|
+
day = parseInt(trailingSlash.remove(day));
|
|
71
|
+
return this.inRange(day)
|
|
72
|
+
? valueFn(year.toString(), twoDigits(month), twoDigits(day))
|
|
73
|
+
: undefined;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
inRange(day) {
|
|
77
|
+
if (year === start.year && year === end.year) {
|
|
78
|
+
if (month === start.month && month === end.month) {
|
|
79
|
+
return day >= start.day && day <= end.day;
|
|
80
|
+
} else if (month === start.month) {
|
|
81
|
+
return day >= start.day;
|
|
82
|
+
} else if (month === end.month) {
|
|
83
|
+
return day <= end.day;
|
|
84
|
+
} else {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
} else if (year === start.year) {
|
|
88
|
+
if (month === start.month) {
|
|
89
|
+
return day >= start.day;
|
|
90
|
+
} else {
|
|
91
|
+
return month > start.month;
|
|
92
|
+
}
|
|
93
|
+
} else if (year === end.year) {
|
|
94
|
+
if (month === end.month) {
|
|
95
|
+
return day <= end.day;
|
|
96
|
+
} else {
|
|
97
|
+
return month < end.month;
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
async keys() {
|
|
105
|
+
const days = Array.from(
|
|
106
|
+
{ length: daysInMonth(year, month) },
|
|
107
|
+
(_, i) => i + 1
|
|
108
|
+
);
|
|
109
|
+
return days
|
|
110
|
+
.filter((day) => this.inRange(day))
|
|
111
|
+
.map((day) => twoDigits(day));
|
|
112
|
+
},
|
|
113
|
+
};
|
|
73
114
|
}
|
|
74
115
|
|
|
75
116
|
function daysInMonth(year, month) {
|
|
76
117
|
return new Date(year, month, 0).getDate();
|
|
77
118
|
}
|
|
119
|
+
|
|
120
|
+
function monthsForYearTree(year, start, end, valueFn) {
|
|
121
|
+
return {
|
|
122
|
+
async get(month) {
|
|
123
|
+
month = parseInt(trailingSlash.remove(month));
|
|
124
|
+
return this.inRange(month)
|
|
125
|
+
? daysForMonthTree(year, month, start, end, valueFn)
|
|
126
|
+
: undefined;
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
inRange(month) {
|
|
130
|
+
if (year === start.year && year === end.year) {
|
|
131
|
+
return month >= start.month && month <= end.month;
|
|
132
|
+
} else if (year === start.year) {
|
|
133
|
+
return month >= start.month;
|
|
134
|
+
} else if (year === end.year) {
|
|
135
|
+
return month <= end.month;
|
|
136
|
+
} else {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
async keys() {
|
|
142
|
+
const months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
|
143
|
+
return months
|
|
144
|
+
.filter((month) => this.inRange(month))
|
|
145
|
+
.map((month) => twoDigits(month));
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function twoDigits(number) {
|
|
151
|
+
return number.toString().padStart(2, "0");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function yearsTree(start, end, valueFn) {
|
|
155
|
+
return {
|
|
156
|
+
async get(year) {
|
|
157
|
+
year = parseInt(trailingSlash.remove(year));
|
|
158
|
+
return this.inRange(year)
|
|
159
|
+
? monthsForYearTree(year, start, end, valueFn)
|
|
160
|
+
: undefined;
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
inRange(year) {
|
|
164
|
+
return year >= start.year && year <= end.year;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
async keys() {
|
|
168
|
+
return Array.from(
|
|
169
|
+
{ length: end.year - start.year + 1 },
|
|
170
|
+
(_, i) => start.year + i
|
|
171
|
+
);
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
@@ -5,7 +5,9 @@ import { toPlainValue } from "../src/utilities.js";
|
|
|
5
5
|
|
|
6
6
|
describe("calendarTree", () => {
|
|
7
7
|
test("without a start or end, returns a tree for today", async () => {
|
|
8
|
-
const tree = calendarTree(
|
|
8
|
+
const tree = calendarTree({
|
|
9
|
+
value: (year, month, day) => `${year}-${month}-${day}`,
|
|
10
|
+
});
|
|
9
11
|
const plain = await toPlainValue(tree);
|
|
10
12
|
const today = new Date();
|
|
11
13
|
const year = today.getFullYear();
|
|
@@ -14,96 +16,104 @@ describe("calendarTree", () => {
|
|
|
14
16
|
assert.deepEqual(plain, {
|
|
15
17
|
[year]: {
|
|
16
18
|
[month]: {
|
|
17
|
-
[day]:
|
|
19
|
+
[day]: `${year}-${month}-${day}`,
|
|
18
20
|
},
|
|
19
21
|
},
|
|
20
22
|
});
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
test("returns a tree for a month range", async () => {
|
|
24
|
-
const tree = calendarTree(
|
|
26
|
+
const tree = calendarTree({
|
|
27
|
+
start: "2025-01",
|
|
28
|
+
end: "2025-02",
|
|
29
|
+
value: (year, month, day) => `${year}-${month}-${day}`,
|
|
30
|
+
});
|
|
25
31
|
const plain = await toPlainValue(tree);
|
|
26
32
|
assert.deepEqual(plain, {
|
|
27
33
|
2025: {
|
|
28
34
|
"01": {
|
|
29
|
-
"01":
|
|
30
|
-
"02":
|
|
31
|
-
"03":
|
|
32
|
-
"04":
|
|
33
|
-
"05":
|
|
34
|
-
"06":
|
|
35
|
-
"07":
|
|
36
|
-
"08":
|
|
37
|
-
"09":
|
|
38
|
-
10:
|
|
39
|
-
11:
|
|
40
|
-
12:
|
|
41
|
-
13:
|
|
42
|
-
14:
|
|
43
|
-
15:
|
|
44
|
-
16:
|
|
45
|
-
17:
|
|
46
|
-
18:
|
|
47
|
-
19:
|
|
48
|
-
20:
|
|
49
|
-
21:
|
|
50
|
-
22:
|
|
51
|
-
23:
|
|
52
|
-
24:
|
|
53
|
-
25:
|
|
54
|
-
26:
|
|
55
|
-
27:
|
|
56
|
-
28:
|
|
57
|
-
29:
|
|
58
|
-
30:
|
|
59
|
-
31:
|
|
35
|
+
"01": "2025-01-01",
|
|
36
|
+
"02": "2025-01-02",
|
|
37
|
+
"03": "2025-01-03",
|
|
38
|
+
"04": "2025-01-04",
|
|
39
|
+
"05": "2025-01-05",
|
|
40
|
+
"06": "2025-01-06",
|
|
41
|
+
"07": "2025-01-07",
|
|
42
|
+
"08": "2025-01-08",
|
|
43
|
+
"09": "2025-01-09",
|
|
44
|
+
10: "2025-01-10",
|
|
45
|
+
11: "2025-01-11",
|
|
46
|
+
12: "2025-01-12",
|
|
47
|
+
13: "2025-01-13",
|
|
48
|
+
14: "2025-01-14",
|
|
49
|
+
15: "2025-01-15",
|
|
50
|
+
16: "2025-01-16",
|
|
51
|
+
17: "2025-01-17",
|
|
52
|
+
18: "2025-01-18",
|
|
53
|
+
19: "2025-01-19",
|
|
54
|
+
20: "2025-01-20",
|
|
55
|
+
21: "2025-01-21",
|
|
56
|
+
22: "2025-01-22",
|
|
57
|
+
23: "2025-01-23",
|
|
58
|
+
24: "2025-01-24",
|
|
59
|
+
25: "2025-01-25",
|
|
60
|
+
26: "2025-01-26",
|
|
61
|
+
27: "2025-01-27",
|
|
62
|
+
28: "2025-01-28",
|
|
63
|
+
29: "2025-01-29",
|
|
64
|
+
30: "2025-01-30",
|
|
65
|
+
31: "2025-01-31",
|
|
60
66
|
},
|
|
61
67
|
"02": {
|
|
62
|
-
"01":
|
|
63
|
-
"02":
|
|
64
|
-
"03":
|
|
65
|
-
"04":
|
|
66
|
-
"05":
|
|
67
|
-
"06":
|
|
68
|
-
"07":
|
|
69
|
-
"08":
|
|
70
|
-
"09":
|
|
71
|
-
10:
|
|
72
|
-
11:
|
|
73
|
-
12:
|
|
74
|
-
13:
|
|
75
|
-
14:
|
|
76
|
-
15:
|
|
77
|
-
16:
|
|
78
|
-
17:
|
|
79
|
-
18:
|
|
80
|
-
19:
|
|
81
|
-
20:
|
|
82
|
-
21:
|
|
83
|
-
22:
|
|
84
|
-
23:
|
|
85
|
-
24:
|
|
86
|
-
25:
|
|
87
|
-
26:
|
|
88
|
-
27:
|
|
89
|
-
28:
|
|
68
|
+
"01": "2025-02-01",
|
|
69
|
+
"02": "2025-02-02",
|
|
70
|
+
"03": "2025-02-03",
|
|
71
|
+
"04": "2025-02-04",
|
|
72
|
+
"05": "2025-02-05",
|
|
73
|
+
"06": "2025-02-06",
|
|
74
|
+
"07": "2025-02-07",
|
|
75
|
+
"08": "2025-02-08",
|
|
76
|
+
"09": "2025-02-09",
|
|
77
|
+
10: "2025-02-10",
|
|
78
|
+
11: "2025-02-11",
|
|
79
|
+
12: "2025-02-12",
|
|
80
|
+
13: "2025-02-13",
|
|
81
|
+
14: "2025-02-14",
|
|
82
|
+
15: "2025-02-15",
|
|
83
|
+
16: "2025-02-16",
|
|
84
|
+
17: "2025-02-17",
|
|
85
|
+
18: "2025-02-18",
|
|
86
|
+
19: "2025-02-19",
|
|
87
|
+
20: "2025-02-20",
|
|
88
|
+
21: "2025-02-21",
|
|
89
|
+
22: "2025-02-22",
|
|
90
|
+
23: "2025-02-23",
|
|
91
|
+
24: "2025-02-24",
|
|
92
|
+
25: "2025-02-25",
|
|
93
|
+
26: "2025-02-26",
|
|
94
|
+
27: "2025-02-27",
|
|
95
|
+
28: "2025-02-28",
|
|
90
96
|
},
|
|
91
97
|
},
|
|
92
98
|
});
|
|
93
99
|
});
|
|
94
100
|
|
|
95
101
|
test("returns a tree for a day range", async () => {
|
|
96
|
-
const tree = calendarTree(
|
|
102
|
+
const tree = calendarTree({
|
|
103
|
+
start: "2025-02-27",
|
|
104
|
+
end: "2025-03-02",
|
|
105
|
+
value: (year, month, day) => `${year}-${month}-${day}`,
|
|
106
|
+
});
|
|
97
107
|
const plain = await toPlainValue(tree);
|
|
98
108
|
assert.deepEqual(plain, {
|
|
99
109
|
2025: {
|
|
100
110
|
"02": {
|
|
101
|
-
27:
|
|
102
|
-
28:
|
|
111
|
+
27: "2025-02-27",
|
|
112
|
+
28: "2025-02-28",
|
|
103
113
|
},
|
|
104
114
|
"03": {
|
|
105
|
-
"01":
|
|
106
|
-
"02":
|
|
115
|
+
"01": "2025-03-01",
|
|
116
|
+
"02": "2025-03-02",
|
|
107
117
|
},
|
|
108
118
|
},
|
|
109
119
|
});
|