diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..48f3b67 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +/biome.json diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..73c78f4 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,40 @@ +name: build +on: + push: + branches: + - main + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-build + cancel-in-progress: true +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/setup-buildx-action@v3 + - uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=sha,format=short,prefix=,priority=100 + type=raw,value=latest,priority=200 + - uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile + push: true + provenance: true + no-cache: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..8d35667 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,32 @@ +name: lint +on: + pull_request: + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-lint + cancel-in-progress: true +jobs: + actionlint: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-actionlint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + javascript: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + - run: bun install + - uses: biomejs/setup-biome@v2 + - run: biome ci . + typos: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: crate-ci/typos@master diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..a6d36b2 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,19 @@ +name: test +on: + push: + branches: + - main + pull_request: + workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-test + cancel-in-progress: true +jobs: + javascript: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v1 + - run: bun install + - run: bun test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..15c21e2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM oven/bun:latest +COPY . . +ENTRYPOINT ["bun", "./hello.ts"] diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..96e7381 --- /dev/null +++ b/biome.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", + "files": { + "ignore": ["node_modules"], + "ignoreUnknown": true + }, + "organizeImports": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "complexity": { + "noBannedTypes": "off" + } + } + } +} diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..48c408d Binary files /dev/null and b/bun.lockb differ diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..4773ab3 --- /dev/null +++ b/index.ts @@ -0,0 +1,34 @@ +import { Hono } from "hono"; +import { logger } from "hono/logger"; +import { createHeadlessEditor } from "@lexical/headless"; +import { JSDOM } from "jsdom"; +import { $generateNodesFromDOM } from "@lexical/html"; +import { $getRoot, $getSelection } from "lexical"; + +export const runtime = "edge"; + +const app = new Hono(); +app.use(logger()); + +app.get("/healthcheck", (c) => c.text("ok")); +app.post("/html_to_json", async (c) => { + const body = await c.req.text(); + + const editor = createHeadlessEditor({ + nodes: [], + onError: (e) => { + console.error(e); + }, + }); + await editor.update(() => { + const dom = new JSDOM(body); + const nodes = $generateNodesFromDOM(editor, dom.window.document); + $getRoot().select(); + const selection = $getSelection(); + selection?.insertNodes(nodes); + }); + + return c.json(editor.getEditorState().toJSON()); +}); + +export default app; diff --git a/package.json b/package.json new file mode 100644 index 0000000..209ce26 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "lexical-server", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@biomejs/biome": "1.6.1", + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@lexical/headless": "0.14.2", + "@lexical/html": "0.14.2", + "hono": "4.1.3", + "jsdom": "24.0.0", + "lexical": "0.14.2" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0fef23a --- /dev/null +++ b/tsconfig.json @@ -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": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}