@shevky/core 0.0.2 → 0.0.4

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.
@@ -0,0 +1,12 @@
1
+ export class ContentBody {
2
+ /**
3
+ * @param {string} content
4
+ */
5
+ constructor(content) {
6
+ this._content = content;
7
+ }
8
+
9
+ get content() {
10
+ return this._content;
11
+ }
12
+ }
@@ -0,0 +1,170 @@
1
+ import { ContentBody } from "./contentBody.js";
2
+ import { ContentHeader } from "./contentHeader.js";
3
+
4
+ export class ContentFile {
5
+ /**
6
+ *
7
+ * @param {Record<string, unknown>} frontMatter
8
+ * @param {string} content
9
+ * @param {string} filePath
10
+ * @param {boolean} isValid
11
+ */
12
+ constructor(frontMatter, content, filePath, isValid) {
13
+ this._header = new ContentHeader(frontMatter);
14
+ this._body = new ContentBody(content);
15
+ this._filePath = filePath;
16
+ this._isValid = isValid;
17
+ }
18
+
19
+ get header() {
20
+ return this._header;
21
+ }
22
+
23
+ get body() {
24
+ return this._body;
25
+ }
26
+
27
+ get isValid() {
28
+ return this._isValid;
29
+ }
30
+
31
+ get sourcePath() {
32
+ return this._filePath;
33
+ }
34
+
35
+ get content() {
36
+ return this._body.content;
37
+ }
38
+
39
+ get status() {
40
+ return this._header.status;
41
+ }
42
+
43
+ get id() {
44
+ return this._header.id;
45
+ }
46
+
47
+ get lang() {
48
+ return this._header.lang;
49
+ }
50
+
51
+ get slug() {
52
+ return this._header.slug;
53
+ }
54
+
55
+ get canonical() {
56
+ return this._header.canonical;
57
+ }
58
+
59
+ get title() {
60
+ return this._header.title;
61
+ }
62
+
63
+ get template() {
64
+ return this._header.template;
65
+ }
66
+
67
+ get isFeatured() {
68
+ return this._header.isFeatured;
69
+ }
70
+
71
+ get category() {
72
+ return this._header.category;
73
+ }
74
+
75
+ get tags() {
76
+ return this._header.tags;
77
+ }
78
+
79
+ get keywords() {
80
+ return this._header.keywords;
81
+ }
82
+
83
+ get series() {
84
+ return this._header.series;
85
+ }
86
+
87
+ get collectionType() {
88
+ return this._header.collectionType;
89
+ }
90
+
91
+ get isCollectionPage() {
92
+ return this._header.isCollectionPage;
93
+ }
94
+
95
+ get isPolicy() {
96
+ return this._header.isPolicy;
97
+ }
98
+
99
+ get isAboutPage() {
100
+ return this._header.isAboutPage;
101
+ }
102
+
103
+ get isContactPage() {
104
+ return this._header.isContactPage;
105
+ }
106
+
107
+ get date() {
108
+ return this._header.date;
109
+ }
110
+
111
+ get updated() {
112
+ return this._header.updated;
113
+ }
114
+
115
+ get dateDisplay() {
116
+ return this._header.dateDisplay;
117
+ }
118
+
119
+ get description() {
120
+ return this._header.description;
121
+ }
122
+
123
+ get cover() {
124
+ return this._header.cover;
125
+ }
126
+
127
+ get coverAlt() {
128
+ return this._header.coverAlt;
129
+ }
130
+
131
+ get coverCaption() {
132
+ return this._header.coverCaption;
133
+ }
134
+
135
+ get readingTime() {
136
+ return this._header.readingTime;
137
+ }
138
+
139
+ get seriesTitle() {
140
+ return this._header.seriesTitle;
141
+ }
142
+
143
+ get menuLabel() {
144
+ return this._header.menuLabel;
145
+ }
146
+
147
+ get isHiddenOnMenu() {
148
+ return this._header.isHiddenOnMenu;
149
+ }
150
+
151
+ get menuOrder() {
152
+ return this._header.menuOrder;
153
+ }
154
+
155
+ get layout() {
156
+ return this._header.layout;
157
+ }
158
+
159
+ get isPublished() {
160
+ return this.status === "published";
161
+ }
162
+
163
+ get isDraft() {
164
+ return this.status === "draft";
165
+ }
166
+
167
+ get isPostTemplate() {
168
+ return this.template === "post";
169
+ }
170
+ }
@@ -0,0 +1,295 @@
1
+ import { format as _fmt, config as _cfg } from "@shevky/base";
2
+
3
+ export class ContentHeader {
4
+ /**
5
+ * @param {Record<string, unknown>} frontMatter
6
+ */
7
+ constructor(frontMatter) {
8
+ this._frontMatter = frontMatter ?? {};
9
+ }
10
+
11
+ get raw() {
12
+ return this._frontMatter;
13
+ }
14
+
15
+ get status() {
16
+ return typeof this._frontMatter.status === "string"
17
+ ? this._frontMatter.status.trim().toLowerCase()
18
+ : "";
19
+ }
20
+
21
+ get id() {
22
+ return typeof this._frontMatter.id === "string"
23
+ ? this._frontMatter.id.trim()
24
+ : "";
25
+ }
26
+
27
+ get lang() {
28
+ return typeof this._frontMatter.lang === "string"
29
+ ? this._frontMatter.lang
30
+ : "";
31
+ }
32
+
33
+ get slug() {
34
+ return typeof this._frontMatter.slug === "string"
35
+ ? this._frontMatter.slug
36
+ : "";
37
+ }
38
+
39
+ get canonical() {
40
+ return typeof this._frontMatter.canonical === "string"
41
+ ? this._frontMatter.canonical
42
+ : "";
43
+ }
44
+
45
+ get alternate() {
46
+ const value = this._frontMatter.alternate;
47
+ if (typeof value === "string") {
48
+ return value.trim();
49
+ }
50
+ if (value && typeof value === "object") {
51
+ return value;
52
+ }
53
+ return "";
54
+ }
55
+
56
+ get pair() {
57
+ return typeof this._frontMatter.pair === "string"
58
+ ? this._frontMatter.pair.trim()
59
+ : "";
60
+ }
61
+
62
+ get title() {
63
+ return typeof this._frontMatter.title === "string"
64
+ ? this._frontMatter.title
65
+ : "";
66
+ }
67
+
68
+ get template() {
69
+ return typeof this._frontMatter.template === "string"
70
+ ? this._frontMatter.template.trim()
71
+ : "page";
72
+ }
73
+
74
+ get listKey() {
75
+ return typeof this._frontMatter.listKey === "string"
76
+ ? this._frontMatter.listKey.trim()
77
+ : "";
78
+ }
79
+
80
+ get listHeading() {
81
+ return typeof this._frontMatter.listHeading === "string"
82
+ ? this._frontMatter.listHeading.trim()
83
+ : "";
84
+ }
85
+
86
+ get listingEmpty() {
87
+ const value = this._frontMatter.listingEmpty;
88
+ return value ?? "";
89
+ }
90
+
91
+ get listType() {
92
+ return typeof this._frontMatter.listType === "string"
93
+ ? this._frontMatter.listType.trim()
94
+ : "";
95
+ }
96
+
97
+ get type() {
98
+ return typeof this._frontMatter.type === "string"
99
+ ? this._frontMatter.type.trim()
100
+ : "";
101
+ }
102
+
103
+ get related() {
104
+ return Array.isArray(this._frontMatter.related)
105
+ ? this._frontMatter.related
106
+ : [];
107
+ }
108
+
109
+ get isFeatured() {
110
+ return _fmt.boolean(this._frontMatter.featured);
111
+ }
112
+
113
+ get category() {
114
+ return _fmt.slugify(
115
+ typeof this._frontMatter.category === "string"
116
+ ? this._frontMatter.category
117
+ : "",
118
+ );
119
+ }
120
+
121
+ get tags() {
122
+ const tags = _fmt.normalizeStringArray(this._frontMatter.tags);
123
+ return tags.map((t) => {
124
+ return _fmt.slugify(t);
125
+ });
126
+ }
127
+
128
+ get keywords() {
129
+ const keywords = _fmt.normalizeStringArray(this._frontMatter.keywords);
130
+ return keywords.filter((item) => item && item.trim().length > 0);
131
+ }
132
+
133
+ get series() {
134
+ return _fmt.slugify(
135
+ typeof this._frontMatter.series === "string"
136
+ ? this._frontMatter.series
137
+ : "",
138
+ );
139
+ }
140
+
141
+ get collectionType() {
142
+ return typeof this._frontMatter.collectionType === "string"
143
+ ? this._frontMatter.collectionType.trim()
144
+ : "";
145
+ }
146
+
147
+ get isCollectionPage() {
148
+ const type = this.collectionType;
149
+ return type === "tag" || type === "category" || type === "series";
150
+ }
151
+
152
+ get isPolicy() {
153
+ const category =
154
+ typeof this._frontMatter.category === "string"
155
+ ? this._frontMatter.category.trim()
156
+ : "";
157
+ return _fmt.boolean(category === "policy");
158
+ }
159
+
160
+ get isAboutPage() {
161
+ const type =
162
+ typeof this._frontMatter.type === "string"
163
+ ? this._frontMatter.type.trim()
164
+ : "";
165
+ return _fmt.boolean(type === "about");
166
+ }
167
+
168
+ get isContactPage() {
169
+ const type =
170
+ typeof this._frontMatter.type === "string"
171
+ ? this._frontMatter.type.trim()
172
+ : "";
173
+ return _fmt.boolean(type === "contact");
174
+ }
175
+
176
+ get date() {
177
+ return this._frontMatter.date instanceof Date ||
178
+ typeof this._frontMatter.date === "string" ||
179
+ typeof this._frontMatter.date === "number"
180
+ ? this._frontMatter.date
181
+ : "";
182
+ }
183
+
184
+ get updated() {
185
+ return this._frontMatter.updated instanceof Date ||
186
+ typeof this._frontMatter.updated === "string" ||
187
+ typeof this._frontMatter.updated === "number"
188
+ ? this._frontMatter.updated
189
+ : "";
190
+ }
191
+
192
+ get dateDisplay() {
193
+ const dateValue =
194
+ this._frontMatter.date instanceof Date
195
+ ? this._frontMatter.date
196
+ : typeof this._frontMatter.date === "string" ||
197
+ typeof this._frontMatter.date === "number"
198
+ ? this._frontMatter.date
199
+ : null;
200
+ const langValue =
201
+ typeof this._frontMatter.lang === "string"
202
+ ? this._frontMatter.lang
203
+ : undefined;
204
+ return dateValue ? _fmt.date(dateValue, langValue) : null;
205
+ }
206
+
207
+ get description() {
208
+ return typeof this._frontMatter.description === "string"
209
+ ? this._frontMatter.description
210
+ : "";
211
+ }
212
+
213
+ get cover() {
214
+ return typeof this._frontMatter.cover === "string" &&
215
+ this._frontMatter.cover.trim().length > 0
216
+ ? this._frontMatter.cover
217
+ : _cfg.seo.defaultImage;
218
+ }
219
+
220
+ get coverAlt() {
221
+ return typeof this._frontMatter.coverAlt === "string"
222
+ ? this._frontMatter.coverAlt
223
+ : "";
224
+ }
225
+
226
+ get coverCaption() {
227
+ return typeof this._frontMatter.coverCaption === "string"
228
+ ? this._frontMatter.coverCaption
229
+ : "";
230
+ }
231
+
232
+ get readingTime() {
233
+ const value =
234
+ typeof this._frontMatter.readingTime === "number" ||
235
+ typeof this._frontMatter.readingTime === "string"
236
+ ? this._frontMatter.readingTime
237
+ : 0;
238
+ return _fmt.readingTime(value);
239
+ }
240
+
241
+ get seriesTitle() {
242
+ if (!this._frontMatter.series) {
243
+ return "";
244
+ }
245
+
246
+ const rawTitle =
247
+ typeof this._frontMatter.seriesTitle === "string"
248
+ ? this._frontMatter.seriesTitle.trim()
249
+ : "";
250
+ if (rawTitle.length > 0) {
251
+ return rawTitle;
252
+ }
253
+
254
+ return typeof this._frontMatter.series === "string"
255
+ ? this._frontMatter.series
256
+ : "";
257
+ }
258
+
259
+ get menuLabel() {
260
+ const fallbackKey =
261
+ (typeof this._frontMatter.id === "string" &&
262
+ this._frontMatter.id.trim()) ||
263
+ (typeof this._frontMatter.slug === "string" &&
264
+ this._frontMatter.slug.trim()) ||
265
+ "";
266
+ return (
267
+ (typeof this._frontMatter.menu === "string" &&
268
+ this._frontMatter.menu.trim().length > 0
269
+ ? this._frontMatter.menu.trim()
270
+ : typeof this._frontMatter.title === "string" &&
271
+ this._frontMatter.title.trim().length > 0
272
+ ? this._frontMatter.title.trim()
273
+ : fallbackKey) ?? fallbackKey
274
+ );
275
+ }
276
+
277
+ get isHiddenOnMenu() {
278
+ return !_fmt.boolean(this._frontMatter.show);
279
+ }
280
+
281
+ get menuOrder() {
282
+ const value =
283
+ typeof this._frontMatter.order === "number" ||
284
+ typeof this._frontMatter.order === "string"
285
+ ? this._frontMatter.order
286
+ : 0;
287
+ return _fmt.order(value);
288
+ }
289
+
290
+ get layout() {
291
+ return typeof this._frontMatter.layout === "string"
292
+ ? this._frontMatter.layout.trim()
293
+ : "default";
294
+ }
295
+ }
@@ -0,0 +1,85 @@
1
+ import { ContentFile } from "./contentFile.js";
2
+
3
+ export class ContentSummary {
4
+ /**
5
+ * @param {ContentFile} file
6
+ */
7
+ constructor(file) {
8
+ this._file = file;
9
+ }
10
+
11
+ get id() {
12
+ return this._file.id;
13
+ }
14
+
15
+ get title() {
16
+ return this._file.title;
17
+ }
18
+
19
+ get date() {
20
+ return this._file.date;
21
+ }
22
+
23
+ get description() {
24
+ return this._file.description;
25
+ }
26
+
27
+ get cover() {
28
+ return this._file.cover;
29
+ }
30
+
31
+ get coverAlt() {
32
+ return this._file.coverAlt;
33
+ }
34
+
35
+ get coverCaption() {
36
+ return this._file.coverCaption;
37
+ }
38
+
39
+ get readingTime() {
40
+ return this._file.readingTime;
41
+ }
42
+
43
+ get dateDisplay() {
44
+ return this._file.dateDisplay;
45
+ }
46
+
47
+ get slug() {
48
+ return this._file.slug;
49
+ }
50
+
51
+ get lang() {
52
+ return this._file.lang;
53
+ }
54
+
55
+ get canonical() {
56
+ return this._file.canonical;
57
+ }
58
+
59
+ get updated() {
60
+ return this._file.updated;
61
+ }
62
+
63
+ get seriesTitle() {
64
+ return this._file.seriesTitle;
65
+ }
66
+
67
+ toObject() {
68
+ return {
69
+ id: this.id,
70
+ title: this.title,
71
+ slug: this.slug,
72
+ lang: this.lang,
73
+ canonical: this.canonical,
74
+ date: this.date,
75
+ updated: this.updated,
76
+ description: this.description,
77
+ cover: this.cover,
78
+ coverAlt: this.coverAlt,
79
+ coverCaption: this.coverCaption,
80
+ readingTime: this.readingTime,
81
+ dateDisplay: this.dateDisplay,
82
+ seriesTitle: this.seriesTitle,
83
+ };
84
+ }
85
+ }
@@ -0,0 +1,51 @@
1
+ import { ContentFile } from "./contentFile.js";
2
+
3
+ export class MenuItem {
4
+ /**
5
+ * @param {ContentFile} file
6
+ */
7
+ constructor(file) {
8
+ this._file = file;
9
+ }
10
+
11
+ get key() {
12
+ return this._file.id;
13
+ }
14
+
15
+ get label() {
16
+ return this._file.menuLabel;
17
+ }
18
+
19
+ get url() {
20
+ return this._file.canonical;
21
+ }
22
+
23
+ get slug() {
24
+ return this._file.slug;
25
+ }
26
+
27
+ get order() {
28
+ return typeof this._file.menuOrder === "number" ? this._file.menuOrder : 0;
29
+ }
30
+
31
+ get lang() {
32
+ return this._file.lang;
33
+ }
34
+
35
+ get isEligable() {
36
+ return (
37
+ this._file.isValid &&
38
+ !this._file.isDraft &&
39
+ this._file.isPublished &&
40
+ !this._file.isHiddenOnMenu
41
+ );
42
+ }
43
+
44
+ toObject() {
45
+ return {
46
+ key: this.key,
47
+ label: this.label,
48
+ order: this.order,
49
+ };
50
+ }
51
+ }
package/lib/page.js ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @typedef {{
3
+ * kind?: string,
4
+ * type?: string,
5
+ * lang?: string,
6
+ * slug?: string,
7
+ * canonical?: string,
8
+ * layout?: string,
9
+ * template?: string,
10
+ * front?: Record<string, unknown>,
11
+ * view?: Record<string, unknown>,
12
+ * html?: string,
13
+ * sourcePath?: string,
14
+ * outputPath?: string,
15
+ * writeMeta?: Record<string, unknown>,
16
+ * isDynamic?: boolean,
17
+ * isCollection?: boolean,
18
+ * isStatic?: boolean,
19
+ * }} PageInput
20
+ */
21
+
22
+ export class Page {
23
+ /**
24
+ * @param {PageInput} input
25
+ */
26
+ constructor(input) {
27
+ this._input = input ?? {};
28
+ }
29
+
30
+ get kind() {
31
+ return typeof this._input.kind === "string" ? this._input.kind : "";
32
+ }
33
+
34
+ get type() {
35
+ return typeof this._input.type === "string" ? this._input.type : "";
36
+ }
37
+
38
+ get lang() {
39
+ return typeof this._input.lang === "string" ? this._input.lang : "";
40
+ }
41
+
42
+ get slug() {
43
+ return typeof this._input.slug === "string" ? this._input.slug : "";
44
+ }
45
+
46
+ get canonical() {
47
+ return typeof this._input.canonical === "string"
48
+ ? this._input.canonical
49
+ : "";
50
+ }
51
+
52
+ get layout() {
53
+ return typeof this._input.layout === "string" ? this._input.layout : "";
54
+ }
55
+
56
+ get template() {
57
+ return typeof this._input.template === "string" ? this._input.template : "";
58
+ }
59
+
60
+ get front() {
61
+ return this._input.front ?? {};
62
+ }
63
+
64
+ get view() {
65
+ return this._input.view ?? {};
66
+ }
67
+
68
+ get html() {
69
+ return typeof this._input.html === "string" ? this._input.html : "";
70
+ }
71
+
72
+ get sourcePath() {
73
+ return typeof this._input.sourcePath === "string"
74
+ ? this._input.sourcePath
75
+ : "";
76
+ }
77
+
78
+ get outputPath() {
79
+ return typeof this._input.outputPath === "string"
80
+ ? this._input.outputPath
81
+ : "";
82
+ }
83
+
84
+ get writeMeta() {
85
+ return this._input.writeMeta ?? {};
86
+ }
87
+
88
+ get isDynamic() {
89
+ return Boolean(this._input.isDynamic);
90
+ }
91
+
92
+ get isCollection() {
93
+ return Boolean(this._input.isCollection);
94
+ }
95
+
96
+ get isStatic() {
97
+ return Boolean(this._input.isStatic);
98
+ }
99
+
100
+ toObject() {
101
+ return { ...this._input };
102
+ }
103
+ }