Showing preview only (924K chars total). Download the full file or copy to clipboard to get everything.
Repository: xiaoxinghu/orgajs
Branch: main
Commit: 511bbeef8998
Files: 439
Total size: 820.0 KB
Directory structure:
gitextract_ms15wv5a/
├── .changeset/
│ ├── README.md
│ └── config.json
├── .editorconfig
├── .eslintignore
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── ci.yml
│ ├── release.yml
│ └── website.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── CHANGELOG.md
├── CONTRIBUTING.org
├── LICENSE.org
├── README.org
├── biome.json
├── docs/
│ ├── .gitignore
│ ├── _components.tsx
│ ├── _layout.tsx
│ ├── _snippets/
│ │ └── hey.org
│ ├── advanced/
│ │ ├── _layout.tsx
│ │ ├── api.org
│ │ ├── ast.org
│ │ ├── index.org
│ │ └── latex.org
│ ├── contribute.org
│ ├── guides/
│ │ ├── _layout.tsx
│ │ ├── astro.org
│ │ ├── gatsby.org
│ │ ├── index.org
│ │ ├── next.org
│ │ ├── orga-build.org
│ │ └── webpack.org
│ ├── index.org
│ ├── playground.tsx
│ ├── style.css
│ └── tsconfig.json
├── examples/
│ ├── README.org
│ ├── build/
│ │ ├── index.org
│ │ ├── more.org
│ │ ├── package.json
│ │ └── test-content.tsx
│ ├── editor/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── content.org
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── main.ts
│ │ │ └── style.css
│ │ └── tsconfig.json
│ ├── getting-started/
│ │ ├── .gitignore
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── index.js
│ │ └── package.json
│ └── webpack/
│ ├── .babelrc
│ ├── CHANGELOG.md
│ ├── README.org
│ ├── package.json
│ ├── public/
│ │ └── index.html
│ ├── src/
│ │ ├── box.js
│ │ ├── hello.org
│ │ └── index.js
│ └── webpack.config.mjs
├── orga.config.js
├── package.json
├── packages/
│ ├── astro/
│ │ └── README.org
│ ├── codemirror-lang/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── editor/
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── actions/
│ │ │ │ ├── fold.js
│ │ │ │ ├── shift.js
│ │ │ │ ├── todo.js
│ │ │ │ └── utils.js
│ │ │ ├── editor.js
│ │ │ ├── extensions/
│ │ │ │ └── cleanup.js
│ │ │ ├── settings.js
│ │ │ ├── setup.js
│ │ │ └── theme.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── esbuild/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ └── package.json
│ ├── lezer/
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── context.js
│ │ │ ├── fragments.js
│ │ │ ├── handlers.js
│ │ │ ├── index.js
│ │ │ ├── nodes.js
│ │ │ ├── oast-to-lezer.js
│ │ │ ├── tree.js
│ │ │ └── types.ts
│ │ ├── package.json
│ │ ├── tests/
│ │ │ ├── compare-tree.js
│ │ │ └── incremental.test.js
│ │ └── tsconfig.json
│ ├── loader/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── index.cjs
│ │ ├── index.d.ts
│ │ ├── lib/
│ │ │ └── index.js
│ │ ├── package.json
│ │ └── tests/
│ │ ├── compiler.js
│ │ ├── example.md
│ │ ├── fixture.org
│ │ └── loader.test.js
│ ├── metadata/
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── index.js
│ │ ├── lib/
│ │ │ └── index.js
│ │ ├── package.json
│ │ ├── tests/
│ │ │ └── test.js
│ │ └── tsconfig.json
│ ├── next/
│ │ └── README.org
│ ├── node-loader/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ └── package.json
│ ├── oast-to-hast/
│ │ ├── .projectile
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── handlers/
│ │ │ │ ├── block.js
│ │ │ │ ├── document.js
│ │ │ │ ├── footnote.js
│ │ │ │ ├── headline.js
│ │ │ │ ├── hr.js
│ │ │ │ ├── html.js
│ │ │ │ ├── index.js
│ │ │ │ ├── keyword.js
│ │ │ │ ├── latex.js
│ │ │ │ ├── link.js
│ │ │ │ ├── list.js
│ │ │ │ ├── newline.js
│ │ │ │ ├── paragraph.js
│ │ │ │ ├── section.js
│ │ │ │ ├── table.js
│ │ │ │ └── text.js
│ │ │ ├── index.js
│ │ │ └── state.js
│ │ ├── package.json
│ │ ├── tests/
│ │ │ ├── block.js
│ │ │ ├── classname.js
│ │ │ ├── heading.js
│ │ │ ├── list.js
│ │ │ └── paragraph.js
│ │ └── tsconfig.json
│ ├── oast-to-prose/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── handlers/
│ │ │ │ ├── block.js
│ │ │ │ ├── headline.js
│ │ │ │ ├── index.js
│ │ │ │ ├── link.js
│ │ │ │ ├── newline.js
│ │ │ │ ├── paragraph.js
│ │ │ │ ├── section.js
│ │ │ │ ├── stars.js
│ │ │ │ ├── tags.js
│ │ │ │ ├── text.js
│ │ │ │ └── todo.js
│ │ │ ├── index.js
│ │ │ ├── schema.js
│ │ │ └── state.js
│ │ ├── package.json
│ │ ├── tests/
│ │ │ └── text.js
│ │ └── tsconfig.json
│ ├── orga/
│ │ ├── .projectile
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── README.org
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── __tests__/
│ │ │ │ ├── block/
│ │ │ │ │ ├── affiliated keyword.json
│ │ │ │ │ ├── affiliated keyword.org
│ │ │ │ │ ├── export.json
│ │ │ │ │ ├── export.org
│ │ │ │ │ ├── missing begin.json
│ │ │ │ │ ├── missing begin.org
│ │ │ │ │ ├── missing end.json
│ │ │ │ │ ├── missing end.org
│ │ │ │ │ ├── standard.json
│ │ │ │ │ └── standard.org
│ │ │ │ ├── footnote/
│ │ │ │ │ ├── multiline.json
│ │ │ │ │ ├── multiline.org
│ │ │ │ │ ├── standard.json
│ │ │ │ │ ├── standard.org
│ │ │ │ │ ├── stopped by empty lines.json
│ │ │ │ │ ├── stopped by empty lines.org
│ │ │ │ │ ├── stopped by footnote.json
│ │ │ │ │ ├── stopped by footnote.org
│ │ │ │ │ ├── stopped by headline.json
│ │ │ │ │ ├── stopped by headline.org
│ │ │ │ │ ├── with block.json
│ │ │ │ │ └── with block.org
│ │ │ │ ├── headline/
│ │ │ │ │ ├── broken drawer.json
│ │ │ │ │ ├── broken drawer.org
│ │ │ │ │ ├── drawers.json
│ │ │ │ │ ├── drawers.org
│ │ │ │ │ ├── keyword.json
│ │ │ │ │ ├── keyword.org
│ │ │ │ │ ├── nested.json
│ │ │ │ │ ├── nested.org
│ │ │ │ │ ├── planning.json
│ │ │ │ │ ├── planning.org
│ │ │ │ │ ├── with tags.json
│ │ │ │ │ └── with tags.org
│ │ │ │ ├── hr/
│ │ │ │ │ ├── standard.json
│ │ │ │ │ └── standard.org
│ │ │ │ ├── index.test.ts
│ │ │ │ ├── keyword/
│ │ │ │ │ ├── multiple todo.json
│ │ │ │ │ ├── multiple todo.org
│ │ │ │ │ ├── other.json
│ │ │ │ │ ├── other.org
│ │ │ │ │ ├── todo.json
│ │ │ │ │ └── todo.org
│ │ │ │ ├── latex/
│ │ │ │ │ ├── does not match.json
│ │ │ │ │ ├── does not match.org
│ │ │ │ │ ├── latex block.json
│ │ │ │ │ ├── latex block.org
│ │ │ │ │ ├── missing begin.json
│ │ │ │ │ ├── missing begin.org
│ │ │ │ │ ├── missing end.json
│ │ │ │ │ └── missing end.org
│ │ │ │ ├── list/
│ │ │ │ │ ├── broken by empty line.json
│ │ │ │ │ ├── broken by empty line.org
│ │ │ │ │ ├── descriptive.json
│ │ │ │ │ ├── descriptive.org
│ │ │ │ │ ├── multiline.json
│ │ │ │ │ ├── multiline.org
│ │ │ │ │ ├── nested.json
│ │ │ │ │ ├── nested.org
│ │ │ │ │ ├── ordered.json
│ │ │ │ │ ├── ordered.org
│ │ │ │ │ ├── unordered.json
│ │ │ │ │ └── unordered.org
│ │ │ │ ├── paragraph/
│ │ │ │ │ ├── anonymous footnote.json
│ │ │ │ │ ├── anonymous footnote.org
│ │ │ │ │ ├── footnote reference at the end.json
│ │ │ │ │ ├── footnote reference at the end.org
│ │ │ │ │ ├── footnote refernece in the middle.json
│ │ │ │ │ ├── footnote refernece in the middle.org
│ │ │ │ │ ├── footnote without body.json
│ │ │ │ │ ├── footnote without body.org
│ │ │ │ │ ├── inline footnote with style.json
│ │ │ │ │ ├── inline footnote with style.org
│ │ │ │ │ ├── inline footnote.json
│ │ │ │ │ ├── inline footnote.org
│ │ │ │ │ ├── inline math.json
│ │ │ │ │ ├── inline math.org
│ │ │ │ │ ├── link with style.json
│ │ │ │ │ ├── link with style.org
│ │ │ │ │ ├── link.json
│ │ │ │ │ ├── link.org
│ │ │ │ │ ├── nested footnote.json
│ │ │ │ │ ├── nested footnote.org
│ │ │ │ │ ├── styled text.json
│ │ │ │ │ └── styled text.org
│ │ │ │ └── table/
│ │ │ │ ├── standard.json
│ │ │ │ ├── standard.org
│ │ │ │ ├── with inline styles.json
│ │ │ │ └── with inline styles.org
│ │ │ ├── index.ts
│ │ │ ├── nodes.ts
│ │ │ ├── options.ts
│ │ │ ├── parse/
│ │ │ │ ├── _parseSymbols.ts
│ │ │ │ ├── _primitive.ts
│ │ │ │ ├── _utils.ts
│ │ │ │ ├── block.ts
│ │ │ │ ├── context.ts
│ │ │ │ ├── drawer.ts
│ │ │ │ ├── footnote.ts
│ │ │ │ ├── headline.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── keyword.ts
│ │ │ │ ├── latex.ts
│ │ │ │ ├── list.ts
│ │ │ │ ├── paragraph.ts
│ │ │ │ ├── phrasing.ts
│ │ │ │ ├── planning.ts
│ │ │ │ ├── section.ts
│ │ │ │ └── table.ts
│ │ │ ├── position.ts
│ │ │ ├── timestamp.test.ts
│ │ │ ├── timestamp.ts
│ │ │ ├── todo.test.ts
│ │ │ ├── todo.ts
│ │ │ ├── tokenize/
│ │ │ │ ├── __tests__/
│ │ │ │ │ ├── debug.ts
│ │ │ │ │ └── tok.ts
│ │ │ │ ├── blank.test.ts
│ │ │ │ ├── block.test.ts
│ │ │ │ ├── block.ts
│ │ │ │ ├── comment.test.ts
│ │ │ │ ├── comment.ts
│ │ │ │ ├── drawer.test.ts
│ │ │ │ ├── drawer.ts
│ │ │ │ ├── empty.ts
│ │ │ │ ├── footnote.test.ts
│ │ │ │ ├── footnote.ts
│ │ │ │ ├── headline.test.ts
│ │ │ │ ├── headline.ts
│ │ │ │ ├── hr.test.ts
│ │ │ │ ├── hr.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── inline/
│ │ │ │ │ ├── footnote.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── link.ts
│ │ │ │ │ ├── math.ts
│ │ │ │ │ └── text.ts
│ │ │ │ ├── inline.test.ts
│ │ │ │ ├── keyword.ts
│ │ │ │ ├── keywords.test.ts
│ │ │ │ ├── latex.ts
│ │ │ │ ├── list.test.ts
│ │ │ │ ├── list.ts
│ │ │ │ ├── partial.test.ts
│ │ │ │ ├── planning.test.ts
│ │ │ │ ├── planning.ts
│ │ │ │ ├── table.test.ts
│ │ │ │ └── table.ts
│ │ │ ├── types.ts
│ │ │ ├── uri.test.ts
│ │ │ ├── uri.ts
│ │ │ └── utils.ts
│ │ └── tsconfig.json
│ ├── orga-build/
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── cli.js
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── __tests__/
│ │ │ │ └── build.test.js
│ │ │ ├── app.jsx
│ │ │ ├── build.js
│ │ │ ├── components.js
│ │ │ ├── config.js
│ │ │ ├── content.d.ts
│ │ │ ├── csr.jsx
│ │ │ ├── endpoint.js
│ │ │ ├── files.js
│ │ │ ├── fs.js
│ │ │ ├── index.html
│ │ │ ├── orga.js
│ │ │ ├── plugin.js
│ │ │ ├── serve.js
│ │ │ ├── ssr.jsx
│ │ │ ├── util.js
│ │ │ ├── vite.js
│ │ │ └── watch.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── orgx/
│ │ ├── CHANGELOG.md
│ │ ├── README.org
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── compile.js
│ │ │ ├── core.js
│ │ │ ├── evaluate.js
│ │ │ ├── plugin/
│ │ │ │ ├── recma-build-jsx-transform.js
│ │ │ │ ├── recma-document.js
│ │ │ │ ├── recma-jsx-rewrite.js
│ │ │ │ └── rehype-recma.js
│ │ │ ├── run.js
│ │ │ ├── types.ts
│ │ │ └── util/
│ │ │ ├── estree-util-create.js
│ │ │ ├── estree-util-declaration-to-expression.js
│ │ │ ├── estree-util-is-declaration.js
│ │ │ ├── estree-util-specifiers-to-declarations.js
│ │ │ ├── estree-util-to-binary-addition.js
│ │ │ ├── estree-util-to-id-or-member-expression.js
│ │ │ ├── is-org-content.js
│ │ │ ├── render-error.js
│ │ │ ├── resolve-evaluate-options.js
│ │ │ └── resolve-file-and-options.js
│ │ ├── package.json
│ │ ├── tests/
│ │ │ ├── compile.test.js
│ │ │ └── evaluate.test.js
│ │ └── tsconfig.json
│ ├── react/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── tests/
│ │ │ ├── remove-export-keywords.js
│ │ │ └── test.tsx
│ │ └── tsconfig.json
│ ├── react-cm/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ └── package.json
│ ├── react-editor/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── reorg/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── README.org
│ │ ├── index.js
│ │ └── package.json
│ ├── reorg-parse/
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── README.org
│ │ ├── index.d.ts
│ │ ├── index.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── reorg-prose/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ ├── lib/
│ │ │ └── index.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── reorg-rehype/
│ │ ├── .projectile
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE.org
│ │ ├── index.js
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── rollup/
│ │ ├── CHANGELOG.md
│ │ ├── index.js
│ │ ├── package.json
│ │ ├── test.js
│ │ └── tsconfig.json
│ └── text-kit/
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── index.js
│ ├── lib/
│ │ ├── core.js
│ │ ├── reader.js
│ │ └── utils/
│ │ ├── index.js
│ │ ├── lines.js
│ │ └── substring.js
│ ├── package.json
│ ├── tests/
│ │ ├── core.js
│ │ └── lines.js
│ └── tsconfig.json
├── pnpm-workspace.yaml
├── shell.nix
├── tsconfig.base.json
├── tsconfig.esm.json
├── tsconfig.json
└── tsconfig.packages.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .changeset/README.md
================================================
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
================================================
FILE: .changeset/config.json
================================================
{
"$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = tab
[*.{yml,yaml}]
indent_style = space
indent_size = 2
[vcbuild.bat]
end_of_line = crlf
[Makefile]
indent_style = tab
indent_size = 8
[{deps}/**]
indent_style = ignore
indent_size = ignore
end_of_line = ignore
trim_trailing_whitespace = ignore
charset = ignore
[{test/fixtures,deps,tools/node_modules,tools/gyp,tools/icu,tools/msvs}/**]
insert_final_newline = false
================================================
FILE: .eslintignore
================================================
node_modules
**/dist/**
**/__tests__/**/*.json
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: ['xiaoxinghu']
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches:
- main
paths-ignore:
- 'docs/**'
- '**/README.org'
- '**/README.md'
pull_request:
paths-ignore:
- 'docs/**'
- '**/README.org'
- '**/README.md'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v4
with:
version: 10
cache: 'pnpm'
- name: install dependencies
run: pnpm install
- name: build packages
run: pnpm build
- name: run unit tests
run: pnpm test
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
branches:
- main
env:
CI: true
permissions: {}
jobs:
release:
name: Release
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC trusted publishing
contents: write # Required for changesets to commit
pull-requests: write # Required for changesets to create PRs
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- name: Setup Node.js 24
uses: actions/setup-node@v4
with:
node-version: 24
- uses: pnpm/action-setup@v4
with:
version: 10
- name: install dependencies
run: pnpm install --no-frozen-lockfile
- name: Create Release Pull Request or Publish to npm
uses: changesets/action@v1
with:
version: pnpm ci:version
commit: 'chore: update versions'
title: 'chore: update versions'
publish: pnpm ci:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_CONFIG_PROVENANCE: true
================================================
FILE: .github/workflows/website.yml
================================================
name: Deploy to GitHub Pages
on:
# Trigger the workflow every time you push to the `main` branch
# Using a different branch name? Replace `main` with your branch’s name
push:
branches: [main]
# Allows you to run this workflow manually from the Actions tab on GitHub.
workflow_dispatch:
# Allow this job to clone the repo and create a page deployment
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout your repository using git
uses: actions/checkout@v3
- name: Setup PNPM
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Install
run: |
pnpm install
pnpm run build
pnpm run docs
- name: Upload Page Artifact
uses: actions/upload-pages-artifact@v3
with:
path: '.out/'
deploy:
needs: build
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
================================================
FILE: .gitignore
================================================
# macOS
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
.npmrc
# private
.archive
/.idea
.vscode
# build artifacts
dist
*.tsbuildinfo
*.d.ts
*.d.ts.map
!packages/reorg-parse/index.d.ts
!packages/loader/index.d.ts
!packages/orga-build/lib/content.d.ts
.meta.json
.orga-build
.turbo
.aider*
.out
.direnv
.website
deprecated
================================================
FILE: .prettierignore
================================================
.archive
.cache
node_modules
.next
public
lib
**/dist/**
.yarn/*
**/__tests__/**/*.json
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"semi": false,
"trailingComma": "none",
"bracketSpacing": true,
"useTabs": true
}
================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.6.0](https://github.com/orgapp/orgajs/compare/v2.5.0...v2.6.0) (2021-08-28)
- feat!: major version bump ([998c0f3](https://github.com/orgapp/orgajs/commit/998c0f30a7c8f9af27243b3cb48b650708cdc4b3))
### Bug Fixes
- fix examples ([bdcd265](https://github.com/orgapp/orgajs/commit/bdcd2655502a73800e8915ba09fd78452dff503f))
- fix headline regex issue ([a36b75d](https://github.com/orgapp/orgajs/commit/a36b75d87da125f56edf7da1ddaf23771040ce1b))
- fix headline tags parsing issue [#126](https://github.com/orgapp/orgajs/issues/126) ([71d7f82](https://github.com/orgapp/orgajs/commit/71d7f8277708fc72d3b5be01ed0f72233bf7057b))
- fix phrasing content in headline ([31ca41c](https://github.com/orgapp/orgajs/commit/31ca41cb3b9b65a19dbc71a906f86ee4d725ad8f))
- fix publish script ([7fc1bdf](https://github.com/orgapp/orgajs/commit/7fc1bdfc6880e825cd10d99d108da9685f58638c))
- fix publish script ([f175e5b](https://github.com/orgapp/orgajs/commit/f175e5bb3cad0ce31cc118c1c675fe30b4065fc9))
- inline markup check post ([d3d31c6](https://github.com/orgapp/orgajs/commit/d3d31c622dde2a2d469ac41884f2320497f811c6))
- lock unified & @types/unist version ([dc72217](https://github.com/orgapp/orgajs/commit/dc72217f0cfcd778436d704021116c8479f8ee1e))
- remove prepublish step individually ([a75a6a9](https://github.com/orgapp/orgajs/commit/a75a6a9606421b66b6ef69b28e3fcb03a5ee282a))
- **website:** better code block ([9d5b3a2](https://github.com/orgapp/orgajs/commit/9d5b3a2d554672d22523727e89b2b5c60dc6233d))
- update yarn.lock file ([bf0e695](https://github.com/orgapp/orgajs/commit/bf0e6954246f7ed78a014601aca756cd47fa4fec))
### Features
- add jsx support ([0d22499](https://github.com/orgapp/orgajs/commit/0d224990b412e064ebf6816608eea6766f93d60c))
- better code block in website ([3efe4cd](https://github.com/orgapp/orgajs/commit/3efe4cd96a63623e2f70028bd66346960ec90bec))
- **gatsby:** process images ([76fdade](https://github.com/orgapp/orgajs/commit/76fdaded0d87a3bc2e188392b520f62ad789598c))
### BREAKING CHANGES
- due to my own lack of knowledge about how conventional commits works in
lerna, I published the breaking change as a minor version 2.5.0. Here I am
trying to get it right. It might not work... Sorry for the inconvenience.
## 2.4.9 (2021-07-13)
# [2.5.0](https://github.com/orgapp/orgajs/compare/v2.4.9...v2.5.0) (2021-08-27)
### Bug Fixes
- fix examples ([bdcd265](https://github.com/orgapp/orgajs/commit/bdcd2655502a73800e8915ba09fd78452dff503f))
- fix headline regex issue ([a36b75d](https://github.com/orgapp/orgajs/commit/a36b75d87da125f56edf7da1ddaf23771040ce1b))
- fix phrasing content in headline ([31ca41c](https://github.com/orgapp/orgajs/commit/31ca41cb3b9b65a19dbc71a906f86ee4d725ad8f))
- fix publish script ([7fc1bdf](https://github.com/orgapp/orgajs/commit/7fc1bdfc6880e825cd10d99d108da9685f58638c))
- fix publish script ([f175e5b](https://github.com/orgapp/orgajs/commit/f175e5bb3cad0ce31cc118c1c675fe30b4065fc9))
- inline markup check post ([d3d31c6](https://github.com/orgapp/orgajs/commit/d3d31c622dde2a2d469ac41884f2320497f811c6))
- **website:** better code block ([9d5b3a2](https://github.com/orgapp/orgajs/commit/9d5b3a2d554672d22523727e89b2b5c60dc6233d))
- lock unified & @types/unist version ([dc72217](https://github.com/orgapp/orgajs/commit/dc72217f0cfcd778436d704021116c8479f8ee1e))
- update yarn.lock file ([bf0e695](https://github.com/orgapp/orgajs/commit/bf0e6954246f7ed78a014601aca756cd47fa4fec))
### Features
- add jsx support ([0d22499](https://github.com/orgapp/orgajs/commit/0d224990b412e064ebf6816608eea6766f93d60c))
- better code block in website ([3efe4cd](https://github.com/orgapp/orgajs/commit/3efe4cd96a63623e2f70028bd66346960ec90bec))
- **gatsby:** process images ([76fdade](https://github.com/orgapp/orgajs/commit/76fdaded0d87a3bc2e188392b520f62ad789598c))
- **gatsby-plugin-orga:** better code block ([e6d7d20](https://github.com/orgapp/orgajs/commit/e6d7d20f63fa1871d8f53b0534b50ac6d7d99fc9))
## [2.4.9](https://github.com/orgapp/orgajs/compare/v2.4.8...v2.4.9) (2021-07-13)
**Note:** Version bump only for package orgajs
## [2.4.8](https://github.com/orgapp/orgajs/compare/v2.4.7...v2.4.8) (2021-04-26)
## 2.4.6 (2021-04-25)
**Note:** Version bump only for package orgajs
## [2.4.7](https://github.com/orgapp/orgajs/compare/v2.4.6...v2.4.7) (2021-04-26)
**Note:** Version bump only for package orgajs
================================================
FILE: CONTRIBUTING.org
================================================
#+title: How to contribute to orgajs
Hi 👋 🦄.
* Getting Started
Make sure you have latest yarn installed locally.
To get started with the repo, after cloning the repo.
#+begin_src sh
yarn install
#+end_src
* Ways to Contribute
** Improve documentation
Documentations resides in the [[file:docs][docs]] folder. The content will be published to the [[https://orga.js.org][official website]]. As a user of the library and tools, you are the best person for writing them. Any help with documentation would be appreciated greatly.
** Write code and tests
It's often a good idea to create an issue to discuss the bug or feature before creating a pull request to prevent from doing unnecessary work.
** Discussion
Have some cool ideas? Let's talk about it in the [[https://github.com/orgapp/orgajs/discussions][Discussions]] tab.
* Commit Messages
We are following the [[https://www.conventionalcommits.org/en/v1.0.0/][conventional commits]] standards, an example would be:
#+begin_example
feat(parser): add new syntax
this is a body
#+end_example
The above commit message would result in a minor version bump when it is merged into master for release. Take a look at the spec for more details. This is for extracting changelog and streamline version bump automatically.
* Run Unit Tests
#+begin_src sh
yarn build # always build before running tests
yarn test
#+end_src
* Submitting Pull Requests
Please submit pull requests against =develop= branch. =master= is for releasing.
* Releasing
All packages in orgajs is automatically released once merged into master. That's why the commit message is extra important. Especially when there are =BRAKING CHANGE=.
================================================
FILE: LICENSE.org
================================================
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.org
================================================
#+title: Orga
#+subtitle: org-mode < JavaScript
* What Is It
=Orga= is a flexible org-mode syntax parser. It parses org content into AST ([[https://en.wikipedia.org/wiki/Abstract_syntax_tree][Abstract Syntax Tree 🌲]]). And it's written in JavaScript.
* Why
org-mode is simply a superior format than other more popular ones, but it's mostly trapped inside of emacs. It's so good that it was the #1 reason to learn and use emacs for a lot of people (me included). But it's too good to not share with the rest of the world. If it can run in JavaScript, it can run on anything.
* Compatible Eco-systems
It integrates natively with popular tools.
** [[https://unifiedjs.com][Unified]]
#+BEGIN_QUOTE
☔️ interface for parsing, inspecting, transforming, and serializing content through syntax trees
#+END_QUOTE
The =orga= parser is completely compatible with unified. Which means you get to take advantage of the works of others put into the pipeline. [[https://github.com/retextjs/retext][linting for natural language]], [[https://alexjs.com][correct your writing]], [[https://wooorm.com/write-music/][write music]]? etc. Here is [[https://github.com/orgapp/orgajs/tree/develop/examples/getting-started][an example]].
** [[https://webpack.js.org][Webpack]]
=@orgajs/loader= is a webpack loader that made orga native citizen of webpack ecosystem. Coupled with plugins, it works smoothly. Take a look at [[https://github.com/orgapp/orgajs/tree/develop/examples/webpack][the example project]].
** [[https://reactjs.org/][React]]
#+begin_quote
A JavaScript library for building user interfaces
#+end_quote
You can render react components directly in your org file. Something like this:
#+begin_src org
,* Hello World
Let's render *the box*.
,#+begin_export jsx
<div style={{
backgroundColor: 'gold',
padding: '1em',
border: '1px solid black',
boxShadow: '5px 5px'
}}>I am a box with shadow</div>
,#+end_export
#+end_src
[[https://orga.js.org/playground/?text=*%20Hello%20World%0A%0ALet's%20render%20*the%20box*.%0A%0A%23%2Bbegin_export%20jsx%0A%3Cdiv%20style%3D%7B%7B%0A%20%20backgroundColor%3A%20'gold'%2C%20%0A%20%20padding%3A%20'1em'%2C%0A%20%20border%3A%20'1px%20solid%20black'%2C%0A%20%20boxShadow%3A%20'5px%205px'%0A%7D%7D%3EI%20am%20a%20box%20with%20shadow%3C%2Fdiv%3E%0A%23%2Bend_export%0A][Try it our yourself in the playground]].
** [[https://vitejs.dev][Vite]]
#+begin_quote
Next generation frontend tooling
#+end_quote
=@orgajs/rollup= is a plugin compatible with both Rollup and Vite. It lets you import =.org= files directly in your project.
- Package: =@orgajs/rollup=
** [[https://astro.build][Astro]]
#+begin_quote
The web framework for content-driven websites
#+end_quote
Astro integration is maintained in a standalone repository.
- [[https://github.com/orgapp/orga-astro][orga-astro repository]]
- Package: =@orgajs/astro=
** [[https://nextjs.org][Nextjs]]
#+begin_quote
The React Framework
#+end_quote
Next.js integration is maintained in a standalone repository.
- [[https://github.com/orgapp/orga-next][orga-next repository]]
- Package: =@orgajs/next=
- Guide: [[https://orga.js.org/guides/next][Next.js integration guide]]
* Examples
Take a look at the [[https://github.com/orgapp/orgajs/tree/main/examples][collection of examples]] to quickly get started.
* Contribute
See the [[file:CONTRIBUTING.org][contributing file]] for ways to get started.
================================================
FILE: biome.json
================================================
{
"$schema": "https://biomejs.dev/schemas/2.4.4/schema.json",
"files": {
"includes": ["packages/**", "!packages/**/__tests__/**/*.json"]
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"formatter": {
"indentStyle": "tab",
"bracketSpacing": true
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "asNeeded",
"trailingCommas": "none"
}
},
"linter": {
"rules": {
"complexity": {
"useArrowFunction": "off"
}
}
}
}
================================================
FILE: docs/.gitignore
================================================
out
================================================
FILE: docs/_components.tsx
================================================
import { Editor } from '@orgajs/react-editor'
import { ReactCodeMirror } from '@orgajs/react-cm'
import { tags as t } from '@lezer/highlight'
import { EditorView } from '@codemirror/view'
import {
HighlightStyle,
defaultHighlightStyle,
syntaxHighlighting,
foldGutter
} from '@codemirror/language'
import { javascript } from '@codemirror/lang-javascript'
export function Notice({
title,
children
}: {
title?: string
children: React.ReactNode
}) {
return (
<div role="alert" className="alert">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
className="stroke-info h-6 w-6 shrink-0"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path>
</svg>
<span>{children}</span>
</div>
)
}
const nord0 = '#2E3440',
nord1 = '#3B4252',
nord2 = '#434C5E',
nord3 = '#4C566A',
nord4 = '#D8DEE9',
nord5 = '#E5E9F0',
nord6 = '#ECEFF4',
nord7 = '#8FBCBB',
nord8 = '#88C0D0',
nord9 = '#81A1C1',
nord10 = '#5E81AC',
nord11 = '#BF616A',
nord12 = '#D08770',
nord13 = '#EBCB8B',
nord14 = '#A3BE8C',
nord15 = '#B48EAD'
const nordTheme = EditorView.theme(
{
'&': {
color: nord4,
backgroundColor: nord0
},
'.cm-content': {
caretColor: nord4
},
'.cm-cursor, .cm-dropCursor': { borderLeftColor: nord4 },
'&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection':
{
backgroundColor: nord2
},
'.cm-panels': { backgroundColor: nord1, color: nord5 },
'.cm-panels.cm-panels-top': { borderBottom: `2px solid ${nord3}` },
'.cm-panels.cm-panels-bottom': { borderTop: `2px solid ${nord3}` },
'.cm-searchMatch': {
backgroundColor: nord13,
outline: `1px solid ${nord3}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: nord12
},
'.cm-activeLine': { backgroundColor: nord1 },
'.cm-activeLineGutter': { backgroundColor: nord2 },
'.cm-selectionMatch': { backgroundColor: nord3 },
'.cm-matchingBracket, .cm-nonmatchingBracket': {
backgroundColor: nord8,
outline: `none`
},
'.cm-gutters': {
backgroundColor: nord0,
color: nord3,
border: 'none'
},
'.cm-lineNumbers .cm-gutterElement': {
padding: '0 3px 0 5px'
},
'.cm-tooltip': {
border: `1px solid ${nord3}`,
backgroundColor: nord2
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
backgroundColor: nord3,
color: nord6
}
}
},
{ dark: true }
)
const nordHighlightStyle = HighlightStyle.define([
{ tag: t.keyword, color: nord9 },
{
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
color: nord4
},
{ tag: [t.function(t.variableName), t.labelName], color: nord8 },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: nord7 },
{ tag: [t.definition(t.name), t.separator], color: nord4 },
{ tag: [t.className], color: nord7 },
{
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
color: nord15
},
{ tag: [t.typeName], color: nord7 },
{ tag: [t.operator, t.operatorKeyword], color: nord9 },
{ tag: [t.url, t.escape, t.regexp, t.link], color: nord13 },
{ tag: [t.meta, t.comment], color: nord3, fontStyle: 'italic' },
{ tag: [t.strong], fontWeight: 'bold' },
{ tag: [t.emphasis], fontStyle: 'italic' },
{ tag: [t.strikethrough], textDecoration: 'line-through' },
{ tag: [t.string], color: nord14 },
{ tag: [t.invalid], color: nord11 }
])
const nord = [nordTheme, syntaxHighlighting(nordHighlightStyle)]
export function JSEditor({
className,
children
}: {
className?: string
children: string
}) {
return (
<div className={className}>
<ReactCodeMirror
extensions={[
foldGutter(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
javascript(),
EditorView.editable.of(false),
nord
]}
content={children}
/>
</div>
)
}
export function OrgEditor({ className = '', content, onChange }) {
return (
<Editor
className={className}
content={content}
onChange={onChange}
extensions={[nord]}
/>
)
}
================================================
FILE: docs/_layout.tsx
================================================
import { ReactNode } from 'react'
import { Link } from 'orga-build/components'
import type { SVGProps } from 'react'
const GitHub = (props: SVGProps<SVGSVGElement>) => (
<svg
width="1em"
height="1em"
viewBox="0 0 1024 1024"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 0C3.58 0 0 3.58 0 8C0 11.54 2.29 14.53 5.47 15.59C5.87 15.66 6.02 15.42 6.02 15.21C6.02 15.02 6.01 14.39 6.01 13.72C4 14.09 3.48 13.23 3.32 12.78C3.23 12.55 2.84 11.84 2.5 11.65C2.22 11.5 1.82 11.13 2.49 11.12C3.12 11.11 3.57 11.7 3.72 11.94C4.44 13.15 5.59 12.81 6.05 12.6C6.12 12.08 6.33 11.73 6.56 11.53C4.78 11.33 2.92 10.64 2.92 7.58C2.92 6.71 3.23 5.99 3.74 5.43C3.66 5.23 3.38 4.41 3.82 3.31C3.82 3.31 4.49 3.1 6.02 4.13C6.66 3.95 7.34 3.86 8.02 3.86C8.7 3.86 9.38 3.95 10.02 4.13C11.55 3.09 12.22 3.31 12.22 3.31C12.66 4.41 12.38 5.23 12.3 5.43C12.81 5.99 13.12 6.7 13.12 7.58C13.12 10.65 11.25 11.33 9.47 11.53C9.76 11.78 10.01 12.26 10.01 13.01C10.01 14.08 10 14.94 10 15.21C10 15.42 10.15 15.67 10.55 15.59C13.71 14.53 16 11.53 16 8C16 3.58 12.42 0 8 0Z"
transform="scale(64)"
fill="#1B1F23"
/>
</svg>
)
interface LayoutProps {
title: string
children: ReactNode
}
const navItems = [
{ name: 'Orga', href: '/' },
{ name: 'Documents', href: '/guides' },
{ name: 'Playground', href: '/playground' }
]
export default function Layout({ children }: LayoutProps) {
return (
<>
<nav className="navbar bg-base-200 shadow-sm">
<ol className="flex flex-1 gap-4">
{navItems.map((item) => (
<li key={item.name}>
<Link href={item.href} className="btn btn-ghost">
{item.name}
</Link>
</li>
))}
</ol>
<div className="navbar-end">
<a
className="btn btn-ghost btn-circle"
target="_blank"
href="https://github.com/orgapp/orgajs"
>
<div className="indicator">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" />
</svg>
</div>
</a>
</div>
</nav>
<main className="flex-grow flex-row overflow-hidden">{children}</main>
<footer className="footer sm:footer-horizontal footer-center bg-base-200 text-base-content p-4">
<aside>
<p>Copyright © {new Date().getFullYear()} - All right reserved</p>
</aside>
</footer>
{/* Client-side JS is now added by build process */}
</>
)
}
type Page = {
slug: string
title: string
position: number
type: string
}
function findParentSlug(slug: string, pages: Page[]): string | null {
const parts = slug.split('/').filter(Boolean)
while (parts.length > 0) {
parts.pop()
const parentSlug = '/' + parts.join('/')
if (pages.some((p) => p.slug === parentSlug)) return parentSlug
}
return null
}
function renderMenu(path: string, pages: Page[]) {
const children = pages
.filter(
(p) => findParentSlug(p.slug, pages) === path && p.type === 'document'
)
.sort((a, b) => (Number(a.position) || 0) - (Number(b.position) || 0))
if (children.length === 0) return null
return (
<ul>
{children.map((child) => (
<li key={child.slug}>
<Link href={child.slug}>{child.title}</Link>
{renderMenu(child.slug, pages)}
</li>
))}
</ul>
)
}
export function DocumentLayout({ title, pages = [], children }) {
return (
<div className="flex h-full w-full">
<ul className="menu bg-base-300 w-56">{renderMenu('/', pages)}</ul>
<Content>
<h1>{title}</h1>
{children}
</Content>
</div>
)
}
function Content({ children }: { children: ReactNode }) {
return (
<div className="overflow-auto h-full w-full">
<article className="prose p-4">{children}</article>
</div>
)
}
================================================
FILE: docs/_snippets/hey.org
================================================
* Hey, there
The /beauty/ of org *must* be shared.
[[https://upload.wikimedia.org/wikipedia/commons/a/a6/Org-mode-unicorn.svg][org-mode logo]]
================================================
FILE: docs/advanced/_layout.tsx
================================================
import { DocumentLayout } from '../_layout.tsx'
export default DocumentLayout
================================================
FILE: docs/advanced/api.org
================================================
#+title: API
#+published: true
#+position: 201
#+type: document
#+jsx: <Notice>This page is a WIP</Notice>
Describe the API.
================================================
FILE: docs/advanced/ast.org
================================================
#+title: AST
#+published: true
#+position: 202
#+type: document
#+jsx: <Notice>This page is a WIP</Notice>
Orga Abstract Syntax Tree.
================================================
FILE: docs/advanced/index.org
================================================
#+title: Advanced
#+published: true
#+type: document
#+position: 200
#+jsx: <Notice>This page is a WIP</Notice>
================================================
FILE: docs/advanced/latex.org
================================================
#+title: Latex Support
#+published: true
#+position: 203
#+type: document
** Inline Math
Orgajs supports inline math with latex math delimiters.
#+begin_src org
If $$a^2=b$$ and \( b=2 \), then the solution must be either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \].
#+end_src
With be rendered as follows.
If $$a^2=b$$ and \( b=2 \), then the solution must be either $$ a=+\sqrt{2} $$ or \[ a=-\sqrt{2} \].
** Latex Block
It also supports =\begin= commands.
#+begin_src org
\begin{equation}
x=\sqrt{b}
\end{equation}
#+end_src
Will be rendered
\begin{equation}
x=\sqrt{b}
\end{equation}
** Styling
=@orgajs/rehype-latex= is the plugin for handling latex. It uses [[https://katex.org][katex]] underneath, so you will have to add the css link yourself in your website. Add the following to the =head=.
================================================
FILE: docs/contribute.org
================================================
#+title: Contribute
#+published: true
#+position: 300
#+type: document
#+jsx: <Notice>This page is a WIP</Notice>
* Need Some Inspiration?
You can find tons of plugins for remark, since they work in similar ways, we can steal some ideas [[https://github.com/remarkjs/remark/blob/main/doc/plugins.md#creating-plugins][here]] and [[https://github.com/remarkjs/awesome-remark][there]], maybe even use them directly.
================================================
FILE: docs/guides/_layout.tsx
================================================
import { DocumentLayout } from '../_layout.tsx'
export default DocumentLayout
================================================
FILE: docs/guides/astro.org
================================================
#+title: Astro
#+published: true
#+type: document
#+position: 5
Use =@orgajs/astro= to write Astro pages in Org Mode (=.org=) and compile them with orgx.
* Quick Start
1. Install the integration:
#+begin_src sh
pnpm add @orgajs/astro
#+end_src
2. Register it in =astro.config.mjs=:
#+begin_src javascript
import { defineConfig } from 'astro/config'
import orgMode from '@orgajs/astro'
export default defineConfig({
integrations: [orgMode()]
})
#+end_src
3. Create a page at =src/pages/index.org=:
#+begin_src org
,* Hello from Org Mode
This page is rendered from Org Mode in Astro.
#+end_src
4. Start Astro:
#+begin_src sh
pnpm astro dev
#+end_src
* Major Features
** Native =.org= pages in Astro
Any file in =src/pages/*.org= is treated as a page route, just like Astro files in other supported formats.
** Org metadata support
Org keywords such as =#+title:=, =#+description:=, and =#+slug:= are parsed and exposed as entry metadata for Astro content handling.
** orgx-powered compilation
Under the hood, this integration uses orgx (via =@orgajs/rollup=), so you get:
- Org Mode parsing to JSX-compatible output
- JavaScript imports/exports inside Org documents
- Unified/rehype/recma pipeline compatibility
** Inline JSX components
You can embed JSX directly in Org files, including imported components.
#+begin_src org
,#+jsx: import Card from '../components/Card.astro'
Here is a Card rendered inline:
,#+jsx: <Card title="Inline component">Hello from Org + JSX</Card>
,#+begin_export jsx
<section className="hero">
<h2>JSX export block</h2>
<p>You can also write larger JSX blocks.</p>
</section>
,#+end_export
#+end_src
Use =#+jsx:= for single-line JSX/imports and =#+begin_export jsx= for multi-line blocks.
================================================
FILE: docs/guides/gatsby.org
================================================
#+title: Gatsby
#+published: true
#+type: document
#+position: 102
#+jsx: <Notice title="DEPRECATED">I'm no longer actively maintaining this Gatsby integration due to the rapid pace of frontend development. However, the source code remains available for those who wish to adapt and maintain it independently. You can refer to the orgajs project for examples of advanced usage.</Notice>
* Create Gatsby Project
Create a new gatsby website following the [[https://www.gatsbyjs.com/get-started/][documentation]]. Or simply
#+begin_src sh
npx gatsby new gatsby-site
#+end_src
* Installation
Install packages.
#+begin_src sh
cd gatsby-site
yarn add gatsby-plugin-orga @orgajs/react @orgajs/loader
#+end_src
* Configuration
Add =gatsby-plugin-orga= to =gatsby-config.js=.
#+begin_src javascript
module.exports = {
plugins: ['gatsby-plugin-orga']
}
#+end_src
Add a org file in folder =src/pages= directory. It should work out of the box.
For more advanced usage, please checkout code of [[https://github.com/orgapp/orgajs][orgajs project]], which generate this website via =gatsby-theme-orga-docs=.
================================================
FILE: docs/guides/index.org
================================================
#+title: Getting Started
#+published: true
#+type: document
#+position: 100
** Basic Setup
Orga is built on the [[https://unifiedjs.com][unified]] ecosystem. The core parser package =@orgajs/reorg= is the minimum requirement to get started.
** Simple HTML Compilation
To transform Org-mode content into HTML, install the required packages:
#+begin_src sh
npm install @orgajs/reorg @orgajs/reorg-rehype rehype-stringify unified-stream
#+end_src
Create a basic compilation script:
#+begin_src javascript
// compile.js
const stream = require('unified-stream')
const reorg = require('@orgajs/reorg')
const mutate = require('@orgajs/reorg-rehype')
const html = require('rehype-stringify')
const processor = reorg()
.use(mutate)
.use(html)
process.stdin.pipe(stream(processor)).pipe(process.stdout)
#+end_src
Convert your Org files to HTML:
#+begin_src sh
node compile.js < input.org > output.html
#+end_src
#+end_src
Example Input (input.org)
#+begin_src org
,* Hello Orga
Orga is *awesome*.
#+end_src
Yields Output (output.html)
#+begin_src html
<div class="section">
<h1>Hello Orga</h1>
<p>Orga is <strong class="">awesome</strong>. </p>
</div>
#+end_src
================================================
FILE: docs/guides/next.org
================================================
#+title: Next.js
#+published: true
#+type: document
#+position: 4
Use =@orgajs/next= to write Next.js pages in Org Mode (=.org=) and compile them with orgx.
Standalone repository:
- [[https://github.com/orgapp/orga-next][orgapp/orga-next]]
* Quick Start
1. Install the integration:
#+begin_src sh
pnpm add @orgajs/next @orgajs/loader @orgajs/react
#+end_src
2. Register it in =next.config.js=:
#+begin_src javascript
const withOrg = require('@orgajs/next')()
module.exports = withOrg({
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'org'],
})
#+end_src
3. Create a page at =app/page.org= (or =pages/index.org=):
#+begin_src org
,* Hello from Org Mode
This page is rendered from Org Mode in Next.js.
#+end_src
4. Start Next.js:
#+begin_src sh
pnpm next dev
#+end_src
* Major Features
** Native =.org= routes in Next.js
Org files can be used as top-level routes in Next.js once =pageExtensions= includes =org=.
** Works with App Router and Pages Router
You can place Org pages in either:
- =app/**/page.org=
- =pages/**/*.org=
** Global Org component mapping
Create =org-components.js= at project root to override rendered elements globally.
#+begin_src javascript
export function useOrgComponents() {
return {
h1: (props) => <h1 style={{ color: 'tomato' }} {...props} />,
}
}
#+end_src
** orgx-powered compilation
This integration uses =@orgajs/loader= under the hood, providing Org Mode to JSX compilation and compatibility with orgx features.
* Notes
- Package name: =@orgajs/next=
- Repository: [[https://github.com/orgapp/orga-next][orgapp/orga-next]]
================================================
FILE: docs/guides/orga-build.org
================================================
#+title: Build a blog with orga-build
#+position: 2
#+type: document
=orga-build= is a powerful static site generator that allows you to build entire websites using only Org-mode files. Tired of learning ever changing frontend frameworks, just want to build a good old static website? This is for you.
Get a bunch of org files in a folder. Run
#+begin_src sh
npx orga-build
#+end_src
This command will generate a static website in the =out= folder, with each Org-mode file translated into an HTML file. The end.
** Layouts
Layout is powerful tool that allows you to define the overall structure and appearance of your website pages. If you are not allergic to write a little bit of =jsx=, you can create layout files and nest them within folders to apply specific layouts to different sections of your website.
To add a layout, create a file named =_layout.tsx= in the desired folder. The root-level layout file (=<project_root>/_layout.tsx=) will be applied to all pages, while nested layout files (e.g., =<project_root>/blog/_layout.tsx=) will be applied to all pages within that specific folder, nested inside the root-level layout.
*** Layout Props
Layout components have access to the in-buffer settings of the corresponding Org-mode file. For example, if you have the following lines in your Org-mode file:
#+begin_src org
,#+title: My Page
,#+author: John
#+end_src
These values will be available as props in your layout file, allowing you to use them dynamically.
Additionally, the layout component receives a =pages= prop, which is an array of page objects representing the pages within the current folder. This feature makes it easy to build navigation components that reflect the structure of your website.
** Build Commands
=orga-build= supports two lifecycle hooks: =preBuild= and =postBuild=. These hooks allow you to run custom commands before and after the main build process, respectively. You can set up these hooks in the =orga.config.js= file by exporting named variables:
#+begin_src javascript
export const preBuild = ['npm run build:css']
#+end_src
The =preBuild= and =postBuild= variables should be arrays of strings, where each string represents a shell command to be executed by the build process.
** Custom Components
=orga-build= allows you to create and use custom React components within your Org-mode files. To do this, create a file named =_components.tsx= in your project root and export your custom components:
#+begin_src jsx
export function FancyBox({ children }) {
return <div className="fancy">{children}</div>;
}
#+end_src
You can then use these components directly in your Org-mode files using the =#+jsx:= syntax:
#+begin_src org
#+jsx: <FancyBox>hey, box</FancyBox>
#+end_src
This powerful feature enables you to extend the functionality of your website and create rich, interactive experiences.
================================================
FILE: docs/guides/webpack.org
================================================
#+title: Webpack
#+published: true
#+type: document
#+position: 3
=@orgajs/loader= is a webpack loader taht can be used natrually with webpack setup.
For hassle free experience, use [[file:orga-build.org][orga-build]].
* Installation
#+begin_src sh
npm install --save-dev @orgajs/loader @orgajs/estree-jsx @orgajs/rehype-estree @orgajs/reorg-rehype
#+end_src
* Configuration
An example =webpack.config.js= file.
#+begin_src javascript
import toEstree from '@orgajs/rehype-estree'
import toRehype from '@orgajs/reorg-rehype'
import toJsx from '@orgajs/estree-jsx'
const config = {
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.org$/,
use: [
'babel-loader',
{
loader: '@orgajs/loader',
options: {
plugins: [
toRehype,
toEstree,
toJsx,
]
}
}],
},
]
},
}
export default config
#+end_src
As you can see that the output of =@orgajs/loader= is normal JSX code, so you will need [[https://webpack.js.org/loaders/babel-loader/][babel-loader]] to finish it at the end.
* Babel Configuration
YOu will need to configure babel to support react syntax. An example of =.babelrc= file.
#+begin_src json
{
"presets": ["@babel/env", "@babel/react"]
}
#+end_src
Take a look at webpack documentation for creating a basic react project for more details.
================================================
FILE: docs/index.org
================================================
#+title: Orgajs
#+jsx: import code from './index.org?raw'
* What Is It
=Orga= is a flexible org-mode syntax parser. It parses org content into AST ([[https://en.wikipedia.org/wiki/Abstract_syntax_tree][Abstract Syntax Tree 🌲]]). And it's written in JavaScript.
* What can I do with it
** Editor
Introducing org editor. This the source code of *this page*.
#+jsx: <OrgEditor className='h-64 not-prose' content={code}/>
** Publication
Build a website with org-mode files and [[/guides/orga-build][orga-build]].
# the "orga-editor" is a web-component, the following line defines it
#+jsx: <script type="module" src="/editor.js"/>
================================================
FILE: docs/playground.tsx
================================================
import { ReactNode, useEffect, useMemo, useState } from 'react'
import { VFile } from 'vfile'
import { evaluate } from '@orgajs/orgx'
import * as runtime from 'react/jsx-runtime'
import { map } from 'unist-util-map'
import { JSEditor, OrgEditor } from './_components'
import initContent from './_snippets/hey.org?raw'
const tabs = ['Rendered', 'Oast (Org-mode)', 'Hast (HTML)', 'JSX Code']
export default function Playground() {
const [content, setContent] = useState<string>(initContent)
const [parsed, setParsed] = useState({
oast: '',
hast: '',
jsx: '',
preview: <div>rendering...</div>
})
const [activeTab, setActiveTab] = useState(0)
const showPosition = false
const code = useMemo(() => {
switch (activeTab) {
case 1:
return parsed.oast
case 2:
return parsed.hast
case 3:
return parsed.jsx
default:
return ''
}
}, [activeTab, parsed])
useEffect(() => {
const url = new URL(window.location.href)
const text = url.searchParams.get('text')
if (text) {
setContent(decodeURIComponent(text))
}
}, [])
useEffect(() => {
render(content).then(setParsed)
}, [content])
return (
<div className="flex h-full w-full">
{/* Editor panel */}
<div className="h-full w-1/2 border-1 border-gray-600">
<OrgEditor
className="h-full"
content={content}
onChange={(state) => setContent(state.doc.toString())}
/>
</div>
{/* Preview panel */}
<div className="h-full w-1/2 flex flex-col">
<ul className="tabs tabs-border">
{tabs.map((tab, i) => (
<input
key={`tab-${i}`}
type="radio"
name="tabs"
className="tab"
aria-label={tab}
onChange={() => setActiveTab(i)}
checked={activeTab === i}
/>
))}
</ul>
<div className="h-full overflow-auto">
<div className={`p-4 ${activeTab === 0 ? 'block' : 'hidden'}`}>
{parsed.preview}
</div>
<div className={activeTab === 0 ? 'hidden' : 'block'}>
<JSEditor>{code}</JSEditor>
</div>
</div>
<div className="menu lg:menu-horizontal rounded-box w-full justify-end">
<li>
<button onClick={generateLink}>
<svg
xmlns="http://www.w3.org/2000/svg"
height="24px"
viewBox="0 -960 960 960"
width="24px"
fill="#e3e3e3"
>
<path d="M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm200 160v-80h160q50 0 85-35t35-85q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H520Z" />
</svg>
Generate Link
</button>
</li>
</div>
</div>
</div>
)
// Generate shareable link
function generateLink() {
const url = new URL(window.location.href)
const encoded = encodeURIComponent(content)
url.searchParams.set('text', encoded)
navigator.clipboard.writeText(url.toString())
// This assumes window.echo is available globally
if (typeof window.echo === 'function') {
window.echo('Link copied to clipboard')
} else {
console.log('Link copied to clipboard')
}
}
async function render(content: string) {
const file = new VFile(content)
let oast = ''
let hast = ''
let jsx = ''
const { default: Content } = await evaluate(file, {
...runtime,
rehypePlugins: [capture((v) => (hast = toJSON(v)))],
reorgPlugins: [capture((v) => (oast = toJSON(v)))]
})
jsx = String(file)
return {
oast,
hast,
jsx,
preview: (
<div className="prose h-full overflow-auto">
<Content />
</div>
)
}
}
function capture(fn: (v: any) => void) {
return function () {
return function (tree) {
fn(tree)
}
}
}
function toJSON(tree: any) {
return JSON.stringify(
map(tree, (node) => {
const { position, ...rest } = node
if (!showPosition) {
return rest
}
return node
}),
null,
2
)
}
}
================================================
FILE: docs/style.css
================================================
@import 'tailwindcss';
@plugin "@tailwindcss/typography";
@plugin "daisyui" {
themes: nord --default, dark --prefersdark;
}
#root {
@apply flex flex-col h-screen;
}
.cm-editor {
outline: none;
}
.cm-editor.cm-focused {
outline: none;
}
/* GitHub-like code block styling for rehype-pretty-code output */
.prose pre[data-theme] {
background-color: #0d1117;
border: 1px solid #30363d;
border-radius: 8px;
color: #c9d1d9;
margin: 1.25rem 0;
overflow-x: auto;
padding: 1rem 0;
}
.prose pre[data-theme] code {
background: transparent;
color: inherit;
counter-reset: line;
display: grid;
font-size: 0.875rem;
line-height: 1.5;
padding: 0;
}
.prose pre[data-theme] code .line {
display: inline-block;
min-height: 1.5rem;
padding: 0 1rem;
width: 100%;
}
.prose pre[data-theme] code .line--highlighted {
background-color: rgba(56, 139, 253, 0.15);
}
.prose pre[data-theme] code .word--highlighted {
background-color: rgba(56, 139, 253, 0.3);
border: 1px solid rgba(56, 139, 253, 0.45);
border-radius: 4px;
padding: 0.1rem 0.25rem;
}
.prose code:not(pre code) {
background-color: rgba(175, 184, 193, 0.2);
border-radius: 6px;
font-size: 0.875em;
padding: 0.15rem 0.35rem;
}
================================================
FILE: docs/tsconfig.json
================================================
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["esnext", "DOM"],
"moduleResolution": "node",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"allowImportingTsExtensions": true,
"skipLibCheck": true,
"isolatedModules": true,
"target": "esnext",
"module": "esnext"
}
}
================================================
FILE: examples/README.org
================================================
#+TITLE: Examples
* Setup
Before using any of the examples, you have to build the monorepo.
#+begin_src shell
git clone git@github.com:orgapp/orgajs.git
cd orgajs
yarn
yarn build
#+end_src
Now you can =cd= into specific example project directory and start hacking.
* Which Example To Follow
You should choose...
- [[file:gatsby/][gatsby]] :: if you use gatsby, want highly customized website, render react component directly in org file. okay with one page per org file.
- [[file:gatsby-posts/][gatsby-posts]] :: if you use gatsby, want out-of-the-box blog-like website. Organize posts into either files or sections in files. Mostly okay with the default layout.
- [[file:gatsby-posts-core/][gatsby-posts-core]] :: if you want to customize gatsby-posts to the bone.
- [[file:next/][next]] :: if you use next.js
- [[file:webpack/][webpack]] :: if you want total control, build from scratch, use webpack
* A Little Bit Of Details About Gatsby Examples
If you are trying to choose a gatsby example, here are some technical details that you should know.
There are currently two styles of rendering org-mode content in gatsby.
** [[file:~/Code/orgajs/packages/gatsby-transformer-orga/][gatsby-transformer-orga]] (original)
This is the original implementation. To draw parity from the markdown world, the implementation is similar to [[https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-transformer-remark][gatsby-transformer-remark]]. It's a gatsby [[https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/creating-a-transformer-plugin/]["transfomer"]] plugin. To summaries, it taps into gatsby's build lifecycle and transform source (your org files in this case) into gatsby nodes, eventually render them as web pages. You will get custom graphql types (=OrgContent=, if use the [[file:~/Code/orgajs/packages/gatsby-theme-orga-posts-core/][gatsby-theme-posts-core]] or [[file:~/Code/orgajs/packages/gatsby-theme-orga-posts/][gatsby-theme-posts]], it gets translated into =OrgPost= type). So you can generate your own custom pages, like a post list page, with the help of graphql queries. Another special feature is the ability to generate multiple pages from sections within single org-mode file. Basically your org-mode files are treated as *data*. Take a look at the following examples for details.
- [[file:gatsby-posts/][gatsby-posts]]
- [[file:gatsby-posts-core/][gatsby-posts-core]]
** [[file:~/Code/orgajs/packages/gatsby-plugin-orga/][gatsby-plugin-orga]] (new)
This is the latest implementation from the v3.x release. This is the equivalent of [[https://mdxjs.com][mdx]] on the markdown side. It is powered by the webpack loader [[file:~/Code/orgajs/packages/loader/][@orgajs/loader]], which enables orga to be easily integrated with a much wider range of tools (e.g. next.js, webpack, create-react-app etc...).
Here is a list of my favorite features:
- render react components in org-mode file, just like mdx
- per file custom layout
- passing arbitrary data to layout component via =#+key: value=
- replace default elements with your own react components
Basically Your org files are powerful *pages*. the [[file:gatsby/][gatsby example project]] is a minimal setup. For more advanced example, you can draw some inspirations from the [[file:~/Code/orgajs/website/][website]] (source code for https://orga.js.org).
** The Themes
There are a couple of [[https://www.gatsbyjs.com/docs/themes/][gatsby themes]] you can choose from if you want some out of the box goodies. Also they are good resources for creating your own theme.
- gatsby-theme-orga-posts-core :: Powered by =gatsby-transformer-orga=, it transforms your org files into blog posts, with zero UI elements (it literally print out stringified JSON objects by default). It's totally up to you to customize the look and feel.
- gatsby-theme-orga-posts :: A wrapper around =gatsby-theme-posts-core=, with opinionated UI design. Yet still customizable to certain extend through [[https://www.gatsbyjs.com/docs/how-to/plugins-and-themes/shadowing/][component shadowing]].
- gatsby-theme-orga-docs :: Powered by =gatsby-plugin-orga=, this is what the [[file:~/Code/orgajs/website/][website]] is using. It's designed for documentation kind of websites, with swappable components (through shadowing)
================================================
FILE: examples/build/index.org
================================================
#+title: Build with Orga
* Hi
You can build a static website with *just* org files.
Here's [[file:more.org][another page]].
#+begin_src sh
orga-build
#+end_src
================================================
FILE: examples/build/more.org
================================================
#+title: Another Page
This is another page.
================================================
FILE: examples/build/package.json
================================================
{
"name": "@orgajs/example-build",
"private": true,
"type": "module",
"scripts": {
"dev": "orga-build dev",
"build": "orga-build"
},
"devDependencies": {
"orga-build": "workspace:^"
}
}
================================================
FILE: examples/build/test-content.tsx
================================================
import { getPages, getPage } from 'orga-build:content'
export default function TestContent() {
// Test 1: Get all pages
const allPages = getPages()
// Test 2: Get a specific page
const indexPage = getPage('index')
// Test 3: Filter pages
const filtered = getPages('', (entry) => entry.ext === 'org')
return (
<div>
<h1>Content API Test</h1>
<h2>All Pages ({allPages.length})</h2>
<ul>
{allPages.map((page) => (
<li key={page.id}>
<strong>{page.id}</strong> - {page.slug} (path: {page.path || '(root)'})
{page.data && Object.keys(page.data).length > 0 && (
<pre>{JSON.stringify(page.data, null, 2)}</pre>
)}
</li>
))}
</ul>
<h2>Index Page</h2>
{indexPage ? (
<div>
<p>Found: {indexPage.slug}</p>
<pre>{JSON.stringify(indexPage, null, 2)}</pre>
</div>
) : (
<p>Not found</p>
)}
<h2>Filtered Pages (org only)</h2>
<ul>
{filtered.map((page) => (
<li key={page.id}>{page.slug} - {page.ext}</li>
))}
</ul>
</div>
)
}
================================================
FILE: examples/editor/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
================================================
FILE: examples/editor/CHANGELOG.md
================================================
# @orgajs/example-editor
## 0.3.0
### Minor Changes
- a53cfea: all about the editor
This release improves the editor with new fold/shift/todo actions and settings, while also refactoring orga tokenization/parsing and lezer conversion to improve TODO handling, context hashing, and tree generation consistency.
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/editor@1.4.0
## 0.2.4
### Patch Changes
- Updated dependencies [60ad38f]
- @orgajs/editor@1.3.1
## 0.2.3
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/editor@1.3.0
## 0.2.2
### Patch Changes
- Updated dependencies [2f7b62d]
- @orgajs/editor@1.2.2
## 0.2.1
### Patch Changes
- e3ef3a5: build website with orga-build
- Updated dependencies [e3ef3a5]
- @orgajs/editor@1.2.1
## 0.2.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- Updated dependencies [d8861c2]
- @orgajs/editor@1.2.0
## 0.1.7
### Patch Changes
- 0f825de5: update editor dependencies
- Updated dependencies [0f825de5]
- @orgajs/editor@1.1.7
## 0.1.6
### Patch Changes
- Updated dependencies [e9564ff5]
- @orgajs/editor@1.1.6
## 0.1.5
### Patch Changes
- Updated dependencies [0ffa3415]
- @orgajs/editor@1.1.5
## 0.1.4
### Patch Changes
- dc3a9db2: cleanup editor
- Updated dependencies [dc3a9db2]
- @orgajs/editor@1.1.4
## 0.1.3
### Patch Changes
- Updated dependencies [7cfff79a]
- @orgajs/editor@1.1.3
## 0.1.2
### Patch Changes
- Updated dependencies [ea032b35]
- @orgajs/editor@1.1.2
## 0.1.1
### Patch Changes
- ac322714: implement editor
- Updated dependencies [ac322714]
- @orgajs/editor@1.1.1
## 0.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- @orgajs/editor@1.1.0
================================================
FILE: examples/editor/content.org
================================================
#+title: Example Org File
#+date: 2023-11-24
#+todo: TODO NEXT | DONE
Org uses single characters to markup *bold* /italic/ _underline_ +strike through+ ~code~ and =verbatim=. Links also use minimal
markup in [[https://orgmode.org][Org]].
* NEXT Blocks
#+begin_src js
console.log('hello')
#+end_src
* Lists
- one
- two
- three
* Tasks
** DONE buy milk
** TODO drink it
================================================
FILE: examples/editor/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + TS</title>
</head>
<body>
<div id="container">
<h1>Org Editor</h1>
<div id="editor"></div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
================================================
FILE: examples/editor/package.json
================================================
{
"name": "@orgajs/example-editor",
"private": true,
"version": "0.3.0",
"type": "module",
"scripts": {
"dev": "vite --port 3000 --force",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"@codemirror/view": "^6.36.2",
"typescript": "^5.9.2",
"vite": "^6.0.11"
},
"dependencies": {
"@orgajs/editor": "workspace:^",
"cm6-theme-nord": "^0.2.0"
}
}
================================================
FILE: examples/editor/src/main.ts
================================================
import { makeEditor } from '@orgajs/editor'
import content from '../content.org?raw'
import './style.css'
const target = document.querySelector('#editor')
if (target === null) {
throw new Error('No target element found')
}
makeEditor({ target, content, extensions: [] })
================================================
FILE: examples/editor/src/style.css
================================================
body {
background-color: #e7e6e5;
}
#editor {
width: 720px;
height: 800px;
overflow: auto;
border: 1px solid #ccc;
background-color: #fff;
}
================================================
FILE: examples/editor/tsconfig.json
================================================
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
================================================
FILE: examples/getting-started/.gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
================================================
FILE: examples/getting-started/CHANGELOG.md
================================================
# Change Log
## 4.2.12
### Patch Changes
- @orgajs/reorg-rehype@4.3.11
## 4.2.11
### Patch Changes
- @orgajs/reorg-rehype@4.3.10
## 4.2.10
### Patch Changes
- Updated dependencies [bd2365a]
- @orgajs/reorg@4.3.3
- @orgajs/reorg-rehype@4.3.9
## 4.2.9
### Patch Changes
- @orgajs/reorg-rehype@4.3.8
## 4.2.8
### Patch Changes
- @orgajs/reorg-rehype@4.3.7
## 4.2.7
### Patch Changes
- @orgajs/reorg-rehype@4.3.6
## 4.2.6
### Patch Changes
- @orgajs/reorg-rehype@4.3.5
## 4.2.5
### Patch Changes
- @orgajs/reorg-rehype@4.3.4
## 4.2.4
### Patch Changes
- @orgajs/reorg@4.3.2
- @orgajs/reorg-rehype@4.3.3
## 4.2.3
### Patch Changes
- @orgajs/reorg-rehype@4.3.2
- @orgajs/reorg@4.3.1
## 4.2.2
### Patch Changes
- @orgajs/reorg-rehype@4.3.1
## 4.2.1
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/reorg-rehype@4.3.0
- @orgajs/reorg@4.3.0
## 4.2.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- Updated dependencies [d8861c2]
- @orgajs/reorg-rehype@4.2.0
- @orgajs/reorg@4.2.0
## 4.1.3
### Patch Changes
- @orgajs/reorg-rehype@4.1.3
## 4.1.2
### Patch Changes
- @orgajs/reorg-rehype@4.1.2
- @orgajs/reorg@4.1.2
## 4.1.1
### Patch Changes
- @orgajs/reorg-rehype@4.1.1
- @orgajs/reorg@4.1.1
## 4.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- @orgajs/reorg-rehype@4.1.0
- @orgajs/reorg@4.1.0
## 4.0.0
### Major Changes
- 176a3b5d: # Migrate most of the ecosystem to ESM
We are excited to announce that we have migrated most of our ecosystem to ESM! This move was necessary as the unified ecosystem had already transitioned to ESM, leaving our orgajs system stuck on an older version if we wanted to stay on commonjs. We understand that this transition may come with some inevitable breaking changes, but we have done our best to make it as gentle as possible.
In the past, ESM support in popular frameworks like webpack, gatsby, and nextjs was problematic, but the JS world has steadily moved forward, and we are now in a much better state. We have put in a lot of effort to bring this project up to speed, and we are happy to say that it's in a pretty good state now.
We acknowledge that there are still some missing features that we will gradually add back over time. However, we feel that the changes are now in a great state to be released to the world. If you want to use the new versions, we recommend checking out the `examples` folder to get started.
We understand that this upgrade path may not be compatible with older versions, and we apologize for any inconvenience this may cause. However, we encourage you to consider starting fresh, as the most important part of your site should always be your content (org-mode files). Thank you for your understanding, and we hope you enjoy the new and improved ecosystem!
### Patch Changes
- Updated dependencies [176a3b5d]
- @orgajs/reorg-rehype@4.0.0
- @orgajs/reorg@4.0.0
## 3.1.8
### Patch Changes
- Updated dependencies [eeccc870]
- @orgajs/reorg-rehype@3.0.10
- @orgajs/reorg@3.1.7
## 3.1.7
### Patch Changes
- @orgajs/reorg-rehype@3.0.9
- @orgajs/reorg@3.1.6
## 3.1.6
### Patch Changes
- 4bde5155: tidy up dependencies
- @orgajs/reorg-rehype@3.0.8
- @orgajs/reorg@3.1.5
## 3.1.5
### Patch Changes
- @orgajs/reorg-rehype@3.0.7
- @orgajs/reorg@3.1.4
## 3.1.4
### Patch Changes
- @orgajs/reorg-rehype@3.0.6
- @orgajs/reorg@3.1.3
## 3.1.3
### Patch Changes
- @orgajs/reorg-rehype@3.0.5
- @orgajs/reorg@3.1.2
## 3.1.2
### Patch Changes
- @orgajs/reorg-rehype@3.0.4
- @orgajs/reorg@3.1.1
## 3.1.1
### Patch Changes
- Updated dependencies [7f209ff5]
- @orgajs/reorg-rehype@3.0.3
## 3.1.0
### Minor Changes
- eeea0c54: introduce new token: empty line
### Patch Changes
- Updated dependencies [eeea0c54]
- @orgajs/reorg@3.1.0
- @orgajs/reorg-rehype@3.0.2
## 3.0.1
### Patch Changes
- Updated dependencies [6ed76057]
- Updated dependencies [759e6149]
- @orgajs/reorg@3.0.1
- @orgajs/reorg-rehype@3.0.1
## 3.0.0
### Major Changes
- 8b02d10: # Features
- more powerful and flexible lexer and parser
- webpack support
- `jsx` support
- better code block rendering
- better image processing in gatsby
- updated examples
- tons of bug fixes
- brand new `gatsby-plugin-orga`
### Patch Changes
- Updated dependencies [8b02d10]
- @orgajs/reorg@3.0.0
- @orgajs/reorg-rehype@3.0.0
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.6.0](https://github.com/orgapp/orgajs/compare/v2.5.0...v2.6.0) (2021-08-28)
**Note:** Version bump only for package @orgajs/getting-started
# [2.5.0](https://github.com/orgapp/orgajs/compare/v2.4.9...v2.5.0) (2021-08-27)
### Bug Fixes
- lock unified & @types/unist version ([dc72217](https://github.com/orgapp/orgajs/commit/dc72217f0cfcd778436d704021116c8479f8ee1e))
## [2.4.9](https://github.com/orgapp/orgajs/compare/v2.4.8...v2.4.9) (2021-07-13)
**Note:** Version bump only for package example
## [2.4.8](https://github.com/orgapp/orgajs/compare/v2.4.7...v2.4.8) (2021-04-26)
**Note:** Version bump only for package example
## [2.4.7](https://github.com/orgapp/orgajs/compare/v2.4.6...v2.4.7) (2021-04-26)
**Note:** Version bump only for package example
================================================
FILE: examples/getting-started/README.org
================================================
This is an example project, with [[file:index.js][10 lines of code]].
#+BEGIN_SRC sh
npm install
npm run build
#+END_SRC
Take a look at =readme.html= file.
================================================
FILE: examples/getting-started/index.js
================================================
import { reorg } from '@orgajs/reorg'
import { stream } from 'unified-stream'
import mutate from '@orgajs/reorg-rehype'
import html from 'rehype-stringify'
const processor = reorg().use(mutate).use(html)
process.stdin.pipe(stream(processor)).pipe(process.stdout)
================================================
FILE: examples/getting-started/package.json
================================================
{
"private": true,
"name": "@orgajs/getting-started",
"version": "4.2.12",
"description": "",
"main": "index.js",
"type": "module",
"scripts": {
"build": "node index.js < README.org > readme.html"
},
"author": "",
"license": "ISC",
"dependencies": {
"@orgajs/reorg": "workspace:*",
"@orgajs/reorg-rehype": "workspace:*",
"rehype-stringify": "^10.0.1",
"unified": "11.0.5",
"unified-stream": "^3.0.0"
}
}
================================================
FILE: examples/webpack/.babelrc
================================================
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
================================================
FILE: examples/webpack/CHANGELOG.md
================================================
# Change Log
## 3.2.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
## 3.1.1
### Patch Changes
- e3ef3a5: build website with orga-build
## 3.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
## 3.0.1
### Patch Changes
- 4bde5155: tidy up dependencies
## 3.0.0
### Major Changes
- 8b02d10: # Features
- more powerful and flexible lexer and parser
- webpack support
- `jsx` support
- better code block rendering
- better image processing in gatsby
- updated examples
- tons of bug fixes
- brand new `gatsby-plugin-orga`
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.6.0](https://github.com/orgapp/orgajs/compare/v2.5.0...v2.6.0) (2021-08-28)
**Note:** Version bump only for package @orgajs/example-webpack
# [2.5.0](https://github.com/orgapp/orgajs/compare/v2.4.9...v2.5.0) (2021-08-27)
### Bug Fixes
- fix examples ([bdcd265](https://github.com/orgapp/orgajs/commit/bdcd2655502a73800e8915ba09fd78452dff503f))
## [2.4.9](https://github.com/orgapp/orgajs/compare/v2.4.8...v2.4.9) (2021-07-13)
**Note:** Version bump only for package @orgajs/example-webpack
## [2.4.8](https://github.com/orgapp/orgajs/compare/v2.4.7...v2.4.8) (2021-04-26)
**Note:** Version bump only for package @orgajs/example-webpack
## [2.4.7](https://github.com/orgapp/orgajs/compare/v2.4.6...v2.4.7) (2021-04-26)
**Note:** Version bump only for package @orgajs/example-webpack
================================================
FILE: examples/webpack/README.org
================================================
#+title: Webpack + Orga
This is a minimal webpack website that recognizes org-mode files as pages.
-----
* Running locally
See the [[file:../README.org][setup instructions]] before using this project.
#+begin_src shell
yarn start
#+end_src
================================================
FILE: examples/webpack/package.json
================================================
{
"name": "@orgajs/example-webpack",
"private": true,
"version": "3.2.0",
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"scripts": {
"build": "webpack",
"webpack": "webpack",
"start": "webpack serve"
},
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/preset-env": "^7.22.14",
"@babel/preset-react": "^7.22.5",
"@orgajs/loader": "workspace:^",
"babel-loader": "^9.1.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"webpack": "^5.104.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
}
}
================================================
FILE: examples/webpack/public/index.html
================================================
<!DOCTYPE html>
<meta charset="utf-8" />
<div id="root"></div>
<script src="main.js"></script>
================================================
FILE: examples/webpack/src/box.js
================================================
import React from 'react'
export default ({ children }) => (
<div
style={{
padding: 20,
backgroundColor: 'tomato',
color: 'white',
}}
>
{children}
</div>
)
================================================
FILE: examples/webpack/src/hello.org
================================================
#+jsx: import Box from './box'
* Hello
#+begin_export jsx
export default ({ children }) =>
<div style={{ padding: 20 }}>
<h1 style={{ color: 'blue' }}>Orga + Webpack</h1>
{children}
</div>
#+end_export
This is *org-mode* with /JSX/!
-----
#+begin_export jsx
<Box>the tomato box</Box>
#+end_export
================================================
FILE: examples/webpack/src/index.js
================================================
import React from 'react'
import { createRoot } from 'react-dom/client'
import Hello from './hello.org'
const root = createRoot(document.getElementById('root'))
root.render(<Hello />)
================================================
FILE: examples/webpack/webpack.config.mjs
================================================
export default {
mode: 'development',
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.org$/,
use: ['@orgajs/loader'],
},
],
},
}
================================================
FILE: orga.config.js
================================================
import tailwindcss from '@tailwindcss/vite'
import rehypePrettyCode from 'rehype-pretty-code'
export const containerClass = 'prose p-4'
export const styles = ['docs/style.css']
export const vitePlugins = [tailwindcss()]
export const rehypePlugins = [[rehypePrettyCode, { theme: 'github-dark' }]]
export const root = 'docs'
export const exclude = ['config.d.ts']
================================================
FILE: package.json
================================================
{
"name": "orgajs",
"private": true,
"type": "module",
"devDependencies": {
"@biomejs/biome": "^2.4.4",
"@changesets/cli": "^2.29.8",
"@codemirror/lang-javascript": "^6.2.3",
"@codemirror/language": "^6.10.8",
"@codemirror/theme-one-dark": "^6.1.2",
"@codemirror/view": "^6.36.2",
"@lezer/highlight": "^1.2.1",
"@orgajs/orgx": "workspace:^",
"@orgajs/react-cm": "workspace:^",
"@orgajs/react-editor": "workspace:^",
"@tailwindcss/typography": "^0.5.9",
"@tailwindcss/vite": "^4.1.4",
"@types/node": "^25.3.2",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"daisyui": "^5.0.28",
"orga-build": "workspace:^",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rehype-pretty-code": "^0.14.1",
"shiki": "^3.23.0",
"tailwindcss": "^4.0.3",
"type-coverage": "^2.29.7",
"typescript": "^5.9.2",
"unist-util-map": "4.0.0",
"vfile": "^6.0.3"
},
"scripts": {
"build": "pnpm -r --filter './packages/*' --if-present run build && tsc --build --clean && tsc --build && type-coverage",
"clean": "tsc --build --clean",
"lint": "biome lint .",
"lint:fix": "biome lint . --write",
"test": "pnpm run check && pnpm -r --filter './packages/*' --if-present run test",
"format": "biome format --write .",
"check": "biome check .",
"check:fix": "biome check . --write",
"changeset": "changeset",
"ci:version": "changeset version",
"ci:publish": "pnpm build && changeset publish",
"docs": "orga-build",
"docs:dev": "orga-build dev"
}
}
================================================
FILE: packages/astro/README.org
================================================
* @orgajs/astro (Moved)
The Astro integration package has moved to a dedicated repository:
[[https://github.com/orgapp/orga-astro][github.com/orgapp/orga-astro]]
Please use that repository for source code, issues, and releases.
================================================
FILE: packages/codemirror-lang/CHANGELOG.md
================================================
# @orgajs/cm-lang
## 1.3.0
### Minor Changes
- a53cfea: all about the editor
This release improves the editor with new fold/shift/todo actions and settings, while also refactoring orga tokenization/parsing and lezer conversion to improve TODO handling, context hashing, and tree generation consistency.
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/lezer@1.4.0
## 1.2.1
### Patch Changes
- @orgajs/lezer@1.3.1
## 1.2.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/lezer@1.3.0
## 1.1.6
### Patch Changes
- e3ef3a5: build website with orga-build
- Updated dependencies [e3ef3a5]
- @orgajs/lezer@1.2.1
## 1.1.5
### Patch Changes
- Updated dependencies [d8861c2]
- @orgajs/lezer@1.2.0
## 1.1.4
### Patch Changes
- 0f825de5: update editor dependencies
- Updated dependencies [0f825de5]
- @orgajs/lezer@1.1.4
## 1.1.3
### Patch Changes
- @orgajs/lezer@1.1.3
## 1.1.2
### Patch Changes
- Updated dependencies [ea032b35]
- @orgajs/lezer@1.1.2
## 1.1.1
### Patch Changes
- ac322714: implement editor
- Updated dependencies [ac322714]
- @orgajs/lezer@1.1.1
## 1.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- @orgajs/lezer@1.1.0
================================================
FILE: packages/codemirror-lang/index.js
================================================
/** @typedef {import('@lezer/common').SyntaxNode} SyntaxNode */
import {
defineLanguageFacet,
foldNodeProp,
foldService,
Language,
LanguageSupport,
syntaxTree
} from '@codemirror/language'
import { parser as baseParser } from '@orgajs/lezer'
const data = defineLanguageFacet({})
// --- folding ---
/**
* @param {SyntaxNode} node
*/
function getHeadlineLevel(node) {
if (node.type.name !== 'headline') return
const stars = node.getChild('stars')
if (stars) {
const level = stars.to - stars.from
return level
}
}
/**
* @param {SyntaxNode} headerNode
*/
function findSectionEnd(headerNode) {
const level = getHeadlineLevel(headerNode)
if (level === undefined) throw new Error('Not a headline')
let last = headerNode
for (;;) {
const next = last.nextSibling
if (!next) {
break
}
const l = getHeadlineLevel(next)
if (l !== undefined && l <= level) {
return next.from - 1 // Escape the newline. TODO: is this safe?
}
last = next
}
return last.to
}
const headerIndent = foldService.of((state, start, end) => {
for (
let /** @type {SyntaxNode | null} */ node = syntaxTree(state).resolveInner(
end,
-1
);
node;
node = node.parent
) {
if (node.from < start) {
break
}
if (!node.type.name.startsWith('headline')) {
continue
}
const upto = findSectionEnd(node)
if (upto > end) {
return { from: end, to: upto }
}
}
return null
})
const parser = baseParser.configure({
props: [
foldNodeProp.add((type) => {
if (type.name !== 'headline') {
return undefined
}
return (tree, state) => ({
from: state.doc.lineAt(tree.from).to,
to: state.doc.lineAt(tree.from).to
})
})
]
})
/**
* @param {any} parser
*/
function mkLang(parser) {
return new Language(data, parser, [headerIndent], 'org')
}
export function org() {
const lang = mkLang(parser)
return new LanguageSupport(lang)
}
export { tags } from '@orgajs/lezer'
================================================
FILE: packages/codemirror-lang/package.json
================================================
{
"name": "@orgajs/cm-lang",
"version": "1.3.0",
"description": "codemirror language: org",
"type": "module",
"files": [
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"scripts": {},
"keywords": [
"org",
"org-mode",
"orgajs",
"orga",
"codemirror"
],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com:orgapp/orgajs.git",
"directory": "packages/cm-lang"
},
"dependencies": {
"@codemirror/language": "^6.10.8",
"@orgajs/lezer": "workspace:^"
},
"devDependencies": {
"@codemirror/state": "^6.5.2",
"@lezer/common": "^1.1.1"
}
}
================================================
FILE: packages/codemirror-lang/tsconfig.json
================================================
{
"extends": "../../tsconfig.json"
}
================================================
FILE: packages/editor/CHANGELOG.md
================================================
# @orgajs/editor
## 1.4.1
### Patch Changes
- bd2365a: fix types and linting
## 1.4.0
### Minor Changes
- a53cfea: all about the editor
This release improves the editor with new fold/shift/todo actions and settings, while also refactoring orga tokenization/parsing and lezer conversion to improve TODO handling, context hashing, and tree generation consistency.
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/cm-lang@1.3.0
## 1.3.1
### Patch Changes
- 60ad38f: migrate orga-build to be based on vite
- @orgajs/cm-lang@1.2.1
## 1.3.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/cm-lang@1.2.0
## 1.2.2
### Patch Changes
- 2f7b62d: fix package.json file
## 1.2.1
### Patch Changes
- e3ef3a5: build website with orga-build
- Updated dependencies [e3ef3a5]
- @orgajs/cm-lang@1.1.6
## 1.2.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- @orgajs/cm-lang@1.1.5
## 1.1.7
### Patch Changes
- 0f825de5: update editor dependencies
- Updated dependencies [0f825de5]
- @orgajs/cm-lang@1.1.4
## 1.1.6
### Patch Changes
- e9564ff5: remove opinionated extensions from default editor
## 1.1.5
### Patch Changes
- 0ffa3415: cleanup theme
## 1.1.4
### Patch Changes
- dc3a9db2: cleanup editor
## 1.1.3
### Patch Changes
- 7cfff79a: headline elements (stars, todo keywords and priority) end after the whitespaces
- @orgajs/cm-lang@1.1.3
## 1.1.2
### Patch Changes
- ea032b35: bug fix, link generating button
- @orgajs/cm-lang@1.1.2
## 1.1.1
### Patch Changes
- ac322714: implement editor
- Updated dependencies [ac322714]
- @orgajs/cm-lang@1.1.1
## 1.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- @orgajs/cm-lang@1.1.0
================================================
FILE: packages/editor/README.org
================================================
* TODO Quick Start
* Customization
** TODO Write a Theme
** TODO key bindings
================================================
FILE: packages/editor/index.js
================================================
/**
* @typedef {import('./lib/editor.js').Config} EditorConfig
*/
export { tags } from '@orgajs/cm-lang'
export { makeEditor } from './lib/editor.js'
export { settings } from './lib/settings.js'
export { setup } from './lib/setup.js'
================================================
FILE: packages/editor/lib/actions/fold.js
================================================
/**
* @file Actions to shift sections.
*
* @typedef {import('@codemirror/view').EditorView} EditorView
* @typedef {import('@lezer/common').Tree} Tree
* @typedef {import('@lezer/common').SyntaxNode} Node
* @typedef {import('@codemirror/state').ChangeSpec} ChangeSpec
*/
import {
foldAll,
foldCode,
foldState,
unfoldAll,
unfoldCode
} from '@codemirror/language'
import { EditorState } from '@codemirror/state'
import { selectedLines } from './utils'
/**
* @param {EditorView} view
*/
export function toggleFold(view) {
const { state } = view
const lines = selectedLines(view)
for (const line of lines) {
const folded = findFold(state, line.from, line.to)
if (folded) {
unfoldCode(view)
} else {
foldCode(view)
}
}
return true
}
/**
* @param {EditorState} state
* @param {number} from
* @param {number} to
*/
function findFold(state, from, to) {
/** @type {{from:number, to:number} | null} */ let found = null
state.field(foldState, false)?.between(from, to, (from, to) => {
if (!found || found.from > from) found = { from, to }
})
return found
}
/**
* @param {EditorView} view
*/
export function toggleFoldAll(view) {
const state = view.state
const folds = state.field(foldState, false)
if (folds?.size) {
unfoldAll(view)
} else {
foldAll(view)
}
return true
}
================================================
FILE: packages/editor/lib/actions/shift.js
================================================
/**
* @file Actions to shift sections.
*
* @typedef {import('@codemirror/view').EditorView} EditorView
* @typedef {import('@lezer/common').Tree} Tree
* @typedef {import('@lezer/common').SyntaxNode} Node
* @typedef {import('@codemirror/state').ChangeSpec} ChangeSpec
*/
import { syntaxTree } from '@codemirror/language'
/**
* Shift the headline.
* @param {number} delta - The number of spaces to shift. Positive values shift right, negative values shift left.
* @param {boolean} [recursive=false] - Whether to shift subsections recursively.
*/
export function shift(delta, recursive = false) {
/**
* @param {EditorView} view
*/
return function (view) {
const { state } = view
const tree = syntaxTree(state)
const pos = state.selection.main.head
// the selection must be in a headline
const headline = getHeadline(tree, pos)
if (!headline) return false
/** @type {ChangeSpec[]} */
const changes = []
let cancelled = false
if (recursive === false) {
const stars = headline.getChild('stars')
if (!stars || stars.to - stars.from + delta < 1) {
return true
}
const change = _shift(stars, delta)
if (change) {
changes.push(change)
}
} else {
const cursor = headline.cursor()
const change = _shift(headline, delta)
if (change) {
changes.push(change)
} else {
return true
}
while (cursor.nextSibling()) {
if (cursor.type.name === 'headline') {
const change = _shift(cursor.node, delta)
if (change) {
changes.push(change)
} else {
cancelled = true
break
}
}
}
}
if (!cancelled && changes.length > 0) {
view.dispatch({ changes })
}
return true
}
}
/**
* shift the stars
* @param {Node|null|undefined} node
* @param {number} delta
* @returns {ChangeSpec | undefined}
*/
function _shift(node, delta) {
if (!node) return undefined
if (node.type.name === 'headline')
return _shift(node.getChild('stars'), delta)
if (node.type.name !== 'stars') return
if (delta > 0) {
return {
from: node.from,
insert: '*'.repeat(delta)
}
}
if (delta < 0 && node.to - node.from + delta >= 1) {
return {
from: node.from,
to: node.from - delta,
insert: ''
}
}
}
/**
* @param {Tree} tree
* @param {number} pos
*/
function getHeadline(tree, pos) {
/** @type {import('@lezer/common').NodeIterator | null} */
let iter = tree.resolveStack(pos)
while (iter) {
const name = iter.node.type.name
if (name.startsWith('headline')) return iter.node
iter = iter.next
}
return null
}
================================================
FILE: packages/editor/lib/actions/todo.js
================================================
/**
* @typedef {import('@codemirror/view').EditorView} EditorView
*/
import { syntaxTree } from '@codemirror/language'
import { parseTodoKeywords } from 'orga/todo'
import { settings } from '../settings'
import { getTodo } from './utils'
/**
* @param {EditorView} view
*/
export function toggleTodo(view) {
const { state } = view
const pos = state.selection.main.head
const tree = syntaxTree(state)
const _todo = getTodo(tree, pos)
if (!_todo) return false
const content = state.sliceDoc(_todo.from, _todo.to)
const _settings = state.field(settings)
const t = parseTodoKeywords(_settings.todo)
const next = t.next(content)
const change = {
from: _todo.from,
to: _todo.to,
...(next !== undefined && { insert: next })
}
view.dispatch({ changes: change })
console.log({ todo: _todo, content, next })
return true
}
================================================
FILE: packages/editor/lib/actions/utils.js
================================================
/**
* @typedef {import('@codemirror/view').EditorView} EditorView
* @typedef {import('@lezer/common').Tree} Tree
*/
/**
* @param {EditorView} view
*/
export function selectedLines(view) {
/** @type {Array<import('@codemirror/view').BlockInfo>} */
const lines = []
for (const { head } of view.state.selection.ranges) {
if (lines.some((l) => l.from <= head && l.to >= head)) continue
lines.push(view.lineBlockAt(head))
}
return lines
}
/**
* @param {Tree} tree
* @param {number} pos
*/
export function getTodo(tree, pos) {
const headline = getNode(tree, pos, 'headline')
return headline?.getChild('todo')
}
/**
* @param {Tree} tree
* @param {number} pos
* @param {string} type
*/
export function getNode(tree, pos, type) {
/** @type {import('@lezer/common').NodeIterator | null} */
let iter = tree.resolveStack(pos)
while (iter) {
const name = iter.node.type.name
if (name === type) return iter.node
iter = iter.next
}
return null
}
================================================
FILE: packages/editor/lib/editor.js
================================================
/**
* @callback OnChange
* @param {EditorState} state
*/
/**
* @typedef Config
* @property {Element} target
* @property {string} [content='']
* @property {import('@codemirror/state').Extension} [extensions=[]]
* @property {boolean} [dark=false]
* @property {OnChange} [onChange=() => {}]
*/
import { EditorState } from '@codemirror/state'
import { EditorView } from '@codemirror/view'
import { setup } from './setup.js'
/**
* @param {Config} config
*/
export function makeEditor(config) {
const { target, content = '', extensions = [], onChange } = config
const state = EditorState.create({
doc: content,
extensions: [setup, extensions]
})
const editor = new EditorView({
state,
parent: target,
dispatch: (tr) => {
editor.update([tr])
tr.docChanged && onChange && onChange(editor.state)
}
})
return { editor }
}
================================================
FILE: packages/editor/lib/extensions/cleanup.js
================================================
/**
* @typedef Range
* @property {number} from
* @property {number} to
*
* @typedef {object} Options
* @property {boolean} hideStars
* @property {boolean} hideLinks
*/
import { syntaxTree } from '@codemirror/language'
import { Decoration, ViewPlugin } from '@codemirror/view'
import { parseTodoKeywords } from 'orga/todo'
import { settings } from '../settings'
/**
* @param {Range} a
* @param {Range} b
*/
function overlap(a, b) {
return a.from <= b.to && a.to >= b.from
}
/**
* @param {Options} options
*/
export function cleanup(options) {
return ViewPlugin.define(
(view) => {
let _data = createDecorations(view, options)
let _selection = view.state.selection.main
return {
get decorations() {
return _data.decorations
},
get selection() {
return _selection
},
update(update) {
_selection = update.state.selection.main
if (update.docChanged) {
_data = createDecorations(update.view, options)
}
}
}
},
{
decorations: (v) => {
const { decorations, selection } = v
return decorations.update({
filter: (_from, _to, deco) => {
const revealRange = deco.spec.revealRange
if (revealRange) {
return !overlap(revealRange, selection)
}
return true
}
})
},
eventHandlers: {
// cmd+click to open links
mousedown(e, view) {
const pos = view.posAtCoords(e)
if (!pos) return
if (!e.metaKey) return
this.decorations.between(pos, pos, (_from, _to, deco) => {
const { tagName, attributes } = deco.spec
if (tagName === 'a' && attributes) {
e.preventDefault()
// TODO: is it possible to make it a real link?
// I guess that'd be difficult because it's a fucking editor
window.open(deco.spec.attributes.href, '_blank')
return false
}
})
}
}
}
)
}
// TODO: this plugin is getting big, in terms of responsibility, break it down
/**
* @param {Range | null} reveal
*/
function hide(reveal) {
return Decoration.replace({
revealRange: reveal
})
}
/**
* @param {boolean} actionable
*/
function todo(actionable) {
return Decoration.mark({
attributes: {
class: 'cm-org-todo',
'data-actionable': actionable.toString()
}
})
}
/**
* @param {import('@codemirror/view').EditorView} view
* @param {Options} options
*/
function createDecorations(view, options) {
const _settings = view.state.field(settings)
const t = parseTodoKeywords(_settings.todo)
let decorations = Decoration.none
/** @type {Range[]} */
const links = []
/** @type {Range | null} */
let headlineRange = null
/** @type {Range | null} */
let linkRange = null
syntaxTree(view.state).iterate({
enter(node) {
if (node.name.startsWith('headline')) {
headlineRange = { from: node.from, to: node.to }
}
if (node.name === 'link') {
linkRange = { from: node.from, to: node.to }
}
if (node.name === 'url') {
if (linkRange === null) return
// get text of node
const text = view.state.doc.sliceString(node.from, node.to)
decorations = decorations.update({
add: [
Decoration.mark({
tagName: 'a',
attributes: { class: 'cm-link', href: text.slice(1, -1) }
}).range(linkRange.from, linkRange.to)
]
})
}
if (options.hideLinks && (node.name === 'url' || node.name === 'mark')) {
decorations = decorations.update({
add: [hide(linkRange).range(node.from, node.to)]
})
}
if (options.hideStars && node.name === 'stars') {
const revealRange = { from: headlineRange?.from, to: headlineRange?.to }
decorations = decorations.update({
add: [
Decoration.replace({
revealRange
}).range(node.from, node.to)
]
})
}
if (node.name === 'todo') {
const content = view.state.doc.sliceString(node.from, node.to).trim()
decorations = decorations.update({
add: [todo(t.actionable(content)).range(node.from, node.to)]
})
}
if (node.name === 'done') {
decorations = decorations.update({
add: [todo(false).range(node.from, node.to)]
})
}
},
leave: (node) => {
if (node.name.startsWith('headline')) headlineRange = null
if (node.name === 'link') linkRange = null
}
})
return { decorations, links }
}
================================================
FILE: packages/editor/lib/settings.js
================================================
/**
* @typedef {import('@codemirror/state').EditorState} EditorState
*
* @typedef {Object} TodoKeywordSet
* @property {string[]} actionables - The keywords that represent actionable states (e.g. "TODO", "NEXT").
* @property {string[]} done - The keywords that represent completed states (e.g. "DONE", "CANCELLED").
*
* @typedef {Object} Settings
* @property {string} todo - The set of todo keywords used in the document.
*/
import { syntaxTree } from '@codemirror/language'
import { StateField } from '@codemirror/state'
export const settings = StateField.define({
create(state) {
return extractSettings(state)
},
update(value, tr) {
if (tr.docChanged) {
return extractSettings(tr.state)
}
return value
}
})
/**
* @param {EditorState} state
* @return {Settings}
*/
function extractSettings(state) {
const tree = syntaxTree(state)
/** @type {Settings} */
const settings = {
todo: 'TODO DONE'
}
tree.iterate({
enter(node) {
if (node.name === 'keyword') {
const content = state.doc.sliceString(node.from, node.to).trim()
const m = content.match(/^#\+(\w+):(?:[ \t]+(.*))?$/y)
if (!m) return true
const [_, key, value] = m
if (!key || !value) return true
if (key.toLowerCase() === 'todo') {
settings.todo = value.trim()
return true
}
}
return true
}
})
return settings
}
================================================
FILE: packages/editor/lib/setup.js
================================================
import { defaultKeymap } from '@codemirror/commands'
import { bracketMatching, foldGutter } from '@codemirror/language'
import { EditorView, highlightActiveLine, keymap } from '@codemirror/view'
import { org } from '@orgajs/cm-lang'
import { toggleFold, toggleFoldAll } from './actions/fold.js'
import { shift } from './actions/shift.js'
import { toggleTodo } from './actions/todo'
import { cleanup } from './extensions/cleanup.js'
import { settings } from './settings'
import theme from './theme.js'
const keys = [
{ key: 'Tab', run: toggleFold, shift: toggleFoldAll },
{
key: 'Cmd-ArrowLeft',
run: shift(-1),
shift: shift(-1, true),
preventDefault: true
},
{
key: 'Cmd-ArrowRight',
run: shift(1),
shift: shift(1, true),
preventDefault: true
},
{
key: 'Cmd-x',
run: toggleTodo,
preventDefault: true
}
]
export const setup = (() => [
org(),
settings,
theme,
keymap.of([...keys, ...defaultKeymap]),
highlightActiveLine(),
foldGutter({
openText: '▾',
closedText: '▸'
}),
EditorView.lineWrapping,
bracketMatching(),
cleanup({ hideStars: false, hideLinks: true })
])()
================================================
FILE: packages/editor/lib/theme.js
================================================
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language'
import { EditorView } from '@codemirror/view'
import { tags as t } from '@orgajs/cm-lang'
const theme = EditorView.baseTheme({
'&': {
height: '100%'
},
'.cm-link': {
cursor: 'pointer'
},
'.cm-org-todo': {
color: 'white',
backgroundColor: 'green',
padding: '0 2px',
borderRadius: '2px',
cursor: 'pointer'
},
'.cm-org-todo[data-actionable="true"]': {
backgroundColor: 'red'
}
})
const baseStyle = HighlightStyle.define([
{
tag: [t.heading],
fontWeight: 'bold',
textDecoration: 'underline'
},
{ tag: [t.keyword, t.strong], fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{
tag: t.monospace,
borderRadius: '4px',
padding: '1px 4px',
fontFamily: "'JetBrains Mono', monospace"
},
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.underline, textDecoration: 'underline' }
])
const lightColors = HighlightStyle.define(
[
{ tag: t.keyword, color: '#e45649' },
{ tag: t.comment, color: '#9ca0a4' },
{ tag: t.processingInstruction, color: '#9ca0a4' },
{ tag: t.attributeName, color: '#9ca0a4' }
],
{ themeType: 'light' }
)
const darkColors = HighlightStyle.define(
[
{ tag: t.keyword, color: 'green' },
{ tag: t.comment, color: 'red' },
{ tag: t.processingInstruction, color: 'gray' },
{ tag: t.attributeName, color: 'gray' }
],
{ themeType: 'dark' }
)
export default [
theme,
syntaxHighlighting(lightColors),
syntaxHighlighting(darkColors),
syntaxHighlighting(baseStyle)
]
================================================
FILE: packages/editor/package.json
================================================
{
"name": "@orgajs/editor",
"version": "1.4.1",
"type": "module",
"files": [
"lib/",
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"description": "react org-mode editor based on prose-mirror",
"scripts": {},
"repository": {
"type": "git",
"url": "https://github.com/orgapp/orgajs.git",
"directory": "packages/editor"
},
"keywords": [
"org-mode",
"CodeMirror",
"editor"
],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"dependencies": {
"@codemirror/commands": "^6.8.0",
"@codemirror/language": "^6.10.8",
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.36.2",
"@orgajs/cm-lang": "workspace:^"
},
"devDependencies": {
"@lezer/common": "^1.2.3",
"orga": "workspace:^",
"vfile": "^6.0.3"
}
}
================================================
FILE: packages/editor/tsconfig.json
================================================
{
"extends": "../../tsconfig.json"
}
================================================
FILE: packages/esbuild/CHANGELOG.md
================================================
# @orgajs/esbuild
## 1.1.5
### Patch Changes
- bd2365a: fix types and linting
- Updated dependencies [bd2365a]
- @orgajs/orgx@2.6.1
## 1.1.4
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/orgx@2.6.0
## 1.1.3
### Patch Changes
- @orgajs/orgx@2.5.2
## 1.1.2
### Patch Changes
- @orgajs/orgx@2.5.1
## 1.1.1
### Patch Changes
- 8451164: move orga-build to esbuild
## 1.1.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/orgx@2.5.0
## 1.0.1
### Patch Changes
- Updated dependencies [e3ef3a5]
- @orgajs/orgx@2.4.1
## 1.0.0
### Major Changes
- 351f690: introduce @orgajs/node-loader, @orgajs/esbuild, @orgajs/build
- @orgajs/node-loader : the nodejs loader for org-mode files
- @orgajs/esbuild : esbuild plugin
- @orgajs/build : static site generator, a.k.a orga-build
### Patch Changes
- Updated dependencies [351f690]
- @orgajs/orgx@2.4.0
================================================
FILE: packages/esbuild/index.js
================================================
/**
* @import { CompileOptions } from '@orgajs/orgx'
* @import {
OnLoadResult,
PluginBuild
* } from 'esbuild'
*/
import fs from 'node:fs/promises'
import { compile } from '@orgajs/orgx'
import { SourceMapGenerator } from 'source-map'
import { VFile } from 'vfile'
const name = '@orgajs/esbuild'
/**
* Create Node.js hooks to handle org files.
*
* @param {Readonly<CompileOptions> | null | undefined} [options]
* Configuration (optional).
* @returns
* Node.js hooks.
*/
function esbuild(options) {
return {
name,
setup
}
/**
* @param {PluginBuild} build
* Build.
* @returns {undefined}
* Nothing.
*/
function setup(build) {
build.onLoad({ filter: /\.org$/ }, onload)
}
/**
* @param {any} data
* Data.
* @returns {Promise<OnLoadResult>}
* Result.
*/
async function onload(data) {
const document = String(
data.pluginData &&
data.pluginData.contents !== null &&
data.pluginData.contents !== undefined
? data.pluginData.contents
: await fs.readFile(data.path)
)
const file = new VFile({ path: data.path, value: document })
const code = await compile(file, { ...options, SourceMapGenerator })
const contents =
String(code) +
'\n' +
'//# sourceMappingURL=data:application/json;base64,' +
Buffer.from(JSON.stringify(file.map)).toString('base64') +
'\n'
return {
contents
}
}
}
export default esbuild
================================================
FILE: packages/esbuild/package.json
================================================
{
"name": "@orgajs/esbuild",
"version": "1.1.5",
"description": "esbuild plugin for orgajs",
"type": "module",
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts.map",
"index.d.ts",
"index.js"
],
"scripts": {},
"license": "MIT",
"keywords": [
"esbuild",
"jsx",
"org-mode",
"react"
],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"repository": {
"type": "git",
"url": "https://github.com/orgapp/orgajs.git",
"directory": "packages/esbuild"
},
"dependencies": {
"@orgajs/orgx": "workspace:^",
"source-map": "^0.7.4",
"vfile": "^6.0.3"
},
"devDependencies": {
"esbuild": "^0.24.2"
}
}
================================================
FILE: packages/lezer/CHANGELOG.md
================================================
# @orgajs/lezer
## 1.4.1
### Patch Changes
- bd2365a: fix types and linting
- Updated dependencies [bd2365a]
- orga@4.7.1
## 1.4.0
### Minor Changes
- a53cfea: all about the editor
This release improves the editor with new fold/shift/todo actions and settings, while also refactoring orga tokenization/parsing and lezer conversion to improve TODO handling, context hashing, and tree generation consistency.
### Patch Changes
- Updated dependencies [a53cfea]
- orga@4.6.0
## 1.3.1
### Patch Changes
- Updated dependencies [60ad38f]
- orga@4.5.1
## 1.3.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- orga@4.5.0
## 1.2.1
### Patch Changes
- e3ef3a5: build website with orga-build
## 1.2.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- Updated dependencies [d8861c2]
- orga@4.4.0
## 1.1.4
### Patch Changes
- 0f825de5: update editor dependencies
## 1.1.3
### Patch Changes
- Updated dependencies [7cfff79a]
- orga@4.3.0
## 1.1.2
### Patch Changes
- ea032b35: bug fix, link generating button
## 1.1.1
### Patch Changes
- ac322714: implement editor
- Updated dependencies [ac322714]
- orga@4.2.0
## 1.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- orga@4.1.0
================================================
FILE: packages/lezer/README.org
================================================
#+title: Lezer Parser for org-mode
* Tasks
** TODO properly support incremental parsing
** TODO finish nodes design
** TODO finish handlers
** TODO cleanup dependencies
================================================
FILE: packages/lezer/index.js
================================================
export { OrgParser, parser } from './lib/index.js'
export { tags } from './lib/nodes.js'
================================================
FILE: packages/lezer/lib/context.js
================================================
/**
* @typedef {import('@lezer/common').PartialParse} PartialParse
* @typedef {import('@lezer/common').Input} Input
* @typedef {import('@lezer/common').TreeFragment} TreeFragment
* @typedef {import('./fragments.js').FragmentCursor} FragmentCursor
*/
import { getSettings, makeParser } from 'orga'
import { fragmentCursor } from './fragments.js'
import { nodes } from './nodes.js'
import { toLezer } from './oast-to-lezer.js'
import { treeBuilder } from './tree.js'
/**
* @param {import('./index.js').OrgParser} config
* @param {Input} input
* @param {TreeFragment[]} _fragments
* @param {{from: number, to: number}[]} ranges
* @returns {PartialParse}
*/
export function parseContext(config, input, _fragments, ranges) {
const { log, nodeSet } = config
let cursor = ranges[0].from
const end = ranges[ranges.length - 1].to
const rangeI = 0
/** @type {number | null} */
let stoppedAt = null
const full = input.read(0, input.length)
const builder = treeBuilder(nodeSet, nodes.document, 0, cursor, 0, 0)
const fragments = _fragments.length
? fragmentCursor(config, _fragments, input)
: null
// Read settings directly from document text
const settings = getSettings(full)
/** @type {import('orga').Parser | null} */
let parser = null
/**
* check if we reached the end of the input (ranges)
* finish the block in parser if exist
* check if we can reuse a fragment
* @returns {import('@lezer/common').Tree | null}
*/
function advance() {
log('advance called', cursor, end)
// TODO: should we set an end to the tree?
// will take a look when this actually happens
if (stoppedAt != null && cursor > stoppedAt) return builder.build()
if (cursor >= end) {
// end of the tree has to match the end of the input
// sometimes the the chidren does not fill the whole tree
// which causes the end of the tree to be smaller than the end of the input
// set it to the end of the input will prevent unnecessary parsing
return builder.build(end)
}
if (fragments !== null && couldReuse(fragments)) {
const result = fragments.takeNodes(cursor, ranges, rangeI)
if (result.taken > 0) {
wrapUpParser()
builder.addChildren(result.nodes, result.positions)
cursor += result.taken
return null
} else {
log('took nothing')
}
}
if (!parser) {
log('-- creating parser --', cursor, end)
parser = makeParser(full, {
range: { start: cursor, end },
settings,
flat: true
})
}
// parser.advance should finish a block
const document = parser.advance()
if (typeof document === 'number') {
cursor = document
return null
}
wrapUpParser()
return null
}
function wrapUpParser() {
if (!parser) return
const document = parser.finish()
log(
`wrap up parser: ${document.children.length}, ${document.position?.start.offset}, ${document.position?.end.offset}`
)
const tree = toLezer(document, nodeSet)
log(document)
log(tree)
builder.takeChildren(tree, document.position?.start.offset)
builder.takeProps(tree)
if (document.position?.end.offset) cursor = document.position.end.offset
log('-- destroying parser --')
parser = null
}
/**
* check if we can reuse nodes from fragments
* @param {FragmentCursor} fragments
*/
function couldReuse(fragments) {
const hash = builder.hash
// TODO: pass the real lineStart
if (!fragments.moveTo(cursor, cursor)) return false
if (!fragments.matches(hash)) return false
return true
}
return {
get parsedPos() {
log('parsedPos called', cursor)
// if return undefined, the call of advance was not as intense
return cursor
// return parser.now
},
advance,
stopAt(pos) {
log('stopAt called', pos, stoppedAt)
if (stoppedAt != null && stoppedAt < pos)
throw new RangeError("Can't move stoppedAt forward")
stoppedAt = pos
},
get stoppedAt() {
return stoppedAt
}
}
}
================================================
FILE: packages/lezer/lib/fragments.js
================================================
/**
* @typedef {import('@lezer/common').PartialParse} PartialParse
* @typedef {import('@lezer/common').Input} Input
* @typedef {import('@lezer/common').TreeFragment} TreeFragment
* @typedef {import('@lezer/common').TreeCursor} TreeCursor
*
* @typedef TakeNodesResult
* @property {Tree[]} nodes
* @property {number[]} positions
* @property {number} taken
*
* @typedef FragmentCursor
* @property {(pos: number, lineStart: number) => boolean} moveTo
* @property {(hash: number) => boolean} matches
* @property {(start: number, ranges: {from: number, to: number}[], rangeI: number) => TakeNodesResult} takeNodes
*/
import { NodeProp, Tree } from '@lezer/common'
import { nodes } from './nodes.js'
/**
* @param {import('./index.js').OrgParser} config
* @param {TreeFragment[]} fragments
* @param {Input} input
* @returns {FragmentCursor}
*/
export function fragmentCursor({ log, nodeSet }, fragments, input) {
let i = 0
/** @type {TreeCursor | null} */
let cursor = null
/** @type {TreeFragment | null} */
let fragment = fragments.length ? fragments[i++] : null
let fragmentEnd = -1
return {
moveTo,
matches,
takeNodes
}
function nextFragment() {
fragment = i < fragments.length ? fragments[i++] : null
cursor = null
fragmentEnd = -1
}
/**
* move the cursor to the first block after `pos`.
* @param {number} pos
* @param {number} lineStart
*/
function moveTo(pos, lineStart) {
while (fragment && fragment.to < pos) nextFragment()
if (!fragment || fragment.from > (pos ? pos - 1 : 0)) {
return false
}
fragmentEnd = fragment.to
if (fragmentEnd < 0) {
let end = fragment.to
while (end > 0 && input.read(end - 1, end) !== '\n') end--
fragmentEnd = end ? end - 1 : 0
}
const c = cursor || fragment.tree.cursor()
if (!cursor) {
cursor = c
c.firstChild()
}
// if (!c) {
// c = cursor = fragment.tree.cursor()
// c?.firstChild()
// }
const rPos = pos + fragment.offset
while (c.to <= rPos) if (!c.parent()) return false
for (;;) {
if (c.from >= rPos) return fragment.from <= lineStart
if (!c.childAfter(rPos)) return false
}
}
/**
* @param {number} hash
*/
function matches(hash) {
const tree = cursor?.tree
const result = tree ? tree.prop(NodeProp.contextHash) === hash : false
if (result) {
log('✅ fragment matches, reusing', {
hash,
np: tree?.prop(NodeProp.contextHash)
})
} else {
log('❌ fragment does not match, not reusing', {
hash,
np: tree?.prop(NodeProp.contextHash)
})
}
return result
}
/**
* @param {number} start
* @param {{from: number, to: number}[]} ranges
* @param {number} rangeI
* @returns {TakeNodesResult}
*/
function takeNodes(start, ranges, rangeI) {
/** @type {TakeNodesResult} */
const result = {
nodes: [],
positions: [],
taken: 0
}
log('takeNodes', start, ranges, rangeI)
if (!cursor || !fragment) return result
const cur = cursor
const off = fragment.offset
let end = start
// let prevEnd = end
let blockI = 0
// let prevI = 0
const fragEnd = fragmentEnd - (fragment.openEnd ? 1 : 0)
for (;;) {
if (cur.to - off > fragEnd) {
if (cur.type.isAnonymous && cur.firstChild()) continue
log(
`stop takeNodes from ${cur.name}: fe: ${fragEnd} | ${fragmentEnd}, cur: ${cur.name}, cur.from: ${cur.from}, cur.to: ${cur.to}, off: ${off}`
)
break
}
const pos = toRelative(cur.from - off, ranges)
if (cur.to - off <= ranges[rangeI].to) {
// Fits in current range
log(
`Fits in current range, name: ${cur.name}, pos: ${pos}, cur.from: ${cur.from}, cur.to: ${cur.to}`
)
const tree = cur.tree
if (tree) {
result.nodes.push(tree)
result.positions.push(pos)
}
} else {
log('create dummy')
const dummy = new Tree(
nodeSet.types[nodes.paragraph],
[],
[],
0
// cx.block.hashProp
)
result.nodes.push(dummy)
result.positions.push(pos)
// reuse dummy?
}
if (cur.type.is('Block')) {
log('got block:', cur.type.name)
end = cur.to - off
blockI = result.nodes.length
}
if (!cur.nextSibling()) break
}
log(`>> popping: ${blockI} / ${result.nodes.length}`)
log('node:', result.nodes.map((n) => n.type.name).join(','))
while (result.nodes.length > blockI) {
const n = result.nodes.pop()
log('.. pop non blocks', n?.type.name)
result.positions.pop()
}
result.taken = end - start
return result
}
}
/**
* Convert an input-stream-relative position to a
* Markdown-doc-relative position by subtracting the size of all input
* gaps before `abs`.
* @param {number} abs
* @param {{from: number, to: number}[]} ranges
*/
function toRelative(abs, ranges) {
let pos = abs
for (let i = 1; i < ranges.length; i++) {
const gapFrom = ranges[i - 1].to,
gapTo = ranges[i].from
if (gapFrom < abs) pos -= gapTo - gapFrom
}
return pos
}
================================================
FILE: packages/lezer/lib/handlers.js
================================================
/**
* @typedef {import('./types.js').Seed} Seed
* @typedef {import('./types.js').Handler} Handler
* @typedef {Record<string, Handler>} Handlers
* Handle nodes.
*/
import { NodeProp } from '@lezer/common'
import { nodes } from './nodes.js'
// class NodeProp extends _NodeProp {
// static path = new _NodeProp({ perNode: true })
// }
/** @type {NodeProp<{level: number}>} */
export const headlineProp = new NodeProp({ perNode: true })
export const documentProp = new NodeProp({
perNode: true
// deserialize: (str) => {
// console.log('deserialize', str)
// return str
// }
})
/**
* @type {Handlers}
*/
export const handlers = {
document: (_s, doc) => {
if (doc.type !== 'document') {
return false
}
return {
id: nodes.document,
props: [[documentProp, doc.properties]]
}
},
headline: (_s, node) => {
if (node.type === 'headline') {
return {
id: nodes.headline,
props: [[headlineProp, { level: node.level }]]
}
}
return false
},
stars: () => nodes.stars,
todo: (_s, node) => {
if (node.type !== 'todo') {
return false
}
return nodes.todo
},
'link.path': () => nodes.url,
// 'link.description': () => nodes.linkDescription,
link: () => nodes.link,
opening: () => nodes.mark,
closing: () => nodes.mark,
block: () => nodes.block,
html: () => nodes.html,
jsx: () => nodes.jsx,
'block.begin': () => nodes.blockBegin,
'block.end': () => nodes.blockEnd,
tags: () => nodes.marker,
keyword: () => nodes.keyword,
paragraph: () => nodes.paragraph,
list: () => nodes.list,
'list.item.bullet': () => nodes.marker,
text: (_, node) => {
if (node.type !== 'text') {
return false
}
switch (node.style) {
case 'bold':
return nodes.bold
case 'italic':
return nodes.italic
case 'strikeThrough':
return nodes.strikeThrough
case 'code':
return nodes.code
case 'verbatim':
return nodes.code
case 'underline':
return nodes.underline
}
return false
}
}
================================================
FILE: packages/lezer/lib/index.js
================================================
/**
* @typedef {import('@lezer/common').PartialParse} PartialParse
* @typedef {import('@lezer/common').Input} Input
* @typedef {import('@lezer/common').TreeFragment} TreeFragment
*/
/**
* @typedef OrgParserConfig
* @property {import('@lezer/common').NodePropSource[] | undefined | null} props
*/
import { NodeSet, Parser } from '@lezer/common'
import { parseContext } from './context.js'
import { nodeSet } from './nodes.js'
export { tags } from './nodes.js'
export class OrgParser extends Parser {
/**
* @param {NodeSet} nodeSet
* @param {(...data: any[]) => void} [log]
*/
constructor(nodeSet, log = () => {}) {
super()
this.nodeSet = nodeSet
this.log = log
}
/**
* @param {Input} input
* @param {TreeFragment[]} fragments
* @param {{from: number, to: number}[]} ranges
* @returns {PartialParse}
*/
createParse(input, fragments, ranges) {
const r = ranges.map((r) => `${r.from}-${r.to}`).join(', ')
const frags = fragments
.map(
(f) => `(${f.from}-${f.to}, offset: ${f.offset}, openEnd: ${f.openEnd})`
)
.join(' ')
// TODO: add info more about fragments, how do I use ranges vs fragments?
this.log(`createParse`, `ranges: (${r}), frags: [${frags}]`)
const parse = parseContext(this, input, fragments, ranges)
return parse
}
/**
* @param {OrgParserConfig} config
*/
configure(config) {
let { nodeSet } = this
const nodeTypes = nodeSet.types.slice()
nodeSet = new NodeSet(nodeTypes)
if (config.props && config.props.length > 0) {
nodeSet = nodeSet.extend(...config.props)
}
return new OrgParser(nodeSet, this.log)
}
}
export const parser = new OrgParser(
nodeSet,
console.log.bind(console, 'orga-parser')
)
================================================
FILE: packages/lezer/lib/nodes.js
================================================
import { NodeProp, NodeSet, NodeType } from '@lezer/common'
import { styleTags, Tag, tags as t } from '@lezer/highlight'
let i = 0
export const nodes = Object.freeze({
none: i++,
// block
document: i++,
headline: i++,
paragraph: i++,
keyword: i++,
block: i++,
list: i++,
html: i++,
jsx: i++,
// inline
stars: i++,
todo: i++,
done: i++,
link: i++,
marker: i++,
bold: i++,
italic: i++,
code: i++,
strikeThrough: i++,
underline: i++,
url: i++,
blockBegin: i++,
blockEnd: i++,
// smaller
mark: i++
})
/**
* @type {NodeProp<{level: number}>}
*/
export const headlineProp = new NodeProp()
/** @type {NodeType[]} */
export const nodeTypes = Object.entries(nodes).map(([name, id]) =>
NodeType.define({
id,
name,
props: id >= nodes.stars ? [] : [[NodeProp.group, ['Block']]],
top: name === 'document'
})
)
// extra tags
const underline = Tag.define(t.content)
const orgHighlighting = styleTags({
'headline/...': t.heading,
keyword: t.attributeName,
link: t.link,
'stars mark blockBegin blockEnd': t.processingInstruction,
italic: t.emphasis,
bold: t.strong,
strikeThrough: t.strikethrough,
paragraph: t.content,
list: t.list,
underline: underline,
'html jsx code block': t.monospace
})
export const tags = {
...t,
underline
}
export const nodeSet = new NodeSet(nodeTypes).extend(orgHighlighting)
================================================
FILE: packages/lezer/lib/oast-to-lezer.js
================================================
/**
* @typedef {import('orga').Document} OrgTree
* @typedef {import('@lezer/common').Tree} LezerTree
* @typedef {import('@lezer/common').NodeSet} NodeSet
* @typedef {import('orga').Document} OastRoot
* @typedef {import('orga').Content} OastContent
* @typedef {import('orga').Parent} OastParent
* @callback Mapping
* Transform an oast node to prose node.
* @param {OastNodes} node
* @param {number} id
* @param {Array<LezerTree> | undefined} [children]
* @returns {LezerTree | null | undefined}
* @typedef {import('./types.js').State} ParseState
*/
import { NodeProp, Tree } from '@lezer/common'
import { handlers } from './handlers.js'
/**
* @param {import('vfile').VFile | null} file
* @param {NodeSet} nodeSet
* @returns {ParseState}
*/
function createParseState(file, nodeSet) {
/** @type {ParseState} */
const state = {
file,
ignore: ['newline', 'emptyLine'],
nodeSet: nodeSet,
handlers,
one(node, parent, base = 0) {
return one(this, node, parent, base)
},
all(parent, base) {
return all(this, parent, base)
}
}
return state
}
/**
* @param {OrgTree} tree
* @param {NodeSet} nodeSet
* @param {import('vfile').VFile | null} [file=null]
* @returns {import('@lezer/common').Tree}
*/
export function toLezer(tree, nodeSet, file = null) {
// TODO: inject gaps
const state = createParseState(file, nodeSet)
const result = state.one(tree)
if (!result) {
throw new Error('no result')
}
const t = result.nodes[0]
const _props = tree.properties
return t
}
/** @type {import('./types.js').Handler} */
function defaultUnknownHandler() {
// console.log('unknown node', n.type, n)
return true
}
/**
* @param {import('./types.js').OastNode} node
* @returns {[number, number]}
*/
function getRange(node) {
const start = node.position?.start.offset || 0
const end = node.position?.end.offset || 0
return [start, end - start]
}
/**
* @param {ParseState} state
* @param {import('./types.js').OastNode} node
* @param {OastParent | undefined} [parent]
* @param {number} [base=0]
* @returns {{nodes: LezerTree[], positions: number[]} | null | undefined}}
*/
function one(state, node, parent, base = 0) {
if (state.ignore.includes(node.type)) {
return state.all(node, base)
}
const handler = state.handlers[node.type] || defaultUnknownHandler
const seed = handler(state, node, parent)
if (typeof seed === 'boolean') {
if (seed) {
return state.all(node, base)
}
return null
}
let [id, skip, props] =
typeof seed === 'number' ? [seed, false] : [seed.id, seed.skip, seed.props]
const [loc, len] = getRange(node)
const pos = loc - base
/** @type {Tree[]} */
let nodes = []
/** @type {number[]} */
let positions = []
if (!skip) {
const result = state.all(node, loc)
nodes = result.nodes
positions = result.positions
}
if (node.data?.hash !== undefined) {
if (!props) {
props = []
}
props.push([NodeProp.contextHash, node.data.hash])
}
const tree = new Tree(state.nodeSet.types[id], nodes, positions, len, props)
const result = { nodes: [tree], positions: [pos] }
return result
}
/**
* @param {ParseState} state
* @param {import('./types.js').OastNode} parent
* @param {number} base
* @returns {{nodes: LezerTree[], positions: number[]}}}
*/
function all(state, parent, base) {
/** @type {Array<LezerTree>} */
const _nodes = []
/** @type {Array<number>} */
const _positions = []
if ('children' in parent) {
let index = -1
while (++index < parent.children.length) {
const node = parent.children[index]
const { nodes, positions } = state.one(node, parent, base) || {
nodes: [],
positions: []
}
_nodes.push(...nodes)
_positions.push(...positions)
}
}
return {
nodes: _nodes,
positions: _positions
}
}
================================================
FILE: packages/lezer/lib/tree.js
================================================
import { NodeProp, NodeType, Tree } from '@lezer/common'
import { documentProp } from './handlers.js'
// import { nodes } from './nodes.js'
/**
* @param {number} type
* @param {number} value
* @param {number} [parentHash=0]
*/
function hash(type, value, parentHash = 0) {
return (parentHash + (parentHash << 8) + type + (value << 4)) | 0
}
/**
* @param {import('@lezer/common').NodeSet} nodeSet
* @param {number} type
* @param {number} value
* @param {number} from
* @param {number} parentHash
* @param {number} originalEnd
*/
export function treeBuilder(
nodeSet,
type,
value,
from,
parentHash,
originalEnd
) {
/** @type {Tree[]} */
const children = []
/** @type {number[]} */
const positions = []
const _hash = hash(type, value, parentHash)
/** @type {[NodeProp<any>, any][]} */
const props = [[NodeProp.contextHash, _hash]]
return {
addChild,
addChildren,
takeChildren,
takeProps,
addProps: (/** @type {[NodeProp<any>, any][]} */ p) => props.push(...p),
build,
hash: _hash
}
/**
* @param {Tree} child
* @param {number} pos
*/
function addChild(child, pos) {
if (child.prop(NodeProp.contextHash) !== _hash)
child = new Tree(
child.type,
child.children,
child.positions,
child.length,
props
)
children.push(child)
positions.push(pos)
}
/**
* @param {Tree[]} children
* @param {number[]} positions
*/
function addChildren(children, positions) {
for (let i = 0; i < children.length; i++)
addChild(children[i], positions[i])
}
/**
* @param {Tree} tree
* @param {number} [offset=0]
*/
function takeChildren(tree, offset = 0) {
// addChildren(tree.children, tree.positions)
const cursor = tree.cursor()
if (!cursor.firstChild()) return
do {
const child = cursor.tree
if (!child) continue
// TODO: is the position correct?
addChild(child, cursor.from + offset)
} while (cursor.nextSibling())
}
/**
* @param {Tree} tree
*/
function takeProps(tree) {
const doc = tree.prop(documentProp)
if (doc) {
props.push([documentProp, doc])
}
}
/**
* @param {number} [end = originalEnd] - end of the tree
* @returns {Tree}
*/
function build(end = originalEnd) {
const last = children.length - 1
if (last >= 0)
end = Math.max(end, positions[last] + children[last].length + from)
const tree = new Tree(
nodeSet.types[type],
children,
positions,
end - from
).balance({
makeTree: (children, positions, length) =>
new Tree(NodeType.none, children, positions, length, props)
})
return tree
}
}
================================================
FILE: packages/lezer/lib/types.ts
================================================
import type { Tree as LezerTree, NodeSet } from '@lezer/common'
import type { Content, Document, Parent as OastParent, Token } from 'orga'
import type { Position } from 'unist'
import type { VFile } from 'vfile'
export type OastNode = Document | Content | Token
type Action = boolean
export type Seed =
| {
id: number
position?: Position
props?: any
skip?: Action
}
| Action
| number
interface LezerChild {
node: LezerTree
position: number
}
export type Handler = (
state: State,
node: OastNode,
parent: OastParent | undefined
) => Seed
export interface State {
file: VFile | null
ignore: string[]
readonly nodeSet: NodeSet
handlers: Record<string, Handler>
one: (
node: OastNode,
parent?: OastParent | undefined,
base?: number
) => { nodes: LezerTree[]; positions: number[] } | null | undefined
all: (
node: OastNode,
base: number
) => { nodes: LezerTree[]; positions: number[] }
}
================================================
FILE: packages/lezer/package.json
================================================
{
"name": "@orgajs/lezer",
"version": "1.4.1",
"description": "lezer parser for org-mode",
"type": "module",
"files": [
"lib/",
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"scripts": {
"test": "node --test tests/*.test.js"
},
"keywords": [
"org-mode",
"org",
"parser",
"lezer"
],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"repository": {
"url": "orgapp/orgajs",
"directory": "packages/lezer"
},
"dependencies": {
"@lezer/common": "^1.1.1",
"@lezer/highlight": "^1.2.1",
"orga": "workspace:^",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@types/unist": "^3.0.3",
"text-kit": "workspace:^",
"vfile": "^6.0.3"
}
}
================================================
FILE: packages/lezer/tests/compare-tree.js
================================================
import { Tree } from '@lezer/common'
/**
* @typedef {import('@lezer/common').Tree} Tree
*/
/**
* @param {Tree} a
* @param {Tree} b
*/
export function compareTree(a, b) {
const curA = a.cursor(),
curB = b.cursor()
for (;;) {
let mismatch = null,
next = false
if (curA.type !== curB.type)
mismatch = `Node type mismatch (${curA.name} vs ${curB.name})`
else if (curA.from !== curB.from)
mismatch = `Start pos mismatch for ${curA.name}: ${curA.from} vs ${curB.from}`
else if (curA.to !== curB.to)
mismatch = `End pos mismatch for ${curA.name}: ${curA.to} vs ${curB.to}`
else {
next = curA.next()
if (next !== curB.next()) mismatch = `Tree size mismatch`
}
if (mismatch) {
const lines = [mismatch, 'a-:>', ...print(a), 'b-:>', ...print(b)]
throw new Error(lines.join('\n'))
}
if (!next) break
}
}
/**
* @param {import('@lezer/common').TreeCursor | Tree} tree
* @param {string} [prefix]
*/
export function print(tree, prefix = '') {
const cur = tree instanceof Tree ? tree.cursor() : tree
const lines = [`${prefix}${cur.name} (${cur.from}-${cur.to})`]
if (cur.firstChild()) {
do {
lines.push(...print(cur, `${' '.repeat(prefix.length)}└╴`))
} while (cur.nextSibling())
cur.parent()
}
return lines
}
================================================
FILE: packages/lezer/tests/incremental.test.js
================================================
/**
* @typedef {{from: number, to?: number, insert?: string}[]} ChangeSpec
*/
import assert from 'node:assert'
import { describe, it } from 'node:test'
import { Tree, TreeFragment } from '@lezer/common'
import { parser } from '../lib/index.js'
import { compareTree } from './compare-tree.js'
const doc = `* Header
This is a /paragraph/.
Still the same =paragraph=.
#+begin_src js
console.log('hello')
#+end_src
here is a link: [[https://example.com][link text]]
`
const docLength = doc.length
class State {
constructor(doc, tree, fragments) {
this.doc = doc
this.tree = tree
this.fragments = fragments
}
static start(doc) {
const tree = parser.parse(doc)
return new State(doc, tree, TreeFragment.addTree(tree))
}
/**
* @param {ChangeSpec[]} changes
* @param {boolean} reparse
*/
update(changes, reparse = true) {
let changed = [],
doc = this.doc,
off = 0
for (const { from, to = from, insert = '' } of changes) {
doc = doc.slice(0, from) + insert + doc.slice(to)
changed.push({
fromA: from - off,
toA: to - off,
fromB: from,
toB: from + insert.length
})
off += insert.length - (to - from)
}
const fragments = TreeFragment.applyChanges(this.fragments, changed, 2)
if (!reparse) return new State(doc, Tree.empty, fragments)
// return this
const tree = parser.parse(doc, fragments)
return new State(doc, tree, TreeFragment.addTree(tree, fragments))
}
}
// const state1 = State.start(doc)
/**
* @param {ChangeSpec} change
* @param {boolean} [verbose=false]
* @param {number} reuse
*/
function testChange(change, verbose = false, reuse = 10) {
const state1 = State.start(doc)
const state = state1.update(change)
const updatedDoc = state.doc
verbose && console.log('updatedDoc', updatedDoc)
compareTree(state.tree, parser.parse(updatedDoc))
if (reuse) {
const diff = overlap(state.tree, state1.tree)
assert.ok(diff > reuse, `diff: ${diff}`)
}
}
/**
* @param {Tree} a
* @param {Tree} b
*/
function overlap(a, b) {
let inA = new Set(),
shared = 0,
sharingTo = 0
for (let cur = a.cursor(); cur.next(); ) if (cur.tree) inA.add(cur.tree)
for (let cur = b.cursor(); cur.next(); )
if (
cur.tree &&
inA.has(cur.tree) &&
cur.type.is('Block') &&
cur.from >= sharingTo
) {
shared += cur.to - cur.from
sharingTo = cur.to
}
return Math.round((shared * 100) / b.length)
}
describe('incremential parsing', () => {
// it.runOnly(true)
it('can insert in the middle', () => {
testChange([{ from: 2, to: 2, insert: 'bears' }])
})
it('can insert at the begining', () => {
testChange([{ from: 0, to: 0, insert: 'bears' }])
})
it('can handle deletion', () => {
testChange([{ from: 0, to: 5 }])
})
it('can appending at the end', () => {
const size = doc.length
testChange([{ from: size, to: size, insert: '* another heading' }])
})
it('can replace content', () => {
testChange([{ from: 2, to: 8, insert: 'bears' }])
})
it('reuses nodes from the previous parse', () => {
const state1 = State.start(doc)
const state = state1.update([{ from: 2, to: 8, insert: 'bears' }])
const diff = overlap(state1.tree, state.tree)
assert.ok(diff > 90, `diff: ${diff}`)
console.log('hello test')
})
it('can handle deleting a star', () => testChange([{ from: 0, to: 1 }]))
// it('can reuse content for a change in a block context', () => {})
// it('can handle adding to a quoted block', () => {})
// it('can handle a change in a post-linkref paragraph', () => {})
// it('can handle a change in a paragraph-adjacent linkrefs', () => {})
it('can handle insertion at the eof', () =>
testChange([{ from: docLength, to: docLength, insert: '* h' }]))
})
================================================
FILE: packages/lezer/tsconfig.json
================================================
{
"extends": "../../tsconfig.json"
}
================================================
FILE: packages/loader/CHANGELOG.md
================================================
# Change Log
## 4.4.4
### Patch Changes
- bd2365a: fix types and linting
- Updated dependencies [bd2365a]
- @orgajs/orgx@2.6.1
## 4.4.3
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/orgx@2.6.0
## 4.4.2
### Patch Changes
- @orgajs/orgx@2.5.2
## 4.4.1
### Patch Changes
- @orgajs/orgx@2.5.1
## 4.4.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/orgx@2.5.0
## 4.3.2
### Patch Changes
- e3ef3a5: build website with orga-build
- Updated dependencies [e3ef3a5]
- @orgajs/orgx@2.4.1
## 4.3.1
### Patch Changes
- Updated dependencies [351f690]
- @orgajs/orgx@2.4.0
## 4.3.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- Updated dependencies [d8861c2]
- @orgajs/orgx@2.3.0
## 4.2.2
### Patch Changes
- @orgajs/orgx@2.2.2
## 4.2.1
### Patch Changes
- @orgajs/orgx@2.2.1
## 4.2.0
### Minor Changes
- ac322714: implement editor
### Patch Changes
- Updated dependencies [ac322714]
- @orgajs/orgx@2.2.0
## 4.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- @orgajs/orgx@2.1.0
## 4.0.1
### Patch Changes
- Updated dependencies [1dbf674d]
- @orgajs/orgx@2.0.1
## 4.0.0
### Major Changes
- 176a3b5d: # Migrate most of the ecosystem to ESM
We are excited to announce that we have migrated most of our ecosystem to ESM! This move was necessary as the unified ecosystem had already transitioned to ESM, leaving our orgajs system stuck on an older version if we wanted to stay on commonjs. We understand that this transition may come with some inevitable breaking changes, but we have done our best to make it as gentle as possible.
In the past, ESM support in popular frameworks like webpack, gatsby, and nextjs was problematic, but the JS world has steadily moved forward, and we are now in a much better state. We have put in a lot of effort to bring this project up to speed, and we are happy to say that it's in a pretty good state now.
We acknowledge that there are still some missing features that we will gradually add back over time. However, we feel that the changes are now in a great state to be released to the world. If you want to use the new versions, we recommend checking out the `examples` folder to get started.
We understand that this upgrade path may not be compatible with older versions, and we apologize for any inconvenience this may cause. However, we encourage you to consider starting fresh, as the most important part of your site should always be your content (org-mode files). Thank you for your understanding, and we hope you enjoy the new and improved ecosystem!
### Patch Changes
- Updated dependencies [176a3b5d]
- @orgajs/orgx@2.0.0
## 3.1.10
### Patch Changes
- Updated dependencies [eeccc870]
- @orgajs/orgx@1.0.8
## 3.1.9
### Patch Changes
- Updated dependencies [6c1ddb9f]
- @orgajs/orgx@1.0.7
## 3.1.8
### Patch Changes
- 4bde5155: tidy up dependencies
- Updated dependencies [4bde5155]
- @orgajs/orgx@1.0.6
## 3.1.7
### Patch Changes
- @orgajs/orgx@1.0.5
## 3.1.6
### Patch Changes
- @orgajs/orgx@1.0.4
## 3.1.5
### Patch Changes
- Updated dependencies [cd7cac3d]
- @orgajs/orgx@1.0.3
## 3.1.4
### Patch Changes
- Updated dependencies [c8edd571]
- @orgajs/orgx@1.0.2
## 3.1.3
### Patch Changes
- 594bf16b: ## @orgajs/orgx
Introducing new compiler `@orgajs/orgx`. It's a (almost) a direct port of [xdm](https://github.com/wooorm/xdm).
Most of the packages have already adopted `@orgajs/orgx`. The important ones are:
- `@orgajs/loader`
- `@orgajs/next`
- `gatsby-plugin-orga`
- `gatsby-theme-orga-docs`
- `@orgajs/playground'`
`gatsby-transformer-orga` is still using the original compiler, since it has it's own ecosystem which requires some work to do a proper migration. That means the derivative packages around it are using the original compiler.
- `gatsby-theme-orga-posts`
- `gatsby-theme-orga-posts-core`
## theme-ui support
`theme-ui` has `mdx` support builtin, and it's hard to do a clean extraction. So the package `@orgajs/theme-ui` is wrapping theme-ui, and provide orga specific tweaks. For gatsby, `gatsby-plugin-orga-theme-ui` is the equivalent of `gatsby-plugin-theme-ui`, but with orga support.
- Updated dependencies [594bf16b]
- @orgajs/orgx@1.0.1
## 3.1.2
### Patch Changes
- @orgajs/reorg@3.1.1
## 3.1.1
### Patch Changes
- 8c6f440b: - better layout support
- rename MDXxxx to Orgaxxx
## 3.1.0
### Minor Changes
- eeea0c54: introduce new token: empty line
### Patch Changes
- Updated dependencies [eeea0c54]
- @orgajs/reorg@3.1.0
## 3.0.1
### Patch Changes
- 6ed76057: # rename gatsby themes
- gatsby-theme-orga -> gatsby-theme-orga-posts-core
- gatsby-theme-blorg -> gatsby-theme-orga-posts
# add example projects
- gatsby-posts
- gatsby-posts-core
- 759e6149: # Bug Fixes
- fix lexer for parsing headline with todo keyword
- fix properties drawer issue
- fix orga-theme-ui-preset package
- fix gatsby-transformer-orga & gatsby-theme-blorg
# Improved Playground
- add `tokens` view
- show node type in tree views
- Updated dependencies [6ed76057]
- Updated dependencies [759e6149]
- @orgajs/reorg@3.0.1
## 3.0.0
### Major Changes
- 8b02d10: # Features
- more powerful and flexible lexer and parser
- webpack support
- `jsx` support
- better code block rendering
- better image processing in gatsby
- updated examples
- tons of bug fixes
- brand new `gatsby-plugin-orga`
### Patch Changes
- Updated dependencies [8b02d10]
- @orgajs/reorg@3.0.0
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.6.0](https://github.com/orgapp/orgajs/compare/v2.5.0...v2.6.0) (2021-08-28)
### Bug Fixes
- fix examples ([bdcd265](https://github.com/orgapp/orgajs/commit/bdcd2655502a73800e8915ba09fd78452dff503f))
- remove prepublish step individually ([a75a6a9](https://github.com/orgapp/orgajs/commit/a75a6a9606421b66b6ef69b28e3fcb03a5ee282a))
- **website:** better code block ([9d5b3a2](https://github.com/orgapp/orgajs/commit/9d5b3a2d554672d22523727e89b2b5c60dc6233d))
# [2.5.0](https://github.com/orgapp/orgajs/compare/v2.4.9...v2.5.0) (2021-08-27)
### Bug Fixes
- fix examples ([bdcd265](https://github.com/orgapp/orgajs/commit/bdcd2655502a73800e8915ba09fd78452dff503f))
## [2.4.9](https://github.com/orgapp/orgajs/compare/v2.4.8...v2.4.9) (2021-07-13)
**Note:** Version bump only for package @orgajs/loader
## [2.4.8](https://github.com/orgapp/orgajs/compare/v2.4.7...v2.4.8) (2021-04-26)
**Note:** Version bump only for package @orgajs/loader
## [2.4.7](https://github.com/orgapp/orgajs/compare/v2.4.6...v2.4.7) (2021-04-26)
**Note:** Version bump only for package @orgajs/loader
================================================
FILE: packages/loader/LICENSE.org
================================================
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: packages/loader/index.cjs
================================================
// stolen code from @mdx-js/loader
/**
* Webpack loader
*
* @todo once webpack supports ESM loaders, remove this wrapper.
*
* @this {LoaderContext}
* @param {string} code
*/
module.exports = function orgLoader(code) {
const callback = this.async()
// Note that `import()` caches, so this should be fast enough.
import('./lib/index.js').then((module) =>
module.loader.call(this, code, callback)
)
}
================================================
FILE: packages/loader/index.d.ts
================================================
import type { ProcessorOptions } from '@orgajs/orgx'
import type { LoaderContext } from 'webpack'
/**
* A Webpack loader to compile MDX to JavaScript.
*
* [Reference for Loader API](https://webpack.js.org/api/loaders/)
*
* @this {LoaderContext<unknown>}
* @param {string} value
* The original module source code.
* @returns {void}
*/
declare function orgLoader(this: LoaderContext<unknown>, value: string): void
export default orgLoader
export type Options = ProcessorOptions
================================================
FILE: packages/loader/lib/index.js
================================================
/**
* @typedef {import('webpack').LoaderContext<unknown>} LoaderContext
*/
import path from 'node:path'
import { createProcessor } from '@orgajs/orgx'
/**
* @param {string} source
* @param {LoaderContext['callback']} callback
* @this {LoaderContext}
*/
export async function loader(source, callback) {
const processor = createProcessor({
development: this.mode === 'development',
...this.getOptions()
})
try {
const file = await processor.process({
value: source,
path: this.resourcePath
})
callback(undefined, file.value, file.map)
} catch (error) {
const fpath = path.relative(this.context, this.resourcePath)
error.message = `${fpath}:${error.name}: ${error.message}`
callback(error)
}
}
================================================
FILE: packages/loader/package.json
================================================
{
"name": "@orgajs/loader",
"version": "4.4.4",
"description": "Load org-mode content through orga.",
"type": "module",
"main": "./index.cjs",
"types": "index.d.ts",
"files": [
"lib/",
"index.cjs",
"index.d.ts"
],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"homepage": "https://github.com/orgapp/orgajs/tree/main/packages/loader#readme",
"repository": {
"type": "git",
"url": "https://github.com/orgapp/orgajs.git",
"directory": "packages/loader"
},
"scripts": {
"test": "node --test tests/*.test.js"
},
"dependencies": {
"@orgajs/orgx": "workspace:^",
"vfile-reporter": "^8.1.1"
},
"devDependencies": {
"@orgajs/react": "workspace:^",
"@types/node": "^25.3.2",
"babel-loader": "^9.1.3",
"html-loader": "^4.2.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"webpack": "^5.104.1"
}
}
================================================
FILE: packages/loader/tests/compiler.js
================================================
import { promises as fs } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { promisify } from 'node:util'
import webpack from 'webpack'
export async function compile(fixture, options = {}) {
const base = new URL('.', import.meta.url)
const result = await promisify(webpack)({
// @ts-expect-error TODO: webpack types miss support for `context`.
context: fileURLToPath(base),
entry: `./${fixture}`,
mode: 'none',
output: {
path: fileURLToPath(base),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.org$/,
use: [
// {
// loader: 'babel-loader',
// options: {
// configFile: false,
// plugins: [
// '@babel/plugin-transform-runtime',
// '@babel/plugin-syntax-jsx',
// '@babel/plugin-transform-react-jsx',
// ],
// },
// },
{
// loader: path.resolve(__dirname, '../dist'),
loader: fileURLToPath(new URL('../index.cjs', import.meta.url)),
options
}
]
}
]
}
})
// cleanup
await fs.unlink(new URL('bundle.js', base))
return result
}
================================================
FILE: packages/loader/tests/example.md
================================================
# hello world
this is some content.
================================================
FILE: packages/loader/tests/fixture.org
================================================
#+title: hello world
* TODO headline one
#+begin_export jsx
<div style={{ color: 'red' }}>in a box</div>
#+end_export
================================================
FILE: packages/loader/tests/loader.test.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { compile } from './compiler.js'
test('basic org-mode parsing', async () => {
const stats = await compile('fixture.org', {
name: 'Alice'
})
// wait for 3 seconds
await new Promise((resolve) => setTimeout(resolve, 3000))
console.log('after the wait')
const output = `${stats.toJson({ source: true }).modules[0].source}`
assert.equal(
output.trim(),
`
/*@jsxRuntime automatic @jsxImportSource react*/
import {jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
export const title = 'hello world';
function _createOrgContent(props) {
const _components = Object.assign({
div: "div",
h1: "h1"
}, props.components);
return _jsxs(_components.div, {
className: "section",
children: [_jsx(_components.h1, {
children: "headline one"
}), _jsx(_components.div, {
style: {
color: 'red'
},
children: "in a box"
})]
});
}
function OrgContent(props = {}) {
const {wrapper: OrgLayout} = props.components || ({});
return OrgLayout ? _jsx(OrgLayout, {
...props,
children: _jsx(_createOrgContent, {
...props
})
}) : _createOrgContent(props);
}
export default OrgContent;
`.trim()
)
})
================================================
FILE: packages/metadata/CHANGELOG.md
================================================
# @orgajs/metadata
## 2.4.1
### Patch Changes
- bd2365a: fix types and linting
## 2.4.0
### Minor Changes
- a53cfea: all about the editor
This release improves the editor with new fold/shift/todo actions and settings, while also refactoring orga tokenization/parsing and lezer conversion to improve TODO handling, context hashing, and tree generation consistency.
## 2.3.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
## 2.2.0
### Minor Changes
- d8861c2: update unified ecosystem
## 2.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
## 2.0.0
### Major Changes
- 176a3b5d: # Migrate most of the ecosystem to ESM
We are excited to announce that we have migrated most of our ecosystem to ESM! This move was necessary as the unified ecosystem had already transitioned to ESM, leaving our orgajs system stuck on an older version if we wanted to stay on commonjs. We understand that this transition may come with some inevitable breaking changes, but we have done our best to make it as gentle as possible.
In the past, ESM support in popular frameworks like webpack, gatsby, and nextjs was problematic, but the JS world has steadily moved forward, and we are now in a much better state. We have put in a lot of effort to bring this project up to speed, and we are happy to say that it's in a pretty good state now.
We acknowledge that there are still some missing features that we will gradually add back over time. However, we feel that the changes are now in a great state to be released to the world. If you want to use the new versions, we recommend checking out the `examples` folder to get started.
We understand that this upgrade path may not be compatible with older versions, and we apologize for any inconvenience this may cause. However, we encourage you to consider starting fresh, as the most important part of your site should always be your content (org-mode files). Thank you for your understanding, and we hope you enjoy the new and improved ecosystem!
## 1.0.2
### Patch Changes
- eeccc870: - get image links out of paragraph
- some other minor fixes
## 1.0.1
### Patch Changes
- 594bf16b: ## @orgajs/orgx
Introducing new compiler `@orgajs/orgx`. It's a (almost) a direct port of [xdm](https://github.com/wooorm/xdm).
Most of the packages have already adopted `@orgajs/orgx`. The important ones are:
- `@orgajs/loader`
- `@orgajs/next`
- `gatsby-plugin-orga`
- `gatsby-theme-orga-docs`
- `@orgajs/playground'`
`gatsby-transformer-orga` is still using the original compiler, since it has it's own ecosystem which requires some work to do a proper migration. That means the derivative packages around it are using the original compiler.
- `gatsby-theme-orga-posts`
- `gatsby-theme-orga-posts-core`
## theme-ui support
`theme-ui` has `mdx` support builtin, and it's hard to do a clean extraction. So the package `@orgajs/theme-ui` is wrapping theme-ui, and provide orga specific tweaks. For gatsby, `gatsby-plugin-orga-theme-ui` is the equivalent of `gatsby-plugin-theme-ui`, but with orga support.
================================================
FILE: packages/metadata/README.org
================================================
#+title: @orgajs/metadata
================================================
FILE: packages/metadata/index.js
================================================
/**
* @typedef {import('./lib/index.js').Metadata} Metadata
*/
export { parse } from './lib/index.js'
================================================
FILE: packages/metadata/lib/index.js
================================================
/**
* TODO: more types?
* @typedef {string} Value
* @typedef {Record<string, Value | Value[]>} Metadata
*/
const TO_DISCARD = [
'caption',
'header',
'name',
'plot',
'results',
/^attr_\w+/i, // Affiliated Keywords
/^begin_\w+/i,
/^end_\w+/i,
'begin',
'end', // blocks
'call', // call
'jsx' // orga's jsx support
]
/**
* @param {string} key
* @returns {boolean}
*/
function shouldDiscard(key) {
return !!TO_DISCARD.find((test) => {
if (typeof test === 'string') {
return test === key.toLowerCase()
}
return test.test(key)
})
}
/**
* trim whitespaces and strip quotes if necessary
* @param {string} text
* @returns {Value}
*/
function processValue(text) {
return text.trim().replace(/^["'](.+(?=["']$))["']$/, '$1')
}
/**
* @param {Metadata} data
*/
function pushTo(data) {
/**
* @param {string} _key
* @param {string} _value
* @returns {Metadata}
*/
return function (_key, _value) {
const key = _key.toLowerCase()
const value = processValue(_value)
const existing = data[key]
if (existing) {
if (Array.isArray(existing)) {
existing.push(value)
} else {
data[key] = [existing, value]
}
} else {
data[key] = value
}
return data
}
}
/**
* @param {string} text
* @returns {Metadata}
*/
export function parse(text) {
const matches = text.matchAll(/^\s*#\+(\S+):(.*)$/gm)
return [...matches].reduce((data, [, key, value]) => {
if (shouldDiscard(key)) return data
return pushTo(data)(key, value)
}, {})
}
================================================
FILE: packages/metadata/package.json
================================================
{
"name": "@orgajs/metadata",
"version": "2.4.1",
"description": "extract metadata info from org file",
"type": "module",
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"homepage": "https://github.com/orgapp/orgajs/tree/main/packages/metadata#readme",
"repository": {
"type": "git",
"url": "https://github.com/orgapp/orgajs.git",
"directory": "packages/metadata"
},
"files": [
"lib",
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"exports": "./index.js",
"scripts": {
"test": "node --test --no-warnings tests/test.js"
},
"devDependencies": {
"@types/node": "^25.3.2",
"tsx": "^4.19.2",
"typescript": "^5.9.2"
}
}
================================================
FILE: packages/metadata/tests/test.js
================================================
import * as assert from 'node:assert'
import { describe, it } from 'node:test'
import { parse } from '../index.js'
describe('metadata parser', () => {
it('works', () => {
assert.deepEqual(parse('#+title: hello world'), {
title: 'hello world'
})
})
it('can handle multiple entries', () => {
assert.deepEqual(
parse(`
#+include: file1.org
#+include: ../file2.org
`),
{
include: ['file1.org', '../file2.org']
}
)
})
it('can handle spaces at the front', () => {
assert.deepEqual(
parse(`
#+title: orga
#+keywords: parser ast
`),
{
title: 'orga',
keywords: 'parser ast'
}
)
})
it('transform keys to lowercase', () => {
assert.deepEqual(
parse(`
#+TODO: TODO NEXT | DONE
#+todo: DRAFT | PUBLISHED
`),
{
todo: ['TODO NEXT | DONE', 'DRAFT | PUBLISHED']
}
)
})
it('strips quotes if necessary', () => {
assert.deepEqual(
parse(`
#+include: "./file1.org"
#+include: './file2.org'
#+desc: it's good
`),
{
include: ['./file1.org', './file2.org'],
desc: "it's good"
}
)
})
})
================================================
FILE: packages/metadata/tsconfig.json
================================================
{
"extends": "../../tsconfig.json"
}
================================================
FILE: packages/next/README.org
================================================
* @orgajs/next
Next.js integration is now maintained in a standalone repository:
- [[https://github.com/orgapp/orga-next][orgapp/orga-next]]
Package name remains =@orgajs/next=.
For usage and setup instructions, see:
- [[https://github.com/orgapp/orga-next/blob/main/README.org][README.org]]
- [[https://orga.js.org/guides/next][Next.js guide]]
================================================
FILE: packages/node-loader/CHANGELOG.md
================================================
# @orgajs/node-loader
## 1.1.5
### Patch Changes
- bd2365a: fix types and linting
- Updated dependencies [bd2365a]
- @orgajs/orgx@2.6.1
## 1.1.4
### Patch Changes
- Updated dependencies [a53cfea]
- @orgajs/orgx@2.6.0
## 1.1.3
### Patch Changes
- @orgajs/orgx@2.5.2
## 1.1.2
### Patch Changes
- @orgajs/orgx@2.5.1
## 1.1.1
### Patch Changes
- b73e6b3: fix builder
## 1.1.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- @orgajs/orgx@2.5.0
## 1.0.1
### Patch Changes
- Updated dependencies [e3ef3a5]
- @orgajs/orgx@2.4.1
## 1.0.0
### Major Changes
- 351f690: introduce @orgajs/node-loader, @orgajs/esbuild, @orgajs/build
- @orgajs/node-loader : the nodejs loader for org-mode files
- @orgajs/esbuild : esbuild plugin
- @orgajs/build : static site generator, a.k.a orga-build
### Patch Changes
- Updated dependencies [351f690]
- @orgajs/orgx@2.4.0
================================================
FILE: packages/node-loader/index.js
================================================
/**
* @import {LoadFnOutput, LoadHook, LoadHookContext} from 'node:module'
* @import {ProcessorOptions} from '@orgajs/orgx'
*/
/**
* @typedef {Parameters<LoadHook>[2]} NextLoad
* Next.
*
* @typedef {ProcessorOptions} Options
* Configuration.
*
*/
import fs from 'node:fs/promises'
import { createProcessor } from '@orgajs/orgx'
import { SourceMapGenerator } from 'source-map'
import { VFile } from 'vfile'
import { reporter } from 'vfile-reporter'
/**
* Create Node.js hooks to handle org files.
*
* @param {Readonly<Options> | null | undefined} [loaderOptions]
* Configuration (optional).
* @returns
* Node.js hooks.
*/
export function createLoader(loaderOptions) {
let settings = configure(loaderOptions || {})
return { initialize, load }
/**
* @param {Readonly<Options> | null | undefined} options
*/
async function initialize(options) {
settings = configure({ ...loaderOptions, ...options })
}
/**
* Load `file:` URLs to MD(X) files.
*
* @param {string} href
* URL.
* @param {LoadHookContext} context
* Context.
* @param {NextLoad} nextLoad
* Next or default `load` function.
* @returns {Promise<LoadFnOutput>}
* Result.
* @satisfies {LoadHook}
*/
async function load(href, context, nextLoad) {
const url = new URL(href)
const { compile } = settings
if (url.protocol === 'file:' && /.org$/.test(url.pathname)) {
const value = await fs.readFile(url)
const file = await compile(new VFile({ value, path: url }))
if (file.messages.length > 0) {
console.error(reporter(file))
}
let source = String(file)
source +=
'\n//# sourceMappingURL=data:application/json;base64,' +
Buffer.from(JSON.stringify(file.map)).toString('base64') +
'\n'
return {
format: 'module',
shortCircuit: true,
source
}
}
return nextLoad(href, context)
}
}
/**
* @param {Options} options
*/
function configure(options) {
const processor = createProcessor({
development: true,
...options,
SourceMapGenerator
})
/**
* @param {import('vfile').Compatible} file
*/
function compile(file) {
return processor.process(file)
}
return { compile }
}
const defaultLoader = createLoader()
/**
* Pass options to the loader.
*/
export const initialize = defaultLoader.initialize
/**
* Load `file:` URLs to org files.
*/
export const load = defaultLoader.load
================================================
FILE: packages/node-loader/package.json
================================================
{
"name": "@orgajs/node-loader",
"version": "1.1.5",
"description": "",
"type": "module",
"files": [
"lib",
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"exports": "./index.js",
"scripts": {},
"keywords": [],
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/orgapp/orgajs.git",
"directory": "packages/node-loader"
},
"dependencies": {
"@orgajs/orgx": "workspace:^",
"source-map": "^0.7.4",
"vfile": "^6.0.3",
"vfile-reporter": "^8.1.1"
},
"devDependencies": {
"@types/node": "^25.3.2"
}
}
================================================
FILE: packages/oast-to-hast/.projectile
================================================
================================================
FILE: packages/oast-to-hast/CHANGELOG.md
================================================
# Change Log
## 4.5.3
### Patch Changes
- 850bcf9: fix: use native anchor for external links to prevent wouter pushState SecurityError
## 4.5.2
### Patch Changes
- be20652: expose rehypePlugins in orga-build
## 4.5.1
### Patch Changes
- bd2365a: fix types and linting
- Updated dependencies [bd2365a]
- orga@4.7.1
## 4.5.0
### Minor Changes
- 761c484: Preserve inline markup in quote and center blocks.
### Patch Changes
- Updated dependencies [761c484]
- orga@4.7.0
## 4.4.3
### Patch Changes
- 68430c7: fix newline in paragraph
## 4.4.2
### Patch Changes
- d8da621: fix invalid html structure with image/video
## 4.4.1
### Patch Changes
- 20f5a03: fix: render video links as `<video controls>` elements
## 4.4.0
### Minor Changes
- da20dcc: bug fix: correct definition list HTML output
## 4.3.3
### Patch Changes
- Updated dependencies [a53cfea]
- orga@4.6.0
## 4.3.2
### Patch Changes
- Updated dependencies [60ad38f]
- orga@4.5.1
## 4.3.1
### Patch Changes
- 7c3c600: fix react resolve issue
## 4.3.0
### Minor Changes
- 188d30f: - migrate most of modules to js
- fix types during the process
- remove unmaintained modules
### Patch Changes
- Updated dependencies [188d30f]
- orga@4.5.0
## 4.2.0
### Minor Changes
- d8861c2: update unified ecosystem
### Patch Changes
- Updated dependencies [d8861c2]
- orga@4.4.0
## 4.1.3
### Patch Changes
- ab38e4b0: add ability to customize <a>'s target attribute
## 4.1.2
### Patch Changes
- Updated dependencies [7cfff79a]
- orga@4.3.0
## 4.1.1
### Patch Changes
- Updated dependencies [ac322714]
- orga@4.2.0
## 4.1.0
### Minor Changes
- 4d8efbb7: Add increamental parsing ability for the editor.
### Patch Changes
- Updated dependencies [4d8efbb7]
- orga@4.1.0
## 4.0.0
### Major Changes
- 176a3b5d: # Migrate most of the ecosystem to ESM
We are excited to announce that we have migrated most of our ecosystem to ESM! This move was necessary as the unified ecosystem had already transitioned to ESM, leaving our orgajs system stuck on an older version if we wanted to stay on commonjs. We understand that this transition may come with some inevitable breaking changes, but we have done our best to make it as gentle as possible.
In the past, ESM support in popular frameworks like webpack, gatsby, and nextjs was problematic, but the JS world has steadily moved forward, and we are now in a much better state. We have put in a lot of effort to bring this project up to speed, and we are happy to say that it's in a pretty good state now.
We acknowledge that there are still some missing features that we will gradually add back over time. However, we feel that the changes are now in a great state to be released to the world. If you want to use the new versions, we recommend checking out the `examples` folder to get started.
We understand that this upgrade path may not be compatible with older versions, and we apologize for any inconvenience this may cause. However, we encourage you to consider starting fresh, as the most important part of your site should always be your content (org-mode files). Thank you for your understanding, and we hope you enjoy the new and improved ecosystem!
### Patch Changes
- Updated dependencies [176a3b5d]
- orga@4.0.0
## 3.2.1
### Patch Changes
- eeccc870: - get image links out of paragraph
- some other minor fixes
- Updated dependencies [eeccc870]
- orga@3.2.1
## 3.2.0
### Minor Changes
- 6c1ddb9f: add latex support
### Patch Changes
- Updated dependencies [6c1ddb9f]
- orga@3.2.0
## 3.1.6
### Patch Changes
- Updated dependencies [4bde5155]
- orga@3.1.5
## 3.1.5
### Patch Changes
- ae83a3b0: - affiliated keyword support for list
- `HTML_CONTAINER_CLASS` support in properties drawer
- remove complex regex from inline parsing
- Updated dependencies [ae83a3b0]
- orga@3.1.4
## 3.1.4
### Patch Changes
- Updated dependencies [09a3b5c6]
- orga@3.1.3
## 3.1.3
### Patch Changes
- Updated dependencies [594bf16b]
- orga@3.1.2
## 3.1.2
### Patch Changes
- 19156b8a: inject props into layout
- Updated dependencies [19156b8a]
- orga@3.1.1
## 3.1.1
### Patch Changes
- 7f209ff5: oast-to-hast: add `all` function to context
## 3.1.0
### Minor Changes
- eeea0c54: introduce new token: empty line
### Patch Changes
- Updated dependencies [eeea0c54]
- orga@3.1.0
## 3.0.1
### Patch Changes
- 6ed76057: # rename gatsby themes
- gatsby-theme-orga -> gatsby-theme-orga-posts-core
- gatsby-theme-blorg -> gatsby-theme-orga-posts
# add example projects
- gatsby-posts
- gatsby-posts-core
- 759e6149: # Bug Fixes
- fix lexer for parsing headline with todo keyword
- fix properties drawer issue
- fix orga-theme-ui-preset package
- fix gatsby-transformer-orga & gatsby-theme-blorg
# Improved Playground
- add `tokens` view
- show node type in tree views
- Updated dependencies [6ed76057]
- Updated dependencies [759e6149]
- orga@3.0.1
## 3.0.0
### Major Changes
- 8b02d10: # Features
- more powerful and flexible lexer and parser
- webpack support
- `jsx` support
- better code block rendering
- better image processing in gatsby
- updated examples
- tons of bug fixes
- brand new `gatsby-plugin-orga`
### Patch Changes
- Updated dependencies [8b02d10]
- orga@3.0.0
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.6.0](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/compare/v2.5.0...v2.6.0) (2021-08-28)
### Bug Fixes
- remove prepublish step individually ([a75a6a9](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/commit/a75a6a9606421b66b6ef69b28e3fcb03a5ee282a))
- **website:** better code block ([9d5b3a2](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/commit/9d5b3a2d554672d22523727e89b2b5c60dc6233d))
### Features
- add jsx support ([0d22499](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/commit/0d224990b412e064ebf6816608eea6766f93d60c))
# [2.5.0](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/compare/v2.4.9...v2.5.0) (2021-08-27)
### Features
- add jsx support ([0d22499](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/commit/0d224990b412e064ebf6816608eea6766f93d60c))
## [2.4.9](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/compare/v2.4.8...v2.4.9) (2021-07-13)
**Note:** Version bump only for package oast-to-hast
## [2.4.8](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/compare/v2.4.7...v2.4.8) (2021-04-26)
**Note:** Version bump only for package oast-to-hast
## [2.4.7](https://github.com/orgapp/orgajs/tree/master/packages/oast-to-hast/compare/v2.4.6...v2.4.7) (2021-04-26)
**Note:** Version bump only for package oast-to-hast
================================================
FILE: packages/oast-to-hast/LICENSE.org
================================================
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: packages/oast-to-hast/index.js
================================================
/**
* @typedef {import('./lib/index.js').Options} Options
*/
export { handlers as defaultHandlers } from './lib/handlers/index.js'
export { toHast, toHast as default } from './lib/index.js'
================================================
FILE: packages/oast-to-hast/lib/handlers/block.js
================================================
import { parseHtml } from './html.js'
/**
* @param {import('../state.js').State} state
* @param {import('orga').Block} node
* @returns {import('hast').Element|undefined}
*/
export function block(state, node) {
const name = node.name.toLowerCase()
/**
* Preserve inline markup for block types whose content is parsed into
* block children by orga. Fallback to the raw value for externally-provided
* trees that omit `children`.
*/
const parsedChildren = state.all(node)
if (name === 'src') {
const lang = node.params?.[0]
? `language-${node.params[0]}`
: 'language-undefined'
return state.patch(node, {
type: 'element',
tagName: 'pre',
properties: {},
children: [
{
type: 'element',
tagName: 'code',
properties: { className: [lang] },
children: [
{
type: 'text',
value: node.value
}
]
}
]
})
}
if (name === 'quote') {
return state.patch(node, {
type: 'element',
tagName: 'blockquote',
properties: {},
children:
parsedChildren.length > 0
? parsedChildren
: [
{
type: 'text',
value: node.value
}
]
})
}
if (name === 'center') {
return state.patch(node, {
type: 'element',
tagName: 'center',
properties: {},
children:
parsedChildren.length > 0
? parsedChildren
: [
{
type: 'text',
value: node.value
}
]
})
}
if (name === 'export') {
if (node.params[0].toLowerCase() === 'html') {
return state.patch(node, parseHtml(node.value))
}
return {
// @ts-expect-error: this is a special passthrough
type: (node.params[0] || 'raw').toLowerCase(),
value: node.value
}
}
if (name === 'comment') {
return undefined
}
return state.patch(node, {
type: 'element',
tagName: 'pre',
properties: { className: [name] },
children: [
{
type: 'text',
value: node.value
}
]
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/document.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').Document} node
* @returns {import('hast').Root}
*/
export function document(state, node) {
return {
type: 'root',
data: node.properties,
children: state.all(node)
}
}
================================================
FILE: packages/oast-to-hast/lib/handlers/footnote.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').FootnoteReference} node
* @returns {import('hast').Element}
*/
export function footnoteRef(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'sup',
properties: { id: `fnref-${node.label}` },
children: [
{
type: 'element',
tagName: 'a',
properties: { href: `#fn-${node.label}` },
children: [{ type: 'text', value: node.label }]
}
]
})
}
/**
* @param {import('../state.js').State} state
* @param {import('orga').Footnote} node
* @returns {import('hast').Element}
*/
export function footnote(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'div',
properties: {
id: `fn-${node.label}`,
className: ['footnote'],
dataLabel: node.label
},
children: state.all(node)
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/headline.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').Headline} node
* @returns {import('hast').Element}
*/
export function headline(state, node) {
return state.patch(node, {
type: 'element',
tagName: `h${node.level}`,
properties: {},
children: state.all(node)
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/hr.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').HorizontalRule} node
* @returns {import('hast').Element}
*/
export function hr(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'hr',
properties: {},
children: []
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/html.js
================================================
import { fromHtml } from 'hast-util-from-html'
/**
* @param {import('../state.js').State} state
* @param {import('orga').HTML} node
* @returns {import('hast').Element}
*/
export function html(state, node) {
return state.patch(node, parseHtml(node.value))
}
/**
* @param {string} html
* @returns {import('hast').Element}
*/
export function parseHtml(html) {
const hast = fromHtml(html, { fragment: true })
/** @type {import('hast').Element} */
const result = {
type: 'element',
tagName: 'div',
properties: {},
children: []
}
hast.children.forEach((child) => {
if (
child.type === 'element' ||
child.type === 'text' ||
child.type === 'comment'
) {
result.children.push(child)
}
})
return result
}
================================================
FILE: packages/oast-to-hast/lib/handlers/index.js
================================================
import { block } from './block.js'
import { document } from './document.js'
import { footnote, footnoteRef } from './footnote.js'
import { headline } from './headline.js'
import { hr } from './hr.js'
import { html } from './html.js'
import { keyword } from './keyword.js'
import { latex } from './latex.js'
import { link } from './link.js'
import { checkbox, list, item as listItem } from './list.js'
import { newline } from './newline.js'
import { paragraph } from './paragraph.js'
import { section } from './section.js'
import {
table,
cell as tableCell,
hr as tableHr,
row as tableRow
} from './table.js'
import { text } from './text.js'
/**
* Default handlers for nodes.
*
* @satisfies {import('../state.js').Handlers}
*/
export const handlers = {
document,
keyword,
headline,
section,
paragraph,
text,
block,
latex,
link,
list,
'list.item': listItem,
'list.item.tag': ignore,
'list.item.bullet': ignore,
'list.item.checkbox': checkbox,
'link.path': ignore,
table,
'table.row': tableRow,
'table.cell': tableCell,
'table.hr': tableHr,
html,
jsx: passThrough,
drawer: ignore,
priority: ignore,
planning: ignore,
footnote,
'footnote.reference': footnoteRef,
hr,
newline
}
/** @type {import('../state.js').Handler} */
function ignore() {
return undefined
}
/** @type {import('../state.js').Handler} */
function passThrough(_, node) {
return node
}
================================================
FILE: packages/oast-to-hast/lib/handlers/keyword.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').Keyword} node
* @returns {import('hast').Element|undefined}
*/
export function keyword(state, node) {
if (node.key.toLowerCase() === 'select_tags') {
const tags = node.value
.split(',')
.map((tag) => tag.trim())
.filter(Boolean)
state.options.selectTags = tags
}
return undefined
}
================================================
FILE: packages/oast-to-hast/lib/handlers/latex.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').Latex} node
* @returns {import('hast').Element}
*/
export function latex(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'div',
properties: { className: ['math-display'] },
children: [
{
type: 'text',
value: node.value
}
]
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/link.js
================================================
/**
* @import { Element } from 'hast'
*/
import mime from 'mime'
/**
* @param {import('../state.js').State} state
* @param {import('orga').Link} node
* @returns {Element}
*/
export function link(state, node) {
const type = mime.getType(node.path.value)
if (type?.startsWith('image')) {
/** @type {Element} */
const image = {
type: 'element',
tagName: 'img',
properties: {
src: node.path.value,
target: state.options.linkTarget
},
children: []
}
/** @type {Element|null} */
let cap = null
const c = node.attributes.caption
if (c) {
cap = {
type: 'element',
tagName: 'figcaption',
properties: {},
children: [
{
type: 'text',
value: `${c}`
}
]
}
} else if (node.children.length > 0) {
cap = {
type: 'element',
tagName: 'figcaption',
properties: {},
children: state.all(node)
}
}
if (cap) {
return state.patch(node, {
type: 'element',
tagName: 'figure',
properties: {},
children: [image, cap]
})
}
return state.patch(node, image)
}
if (type?.startsWith('video')) {
/** @type {Element} */
const video = {
type: 'element',
tagName: 'video',
properties: {
src: node.path.value,
controls: true
},
children: []
}
/** @type {Element|null} */
let cap = null
const c = node.attributes.caption
if (c) {
cap = {
type: 'element',
tagName: 'figcaption',
properties: {},
children: [
{
type: 'text',
value: `${c}`
}
]
}
} else if (node.children.length > 0) {
cap = {
type: 'element',
tagName: 'figcaption',
properties: {},
children: state.all(node)
}
}
if (cap) {
return state.patch(node, {
type: 'element',
tagName: 'figure',
properties: {},
children: [video, cap]
})
}
return state.patch(node, video)
}
return state.patch(node, {
type: 'element',
tagName: 'a',
properties: {
href: state.options.linkHref(node),
target: state.options.linkTarget
},
children: state.all(node)
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/list.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').List} node
* @returns {import('hast').Element}
*/
export function list(state, node) {
let tagName = node.ordered ? 'ol' : 'ul'
if (node.children.every((i) => i.type !== 'list.item' || i.tag)) {
tagName = 'dl'
}
const properties = state.getAttrHtml(node)
return state.patch(node, {
type: 'element',
tagName: tagName,
properties: properties ?? {},
children: state.all(node)
})
}
/**
* @param {import('../state.js').State} state
* @param {import('orga').ListItem} node
* @param {import('orga').Parent | undefined} parent
* @returns {import('hast').ElementContent | import('hast').ElementContent[]}
*/
export function item(state, node, parent) {
if (node.tag) {
/** @type {import('hast').Element[]} */
const dtdd = [
{
type: 'element',
tagName: 'dt',
properties: {},
children: [{ type: 'text', value: node.tag }]
},
{
type: 'element',
tagName: 'dd',
properties: {},
children: state.all(node)
}
]
const allTagged = parent?.children?.every(
(i) => i.type !== 'list.item' || i.tag
)
if (allTagged) {
// Pure definition list: return [<dt>, <dd>] to be flattened into <dl>
return dtdd
}
// Definition item inside a mixed list: wrap in <li><dl>…</dl></li>
return state.patch(node, {
type: 'element',
tagName: 'li',
properties: {},
children: [
{
type: 'element',
tagName: 'dl',
properties: {},
children: dtdd
}
]
})
}
return state.patch(node, {
type: 'element',
tagName: 'li',
properties: {},
children: state.all(node)
})
}
/**
* @param {import('../state.js').State} state
* @param {import('orga').ListItemCheckbox} node
* @returns {import('hast').Element}
*/
export function checkbox(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'input',
properties: {
type: 'checkbox',
checked: node.checked,
disabled: true
},
children: []
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/newline.js
================================================
/**
* @param {import('../state.js').State} _state
* @param {import('orga').Newline} _node
* @param {import('orga').Parent | undefined} parent
* @returns {import('hast').Text | undefined}
*/
export function newline(_state, _node, parent) {
// In Org paragraphs, a single source newline is a soft break. For HTML
// output, normalize it to a space so text remains readable.
if (parent?.type === 'paragraph') {
return { type: 'text', value: ' ' }
}
return undefined
}
================================================
FILE: packages/oast-to-hast/lib/handlers/paragraph.js
================================================
/**
* Block-level HTML elements that are not allowed as descendants of <p>.
* When a paragraph contains any of these, we must avoid wrapping in <p>.
*
* @see https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element
*/
const BLOCK_TAGS = new Set([
'address',
'article',
'aside',
'blockquote',
'details',
'dialog',
'dd',
'div',
'dl',
'dt',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'header',
'hgroup',
'hr',
'li',
'main',
'nav',
'ol',
'p',
'pre',
'section',
'summary',
'table',
'ul'
])
/**
* @param {import('../state.js').State} state
* @param {import('orga').Paragraph} node
* @returns {import('hast').Element}
*/
export function paragraph(state, node) {
const properties = state.getAttrHtml(node)
const children = state.all(node)
// If any child is a block-level element (e.g. a <figure> from a media link
// with caption), wrapping in <p> produces invalid HTML and causes hydration
// errors in React. Unwrap single block children; use <div> for mixed content.
const hasBlock = children.some(
(child) =>
child.type === 'element' &&
BLOCK_TAGS.has(/** @type {import('hast').Element} */ (child).tagName)
)
if (hasBlock) {
if (children.length === 1) {
return /** @type {import('hast').Element} */ (children[0])
}
return state.patch(node, {
type: 'element',
tagName: 'div',
properties: properties ?? {},
children
})
}
return state.patch(node, {
type: 'element',
tagName: 'p',
properties: properties ?? {},
children
})
}
================================================
FILE: packages/oast-to-hast/lib/handlers/section.js
================================================
/**
* @param {import('../state.js').State} state
* @param {import('orga').Section} node
* @returns {import('hast').Element|undefined}
*/
export function section(state, node) {
const headline = node.children.find((n) => n.type === 'headline')
if (headline) {
if (shouldSkip(state.options, headline.tags || [])) {
return undefined
}
}
let className = 'section'
const drawer = node.children.find((n) => n.type === 'drawer')
if (drawer && drawer.name === 'PROPERTIES') {
const lines = drawer.value.split('\n')
lines.forEach((line) => {
const m = line.match(/:(\w+):(.*)$/)
if (m && m[1].toUpperCase() === 'HTML_CONTAINER_CLASS') {
className = `${className} ${m[2].trim()}`
}
})
}
return state.patch(node, {
type: 'element',
tagName: 'div',
properties: { className: className.split(/\s+/).filter(Boolean) },
children: state.all(node)
})
}
/**
* @param {import('../state.js').Config} config
* @param {string[]} tags
* @returns {boolean}
*/
function shouldSkip({ selectTags = [], excludeTags = [] }, tags) {
if (selectTags.length > 0) {
return !tags.some((tag) => selectTags.includes(tag))
}
if (excludeTags.length > 0) {
return tags.some((tag) => excludeTags.includes(tag))
}
return false
}
================================================
FILE: packages/oast-to-hast/lib/handlers/table.js
================================================
/**
* @import {Element,ElementContent} from 'hast'
* @import {Table,TableCell,TableRow} from 'orga'
* @import {State} from '../state.js'
*/
/**
* @param {State} state
* @param {Table} node
* @returns {Element}
*/
export function table(state, node) {
const rows = state.all(node)
const hrIndex = rows.findIndex(
(row) => row.type === 'element' && row.tagName === 'hr'
)
/** @type {ElementContent[]} */
const headRows = []
/** @type {ElementContent[]} */
const bodyRows = []
rows.forEach((row, i) => {
if (i < hrIndex) {
headRows.push(row)
} else if (i > hrIndex) {
bodyRows.push(row)
}
})
/** @type {ElementContent[]} */
const tableContent = []
if (headRows.length > 0) {
tableContent.push({
type: 'element',
tagName: 'thead',
properties: {},
children: headRows
})
}
if (bodyRows.length > 0) {
tableContent.push({
type: 'element',
tagName: 'tbody',
properties: {},
children: bodyRows
})
}
const caption = node.attributes.caption
if (caption) {
tableContent.push({
type: 'element',
tagName: 'caption',
properties: {},
children: [{ type: 'text', value: `${caption}` }]
})
}
return state.patch(node, {
type: 'element',
tagName: 'table',
properties: {},
children: tableContent
})
}
/**
* @param {State} state
* @param {TableRow} node
* @returns {Element}
*/
export function row(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'tr',
properties: {},
children: state.all(node)
})
}
/**
* @param {State} state
* @param {TableCell} node
* @returns {Element}
*/
export function cell(state, node) {
return state.patch(node, {
type: 'element',
tagName: 'td',
properties: {},
children: state.all(node)
})
}
/**
* @returns {Element}
*/
export function hr() {
return {
type: 'element',
tagName: 'hr',
properties: {},
children: []
}
}
================================================
FILE: packages/oast-to-hast/lib/handlers/text.js
================================================
/**
* @import {Element,Text} from 'hast'
*
*/
const wrapper = {
bold: 'strong',
italic: 'i',
code: 'code',
verbatim: 'code',
underline: 'u',
strikeThrough: 'del',
math: 'span'
}
/**
* @param {import('../state.js').State} state
* @param {import('orga').Text} node
* @returns {Element|Text}
*/
export function text(state, node) {
/** @type {Element|Text} */
let e = {
type: 'text',
value: node.value
}
if (node.style) {
e = {
type: 'element',
tagName: wrapper[node.style],
properties: {},
children: [e]
}
if (node.style === 'math') {
e.properties.className = ['math-inline']
}
}
return state.patch(node, e)
}
================================================
FILE: packages/oast-to-hast/lib/index.js
================================================
/**
* @typedef {import('hast').Nodes} HastNodes
* @typedef {import('orga').Nodes} OastNodes
* @typedef {Partial<import('./state.js').Config> | null | undefined} Options
*/
import { createState } from './state.js'
/**
* @param {OastNodes} tree
* oast tree.
* @param {Options} [options]
* Configuration (optional).
* @returns {HastNodes}
* hast tree.
*/
export function toHast(tree, options = {}) {
const state = createState(tree, options)
const node = state.one(tree)
if (Array.isArray(node)) {
return { type: 'root', children: node }
}
// if (tree.type === 'document') {
// return {
// type: 'root',
// data: tree.properties,
// children: node ? [node] : [],
// }
// }
return node || { type: 'root', children: [] }
}
================================================
FILE: packages/oast-to-hast/lib/state.js
================================================
/**
* @typedef {import('hast').Nodes} HastNodes
@import {ElementContent as HastElementContent,Root as HastRoot} from 'hast'
* @typedef {import('orga').Parent} OastParent
* @typedef {import('orga').Nodes} OastNodes
*/
/**
* @typedef {Object} Config
* @property {Handlers} handlers
* @property {string} linkTarget
* @property {(link: import('orga').Link) => string} linkHref
* @property {string[]} selectTags=[]
* @property {string[]} excludeTags=['noexport']
*/
/**
* @typedef {ReturnType<typeof createState>} State
*
* @callback Handler
* @param {State} state
* @param {any} node
* @param {OastParent | undefined} parent
* @returns {Array<HastElementContent> | HastElementContent | HastRoot | undefined}
* hast node.
*
* @typedef {Partial<Record<OastNodes['type'], Handler>>} Handlers
* Handle nodes.
*/
import { position } from 'unist-util-position'
import { handlers as defaultHandlers } from './handlers/index.js'
/**
* @param {OastNodes} _tree
* @param {Partial<Config> | null | undefined} [options = {}]
*/
export function createState(_tree, options = {}) {
/** @type {Handlers} */
let handlers = { ...defaultHandlers }
if (options?.handlers) {
handlers = { ...handlers, ...options.handlers }
}
const state = {
one,
all,
handlers,
getAttrHtml,
patch,
/** @type {Config} */
options: {
handlers,
linkTarget: '_self',
selectTags: [],
excludeTags: ['noexport'],
linkHref: defaultLinkHref,
...options
}
}
return state
/**
* @param {OastNodes} parent
* @returns {Array<HastElementContent>}
*/
function all(parent) {
/** @type {Array<HastElementContent>} */
const values = []
if ('children' in parent) {
parent.children.forEach((node) => {
const result = one(node, parent)
if (!result) {
return
}
if (Array.isArray(result)) {
values.push(...result)
} else {
// @ts-expect-error: can never be Root here
values.push(result)
}
})
}
return values
}
/**
* @param {OastNodes} node
* @param {OastParent | undefined} parent
*/
function one(node, parent = undefined) {
const handle = handlers[node.type] || unkownHandler
return handle(state, node, parent)
}
/**
* @param {OastNodes} node
* @returns {Record<string, string> | undefined}
*/
function getAttrHtml(node) {
if ('properties' in node && 'attr_html' in node.properties) {
const a = node.properties.attr_html
if (typeof a === 'string') return
if (Array.isArray(a)) return
return a
}
}
/**
* @template {HastNodes} T
* @param {OastNodes} from
* @param {T} to
* @returns {T}
*/
function patch(from, to) {
if (from.position) {
to.position = position(from)
}
return to
}
}
/**
* @param {import('orga').Link} link
* @returns {string}
*/
function defaultLinkHref(link) {
const protocol = link.path.protocol
if (!protocol || protocol === 'internal' || protocol === 'file') {
return link.path.value
}
if (protocol === 'http' || protocol === 'https') {
return link.path.value
}
return `${protocol}:${link.path.value}`
}
/** @type {Handler} */
function unkownHandler(state, node) {
if (node?.children) {
return {
type: 'element',
tagName: 'div',
properties: {},
children: state.all(node)
}
} else if ('value' in node) {
return { type: 'text', value: `${node.value}` }
}
return undefined
}
================================================
FILE: packages/oast-to-hast/package.json
================================================
{
"name": "oast-to-hast",
"version": "4.5.3",
"description": "Transform OAST to HAST",
"files": [
"lib",
"index.js",
"index.d.ts",
"index.d.ts.map"
],
"exports": "./index.js",
"type": "module",
"author": "Xiaoxing Hu <hi@xiaoxing.dev>",
"license": "MIT",
"repository": "https://github.com/orgapp/orgajs/tree/main/packages/oast-to-hast",
"dependencies": {
"hast-util-from-html": "^2.0.3",
"mime": "^3.0.0",
"orga": "workspace:^",
"parse5": "^7.1.2",
"unist-util-position": "^5.0.0"
},
"scripts": {
"test": "node --test tests/*.js"
},
"devDependencies": {
"@types/hast": "^3.0.4",
"@types/mime": "^3.0.1",
"@types/unist": "^3.0.3",
"hastscript": "^9.0.0"
}
}
================================================
FILE: packages/oast-to-hast/tests/block.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { h } from 'hastscript'
import { parse } from 'orga'
import { toHast } from '../index.js'
test('quote block preserves inline markup', () => {
const oast = parse(`#+BEGIN_QUOTE
Be *bold*, and if you must, be /italic/.
#+END_QUOTE
`)
const hast = removePosition(toHast(oast))
assert.deepEqual(hast, {
type: 'root',
data: {},
children: [
h('blockquote', [
'Be ',
h('strong', 'bold'),
', and if you must, be ',
h('i', 'italic'),
'.'
])
]
})
})
function removePosition(node) {
if (!node || typeof node !== 'object') return node
if (Array.isArray(node)) return node.map(removePosition)
const result = {}
for (const [key, value] of Object.entries(node)) {
if (key === 'position') continue
result[key] = removePosition(value)
}
return result
}
================================================
FILE: packages/oast-to-hast/tests/classname.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { parse } from 'orga'
import { toHast } from '../index.js'
test('src blocks emit code.className as token array', () => {
const oast = parse(`#+begin_src javascript
console.log('ok')
#+end_src`)
const hast = toHast(oast)
const code = hast.children[0]?.children?.[0]
assert.deepEqual(code?.tagName, 'code')
assert.deepEqual(code?.properties?.className, ['language-javascript'])
})
test('sections emit div.className as token array', () => {
const oast = parse(`* Heading
:PROPERTIES:
:HTML_CONTAINER_CLASS: foo bar
:END:
Body`)
const hast = toHast(oast)
const section = hast.children[0]
assert.deepEqual(section?.tagName, 'div')
assert.deepEqual(section?.properties?.className, ['section', 'foo', 'bar'])
})
================================================
FILE: packages/oast-to-hast/tests/heading.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { h } from 'hastscript'
import { toHast } from '../index.js'
test('heading', async () => {
const hast = toHast({
type: 'headline',
level: 3,
children: [{ type: 'text', value: 'Hello' }]
})
assert.deepEqual(hast, h('h3', 'Hello'))
})
================================================
FILE: packages/oast-to-hast/tests/list.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { h } from 'hastscript'
import { toHast } from '../index.js'
test('regular unordered list', () => {
const hast = toHast({
type: 'list',
ordered: false,
indent: 0,
children: [
{
type: 'list.item',
indent: 0,
children: [{ type: 'text', value: 'item one' }]
},
{
type: 'list.item',
indent: 0,
children: [{ type: 'text', value: 'item two' }]
}
]
})
assert.deepEqual(hast, h('ul', [h('li', 'item one'), h('li', 'item two')]))
})
test('pure definition list produces <dl> with flat <dt>/<dd> pairs (no <div> wrapper)', () => {
const hast = toHast({
type: 'list',
ordered: false,
indent: 0,
children: [
{
type: 'list.item',
indent: 0,
tag: 'word',
children: [{ type: 'text', value: 'description.' }]
},
{
type: 'list.item',
indent: 0,
tag: 'another',
children: [{ type: 'text', value: 'definition.' }]
}
]
})
assert.deepEqual(
hast,
h('dl', [
h('dt', 'word'),
h('dd', 'description.'),
h('dt', 'another'),
h('dd', 'definition.')
])
)
})
test('pure definition list followed by a paragraph still produces <dl>', () => {
// The parser appends a trailing newline node as a child of the list when
// followed by a blank line + paragraph. It must not be mistaken for a
// non-tagged item.
const hast = toHast({
type: 'list',
ordered: false,
indent: 0,
children: [
{
type: 'list.item',
indent: 0,
tag: 'hello',
children: [{ type: 'text', value: 'this is greeting.' }]
},
{
type: 'list.item',
indent: 0,
tag: 'world',
children: [{ type: 'text', value: 'this is the world.' }]
},
{ type: 'newline' }
]
})
assert.deepEqual(
hast,
h('dl', [
h('dt', 'hello'),
h('dd', 'this is greeting.'),
h('dt', 'world'),
h('dd', 'this is the world.')
])
)
})
test('mixed list wraps definition items as <li><dl><dt>/<dd></dl></li>', () => {
const hast = toHast({
type: 'list',
ordered: false,
indent: 0,
children: [
{
type: 'list.item',
indent: 0,
children: [{ type: 'text', value: 'item one' }]
},
{
type: 'list.item',
indent: 0,
tag: 'word',
children: [{ type: 'text', value: 'definition goes here.' }]
}
]
})
assert.deepEqual(
hast,
h('ul', [
h('li', 'item one'),
h('li', [h('dl', [h('dt', 'word'), h('dd', 'definition goes here.')])])
])
)
})
================================================
FILE: packages/oast-to-hast/tests/paragraph.js
================================================
import * as assert from 'node:assert'
import test from 'node:test'
import { h } from 'hastscript'
import { toHast } from '../index.js'
test('paragraph with text', async () => {
const hast = toHast({
type: 'paragraph',
children: [{ type: 'text', value: 'Hello' }]
})
assert.deepEqual(hast, h('p', 'Hello'))
})
test('paragraph newline is rendered as a space', async () => {
const hast = toHast({
type: 'paragraph',
children: [
{ type: 'text', value: 'foo' },
{ type: 'newline' },
{ type: 'text', value: 'bar' }
]
})
assert.deepEqual(hast, h('p', ['foo', ' ', 'bar']))
})
test('paragraph mailto link keeps protocol in href', async () => {
const hast = toHast({
type: 'paragraph',
children: [
{
type: 'link',
path: { protocol: 'mailto', val
gitextract_ms15wv5a/ ├── .changeset/ │ ├── README.md │ └── config.json ├── .editorconfig ├── .eslintignore ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ ├── ci.yml │ ├── release.yml │ └── website.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── CONTRIBUTING.org ├── LICENSE.org ├── README.org ├── biome.json ├── docs/ │ ├── .gitignore │ ├── _components.tsx │ ├── _layout.tsx │ ├── _snippets/ │ │ └── hey.org │ ├── advanced/ │ │ ├── _layout.tsx │ │ ├── api.org │ │ ├── ast.org │ │ ├── index.org │ │ └── latex.org │ ├── contribute.org │ ├── guides/ │ │ ├── _layout.tsx │ │ ├── astro.org │ │ ├── gatsby.org │ │ ├── index.org │ │ ├── next.org │ │ ├── orga-build.org │ │ └── webpack.org │ ├── index.org │ ├── playground.tsx │ ├── style.css │ └── tsconfig.json ├── examples/ │ ├── README.org │ ├── build/ │ │ ├── index.org │ │ ├── more.org │ │ ├── package.json │ │ └── test-content.tsx │ ├── editor/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── content.org │ │ ├── index.html │ │ ├── package.json │ │ ├── src/ │ │ │ ├── main.ts │ │ │ └── style.css │ │ └── tsconfig.json │ ├── getting-started/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── index.js │ │ └── package.json │ └── webpack/ │ ├── .babelrc │ ├── CHANGELOG.md │ ├── README.org │ ├── package.json │ ├── public/ │ │ └── index.html │ ├── src/ │ │ ├── box.js │ │ ├── hello.org │ │ └── index.js │ └── webpack.config.mjs ├── orga.config.js ├── package.json ├── packages/ │ ├── astro/ │ │ └── README.org │ ├── codemirror-lang/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── editor/ │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── actions/ │ │ │ │ ├── fold.js │ │ │ │ ├── shift.js │ │ │ │ ├── todo.js │ │ │ │ └── utils.js │ │ │ ├── editor.js │ │ │ ├── extensions/ │ │ │ │ └── cleanup.js │ │ │ ├── settings.js │ │ │ ├── setup.js │ │ │ └── theme.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── esbuild/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ └── package.json │ ├── lezer/ │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── context.js │ │ │ ├── fragments.js │ │ │ ├── handlers.js │ │ │ ├── index.js │ │ │ ├── nodes.js │ │ │ ├── oast-to-lezer.js │ │ │ ├── tree.js │ │ │ └── types.ts │ │ ├── package.json │ │ ├── tests/ │ │ │ ├── compare-tree.js │ │ │ └── incremental.test.js │ │ └── tsconfig.json │ ├── loader/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── index.cjs │ │ ├── index.d.ts │ │ ├── lib/ │ │ │ └── index.js │ │ ├── package.json │ │ └── tests/ │ │ ├── compiler.js │ │ ├── example.md │ │ ├── fixture.org │ │ └── loader.test.js │ ├── metadata/ │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── index.js │ │ ├── lib/ │ │ │ └── index.js │ │ ├── package.json │ │ ├── tests/ │ │ │ └── test.js │ │ └── tsconfig.json │ ├── next/ │ │ └── README.org │ ├── node-loader/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ └── package.json │ ├── oast-to-hast/ │ │ ├── .projectile │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── handlers/ │ │ │ │ ├── block.js │ │ │ │ ├── document.js │ │ │ │ ├── footnote.js │ │ │ │ ├── headline.js │ │ │ │ ├── hr.js │ │ │ │ ├── html.js │ │ │ │ ├── index.js │ │ │ │ ├── keyword.js │ │ │ │ ├── latex.js │ │ │ │ ├── link.js │ │ │ │ ├── list.js │ │ │ │ ├── newline.js │ │ │ │ ├── paragraph.js │ │ │ │ ├── section.js │ │ │ │ ├── table.js │ │ │ │ └── text.js │ │ │ ├── index.js │ │ │ └── state.js │ │ ├── package.json │ │ ├── tests/ │ │ │ ├── block.js │ │ │ ├── classname.js │ │ │ ├── heading.js │ │ │ ├── list.js │ │ │ └── paragraph.js │ │ └── tsconfig.json │ ├── oast-to-prose/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── handlers/ │ │ │ │ ├── block.js │ │ │ │ ├── headline.js │ │ │ │ ├── index.js │ │ │ │ ├── link.js │ │ │ │ ├── newline.js │ │ │ │ ├── paragraph.js │ │ │ │ ├── section.js │ │ │ │ ├── stars.js │ │ │ │ ├── tags.js │ │ │ │ ├── text.js │ │ │ │ └── todo.js │ │ │ ├── index.js │ │ │ ├── schema.js │ │ │ └── state.js │ │ ├── package.json │ │ ├── tests/ │ │ │ └── text.js │ │ └── tsconfig.json │ ├── orga/ │ │ ├── .projectile │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── README.org │ │ ├── package.json │ │ ├── src/ │ │ │ ├── __tests__/ │ │ │ │ ├── block/ │ │ │ │ │ ├── affiliated keyword.json │ │ │ │ │ ├── affiliated keyword.org │ │ │ │ │ ├── export.json │ │ │ │ │ ├── export.org │ │ │ │ │ ├── missing begin.json │ │ │ │ │ ├── missing begin.org │ │ │ │ │ ├── missing end.json │ │ │ │ │ ├── missing end.org │ │ │ │ │ ├── standard.json │ │ │ │ │ └── standard.org │ │ │ │ ├── footnote/ │ │ │ │ │ ├── multiline.json │ │ │ │ │ ├── multiline.org │ │ │ │ │ ├── standard.json │ │ │ │ │ ├── standard.org │ │ │ │ │ ├── stopped by empty lines.json │ │ │ │ │ ├── stopped by empty lines.org │ │ │ │ │ ├── stopped by footnote.json │ │ │ │ │ ├── stopped by footnote.org │ │ │ │ │ ├── stopped by headline.json │ │ │ │ │ ├── stopped by headline.org │ │ │ │ │ ├── with block.json │ │ │ │ │ └── with block.org │ │ │ │ ├── headline/ │ │ │ │ │ ├── broken drawer.json │ │ │ │ │ ├── broken drawer.org │ │ │ │ │ ├── drawers.json │ │ │ │ │ ├── drawers.org │ │ │ │ │ ├── keyword.json │ │ │ │ │ ├── keyword.org │ │ │ │ │ ├── nested.json │ │ │ │ │ ├── nested.org │ │ │ │ │ ├── planning.json │ │ │ │ │ ├── planning.org │ │ │ │ │ ├── with tags.json │ │ │ │ │ └── with tags.org │ │ │ │ ├── hr/ │ │ │ │ │ ├── standard.json │ │ │ │ │ └── standard.org │ │ │ │ ├── index.test.ts │ │ │ │ ├── keyword/ │ │ │ │ │ ├── multiple todo.json │ │ │ │ │ ├── multiple todo.org │ │ │ │ │ ├── other.json │ │ │ │ │ ├── other.org │ │ │ │ │ ├── todo.json │ │ │ │ │ └── todo.org │ │ │ │ ├── latex/ │ │ │ │ │ ├── does not match.json │ │ │ │ │ ├── does not match.org │ │ │ │ │ ├── latex block.json │ │ │ │ │ ├── latex block.org │ │ │ │ │ ├── missing begin.json │ │ │ │ │ ├── missing begin.org │ │ │ │ │ ├── missing end.json │ │ │ │ │ └── missing end.org │ │ │ │ ├── list/ │ │ │ │ │ ├── broken by empty line.json │ │ │ │ │ ├── broken by empty line.org │ │ │ │ │ ├── descriptive.json │ │ │ │ │ ├── descriptive.org │ │ │ │ │ ├── multiline.json │ │ │ │ │ ├── multiline.org │ │ │ │ │ ├── nested.json │ │ │ │ │ ├── nested.org │ │ │ │ │ ├── ordered.json │ │ │ │ │ ├── ordered.org │ │ │ │ │ ├── unordered.json │ │ │ │ │ └── unordered.org │ │ │ │ ├── paragraph/ │ │ │ │ │ ├── anonymous footnote.json │ │ │ │ │ ├── anonymous footnote.org │ │ │ │ │ ├── footnote reference at the end.json │ │ │ │ │ ├── footnote reference at the end.org │ │ │ │ │ ├── footnote refernece in the middle.json │ │ │ │ │ ├── footnote refernece in the middle.org │ │ │ │ │ ├── footnote without body.json │ │ │ │ │ ├── footnote without body.org │ │ │ │ │ ├── inline footnote with style.json │ │ │ │ │ ├── inline footnote with style.org │ │ │ │ │ ├── inline footnote.json │ │ │ │ │ ├── inline footnote.org │ │ │ │ │ ├── inline math.json │ │ │ │ │ ├── inline math.org │ │ │ │ │ ├── link with style.json │ │ │ │ │ ├── link with style.org │ │ │ │ │ ├── link.json │ │ │ │ │ ├── link.org │ │ │ │ │ ├── nested footnote.json │ │ │ │ │ ├── nested footnote.org │ │ │ │ │ ├── styled text.json │ │ │ │ │ └── styled text.org │ │ │ │ └── table/ │ │ │ │ ├── standard.json │ │ │ │ ├── standard.org │ │ │ │ ├── with inline styles.json │ │ │ │ └── with inline styles.org │ │ │ ├── index.ts │ │ │ ├── nodes.ts │ │ │ ├── options.ts │ │ │ ├── parse/ │ │ │ │ ├── _parseSymbols.ts │ │ │ │ ├── _primitive.ts │ │ │ │ ├── _utils.ts │ │ │ │ ├── block.ts │ │ │ │ ├── context.ts │ │ │ │ ├── drawer.ts │ │ │ │ ├── footnote.ts │ │ │ │ ├── headline.ts │ │ │ │ ├── index.ts │ │ │ │ ├── keyword.ts │ │ │ │ ├── latex.ts │ │ │ │ ├── list.ts │ │ │ │ ├── paragraph.ts │ │ │ │ ├── phrasing.ts │ │ │ │ ├── planning.ts │ │ │ │ ├── section.ts │ │ │ │ └── table.ts │ │ │ ├── position.ts │ │ │ ├── timestamp.test.ts │ │ │ ├── timestamp.ts │ │ │ ├── todo.test.ts │ │ │ ├── todo.ts │ │ │ ├── tokenize/ │ │ │ │ ├── __tests__/ │ │ │ │ │ ├── debug.ts │ │ │ │ │ └── tok.ts │ │ │ │ ├── blank.test.ts │ │ │ │ ├── block.test.ts │ │ │ │ ├── block.ts │ │ │ │ ├── comment.test.ts │ │ │ │ ├── comment.ts │ │ │ │ ├── drawer.test.ts │ │ │ │ ├── drawer.ts │ │ │ │ ├── empty.ts │ │ │ │ ├── footnote.test.ts │ │ │ │ ├── footnote.ts │ │ │ │ ├── headline.test.ts │ │ │ │ ├── headline.ts │ │ │ │ ├── hr.test.ts │ │ │ │ ├── hr.ts │ │ │ │ ├── index.ts │ │ │ │ ├── inline/ │ │ │ │ │ ├── footnote.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── link.ts │ │ │ │ │ ├── math.ts │ │ │ │ │ └── text.ts │ │ │ │ ├── inline.test.ts │ │ │ │ ├── keyword.ts │ │ │ │ ├── keywords.test.ts │ │ │ │ ├── latex.ts │ │ │ │ ├── list.test.ts │ │ │ │ ├── list.ts │ │ │ │ ├── partial.test.ts │ │ │ │ ├── planning.test.ts │ │ │ │ ├── planning.ts │ │ │ │ ├── table.test.ts │ │ │ │ └── table.ts │ │ │ ├── types.ts │ │ │ ├── uri.test.ts │ │ │ ├── uri.ts │ │ │ └── utils.ts │ │ └── tsconfig.json │ ├── orga-build/ │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── cli.js │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── __tests__/ │ │ │ │ └── build.test.js │ │ │ ├── app.jsx │ │ │ ├── build.js │ │ │ ├── components.js │ │ │ ├── config.js │ │ │ ├── content.d.ts │ │ │ ├── csr.jsx │ │ │ ├── endpoint.js │ │ │ ├── files.js │ │ │ ├── fs.js │ │ │ ├── index.html │ │ │ ├── orga.js │ │ │ ├── plugin.js │ │ │ ├── serve.js │ │ │ ├── ssr.jsx │ │ │ ├── util.js │ │ │ ├── vite.js │ │ │ └── watch.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── orgx/ │ │ ├── CHANGELOG.md │ │ ├── README.org │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── compile.js │ │ │ ├── core.js │ │ │ ├── evaluate.js │ │ │ ├── plugin/ │ │ │ │ ├── recma-build-jsx-transform.js │ │ │ │ ├── recma-document.js │ │ │ │ ├── recma-jsx-rewrite.js │ │ │ │ └── rehype-recma.js │ │ │ ├── run.js │ │ │ ├── types.ts │ │ │ └── util/ │ │ │ ├── estree-util-create.js │ │ │ ├── estree-util-declaration-to-expression.js │ │ │ ├── estree-util-is-declaration.js │ │ │ ├── estree-util-specifiers-to-declarations.js │ │ │ ├── estree-util-to-binary-addition.js │ │ │ ├── estree-util-to-id-or-member-expression.js │ │ │ ├── is-org-content.js │ │ │ ├── render-error.js │ │ │ ├── resolve-evaluate-options.js │ │ │ └── resolve-file-and-options.js │ │ ├── package.json │ │ ├── tests/ │ │ │ ├── compile.test.js │ │ │ └── evaluate.test.js │ │ └── tsconfig.json │ ├── react/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── index.js │ │ ├── package.json │ │ ├── tests/ │ │ │ ├── remove-export-keywords.js │ │ │ └── test.tsx │ │ └── tsconfig.json │ ├── react-cm/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ └── package.json │ ├── react-editor/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── reorg/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── README.org │ │ ├── index.js │ │ └── package.json │ ├── reorg-parse/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── README.org │ │ ├── index.d.ts │ │ ├── index.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── reorg-prose/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ ├── lib/ │ │ │ └── index.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── reorg-rehype/ │ │ ├── .projectile │ │ ├── CHANGELOG.md │ │ ├── LICENSE.org │ │ ├── index.js │ │ ├── package.json │ │ └── tsconfig.json │ ├── rollup/ │ │ ├── CHANGELOG.md │ │ ├── index.js │ │ ├── package.json │ │ ├── test.js │ │ └── tsconfig.json │ └── text-kit/ │ ├── CHANGELOG.md │ ├── README.md │ ├── index.js │ ├── lib/ │ │ ├── core.js │ │ ├── reader.js │ │ └── utils/ │ │ ├── index.js │ │ ├── lines.js │ │ └── substring.js │ ├── package.json │ ├── tests/ │ │ ├── core.js │ │ └── lines.js │ └── tsconfig.json ├── pnpm-workspace.yaml ├── shell.nix ├── tsconfig.base.json ├── tsconfig.esm.json ├── tsconfig.json └── tsconfig.packages.json
SYMBOL INDEX (340 symbols across 118 files)
FILE: docs/_components.tsx
function Notice (line 13) | function Notice({
function JSEditor (line 137) | function JSEditor({
function OrgEditor (line 160) | function OrgEditor({ className = '', content, onChange }) {
FILE: docs/_layout.tsx
type LayoutProps (line 24) | interface LayoutProps {
function Layout (line 35) | function Layout({ children }: LayoutProps) {
type Page (line 84) | type Page = {
function findParentSlug (line 91) | function findParentSlug(slug: string, pages: Page[]): string | null {
function renderMenu (line 101) | function renderMenu(path: string, pages: Page[]) {
function DocumentLayout (line 122) | function DocumentLayout({ title, pages = [], children }) {
function Content (line 134) | function Content({ children }: { children: ReactNode }) {
FILE: docs/playground.tsx
function Playground (line 11) | function Playground() {
FILE: examples/build/test-content.tsx
function TestContent (line 3) | function TestContent() {
FILE: packages/codemirror-lang/index.js
function getHeadlineLevel (line 20) | function getHeadlineLevel(node) {
function findSectionEnd (line 32) | function findSectionEnd(headerNode) {
function mkLang (line 97) | function mkLang(parser) {
function org (line 101) | function org() {
FILE: packages/editor/lib/actions/fold.js
function toggleFold (line 22) | function toggleFold(view) {
function findFold (line 42) | function findFold(state, from, to) {
function toggleFoldAll (line 53) | function toggleFoldAll(view) {
FILE: packages/editor/lib/actions/shift.js
function shift (line 17) | function shift(delta, recursive = false) {
function _shift (line 74) | function _shift(node, delta) {
function getHeadline (line 99) | function getHeadline(tree, pos) {
FILE: packages/editor/lib/actions/todo.js
function toggleTodo (line 13) | function toggleTodo(view) {
FILE: packages/editor/lib/actions/utils.js
function selectedLines (line 9) | function selectedLines(view) {
function getTodo (line 23) | function getTodo(tree, pos) {
function getNode (line 33) | function getNode(tree, pos, type) {
FILE: packages/editor/lib/editor.js
function makeEditor (line 21) | function makeEditor(config) {
FILE: packages/editor/lib/extensions/cleanup.js
function overlap (line 19) | function overlap(a, b) {
function cleanup (line 26) | function cleanup(options) {
function hide (line 87) | function hide(reveal) {
function todo (line 96) | function todo(actionable) {
function createDecorations (line 109) | function createDecorations(view, options) {
FILE: packages/editor/lib/settings.js
method create (line 16) | create(state) {
method update (line 19) | update(value, tr) {
function extractSettings (line 31) | function extractSettings(state) {
FILE: packages/esbuild/index.js
function esbuild (line 23) | function esbuild(options) {
FILE: packages/lezer/lib/context.js
function parseContext (line 21) | function parseContext(config, input, _fragments, ranges) {
FILE: packages/lezer/lib/fragments.js
function fragmentCursor (line 27) | function fragmentCursor({ log, nodeSet }, fragments, input) {
function toRelative (line 190) | function toRelative(abs, ranges) {
FILE: packages/lezer/lib/index.js
class OrgParser (line 18) | class OrgParser extends Parser {
method constructor (line 23) | constructor(nodeSet, log = () => {}) {
method createParse (line 35) | createParse(input, fragments, ranges) {
method configure (line 51) | configure(config) {
FILE: packages/lezer/lib/oast-to-lezer.js
function createParseState (line 26) | function createParseState(file, nodeSet) {
function toLezer (line 49) | function toLezer(tree, nodeSet, file = null) {
function defaultUnknownHandler (line 62) | function defaultUnknownHandler() {
function getRange (line 71) | function getRange(node) {
function one (line 84) | function one(state, node, parent, base = 0) {
function all (line 133) | function all(state, parent, base) {
FILE: packages/lezer/lib/tree.js
function hash (line 11) | function hash(type, value, parentHash = 0) {
function treeBuilder (line 23) | function treeBuilder(
FILE: packages/lezer/lib/types.ts
type OastNode (line 6) | type OastNode = Document | Content | Token
type Action (line 8) | type Action = boolean
type Seed (line 10) | type Seed =
type LezerChild (line 20) | interface LezerChild {
type Handler (line 25) | type Handler = (
type State (line 31) | interface State {
FILE: packages/lezer/tests/compare-tree.js
function compareTree (line 11) | function compareTree(a, b) {
function print (line 40) | function print(tree, prefix = '') {
FILE: packages/lezer/tests/incremental.test.js
class State (line 23) | class State {
method constructor (line 24) | constructor(doc, tree, fragments) {
method start (line 30) | static start(doc) {
method update (line 39) | update(changes, reparse = true) {
function testChange (line 68) | function testChange(change, verbose = false, reuse = 10) {
function overlap (line 85) | function overlap(a, b) {
FILE: packages/loader/index.d.ts
type Options (line 18) | type Options = ProcessorOptions
FILE: packages/loader/lib/index.js
function loader (line 13) | async function loader(source, callback) {
FILE: packages/loader/tests/compiler.js
function compile (line 6) | async function compile(fixture, options = {}) {
FILE: packages/metadata/lib/index.js
constant TO_DISCARD (line 7) | const TO_DISCARD = [
function shouldDiscard (line 26) | function shouldDiscard(key) {
function processValue (line 40) | function processValue(text) {
function pushTo (line 47) | function pushTo(data) {
function parse (line 75) | function parse(text) {
FILE: packages/node-loader/index.js
function createLoader (line 29) | function createLoader(loaderOptions) {
function configure (line 85) | function configure(options) {
FILE: packages/oast-to-hast/lib/handlers/block.js
function block (line 8) | function block(state, node) {
FILE: packages/oast-to-hast/lib/handlers/document.js
function document (line 6) | function document(state, node) {
FILE: packages/oast-to-hast/lib/handlers/footnote.js
function footnoteRef (line 6) | function footnoteRef(state, node) {
function footnote (line 27) | function footnote(state, node) {
FILE: packages/oast-to-hast/lib/handlers/headline.js
function headline (line 6) | function headline(state, node) {
FILE: packages/oast-to-hast/lib/handlers/hr.js
function hr (line 6) | function hr(state, node) {
FILE: packages/oast-to-hast/lib/handlers/html.js
function html (line 8) | function html(state, node) {
function parseHtml (line 16) | function parseHtml(html) {
FILE: packages/oast-to-hast/lib/handlers/index.js
function ignore (line 59) | function ignore() {
function passThrough (line 64) | function passThrough(_, node) {
FILE: packages/oast-to-hast/lib/handlers/keyword.js
function keyword (line 6) | function keyword(state, node) {
FILE: packages/oast-to-hast/lib/handlers/latex.js
function latex (line 6) | function latex(state, node) {
FILE: packages/oast-to-hast/lib/handlers/link.js
function link (line 12) | function link(state, node) {
FILE: packages/oast-to-hast/lib/handlers/list.js
function list (line 6) | function list(state, node) {
function item (line 28) | function item(state, node, parent) {
function checkbox (line 84) | function checkbox(state, node) {
FILE: packages/oast-to-hast/lib/handlers/newline.js
function newline (line 7) | function newline(_state, _node, parent) {
FILE: packages/oast-to-hast/lib/handlers/paragraph.js
constant BLOCK_TAGS (line 7) | const BLOCK_TAGS = new Set([
function paragraph (line 49) | function paragraph(state, node) {
FILE: packages/oast-to-hast/lib/handlers/section.js
function section (line 6) | function section(state, node) {
function shouldSkip (line 40) | function shouldSkip({ selectTags = [], excludeTags = [] }, tags) {
FILE: packages/oast-to-hast/lib/handlers/table.js
function table (line 12) | function table(state, node) {
function row (line 74) | function row(state, node) {
function cell (line 88) | function cell(state, node) {
function hr (line 100) | function hr() {
FILE: packages/oast-to-hast/lib/handlers/text.js
function text (line 21) | function text(state, node) {
FILE: packages/oast-to-hast/lib/index.js
function toHast (line 17) | function toHast(tree, options = {}) {
FILE: packages/oast-to-hast/lib/state.js
function createState (line 38) | function createState(_tree, options = {}) {
function defaultLinkHref (line 128) | function defaultLinkHref(link) {
function unkownHandler (line 140) | function unkownHandler(state, node) {
FILE: packages/oast-to-hast/tests/block.js
function removePosition (line 30) | function removePosition(node) {
FILE: packages/oast-to-prose/lib/handlers/block.js
function block (line 10) | function block(state, node) {
FILE: packages/oast-to-prose/lib/handlers/headline.js
function headline (line 10) | function headline(state, node) {
FILE: packages/oast-to-prose/lib/handlers/link.js
function link (line 10) | function link(state, node) {
FILE: packages/oast-to-prose/lib/handlers/newline.js
function newline (line 9) | function newline(state) {
FILE: packages/oast-to-prose/lib/handlers/paragraph.js
function paragraph (line 10) | function paragraph(state, node) {
FILE: packages/oast-to-prose/lib/handlers/section.js
function section (line 10) | function section(state, node) {
FILE: packages/oast-to-prose/lib/handlers/stars.js
function stars (line 10) | function stars(state, node) {
FILE: packages/oast-to-prose/lib/handlers/tags.js
function tags (line 10) | function tags(state, node) {
FILE: packages/oast-to-prose/lib/handlers/text.js
function text (line 10) | function text(state, node) {
FILE: packages/oast-to-prose/lib/handlers/todo.js
function todo (line 10) | function todo(state, node) {
FILE: packages/oast-to-prose/lib/index.js
function toProse (line 37) | function toProse(tree, file, options) {
FILE: packages/oast-to-prose/lib/schema.js
method toDOM (line 11) | toDOM() {
method toDOM (line 29) | toDOM(node) {
method toDOM (line 40) | toDOM(node) {
method toDOM (line 54) | toDOM(node) {
method toDOM (line 66) | toDOM() {
method toDOM (line 74) | toDOM() {
method getAttrs (line 93) | getAttrs(dom) {
method toDOM (line 102) | toDOM(node) {
method toDOM (line 110) | toDOM() {
method toDOM (line 118) | toDOM() {
method toDOM (line 128) | toDOM(node) {
FILE: packages/oast-to-prose/lib/state.js
function createParseState (line 36) | function createParseState(file, options) {
function defaultUnknownHandler (line 95) | function defaultUnknownHandler(state, node, file) {
function getRawContent (line 122) | function getRawContent(node, file) {
FILE: packages/orga-build/lib/__tests__/build.test.js
function markCodeBlocks (line 12) | function markCodeBlocks() {
FILE: packages/orga-build/lib/app.jsx
function SmartLink (line 6) | function SmartLink({ href, ...props }) {
function App (line 13) | function App() {
FILE: packages/orga-build/lib/build.js
function build (line 21) | async function build(
FILE: packages/orga-build/lib/config.js
function loadConfig (line 34) | async function loadConfig(...files) {
FILE: packages/orga-build/lib/content.d.ts
type ContentEntry (line 2) | interface ContentEntry {
FILE: packages/orga-build/lib/endpoint.js
function resolveEndpointResponse (line 15) | async function resolveEndpointResponse(
FILE: packages/orga-build/lib/files.js
function getFileExtension (line 34) | function getFileExtension(filePath) {
function getContentPath (line 44) | function getContentPath(slug) {
function getContentId (line 71) | function getContentId(slug) {
function setup (line 91) | function setup(dir, { outDir, exclude = [] } = {}) {
function cache (line 281) | function cache(fn) {
function getSlugFromContentFilePath (line 304) | function getSlugFromContentFilePath(contentFilePath) {
function getPageSlugFromFilePath (line 328) | function getPageSlugFromFilePath(filePath) {
function getEndpointRouteFromFilePath (line 339) | function getEndpointRouteFromFilePath(filePath) {
function assertUniqueRoute (line 362) | function assertUniqueRoute(routeOwners, route, sourceType, filePath) {
FILE: packages/orga-build/lib/fs.js
function resolvePath (line 9) | function resolvePath(rootPath) {
function exists (line 27) | async function exists(path) {
function emptyDir (line 40) | async function emptyDir(dir) {
function ensureDir (line 57) | async function ensureDir(path) {
function copy (line 71) | async function copy(src, dest) {
FILE: packages/orga-build/lib/orga.js
function setupOrga (line 15) | function setupOrga({ containerClass, root, rehypePlugins = [] }) {
function mediaAssets (line 28) | function mediaAssets() {
function rehypeWrap (line 64) | function rehypeWrap({ className = [] }) {
function rewriteOrgFileLinks (line 95) | function rewriteOrgFileLinks({ root }) {
function resolveOrgHrefToContentSlug (line 127) | function resolveOrgHrefToContentSlug({ root, filePath, href }) {
function genId (line 144) | function genId(length = 8) {
FILE: packages/orga-build/lib/plugin.js
function orgaBuildPlugin (line 42) | function orgaBuildPlugin({
function createOrgaBuildConfig (line 64) | function createOrgaBuildConfig({
function hasUserIndexHtml (line 103) | async function hasUserIndexHtml(root) {
function htmlFallbackPlugin (line 126) | function htmlFallbackPlugin(projectRoot, styles = []) {
FILE: packages/orga-build/lib/serve.js
function serve (line 12) | async function serve(config, port = 3000, projectRoot = process.cwd()) {
FILE: packages/orga-build/lib/ssr.jsx
function render (line 13) | function render(url) {
FILE: packages/orga-build/lib/util.js
function buildNav (line 4) | function buildNav() {}
function match (line 11) | function match(file, ...patterns) {
function DefaultLayout (line 27) | function DefaultLayout({ title, children }) {
function escapeHtml (line 49) | function escapeHtml(str) {
function $ (line 60) | async function $(cmd) {
FILE: packages/orga-build/lib/vite.js
function pluginFactory (line 20) | function pluginFactory({ dir, outDir, styles = [], exclude = [] }) {
FILE: packages/orga-build/lib/watch.js
function watch (line 8) | async function watch(dir, ignore, onChange) {
FILE: packages/orga/src/__tests__/index.test.ts
function removeUndefined (line 38) | function removeUndefined(obj: any) {
FILE: packages/orga/src/index.ts
function makeParser (line 31) | function makeParser(text: string, options: Partial<Options> = {}) {
function getSettings (line 43) | function getSettings(text: string): Settings {
function getTodo (line 78) | function getTodo(settings: Settings) {
FILE: packages/orga/src/options.ts
type LexerOptions (line 5) | interface LexerOptions {
type ParserOptions (line 11) | interface ParserOptions {
type Options (line 17) | interface Options {
FILE: packages/orga/src/parse/_utils.ts
constant COMMON_IMAGE_EXTENSIONS (line 1) | const COMMON_IMAGE_EXTENSIONS = [
FILE: packages/orga/src/parse/context.ts
function initialProperties (line 19) | function initialProperties(settings: Properties | undefined): Properties {
type Snapshot (line 25) | interface Snapshot {
type Context (line 32) | interface Context {
function point (line 62) | function point(d: Point): Point {
function createContext (line 66) | function createContext(lexer: Lexer, options: ParserOptions): Context {
FILE: packages/orga/src/parse/index.ts
type Parse (line 16) | type Parse = (lexer: Lexer) => Parent | undefined
type FlowControl (line 23) | type FlowControl = 'break' | 'next' | 'finish'
type Action (line 25) | type Action = (
type Predicate (line 30) | type Predicate = string | 'EOF' | RegExp | ((token: Node) => boolean)
function test (line 32) | function test(node: Node, predicate: Predicate) {
function not (line 36) | function not(test: Predicate): Predicate {
function toFunc (line 40) | function toFunc(test: Predicate): (token: Node) => boolean {
type Rule (line 55) | type Rule = { test: Predicate | Predicate[]; action: Action | Handler }
type Handler (line 57) | interface Handler {
type Parser (line 102) | interface Parser {
function parser (line 109) | function parser(lexer: Lexer, options: ParserOptions): Parser {
FILE: packages/orga/src/parse/keyword.ts
constant AFFILIATED_KEYWORDS (line 6) | const AFFILIATED_KEYWORDS = ['caption', 'header', 'name', 'plot', 'resul...
FILE: packages/orga/src/todo.ts
type TodoKeywordSet (line 1) | interface TodoKeywordSet {
type TodoManager (line 10) | interface TodoManager extends TodoKeywordSet {
function parseTodoKeywords (line 25) | function parseTodoKeywords(value: string): TodoKeywordSet {
function todoManager (line 70) | function todoManager(...keywords: string[]): TodoManager {
FILE: packages/orga/src/tokenize/index.ts
constant PLANNING_KEYWORDS (line 20) | const PLANNING_KEYWORDS = ['DEADLINE', 'SCHEDULED', 'CLOSED']
type Lexer (line 22) | interface Lexer {
type Tokenizer (line 39) | type Tokenizer = (reader: Reader) => Token[] | Token | undefined
function tok (line 69) | function tok(): Token[] {
method eatAll (line 121) | eatAll(type: string): number {
method match (line 128) | match(cond, _offset = 0) {
method all (line 137) | all(_max: number | undefined = undefined): Token[] {
method restore (line 149) | restore(point) {
method now (line 155) | get now() {
method todo (line 161) | get todo() {
FILE: packages/orga/src/tokenize/inline/index.ts
constant ALL (line 9) | const ALL: Tokenizer[] = [
FILE: packages/orga/src/tokenize/inline/text.ts
constant MARKERS (line 5) | const MARKERS: { [key: string]: Style } = {
FILE: packages/orga/src/types.ts
type Literal (line 7) | interface Literal extends UnistLiteral {
type Parent (line 11) | interface Parent extends UnistParent {
type Primitive (line 15) | type Primitive = string | number | boolean
type Attributes (line 17) | interface Attributes {
type Attributed (line 21) | interface Attributed {
type Timestamp (line 25) | interface Timestamp {
type Properties (line 30) | type Properties = Record<string, PropertyValue>
type Settings (line 31) | type Settings = Record<string, PropertyValue>
type PropertyValue (line 33) | type PropertyValue = string | string[] | Record<string, string>
type Nodes (line 35) | type Nodes = Document | Content | Token
type Document (line 38) | interface Document extends Parent {
type Section (line 44) | interface Section extends Parent {
type BlockContent (line 52) | type BlockContent =
type TopLevelContent (line 66) | type TopLevelContent = BlockContent | Keyword | Footnote
type Content (line 68) | type Content =
type Footnote (line 76) | interface Footnote extends Parent {
type Block (line 81) | interface Block extends Literal, Attributed {
type Latex (line 88) | interface Latex extends Literal {
type Drawer (line 93) | interface Drawer extends Literal {
type Planning (line 98) | interface Planning extends Node {
type ListContent (line 104) | type ListContent = ListItem | List
type List (line 106) | interface List extends Parent, Attributed {
type TableContent (line 113) | type TableContent = TableRow | TableRule
type Table (line 115) | interface Table extends Parent, Attributed {
type TableRow (line 120) | interface TableRow extends Parent {
type TableCell (line 125) | interface TableCell extends Parent {
type ListItem (line 130) | interface ListItem extends Parent {
type Headline (line 137) | interface Headline extends Parent {
type Paragraph (line 147) | interface Paragraph extends Parent, Attributed {
type HTML (line 152) | interface HTML extends Literal {
type JSX (line 156) | interface JSX extends Literal {
type Token (line 161) | type Token =
type PhrasingContent (line 190) | type PhrasingContent =
type HorizontalRule (line 199) | interface HorizontalRule extends Node {
type Newline (line 203) | interface Newline extends Node {
type EmptyLine (line 207) | interface EmptyLine extends Node {
type Style (line 211) | type Style =
type Text (line 220) | interface Text extends Literal {
type Link (line 225) | interface Link extends Parent, Attributed {
type LinkPath (line 231) | interface LinkPath extends Literal {
type Enclosed (line 237) | type Enclosed = Style | 'link' | 'footnote.reference'
type Opening (line 239) | interface Opening extends Node {
type Closing (line 244) | interface Closing extends Node {
type FootnoteReference (line 268) | interface FootnoteReference extends Parent {
type Stars (line 275) | interface Stars extends Node {
type Todo (line 280) | interface Todo extends Node {
type Priority (line 286) | interface Priority extends Literal {
type Tags (line 290) | interface Tags extends Node {
type BlockBegin (line 296) | interface BlockBegin extends Node {
type BlockEnd (line 302) | interface BlockEnd extends Node {
type DrawerBegin (line 308) | interface DrawerBegin extends Node {
type DrawerEnd (line 313) | interface DrawerEnd extends Node {
type LatexBegin (line 317) | interface LatexBegin extends Node {
type LatexEnd (line 322) | interface LatexEnd extends Node {
type Comment (line 327) | interface Comment extends Literal {
type Keyword (line 331) | interface Keyword extends Node {
type FootnoteLabel (line 337) | interface FootnoteLabel extends Node {
type PlanningKeyword (line 342) | interface PlanningKeyword extends Literal {
type PlanningTimestamp (line 346) | interface PlanningTimestamp extends UnistLiteral {
type ListItemTag (line 351) | interface ListItemTag extends Literal {
type ListItemCheckbox (line 355) | interface ListItemCheckbox extends Node {
type ListItemBullet (line 360) | interface ListItemBullet extends Node {
type TableRule (line 366) | interface TableRule extends Node {
type TableColumnSeparator (line 370) | interface TableColumnSeparator extends Node {
function isSection (line 374) | function isSection(node: Node): node is Section {
function isParagraph (line 378) | function isParagraph(node: Node): node is Paragraph {
function isLink (line 382) | function isLink(node: Node): node is Link {
function isFootnoteReference (line 386) | function isFootnoteReference(node: Node): node is FootnoteReference {
function isText (line 390) | function isText(node: Node): node is Text {
type Data (line 395) | interface Data {
FILE: packages/orga/src/uri.ts
constant URL_PATTERN (line 1) | const URL_PATTERN = /(?:([a-z][a-z0-9+.-]*):)?(.*)/i
type LinkInfo (line 3) | interface LinkInfo {
FILE: packages/orgx/lib/compile.js
function compile (line 35) | function compile(vfileCompatible, compileOptions) {
function compileSync (line 54) | function compileSync(vfileCompatible, compileOptions) {
FILE: packages/orgx/lib/core.js
function createProcessor (line 58) | function createProcessor(options) {
FILE: packages/orgx/lib/evaluate.js
function evaluate (line 22) | async function evaluate(vfileCompatible, evaluateOptions) {
function evaluateSync (line 38) | function evaluateSync(vfileCompatible, evaluateOptions) {
FILE: packages/orgx/lib/plugin/recma-build-jsx-transform.js
function recmaBuildJsxTransform (line 24) | function recmaBuildJsxTransform(options) {
FILE: packages/orgx/lib/plugin/recma-document.js
function recmaDocument (line 64) | function recmaDocument(options) {
FILE: packages/orgx/lib/plugin/recma-jsx-rewrite.js
function recmaJsxRewrite (line 66) | function recmaJsxRewrite(options) {
function createImportProvider (line 562) | function createImportProvider(providerImportSource, outputFormat) {
function isNamedFunction (line 593) | function isNamedFunction(node, name) {
function inScope (line 602) | function inScope(scope, id) {
FILE: packages/orgx/lib/plugin/rehype-recma.js
function rehypeRecma (line 20) | function rehypeRecma(options) {
function isProgram (line 67) | function isProgram(node) {
function parse (line 74) | function parse(code) {
function removeQuotes (line 122) | function removeQuotes(text) {
function createExport (line 131) | function createExport(k, v) {
FILE: packages/orgx/lib/run.js
function run (line 14) | async function run(file, options) {
function runSync (line 28) | function runSync(file, options) {
FILE: packages/orgx/lib/types.ts
type FunctionComponent (line 1) | type FunctionComponent<Props> = (props: Props) => React.JSX.Element | null
type ClassComponent (line 2) | type ClassComponent<Props> = new (props: Props) => React.JSX.ElementClass
type Component (line 3) | type Component<Props> =
type NestedOrgComponents (line 8) | interface NestedOrgComponents {
type OrgComponents (line 12) | type OrgComponents = NestedOrgComponents & {
type OrgProps (line 23) | interface OrgProps {
type OrgContent (line 36) | type OrgContent = (props: OrgProps) => React.JSX.Element
type OrgModule (line 38) | interface OrgModule {
FILE: packages/orgx/lib/util/estree-util-create.js
function create (line 13) | function create(from, to) {
FILE: packages/orgx/lib/util/estree-util-declaration-to-expression.js
function declarationToExpression (line 18) | function declarationToExpression(declaration) {
FILE: packages/orgx/lib/util/estree-util-is-declaration.js
function isDeclaration (line 14) | function isDeclaration(node) {
FILE: packages/orgx/lib/util/estree-util-specifiers-to-declarations.js
function specifiersToDeclarations (line 19) | function specifiersToDeclarations(specifiers, init) {
FILE: packages/orgx/lib/util/estree-util-to-binary-addition.js
function toBinaryAddition (line 8) | function toBinaryAddition(expressions) {
FILE: packages/orgx/lib/util/estree-util-to-id-or-member-expression.js
function toIdOrMemberExpressionFactory (line 37) | function toIdOrMemberExpressionFactory(idType, memberType, isIdentifier) {
function isJsxIdentifierName (line 90) | function isJsxIdentifierName(name) {
function jsxCont (line 108) | function jsxCont(code) {
FILE: packages/orgx/lib/util/is-org-content.js
function isOrgContent (line 6) | function isOrgContent(node) {
FILE: packages/orgx/lib/util/resolve-evaluate-options.js
function resolveEvaluateOptions (line 30) | function resolveEvaluateOptions(options) {
FILE: packages/orgx/lib/util/resolve-file-and-options.js
function resolveFileAndOptions (line 17) | function resolveFileAndOptions(vfileCompatible, options) {
function looksLikeAVFile (line 33) | function looksLikeAVFile(value) {
FILE: packages/react-cm/index.js
function ReactCodeMirror (line 16) | function ReactCodeMirror({
FILE: packages/react-editor/index.js
function Editor (line 15) | function Editor({ content = '', className, onChange, extensions = [] }) {
FILE: packages/react/index.js
function useOrgComponents (line 36) | function useOrgComponents(components) {
function OrgProvider (line 59) | function OrgProvider({ components, children, disableParentContext }) {
FILE: packages/react/tests/remove-export-keywords.js
method ExportNamedDeclaration (line 4) | ExportNamedDeclaration(path) {
FILE: packages/reorg-parse/index.js
function reorgParse (line 22) | function reorgParse(options) {
FILE: packages/reorg-prose/lib/index.js
function reorgProse (line 17) | function reorgProse(options) {
FILE: packages/reorg-rehype/index.js
function reorg2rehype (line 26) | function reorg2rehype(options = {}) {
FILE: packages/rollup/index.js
function rollup (line 65) | function rollup(options) {
FILE: packages/text-kit/index.js
function read (line 17) | function read(text, range = {}) {
FILE: packages/text-kit/lib/core.js
function clamp (line 21) | function clamp(num, min, max) {
function core (line 29) | function core(text) {
FILE: packages/text-kit/lib/reader.js
constant PAIRS (line 16) | const PAIRS = [
function reader (line 33) | function reader(_core, range = {}) {
FILE: packages/text-kit/lib/utils/index.js
function enhance (line 11) | function enhance(core) {
FILE: packages/text-kit/lib/utils/lines.js
function linePosition (line 31) | function linePosition(start, end) {
function endOfLine (line 58) | function endOfLine(ln) {
FILE: packages/text-kit/lib/utils/substring.js
function addSubstring (line 18) | function addSubstring(core) {
Condensed preview — 439 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (959K chars).
[
{
"path": ".changeset/README.md",
"chars": 510,
"preview": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that wo"
},
{
"path": ".changeset/config.json",
"chars": 256,
"preview": "{\n \"$schema\": \"https://unpkg.com/@changesets/config@1.6.0/schema.json\",\n \"changelog\": \"@changesets/cli/changelog\",\n \""
},
{
"path": ".editorconfig",
"chars": 497,
"preview": "root = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nindent_sty"
},
{
"path": ".eslintignore",
"chars": 47,
"preview": "node_modules\n**/dist/**\n**/__tests__/**/*.json\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 70,
"preview": "# These are supported funding model platforms\n\ngithub: ['xiaoxinghu']\n"
},
{
"path": ".github/workflows/ci.yml",
"chars": 682,
"preview": "name: CI\n\non:\n push:\n branches:\n - main\n paths-ignore:\n - 'docs/**'\n - '**/README.org'\n - '**"
},
{
"path": ".github/workflows/release.yml",
"chars": 1227,
"preview": "name: Release\n\non:\n push:\n branches:\n - main\n\nenv:\n CI: true\n\npermissions: {}\n\njobs:\n release:\n name: Rele"
},
{
"path": ".github/workflows/website.yml",
"chars": 1549,
"preview": "name: Deploy to GitHub Pages\n\non:\n # Trigger the workflow every time you push to the `main` branch\n # Using a differen"
},
{
"path": ".gitignore",
"chars": 1599,
"preview": "# macOS\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that "
},
{
"path": ".prettierignore",
"chars": 88,
"preview": ".archive\n.cache\nnode_modules\n.next\npublic\nlib\n**/dist/**\n.yarn/*\n**/__tests__/**/*.json\n"
},
{
"path": ".prettierrc",
"chars": 110,
"preview": "{\n\t\"singleQuote\": true,\n\t\"semi\": false,\n\t\"trailingComma\": \"none\",\n\t\"bracketSpacing\": true,\n\t\"useTabs\": true\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 4548,
"preview": "# Change Log\n\nAll notable changes to this project will be documented in this file.\nSee [Conventional Commits](https://co"
},
{
"path": "CONTRIBUTING.org",
"chars": 1667,
"preview": "#+title: How to contribute to orgajs\n\nHi 👋 🦄.\n\n* Getting Started\nMake sure you have latest yarn installed locally.\nTo ge"
},
{
"path": "LICENSE.org",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "README.org",
"chars": 3396,
"preview": "#+title: Orga\n#+subtitle: org-mode < JavaScript\n\n* What Is It\n\n=Orga= is a flexible org-mode syntax parser. It parses or"
},
{
"path": "biome.json",
"chars": 509,
"preview": "{\n\t\"$schema\": \"https://biomejs.dev/schemas/2.4.4/schema.json\",\n\t\"files\": {\n\t\t\"includes\": [\"packages/**\", \"!packages/**/_"
},
{
"path": "docs/.gitignore",
"chars": 4,
"preview": "out\n"
},
{
"path": "docs/_components.tsx",
"chars": 4130,
"preview": "import { Editor } from '@orgajs/react-editor'\nimport { ReactCodeMirror } from '@orgajs/react-cm'\nimport { tags as t } fr"
},
{
"path": "docs/_layout.tsx",
"chars": 4259,
"preview": "import { ReactNode } from 'react'\nimport { Link } from 'orga-build/components'\n\nimport type { SVGProps } from 'react'\nco"
},
{
"path": "docs/_snippets/hey.org",
"chars": 144,
"preview": "* Hey, there\n\nThe /beauty/ of org *must* be shared.\n[[https://upload.wikimedia.org/wikipedia/commons/a/a6/Org-mode-unico"
},
{
"path": "docs/advanced/_layout.tsx",
"chars": 78,
"preview": "import { DocumentLayout } from '../_layout.tsx'\nexport default DocumentLayout\n"
},
{
"path": "docs/advanced/api.org",
"chars": 127,
"preview": "#+title: API\n#+published: true\n#+position: 201\n#+type: document\n\n#+jsx: <Notice>This page is a WIP</Notice>\n\nDescribe th"
},
{
"path": "docs/advanced/ast.org",
"chars": 136,
"preview": "#+title: AST\n#+published: true\n#+position: 202\n#+type: document\n\n#+jsx: <Notice>This page is a WIP</Notice>\n\nOrga Abstra"
},
{
"path": "docs/advanced/index.org",
"chars": 113,
"preview": "#+title: Advanced\n#+published: true\n#+type: document\n#+position: 200\n\n#+jsx: <Notice>This page is a WIP</Notice>\n"
},
{
"path": "docs/advanced/latex.org",
"chars": 807,
"preview": "#+title: Latex Support\n#+published: true\n#+position: 203\n#+type: document\n\n\n** Inline Math\nOrgajs supports inline math w"
},
{
"path": "docs/contribute.org",
"chars": 416,
"preview": "#+title: Contribute\n#+published: true\n#+position: 300\n#+type: document\n\n#+jsx: <Notice>This page is a WIP</Notice>\n\n* Ne"
},
{
"path": "docs/guides/_layout.tsx",
"chars": 78,
"preview": "import { DocumentLayout } from '../_layout.tsx'\nexport default DocumentLayout\n"
},
{
"path": "docs/guides/astro.org",
"chars": 1744,
"preview": "#+title: Astro\n#+published: true\n#+type: document\n#+position: 5\n\nUse =@orgajs/astro= to write Astro pages in Org Mode (="
},
{
"path": "docs/guides/gatsby.org",
"chars": 1106,
"preview": "#+title: Gatsby\n#+published: true\n#+type: document\n#+position: 102\n\n#+jsx: <Notice title=\"DEPRECATED\">I'm no longer acti"
},
{
"path": "docs/guides/index.org",
"chars": 1177,
"preview": "#+title: Getting Started\n#+published: true\n#+type: document\n#+position: 100\n\n** Basic Setup\nOrga is built on the [[https"
},
{
"path": "docs/guides/next.org",
"chars": 1584,
"preview": "#+title: Next.js\n#+published: true\n#+type: document\n#+position: 4\n\nUse =@orgajs/next= to write Next.js pages in Org Mode"
},
{
"path": "docs/guides/orga-build.org",
"chars": 2864,
"preview": "#+title: Build a blog with orga-build\n#+position: 2\n#+type: document\n\n\n=orga-build= is a powerful static site generator "
},
{
"path": "docs/guides/webpack.org",
"chars": 1538,
"preview": "#+title: Webpack\n#+published: true\n#+type: document\n#+position: 3\n\n=@orgajs/loader= is a webpack loader taht can be used"
},
{
"path": "docs/index.org",
"chars": 636,
"preview": "#+title: Orgajs\n#+jsx: import code from './index.org?raw'\n\n* What Is It\n\n=Orga= is a flexible org-mode syntax parser. It"
},
{
"path": "docs/playground.tsx",
"chars": 3933,
"preview": "import { ReactNode, useEffect, useMemo, useState } from 'react'\nimport { VFile } from 'vfile'\nimport { evaluate } from '"
},
{
"path": "docs/style.css",
"chars": 1203,
"preview": "@import 'tailwindcss';\n@plugin \"@tailwindcss/typography\";\n@plugin \"daisyui\" {\n\tthemes: nord --default, dark --prefersdar"
},
{
"path": "docs/tsconfig.json",
"chars": 327,
"preview": "{\n\t\"compilerOptions\": {\n\t\t\"jsx\": \"react-jsx\",\n\t\t\"lib\": [\"esnext\", \"DOM\"],\n\t\t\"moduleResolution\": \"node\",\n\t\t\"allowJs\": tru"
},
{
"path": "examples/README.org",
"chars": 4287,
"preview": "#+TITLE: Examples\n\n* Setup\n\nBefore using any of the examples, you have to build the monorepo.\n\n#+begin_src shell\ngit clo"
},
{
"path": "examples/build/index.org",
"chars": 164,
"preview": "#+title: Build with Orga\n\n* Hi\n\nYou can build a static website with *just* org files.\n\nHere's [[file:more.org][another p"
},
{
"path": "examples/build/more.org",
"chars": 45,
"preview": "#+title: Another Page\n\nThis is another page.\n"
},
{
"path": "examples/build/package.json",
"chars": 199,
"preview": "{\n\t\"name\": \"@orgajs/example-build\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"dev\": \"orga-build dev\",\n\t\t\"bui"
},
{
"path": "examples/build/test-content.tsx",
"chars": 1164,
"preview": "import { getPages, getPage } from 'orga-build:content'\n\nexport default function TestContent() {\n // Test 1: Get all pag"
},
{
"path": "examples/editor/.gitignore",
"chars": 253,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
},
{
"path": "examples/editor/CHANGELOG.md",
"chars": 1819,
"preview": "# @orgajs/example-editor\n\n## 0.3.0\n\n### Minor Changes\n\n- a53cfea: all about the editor\n\n This release improves the edit"
},
{
"path": "examples/editor/content.org",
"chars": 379,
"preview": "#+title: Example Org File\n#+date: 2023-11-24\n#+todo: TODO NEXT | DONE\n\nOrg uses single characters to markup *bold* /i"
},
{
"path": "examples/editor/index.html",
"chars": 423,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <link rel=\"icon\" type=\"image/svg+xml\" href=\"/"
},
{
"path": "examples/editor/package.json",
"chars": 403,
"preview": "{\n\t\"name\": \"@orgajs/example-editor\",\n\t\"private\": true,\n\t\"version\": \"0.3.0\",\n\t\"type\": \"module\",\n\t\"scripts\": {\n\t\t\"dev\": \"v"
},
{
"path": "examples/editor/src/main.ts",
"chars": 274,
"preview": "import { makeEditor } from '@orgajs/editor'\nimport content from '../content.org?raw'\nimport './style.css'\n\nconst target "
},
{
"path": "examples/editor/src/style.css",
"chars": 148,
"preview": "body {\n\tbackground-color: #e7e6e5;\n}\n\n#editor {\n\twidth: 720px;\n\theight: 800px;\n\toverflow: auto;\n\tborder: 1px solid #ccc;"
},
{
"path": "examples/editor/tsconfig.json",
"chars": 527,
"preview": "{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"useDefineForClassFields\": true,\n \"module\": \"ESNext\",\n \"lib\":"
},
{
"path": "examples/getting-started/.gitignore",
"chars": 913,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directo"
},
{
"path": "examples/getting-started/CHANGELOG.md",
"chars": 5434,
"preview": "# Change Log\n\n## 4.2.12\n\n### Patch Changes\n\n- @orgajs/reorg-rehype@4.3.11\n\n## 4.2.11\n\n### Patch Changes\n\n- @orgajs/reorg"
},
{
"path": "examples/getting-started/README.org",
"chars": 158,
"preview": "This is an example project, with [[file:index.js][10 lines of code]].\n\n#+BEGIN_SRC sh\nnpm install\nnpm run build\n#+END_SR"
},
{
"path": "examples/getting-started/index.js",
"chars": 265,
"preview": "import { reorg } from '@orgajs/reorg'\nimport { stream } from 'unified-stream'\nimport mutate from '@orgajs/reorg-rehype'\n"
},
{
"path": "examples/getting-started/package.json",
"chars": 452,
"preview": "{\n \"private\": true,\n \"name\": \"@orgajs/getting-started\",\n \"version\": \"4.2.12\",\n \"description\": \"\",\n \"main\": \"index.j"
},
{
"path": "examples/webpack/.babelrc",
"chars": 62,
"preview": "{\n \"presets\": [\"@babel/preset-env\", \"@babel/preset-react\"]\n}\n"
},
{
"path": "examples/webpack/CHANGELOG.md",
"chars": 1614,
"preview": "# Change Log\n\n## 3.2.0\n\n### Minor Changes\n\n- 188d30f: - migrate most of modules to js\n - fix types during the process\n "
},
{
"path": "examples/webpack/README.org",
"chars": 246,
"preview": "#+title: Webpack + Orga\n\nThis is a minimal webpack website that recognizes org-mode files as pages.\n\n-----\n\n* Running lo"
},
{
"path": "examples/webpack/package.json",
"chars": 536,
"preview": "{\n\t\"name\": \"@orgajs/example-webpack\",\n\t\"private\": true,\n\t\"version\": \"3.2.0\",\n\t\"author\": \"Xiaoxing Hu <hi@xiaoxing.dev>\","
},
{
"path": "examples/webpack/public/index.html",
"chars": 95,
"preview": "<!DOCTYPE html>\n<meta charset=\"utf-8\" />\n<div id=\"root\"></div>\n<script src=\"main.js\"></script>\n"
},
{
"path": "examples/webpack/src/box.js",
"chars": 193,
"preview": "import React from 'react'\n\nexport default ({ children }) => (\n <div\n style={{\n padding: 20,\n backgroundCol"
},
{
"path": "examples/webpack/src/hello.org",
"chars": 315,
"preview": "#+jsx: import Box from './box'\n\n* Hello\n\n#+begin_export jsx\nexport default ({ children }) =>\n <div style={{ padding: 20"
},
{
"path": "examples/webpack/src/index.js",
"chars": 185,
"preview": "import React from 'react'\nimport { createRoot } from 'react-dom/client'\nimport Hello from './hello.org'\n\nconst root = cr"
},
{
"path": "examples/webpack/webpack.config.mjs",
"chars": 255,
"preview": "export default {\n mode: 'development',\n module: {\n rules: [\n {\n test: /\\.js$/,\n use: 'babel-load"
},
{
"path": "orga.config.js",
"chars": 363,
"preview": "import tailwindcss from '@tailwindcss/vite'\nimport rehypePrettyCode from 'rehype-pretty-code'\n\nexport const containerCla"
},
{
"path": "package.json",
"chars": 1501,
"preview": "{\n\t\"name\": \"orgajs\",\n\t\"private\": true,\n\t\"type\": \"module\",\n\t\"devDependencies\": {\n\t\t\"@biomejs/biome\": \"^2.4.4\",\n\t\t\"@change"
},
{
"path": "packages/astro/README.org",
"chars": 231,
"preview": "* @orgajs/astro (Moved)\n\nThe Astro integration package has moved to a dedicated repository:\n\n[[https://github.com/orgapp"
},
{
"path": "packages/codemirror-lang/CHANGELOG.md",
"chars": 1421,
"preview": "# @orgajs/cm-lang\n\n## 1.3.0\n\n### Minor Changes\n\n- a53cfea: all about the editor\n\n This release improves the editor with"
},
{
"path": "packages/codemirror-lang/index.js",
"chars": 1933,
"preview": "/** @typedef {import('@lezer/common').SyntaxNode} SyntaxNode */\n\nimport {\n\tdefineLanguageFacet,\n\tfoldNodeProp,\n\tfoldServ"
},
{
"path": "packages/codemirror-lang/package.json",
"chars": 639,
"preview": "{\n\t\"name\": \"@orgajs/cm-lang\",\n\t\"version\": \"1.3.0\",\n\t\"description\": \"codemirror language: org\",\n\t\"type\": \"module\",\n\t\"file"
},
{
"path": "packages/codemirror-lang/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/editor/CHANGELOG.md",
"chars": 1948,
"preview": "# @orgajs/editor\n\n## 1.4.1\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n\n## 1.4.0\n\n### Minor Changes\n\n- a53cfea:"
},
{
"path": "packages/editor/README.org",
"chars": 79,
"preview": "* TODO Quick Start\n\n* Customization\n** TODO Write a Theme\n** TODO key bindings\n"
},
{
"path": "packages/editor/index.js",
"chars": 237,
"preview": "/**\n * @typedef {import('./lib/editor.js').Config} EditorConfig\n */\n\nexport { tags } from '@orgajs/cm-lang'\nexport { mak"
},
{
"path": "packages/editor/lib/actions/fold.js",
"chars": 1318,
"preview": "/**\n * @file Actions to shift sections.\n *\n * @typedef {import('@codemirror/view').EditorView} EditorView\n * @typedef {i"
},
{
"path": "packages/editor/lib/actions/shift.js",
"chars": 2545,
"preview": "/**\n * @file Actions to shift sections.\n *\n * @typedef {import('@codemirror/view').EditorView} EditorView\n * @typedef {i"
},
{
"path": "packages/editor/lib/actions/todo.js",
"chars": 838,
"preview": "/**\n * @typedef {import('@codemirror/view').EditorView} EditorView\n */\n\nimport { syntaxTree } from '@codemirror/language"
},
{
"path": "packages/editor/lib/actions/utils.js",
"chars": 968,
"preview": "/**\n * @typedef {import('@codemirror/view').EditorView} EditorView\n * @typedef {import('@lezer/common').Tree} Tree\n */\n\n"
},
{
"path": "packages/editor/lib/editor.js",
"chars": 851,
"preview": "/**\n * @callback OnChange\n * @param {EditorState} state\n */\n\n/**\n * @typedef Config\n * @property {Element} target\n * @pr"
},
{
"path": "packages/editor/lib/extensions/cleanup.js",
"chars": 4291,
"preview": "/**\n * @typedef Range\n * @property {number} from\n * @property {number} to\n *\n * @typedef {object} Options\n * @property {"
},
{
"path": "packages/editor/lib/settings.js",
"chars": 1358,
"preview": "/**\n * @typedef {import('@codemirror/state').EditorState} EditorState\n *\n * @typedef {Object} TodoKeywordSet\n * @propert"
},
{
"path": "packages/editor/lib/setup.js",
"chars": 1110,
"preview": "import { defaultKeymap } from '@codemirror/commands'\nimport { bracketMatching, foldGutter } from '@codemirror/language'\n"
},
{
"path": "packages/editor/lib/theme.js",
"chars": 1547,
"preview": "import { HighlightStyle, syntaxHighlighting } from '@codemirror/language'\nimport { EditorView } from '@codemirror/view'\n"
},
{
"path": "packages/editor/package.json",
"chars": 764,
"preview": "{\n\t\"name\": \"@orgajs/editor\",\n\t\"version\": \"1.4.1\",\n\t\"type\": \"module\",\n\t\"files\": [\n\t\t\"lib/\",\n\t\t\"index.js\",\n\t\t\"index.d.ts\","
},
{
"path": "packages/editor/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/esbuild/CHANGELOG.md",
"chars": 1033,
"preview": "# @orgajs/esbuild\n\n## 1.1.5\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n- Updated dependencies [bd2365a]\n - @o"
},
{
"path": "packages/esbuild/index.js",
"chars": 1420,
"preview": "/**\n * @import { CompileOptions } from '@orgajs/orgx'\n * @import {\n OnLoadResult,\n PluginBuild\n * } from 'esbu"
},
{
"path": "packages/esbuild/package.json",
"chars": 633,
"preview": "{\n\t\"name\": \"@orgajs/esbuild\",\n\t\"version\": \"1.1.5\",\n\t\"description\": \"esbuild plugin for orgajs\",\n\t\"type\": \"module\",\n\t\"exp"
},
{
"path": "packages/lezer/CHANGELOG.md",
"chars": 1465,
"preview": "# @orgajs/lezer\n\n## 1.4.1\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n- Updated dependencies [bd2365a]\n - orga"
},
{
"path": "packages/lezer/README.org",
"chars": 171,
"preview": "#+title: Lezer Parser for org-mode\n\n* Tasks\n\n** TODO properly support incremental parsing\n** TODO finish nodes design\n**"
},
{
"path": "packages/lezer/index.js",
"chars": 89,
"preview": "export { OrgParser, parser } from './lib/index.js'\nexport { tags } from './lib/nodes.js'\n"
},
{
"path": "packages/lezer/lib/context.js",
"chars": 3898,
"preview": "/**\n * @typedef {import('@lezer/common').PartialParse} PartialParse\n * @typedef {import('@lezer/common').Input} Input\n *"
},
{
"path": "packages/lezer/lib/fragments.js",
"chars": 4915,
"preview": "/**\n * @typedef {import('@lezer/common').PartialParse} PartialParse\n * @typedef {import('@lezer/common').Input} Input\n *"
},
{
"path": "packages/lezer/lib/handlers.js",
"chars": 1974,
"preview": "/**\n * @typedef {import('./types.js').Seed} Seed\n * @typedef {import('./types.js').Handler} Handler\n\n * @typedef {Record"
},
{
"path": "packages/lezer/lib/index.js",
"chars": 1699,
"preview": "/**\n * @typedef {import('@lezer/common').PartialParse} PartialParse\n * @typedef {import('@lezer/common').Input} Input\n *"
},
{
"path": "packages/lezer/lib/nodes.js",
"chars": 1345,
"preview": "import { NodeProp, NodeSet, NodeType } from '@lezer/common'\nimport { styleTags, Tag, tags as t } from '@lezer/highlight'"
},
{
"path": "packages/lezer/lib/oast-to-lezer.js",
"chars": 3758,
"preview": "/**\n * @typedef {import('orga').Document} OrgTree\n * @typedef {import('@lezer/common').Tree} LezerTree\n * @typedef {impo"
},
{
"path": "packages/lezer/lib/tree.js",
"chars": 2569,
"preview": "import { NodeProp, NodeType, Tree } from '@lezer/common'\nimport { documentProp } from './handlers.js'\n\n// import { nodes"
},
{
"path": "packages/lezer/lib/types.ts",
"chars": 930,
"preview": "import type { Tree as LezerTree, NodeSet } from '@lezer/common'\nimport type { Content, Document, Parent as OastParent, T"
},
{
"path": "packages/lezer/package.json",
"chars": 696,
"preview": "{\n\t\"name\": \"@orgajs/lezer\",\n\t\"version\": \"1.4.1\",\n\t\"description\": \"lezer parser for org-mode\",\n\t\"type\": \"module\",\n\t\"files"
},
{
"path": "packages/lezer/tests/compare-tree.js",
"chars": 1266,
"preview": "import { Tree } from '@lezer/common'\n\n/**\n * @typedef {import('@lezer/common').Tree} Tree\n */\n\n/**\n * @param {Tree} a\n *"
},
{
"path": "packages/lezer/tests/incremental.test.js",
"chars": 3682,
"preview": "/**\n * @typedef {{from: number, to?: number, insert?: string}[]} ChangeSpec\n */\n\nimport assert from 'node:assert'\nimport"
},
{
"path": "packages/lezer/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/loader/CHANGELOG.md",
"chars": 7031,
"preview": "# Change Log\n\n## 4.4.4\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n- Updated dependencies [bd2365a]\n - @orgajs"
},
{
"path": "packages/loader/LICENSE.org",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "packages/loader/index.cjs",
"chars": 412,
"preview": "// stolen code from @mdx-js/loader\n\n/**\n * Webpack loader\n *\n * @todo once webpack supports ESM loaders, remove this wra"
},
{
"path": "packages/loader/index.d.ts",
"chars": 490,
"preview": "import type { ProcessorOptions } from '@orgajs/orgx'\nimport type { LoaderContext } from 'webpack'\n\n/**\n * A Webpack load"
},
{
"path": "packages/loader/lib/index.js",
"chars": 727,
"preview": "/**\n * @typedef {import('webpack').LoaderContext<unknown>} LoaderContext\n */\n\nimport path from 'node:path'\nimport { crea"
},
{
"path": "packages/loader/package.json",
"chars": 852,
"preview": "{\n\t\"name\": \"@orgajs/loader\",\n\t\"version\": \"4.4.4\",\n\t\"description\": \"Load org-mode content through orga.\",\n\t\"type\": \"modul"
},
{
"path": "packages/loader/tests/compiler.js",
"chars": 1141,
"preview": "import { promises as fs } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\n"
},
{
"path": "packages/loader/tests/example.md",
"chars": 37,
"preview": "# hello world\n\nthis is some content.\n"
},
{
"path": "packages/loader/tests/fixture.org",
"chars": 119,
"preview": "#+title: hello world\n* TODO headline one\n\n#+begin_export jsx\n<div style={{ color: 'red' }}>in a box</div>\n#+end_export\n"
},
{
"path": "packages/loader/tests/loader.test.js",
"chars": 1248,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { compile } from './compiler.js'\n\ntest('basic "
},
{
"path": "packages/metadata/CHANGELOG.md",
"chars": 3198,
"preview": "# @orgajs/metadata\n\n## 2.4.1\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n\n## 2.4.0\n\n### Minor Changes\n\n- a53cfe"
},
{
"path": "packages/metadata/README.org",
"chars": 26,
"preview": "#+title: @orgajs/metadata\n"
},
{
"path": "packages/metadata/index.js",
"chars": 105,
"preview": "/**\n * @typedef {import('./lib/index.js').Metadata} Metadata\n */\n\nexport { parse } from './lib/index.js'\n"
},
{
"path": "packages/metadata/lib/index.js",
"chars": 1494,
"preview": "/**\n * TODO: more types?\n * @typedef {string} Value\n * @typedef {Record<string, Value | Value[]>} Metadata\n */\n\nconst TO"
},
{
"path": "packages/metadata/package.json",
"chars": 665,
"preview": "{\n\t\"name\": \"@orgajs/metadata\",\n\t\"version\": \"2.4.1\",\n\t\"description\": \"extract metadata info from org file\",\n\t\"type\": \"mod"
},
{
"path": "packages/metadata/tests/test.js",
"chars": 1060,
"preview": "import * as assert from 'node:assert'\nimport { describe, it } from 'node:test'\nimport { parse } from '../index.js'\n\ndesc"
},
{
"path": "packages/metadata/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/next/README.org",
"chars": 350,
"preview": "* @orgajs/next\n\nNext.js integration is now maintained in a standalone repository:\n\n- [[https://github.com/orgapp/orga-ne"
},
{
"path": "packages/node-loader/CHANGELOG.md",
"chars": 1022,
"preview": "# @orgajs/node-loader\n\n## 1.1.5\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n- Updated dependencies [bd2365a]\n "
},
{
"path": "packages/node-loader/index.js",
"chars": 2387,
"preview": "/**\n * @import {LoadFnOutput, LoadHook, LoadHookContext} from 'node:module'\n * @import {ProcessorOptions} from '@orgajs/"
},
{
"path": "packages/node-loader/package.json",
"chars": 601,
"preview": "{\n\t\"name\": \"@orgajs/node-loader\",\n\t\"version\": \"1.1.5\",\n\t\"description\": \"\",\n\t\"type\": \"module\",\n\t\"files\": [\n\t\t\"lib\",\n\t\t\"in"
},
{
"path": "packages/oast-to-hast/.projectile",
"chars": 0,
"preview": ""
},
{
"path": "packages/oast-to-hast/CHANGELOG.md",
"chars": 6917,
"preview": "# Change Log\n\n## 4.5.3\n\n### Patch Changes\n\n- 850bcf9: fix: use native anchor for external links to prevent wouter pushSt"
},
{
"path": "packages/oast-to-hast/LICENSE.org",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "packages/oast-to-hast/index.js",
"chars": 194,
"preview": "/**\n * @typedef {import('./lib/index.js').Options} Options\n */\n\nexport { handlers as defaultHandlers } from './lib/handl"
},
{
"path": "packages/oast-to-hast/lib/handlers/block.js",
"chars": 1950,
"preview": "import { parseHtml } from './html.js'\n\n/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Block"
},
{
"path": "packages/oast-to-hast/lib/handlers/document.js",
"chars": 253,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Document} node\n * @returns {import('hast').R"
},
{
"path": "packages/oast-to-hast/lib/handlers/footnote.js",
"chars": 839,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').FootnoteReference} node\n * @returns {import("
},
{
"path": "packages/oast-to-hast/lib/handlers/headline.js",
"chars": 300,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Headline} node\n * @returns {import('hast').E"
},
{
"path": "packages/oast-to-hast/lib/handlers/hr.js",
"chars": 275,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').HorizontalRule} node\n * @returns {import('ha"
},
{
"path": "packages/oast-to-hast/lib/handlers/html.js",
"chars": 741,
"preview": "import { fromHtml } from 'hast-util-from-html'\n\n/**\n * @param {import('../state.js').State} state\n * @param {import('org"
},
{
"path": "packages/oast-to-hast/lib/handlers/index.js",
"chars": 1389,
"preview": "import { block } from './block.js'\nimport { document } from './document.js'\nimport { footnote, footnoteRef } from './foo"
},
{
"path": "packages/oast-to-hast/lib/handlers/keyword.js",
"chars": 377,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Keyword} node\n * @returns {import('hast').El"
},
{
"path": "packages/oast-to-hast/lib/handlers/latex.js",
"chars": 352,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Latex} node\n * @returns {import('hast').Elem"
},
{
"path": "packages/oast-to-hast/lib/handlers/link.js",
"chars": 2075,
"preview": "/**\n * @import { Element } from 'hast'\n */\n\nimport mime from 'mime'\n\n/**\n * @param {import('../state.js').State} state\n "
},
{
"path": "packages/oast-to-hast/lib/handlers/list.js",
"chars": 2002,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').List} node\n * @returns {import('hast').Eleme"
},
{
"path": "packages/oast-to-hast/lib/handlers/newline.js",
"chars": 478,
"preview": "/**\n * @param {import('../state.js').State} _state\n * @param {import('orga').Newline} _node\n * @param {import('orga').Pa"
},
{
"path": "packages/oast-to-hast/lib/handlers/paragraph.js",
"chars": 1580,
"preview": "/**\n * Block-level HTML elements that are not allowed as descendants of <p>.\n * When a paragraph contains any of these, "
},
{
"path": "packages/oast-to-hast/lib/handlers/section.js",
"chars": 1251,
"preview": "/**\n * @param {import('../state.js').State} state\n * @param {import('orga').Section} node\n * @returns {import('hast').El"
},
{
"path": "packages/oast-to-hast/lib/handlers/table.js",
"chars": 1886,
"preview": "/**\n * @import {Element,ElementContent} from 'hast'\n * @import {Table,TableCell,TableRow} from 'orga'\n * @import {State}"
},
{
"path": "packages/oast-to-hast/lib/handlers/text.js",
"chars": 656,
"preview": "/**\n * @import {Element,Text} from 'hast'\n *\n */\n\nconst wrapper = {\n\tbold: 'strong',\n\titalic: 'i',\n\tcode: 'code',\n\tverba"
},
{
"path": "packages/oast-to-hast/lib/index.js",
"chars": 759,
"preview": "/**\n * @typedef {import('hast').Nodes} HastNodes\n * @typedef {import('orga').Nodes} OastNodes\n * @typedef {Partial<impor"
},
{
"path": "packages/oast-to-hast/lib/state.js",
"chars": 3375,
"preview": "/**\n * @typedef {import('hast').Nodes} HastNodes\n\t @import {ElementContent as HastElementContent,Root as HastRoot} from "
},
{
"path": "packages/oast-to-hast/package.json",
"chars": 701,
"preview": "{\n\t\"name\": \"oast-to-hast\",\n\t\"version\": \"4.5.3\",\n\t\"description\": \"Transform OAST to HAST\",\n\t\"files\": [\n\t\t\"lib\",\n\t\t\"index."
},
{
"path": "packages/oast-to-hast/tests/block.js",
"chars": 862,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { h } from 'hastscript'\nimport { parse } from "
},
{
"path": "packages/oast-to-hast/tests/classname.js",
"chars": 793,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { parse } from 'orga'\nimport { toHast } from '"
},
{
"path": "packages/oast-to-hast/tests/heading.js",
"chars": 318,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { h } from 'hastscript'\nimport { toHast } from"
},
{
"path": "packages/oast-to-hast/tests/list.js",
"chars": 2467,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { h } from 'hastscript'\nimport { toHast } from"
},
{
"path": "packages/oast-to-hast/tests/paragraph.js",
"chars": 2170,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { h } from 'hastscript'\nimport { toHast } from"
},
{
"path": "packages/oast-to-hast/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/oast-to-prose/CHANGELOG.md",
"chars": 374,
"preview": "# oast-to-prose\n\n## 1.3.1\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n\n## 1.3.0\n\n### Minor Changes\n\n- 188d30f: "
},
{
"path": "packages/oast-to-prose/index.js",
"chars": 113,
"preview": "/**\n * @typedef {import('./lib/index.js').Options} Options\n */\n\nexport { schema, toProse } from './lib/index.js'\n"
},
{
"path": "packages/oast-to-prose/lib/handlers/block.js",
"chars": 449,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/headline.js",
"chars": 417,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/index.js",
"chars": 574,
"preview": "import { block } from './block.js'\nimport { headline } from './headline.js'\nimport { link } from './link.js'\nimport { ne"
},
{
"path": "packages/oast-to-prose/lib/handlers/link.js",
"chars": 436,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/newline.js",
"chars": 254,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/paragraph.js",
"chars": 395,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/section.js",
"chars": 336,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/stars.js",
"chars": 320,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/tags.js",
"chars": 351,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/text.js",
"chars": 295,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/handlers/todo.js",
"chars": 352,
"preview": "/**\n * @typedef {import('prosemirror-model').Node} ProseNode\n */\n\n/**\n * @param {import('../state.js').State} state\n * @"
},
{
"path": "packages/oast-to-prose/lib/index.js",
"chars": 1227,
"preview": "/**\n * @typedef {import('orga').Document} OastRoot\n * @typedef {import('orga').Content} OastContent\n * @typedef {import("
},
{
"path": "packages/oast-to-prose/lib/schema.js",
"chars": 2403,
"preview": "import { Schema } from 'prosemirror-model'\n\nexport const defaultSchema = new Schema({\n\tnodes: {\n\t\tdoc: {\n\t\t\tcontent: 'bl"
},
{
"path": "packages/oast-to-prose/lib/state.js",
"chars": 3413,
"preview": "/**\n * @typedef {import('orga').Document} OastRoot\n * @typedef {import('orga').Content} OastContent\n * @typedef {import("
},
{
"path": "packages/oast-to-prose/package.json",
"chars": 640,
"preview": "{\n\t\"name\": \"oast-to-prose\",\n\t\"version\": \"1.3.1\",\n\t\"description\": \"Transform OAST to ProseMirror Document\",\n\t\"author\": \"X"
},
{
"path": "packages/oast-to-prose/tests/text.js",
"chars": 555,
"preview": "import * as assert from 'node:assert'\nimport test from 'node:test'\nimport { toProse } from '../lib/index.js'\n\ntest('test"
},
{
"path": "packages/oast-to-prose/tsconfig.json",
"chars": 38,
"preview": "{\n\t\"extends\": \"../../tsconfig.json\"\n}\n"
},
{
"path": "packages/orga/.projectile",
"chars": 0,
"preview": ""
},
{
"path": "packages/orga/CHANGELOG.md",
"chars": 7986,
"preview": "# Change Log\n\n## 4.7.1\n\n### Patch Changes\n\n- bd2365a: fix types and linting\n- Updated dependencies [bd2365a]\n - text-ki"
},
{
"path": "packages/orga/LICENSE.org",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "packages/orga/README.org",
"chars": 2128,
"preview": "* orga\n\nTurns org-mode content into AST.\n\n** Install\n\n#+BEGIN_SRC sh\n npm install --save orga\n#+END_SRC\n\n** Usage\n\n#+BE"
},
{
"path": "packages/orga/package.json",
"chars": 780,
"preview": "{\n\t\"name\": \"orga\",\n\t\"version\": \"4.7.1\",\n\t\"description\": \"org-mode parser\",\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"main\": \"dist/index"
},
{
"path": "packages/orga/src/__tests__/block/affiliated keyword.json",
"chars": 4937,
"preview": "{\n \"type\": \"document\",\n \"properties\": {\n \"nop\": \"code_block\"\n },\n \"children\": [\n {\n \"type\": \"keyword\",\n "
},
{
"path": "packages/orga/src/__tests__/block/affiliated keyword.org",
"chars": 236,
"preview": "#+NAME: code_block\n#+BEGIN_SRC javascript\nconsole.log('named code block')\n#+END_SRC\n\n#+NAME: code_block\n\n#+BEGIN_SRC jav"
},
{
"path": "packages/orga/src/__tests__/block/export.json",
"chars": 2028,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"html\",\n \"value\": \"<h1>Hello</h1>\","
},
{
"path": "packages/orga/src/__tests__/block/export.org",
"chars": 72,
"preview": "#+HTML: <h1>Hello</h1>\n\n#+BEGIN_EXPORT html\n<p>world!</p>\n#+END_EXPORT\n\n"
},
{
"path": "packages/orga/src/__tests__/block/missing begin.json",
"chars": 2165,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"children\": [\n "
},
{
"path": "packages/orga/src/__tests__/block/missing begin.org",
"chars": 52,
"preview": "console.log('hello')\nconsole.log('world')\n#+END_SRC\n"
},
{
"path": "packages/orga/src/__tests__/block/missing end.json",
"chars": 2957,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"children\": [\n "
},
{
"path": "packages/orga/src/__tests__/block/missing end.org",
"chars": 65,
"preview": "#+BEGIN_SRC javascript\nconsole.log('hello')\nconsole.log('world')\n"
},
{
"path": "packages/orga/src/__tests__/block/standard.json",
"chars": 1544,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"block\",\n \"name\": \"SRC\",\n \"par"
},
{
"path": "packages/orga/src/__tests__/block/standard.org",
"chars": 75,
"preview": "#+BEGIN_SRC javascript\nconsole.log('hello')\nconsole.log('world')\n#+END_SRC\n"
},
{
"path": "packages/orga/src/__tests__/footnote/multiline.json",
"chars": 7716,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"children\": [\n "
},
{
"path": "packages/orga/src/__tests__/footnote/multiline.org",
"chars": 87,
"preview": "reference footnote [fn:1]\n\n[fn:1] Content of the footnote.\nAnd here is *another* line.\n"
},
{
"path": "packages/orga/src/__tests__/footnote/standard.json",
"chars": 5802,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"children\": [\n "
},
{
"path": "packages/orga/src/__tests__/footnote/standard.org",
"chars": 59,
"preview": "reference footnote [fn:1]\n\n[fn:1] Content of the footnote.\n"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by empty lines.json",
"chars": 7014,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"footnote\",\n \"label\": \"1\",\n \"c"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by empty lines.org",
"chars": 96,
"preview": "[fn:1] Content of the footnote.\nAnd here is another line.\n\nstill belongs to fn:1\n\n\nThis is not.\n"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by footnote.json",
"chars": 5432,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"footnote\",\n \"label\": \"1\",\n \"c"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by footnote.org",
"chars": 83,
"preview": "[fn:1] Content of the footnote.\nAnd here is another line.\n[fn:2] another footnote.\n"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by headline.json",
"chars": 5088,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"footnote\",\n \"label\": \"1\",\n \"c"
},
{
"path": "packages/orga/src/__tests__/footnote/stopped by headline.org",
"chars": 71,
"preview": "[fn:1] Content of the footnote.\nAnd here is another line.\n* A Headline\n"
},
{
"path": "packages/orga/src/__tests__/footnote/with block.json",
"chars": 6895,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"paragraph\",\n \"children\": [\n "
},
{
"path": "packages/orga/src/__tests__/footnote/with block.org",
"chars": 132,
"preview": "reference footnote [fn:1]\n\n[fn:1] Content of the footnote.\n#+BEGIN_SRC javascript\nconsole.log('footnote with code block'"
},
{
"path": "packages/orga/src/__tests__/headline/broken drawer.json",
"chars": 7048,
"preview": "{\n \"type\": \"document\",\n \"properties\": {},\n \"children\": [\n {\n \"type\": \"section\",\n \"level\": 1,\n \"prop"
}
]
// ... and 239 more files (download for full content)
About this extraction
This page contains the full source code of the xiaoxinghu/orgajs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 439 files (820.0 KB), approximately 236.4k tokens, and a symbol index with 340 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.