astro-accelerator-utils 0.0.44 → 0.1.0

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,13 +1,11 @@
1
+ import { DateFormatter } from "./lib/v1/dates.mjs";
2
+ import { UrlFormatter } from "./lib/v1/urls.mjs";
1
3
  import * as PostQueries from "./lib/postQueries.mjs";
2
4
  import * as PostFiltering from "./lib/postFiltering.mjs";
3
5
  import * as PostOrdering from "./lib/postOrdering.mjs";
4
6
  import * as PostPaging from "./lib/postPaging.mjs";
5
- import * as Cache from "./lib/cache.mjs";
6
- import * as Config from "./lib/config.mjs";
7
- import * as Dates from "./lib/dates.mjs";
8
7
  import * as FooterMenu from "./lib/footerMenu.mjs";
9
8
  import * as Markdown from "./lib/markdown.mjs";
10
9
  import * as Navigation from "./lib/navigation.mjs";
11
10
  import * as Taxonomy from "./lib/taxonomy.mjs";
12
- import * as Urls from "./lib/urls.mjs";
13
- export { PostQueries, PostFiltering, PostOrdering, PostPaging, Cache, Config, Dates, FooterMenu, Markdown, Navigation, Taxonomy, Urls };
11
+ export { DateFormatter, UrlFormatter, PostQueries, PostFiltering, PostOrdering, PostPaging, FooterMenu, Markdown, Navigation, Taxonomy };
package/index.mjs CHANGED
@@ -1,27 +1,25 @@
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
+
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 Config from './lib/config.mjs';
7
- import * as Dates from './lib/dates.mjs';
8
9
  import * as FooterMenu from './lib/footerMenu.mjs';
9
10
  import * as Markdown from './lib/markdown.mjs';
10
11
  import * as Navigation from './lib/navigation.mjs';
11
12
  import * as Taxonomy from './lib/taxonomy.mjs';
12
- import * as Urls from './lib/urls.mjs';
13
13
 
14
14
  export {
15
+ DateFormatter,
16
+ UrlFormatter,
15
17
  PostQueries,
16
18
  PostFiltering,
17
19
  PostOrdering,
18
20
  PostPaging,
19
- Cache,
20
- Config,
21
- Dates,
22
21
  FooterMenu,
23
22
  Markdown,
24
23
  Navigation,
25
- Taxonomy,
26
- Urls
24
+ Taxonomy
27
25
  };
@@ -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 {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')[]): 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 {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 | null} address
17
+ * @returns {string}
18
+ */
19
+ addSlashToAddress(address: string | null): 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 | null} 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.44",
3
+ "version": "0.1.00",
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/cache.d.mts DELETED
@@ -1,25 +0,0 @@
1
- /**
2
- * Get's the path of the cache files
3
- * @returns {Promise<string>}
4
- */
5
- export function getCachePath(): Promise<string>;
6
- /**
7
- * Gets the file path for a cache item
8
- * @param {string} key
9
- * @returns {Promise<string>}
10
- */
11
- export function getItemPath(key: string): Promise<string>;
12
- /**
13
- * Gets an item from the cache
14
- * @param {string} key
15
- * @returns {Promise<any>}
16
- */
17
- export function getItem(key: string): Promise<any>;
18
- /**
19
- * Adds an item to the cache
20
- * @param {string} key
21
- * @param {any} value
22
- * @returns {Promise<void>}
23
- */
24
- export function setItem(key: string, value: any): Promise<void>;
25
- export const maxAge: 200;
package/lib/cache.mjs DELETED
@@ -1,60 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import process from 'process';
4
-
5
- export const maxAge = 200; //seconds
6
-
7
- /**
8
- * Get's the path of the cache files
9
- * @returns {Promise<string>}
10
- */
11
- export async function getCachePath () {
12
- const cachePath = path.join(process.cwd(), '.cache/');
13
- await fs.promises.mkdir(cachePath, { recursive: true })
14
- return cachePath;
15
- }
16
-
17
- /**
18
- * Gets the file path for a cache item
19
- * @param {string} key
20
- * @returns {Promise<string>}
21
- */
22
- export async function getItemPath (key) {
23
- const cachePath = await getCachePath();
24
- return path.join(cachePath, key + '.json');
25
- }
26
-
27
- /**
28
- * Gets an item from the cache
29
- * @param {string} key
30
- * @returns {Promise<any>}
31
- */
32
- export async function getItem (key) {
33
- const itemPath = await getItemPath(key);
34
- try {
35
-
36
- const { mtime } = await fs.promises.stat(itemPath);
37
-
38
- var date_time = new Date();
39
- let timeDifference = Math.abs((date_time.getTime() - mtime.getTime()) / 1000);
40
- if (timeDifference < maxAge) {
41
- console.log('Cache hit', key);
42
- const content = fs.readFileSync(itemPath).toString();
43
- return JSON.parse(content);
44
- }
45
- } catch{}
46
-
47
- console.warn('Cache miss', key);
48
- return null;
49
- }
50
-
51
- /**
52
- * Adds an item to the cache
53
- * @param {string} key
54
- * @param {any} value
55
- * @returns {Promise<void>}
56
- */
57
- export async function setItem (key, value) {
58
- const itemPath = await getItemPath(key);
59
- await fs.promises.writeFile(itemPath, JSON.stringify(value));
60
- }
package/lib/config.d.mts DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * @typedef { import("../types/Site").Site } Site
3
- */
4
- /**
5
- * Gets default configuration
6
- * @returns {Site}
7
- */
8
- export function getDefault(): Site;
9
- export type Site = import("../types/Site").Site;
package/lib/config.mjs DELETED
@@ -1,49 +0,0 @@
1
- /**
2
- * @typedef { import("../types/Site").Site } Site
3
- */
4
-
5
- /**
6
- * Gets default configuration
7
- * @returns {Site}
8
- */
9
- export function getDefault() {
10
- return {
11
- owner: '',
12
- url: '',
13
- feedUrl: '',
14
- title: '',
15
- description: '',
16
- themeColor: '#222255',
17
- subfolder: '',
18
- defaultLanguage: 'en',
19
- default: {
20
- lang: 'en',
21
- locale: 'en-US',
22
- dir: 'ltr'
23
- },
24
- search: {
25
- fallbackUrl: 'https://www.google.com/search',
26
- fallbackSite: 'q',
27
- fallbackQuery: 'q',
28
- },
29
- pageSize: 12,
30
- pageLinks: 3,
31
- rssLimit: 20,
32
- dateOptions: {
33
- weekday: 'long',
34
- year: 'numeric',
35
- month: 'long',
36
- day: 'numeric',
37
- },
38
- featureFlags: {
39
- codeBlocks: ['copy'],
40
- figures: ['enlarge'],
41
- youTubeLinks: ['embed'],
42
- },
43
- images: {
44
- contentSize: '(max-width: 860px) 100vw, 620px',
45
- listerSize: '(max-width: 860px) 90vw, 350px',
46
- authorSize: '50px',
47
- }
48
- };
49
- }
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
- }