astro-accelerator-utils 0.0.45 → 0.1.1

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/README.md CHANGED
@@ -1,2 +1,6 @@
1
- # astro-accelerator-utils
1
+ # Astro Accelerator Utils
2
+
3
+ [![Test](https://github.com/Steve-Fenton/astro-accelerator-utils/actions/workflows/build-astro.yml/badge.svg)](https://github.com/Steve-Fenton/astro-accelerator-utils/actions/workflows/build-astro.yml)
4
+
2
5
  Utility classes for Astro Accelerator
6
+
package/index.d.mts CHANGED
@@ -1,12 +1,13 @@
1
+ import { DateFormatter } from "./lib/v1/dates.mjs";
2
+ import { UrlFormatter } from "./lib/v1/urls.mjs";
3
+ import { Posts } from "./lib/v1/posts.mjs";
4
+ import * as Cache from "./lib/cache.mjs";
1
5
  import * as PostQueries from "./lib/postQueries.mjs";
2
6
  import * as PostFiltering from "./lib/postFiltering.mjs";
3
7
  import * as PostOrdering from "./lib/postOrdering.mjs";
4
8
  import * as PostPaging from "./lib/postPaging.mjs";
5
- import * as Cache from "./lib/cache.mjs";
6
- import * as Dates from "./lib/dates.mjs";
7
9
  import * as FooterMenu from "./lib/footerMenu.mjs";
8
10
  import * as Markdown from "./lib/markdown.mjs";
9
11
  import * as Navigation from "./lib/navigation.mjs";
10
12
  import * as Taxonomy from "./lib/taxonomy.mjs";
11
- import * as Urls from "./lib/urls.mjs";
12
- export { PostQueries, PostFiltering, PostOrdering, PostPaging, Cache, Dates, FooterMenu, Markdown, Navigation, Taxonomy, Urls };
13
+ export { DateFormatter, UrlFormatter, Posts, Cache, PostQueries, PostFiltering, PostOrdering, PostPaging, FooterMenu, Markdown, Navigation, Taxonomy };
package/index.mjs CHANGED
@@ -1,25 +1,28 @@
1
+ import { DateFormatter } from './lib/v1/dates.mjs';
2
+ import { UrlFormatter } from './lib/v1/urls.mjs';
3
+ import { Posts } from './lib/v1/posts.mjs';
4
+
5
+ import * as Cache from './lib/cache.mjs';
1
6
  import * as PostQueries from './lib/postQueries.mjs';
2
7
  import * as PostFiltering from './lib/postFiltering.mjs';
3
8
  import * as PostOrdering from './lib/postOrdering.mjs';
4
9
  import * as PostPaging from './lib/postPaging.mjs';
5
- import * as Cache from './lib/cache.mjs';
6
- import * as Dates from './lib/dates.mjs';
7
10
  import * as FooterMenu from './lib/footerMenu.mjs';
8
11
  import * as Markdown from './lib/markdown.mjs';
9
12
  import * as Navigation from './lib/navigation.mjs';
10
13
  import * as Taxonomy from './lib/taxonomy.mjs';
11
- import * as Urls from './lib/urls.mjs';
12
14
 
13
15
  export {
16
+ DateFormatter,
17
+ UrlFormatter,
18
+ Posts,
19
+ Cache,
14
20
  PostQueries,
15
21
  PostFiltering,
16
22
  PostOrdering,
17
23
  PostPaging,
18
- Cache,
19
- Dates,
20
24
  FooterMenu,
21
25
  Markdown,
22
26
  Navigation,
23
- Taxonomy,
24
- Urls
27
+ Taxonomy
25
28
  };
package/lib/cache.d.mts CHANGED
@@ -12,9 +12,10 @@ export function getItemPath(key: string): Promise<string>;
12
12
  /**
13
13
  * Gets an item from the cache
14
14
  * @param {string} key
15
+ * @param {number} [maxAgeInSeconds]
15
16
  * @returns {Promise<any>}
16
17
  */
17
- export function getItem(key: string): Promise<any>;
18
+ export function getItem(key: string, maxAgeInSeconds?: number): Promise<any>;
18
19
  /**
19
20
  * Adds an item to the cache
20
21
  * @param {string} key
@@ -27,4 +28,3 @@ export function setItem(key: string, value: any): Promise<void>;
27
28
  * @returns {Promise<void>}
28
29
  */
29
30
  export function clear(): Promise<void>;
30
- export const maxAge: 200;
package/lib/cache.mjs CHANGED
@@ -2,8 +2,6 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import process from 'process';
4
4
 
5
- export const maxAge = 200; //seconds
6
-
7
5
  /**
8
6
  * Get's the path of the cache files
9
7
  * @returns {Promise<string>}
@@ -27,9 +25,14 @@ export async function getItemPath (key) {
27
25
  /**
28
26
  * Gets an item from the cache
29
27
  * @param {string} key
28
+ * @param {number} [maxAgeInSeconds]
30
29
  * @returns {Promise<any>}
31
30
  */
32
- export async function getItem (key) {
31
+ export async function getItem (key, maxAgeInSeconds) {
32
+ if (maxAgeInSeconds == null) {
33
+ maxAgeInSeconds = 200;
34
+ }
35
+
33
36
  const itemPath = await getItemPath(key);
34
37
  try {
35
38
 
@@ -37,14 +40,14 @@ export async function getItem (key) {
37
40
 
38
41
  var date_time = new Date();
39
42
  let timeDifference = Math.abs((date_time.getTime() - mtime.getTime()) / 1000);
40
- if (timeDifference < maxAge) {
43
+ if (timeDifference < maxAgeInSeconds) {
41
44
  console.log('Cache hit', key);
42
45
  const content = fs.readFileSync(itemPath).toString();
43
46
  return JSON.parse(content);
44
47
  }
45
48
  } catch{}
46
49
 
47
- console.warn('Cache miss', key);
50
+ console.log('Cache miss', key);
48
51
  return null;
49
52
  }
50
53
 
@@ -64,10 +67,10 @@ export async function setItem (key, value) {
64
67
  * @returns {Promise<void>}
65
68
  */
66
69
  export async function clear() {
67
- const path = await getCachePath();
68
- const files = await fs.promises.readdir(path);
70
+ const folder = await getCachePath();
71
+ const files = fs.readdirSync(folder);
69
72
 
70
73
  for(const file of files) {
71
- await fs.promises.unlink(path.join(path, file));
74
+ fs.unlinkSync(path.join(folder, file));
72
75
  }
73
76
  }
@@ -12,9 +12,9 @@
12
12
  * @param {any} translations
13
13
  * @param {Site} site
14
14
  * @param {(NavPage | 'categories' | 'tags' | 'toptags')[]} menu
15
- * @returns
15
+ * @returns {Promise<NavPage[]>}
16
16
  */
17
- export function getMenu(currentUrl: URL, _: TranslationProvider, translations: any, site: any, menu: (NavPage | 'categories' | 'tags' | 'toptags')[]): Promise<import("../types/NavPage").NavPage[]>;
17
+ export function getMenu(currentUrl: URL, _: TranslationProvider, translations: any, site: any, menu: (NavPage | 'categories' | 'tags' | 'toptags')[]): Promise<NavPage[]>;
18
18
  /**
19
19
  *
20
20
  * @param {TaxonomyLinks} links
@@ -17,7 +17,7 @@ import * as PostQueries from './postQueries.mjs';
17
17
  * @param {any} translations
18
18
  * @param {Site} site
19
19
  * @param {(NavPage | 'categories' | 'tags' | 'toptags')[]} menu
20
- * @returns
20
+ * @returns {Promise<NavPage[]>}
21
21
  */
22
22
  export async function getMenu (currentUrl, _, translations, site, menu) {
23
23
  const links = Taxonomy.taxonomyLinks(translations, _, site);
@@ -1,11 +1,18 @@
1
1
  /**
2
- * Fetches pages
2
+ * Replaces the import.meta.glob function
3
+ * @param {() => MarkdownInstance[]} fetcher
4
+ */
5
+ export function injectFetchAll(fetcher: () => MarkdownInstance[]): void;
6
+ /**
7
+ * Replaced by Posts.all()
8
+ * Use Posts.all().filter(...) to filter results
3
9
  * @param {PagePredicate} [filter]
4
10
  * @returns {Promise<MarkdownInstance[]>}
5
11
  */
6
12
  export function getPages(filter?: PagePredicate): Promise<MarkdownInstance[]>;
7
13
  /**
8
- *
14
+ * Replaced by Posts.root()
15
+ * Use Posts.root().filter(...) to filter results
9
16
  * @param {Site} site
10
17
  * @param {PagePredicate} [filter]
11
18
  * @returns {Promise<MarkdownInstance[]>}
@@ -18,7 +25,7 @@ export function getTopLevelPages(site: Site, filter?: PagePredicate): Promise<Ma
18
25
  */
19
26
  export function getAuthors(frontmatter: Frontmatter): Promise<AuthorList>;
20
27
  /**
21
- *
28
+ * Get a single author by id/slug
22
29
  * @param {string} slug
23
30
  * @returns {Promise<AuthorInfo>}
24
31
  */
@@ -12,12 +12,23 @@ import * as Urls from './urls.mjs';
12
12
  * @typedef { import("../types/Site").Site } Site
13
13
  */
14
14
 
15
- function fetchAll () {
15
+ /* istanbul ignore next */
16
+ /** @type {() => MarkdownInstance[]} */
17
+ let fetchAll = () => {
16
18
  return import.meta.glob("/src/pages/**/*.md", { eager: true });
17
19
  }
18
20
 
19
21
  /**
20
- * Fetches pages
22
+ * Replaces the import.meta.glob function
23
+ * @param {() => MarkdownInstance[]} fetcher
24
+ */
25
+ export function injectFetchAll (fetcher) {
26
+ fetchAll = fetcher;
27
+ }
28
+
29
+ /**
30
+ * Replaced by Posts.all()
31
+ * Use Posts.all().filter(...) to filter results
21
32
  * @param {PagePredicate} [filter]
22
33
  * @returns {Promise<MarkdownInstance[]>}
23
34
  */
@@ -39,7 +50,8 @@ export async function getPages (filter) {
39
50
  }
40
51
 
41
52
  /**
42
- *
53
+ * Replaced by Posts.root()
54
+ * Use Posts.root().filter(...) to filter results
43
55
  * @param {Site} site
44
56
  * @param {PagePredicate} [filter]
45
57
  * @returns {Promise<MarkdownInstance[]>}
@@ -113,7 +125,7 @@ export async function getAuthors (frontmatter) {
113
125
  }
114
126
 
115
127
  /**
116
- *
128
+ * Get a single author by id/slug
117
129
  * @param {string} slug
118
130
  * @returns {Promise<AuthorInfo>}
119
131
  */
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * @typedef { import("../types/Site").Site } Site
2
3
  * @typedef { import("../types/Taxonomy").Taxonomy } Taxonomy
3
4
  * @typedef { import("../types/Taxonomy").TaxonomyEntry } TaxonomyEntry
4
5
  * @typedef { import("../types/Taxonomy").TaxonomyLinks } TaxonomyLinks
@@ -24,6 +25,7 @@ export function taxonomyLinks(translations: any, lang: (entry: any) => string, s
24
25
  * @returns {Promise<Taxonomy}
25
26
  */
26
27
  export function getTaxonomy(): Promise<Taxonomy>;
28
+ export type Site = import("../types/Site").Site;
27
29
  export type Taxonomy = import("../types/Taxonomy").Taxonomy;
28
30
  export type TaxonomyEntry = import("../types/Taxonomy").TaxonomyEntry;
29
31
  export type TaxonomyLinks = import("../types/Taxonomy").TaxonomyLinks;
package/lib/taxonomy.mjs CHANGED
@@ -4,6 +4,7 @@ import * as PostQueries from './postQueries.mjs';
4
4
  import * as PostFiltering from './postFiltering.mjs';
5
5
 
6
6
  /**
7
+ * @typedef { import("../types/Site").Site } Site
7
8
  * @typedef { import("../types/Taxonomy").Taxonomy } Taxonomy
8
9
  * @typedef { import("../types/Taxonomy").TaxonomyEntry } TaxonomyEntry
9
10
  * @typedef { import("../types/Taxonomy").TaxonomyLinks } TaxonomyLinks
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @typedef { import("../types/Site") } Site
3
+ */
4
+ export class DateFormatter {
5
+ /**
6
+ * Constructor
7
+ * @param {Intl.DateTimeFormatOptions} dateOptions
8
+ */
9
+ constructor(dateOptions: Intl.DateTimeFormatOptions);
10
+ dateOptions: Intl.DateTimeFormatOptions;
11
+ /**
12
+ * Returns the formatted pubDate
13
+ * @param {any} frontmatter
14
+ * @param {string} lang
15
+ * @param {Site} site
16
+ * @returns {string}
17
+ */
18
+ formatDate(date: any, lang: string): string;
19
+ }
20
+ export type Site = any;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @typedef { import("../types/Site") } Site
3
+ */
4
+
5
+ export class DateFormatter {
6
+ /**
7
+ * Constructor
8
+ * @param {Intl.DateTimeFormatOptions} dateOptions
9
+ */
10
+ constructor(dateOptions) {
11
+ this.dateOptions = dateOptions;
12
+ }
13
+
14
+ /**
15
+ * Returns the formatted pubDate
16
+ * @param {any} frontmatter
17
+ * @param {string} lang
18
+ * @param {Site} site
19
+ * @returns {string}
20
+ */
21
+ formatDate(date, lang) {
22
+ if (date) {
23
+ return new Date(date).toLocaleDateString(lang, this.dateOptions);
24
+ }
25
+
26
+ return '';
27
+ }
28
+ }
@@ -0,0 +1,11 @@
1
+ export class Posts {
2
+ /**
3
+ * Constructor
4
+ * @param {() => MarkdownInstance[]} fetchAll
5
+ */
6
+ constructor(fetchAll: () => MarkdownInstance[]);
7
+ fetchAll: () => any;
8
+ allPosts: any[];
9
+ all(): any[];
10
+ root(subfolder: any): any[];
11
+ }
@@ -0,0 +1,30 @@
1
+ export class Posts {
2
+ /**
3
+ * Constructor
4
+ * @param {() => MarkdownInstance[]} fetchAll
5
+ */
6
+ constructor(fetchAll) {
7
+ this.fetchAll = fetchAll ?? function() { return import.meta.glob("/src/pages/**/*.md", { eager: true }); }
8
+ this.allPosts = [];
9
+ }
10
+
11
+ all () {
12
+ if (this.allPosts.length === 0) {
13
+ const pageImportResult = this.fetchAll();
14
+ this.allPosts = Object.values(pageImportResult);
15
+ }
16
+
17
+ return this.allPosts;
18
+ }
19
+
20
+ root (subfolder) {
21
+ const isRoot = subfolder.length == 0;
22
+ const expectedDepth = isRoot ? 1 : 2;
23
+
24
+ return this.all().filter(p => {
25
+ const depth = (p.url ?? '/').split('/').length - 1;
26
+ return depth == expectedDepth
27
+ || (depth == (expectedDepth - 1) && p.file.includes(subfolder.toLowerCase() + '.md'));
28
+ })
29
+ }
30
+ }
@@ -0,0 +1,20 @@
1
+ export class UrlFormatter {
2
+ /**
3
+ * Constructor
4
+ * @param {string} siteUrl
5
+ */
6
+ constructor(siteUrl: string);
7
+ siteUrl: string;
8
+ /**
9
+ * Ensures trailing slash is used
10
+ * @param {URL} url
11
+ * @returns {URL}
12
+ */
13
+ addSlashToUrl(url: URL): URL;
14
+ /**
15
+ * Ensures trailing slash is used
16
+ * @param {string | undefined} address
17
+ * @returns {string}
18
+ */
19
+ addSlashToAddress(address: string | undefined): string;
20
+ }
@@ -0,0 +1,39 @@
1
+ export class UrlFormatter {
2
+ /**
3
+ * Constructor
4
+ * @param {string} siteUrl
5
+ */
6
+ constructor(siteUrl) {
7
+ this.siteUrl = siteUrl;
8
+ }
9
+
10
+ /**
11
+ * Ensures trailing slash is used
12
+ * @param {URL} url
13
+ * @returns {URL}
14
+ */
15
+ addSlashToUrl(url) {
16
+ url.pathname += url.pathname.endsWith('/') ? '' : '/';
17
+ return url;
18
+ }
19
+
20
+ /**
21
+ * Ensures trailing slash is used
22
+ * @param {string | undefined} address
23
+ * @returns {string}
24
+ */
25
+ addSlashToAddress(address) {
26
+ if (!address) {
27
+ // Handle null or empty addresses
28
+ address = '/';
29
+ }
30
+
31
+ if (address.indexOf('//') > -1) {
32
+ // Don't mess with absolute addresses
33
+ return address;
34
+ }
35
+
36
+ const url = this.addSlashToUrl(new URL(address, this.siteUrl));
37
+ return url.pathname + url.search;
38
+ }
39
+ }
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "astro-accelerator-utils",
3
- "version": "0.0.45",
3
+ "version": "0.1.1",
4
4
  "description": "Astro utilities for Astro Accelerator.",
5
5
  "main": "index.mjs",
6
+ "type": "module",
6
7
  "files": [
7
8
  "index.mjs",
8
9
  "index.d.mts",
@@ -11,7 +12,8 @@
11
12
  ],
12
13
  "types": "index.d.mts",
13
14
  "scripts": {
14
- "types": "node ./clean.mjs && npx tsc index.mjs --allowJs --declaration --emitDeclarationOnly"
15
+ "types": "node ./clean.mjs && npx tsc index.mjs --allowJs --declaration --emitDeclarationOnly",
16
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --collectCoverage --runInBand"
15
17
  },
16
18
  "repository": {
17
19
  "type": "git",
@@ -30,10 +32,11 @@
30
32
  "homepage": "https://astro.stevefenton.co.uk/",
31
33
  "devDependencies": {
32
34
  "@types/node": "^18.11.9",
33
- "typescript": "^4.9.3",
34
- "unified": "^10.1.2",
35
+ "jest": "^29.3.1",
36
+ "rehype-stringify": "^9.0.3",
35
37
  "remark-parse": "^10.0.1",
36
38
  "remark-rehype": "^10.1.0",
37
- "rehype-stringify": "^9.0.3"
39
+ "typescript": "^4.9.3",
40
+ "unified": "^10.1.2"
38
41
  }
39
42
  }
package/lib/dates.d.mts DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * @typedef { import("../types/Site") } Site
3
- */
4
- /**
5
- * Returns the formatted pubDate
6
- * @param {any} frontmatter
7
- * @param {string} lang
8
- * @param {Site} site
9
- * @returns {string}
10
- */
11
- export function formatDate(frontmatter: any, lang: string, site: Site): string;
12
- /**
13
- * Returns the formatted modDate
14
- * @param {any} frontmatter
15
- * @param {string} lang
16
- * @param {Site} site
17
- * @returns {string}
18
- */
19
- export function formatModifiedDate(frontmatter: any, lang: string, site: Site): string;
20
- export type Site = typeof import("../types/Site");
package/lib/dates.mjs DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * @typedef { import("../types/Site") } Site
3
- */
4
-
5
- /**
6
- * Returns the formatted pubDate
7
- * @param {any} frontmatter
8
- * @param {string} lang
9
- * @param {Site} site
10
- * @returns {string}
11
- */
12
- export function formatDate (frontmatter, lang, site) {
13
- const date = frontmatter.pubDate ?? '';
14
-
15
- if (date) {
16
- return new Date(date).toLocaleDateString(lang, site.dateOptions);
17
- }
18
-
19
- return '';
20
- }
21
-
22
- /**
23
- * Returns the formatted modDate
24
- * @param {any} frontmatter
25
- * @param {string} lang
26
- * @param {Site} site
27
- * @returns {string}
28
- */
29
- export function formatModifiedDate (frontmatter, lang, site) {
30
- const date = frontmatter.modDate ?? '';
31
-
32
- if (date) {
33
- return new Date(date).toLocaleDateString(lang, site.dateOptions);
34
- }
35
-
36
- return '';
37
- }