Skip to content

Commit

Permalink
feat(bun): add algolia script & github action
Browse files Browse the repository at this point in the history
  • Loading branch information
e-krebs committed Apr 9, 2024
1 parent 45eac27 commit 27133c3
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
APPID=
APIKEY=
INDEXNAME=
25 changes: 25 additions & 0 deletions .github/workflows/algolia.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: algolia-index

on:
push:
branches:
- "main"

jobs:
algolia-index:
name: algolia-index
runs-on: ubuntu-latest
steps:
# ...
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1

# run any `bun` or `bunx` command
- run: bun install
- name: create .env file
run: |
touch .env
echo APPID=${{ secrets.APPID }} >> .env
echo APIKEY=${{ secrets.APIKEY }} >> .env
echo INDEXNAME=${{ secrets.INDEXNAME }} >> .env
- run: bun run algolia
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.env
.vscode
Binary file added bun.lockb
Binary file not shown.
7 changes: 7 additions & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module "bun" {
interface Env {
APPID: string;
APIKEY: string;
INDEXNAME: string;
}
}
16 changes: 16 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "knowledge-base",
"type": "module",
"scripts": {
"algolia": "bun scripts/algolia.ts"
},
"devDependencies": {
"@types/bun": "latest",
"@types/remarkable": "^2.0.8",
"algoliasearch": "^4.23.2",
"remarkable": "^2.0.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
15 changes: 15 additions & 0 deletions scripts/algolia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import algoliasearch from "algoliasearch";
import { list } from "./list";

const urls = await list();

const client = algoliasearch(Bun.env.APPID, Bun.env.APIKEY);

const index = client.initIndex(Bun.env.INDEXNAME);

const { objectIDs } = await index.replaceAllObjects(urls, {
safe: true,
autoGenerateObjectIDIfNotExist: true,
});

console.log(`got ${objectIDs.length} objectIDs for ${urls.length} items`);
38 changes: 38 additions & 0 deletions scripts/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { $, Glob } from "bun";
import { parse } from "./parse";
import type { Item } from "./types";

const clean = new RegExp(/(?:.\/)?(.*).md$/);

const fileNameToTag = (fileName: string): string[] =>
clean
.exec(fileName)![1]
.replaceAll("_", "")
.replaceAll(" ", "-")
.replaceAll("\\", "/")
.toLowerCase()
.split("/");

export const list = async (): Promise<Item[]> => {
const glob = new Glob("**/*.md");

const fileNames = (await Array.fromAsync(glob.scan("."))).filter(
(f) => !f.startsWith("node_modules") && !f.startsWith("README.md")
);

const urls = (
await Promise.all(
fileNames.map(
async (fileName) =>
await $`cat ${fileName}`
.text()
.then(parse)
.then((links) =>
links.map((link) => ({ ...link, tags: fileNameToTag(fileName) } as Item))
)
)
)
).flatMap((x) => x);

return urls;
};
32 changes: 32 additions & 0 deletions scripts/parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Remarkable } from "remarkable";
import type { Token, LinkOpenToken, BlockContentToken, TextToken } from "remarkable/lib";
import type { Link } from "./types";

const md = new Remarkable("default", {});

const isBlockContentToken = (token: Token): token is BlockContentToken => "children" in token;
const isLinkOpenToken = (token: Token): token is LinkOpenToken => token.type === "link_open";
const isTextToken = (token: Token): token is TextToken => token.type === "text";

export const parse = (text: string) => {
const links: Link[] = [];
const tokens = md.parse(text, {});

tokens.forEach((token) => {
if (token.type !== "inline" || !isBlockContentToken(token)) return;
if (!Array.isArray(token.children)) return;
token.children.forEach((child, index) => {
if (isLinkOpenToken(child)) {
const url = child.href;
let text: string = url;
const nextChild = token.children![index + 1];
if (isTextToken(nextChild) && nextChild.content) {
text = nextChild.content;
}
links.push({ url, text });
}
});
});

return links;
};
8 changes: 8 additions & 0 deletions scripts/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface Link {
url: string;
text: string;
}

export interface Item extends Link {
tags: string[];
}
27 changes: 27 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,

// Some stricter flags (disabled by default)
"noUnusedLocals": true,
"noUnusedParameters": true,
"noPropertyAccessFromIndexSignature": true
}
}

0 comments on commit 27133c3

Please sign in to comment.