├── .changeset
├── README.md
└── config.json
├── .envrc
├── .github
└── workflows
│ ├── main.yml
│ └── release.yml
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── codecov.yml
├── docs
└── deviations-from-org-mode.org
├── examples
├── astro
│ ├── .gitignore
│ ├── .vscode
│ │ ├── extensions.json
│ │ └── launch.json
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── astro.config.mjs
│ ├── package.json
│ ├── public
│ │ ├── blog-placeholder-1.jpg
│ │ ├── blog-placeholder-2.jpg
│ │ ├── blog-placeholder-3.jpg
│ │ ├── blog-placeholder-4.jpg
│ │ ├── blog-placeholder-5.jpg
│ │ ├── blog-placeholder-about.jpg
│ │ ├── favicon.svg
│ │ └── fonts
│ │ │ ├── atkinson-bold.woff
│ │ │ └── atkinson-regular.woff
│ ├── src
│ │ ├── components
│ │ │ ├── BaseHead.astro
│ │ │ ├── Footer.astro
│ │ │ ├── FormattedDate.astro
│ │ │ ├── Header.astro
│ │ │ └── HeaderLink.astro
│ │ ├── consts.ts
│ │ ├── content
│ │ │ ├── blog
│ │ │ │ ├── first-post.org
│ │ │ │ ├── org-style-guide.org
│ │ │ │ ├── second-post.org
│ │ │ │ └── third-post.org
│ │ │ └── config.ts
│ │ ├── env.d.ts
│ │ ├── layouts
│ │ │ └── BlogPost.astro
│ │ ├── pages
│ │ │ ├── about.astro
│ │ │ ├── blog
│ │ │ │ ├── [...slug].astro
│ │ │ │ └── index.astro
│ │ │ ├── index.astro
│ │ │ └── rss.xml.js
│ │ └── styles
│ │ │ └── global.css
│ └── tsconfig.json
├── example
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── index.js
│ └── package.json
├── extract-keywords-example
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── example.org
│ ├── index.js
│ └── package.json
├── next-blog-starter
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── _posts
│ │ ├── hello-world.org
│ │ ├── preview.org
│ │ └── uniorg.org
│ ├── components
│ │ ├── alert.js
│ │ ├── avatar.js
│ │ ├── container.js
│ │ ├── cover-image.js
│ │ ├── date-formatter.js
│ │ ├── footer.js
│ │ ├── header.js
│ │ ├── hero-post.js
│ │ ├── intro.js
│ │ ├── layout.js
│ │ ├── meta.js
│ │ ├── more-stories.js
│ │ ├── org-styles.module.css
│ │ ├── post-body.js
│ │ ├── post-header.js
│ │ ├── post-preview.js
│ │ ├── post-title.js
│ │ └── section-separator.js
│ ├── lib
│ │ ├── api.js
│ │ ├── constants.js
│ │ └── orgToHtml.js
│ ├── package.json
│ ├── pages
│ │ ├── _app.js
│ │ ├── _document.js
│ │ ├── index.js
│ │ └── posts
│ │ │ └── [slug].js
│ ├── postcss.config.js
│ ├── public
│ │ ├── assets
│ │ │ └── blog
│ │ │ │ ├── authors
│ │ │ │ ├── jj.jpeg
│ │ │ │ ├── joe.jpeg
│ │ │ │ └── tim.jpeg
│ │ │ │ ├── dynamic-routing
│ │ │ │ └── cover.jpg
│ │ │ │ ├── hello-world
│ │ │ │ └── cover.jpg
│ │ │ │ └── preview
│ │ │ │ └── cover.jpg
│ │ └── favicon
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── browserconfig.xml
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon.ico
│ │ │ ├── mstile-150x150.png
│ │ │ ├── safari-pinned-tab.svg
│ │ │ └── site.webmanifest
│ ├── styles
│ │ └── index.css
│ ├── tailwind.config.js
│ └── vercel.json
└── org-braindump
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── package.json
│ ├── public
│ ├── archive-page.org
│ ├── changing-posts-directory.org
│ ├── code-highlight.org
│ ├── id-links.org
│ ├── index.org
│ ├── org-roam.org
│ ├── styling.org
│ └── uniorg.org
│ ├── src
│ ├── components
│ │ ├── Link.jsx
│ │ └── Rehype.jsx
│ ├── lib
│ │ ├── api.js
│ │ ├── orgToHtml.js
│ │ └── resolveLinks.js
│ ├── pages
│ │ ├── [[...slug]].jsx
│ │ ├── _app.js
│ │ └── archive.jsx
│ └── styles
│ │ └── globals.css
│ └── vercel.json
├── flake.lock
├── flake.nix
├── jest-base.mjs
├── jest.config.js
├── logo.svg
├── package.json
├── packages
├── astro-org
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ ├── plugin
│ │ │ └── rehype-export-frontmatter.ts
│ │ └── server.ts
│ ├── template
│ │ └── content-module-types.d.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── orgast-util-to-string
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── index.spec.ts
│ │ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── orgast-util-visit-ids
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── index.spec.ts
│ │ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── orgx
│ ├── .gitignore
│ ├── .npmignore
│ ├── CHANGELOG.md
│ ├── index.js
│ ├── lib
│ │ ├── compile.js
│ │ ├── condition.browser.js
│ │ ├── condition.js
│ │ ├── core.js
│ │ ├── evaluate.js
│ │ ├── node-types.js
│ │ ├── plugin
│ │ │ ├── recma-document.js
│ │ │ ├── recma-jsx-build.js
│ │ │ ├── recma-jsx-rewrite.js
│ │ │ ├── recma-stringify.js
│ │ │ ├── rehype-recma.js
│ │ │ └── rehype-remove-raw.js
│ │ ├── run.js
│ │ └── 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
│ │ │ ├── extnames-to-regex.js
│ │ │ ├── extnames.js
│ │ │ ├── resolve-evaluate-options.js
│ │ │ └── resolve-file-and-options.js
│ ├── license
│ ├── package.json
│ ├── readme.md
│ ├── test
│ │ ├── compile.js
│ │ ├── context
│ │ │ ├── components.js
│ │ │ └── data.js
│ │ └── evaluate.js
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── rollup-plugin-orgx
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-attach
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __snapshots__
│ │ │ └── index.spec.ts.snap
│ │ ├── index.spec.ts
│ │ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-extract-keywords
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── index.spec.ts
│ │ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-parse
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __snapshots__
│ │ │ └── parser.spec.ts.snap
│ │ ├── entities.ts
│ │ ├── index.ts
│ │ ├── parse-options.ts
│ │ ├── parser.spec.ts
│ │ ├── parser.ts
│ │ ├── reader.ts
│ │ ├── unified-org-parse.ts
│ │ └── utils.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-rehype
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __snapshots__
│ │ │ └── org-to-hast.spec.ts.snap
│ │ ├── index.ts
│ │ ├── org-to-hast.spec.ts
│ │ ├── org-to-hast.ts
│ │ ├── rehype-format.d.ts
│ │ └── unified-org-rehype.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-slug
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── index.spec.ts
│ │ ├── index.ts
│ │ └── unist-util-find.d.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── uniorg-stringify
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── jest.config.js
│ ├── package.json
│ ├── src
│ │ ├── __snapshots__
│ │ │ └── stringify.spec.ts.snap
│ │ ├── index.spec.ts
│ │ ├── index.ts
│ │ ├── stringify.spec.ts
│ │ └── stringify.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── uniorg
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── package.json
│ ├── src
│ └── index.ts
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tsconfig.build.json
├── tsconfig.json
└── turbo.json
/.changeset/README.md:
--------------------------------------------------------------------------------
1 | # Changesets
2 |
3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4 | with multi-package repos, or single-package repos to help you version and publish your code. You can
5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6 |
7 | We have a quick list of common questions to get you started engaging with this project in
8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
9 |
--------------------------------------------------------------------------------
/.changeset/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
3 | "changelog": ["@changesets/changelog-github", { "repo": "rasendubi/uniorg" }],
4 | "commit": false,
5 | "fixed": [],
6 | "linked": [],
7 | "access": "public",
8 | "baseBranch": "main",
9 | "updateInternalDependencies": "minor",
10 | "bumpVersionsWithWorkspaceProtocolOnly": true,
11 | "ignore": [],
12 | "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
13 | "onlyUpdatePeerDependentsWhenOutOfRange": true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.envrc:
--------------------------------------------------------------------------------
1 | # reload when these files change
2 | watch_file flake.nix
3 | watch_file flake.lock
4 | # load the flake devShell
5 | eval "$(nix print-dev-env)"
6 |
7 | layout node
8 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 |
8 | jobs:
9 | main:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: '22'
17 | - uses: pnpm/action-setup@v2
18 | with:
19 | version: 9
20 | - run: pnpm install
21 | - run: pnpm run ci
22 | - uses: codecov/codecov-action@v3
23 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | concurrency: ${{ github.workflow }}-${{ github.ref }}
9 |
10 | jobs:
11 | release:
12 | name: Release
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | # fetch all tags, so changeset tag does not create extra tags
17 | - run: git fetch --tags origin
18 | - uses: actions/setup-node@v3
19 | with:
20 | node-version: '22'
21 | - uses: pnpm/action-setup@v2
22 | with:
23 | version: 9
24 | - run: pnpm install
25 | - uses: changesets/action@v1
26 | with:
27 | title: 'chore: release'
28 | commit: 'chore: bump version'
29 | version: pnpm run version
30 | publish: pnpm run publish
31 | createGithubReleases: true
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | lerna-debug.log
3 | coverage/
4 |
5 | .turbo
6 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | link-workspace-packages = deep
2 | prefer-workspace-packages = true
3 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | coverage/
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "arrowParens": "always",
3 | "tabWidth": 2,
4 | "singleQuote": true,
5 | "semi": true,
6 | "trailingComma": "es5"
7 | }
8 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | status:
3 | project:
4 | default:
5 | informational: true
6 | patch:
7 | default:
8 | informational: true
9 |
--------------------------------------------------------------------------------
/examples/astro/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/examples/astro/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode", "unifiedjs.vscode-mdx"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/examples/astro/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/examples/astro/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # @uniorgjs/astro-example
2 |
3 | ## 0.0.8
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317), [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
8 | - uniorg-parse@3.2.0
9 | - uniorg-rehype@2.2.0
10 |
11 | ## 0.0.7
12 |
13 | ### Patch Changes
14 |
15 | - Updated dependencies [[`381b67c`](https://github.com/rasendubi/uniorg/commit/381b67cf0d64c5926754fce04b54aa0b86699b85), [`da9d596`](https://github.com/rasendubi/uniorg/commit/da9d596718fb3656833f5c3a3d2e0abd9667eaa1)]:
16 | - uniorg-parse@3.1.0
17 |
18 | ## 0.0.6
19 |
20 | ### Patch Changes
21 |
22 | - Updated dependencies [[`7531419`](https://github.com/rasendubi/uniorg/commit/75314196835ee768fc0689cbc6279cf68fedb58b)]:
23 | - astro-org@4.0.0
24 |
25 | ## 0.0.5
26 |
27 | ### Patch Changes
28 |
29 | - Updated dependencies [[`12d0768`](https://github.com/rasendubi/uniorg/commit/12d076891ef1d643cd3712e6845e0c45d38c98cb)]:
30 | - astro-org@3.0.0
31 |
32 | ## 0.0.4
33 |
34 | ### Patch Changes
35 |
36 | - Updated dependencies [[`3af18d6`](https://github.com/rasendubi/uniorg/commit/3af18d630f64f11afda88b93c31f4779473d8e61)]:
37 | - astro-org@2.1.2
38 |
39 | ## 0.0.3
40 |
41 | ### Patch Changes
42 |
43 | - Updated dependencies []:
44 | - astro-org@2.1.1
45 |
46 | ## 0.0.2
47 |
48 | ### Patch Changes
49 |
50 | - [#96](https://github.com/rasendubi/uniorg/pull/96) [`2ec17b8`](https://github.com/rasendubi/uniorg/commit/2ec17b87a2b58546307f61110785dac47d7b2b10) Thanks [@rasendubi](https://github.com/rasendubi)! - Support Astro Content Collections.
51 |
52 | astro-org now supports Astro's [Content Collections](https://docs.astro.build/en/guides/content-collections/). You can simply drop org files to `src/collections/*/` directories and it should work.
53 |
54 | - Updated dependencies [[`2ec17b8`](https://github.com/rasendubi/uniorg/commit/2ec17b87a2b58546307f61110785dac47d7b2b10)]:
55 | - astro-org@2.1.0
56 |
--------------------------------------------------------------------------------
/examples/astro/README.md:
--------------------------------------------------------------------------------
1 | # Astro Starter Kit: Blog
2 |
3 | ```sh
4 | npm create astro@latest -- --template blog
5 | ```
6 |
7 | [](https://stackblitz.com/github/withastro/astro/tree/latest/examples/blog)
8 | [](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/blog)
9 | [](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/blog/devcontainer.json)
10 |
11 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
12 |
13 | 
14 |
15 | Features:
16 |
17 | - ✅ Minimal styling (make it your own!)
18 | - ✅ 100/100 Lighthouse performance
19 | - ✅ SEO-friendly with canonical URLs and OpenGraph data
20 | - ✅ Sitemap support
21 | - ✅ RSS Feed support
22 | - ✅ Org-mode support
23 |
24 | ## 🚀 Project Structure
25 |
26 | Inside of your Astro project, you'll see the following folders and files:
27 |
28 | ```text
29 | ├── public/
30 | ├── src/
31 | │ ├── components/
32 | │ ├── content/
33 | │ ├── layouts/
34 | │ └── pages/
35 | ├── astro.config.mjs
36 | ├── README.md
37 | ├── package.json
38 | └── tsconfig.json
39 | ```
40 |
41 | Astro looks for `.astro` or `.org` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
42 |
43 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
44 |
45 | The `src/content/` directory contains "collections" of related Org documents. Use `getCollection()` to retrieve posts from `src/content/blog/`, and type-check your frontmatter using an optional schema. See [Astro's Content Collections docs](https://docs.astro.build/en/guides/content-collections/) to learn more.
46 |
47 | Any static assets, like images, can be placed in the `public/` directory.
48 |
49 | ## 🧞 Commands
50 |
51 | All commands are run from the root of the project, from a terminal:
52 |
53 | | Command | Action |
54 | | :------------------------ | :----------------------------------------------- |
55 | | `npm install` | Installs dependencies |
56 | | `npm run dev` | Starts local dev server at `localhost:4321` |
57 | | `npm run build` | Build your production site to `./dist/` |
58 | | `npm run preview` | Preview your build locally, before deploying |
59 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
60 | | `npm run astro -- --help` | Get help using the Astro CLI |
61 |
62 | ## 👀 Want to learn more?
63 |
64 | Check out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
65 |
66 | ## Credit
67 |
68 | This theme is based off of the lovely [Bear Blog](https://github.com/HermanMartinus/bearblog/).
69 |
--------------------------------------------------------------------------------
/examples/astro/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 | import org from 'astro-org'
3 |
4 | import sitemap from '@astrojs/sitemap';
5 |
6 | // https://astro.build/config
7 | export default defineConfig({
8 | site: 'https://example.com',
9 | integrations: [org(), sitemap()],
10 | });
11 |
--------------------------------------------------------------------------------
/examples/astro/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uniorgjs/astro-example",
3 | "type": "module",
4 | "version": "0.0.8",
5 | "private": true,
6 | "scripts": {
7 | "dev": "astro dev",
8 | "start": "astro dev",
9 | "build": "astro check && astro build",
10 | "preview": "astro preview",
11 | "astro": "astro"
12 | },
13 | "dependencies": {
14 | "@astrojs/check": "^0.9.4",
15 | "@astrojs/rss": "^4.0.11",
16 | "@astrojs/sitemap": "^3.3.0",
17 | "astro": "^5.5.5",
18 | "astro-org": "workspace:^",
19 | "uniorg-parse": "workspace:^",
20 | "uniorg-rehype": "workspace:^",
21 | "typescript": "^5.4.5"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-1.jpg
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-2.jpg
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-3.jpg
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-4.jpg
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-5.jpg
--------------------------------------------------------------------------------
/examples/astro/public/blog-placeholder-about.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/blog-placeholder-about.jpg
--------------------------------------------------------------------------------
/examples/astro/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/astro/public/fonts/atkinson-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/fonts/atkinson-bold.woff
--------------------------------------------------------------------------------
/examples/astro/public/fonts/atkinson-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/astro/public/fonts/atkinson-regular.woff
--------------------------------------------------------------------------------
/examples/astro/src/components/BaseHead.astro:
--------------------------------------------------------------------------------
1 | ---
2 | // Import the global.css file here so that it is included on
3 | // all pages through the use of the component.
4 | import '../styles/global.css';
5 |
6 | interface Props {
7 | title: string;
8 | description: string;
9 | image?: string;
10 | }
11 |
12 | const canonicalURL = new URL(Astro.url.pathname, Astro.site);
13 |
14 | const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props;
15 | ---
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
{title}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/examples/astro/src/components/FormattedDate.astro:
--------------------------------------------------------------------------------
1 | ---
2 | interface Props {
3 | date: Date;
4 | }
5 |
6 | const { date } = Astro.props;
7 | ---
8 |
9 |
10 | {
11 | date.toLocaleDateString('en-us', {
12 | year: 'numeric',
13 | month: 'short',
14 | day: 'numeric',
15 | })
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/examples/astro/src/components/HeaderLink.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import type { HTMLAttributes } from 'astro/types';
3 |
4 | type Props = HTMLAttributes<'a'>;
5 |
6 | const { href, class: className, ...props } = Astro.props;
7 |
8 | const { pathname } = Astro.url;
9 | const isActive = href === pathname || href === pathname.replace(/\/$/, '');
10 | ---
11 |
12 |
13 |
14 |
15 |
25 |
--------------------------------------------------------------------------------
/examples/astro/src/consts.ts:
--------------------------------------------------------------------------------
1 | // Place any global data in this file.
2 | // You can import this data from anywhere in your site by using the `import` keyword.
3 |
4 | export const SITE_TITLE = 'Astro Blog';
5 | export const SITE_DESCRIPTION = 'Welcome to my website!';
6 |
--------------------------------------------------------------------------------
/examples/astro/src/content/config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection, z } from 'astro:content';
2 |
3 | const blog = defineCollection({
4 | // Type-check frontmatter using a schema
5 | schema: z.object({
6 | title: z.string(),
7 | description: z.string(),
8 | // Transform string to Date object
9 | date: z.coerce.date(),
10 | last_modified: z.coerce.date().optional(),
11 | hero_image: z.string().optional(),
12 | }),
13 | });
14 |
15 | export const collections = { blog };
16 |
--------------------------------------------------------------------------------
/examples/astro/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/examples/astro/src/layouts/BlogPost.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import type { CollectionEntry } from 'astro:content';
3 | import BaseHead from '../components/BaseHead.astro';
4 | import Header from '../components/Header.astro';
5 | import Footer from '../components/Footer.astro';
6 | import FormattedDate from '../components/FormattedDate.astro';
7 |
8 | type Props = CollectionEntry<'blog'>['data'];
9 |
10 | const { title, description, date, last_modified, hero_image } = Astro.props;
11 | ---
12 |
13 |
14 |
15 |
16 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {hero_image &&
}
63 |
64 |
65 |
66 |
67 |
68 | {
69 | last_modified && (
70 |
71 | Last updated on
72 |
73 | )
74 | }
75 |
76 |
{title}
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/examples/astro/src/pages/blog/[...slug].astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { type CollectionEntry, getCollection } from 'astro:content';
3 | import BlogPost from '../../layouts/BlogPost.astro';
4 |
5 | export async function getStaticPaths() {
6 | const posts = await getCollection('blog');
7 | return posts.map((post) => ({
8 | params: { slug: post.slug },
9 | props: post,
10 | }));
11 | }
12 | type Props = CollectionEntry<'blog'>;
13 |
14 | const post = Astro.props;
15 | const { Content } = await post.render();
16 | ---
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/examples/astro/src/pages/blog/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseHead from '../../components/BaseHead.astro';
3 | import Header from '../../components/Header.astro';
4 | import Footer from '../../components/Footer.astro';
5 | import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts';
6 | import { getCollection } from 'astro:content';
7 | import FormattedDate from '../../components/FormattedDate.astro';
8 |
9 | const posts = (await getCollection('blog')).sort(
10 | (a, b) => a.data.date.valueOf() - b.data.date.valueOf()
11 | );
12 | ---
13 |
14 |
15 |
16 |
17 |
18 |
87 |
88 |
89 |
90 |
91 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/examples/astro/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import BaseHead from '../components/BaseHead.astro';
3 | import Header from '../components/Header.astro';
4 | import Footer from '../components/Footer.astro';
5 | import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
6 | ---
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 🧑🚀 Hello, Astronaut!
17 |
18 | Welcome to the official astro-org blog starter template. This
19 | template serves as a lightweight, minimally-styled starting point for anyone looking to
20 | build a personal website, blog, or portfolio with Astro.
21 |
22 |
23 | This template comes with a few integrations already configured in your
24 | astro.config.mjs
file. You can customize your setup with
25 | Astro Integrations to add tools like
26 | Tailwind, React, or Vue to your project.
27 |
28 | Here are a few ideas on how to get started with the template:
29 |
30 | Edit this page in src/pages/index.astro
31 | Edit the site header items in src/components/Header.astro
32 | Add your name to the footer in src/components/Footer.astro
33 | Check out the included blog posts in src/pages/blog/
34 | Customize the blog post page layout in src/layouts/BlogPost.astro
35 |
36 |
37 | Have fun! If you get stuck, remember to read the docs
39 | or join us on Discord to ask questions.
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/astro/src/pages/rss.xml.js:
--------------------------------------------------------------------------------
1 | import rss from '@astrojs/rss';
2 | import { getCollection } from 'astro:content';
3 | import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
4 |
5 | export async function GET(context) {
6 | const posts = await getCollection('blog');
7 | return rss({
8 | title: SITE_TITLE,
9 | description: SITE_DESCRIPTION,
10 | site: context.site,
11 | items: posts.map((post) => ({
12 | title: post.data.title,
13 | pubDate: post.data.date,
14 | description: post.data.description,
15 | link: `/blog/${post.slug}/`,
16 | })),
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/examples/astro/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict",
3 | "compilerOptions": {
4 | "strictNullChecks": true
5 | }
6 | }
--------------------------------------------------------------------------------
/examples/example/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # example
2 |
3 | ## 1.0.6
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317), [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
8 | - uniorg-parse@3.2.0
9 | - uniorg-rehype@2.2.0
10 |
11 | ## 1.0.5
12 |
13 | ### Patch Changes
14 |
15 | - Updated dependencies [[`381b67c`](https://github.com/rasendubi/uniorg/commit/381b67cf0d64c5926754fce04b54aa0b86699b85), [`da9d596`](https://github.com/rasendubi/uniorg/commit/da9d596718fb3656833f5c3a3d2e0abd9667eaa1)]:
16 | - uniorg-parse@3.1.0
17 |
18 | ## 1.0.4
19 |
20 | ### Patch Changes
21 |
22 | - Updated dependencies [[`40ff5c5`](https://github.com/rasendubi/uniorg/commit/40ff5c5331c47f408484ba84daa2c18d81ba554d)]:
23 | - uniorg-rehype@2.1.0
24 |
25 | ## 1.0.3
26 |
27 | ### Patch Changes
28 |
29 | - Updated dependencies [[`dbf6452`](https://github.com/rasendubi/uniorg/commit/dbf6452921ad03120bb9df87746aef52ac72b5fb), [`b45baf9`](https://github.com/rasendubi/uniorg/commit/b45baf992db4659e2732e888bd3860b9eff25504)]:
30 | - uniorg-parse@3.0.0
31 | - uniorg-rehype@1.2.0
32 |
33 | ## 1.0.2
34 |
35 | ### Patch Changes
36 |
37 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
38 |
39 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
40 |
41 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
42 | - uniorg-rehype@1.1.1
43 | - uniorg-parse@2.1.1
44 |
45 | ## 1.0.1
46 |
47 | ### Patch Changes
48 |
49 | - Updated dependencies [[`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6), [`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6)]:
50 | - uniorg-parse@2.0.0
51 | - uniorg-rehype@1.1.0
52 |
--------------------------------------------------------------------------------
/examples/example/README.md:
--------------------------------------------------------------------------------
1 | This is an example project to convert org files to HTML (with [7 lines of code](./index.js)).
2 |
3 | ```sh
4 | npm install
5 | npm start < file.org > file.html
6 | ```
7 |
--------------------------------------------------------------------------------
/examples/example/index.js:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 | import { stream } from 'unified-stream';
3 | import uniorgParse from 'uniorg-parse';
4 | import uniorg2rehype from 'uniorg-rehype';
5 | import html from 'rehype-stringify';
6 |
7 | var processor = unified().use(uniorgParse).use(uniorg2rehype).use(html);
8 |
9 | process.stdin.pipe(stream(processor)).pipe(process.stdout);
10 |
--------------------------------------------------------------------------------
/examples/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.6",
4 | "private": true,
5 | "type": "module",
6 | "description": "Simple example of uniorg usage.",
7 | "author": "Oleksii Shmalko ",
8 | "homepage": "https://github.com/rasendubi/uniorg#readme",
9 | "license": "GPL-3.0-or-later",
10 | "scripts": {
11 | "start": "node ./index.js"
12 | },
13 | "dependencies": {
14 | "rehype-stringify": "10.0.0",
15 | "unified": "11.0.4",
16 | "unified-stream": "3.0.0",
17 | "uniorg-parse": "workspace:^",
18 | "uniorg-rehype": "workspace:^"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/extract-keywords-example/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # extract-keywords-example
2 |
3 | ## 1.0.6
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317), [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
8 | - uniorg-extract-keywords@1.1.0
9 | - uniorg-parse@3.2.0
10 | - uniorg-rehype@2.2.0
11 |
12 | ## 1.0.5
13 |
14 | ### Patch Changes
15 |
16 | - Updated dependencies [[`381b67c`](https://github.com/rasendubi/uniorg/commit/381b67cf0d64c5926754fce04b54aa0b86699b85), [`da9d596`](https://github.com/rasendubi/uniorg/commit/da9d596718fb3656833f5c3a3d2e0abd9667eaa1)]:
17 | - uniorg-parse@3.1.0
18 |
19 | ## 1.0.4
20 |
21 | ### Patch Changes
22 |
23 | - Updated dependencies [[`40ff5c5`](https://github.com/rasendubi/uniorg/commit/40ff5c5331c47f408484ba84daa2c18d81ba554d)]:
24 | - uniorg-rehype@2.1.0
25 |
26 | ## 1.0.3
27 |
28 | ### Patch Changes
29 |
30 | - Updated dependencies [[`dbf6452`](https://github.com/rasendubi/uniorg/commit/dbf6452921ad03120bb9df87746aef52ac72b5fb), [`b45baf9`](https://github.com/rasendubi/uniorg/commit/b45baf992db4659e2732e888bd3860b9eff25504)]:
31 | - uniorg-parse@3.0.0
32 | - uniorg-rehype@1.2.0
33 |
34 | ## 1.0.2
35 |
36 | ### Patch Changes
37 |
38 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
39 |
40 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
41 |
42 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
43 | - uniorg-extract-keywords@1.0.1
44 | - uniorg-rehype@1.1.1
45 | - uniorg-parse@2.1.1
46 |
47 | ## 1.0.1
48 |
49 | ### Patch Changes
50 |
51 | - Updated dependencies [[`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6), [`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6)]:
52 | - uniorg-parse@2.0.0
53 | - uniorg-rehype@1.1.0
54 |
--------------------------------------------------------------------------------
/examples/extract-keywords-example/README.md:
--------------------------------------------------------------------------------
1 | This is an example project to convert org files to HTML and extract keywords.
2 |
3 | Given [example.org](./example.org):
4 | ```
5 | #+TITLE: Post title
6 | #+AUTHOR: Your Name
7 |
8 | other org-mode
9 | ```
10 |
11 | the following commands
12 |
13 | ```sh
14 | npm install
15 | npm start
16 | ```
17 |
18 | will output
19 |
20 | ```
21 | other org-mode
22 |
23 | { title: 'Post title', author: 'Your Name' }
24 | ```
25 |
--------------------------------------------------------------------------------
/examples/extract-keywords-example/example.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Post title
2 | #+AUTHOR: Your Name
3 |
4 | other org-mode
5 |
--------------------------------------------------------------------------------
/examples/extract-keywords-example/index.js:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 | import { readSync } from 'to-vfile';
3 | import uniorgParse from 'uniorg-parse';
4 | import { extractKeywords } from 'uniorg-extract-keywords';
5 | import uniorg2rehype from 'uniorg-rehype';
6 | import html from 'rehype-stringify';
7 |
8 | unified()
9 | .use(uniorgParse)
10 | .use(extractKeywords)
11 | .use(uniorg2rehype)
12 | .use(html)
13 | .process(readSync('example.org'), function (err, file) {
14 | console.log(file.toString());
15 | console.log(file.data);
16 | });
17 |
--------------------------------------------------------------------------------
/examples/extract-keywords-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "extract-keywords-example",
3 | "version": "1.0.6",
4 | "private": true,
5 | "type": "module",
6 | "description": "Example of using uniorg-extract-keywords",
7 | "author": "Oleksii Shmalko ",
8 | "homepage": "https://github.com/rasendubi/uniorg#readme",
9 | "license": "GPL-3.0-or-later",
10 | "main": "index.js",
11 | "scripts": {
12 | "start": "node ./index.js"
13 | },
14 | "dependencies": {
15 | "ci": "^2.3.0",
16 | "rehype-stringify": "10.0.0",
17 | "to-vfile": "8.0.0",
18 | "unified": "11.0.4",
19 | "uniorg-extract-keywords": "workspace:^",
20 | "uniorg-parse": "workspace:^",
21 | "uniorg-rehype": "workspace:^"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # blog-starter
2 |
3 | ## 1.0.6
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317), [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
8 | - uniorg-extract-keywords@1.1.0
9 | - uniorg-parse@3.2.0
10 | - uniorg-rehype@2.2.0
11 |
12 | ## 1.0.5
13 |
14 | ### Patch Changes
15 |
16 | - Updated dependencies [[`381b67c`](https://github.com/rasendubi/uniorg/commit/381b67cf0d64c5926754fce04b54aa0b86699b85), [`da9d596`](https://github.com/rasendubi/uniorg/commit/da9d596718fb3656833f5c3a3d2e0abd9667eaa1)]:
17 | - uniorg-parse@3.1.0
18 |
19 | ## 1.0.4
20 |
21 | ### Patch Changes
22 |
23 | - Updated dependencies [[`40ff5c5`](https://github.com/rasendubi/uniorg/commit/40ff5c5331c47f408484ba84daa2c18d81ba554d)]:
24 | - uniorg-rehype@2.1.0
25 |
26 | ## 1.0.3
27 |
28 | ### Patch Changes
29 |
30 | - Updated dependencies [[`dbf6452`](https://github.com/rasendubi/uniorg/commit/dbf6452921ad03120bb9df87746aef52ac72b5fb), [`b45baf9`](https://github.com/rasendubi/uniorg/commit/b45baf992db4659e2732e888bd3860b9eff25504)]:
31 | - uniorg-parse@3.0.0
32 | - uniorg-rehype@1.2.0
33 |
34 | ## 1.0.2
35 |
36 | ### Patch Changes
37 |
38 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
39 |
40 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
41 |
42 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
43 | - uniorg-extract-keywords@1.0.1
44 | - uniorg-rehype@1.1.1
45 | - uniorg-parse@2.1.1
46 |
47 | ## 1.0.1
48 |
49 | ### Patch Changes
50 |
51 | - Updated dependencies [[`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6), [`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6)]:
52 | - uniorg-parse@2.0.0
53 | - uniorg-rehype@1.1.0
54 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/README.md:
--------------------------------------------------------------------------------
1 | # A statically generated blog example using Next.js and Org
2 |
3 | This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using Org files as the data source.
4 |
5 | The blog posts are stored in `/_posts` as Org files. Adding a new Org file in there will create a new blog post.
6 |
7 | To create the blog posts we use [`uniorg`](https://github.com/rasendubi/uniorg) and [`rehype-stringify`][rehype-stringify] to convert the Org files into an HTML string, and then send it down as a prop to the page. The metadata of every post is handled by `extractExportSettings` unified plugin in [orgToHtml.js](./lib/orgToHtml.js) file.
8 |
9 | [rehype-stringify]: https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify
10 |
11 | ## Demo
12 |
13 | [https://org-blog-starter.vercel.app/](https://org-blog-starter.vercel.app/)
14 |
15 | ## Deploy your own
16 |
17 | Deploy the example using [Vercel](https://vercel.com):
18 |
19 | [](https://vercel.com/new/git/external?repository-url=https://github.com/rasendubi/uniorg/tree/main/examples/next-blog-starter&project-name=org-blog-starter&repository-name=org-blog-starter)
20 |
21 | ## How to use
22 |
23 | Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
24 |
25 | ```bash
26 | npx create-next-app --example https://github.com/rasendubi/uniorg/tree/main/examples/next-blog-starter blog-starter-app
27 | # or
28 | yarn create next-app --example https://github.com/rasendubi/uniorg/tree/main/examples/next-blog-starter blog-starter-app
29 | ```
30 |
31 | Your blog should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/rasendubi/uniorg/discussions).
32 |
33 | Deploy it to the cloud with [Vercel](https://vercel.com/new) ([Documentation](https://nextjs.org/docs/deployment)).
34 |
35 | # Notes
36 |
37 | This blog-starter uses [Tailwind CSS](https://tailwindcss.com). To control the generated stylesheet's filesize, this example uses Tailwind CSS' v2.0 [`purge` option](https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css) to remove unused CSS.
38 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/_posts/hello-world.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Learn How to Pre-render Pages Using Static Generation with Next.js
2 | #+EXCERPT: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.
3 | #+COVER_IMAGE: /assets/blog/hello-world/cover.jpg
4 | #+DATE: 2020-03-16T05:35:07.322Z
5 | #+AUTHOR: Tim Neutkens
6 | #+AUTHOR_PICTURE: /assets/blog/authors/tim.jpeg
7 | #+OG_IMAGE: /assets/blog/hello-world/cover.jpg
8 |
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
10 |
11 | Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt. Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae. Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
12 |
13 | ** Lorem Ipsum
14 |
15 | Tristique senectus et netus et malesuada fames ac turpis. Ridiculous mus mauris vitae ultricies leo integer malesuada nunc vel. In mollis nunc sed id semper. Egestas tellus rutrum tellus pellentesque. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Quis blandit turpis cursus in hac habitasse platea dictumst quisque. Eros donec ac odio tempor orci dapibus ultrices. Aliquam sem et tortor consequat id porta nibh. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla. Diam vulputate ut pharetra sit amet. Ut tellus elementum sagittis vitae et leo. Arcu non odio euismod lacinia at quis risus sed vulputate.
16 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/_posts/preview.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Preview Mode for Static Generation
2 | #+EXCERPT: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus.
3 | #+COVER_IMAGE: /assets/blog/preview/cover.jpg
4 | #+DATE: 2020-03-16T05:35:07.322Z
5 | #+AUTHOR: Joe Haddad
6 | #+AUTHOR_PICTURE: /assets/blog/authors/joe.jpeg
7 | #+OG_IMAGE: /assets/blog/preview/cover.jpg
8 |
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
10 |
11 | Venenatis cras sed felis eget velit. Consectetur libero id faucibus nisl tincidunt. Gravida in fermentum et sollicitudin ac orci phasellus egestas tellus. Volutpat consequat mauris nunc congue nisi vitae. Id aliquet risus feugiat in ante metus dictum at tempor. Sed blandit libero volutpat sed cras. Sed odio morbi quis commodo odio aenean sed adipiscing. Velit euismod in pellentesque massa placerat. Mi bibendum neque egestas congue quisque egestas diam in arcu. Nisi lacus sed viverra tellus in. Nibh cras pulvinar mattis nunc sed. Luctus accumsan tortor posuere ac ut consequat semper viverra. Fringilla ut morbi tincidunt augue interdum velit euismod.
12 |
13 | ** Lorem Ipsum
14 |
15 | Tristique senectus et netus et malesuada fames ac turpis. Ridiculous mus mauris vitae ultricies leo integer malesuada nunc vel. In mollis nunc sed id semper. Egestas tellus rutrum tellus pellentesque. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Quis blandit turpis cursus in hac habitasse platea dictumst quisque. Eros donec ac odio tempor orci dapibus ultrices. Aliquam sem et tortor consequat id porta nibh. Adipiscing elit duis tristique sollicitudin nibh sit amet commodo nulla. Diam vulputate ut pharetra sit amet. Ut tellus elementum sagittis vitae et leo. Arcu non odio euismod lacinia at quis risus sed vulputate.
16 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/_posts/uniorg.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Uniorg parsing example
2 | #+EXCERPT: Check out this post to see how Uniorg parses org files.
3 | #+COVER_IMAGE: /assets/blog/dynamic-routing/cover.jpg
4 | #+DATE: 2021-01-12T18:24Z
5 | #+AUTHOR: Oleksii Shmalko
6 | #+AUTHOR_PICTURE: /assets/blog/authors/jj.jpeg
7 | #+OG_IMAGE: /assets/blog/dynamic-routing/cover.jpg
8 |
9 | Paragraph:
10 |
11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Praesent elementum facilisis leo vel fringilla est ullamcorper eget. At imperdiet dui accumsan sit amet nulla facilities morbi tempus. Praesent elementum facilisis leo vel fringilla. Congue mauris rhoncus aenean vel. Egestas sed tempus urna et pharetra pharetra massa massa ultricies.
12 |
13 | ** Emphasis
14 |
15 | Supported: *bold* /italic/ ~code~ =verbatim= _underline_ +strike-through+.
16 |
17 | ** Links
18 |
19 | Plain link: https://github.com/rasendubi/uniorg.
20 |
21 | Regular link: [[https://github.com][Uniorg]].
22 |
23 | Angle link: .
24 |
25 | ** Lists
26 |
27 | - item 1
28 | - item 2
29 | 1. item 2.1
30 | - tag 1 :: description 1
31 | - tag 2 :: description 2
32 | 2. item 2.2
33 | - item 3
34 |
35 | ** Timestamps
36 | :PROPERTIES:
37 | :CREATED: [2021-01-12 Tue 21:38]
38 | :END:
39 |
40 | - Active: <2021-01-12 Tue>
41 | - Inactive: [2021-01-12 Tue]
42 |
43 | ** TODO Drawers
44 | CLOSED: [2021-01-12 Tue 21:43]
45 | :PROPERTIES:
46 | :CREATED: [2021-01-12 Tue 21:43]
47 | :END:
48 | :LOGBOOK:
49 | - State "DONE" from "TODO" [2021-01-12 Tue 21:43]
50 | :END:
51 | (not rendered)
52 | :MYDRAWER:
53 | hello, there
54 | :END:
55 |
56 | =# comment=: (not rendered)
57 | # some comment
58 |
59 | ** Blocks
60 | Source:
61 | #+begin_src js
62 | console.log('hello, world!');
63 | #+end_src
64 |
65 | Quote:
66 | #+begin_quote
67 | Some quote.
68 |
69 | —Some author
70 | #+end_quote
71 |
72 | Example:
73 | #+begin_example
74 | Example block.
75 | #+end_example
76 |
77 | Export block (needs ~rehype-raw~ to be rendered):
78 | #+begin_export html
79 | hello
80 | #+end_export
81 |
82 | Comment block (not rendered):
83 | #+begin_comment
84 | a comment block.
85 | #+end_comment
86 |
87 | ** Tables
88 |
89 | | heading 1 | heading 2 |
90 | |-----------+-----------|
91 | | item1 | item2 |
92 | | item2 | item3 |
93 |
94 | ** Fixed width
95 |
96 | : fixed with
97 | : text
98 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/alert.js:
--------------------------------------------------------------------------------
1 | import Container from './container.js';
2 | import cn from 'classnames';
3 | import { EXAMPLE_PATH } from '../lib/constants.js';
4 |
5 | export default function Alert({ preview }) {
6 | return (
7 |
13 |
14 |
15 | {preview ? (
16 | <>
17 | This page is a preview.{' '}
18 |
22 | Click here
23 | {' '}
24 | to exit preview mode.
25 | >
26 | ) : (
27 | <>
28 | The source code for this blog is{' '}
29 |
33 | available on GitHub
34 |
35 | .
36 | >
37 | )}
38 |
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/avatar.js:
--------------------------------------------------------------------------------
1 | export default function Avatar({ name, picture }) {
2 | return (
3 |
4 |
5 |
{name}
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/container.js:
--------------------------------------------------------------------------------
1 | export default function Container({ children }) {
2 | return {children}
;
3 | }
4 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/cover-image.js:
--------------------------------------------------------------------------------
1 | import cn from 'classnames';
2 | import Link from 'next/link';
3 | import Image from 'next/legacy/image';
4 |
5 | export default function CoverImage({ title, src, slug, height, width }) {
6 | const image = (
7 |
17 | );
18 | return (
19 |
20 | {slug ? (
21 |
22 | {image}
23 |
24 | ) : (
25 | image
26 | )}
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/date-formatter.js:
--------------------------------------------------------------------------------
1 | import { parseISO, format } from 'date-fns';
2 |
3 | export default function DateFormatter({ dateString }) {
4 | const date = parseISO(dateString);
5 | return {format(date, 'LLLL d, yyyy')} ;
6 | }
7 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/footer.js:
--------------------------------------------------------------------------------
1 | import Container from './container.js';
2 | import { EXAMPLE_PATH } from '../lib/constants.js';
3 |
4 | export default function Footer() {
5 | return (
6 |
7 |
8 |
9 |
10 | Statically Generated with Next.js and Uniorg.
11 |
12 |
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/header.js:
--------------------------------------------------------------------------------
1 | import Link from 'next/link';
2 |
3 | export default function Header() {
4 | return (
5 |
6 |
7 | Blog
8 |
9 | .
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/hero-post.js:
--------------------------------------------------------------------------------
1 | import Avatar from '../components/avatar.js';
2 | import DateFormatter from '../components/date-formatter.js';
3 | import CoverImage from '../components/cover-image.js';
4 | import Link from 'next/link';
5 |
6 | export default function HeroPost({
7 | title,
8 | coverImage,
9 | date,
10 | excerpt,
11 | author,
12 | authorPicture,
13 | slug,
14 | }) {
15 | return (
16 |
17 |
18 |
25 |
26 |
27 |
28 |
29 |
34 | {title}
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/intro.js:
--------------------------------------------------------------------------------
1 | import { CMS_NAME } from '../lib/constants.js';
2 |
3 | export default function Intro() {
4 | return (
5 |
6 |
7 | Blog.
8 |
9 |
10 | A statically generated blog example using{' '}
11 |
15 | Next.js
16 | {' '}
17 | and {CMS_NAME}.
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/layout.js:
--------------------------------------------------------------------------------
1 | import Alert from '../components/alert.js';
2 | import Footer from '../components/footer.js';
3 | import Meta from '../components/meta.js';
4 |
5 | export default function Layout({ preview, children }) {
6 | return (
7 | <>
8 |
9 |
10 |
11 |
{children}
12 |
13 |
14 | >
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/meta.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head';
2 | import { CMS_NAME, HOME_OG_IMAGE_URL } from '../lib/constants.js';
3 |
4 | export default function Meta() {
5 | return (
6 |
7 |
12 |
18 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/more-stories.js:
--------------------------------------------------------------------------------
1 | import PostPreview from '../components/post-preview.js';
2 |
3 | export default function MoreStories({ posts }) {
4 | return (
5 |
6 |
7 | More Stories
8 |
9 |
10 | {posts.map((post) => (
11 |
21 | ))}
22 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/org-styles.module.css:
--------------------------------------------------------------------------------
1 | .org {
2 | @apply text-lg leading-relaxed;
3 | }
4 |
5 | .org h2 {
6 | @apply text-3xl mt-12 mb-4 leading-snug;
7 | }
8 |
9 | .org h3 {
10 | @apply text-2xl mt-8 mb-4 leading-snug;
11 | }
12 |
13 | .org p,
14 | .org ul,
15 | .org ol,
16 | .org blockquote {
17 | @apply my-6;
18 | }
19 |
20 | .org ul,
21 | .org ol,
22 | .org dl {
23 | @apply ml-8;
24 | }
25 | .org ul {
26 | @apply list-disc;
27 | }
28 | .org ol {
29 | @apply list-decimal;
30 | }
31 | .org dt {
32 | @apply font-bold;
33 | }
34 | .org dd {
35 | @apply ml-8;
36 | }
37 |
38 | .org a {
39 | @apply underline hover:text-success duration-200 transition-colors;
40 | }
41 |
42 | .org blockquote {
43 | @apply ml-8 italic;
44 | }
45 |
46 | .org table {
47 | @apply border-collapse;
48 | }
49 | .org th, .org td {
50 | @apply border border-black p-1;
51 | }
52 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/post-body.js:
--------------------------------------------------------------------------------
1 | import orgStyles from './org-styles.module.css';
2 |
3 | export default function PostBody({ content }) {
4 | return (
5 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/post-header.js:
--------------------------------------------------------------------------------
1 | import Avatar from '../components/avatar.js';
2 | import DateFormatter from '../components/date-formatter.js';
3 | import CoverImage from '../components/cover-image.js';
4 | import PostTitle from '../components/post-title.js';
5 |
6 | export default function PostHeader({
7 | title,
8 | coverImage,
9 | date,
10 | author,
11 | authorPicture,
12 | }) {
13 | return (
14 | <>
15 | {title}
16 |
19 |
20 |
21 |
22 |
30 | >
31 | );
32 | }
33 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/post-preview.js:
--------------------------------------------------------------------------------
1 | import Avatar from '../components/avatar.js';
2 | import DateFormatter from '../components/date-formatter.js';
3 | import CoverImage from './cover-image.js';
4 | import Link from 'next/link';
5 |
6 | export default function PostPreview({
7 | title,
8 | coverImage,
9 | date,
10 | excerpt,
11 | author,
12 | authorPicture,
13 | slug,
14 | }) {
15 | return (
16 |
17 |
18 |
25 |
26 |
27 |
32 | {title}
33 |
34 |
35 |
36 |
37 |
38 |
{excerpt}
39 |
40 |
41 | );
42 | }
43 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/post-title.js:
--------------------------------------------------------------------------------
1 | export default function PostTitle({ children }) {
2 | return (
3 |
4 | {children}
5 |
6 | );
7 | }
8 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/components/section-separator.js:
--------------------------------------------------------------------------------
1 | export default function SectionSeparator() {
2 | return ;
3 | }
4 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/lib/api.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import { join } from 'path';
3 | import orgToHtml from './orgToHtml.js';
4 |
5 | const postsDirectory = join(process.cwd(), '_posts');
6 |
7 | export function getPostSlugs() {
8 | return fs.readdirSync(postsDirectory);
9 | }
10 |
11 | export function getPostBySlug(slug, fields = []) {
12 | const realSlug = slug.replace(/\.org$/, '');
13 | const fullPath = join(postsDirectory, `${realSlug}.org`);
14 | const content = fs.readFileSync(fullPath, 'utf8');
15 | const org = orgToHtml(content);
16 |
17 | const items = {};
18 |
19 | // Ensure only the minimal needed data is exposed
20 | fields.forEach((field) => {
21 | if (field === 'slug') {
22 | items[field] = realSlug;
23 | }
24 | if (field === 'content') {
25 | items[field] = String(org);
26 | }
27 | if (org.data[field]) {
28 | items[field] = org.data[field];
29 | }
30 | });
31 |
32 | return items;
33 | }
34 |
35 | export function getAllPosts(fields = []) {
36 | const slugs = getPostSlugs();
37 | const posts = slugs
38 | .map((slug) => getPostBySlug(slug, fields))
39 | // sort posts by date in descending order
40 | .sort((post1, post2) => (post1.date > post2.date ? '-1' : '1'));
41 | return posts;
42 | }
43 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/lib/constants.js:
--------------------------------------------------------------------------------
1 | export const EXAMPLE_PATH = 'next-blog-starter';
2 | export const CMS_NAME = 'Org';
3 | export const HOME_OG_IMAGE_URL =
4 | 'https://og-image.now.sh/Next.js%20Blog%20Starter%20Example.png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fassets.vercel.com%2Fimage%2Fupload%2Ffront%2Fassets%2Fdesign%2Fnextjs-black-logo.svg';
5 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/lib/orgToHtml.js:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 | import html from 'rehype-stringify';
3 |
4 | import uniorg from 'uniorg-parse';
5 | import uniorg2rehype from 'uniorg-rehype';
6 | import extractKeywords from 'uniorg-extract-keywords';
7 |
8 | const processor = unified()
9 | .use(uniorg)
10 | .use(extractKeywords)
11 | .use(uniorg2rehype)
12 | .use(html);
13 |
14 | export default function orgToHtml(org) {
15 | const result = processor.processSync(org);
16 | return result;
17 | }
18 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "blog-starter",
3 | "version": "1.0.6",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "dependencies": {
11 | "classnames": "2.5.1",
12 | "date-fns": "3.6.0",
13 | "next": "^14.2.3",
14 | "react": "18.3.1",
15 | "react-dom": "18.3.1",
16 | "rehype-stringify": "10.0.0",
17 | "unified": "11.0.4",
18 | "uniorg-extract-keywords": "workspace:^",
19 | "uniorg-parse": "workspace:^",
20 | "uniorg-rehype": "workspace:^"
21 | },
22 | "devDependencies": {
23 | "autoprefixer": "^10.4.19",
24 | "postcss": "^8.4.38",
25 | "postcss-preset-env": "^9.5.13",
26 | "sharp": "^0.33.4",
27 | "tailwindcss": "^3.4.3"
28 | },
29 | "license": "MIT"
30 | }
31 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/index.css';
2 |
3 | export default function MyApp({ Component, pageProps }) {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/pages/_document.js:
--------------------------------------------------------------------------------
1 | import Document, { Html, Head, Main, NextScript } from 'next/document';
2 |
3 | export default class MyDocument extends Document {
4 | render() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/pages/index.js:
--------------------------------------------------------------------------------
1 | import Container from '../components/container.js';
2 | import MoreStories from '../components/more-stories.js';
3 | import HeroPost from '../components/hero-post.js';
4 | import Intro from '../components/intro.js';
5 | import Layout from '../components/layout.js';
6 | import { getAllPosts } from '../lib/api.js';
7 | import Head from 'next/head';
8 | import { CMS_NAME } from '../lib/constants.js';
9 |
10 | export default function Index({ allPosts }) {
11 | const heroPost = allPosts[0];
12 | const morePosts = allPosts.slice(1);
13 | return (
14 | <>
15 |
16 |
17 | Next.js Blog Example with {CMS_NAME}
18 |
19 |
20 |
21 | {heroPost && (
22 |
31 | )}
32 | {morePosts.length > 0 && }
33 |
34 |
35 | >
36 | );
37 | }
38 |
39 | export async function getStaticProps() {
40 | const allPosts = getAllPosts([
41 | 'title',
42 | 'date',
43 | 'slug',
44 | 'author',
45 | 'author_picture',
46 | 'cover_image',
47 | 'excerpt',
48 | ]);
49 |
50 | return {
51 | props: { allPosts },
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/pages/posts/[slug].js:
--------------------------------------------------------------------------------
1 | import { useRouter } from 'next/router';
2 | import ErrorPage from 'next/error';
3 | import Container from '../../components/container.js';
4 | import PostBody from '../../components/post-body.js';
5 | import Header from '../../components/header.js';
6 | import PostHeader from '../../components/post-header.js';
7 | import Layout from '../../components/layout.js';
8 | import { getPostBySlug, getAllPosts } from '../../lib/api.js';
9 | import PostTitle from '../../components/post-title.js';
10 | import Head from 'next/head';
11 | import { CMS_NAME } from '../../lib/constants.js';
12 |
13 | export default function Post({ post, morePosts, preview }) {
14 | const router = useRouter();
15 | if (!router.isFallback && !post?.slug) {
16 | return ;
17 | }
18 | return (
19 |
20 |
21 |
22 | {router.isFallback ? (
23 | Loading…
24 | ) : (
25 | <>
26 |
27 |
28 |
29 | {post.title} | Next.js Blog Example with {CMS_NAME}
30 |
31 |
32 |
33 |
40 |
41 |
42 | >
43 | )}
44 |
45 |
46 | );
47 | }
48 |
49 | export async function getStaticProps({ params }) {
50 | const post = getPostBySlug(params.slug, [
51 | 'title',
52 | 'date',
53 | 'slug',
54 | 'author',
55 | 'author_picture',
56 | 'og_image',
57 | 'cover_image',
58 | 'content',
59 | ]);
60 |
61 | return {
62 | props: {
63 | post,
64 | },
65 | };
66 | }
67 |
68 | export async function getStaticPaths() {
69 | const posts = getAllPosts(['slug']);
70 |
71 | return {
72 | paths: posts.map((post) => {
73 | return {
74 | params: {
75 | slug: post.slug,
76 | },
77 | };
78 | }),
79 | fallback: false,
80 | };
81 | }
82 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: ['tailwindcss', 'postcss-preset-env'],
3 | };
4 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/authors/jj.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/authors/jj.jpeg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/authors/joe.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/authors/joe.jpeg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/authors/tim.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/authors/tim.jpeg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/dynamic-routing/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/dynamic-routing/cover.jpg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/hello-world/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/hello-world/cover.jpg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/assets/blog/preview/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/assets/blog/preview/cover.jpg
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #000000
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/examples/next-blog-starter/public/favicon/mstile-150x150.png
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/public/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Next.js",
3 | "short_name": "Next.js",
4 | "icons": [
5 | {
6 | "src": "/favicons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/favicons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#000000",
17 | "background_color": "#000000",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/styles/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 |
3 | /* Write your own custom base styles here */
4 |
5 | /* Start purging... */
6 | @tailwind components;
7 | /* Stop purging. */
8 |
9 | /* Write you own custom component styles here */
10 |
11 | /* Start purging... */
12 | @tailwind utilities;
13 | /* Stop purging. */
14 |
15 | /* Your own custom utilities */
16 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | purge: ['./components/**/*.js', './pages/**/*.js'],
3 | theme: {
4 | extend: {
5 | colors: {
6 | 'accent-1': '#FAFAFA',
7 | 'accent-2': '#EAEAEA',
8 | 'accent-7': '#333',
9 | success: '#0070f3',
10 | cyan: '#79FFE1',
11 | },
12 | spacing: {
13 | 28: '7rem',
14 | },
15 | letterSpacing: {
16 | tighter: '-.04em',
17 | },
18 | lineHeight: {
19 | tight: 1.2,
20 | },
21 | fontSize: {
22 | '5xl': '2.5rem',
23 | '6xl': '2.75rem',
24 | '7xl': '4.5rem',
25 | '8xl': '6.25rem',
26 | },
27 | boxShadow: {
28 | sm: '0 5px 10px rgba(0, 0, 0, 0.12)',
29 | md: '0 8px 30px rgba(0, 0, 0, 0.12)',
30 | },
31 | },
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/examples/next-blog-starter/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "github": {
3 | "silent": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/examples/org-braindump/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/examples/org-braindump/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # org-braindump
2 |
3 | ## 1.0.6
4 |
5 | ### Patch Changes
6 |
7 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317), [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
8 | - orgast-util-visit-ids@1.1.0
9 | - uniorg-extract-keywords@1.1.0
10 | - uniorg-parse@3.2.0
11 | - uniorg-rehype@2.2.0
12 | - uniorg-slug@1.1.0
13 |
14 | ## 1.0.5
15 |
16 | ### Patch Changes
17 |
18 | - Updated dependencies [[`381b67c`](https://github.com/rasendubi/uniorg/commit/381b67cf0d64c5926754fce04b54aa0b86699b85), [`da9d596`](https://github.com/rasendubi/uniorg/commit/da9d596718fb3656833f5c3a3d2e0abd9667eaa1)]:
19 | - uniorg-parse@3.1.0
20 |
21 | ## 1.0.4
22 |
23 | ### Patch Changes
24 |
25 | - Updated dependencies [[`40ff5c5`](https://github.com/rasendubi/uniorg/commit/40ff5c5331c47f408484ba84daa2c18d81ba554d)]:
26 | - uniorg-rehype@2.1.0
27 |
28 | ## 1.0.3
29 |
30 | ### Patch Changes
31 |
32 | - Updated dependencies [[`dbf6452`](https://github.com/rasendubi/uniorg/commit/dbf6452921ad03120bb9df87746aef52ac72b5fb), [`b45baf9`](https://github.com/rasendubi/uniorg/commit/b45baf992db4659e2732e888bd3860b9eff25504)]:
33 | - uniorg-parse@3.0.0
34 | - uniorg-rehype@1.2.0
35 |
36 | ## 1.0.2
37 |
38 | ### Patch Changes
39 |
40 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
41 |
42 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
43 |
44 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
45 | - uniorg-extract-keywords@1.0.1
46 | - orgast-util-visit-ids@1.0.1
47 | - uniorg-rehype@1.1.1
48 | - uniorg-parse@2.1.1
49 | - uniorg-slug@1.0.1
50 |
51 | ## 1.0.1
52 |
53 | ### Patch Changes
54 |
55 | - Updated dependencies [[`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6), [`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6)]:
56 | - uniorg-parse@2.0.0
57 | - uniorg-rehype@1.1.0
58 |
--------------------------------------------------------------------------------
/examples/org-braindump/README.md:
--------------------------------------------------------------------------------
1 | # org-braindump
2 |
3 | This example showcases how you can use [uniorg][uniorg] and [Next.js][nextjs] to publish a simple website from Org files. It is tailored to publishing a collection of interlinked notes.
4 |
5 | It is compatible with [org-roam][org-roam] but org-roam is not a requirement.
6 |
7 | [uniorg]: https://github.com/rasendubi/uniorg
8 | [nextjs]: https://nextjs.org/
9 | [org-roam]: https://github.com/org-roam/org-roam
10 |
11 | ## Demo
12 |
13 | [https://org-braindump.vercel.app](https://org-braindump.vercel.app)
14 |
15 | ## Deploy your own
16 |
17 | Deploy the example using [Vercel](https://vercel.com):
18 |
19 | [](https://vercel.com/new/git/external?repository-url=https://github.com/rasendubi/uniorg/tree/main/examples/org-braindump&project-name=org-blog-starter&repository-name=braindump)
20 |
21 | ## How to use
22 |
23 | Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:
24 |
25 | ```bash
26 | npx create-next-app --example https://github.com/rasendubi/uniorg/tree/main/examples/org-braindump braindump
27 | # or
28 | yarn create next-app --example https://github.com/rasendubi/uniorg/tree/main/examples/org-braindump braindump
29 | ```
30 |
31 | Your braindump should be up and running on [http://localhost:3000](http://localhost:3000)! If it doesn't work, post on [GitHub discussions](https://github.com/rasendubi/uniorg/discussions).
32 |
33 | Deploy it to the cloud with [Vercel](https://vercel.com/new) ([Documentation](https://nextjs.org/docs/deployment)).
34 |
--------------------------------------------------------------------------------
/examples/org-braindump/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "org-braindump",
3 | "version": "1.0.6",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "dependencies": {
11 | "next": "^14.2.3",
12 | "orgast-util-visit-ids": "workspace:^",
13 | "react": "18.3.1",
14 | "react-dom": "18.3.1",
15 | "rehype-react": "8.0.0",
16 | "rehype-url-inspector": "^2.0.2",
17 | "sharp": "^0.33.4",
18 | "to-vfile": "^8.0.0",
19 | "trough": "2.2.0",
20 | "unified": "11.0.4",
21 | "uniorg-extract-keywords": "workspace:^",
22 | "uniorg-parse": "workspace:^",
23 | "uniorg-rehype": "workspace:^",
24 | "uniorg-slug": "workspace:^",
25 | "vfile-find-down": "7.1.0",
26 | "vfile-reporter": "8.1.1"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/archive-page.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Archive page
2 |
3 | [[file:./archive][/archive]] is a special page that contains a list of all pages. It is generated from [[https://github.com/rasendubi/uniorg/blob/main/examples/org-braindump/src/pages/archive.jsx][src/pages/archive.jsx]].
4 |
5 | If you don't want it, you can simply delete the =archive.jsx= file.
6 | If you want it at another location—rename the file.
7 | If you want it to be the starting page, rename it to =index.jsx= and delete =public/index.org= file.
8 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/changing-posts-directory.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Changing posts directory
2 |
3 | By default, all posts are stored in “public” directory.
4 |
5 | If you want to change this directory, you can do that in =src/lib/api.js= file, ~pagesDirectory~ variable. When doing so, make sure you're copying all assets to “public” directory so that next.js serves them along with your pages.
6 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/code-highlight.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Code highlight
2 |
3 | If you want to enable code highlight, you can use [[https://github.com/rehypejs/rehype-highlight][rehype-highlight]] or [[https://github.com/mapbox/rehype-prism][@mapbox/rehype-prism]] plugin.
4 |
5 | Modify =src/lib/orgToHtml.js= and add your plugin of choice after ~org2rehype~, modify styles to include your theme (see [[file:./styling.org][Styling]]).
6 | uniorg-rehype attaches all necessary =language-{name}= classes, so you don't have to worry about this bit.
7 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/id-links.org:
--------------------------------------------------------------------------------
1 | :PROPERTIES:
2 | :ID: 13e0b822-80a1-4faa-8e13-e768e8cecb65
3 | :END:
4 | #+TITLE: Id links
5 |
6 | [[id:536afe10-a7fe-4067-9523-0c4a41872387][org-roam v2]] uses id links exclusively, and org-braindump template supports that.
7 |
8 | You can annotate any headline or file with an id:
9 | #+begin_src org
10 | ,* My headline
11 | :PROPERTIES:
12 | :ID: 13e0b822-80a1-4faa-8e13-e768e8cecb65
13 | :END:
14 | #+end_src
15 |
16 | and then use this id in links across your braindump:
17 | #+begin_src org
18 | link to [[id:13e0b822-80a1-4faa-8e13-e768e8cecb65][My headline]]
19 | #+end_src
20 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/index.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Uniorg braindump example
2 |
3 | This is an example braindump built with [[https://github.com/rasendubi/uniorg][uniorg]] and [[https://nextjs.org/][Next.js]].
4 |
5 | Source code is available [[https://github.com/rasendubi/uniorg/tree/main/examples/org-braindump][at GitHub]].
6 |
7 | You can use ~create-next-app~ to bootstrap the example for you:
8 | #+begin_src sh
9 | npx create-next-app --example https://github.com/rasendubi/uniorg/tree/main/examples/org-braindump
10 | #+end_src
11 |
12 | * Learn about this template
13 | - [[file:./uniorg.org][uniorg]]
14 | - [[file:./styling.org][Styling]]
15 | - [[file:./code-highlight.org][Code highlight]]
16 | - [[file:./changing-posts-directory.org][Changing posts directory]]
17 | - [[file:./archive-page][Archive page]]
18 | - [[file:./org-roam.org][org-roam]]
19 | - [[file:./id-links.org][Id links]]
20 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/org-roam.org:
--------------------------------------------------------------------------------
1 | #+TITLE: org-roam
2 |
3 | [[https://github.com/org-roam/org-roam][org-roam]] is plain-text knowledge management system. You can use org-roam with this example but that is not a requirement.
4 |
5 | ** org-roam v2
6 | :PROPERTIES:
7 | :ID: 536afe10-a7fe-4067-9523-0c4a41872387
8 | :END:
9 |
10 | If you're using org-roam v2, you should know that [[id:13e0b822-80a1-4faa-8e13-e768e8cecb65][id links]] are fully supported in this template.
11 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/styling.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Styling
2 |
3 | To style your braindump, edit [[https://github.com/rasendubi/uniorg/blob/main/examples/org-braindump/src/styles/globals.css][src/styles/globals.css]] style file.
4 |
5 | Alternatively, you can import any CSS file in [[https://github.com/rasendubi/uniorg/blob/main/examples/org-braindump/src/pages/_app.js][src/pages/_app.js]].
6 |
--------------------------------------------------------------------------------
/examples/org-braindump/public/uniorg.org:
--------------------------------------------------------------------------------
1 | #+TITLE: uniorg
2 |
3 | [[https://github.com/rasendubi/uniorg][uniorg]] is an accurate org-mode parser that powers this website.
4 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/components/Link.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NextLink from 'next/link';
3 |
4 | const MyLink = ({ href, ...props }) => {
5 | return ;
6 | };
7 |
8 | export default MyLink;
9 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/components/Rehype.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import { unified } from 'unified';
4 | import rehype2react from 'rehype-react';
5 | import * as prod from 'react/jsx-runtime';
6 |
7 | import Link from './Link.jsx';
8 |
9 | // we use rehype-react to process hast and transform it to React
10 | // component, which allows as replacing some of components with custom
11 | // implementation. e.g., we can replace all links to use
12 | // `next/link`.
13 | const processor = unified().use(rehype2react, {
14 | jsx: prod.jsx,
15 | jsxs: prod.jsxs,
16 | Fragment: prod.Fragment,
17 | // createElement: React.createElement,
18 | // Fragment: React.Fragment,
19 | components: {
20 | a: Link,
21 | },
22 | });
23 |
24 | const Rehype = ({ hast }) => {
25 | return <>{processor.stringify(hast)}>;
26 | };
27 |
28 | export default Rehype;
29 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/lib/api.js:
--------------------------------------------------------------------------------
1 | import * as path from 'path';
2 | import { trough } from 'trough';
3 | import { read } from 'to-vfile';
4 | import { findDownAll } from 'vfile-find-down';
5 | import report from 'vfile-reporter';
6 |
7 | import orgToHtml from './orgToHtml.js';
8 | import resolveLinks from './resolveLinks.js';
9 |
10 | // We serve posts from "public" directory, so that we don't have to
11 | // copy assets.
12 | //
13 | // If you change this directory, make sure you copy all assets
14 | // (images, linked files) to the public directory, so that next.js
15 | // serves them.
16 | const pagesDirectory = path.join(process.cwd(), 'public');
17 |
18 | const processor = trough()
19 | .use(collectFiles)
20 | .use(processPosts)
21 | .use(resolveLinks)
22 | .use(populateBacklinks);
23 |
24 | async function collectFiles(root) {
25 | const files = await findDownAll('.org', root);
26 | files.forEach((f) => {
27 | const slug = '/' + path.relative(root, f.path).replace(/\.org$/, '');
28 | f.data.slug = slug;
29 | });
30 | return files;
31 | }
32 |
33 | async function processPosts(files) {
34 | return Promise.all(files.map(processPost));
35 |
36 | async function processPost(file) {
37 | try {
38 | await read(file, 'utf8');
39 | } catch (e) {
40 | console.error('Error reading file', file, e);
41 | throw e;
42 | }
43 |
44 | file.path = file.data.slug;
45 |
46 | await orgToHtml(file);
47 |
48 | return file;
49 | }
50 | }
51 |
52 | // Assign all collected backlinks to file. This function should be
53 | // called after all pages have been processed---otherwise, it might
54 | // miss backlinks.
55 | function populateBacklinks(files) {
56 | const backlinks = {};
57 | files.forEach((file) => {
58 | file.data.links = file.data.links || new Set();
59 | file.data.backlinks = backlinks[file.data.slug] =
60 | backlinks[file.data.slug] || new Set();
61 |
62 | file.data.links.forEach((other) => {
63 | const decodedOther = decodeURIComponent(other);
64 | backlinks[decodedOther] = backlinks[decodedOther] || new Set();
65 | backlinks[decodedOther].add(file.data.slug);
66 | });
67 | });
68 | }
69 |
70 | const loadPosts = async () => {
71 | const files = await new Promise((resolve, reject) =>
72 | processor.run(pagesDirectory, (err, files) => {
73 | console.error(report(err || files, { quiet: true }));
74 | if (err) reject(err);
75 | else resolve(files);
76 | })
77 | );
78 | const posts = Object.fromEntries(files.map((f) => [f.data.slug, f]));
79 | return posts;
80 | };
81 |
82 | const allPosts = async () => {
83 | const posts = await loadPosts();
84 | return posts;
85 | };
86 |
87 | export async function getAllPaths() {
88 | const posts = await loadPosts();
89 | return Object.keys(posts);
90 | }
91 |
92 | export async function getPostBySlug(slug) {
93 | const posts = await allPosts();
94 | const post = await posts[slug];
95 | return post;
96 | }
97 |
98 | export async function getAllPosts() {
99 | const posts = await allPosts();
100 | return await Promise.all(Object.values(posts));
101 | }
102 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/lib/orgToHtml.js:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 |
3 | import orgParse from 'uniorg-parse';
4 | import org2rehype from 'uniorg-rehype';
5 | import extractKeywords from 'uniorg-extract-keywords';
6 | import { uniorgSlug } from 'uniorg-slug';
7 | import { visitIds } from 'orgast-util-visit-ids';
8 |
9 | const processor = unified()
10 | .use(orgParse)
11 | .use(extractKeywords)
12 | .use(uniorgSlug)
13 | .use(extractIds)
14 | .use(org2rehype)
15 | .use(toJson);
16 |
17 | export default async function orgToHtml(file) {
18 | try {
19 | return await processor.process(file);
20 | } catch (e) {
21 | console.error('failed to process file', file.path, e);
22 | throw e;
23 | }
24 | }
25 |
26 | function extractIds() {
27 | return transformer;
28 |
29 | function transformer(tree, file) {
30 | const data = file.data || (file.data = {});
31 | // ids is a map: id => #anchor
32 | const ids = data.ids || (data.ids = {});
33 |
34 | visitIds(tree, (id, node) => {
35 | if (node.type === 'org-data') {
36 | ids[id] = '';
37 | } else if (node.type === 'section') {
38 | const headline = node.children[0];
39 | if (!headline.data?.hProperties?.id) {
40 | // The headline doesn't have an html id assigned. (Did you
41 | // remove uniorg-slug?)
42 | //
43 | // Assign an html id property based on org id property.
44 | headline.data = headline.data || {};
45 | headline.data.hProperties = headline.data.hProperties || {};
46 | headline.data.hProperties.id = id;
47 | }
48 |
49 | ids[id] = '#' + headline.data.hProperties.id;
50 | }
51 | });
52 | }
53 | }
54 |
55 | /** A primitive compiler to return node as is without stringifying. */
56 | function toJson() {
57 | this.Compiler = (node) => {
58 | return node;
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/lib/resolveLinks.js:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 | import inspectUrls from 'rehype-url-inspector';
3 |
4 | export default function resolveLinks(files) {
5 | // map from id -> { path, url }
6 | const idMap = {};
7 | files.forEach((file) => {
8 | Object.entries(file.data.ids).forEach(([id, anchor]) => {
9 | idMap[id] = { path: file.path, anchor };
10 | });
11 | });
12 |
13 | const processor = unified()
14 | .use(fromJson)
15 | .use(inspectUrls, { inspectEach: processUrl })
16 | .use(toJson);
17 |
18 | return Promise.all(files.map((file) => processor.process(file)));
19 |
20 | /**
21 | * Process each link to:
22 | * 1. Resolve id links.
23 | * 2. Convert relative file:// links to path used by
24 | * blog. file://file.org -> /file.org
25 | * 3. Collect all links to file.data.links, so they can be used later
26 | * to calculate backlinks.
27 | */
28 | function processUrl({ url: urlString, propertyName, node, file }) {
29 | try {
30 | // next/link does not handle relative urls properly. Use
31 | // file.path (the slug of the file) to normalize link against.
32 | let url = new URL(urlString, 'file://' + file.path);
33 |
34 | // process id links
35 | if (url.protocol === 'id:') {
36 | const id = url.pathname;
37 | const ref = idMap[id];
38 | if (ref) {
39 | url = new URL(`file://${ref.path}${ref.anchor}`);
40 | } else {
41 | console.warn(`${file.path}: Unresolved id link`, urlString);
42 | }
43 | // fallthrough. id links are re-processed as file links
44 | }
45 |
46 | if (url.protocol === 'file:') {
47 | let href = url.pathname.replace(/\.org$/, '');
48 | node.properties[propertyName] = href + url.hash;
49 |
50 | file.data.links = file.data.links || [];
51 | file.data.links.push(href);
52 | }
53 | } catch (e) {
54 | // This can happen if org file contains an invalid string, that
55 | // looks like URL string (e.g., "http://example.com:blah/"
56 | // passes regexes, but fails to parse as URL).
57 | console.warn(`${file.path}: Failed to process URL`, urlString, e);
58 | // No re-throwing: the issue is not critical enough to stop
59 | // processing. The document is still valid, it's just link that
60 | // isn't.
61 | }
62 | }
63 | }
64 |
65 | function fromJson() {
66 | this.Parser = (node, file) => {
67 | return file.result || JSON.parse(node);
68 | };
69 | }
70 |
71 | function toJson() {
72 | this.Compiler = (node) => {
73 | return node;
74 | };
75 | }
76 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/pages/[[...slug]].jsx:
--------------------------------------------------------------------------------
1 | import { join } from 'path';
2 | import Head from 'next/head';
3 |
4 | import { getAllPaths, getPostBySlug } from '../lib/api.js';
5 |
6 | import Link from '../components/Link.jsx';
7 | import Rehype from '../components/Rehype.jsx';
8 |
9 | const Note = ({ title, hast, backlinks }) => {
10 | return (
11 |
12 |
13 | {title}
14 |
15 | {title}
16 |
17 | {!!backlinks.length && (
18 |
19 | {'Backlinks'}
20 |
21 | {backlinks.map((b) => (
22 |
23 | {b.title}
24 |
25 | ))}
26 |
27 |
28 | )}
29 |
30 | );
31 | };
32 | export default Note;
33 |
34 | export const getStaticPaths = async () => {
35 | const paths = await getAllPaths();
36 | // add '/' which is synonymous to '/index'
37 | paths.push('/');
38 |
39 | return {
40 | paths,
41 | fallback: false,
42 | };
43 | };
44 |
45 | export const getStaticProps = async ({ params }) => {
46 | const path = '/' + join(...(params.slug || ['index']));
47 | const post = await getPostBySlug(path);
48 | const data = post.data;
49 | const backlinks = await Promise.all([...data.backlinks].map(getPostBySlug));
50 | return {
51 | props: {
52 | title: data.title || post.basename,
53 | hast: post.result,
54 | backlinks: backlinks.map((b) => ({
55 | path: b.path,
56 | title: b.data.title || b.basename,
57 | })),
58 | },
59 | };
60 | };
61 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css';
2 |
3 | function MyApp({ Component, pageProps }) {
4 | return ;
5 | }
6 |
7 | export default MyApp;
8 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/pages/archive.jsx:
--------------------------------------------------------------------------------
1 | import Head from 'next/head';
2 |
3 | import { getAllPosts } from '../lib/api.js';
4 | import Link from '../components/Link.jsx';
5 |
6 | const Archive = ({ posts }) => {
7 | return (
8 |
9 |
10 | {'Archive'}
11 |
12 | {'Archive'}
13 |
14 | {posts.map((p) => (
15 |
16 | {p.title}
17 |
18 | ))}
19 |
20 |
21 | );
22 | };
23 | export default Archive;
24 |
25 | export const getStaticProps = async () => {
26 | const allPosts = await getAllPosts();
27 | const posts = allPosts
28 | .map((p) => ({ title: p.data.title || p.basename, path: p.path }))
29 | .sort((a, b) => {
30 | return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : 1;
31 | });
32 | return { props: { posts } };
33 | };
34 |
--------------------------------------------------------------------------------
/examples/org-braindump/src/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 |
8 | line-height: 1.5;
9 | word-wrap: break-word;
10 | overflow-wrap: break-word;
11 | }
12 |
13 | * {
14 | box-sizing: border-box;
15 | }
16 |
17 | #__next {
18 | margin: 16px;
19 | }
20 |
21 | main {
22 | max-width: 800px;
23 | margin: auto;
24 | }
25 |
26 | pre {
27 | background-color: #eee;
28 | padding: 4px;
29 | overflow: auto;
30 | }
31 | code {
32 | background-color: #eee;
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/examples/org-braindump/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "github": {
3 | "silent": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "flake-utils": {
4 | "inputs": {
5 | "systems": "systems"
6 | },
7 | "locked": {
8 | "lastModified": 1731533236,
9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10 | "owner": "numtide",
11 | "repo": "flake-utils",
12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13 | "type": "github"
14 | },
15 | "original": {
16 | "owner": "numtide",
17 | "repo": "flake-utils",
18 | "type": "github"
19 | }
20 | },
21 | "nixpkgs": {
22 | "locked": {
23 | "lastModified": 1743231893,
24 | "narHash": "sha256-tpJsHMUPEhEnzySoQxx7+kA+KUtgWqvlcUBqROYNNt0=",
25 | "owner": "NixOS",
26 | "repo": "nixpkgs",
27 | "rev": "c570c1f5304493cafe133b8d843c7c1c4a10d3a6",
28 | "type": "github"
29 | },
30 | "original": {
31 | "owner": "NixOS",
32 | "ref": "nixos-24.11",
33 | "repo": "nixpkgs",
34 | "type": "github"
35 | }
36 | },
37 | "root": {
38 | "inputs": {
39 | "flake-utils": "flake-utils",
40 | "nixpkgs": "nixpkgs"
41 | }
42 | },
43 | "systems": {
44 | "locked": {
45 | "lastModified": 1681028828,
46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
47 | "owner": "nix-systems",
48 | "repo": "default",
49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
50 | "type": "github"
51 | },
52 | "original": {
53 | "owner": "nix-systems",
54 | "repo": "default",
55 | "type": "github"
56 | }
57 | }
58 | },
59 | "root": "root",
60 | "version": 7
61 | }
62 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "Uniorg development flake.";
3 |
4 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
5 | inputs.flake-utils.url = "github:numtide/flake-utils";
6 |
7 | outputs = { self, nixpkgs, flake-utils }:
8 | flake-utils.lib.eachDefaultSystem (system:
9 | let
10 | pkgs = nixpkgs.legacyPackages.${system};
11 | in {
12 | devShell = pkgs.mkShell {
13 | nativeBuildInputs = with pkgs; [
14 | nodejs_22
15 | nodejs_22.pkgs.pnpm
16 | ];
17 | };
18 | });
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/jest-base.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | testMatch: ['**/src/**/*.spec.ts'],
3 | testEnvironment: 'node',
4 | transform: {
5 | '^.+\\.[tj]sx?$': [
6 | 'ts-jest',
7 | {
8 | useESM: true,
9 | },
10 | ],
11 | },
12 | transformIgnorePatterns: [],
13 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
14 | extensionsToTreatAsEsm: ['.ts'],
15 |
16 | // Jest doesn't support prettier-3
17 | prettierPath: null,
18 | snapshotFormat: {
19 | // Jest-29 removed string escaping by default. Enable it back to
20 | // keep old snapshots compatible.
21 | escapeString: true,
22 | },
23 |
24 | collectCoverage: !!process.env.CI,
25 |
26 | // This re-mapping is required because of
27 | // https://github.com/microsoft/TypeScript/issues/16577.
28 | //
29 | // 1. ESM module imports don't try guessing extensions, so .js is required.
30 | // 2. Typescript is not going to add .js automatically to relative
31 | // imports, so we manually specify .js for all imports. However,
32 | // typescript properly resolves .js to .ts files, so type
33 | // checking works.
34 | // 3. ts-jest, however, does not resolve .js -> .ts, so the
35 | // following remapping is required.
36 | moduleNameMapper: {
37 | '^(\\.{1,2}/.*)\\.js$': '$1',
38 | },
39 | };
40 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | projects: ['/packages/*'],
3 | // do not search for tests starting from the root directory
4 | testMatch: ['!**'],
5 | };
6 |
--------------------------------------------------------------------------------
/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-root",
3 | "private": true,
4 | "type": "module",
5 | "scripts": {
6 | "clean": "turbo clean",
7 | "build": "turbo build",
8 | "dev": "turbo dev",
9 | "test": "jest",
10 | "ci": "turbo lint build test",
11 | "version": "changeset version && pnpm install --frozen-lockfile=false",
12 | "publish": "turbo build --filter='!./examples/*' && pnpm publish -r && changeset tag"
13 | },
14 | "devDependencies": {
15 | "@changesets/changelog-github": "^0.5.1",
16 | "@changesets/cli": "2.28.1",
17 | "eslint": "^9.23.0",
18 | "jest": "^29.7.0",
19 | "prettier": "^3.5.3",
20 | "ts-jest": "^29.3.0",
21 | "turbo": "^2.4.4",
22 | "typescript": "5.8.2"
23 | },
24 | "packageManager": "pnpm@9.15.9"
25 | }
26 |
--------------------------------------------------------------------------------
/packages/astro-org/.gitignore:
--------------------------------------------------------------------------------
1 | /dist/
2 |
--------------------------------------------------------------------------------
/packages/astro-org/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/astro-org/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-org",
3 | "version": "4.0.0",
4 | "description": "Astro plugin to import org-mode files.",
5 | "type": "module",
6 | "main": "dist/index.js",
7 | "types": "dist/index.d.ts",
8 | "exports": {
9 | ".": "./dist/index.js",
10 | "./server.js": "./dist/server.js"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/rasendubi/uniorg.git"
15 | },
16 | "keywords": [
17 | "astro",
18 | "astro-integration",
19 | "org-mode",
20 | "uniorg"
21 | ],
22 | "author": "Oleksii Shmalko ",
23 | "license": "GPL-3.0-or-later",
24 | "bugs": {
25 | "url": "https://github.com/rasendubi/uniorg/issues"
26 | },
27 | "homepage": "https://github.com/rasendubi/uniorg#readme",
28 | "scripts": {
29 | "build": "rm -rf ./dist && tsc -p tsconfig.build.json",
30 | "clean": "rm -rf ./dist",
31 | "compile": "tsc -p tsconfig.build.json",
32 | "prepublishOnly": "npm run build"
33 | },
34 | "dependencies": {
35 | "acorn": "^8.11.3",
36 | "orgast-util-visit-ids": "^1.0.0",
37 | "rollup-plugin-orgx": "workspace:^2.0.0",
38 | "unified": "^11.0.4",
39 | "uniorg-extract-keywords": "workspace:^1.0.0",
40 | "uniorg-slug": "workspace:^1.0.1",
41 | "vfile": "^6.0.1"
42 | },
43 | "devDependencies": {
44 | "@types/node": "^20.12.12",
45 | "astro": "^5.0.0",
46 | "typescript": "^5.4.5",
47 | "uniorg-parse": "workspace:*",
48 | "uniorg-rehype": "workspace:*"
49 | },
50 | "peerDependencies": {
51 | "astro": "^5.0.0",
52 | "uniorg-parse": ">=1.0.0 <4.0.0",
53 | "uniorg-rehype": ">=1.0.0 <3.0.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/astro-org/src/plugin/rehype-export-frontmatter.ts:
--------------------------------------------------------------------------------
1 | import type { Options } from 'acorn';
2 | import { parse } from 'acorn';
3 |
4 | export const rehypeExportFrontmatter = () => {
5 | return (tree: any, file: any) => {
6 | const astro = file.data.astro;
7 |
8 | tree.children.push(
9 | jsToTreeNode(
10 | `export const frontmatter = ${JSON.stringify(astro.frontmatter)};`
11 | )
12 | );
13 | tree.children.push(
14 | jsToTreeNode(`export const ids = ${JSON.stringify(astro.ids)}`)
15 | );
16 | };
17 | };
18 |
19 | function jsToTreeNode(
20 | jsString: string,
21 | acornOpts: Options = {
22 | ecmaVersion: 'latest',
23 | sourceType: 'module',
24 | }
25 | ) {
26 | return {
27 | type: 'mdxjsEsm',
28 | value: '',
29 | data: {
30 | estree: {
31 | ...parse(jsString, acornOpts),
32 | type: 'Program',
33 | sourceType: 'module',
34 | },
35 | },
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/packages/astro-org/src/server.ts:
--------------------------------------------------------------------------------
1 | import type { NamedSSRLoadedRendererValue } from 'astro';
2 | import { AstroError } from 'astro/errors';
3 | import { AstroJSX, jsx } from 'astro/jsx-runtime';
4 | import { renderJSX } from 'astro/runtime/server/index.js';
5 |
6 | const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
7 |
8 | // This check function is used to determine if the component is rendered by this renderer
9 | export async function check(
10 | Component: any,
11 | props: any,
12 | { default: children = null, ...slotted } = {},
13 | ) {
14 | if (typeof Component !== 'function') return false;
15 | const slots: Record = {};
16 | for (const [key, value] of Object.entries(slotted)) {
17 | const name = slotName(key);
18 | slots[name] = value;
19 | }
20 | try {
21 | const result = await Component({ ...props, ...slots, children });
22 | return result[AstroJSX];
23 | } catch (e) {
24 | throwEnhancedErrorIfOrgComponent(e as Error, Component);
25 | }
26 | return false;
27 | }
28 |
29 | export async function renderToStaticMarkup(
30 | this: any,
31 | Component: any,
32 | props = {},
33 | { default: children = null, ...slotted } = {},
34 | ) {
35 | const slots: Record = {};
36 | for (const [key, value] of Object.entries(slotted)) {
37 | const name = slotName(key);
38 | slots[name] = value;
39 | }
40 |
41 | const { result } = this;
42 | try {
43 | const html = await renderJSX(result, jsx(Component, { ...props, ...slots, children }));
44 | return { html };
45 | } catch (e) {
46 | throwEnhancedErrorIfOrgComponent(e as Error, Component);
47 | throw e;
48 | }
49 | }
50 |
51 | function throwEnhancedErrorIfOrgComponent(error: Error, Component: any) {
52 | // if the exception is from an org component
53 | // throw an error
54 | if (Component[Symbol.for('org-component')]) {
55 | // if it's an existing AstroError, we don't need to re-throw, keep the original hint
56 | if (AstroError.is(error)) return;
57 | // Provide better title and hint for the error overlay
58 | (error as any).title = error.name;
59 | (error as any).hint =
60 | `This issue often occurs when your Org component encounters runtime errors.`;
61 | throw error;
62 | }
63 | }
64 |
65 | const renderer: NamedSSRLoadedRendererValue = {
66 | name: 'astro:jsx',
67 | check,
68 | renderToStaticMarkup,
69 | };
70 |
71 | export default renderer;
--------------------------------------------------------------------------------
/packages/astro-org/template/content-module-types.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'astro:content' {
2 | interface Render {
3 | '.org': Promise<{
4 | Content: import('astro').MarkdownInstance<{}>['Content'];
5 | // headings: import('astro').MarkdownHeading[];
6 | // remarkPluginFrontmatter: Record;
7 | }>;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/astro-org/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "skipLibCheck": true,
5 | "outDir": "./dist",
6 | "moduleResolution": "NodeNext",
7 | "module": "NodeNext"
8 | },
9 | "include": ["./src"]
10 | }
11 |
--------------------------------------------------------------------------------
/packages/astro-org/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./dist",
5 | "moduleResolution": "NodeNext",
6 | "module": "NodeNext"
7 | },
8 | "include": ["./src"]
9 | }
10 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # orgast-util-to-string
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ## 1.0.1
12 |
13 | ### Patch Changes
14 |
15 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
16 |
17 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
18 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/README.md:
--------------------------------------------------------------------------------
1 | # `orgast-util-to-string`
2 |
3 | orgast (uniorg) utility to get the plain text content of a node.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install orgast-util-to-string
9 | ```
10 |
11 | ## Use
12 |
13 | ```js
14 | import { unified } from 'unified';
15 | import uniorgParse from 'uniorg-parse';
16 | import { toString } from 'orgast-util-to-string';
17 |
18 | const tree = unified()
19 | .use(uniorgParse)
20 | .parse('Some /emphasis/, *importance*, and ~code~.');
21 |
22 | console.log(toString(tree)); //=> 'Some emphasis, importance, and code.'
23 | ```
24 |
25 | ## API
26 |
27 | ### `toString(node[, options])`
28 |
29 | Get the text content of a node or list of nodes.
30 |
31 | The algorithm checks `value` of `node`. If no value is found, the algorithm checks the children of `node` and joins them (without spaces or newlines).
32 |
33 | > This is not an org-mode to plain-text library.
34 |
35 | ## License
36 |
37 | [GNU General Public License v3.0 or later](./LICENSE)
38 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "orgast-util-to-string",
3 | "version": "1.1.0",
4 | "type": "module",
5 | "description": "uniorg (orgast) utility to get the plain text content of a node",
6 | "keywords": [
7 | "uniorg",
8 | "orgast",
9 | "orgast-util",
10 | "util",
11 | "org-mode",
12 | "string"
13 | ],
14 | "author": "Oleksii Shmalko ",
15 | "homepage": "https://github.com/rasendubi/uniorg",
16 | "license": "GPL-3.0-or-later",
17 | "main": "lib/index.js",
18 | "types": "lib/index.d.ts",
19 | "directories": {
20 | "lib": "lib",
21 | "test": "__tests__"
22 | },
23 | "files": [
24 | "lib"
25 | ],
26 | "repository": {
27 | "type": "git",
28 | "url": "git+https://github.com/rasendubi/uniorg.git"
29 | },
30 | "scripts": {
31 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
32 | "clean": "rm -rf ./lib",
33 | "compile": "tsc -p tsconfig.build.json",
34 | "prepublishOnly": "npm run build",
35 | "test": "jest"
36 | },
37 | "bugs": {
38 | "url": "https://github.com/rasendubi/uniorg/issues"
39 | },
40 | "dependencies": {
41 | "@types/unist": "^3.0.2"
42 | },
43 | "devDependencies": {
44 | "@types/jest": "29.5.12",
45 | "jest": "29.7.0",
46 | "typescript": "5.4.5",
47 | "uniorg": "workspace:^1.3.0",
48 | "uniorg-parse": "workspace:^3.2.0"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import toString from './';
2 |
3 | import { parse } from 'uniorg-parse/lib/parser';
4 | import { Headline } from 'uniorg';
5 |
6 | describe('orgast-util-to-string', () => {
7 | test('empty', () => {
8 | const node = parse(``);
9 |
10 | const s = toString(node);
11 |
12 | expect(s).toBe('');
13 | });
14 |
15 | test('emphasis', () => {
16 | const node = parse(`Some /emphasis/, *importance*, and ~code~.`);
17 |
18 | const s = toString(node);
19 |
20 | expect(s).toBe('Some emphasis, importance, and code.');
21 | });
22 |
23 | test('code and verbatim', () => {
24 | const node = parse(`~code~ and =verbatim=.`);
25 |
26 | const s = toString(node);
27 |
28 | expect(s).toBe('code and verbatim.');
29 | });
30 | test('headline', () => {
31 | const document: any = parse(`* some text`);
32 | // org-data > section > headline
33 | const headline = document.children[0].children[0] as Headline;
34 | expect(headline.type).toBe('headline');
35 |
36 | const s = toString(headline);
37 |
38 | expect(s).toBe('some text');
39 | });
40 |
41 | test('link', () => {
42 | const tree = parse(`[[https://example.com][example link]]`);
43 |
44 | const s = toString(tree);
45 |
46 | expect(s).toBe('example link');
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { Node } from 'unist';
2 |
3 | export interface Options {}
4 |
5 | /**
6 | * Get the text content of a node.
7 | * Prefer the node’s plain-text fields, otherwise serialize its children,
8 | * and if the given value is an array, serialize the nodes in it.
9 | */
10 | export function toString(node: Node | Node[], _options: Options = {}): string {
11 | return one(node);
12 | }
13 |
14 | function one(node: Node | Node[]): string {
15 | const n = node as any;
16 |
17 | if (!n) {
18 | return '';
19 | }
20 |
21 | if (Array.isArray(n)) {
22 | return all(n);
23 | }
24 |
25 | if (typeof n.value === 'string') {
26 | return n.value;
27 | }
28 |
29 | if ('children' in n) {
30 | return all(n.children as Node[]);
31 | }
32 |
33 | return '';
34 | }
35 |
36 | function all(values: Node[]): string {
37 | return values.map(one).join('');
38 | }
39 |
40 | export default toString;
41 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/orgast-util-to-string/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # orgast-util-visit-ids
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ### Patch Changes
12 |
13 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
14 | - uniorg@1.3.0
15 |
16 | ## 1.0.1
17 |
18 | ### Patch Changes
19 |
20 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
21 |
22 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
23 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/README.md:
--------------------------------------------------------------------------------
1 | # `orgast-util-visit-ids`
2 |
3 | orgast (uniorg) utility to visit all nodes with ids.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install orgast-util-visit-ids
9 | ```
10 |
11 | ## Use
12 |
13 | ```js
14 | import { unified } from 'unified';
15 | import uniorgParse from 'uniorg-parse';
16 | import { visitIds } from 'orgast-util-visit-ids';
17 |
18 | const tree = unified().use(uniorgParse).parse(`
19 | :PROPERTIES:
20 | :ID: id-org-data
21 | :END:
22 |
23 | * First headline
24 | :PROPERTIES:
25 | :ID: id-headline
26 | :END:
27 | ** Second headline
28 | :PROPERTIES:
29 | :ID: id-headline-2
30 | :END:
31 | `);
32 |
33 | visitIds(tree, (id, node) => {
34 | console.log(id, node.type, node.rawValue);
35 | });
36 | //=> id-org-data org-data undefined
37 | //=> id-headline headline First headline
38 | //=> id-headline-2 headline Second headline
39 | ```
40 |
41 | ## API
42 |
43 | ### `visitIds(node: OrgData, callback: (id: string, node: OrgData | Headline) => void)`
44 |
45 | Call `callback` for every node that has an id assigned.
46 |
47 | ## License
48 |
49 | [GNU General Public License v3.0 or later](./LICENSE)
50 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "orgast-util-visit-ids",
3 | "version": "1.1.0",
4 | "type": "module",
5 | "description": "orgast (uniorg) utility to visit all nodes with ids",
6 | "keywords": [
7 | "uniorg",
8 | "orgast",
9 | "orgast-util",
10 | "util",
11 | "org-mode",
12 | "string",
13 | "unified"
14 | ],
15 | "author": "Oleksii Shmalko ",
16 | "homepage": "https://github.com/rasendubi/uniorg",
17 | "license": "GPL-3.0-or-later",
18 | "main": "lib/index.js",
19 | "directories": {
20 | "lib": "lib",
21 | "test": "__tests__"
22 | },
23 | "files": [
24 | "lib"
25 | ],
26 | "repository": {
27 | "type": "git",
28 | "url": "git+https://github.com/rasendubi/uniorg.git"
29 | },
30 | "scripts": {
31 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
32 | "clean": "rm -rf ./lib",
33 | "compile": "tsc -p tsconfig.build.json",
34 | "prepublishOnly": "npm run build",
35 | "test": "jest"
36 | },
37 | "bugs": {
38 | "url": "https://github.com/rasendubi/uniorg/issues"
39 | },
40 | "devDependencies": {
41 | "@types/jest": "29.5.12",
42 | "@types/unist": "3.0.2",
43 | "jest": "29.7.0",
44 | "typescript": "5.4.5",
45 | "uniorg-parse": "workspace:^3.2.0"
46 | },
47 | "dependencies": {
48 | "unist-util-visit-parents": "^6.0.1",
49 | "uniorg": "workspace:^1.3.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { visitIds } from './';
2 |
3 | import { parse } from 'uniorg-parse/lib/parser';
4 |
5 | describe('orgast-util-to-string', () => {
6 | test('empty', () => {
7 | const tree = parse(``);
8 |
9 | const f = jest.fn();
10 | visitIds(tree, f);
11 |
12 | expect(f).not.toBeCalled();
13 | });
14 |
15 | test('top-level id', () => {
16 | const tree = parse(`:PROPERTIES:
17 | :ID: hello-page
18 | :END:
19 |
20 | hi there`);
21 |
22 | const f = jest.fn();
23 | visitIds(tree, f);
24 |
25 | expect(f).toBeCalledTimes(1);
26 | const [id, node] = f.mock.calls[0];
27 | expect(id).toBe('hello-page');
28 | expect(node.type).toBe('org-data');
29 | });
30 |
31 | test('headline', () => {
32 | const tree = parse(`
33 | * hi, there!
34 | :PROPERTIES:
35 | :ID: hi-there
36 | :END:
37 |
38 | hi there`);
39 |
40 | const f = jest.fn();
41 | visitIds(tree, f);
42 |
43 | expect(f).toBeCalledTimes(1);
44 | const [id, node] = f.mock.calls[0];
45 | expect(id).toBe('hi-there');
46 | expect(node.type).toBe('section');
47 | const headline = node.children[0];
48 | expect(headline.type).toBe('headline');
49 | expect(headline.level).toBe(1);
50 | expect(headline.rawValue).toBe('hi, there!');
51 | });
52 |
53 | test('ignores CUSTOM_ID', () => {
54 | const tree = parse(`:PROPERTIES:
55 | :CUSTOM_ID: hello
56 | :END:
57 |
58 | * headline
59 | :PROPERTIES:
60 | :CUSTOM_ID: headline
61 | :END:`);
62 |
63 | const f = jest.fn();
64 | visitIds(tree, f);
65 |
66 | expect(f).not.toBeCalled();
67 | });
68 |
69 | test('multiple and nested', () => {
70 | const tree = parse(`
71 | :PROPERTIES:
72 | :ID: id-org-data
73 | :END:
74 |
75 | * headline
76 | :PROPERTIES:
77 | :ID: id-headline
78 | :END:
79 | ** headline 2
80 | :PROPERTIES:
81 | :ID: id-headline-2
82 | :END:`);
83 |
84 | const f = jest.fn();
85 | visitIds(tree, f);
86 |
87 | expect(f).toBeCalledTimes(3);
88 |
89 | const [id1, node1] = f.mock.calls[0];
90 | expect(id1).toBe('id-org-data');
91 | expect(node1.type).toBe('org-data');
92 |
93 | const [id2, node2] = f.mock.calls[1];
94 | expect(id2).toBe('id-headline');
95 | expect(node2.type).toBe('section');
96 | const headline2 = node2.children[0];
97 | expect(headline2.type).toBe('headline');
98 | expect(headline2.level).toBe(1);
99 |
100 | const [id3, node3] = f.mock.calls[2];
101 | expect(id3).toBe('id-headline-2');
102 | expect(node3.type).toBe('section');
103 | const headline3 = node3.children[0];
104 | expect(headline3.type).toBe('headline');
105 | expect(headline3.level).toBe(2);
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/src/index.ts:
--------------------------------------------------------------------------------
1 | import { OrgNode, OrgData, Section, NodeProperty } from 'uniorg';
2 | import { visitParents } from 'unist-util-visit-parents';
3 |
4 | export function visitIds(
5 | tree: OrgNode,
6 | f: (id: string, node: OrgData | Section) => void
7 | ) {
8 | // This issue does not seem fixed
9 | // 👀https://github.com/syntax-tree/unist-util-visit/issues/33
10 | // @ts-ignore Incessantly deep type instantiation
11 | visitParents(
12 | tree,
13 | { type: 'node-property', key: 'ID' },
14 | (property: NodeProperty, ancestors) => {
15 | const id = property.value;
16 |
17 | let parent = ancestors.pop();
18 | while (
19 | parent &&
20 | parent.type !== 'section' &&
21 | parent.type !== 'org-data'
22 | ) {
23 | parent = ancestors.pop();
24 | }
25 |
26 | if (parent) {
27 | f(id, parent as OrgData | Section);
28 | }
29 | }
30 | );
31 | }
32 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/orgast-util-visit-ids/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/orgx/.gitignore:
--------------------------------------------------------------------------------
1 | /types/
2 |
--------------------------------------------------------------------------------
/packages/orgx/.npmignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rasendubi/uniorg/fc4e3b1105f052709c14f86d9e08d32cb17409a5/packages/orgx/.npmignore
--------------------------------------------------------------------------------
/packages/orgx/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('./lib/core.js').ProcessorOptions} ProcessorOptions
3 | * @typedef {import('./lib/compile.js').CompileOptions} CompileOptions
4 | * @typedef {import('./lib/evaluate.js').EvaluateOptions} EvaluateOptions
5 | */
6 |
7 | export { createProcessor } from './lib/core.js';
8 | export { compile, compileSync } from './lib/compile.js';
9 | export { evaluate, evaluateSync } from './lib/evaluate.js';
10 | export { run, runSync } from './lib/run.js';
11 | export { nodeTypes } from './lib/node-types.js';
12 |
--------------------------------------------------------------------------------
/packages/orgx/lib/compile.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('vfile').VFileCompatible} VFileCompatible
3 | * @typedef {import('vfile').VFile} VFile
4 | * @typedef {import('./core.js').PluginOptions} PluginOptions
5 | * @typedef {import('./core.js').BaseProcessorOptions} BaseProcessorOptions
6 | *
7 | * @typedef {BaseProcessorOptions & PluginOptions} CompileOptions
8 | */
9 |
10 | import { createProcessor } from './core.js';
11 | import { resolveFileAndOptions } from './util/resolve-file-and-options.js';
12 |
13 | /**
14 | * Compile Org-mode to JS.
15 | *
16 | * @param {VFileCompatible} vfileCompatible
17 | * Org document to parse (`string`, `Buffer`, `vfile`, anything that can be
18 | * given to `vfile`).
19 | * @param {CompileOptions} [compileOptions]
20 | * @return {Promise}
21 | */
22 | export function compile(vfileCompatible, compileOptions) {
23 | const { file, options } = resolveFileAndOptions(
24 | vfileCompatible,
25 | compileOptions
26 | );
27 | return createProcessor(options).process(file);
28 | }
29 |
30 | /**
31 | * Synchronously compile Org-mode to JS.
32 | *
33 | * @param {VFileCompatible} vfileCompatible
34 | * MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be
35 | * given to `vfile`).
36 | * @param {CompileOptions} [compileOptions]
37 | * @return {VFile}
38 | */
39 | export function compileSync(vfileCompatible, compileOptions) {
40 | const { file, options } = resolveFileAndOptions(
41 | vfileCompatible,
42 | compileOptions
43 | );
44 | return createProcessor(options).processSync(file);
45 | }
46 |
--------------------------------------------------------------------------------
/packages/orgx/lib/condition.browser.js:
--------------------------------------------------------------------------------
1 | export const development = false;
2 |
--------------------------------------------------------------------------------
/packages/orgx/lib/condition.js:
--------------------------------------------------------------------------------
1 | import process from 'process';
2 |
3 | export const development = process.env.NODE_ENV === 'development';
4 |
--------------------------------------------------------------------------------
/packages/orgx/lib/evaluate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('vfile').VFileCompatible} VFileCompatible
3 | * @typedef {import('./util/resolve-evaluate-options.js').EvaluateOptions} EvaluateOptions
4 | *
5 | * @typedef {import('mdx/types').MDXModule} ExportMap
6 | */
7 |
8 | import { compile, compileSync } from './compile.js';
9 | import { run, runSync } from './run.js';
10 | import { resolveEvaluateOptions } from './util/resolve-evaluate-options.js';
11 |
12 | /**
13 | * Evaluate MDX.
14 | *
15 | * @param {VFileCompatible} vfileCompatible
16 | * MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be
17 | * given to `vfile`).
18 | * @param {EvaluateOptions} evaluateOptions
19 | * @return {Promise}
20 | */
21 | export async function evaluate(vfileCompatible, evaluateOptions) {
22 | const { compiletime, runtime } = resolveEvaluateOptions(evaluateOptions);
23 | // V8 on Erbium.
24 | /* c8 ignore next 2 */
25 | return run(await compile(vfileCompatible, compiletime), runtime);
26 | }
27 |
28 | /**
29 | * Synchronously evaluate MDX.
30 | *
31 | * @param {VFileCompatible} vfileCompatible
32 | * MDX document to parse (`string`, `Buffer`, `vfile`, anything that can be
33 | * given to `vfile`).
34 | * @param {EvaluateOptions} evaluateOptions
35 | * @return {ExportMap}
36 | */
37 | export function evaluateSync(vfileCompatible, evaluateOptions) {
38 | const { compiletime, runtime } = resolveEvaluateOptions(evaluateOptions);
39 | return runSync(compileSync(vfileCompatible, compiletime), runtime);
40 | }
41 |
--------------------------------------------------------------------------------
/packages/orgx/lib/node-types.js:
--------------------------------------------------------------------------------
1 | /**
2 | * List of node types made by `mdast-util-mdx`, which have to be passed
3 | * through untouched from the mdast tree to the hast tree.
4 | */
5 | export const nodeTypes = [
6 | 'mdxFlowExpression',
7 | 'mdxJsxFlowElement',
8 | 'mdxJsxTextElement',
9 | 'mdxTextExpression',
10 | 'mdxjsEsm',
11 | ];
12 |
--------------------------------------------------------------------------------
/packages/orgx/lib/plugin/recma-jsx-build.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Program} Program
3 | * @typedef {import('estree-util-build-jsx').BuildJsxOptions} BuildJsxOptions
4 | *
5 | * @typedef RecmaJsxBuildOptions
6 | * @property {'program'|'function-body'} [outputFormat='program']
7 | * Whether to keep the import of the automatic runtime or get it from
8 | * `arguments[0]` instead.
9 | */
10 |
11 | import { buildJsx } from 'estree-util-build-jsx';
12 | import { specifiersToDeclarations } from '../util/estree-util-specifiers-to-declarations.js';
13 | import { toIdOrMemberExpression } from '../util/estree-util-to-id-or-member-expression.js';
14 |
15 | /**
16 | * A plugin to build JSX into function calls.
17 | * `estree-util-build-jsx` does all the work for us!
18 | *
19 | * @type {import('unified').Plugin<[BuildJsxOptions & RecmaJsxBuildOptions?], Program>}
20 | */
21 | export function recmaJsxBuild(options = {}) {
22 | const { development, outputFormat } = options;
23 |
24 | return (tree, file) => {
25 | buildJsx(tree, { development, filePath: file.history[0] });
26 |
27 | // When compiling to a function body, replace the import that was just
28 | // generated, and get `jsx`, `jsxs`, and `Fragment` from `arguments[0]`
29 | // instead.
30 | if (
31 | outputFormat === 'function-body' &&
32 | tree.body[0] &&
33 | tree.body[0].type === 'ImportDeclaration' &&
34 | typeof tree.body[0].source.value === 'string' &&
35 | /\/jsx-(dev-)?runtime$/.test(tree.body[0].source.value)
36 | ) {
37 | tree.body[0] = {
38 | type: 'VariableDeclaration',
39 | kind: 'const',
40 | declarations: specifiersToDeclarations(
41 | tree.body[0].specifiers,
42 | toIdOrMemberExpression(['arguments', 0])
43 | ),
44 | };
45 | }
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/packages/orgx/lib/plugin/recma-stringify.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Program} Program
3 | * @typedef {typeof import('source-map').SourceMapGenerator} SourceMapGenerator
4 | *
5 | * @typedef RecmaStringifyOptions
6 | * @property {SourceMapGenerator} [SourceMapGenerator]
7 | * Generate a source map by passing a `SourceMapGenerator` from `source-map`
8 | * in.
9 | */
10 |
11 | import { toJs, jsx } from 'estree-util-to-js';
12 |
13 | /**
14 | * A plugin that adds an esast compiler: a small wrapper around `astring` to add
15 | * support for serializing JSX.
16 | *
17 | * @this {import('unified').Processor}
18 | * @type {import('unified').Plugin<[RecmaStringifyOptions]|[], Program, string>}
19 | */
20 | export function recmaStringify(options = {}) {
21 | const { SourceMapGenerator } = options;
22 |
23 | Object.assign(this, { Compiler: compiler });
24 |
25 | /** @type {import('unified').CompilerFunction} */
26 | function compiler(tree, file) {
27 | const result = SourceMapGenerator
28 | ? toJs(tree, {
29 | filePath: file.path || 'unknown.mdx',
30 | SourceMapGenerator,
31 | handlers: jsx,
32 | })
33 | : toJs(tree, { handlers: jsx });
34 |
35 | file.map = result.map;
36 |
37 | return result.value;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/orgx/lib/plugin/rehype-recma.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Program} Program
3 | * @typedef {import('hast').Root} Root
4 | */
5 |
6 | import { toEstree } from 'hast-util-to-estree';
7 |
8 | /**
9 | * A plugin to transform an HTML (hast) tree to a JS (estree).
10 | * `hast-util-to-estree` does all the work for us!
11 | *
12 | * @type {import('unified').Plugin, Root, Program>}
13 | */
14 | export function rehypeRecma() {
15 | return (tree) => toEstree(tree);
16 | }
17 |
--------------------------------------------------------------------------------
/packages/orgx/lib/plugin/rehype-remove-raw.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('hast').Root} Root
3 | */
4 |
5 | import { visit } from 'unist-util-visit';
6 |
7 | /**
8 | * A tiny plugin that removes raw HTML.
9 | * This is needed if the format is `md` and `rehype-raw` was not used to parse
10 | * dangerous HTML into nodes.
11 | *
12 | * @type {import('unified').Plugin, Root>}
13 | */
14 | export function rehypeRemoveRaw() {
15 | return (tree) => {
16 | visit(tree, 'raw', (_, index, parent) => {
17 | if (parent && typeof index === 'number') {
18 | parent.children.splice(index, 1);
19 | return index;
20 | }
21 | });
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/packages/orgx/lib/run.js:
--------------------------------------------------------------------------------
1 | /** @type {new (code: string, ...args: Array) => Function} **/
2 | const AsyncFunction = Object.getPrototypeOf(run).constructor;
3 |
4 | /**
5 | * Asynchronously run code.
6 | *
7 | * @param {{toString(): string}} file
8 | * JS document to run.
9 | * @param {unknown} options
10 | * @return {Promise<*>}
11 | */
12 | export async function run(file, options) {
13 | // V8 on Erbium.
14 | /* c8 ignore next 2 */
15 | return new AsyncFunction(String(file))(options);
16 | }
17 |
18 | /**
19 | * Synchronously run code.
20 | *
21 | * @param {{toString(): string}} file
22 | * JS document to run.
23 | * @param {unknown} options
24 | * @return {*}
25 | */
26 | export function runSync(file, options) {
27 | // eslint-disable-next-line no-new-func
28 | return new Function(String(file))(options);
29 | }
30 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/estree-util-create.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Node} Node
3 | */
4 |
5 | /**
6 | * @template {Node} N
7 | * @param {Node} template
8 | * @param {N} node
9 | * @returns {N}
10 | */
11 | export function create(template, node) {
12 | /** @type {Array} */
13 | // @ts-expect-error: `start`, `end`, `comments` are custom Acorn fields.
14 | const fields = ['start', 'end', 'loc', 'range', 'comments'];
15 | let index = -1;
16 |
17 | while (++index < fields.length) {
18 | const field = fields[index];
19 |
20 | if (field in template) {
21 | // @ts-expect-error: assume they’re settable.
22 | node[field] = template[field];
23 | }
24 | }
25 |
26 | return node;
27 | }
28 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/estree-util-declaration-to-expression.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Declaration} Declaration
3 | * @typedef {import('estree-jsx').Expression} Expression
4 | */
5 |
6 | /**
7 | * Turn a declaration into an expression.
8 | * Doesn’t work for variable declarations, but that’s fine for our use case
9 | * because currently we’re using this utility for export default declarations,
10 | * which can’t contain variable declarations.
11 | *
12 | * @param {Declaration} declaration
13 | * @returns {Expression}
14 | */
15 | export function declarationToExpression(declaration) {
16 | if (declaration.type === 'FunctionDeclaration') {
17 | return { ...declaration, type: 'FunctionExpression' };
18 | }
19 |
20 | if (declaration.type === 'ClassDeclaration') {
21 | return { ...declaration, type: 'ClassExpression' };
22 | /* Internal utility so the next shouldn’t happen or a maintainer is making a
23 | * mistake. */
24 | /* c8 ignore next 4 */
25 | }
26 |
27 | // Probably `VariableDeclaration`.
28 | throw new Error('Cannot turn `' + declaration.type + '` into an expression');
29 | }
30 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/estree-util-is-declaration.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Declaration} Declaration
3 | */
4 |
5 | /**
6 | * @param {unknown} node
7 | * @returns {node is Declaration}
8 | */
9 | export function isDeclaration(node) {
10 | /** @type {string} */
11 | // @ts-expect-error Hush typescript, looks like `type` is available.
12 | const type = node && typeof node === 'object' && node.type;
13 | return Boolean(
14 | type === 'FunctionDeclaration' ||
15 | type === 'ClassDeclaration' ||
16 | type === 'VariableDeclaration'
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/estree-util-specifiers-to-declarations.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Identifier} Identifier
3 | * @typedef {import('estree-jsx').ImportSpecifier} ImportSpecifier
4 | * @typedef {import('estree-jsx').ImportDefaultSpecifier} ImportDefaultSpecifier
5 | * @typedef {import('estree-jsx').ImportNamespaceSpecifier} ImportNamespaceSpecifier
6 | * @typedef {import('estree-jsx').ExportSpecifier} ExportSpecifier
7 | * @typedef {import('estree-jsx').ObjectPattern} ObjectPattern
8 | * @typedef {import('estree-jsx').VariableDeclarator} VariableDeclarator
9 | * @typedef {import('estree-jsx').Expression} Expression
10 | */
11 |
12 | import { create } from './estree-util-create.js';
13 |
14 | /**
15 | * @param {Array} specifiers
16 | * @param {Expression} init
17 | * @returns {Array}
18 | */
19 | export function specifiersToDeclarations(specifiers, init) {
20 | let index = -1;
21 | /** @type {Array} */
22 | const declarations = [];
23 | /** @type {Array} */
24 | const otherSpecifiers = [];
25 | // Can only be one according to JS syntax.
26 | /** @type {ImportNamespaceSpecifier|undefined} */
27 | let importNamespaceSpecifier;
28 |
29 | while (++index < specifiers.length) {
30 | const specifier = specifiers[index];
31 |
32 | if (specifier.type === 'ImportNamespaceSpecifier') {
33 | importNamespaceSpecifier = specifier;
34 | } else {
35 | otherSpecifiers.push(specifier);
36 | }
37 | }
38 |
39 | if (importNamespaceSpecifier) {
40 | declarations.push(
41 | create(importNamespaceSpecifier, {
42 | type: 'VariableDeclarator',
43 | id: importNamespaceSpecifier.local,
44 | init,
45 | })
46 | );
47 | }
48 |
49 | declarations.push({
50 | type: 'VariableDeclarator',
51 | id: {
52 | type: 'ObjectPattern',
53 | properties: otherSpecifiers.map((specifier) => {
54 | /** @type {Identifier} */
55 | let key =
56 | specifier.type === 'ImportSpecifier'
57 | ? specifier.imported
58 | : specifier.type === 'ExportSpecifier'
59 | ? specifier.exported
60 | : { type: 'Identifier', name: 'default' };
61 | let value = specifier.local;
62 |
63 | // Switch them around if we’re exporting.
64 | if (specifier.type === 'ExportSpecifier') {
65 | value = key;
66 | key = specifier.local;
67 | }
68 |
69 | return create(specifier, {
70 | type: 'Property',
71 | kind: 'init',
72 | shorthand: key.name === value.name,
73 | method: false,
74 | computed: false,
75 | key,
76 | value,
77 | });
78 | }),
79 | },
80 | init: importNamespaceSpecifier
81 | ? { type: 'Identifier', name: importNamespaceSpecifier.local.name }
82 | : init,
83 | });
84 |
85 | return declarations;
86 | }
87 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/estree-util-to-binary-addition.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('estree-jsx').Expression} Expression
3 | */
4 |
5 | /**
6 | * @param {Array} expressions
7 | */
8 | export function toBinaryAddition(expressions) {
9 | let index = -1;
10 | /** @type {Expression|undefined} */
11 | let left;
12 |
13 | while (++index < expressions.length) {
14 | const right = expressions[index];
15 | left = left
16 | ? { type: 'BinaryExpression', left, operator: '+', right }
17 | : right;
18 | }
19 |
20 | // Just for types.
21 | /* c8 ignore next */
22 | if (!left) throw new Error('Expected non-empty `expressions` to be passed');
23 |
24 | return left;
25 | }
26 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/extnames-to-regex.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Utility to turn a list of extnames (*with* dots) into an expression.
3 | *
4 | * @param {Array} extnames
5 | * List of extnames.
6 | * @returns {RegExp}
7 | * Regex matching them.
8 | */
9 | export function extnamesToRegex(extnames) {
10 | // eslint-disable-next-line security/detect-non-literal-regexp
11 | return new RegExp(
12 | '\\.(' + extnames.map((d) => d.slice(1)).join('|') + ')([?#]|$)'
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/extnames.js:
--------------------------------------------------------------------------------
1 | export const org = ['.org'];
2 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/resolve-evaluate-options.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('../core.js').ProcessorOptions} ProcessorOptions
3 | *
4 | * @typedef RunnerOptions
5 | * @property {*} Fragment
6 | * Symbol to use for fragments.
7 | * @property {*} [jsx]
8 | * Function to generate an element with static children in production mode.
9 | * @property {*} [jsxs]
10 | * Function to generate an element with dynamic children in production mode.
11 | * @property {*} [jsxDEV]
12 | * Function to generate an element in development mode.
13 | * @property {*} [useMDXComponents]
14 | * Function to get `MDXComponents` from context.
15 | *
16 | * @typedef {Omit } EvaluateProcessorOptions
17 | *
18 | * @typedef {EvaluateProcessorOptions & RunnerOptions} EvaluateOptions
19 | */
20 |
21 | /**
22 | * Split compiletime options from runtime options.
23 | *
24 | * @param {EvaluateOptions} options
25 | * @returns {{compiletime: ProcessorOptions, runtime: RunnerOptions}}
26 | */
27 | export function resolveEvaluateOptions(options) {
28 | const {
29 | development,
30 | Fragment,
31 | jsx,
32 | jsxs,
33 | jsxDEV,
34 | useMDXComponents,
35 | ...rest
36 | } = options || {};
37 |
38 | if (!Fragment) throw new Error('Expected `Fragment` given to `evaluate`');
39 | if (development) {
40 | if (!jsxDEV) throw new Error('Expected `jsxDEV` given to `evaluate`');
41 | } else {
42 | if (!jsx) throw new Error('Expected `jsx` given to `evaluate`');
43 | if (!jsxs) throw new Error('Expected `jsxs` given to `evaluate`');
44 | }
45 |
46 | return {
47 | compiletime: {
48 | ...rest,
49 | development,
50 | outputFormat: 'function-body',
51 | providerImportSource: useMDXComponents ? '#' : undefined,
52 | },
53 | runtime: { Fragment, jsx, jsxs, jsxDEV, useMDXComponents },
54 | };
55 | }
56 |
--------------------------------------------------------------------------------
/packages/orgx/lib/util/resolve-file-and-options.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('vfile').VFileCompatible} VFileCompatible
3 | * @typedef {import('../core.js').ProcessorOptions} ProcessorOptions
4 | * @typedef {import('../compile.js').CompileOptions} CompileOptions
5 | */
6 |
7 | import { VFile } from 'vfile';
8 |
9 | /**
10 | * Create a file and options from a given `vfileCompatible` and options that
11 | * might contain `format: 'detect'`.
12 | *
13 | * @param {VFileCompatible} vfileCompatible
14 | * @param {CompileOptions} [options]
15 | * @returns {{file: VFile, options: ProcessorOptions}}
16 | */
17 | export function resolveFileAndOptions(vfileCompatible, options) {
18 | const file = looksLikeAVFile(vfileCompatible)
19 | ? vfileCompatible
20 | : new VFile(vfileCompatible);
21 | return {
22 | file,
23 | options: options || {},
24 | };
25 | }
26 |
27 | /**
28 | * @param {VFileCompatible} [value]
29 | * @returns {value is VFile}
30 | */
31 | function looksLikeAVFile(value) {
32 | return Boolean(
33 | value &&
34 | typeof value === 'object' &&
35 | 'message' in value &&
36 | 'messages' in value
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/packages/orgx/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Compositor, Inc. and Vercel, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/orgx/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@uniorgjs/orgx",
3 | "version": "2.0.1",
4 | "description": "Org-mode to JS compiler",
5 | "type": "module",
6 | "types": "types/index.d.ts",
7 | "main": "index.js",
8 | "browser": {
9 | "./lib/condition.js": "./lib/condition.browser.js"
10 | },
11 | "react-native": {
12 | "./lib/condition.js": "./lib/condition.browser.js"
13 | },
14 | "scripts": {
15 | "build": "rm -rf ./types && tsc -p tsconfig.build.json",
16 | "prepublishOnly": "npm run build"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/rasendubi/uniorg.git"
21 | },
22 | "author": "Oleksii Shmalko ",
23 | "license": "GPL-3.0-or-later",
24 | "bugs": {
25 | "url": "https://github.com/rasendubi/uniorg/issues"
26 | },
27 | "homepage": "https://github.com/rasendubi/uniorg#readme",
28 | "dependencies": {
29 | "@types/estree-jsx": "^1.0.5",
30 | "estree-util-build-jsx": "^3.0.1",
31 | "estree-util-is-identifier-name": "^3.0.0",
32 | "estree-util-to-js": "^2.0.0",
33 | "estree-walker": "^3.0.3",
34 | "hast-util-to-estree": "^3.1.0",
35 | "periscopic": "^4.0.2",
36 | "unified": "^11.0.4",
37 | "unist-util-position-from-estree": "^2.0.0",
38 | "unist-util-stringify-position": "^4.0.0",
39 | "unist-util-visit": "^5.0.0",
40 | "vfile": "^6.0.1"
41 | },
42 | "peerDependencies": {
43 | "uniorg-parse": ">=1.0.0 <4.0.0",
44 | "uniorg-rehype": ">=1.0.0 <3.0.0"
45 | },
46 | "devDependencies": {
47 | "uniorg-parse": "workspace:*",
48 | "uniorg-rehype": "workspace:*"
49 | },
50 | "publishConfig": {
51 | "access": "public"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/orgx/test/context/components.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | /**
4 | * @param {Record} props
5 | */
6 | export function Pill(props) {
7 | return React.createElement('span', { ...props, style: { color: 'red' } });
8 | }
9 |
10 | /**
11 | * @param {Record} props
12 | */
13 | export function Layout(props) {
14 | return React.createElement('div', { ...props, style: { color: 'red' } });
15 | }
16 |
17 | export default Layout;
18 |
--------------------------------------------------------------------------------
/packages/orgx/test/context/data.js:
--------------------------------------------------------------------------------
1 | export const number = 3.14;
2 |
3 | export const object = { a: 1, b: 2 };
4 |
5 | export const array = [1, 2];
6 |
7 | export default 2 * number;
8 |
--------------------------------------------------------------------------------
/packages/orgx/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "declaration": true,
5 | "emitDeclarationOnly": true,
6 | "skipLibCheck": true,
7 | "outDir": "./types"
8 | },
9 | "include": ["./"],
10 | "exclude": ["./node_modules", "./types"]
11 | }
12 |
--------------------------------------------------------------------------------
/packages/orgx/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/.gitignore:
--------------------------------------------------------------------------------
1 | /lib/
2 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # rollup-plugin-orgx
2 |
3 | ## 2.0.0
4 |
5 | ### Major Changes
6 |
7 | - [#126](https://github.com/rasendubi/uniorg/pull/126) [`7531419`](https://github.com/rasendubi/uniorg/commit/75314196835ee768fc0689cbc6279cf68fedb58b) Thanks [@rasendubi](https://github.com/rasendubi)! - Move uniorg-parse and uniorg-rehype into peer dependencies.
8 |
9 | This is done to give you precise control over your versions of uniorg-parse and uniorg-rehype, so you can account for any quirks or specific needs.
10 |
11 | This shall also allow us to maintain core uniorg packages and integrations independently, so you will be able to use newer integration packages with having to upgrade the parser or vice versa.
12 |
13 | This is a breaking change because you now need to explicitly install uniorg-parse and uniorg-rehype as dependencies in your projects. Previously, these were included as direct dependencies of the packages.
14 |
15 | ### Patch Changes
16 |
17 | - Updated dependencies [[`7531419`](https://github.com/rasendubi/uniorg/commit/75314196835ee768fc0689cbc6279cf68fedb58b)]:
18 | - @uniorgjs/orgx@2.0.0
19 |
20 | ## 1.0.4
21 |
22 | ### Patch Changes
23 |
24 | - Updated dependencies []:
25 | - @uniorgjs/orgx@1.0.8
26 |
27 | ## 1.0.3
28 |
29 | ### Patch Changes
30 |
31 | - Updated dependencies []:
32 | - @uniorgjs/orgx@1.0.7
33 |
34 | ## 1.0.2
35 |
36 | ### Patch Changes
37 |
38 | - Updated dependencies []:
39 | - @uniorgjs/orgx@1.0.6
40 |
41 | ## 1.0.1
42 |
43 | ### Patch Changes
44 |
45 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
46 |
47 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
48 |
49 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
50 | - @uniorgjs/orgx@1.0.5
51 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rollup-plugin-orgx",
3 | "version": "2.0.0",
4 | "description": "Rollup plugin to transform org-mode files to JS.",
5 | "type": "module",
6 | "main": "lib/index.js",
7 | "types": "lib/index.d.ts",
8 | "directories": {
9 | "lib": "lib"
10 | },
11 | "files": [
12 | "lib"
13 | ],
14 | "keywords": [
15 | "uniorg",
16 | "org-mode",
17 | "rollup",
18 | "plugin"
19 | ],
20 | "author": "Oleksii Shmalko ",
21 | "homepage": "https://github.com/rasendubi/uniorg",
22 | "license": "GPL-3.0-or-later",
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/rasendubi/uniorg.git"
26 | },
27 | "bugs": {
28 | "url": "https://github.com/rasendubi/uniorg/issues"
29 | },
30 | "scripts": {
31 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
32 | "clean": "rm -rf ./lib",
33 | "compile": "tsc -p tsconfig.build.json",
34 | "prepublishOnly": "npm run build"
35 | },
36 | "dependencies": {
37 | "@uniorgjs/orgx": "workspace:^2.0.0",
38 | "rollup-pluginutils": "^2.8.2",
39 | "vfile": "^6.0.1"
40 | },
41 | "peerDependencies": {
42 | "uniorg-parse": ">=1.0.0 <4.0.0",
43 | "uniorg-rehype": ">=1.0.0 <3.0.0"
44 | },
45 | "devDependencies": {
46 | "uniorg-parse": "workspace:*",
47 | "uniorg-rehype": "workspace:*"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/src/index.ts:
--------------------------------------------------------------------------------
1 | import { VFile } from 'vfile';
2 | import { createFilter } from 'rollup-pluginutils';
3 | import type { CompileOptions } from '@uniorgjs/orgx';
4 | import { compile } from '@uniorgjs/orgx';
5 |
6 | export interface OrgPluginOptions extends CompileOptions {
7 | include?: string | RegExp | Array;
8 | exclude?: string | RegExp | Array;
9 | }
10 |
11 | export default ({ include, exclude, ...options }: OrgPluginOptions = {}) => {
12 | const filter = createFilter(include, exclude);
13 |
14 | return {
15 | name: 'rollup-plugin-orgx',
16 | transform: async (value: string, path: string) => {
17 | const file = new VFile({ value, path });
18 | if (file.extname === '.org' && filter(file.path)) {
19 | const compiled = await compile(file, options);
20 | return { code: String(compiled.value), map: compiled.map };
21 | }
22 | },
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "skipLibCheck": true,
5 | "outDir": "./lib"
6 | },
7 | "include": ["./src"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/rollup-plugin-orgx/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # uniorg-attach
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ### Patch Changes
12 |
13 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
14 | - uniorg@1.3.0
15 |
16 | ## 1.0.1
17 |
18 | ### Patch Changes
19 |
20 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
21 |
22 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
23 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-attach`
2 |
3 | **[uniorg](https://github.com/rasendubi/uniorg)** plugin to convert `attachment:` links to `file:` links.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install --save uniorg-attach
9 | ```
10 |
11 | ## Use
12 |
13 | If we have the following `example.org` file:
14 |
15 | ```org
16 | :PROPERTIES:
17 | :ID: eae6a180-58d3-44b9-9c95-d8924849d365
18 | :END:
19 |
20 | attachment:file.txt
21 | ```
22 |
23 | and
24 |
25 | ```js
26 | import { unified } from 'unified';
27 | import toVFile from 'to-vfile';
28 | import uniorgParse from 'uniorg-parse';
29 | import { uniorgAttach } from 'uniorg-attach';
30 | import uniorg2rehype from 'uniorg-rehype';
31 | import html from 'rehype-stringify';
32 |
33 | unified()
34 | .use(uniorgParse)
35 | .use(uniorgAttach)
36 | .use(uniorg2rehype)
37 | .use(html)
38 | .process(toVFile.readSync('./example.org'), function (err, file) {
39 | console.log(file.toString());
40 | });
41 | ```
42 |
43 | will output
44 |
45 | ```
46 | file:data/ea/e6a180-58d3-44b9-9c95-d8924849d365/file.txt
47 |
48 | ```
49 |
50 | ## Options
51 |
52 | ### `idDir`
53 |
54 | Type: `string?`
55 |
56 | Default: `"data/"`
57 |
58 | The directory where attachments are stored. If this is a relative path, it will be interpreted relative to the directory where the Org file lives.
59 |
60 | Corresponds to `org-attach-id-dir` in Emacs.
61 |
62 | ### `useInheritance`
63 |
64 | Type: `boolean?`
65 |
66 | Default: `false`
67 |
68 | > **NOTE:** In Emacs, the default is `'selective` which means that Emacs will look at `org-use-property-inheritance` to check whether `ID` and `DIR` properties are inherited. uniorg-attach does not currently do that. This shouldn’t cause any troubles unless you inherit one property but not the other.
69 |
70 | Attachment inheritance for the outline.
71 |
72 | Enabling inheritance for implies that attachment links will look through all parent headings until it finds the linked attachment.
73 |
74 | Corresponds to `org-attach-use-inheritance` in Emacs.
75 |
76 | ### `idToPath`
77 |
78 | Type: `(id: string) => string`
79 |
80 | Default: `idUuidFolderFormat`
81 |
82 | A function parsing an ID string into a folder-path.
83 |
84 | Similar to `org-attach-id-to-path-function-list` in Emacs, but only allows one function.
85 |
86 | This module exports `idUuidFolderFormat` and `idTsFolderFormat` that re-implement two common behaviors for org-attach.
87 |
88 | ## License
89 |
90 | [GNU General Public License v3.0 or later](./LICENSE)
91 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-attach",
3 | "version": "1.1.0",
4 | "type": "module",
5 | "description": "Uniorg plugin to process org-attach attachment links",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "plugin",
10 | "org-mode",
11 | "attach",
12 | "org-attach"
13 | ],
14 | "author": "Oleksii Shmalko ",
15 | "homepage": "https://github.com/rasendubi/uniorg",
16 | "license": "GPL-3.0-or-later",
17 | "main": "lib/index.js",
18 | "types": "lib/index.d.ts",
19 | "directories": {
20 | "lib": "lib"
21 | },
22 | "files": [
23 | "lib"
24 | ],
25 | "repository": {
26 | "type": "git",
27 | "url": "git+https://github.com/rasendubi/uniorg.git"
28 | },
29 | "scripts": {
30 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
31 | "clean": "rm -rf ./lib",
32 | "compile": "tsc -p tsconfig.build.json",
33 | "prepublishOnly": "npm run build",
34 | "test": "jest"
35 | },
36 | "bugs": {
37 | "url": "https://github.com/rasendubi/uniorg/issues"
38 | },
39 | "devDependencies": {
40 | "@types/jest": "29.5.12",
41 | "@types/node": "^20.12.12",
42 | "jest": "29.7.0",
43 | "typescript": "5.4.5",
44 | "uniorg-parse": "workspace:^3.2.0",
45 | "yaml": "^2.4.2"
46 | },
47 | "dependencies": {
48 | "@types/unist": "^3.0.2",
49 | "unified": "^11.0.4",
50 | "unist-util-visit-parents": "^6.0.1",
51 | "uniorg": "workspace:^1.3.0",
52 | "vfile": "^6.0.1"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-attach/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # uniorg-extract-keywords
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ### Patch Changes
12 |
13 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
14 | - uniorg@1.3.0
15 |
16 | ## 1.0.1
17 |
18 | ### Patch Changes
19 |
20 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
21 |
22 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
23 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-extract-keywords`
2 |
3 | **[uniorg](https://github.com/rasendubi/uniorg)** plugin to extract Org-mode keywords from the document and store them in vfile.data.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install --save uniorg-extract-keywords
9 | ```
10 |
11 | ## Use
12 |
13 | If we have the following `example.org` file:
14 |
15 | ```org
16 | #+TITLE: Post title
17 | #+AUTHOR: Your Name
18 |
19 | other org-mode
20 | ```
21 |
22 | and
23 |
24 | ```js
25 | import { unified } from 'unified';
26 | import toVFile from 'to-vfile';
27 | import uniorgParse from 'uniorg-parse';
28 | import { extractKeywords } from 'uniorg-extract-keywords';
29 | import uniorg2rehype from 'uniorg-rehype';
30 | import html from 'rehype-stringify';
31 |
32 | unified()
33 | .use(uniorgParse)
34 | .use(extractKeywords)
35 | .use(uniorg2rehype)
36 | .use(html)
37 | .process(toVFile.readSync('./example.org'), function (err, file) {
38 | console.log(file.toString());
39 | console.log(file.data);
40 | });
41 | ```
42 |
43 | will output
44 |
45 | ```
46 | other org-mode
47 |
48 |
49 | { title: 'Post title', author: 'Your Name' }
50 | ```
51 |
52 | **Note: you should use to-vfile@6. to-vfile@7 is currently incompatible with unified@9. See [#12](https://github.com/rasendubi/uniorg/issues/12#issuecomment-850945694) for more details.**
53 |
54 | ## Options
55 |
56 | ### name
57 |
58 | Type: `string?`
59 |
60 | Default: `undefined`
61 |
62 | Specify a key to store keywords under. For example, `{ name: 'keywords' }` will store all keyword values as `{ data: { keywords: { ... } } }`. By default, all keywords are merged into the `data` object.
63 |
64 | Example:
65 |
66 | ```js
67 | unified()
68 | .use(uniorgParse)
69 | .use(extractKeywords, { name: 'keywords' })
70 | .use(uniorg2rehype)
71 | .use(html)
72 | .process('#+TITLE: Example', function (err, file) {
73 | console.log(file.data);
74 | });
75 | ```
76 |
77 | will output
78 |
79 | ```
80 | { keywords: { title: 'Example' } }
81 | ```
82 |
83 | ### preserveCase
84 |
85 | Type: `boolean`
86 |
87 | Default: `false`
88 |
89 | Whether to preserve case of the keywords. By default, all keywords are converted to lowercase.
90 |
91 | Example:
92 |
93 | ```js
94 | unified()
95 | .use(uniorgParse)
96 | .use(extractKeywords, { preserveCase: true })
97 | .use(uniorg2rehype)
98 | .use(html)
99 | .process('#+TITLE: Example', function (err, file) {
100 | console.log(file.data);
101 | });
102 | ```
103 |
104 | will output
105 |
106 | ```
107 | { TITLE: 'Example' }
108 | ```
109 |
110 | ## License
111 |
112 | [GNU General Public License v3.0 or later](./LICENSE)
113 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-extract-keywords",
3 | "version": "1.1.0",
4 | "type": "module",
5 | "description": "Store org keywords and their values in vfile data property",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "plugin",
10 | "org-mode"
11 | ],
12 | "author": "Oleksii Shmalko ",
13 | "homepage": "https://github.com/rasendubi/uniorg",
14 | "license": "GPL-3.0-or-later",
15 | "main": "lib/index.js",
16 | "types": "lib/index.d.ts",
17 | "directories": {
18 | "lib": "lib",
19 | "test": "__tests__"
20 | },
21 | "files": [
22 | "lib"
23 | ],
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/rasendubi/uniorg.git"
27 | },
28 | "scripts": {
29 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
30 | "clean": "rm -rf ./lib",
31 | "compile": "tsc -p tsconfig.build.json",
32 | "prepublishOnly": "npm run build",
33 | "test": "jest"
34 | },
35 | "bugs": {
36 | "url": "https://github.com/rasendubi/uniorg/issues"
37 | },
38 | "devDependencies": {
39 | "@types/jest": "^29.5.12",
40 | "@types/unist": "^3.0.2",
41 | "jest": "^29.7.0",
42 | "typescript": "^5.4.5",
43 | "uniorg-parse": "workspace:^3.2.0"
44 | },
45 | "dependencies": {
46 | "unified": "^11.0.4",
47 | "unist-util-visit": "^5.0.0",
48 | "uniorg": "workspace:^1.3.0",
49 | "vfile": "^6.0.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { unified } from 'unified';
2 | import uniorg from 'uniorg-parse';
3 | import { VFile } from 'vfile';
4 |
5 | import extractKeywords, { Options } from './';
6 |
7 | const process = (s: string, options?: Options): VFile => {
8 | const processor = unified().use(uniorg).use(extractKeywords, options);
9 |
10 | const f = new VFile(s);
11 | // not interested in result
12 | processor.runSync(processor.parse(f), f);
13 |
14 | return f;
15 | };
16 |
17 | describe('uniorg-extract-keywords', () => {
18 | test('does not crash on empty document', () => {
19 | const document = ``;
20 |
21 | process(document);
22 | });
23 |
24 | test('exports title', () => {
25 | const document = `#+TITLE: hello, there!`;
26 |
27 | const f = process(document);
28 |
29 | const data = f.data as any;
30 | expect(data.title).toBe('hello, there!');
31 | });
32 |
33 | test('exports custom keyword', () => {
34 | const document = `#+MY_KEYWORD: blah`;
35 |
36 | const f = process(document);
37 |
38 | const data = f.data as any;
39 | expect(data.my_keyword).toBe('blah');
40 | });
41 |
42 | test('allows custom `name`', () => {
43 | const document = `#+AUTHOR: my name`;
44 |
45 | const f = process(document, { name: 'keywords' });
46 |
47 | const data = f.data as any;
48 | expect(data.author).toBeUndefined();
49 | expect(data.keywords.author).toBe('my name');
50 | });
51 |
52 | test('allows preserving case', () => {
53 | const document = `#+AUTHOR: my name`;
54 |
55 | const f = process(document, { preserveCase: true });
56 |
57 | const data = f.data as any;
58 | expect(data.AUTHOR).toBe('my name');
59 | });
60 | });
61 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/src/index.ts:
--------------------------------------------------------------------------------
1 | import { visit } from 'unist-util-visit';
2 |
3 | import type { Keyword } from 'uniorg';
4 | import type { Plugin } from 'unified';
5 | import type { Node } from 'unist';
6 | import type { VFile } from 'vfile';
7 |
8 | export interface Options {
9 | /**
10 | * If `name` is specified, keywords are exported under
11 | * `data[options.name][keyword]` instead of `data[keyword]`.
12 | */
13 | name?: string;
14 |
15 | /**
16 | * If `preserveCase` is specified and is `true`, keyword keys are
17 | * not lowercased.
18 | */
19 | preserveCase?: boolean;
20 | }
21 |
22 | export const extractKeywords: Plugin<[Options?]> = (options: Options = {}) => {
23 | return transformer;
24 |
25 | function transformer(tree: Node, file: VFile) {
26 | visit(tree, 'keyword', (kw: Keyword) => {
27 | let data: any = (file.data = file.data || {});
28 | if (options.name) {
29 | data = data[options.name] = data[options.name] || {};
30 | }
31 |
32 | let key = kw.key;
33 | if (!options.preserveCase) {
34 | key = key.toLowerCase();
35 | }
36 |
37 | data[key] = kw.value;
38 | });
39 | }
40 | };
41 |
42 | export default extractKeywords;
43 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-extract-keywords/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-parse`
2 |
3 | [Org-mode](https://orgmode.org/) parser compatible with [unified](https://github.com/unifiedjs/unified) ecosystem.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install uniorg-parse
9 | ```
10 |
11 |
12 | ## Use
13 |
14 | ```js
15 | var unified = require('unified')
16 | var createStream = require('unified-stream')
17 | var uniorgParse = require('uniorg-parse')
18 | var uniorg2rehype = require('uniorg-rehype')
19 | var html = require('rehype-stringify')
20 |
21 | var processor = unified().use(uniorgParse).use(uniorg2rehype).use(html)
22 |
23 | process.stdin.pipe(createStream(processor)).pipe(process.stdout)
24 | ```
25 |
26 |
27 | ## API
28 |
29 |
30 | ### `processor().use(uniorgParse, [, options])`
31 |
32 | Configure the `processor` to read Org as input and process **[uniorg](https://github.com/rasendubi/uniorg)** syntax trees.
33 |
34 |
35 | ### `parse(string[, options])`
36 |
37 | Parse string.
38 |
39 | ```js
40 | import { parse } from 'uniorg-parse/lib/parser';
41 |
42 | console.log(parse('* example document'))
43 | ```
44 |
45 |
46 | ## License
47 |
48 | [GNU General Public License v3.0 or later](./LICENSE)
49 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-parse",
3 | "version": "3.2.0",
4 | "type": "module",
5 | "description": "uniorg plugin to parse org-mode",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "plugin",
10 | "org-mode",
11 | "parse"
12 | ],
13 | "author": "Oleksii Shmalko ",
14 | "homepage": "https://github.com/rasendubi/uniorg",
15 | "license": "GPL-3.0-or-later",
16 | "main": "lib/index.js",
17 | "types": "lib/index.d.ts",
18 | "directories": {
19 | "lib": "lib",
20 | "test": "__tests__"
21 | },
22 | "files": [
23 | "lib"
24 | ],
25 | "repository": {
26 | "type": "git",
27 | "url": "git+https://github.com/rasendubi/uniorg.git"
28 | },
29 | "scripts": {
30 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
31 | "clean": "rm -rf ./lib",
32 | "compile": "tsc -p tsconfig.build.json",
33 | "prepublishOnly": "npm run build",
34 | "test": "jest"
35 | },
36 | "bugs": {
37 | "url": "https://github.com/rasendubi/uniorg/issues"
38 | },
39 | "devDependencies": {
40 | "@types/jest": "29.5.12",
41 | "@types/node": "^20.12.12",
42 | "@types/unist": "^3.0.2",
43 | "jest": "^29.7.0",
44 | "ts-jest": "^29.1.2",
45 | "typescript": "^5.4.5",
46 | "yaml": "^2.4.2"
47 | },
48 | "dependencies": {
49 | "unified": "^11.0.4",
50 | "uniorg": "workspace:^1.3.0",
51 | "unist-builder": "^4.0.0",
52 | "vfile": "^6.0.1",
53 | "vfile-location": "^5.0.2"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default } from './unified-org-parse.js';
2 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/src/unified-org-parse.ts:
--------------------------------------------------------------------------------
1 | import type { Parser, Processor, Plugin } from 'unified';
2 |
3 | import { parse } from './parser.js';
4 | import type { OrgData } from 'uniorg';
5 | import type { ParseOptions } from './parse-options.js';
6 |
7 | const orgParse: Plugin<[Partial?], string, OrgData> = function orgParse(
8 | options: Partial = {}
9 | ): void {
10 | const parser: Parser = (_doc, file) => {
11 | return parse(file, options);
12 | };
13 |
14 | Object.assign(this, { Parser: parser });
15 | }
16 |
17 | export default orgParse;
18 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-parse/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-rehype`
2 |
3 | **[uniorg](https://github.com/rasendubi/uniorg)** plugin to mutate uniorg to **[rehype](https://github.com/rehypejs/rehype)**.
4 |
5 | > Note: `uniorg-rehype` doesn't deal with HTML inside the Org (`#+begin_export html`). You'll need [rehype-raw](https://github.com/rehypejs/rehype-raw) if you're planning on doing that.
6 |
7 |
8 | ## Install
9 |
10 | ```sh
11 | npm install uniorg-rehype
12 | ```
13 |
14 |
15 | ## Use
16 |
17 | ```js
18 | var unified = require('unified')
19 | var createStream = require('unified-stream')
20 | var uniorgParse = require('uniorg-parse')
21 | var uniorg2rehype = require('uniorg-rehype')
22 | var html = require('rehype-stringify')
23 |
24 | var processor = unified().use(uniorgParse).use(uniorg2rehype).use(html)
25 |
26 | process.stdin.pipe(createStream(processor)).pipe(process.stdout)
27 | ```
28 |
29 |
30 | ## API
31 |
32 |
33 | ### `processor().use(uniorg2rehype[, options])`
34 |
35 | **uniorg** plugin to mutate to **[rehype](https://github.com/rehypejs/rehype)**.
36 |
37 | ### `orgToHast(uniorg[, options])`
38 |
39 | Convert uniorg AST into hast.
40 |
41 | ```js
42 | import { parse } from 'uniorg-parse/lib/parser';
43 | import { orgToHast } from 'uniorg-rehype/lib/org-to-hast';
44 |
45 | orgToHast(parse(`* headline`));
46 | ```
47 |
48 | ### `options`
49 | #### `imageFilenameExtensions`
50 | Filename extensions that should be considered as images. This is used to decide whether a link should be rendered as an `` or and ` `.
51 |
52 | #### `useSections`
53 | Whether to wrap all org sections into ``. Defaults to `false`.
54 |
55 | #### `footnotesSection`
56 | Renderer function for footnotes. Roughly corresponds to `org-html-footnotes-section`.
57 |
58 | #### `handlers`
59 | Allow overriding rendering for any uniorg type. Each handler receives the node of the corresponding type and should return valid hast tree.
60 |
61 | For example:
62 | ```js
63 | import { h } from 'hastscript';
64 | const processor = unified()
65 | .use(uniorgParse)
66 | .use(uniorg2rehype, {
67 | handlers: {
68 | 'comment': (org) => {
69 | return h('div.comment', [{ type: 'text', value: org.value }]);
70 | },
71 | },
72 | });
73 | ```
74 |
75 | ## License
76 |
77 | [GNU General Public License v3.0 or later](./LICENSE)
78 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-rehype",
3 | "version": "2.2.0",
4 | "type": "module",
5 | "description": "uniorg plugin to transform to rehype",
6 | "keywords": [
7 | "unified",
8 | "uniorg",
9 | "plugin",
10 | "html",
11 | "hast",
12 | "org-mode",
13 | "rehype"
14 | ],
15 | "author": "Oleksii Shmalko ",
16 | "homepage": "https://github.com/rasendubi/uniorg",
17 | "license": "GPL-3.0-or-later",
18 | "main": "lib/index.js",
19 | "types": "lib/index.d.ts",
20 | "directories": {
21 | "lib": "lib",
22 | "test": "__tests__"
23 | },
24 | "files": [
25 | "lib"
26 | ],
27 | "repository": {
28 | "type": "git",
29 | "url": "git+https://github.com/rasendubi/uniorg.git"
30 | },
31 | "scripts": {
32 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
33 | "clean": "rm -rf ./lib",
34 | "compile": "tsc -p tsconfig.build.json",
35 | "prepublishOnly": "npm run build",
36 | "test": "jest"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/rasendubi/uniorg/issues"
40 | },
41 | "devDependencies": {
42 | "@types/jest": "^29.5.12",
43 | "@types/unist": "^3.0.2",
44 | "jest": "^29.7.0",
45 | "rehype-format": "^5.0.0",
46 | "rehype-raw": "^7.0.0",
47 | "rehype-stringify": "^10.0.0",
48 | "ts-jest": "^29.1.2",
49 | "typescript": "^5.4.5",
50 | "uniorg-parse": "workspace:^3.2.0"
51 | },
52 | "dependencies": {
53 | "@types/hast": "^3.0.4",
54 | "hastscript": "^9.0.0",
55 | "unist-builder": "^4.0.0",
56 | "unified": "^11.0.4",
57 | "uniorg": "workspace:^1.3.0"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default } from './unified-org-rehype.js';
2 | export type { Options } from './unified-org-rehype.js';
3 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/src/rehype-format.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'rehype-format' {
2 | const x: any;
3 | export default x;
4 | }
5 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/src/unified-org-rehype.ts:
--------------------------------------------------------------------------------
1 | import type { Root } from 'hast';
2 | import type { Plugin } from 'unified';
3 | import type { OrgData } from 'uniorg';
4 |
5 | import { orgToHast, type OrgToHastOptions } from './org-to-hast.js';
6 |
7 | export type Options = Partial;
8 |
9 | const org2rehype: Plugin<[Options?], OrgData, Root> = function org2rehype(
10 | options: Options = {}
11 | ) {
12 | return (node: OrgData, _file: unknown) => {
13 | return orgToHast(node, options);
14 | };
15 | };
16 |
17 | export default org2rehype;
18 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-rehype/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # uniorg-slug
2 |
3 | ## 1.1.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ### Patch Changes
12 |
13 | - Updated dependencies [[`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317)]:
14 | - orgast-util-to-string@1.1.0
15 | - uniorg@1.3.0
16 |
17 | ## 1.0.1
18 |
19 | ### Patch Changes
20 |
21 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
22 |
23 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
24 |
25 | - Updated dependencies [[`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d)]:
26 | - orgast-util-to-string@1.0.1
27 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-slug`
2 |
3 | **[uniorg](https://github.com/rasendubi/uniorg)** plugin to add anchors headings using GitHub's algorithm. Similar to [rehype-slug](https://github.com/rehypejs/rehype-slug) but respects org-mode's `CUSTOM_ID` (as `org-html-export`).
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install uniorg-slug
9 | ```
10 |
11 | ## Use
12 |
13 | ```js
14 | import { unified } from 'unified';
15 | import uniorgParse from 'uniorg-parse';
16 | import { uniorgSlug } from 'uniorg-slug';
17 | import uniorg2rehype from 'uniorg-rehype';
18 | import html from 'rehype-stringify';
19 |
20 | const node = unified()
21 | .use(uniorgParse)
22 | .use(uniorgSlug)
23 | .use(uniorg2rehype)
24 | .use(html)
25 | .processSync(`
26 | * headline
27 | ** nested headline
28 | :PROPERTIES:
29 | :CUSTOM_ID: blah
30 | :END:
31 | ** headline
32 | :PROPERTIES:
33 | :ID: my-id
34 | :END:
35 | ~id~ property is ignored.
36 | `);
37 |
38 | console.log(node.toString());
39 | ```
40 |
41 | will output:
42 |
43 | ```
44 | headline
45 | nested headline
46 | headline
47 | id
property is ignored.
48 | ```
49 |
50 | ## License
51 |
52 | [GNU General Public License v3.0 or later](./LICENSE)
53 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-slug",
3 | "version": "1.1.0",
4 | "type": "module",
5 | "description": "uniorg plugin to add `id` attributes to headlines",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "plugin",
10 | "org-mode",
11 | "slug"
12 | ],
13 | "author": "Oleksii Shmalko ",
14 | "homepage": "https://github.com/rasendubi/uniorg",
15 | "license": "GPL-3.0-or-later",
16 | "main": "lib/index.js",
17 | "types": "lib/index.d.ts",
18 | "directories": {
19 | "lib": "lib",
20 | "test": "__tests__"
21 | },
22 | "files": [
23 | "lib"
24 | ],
25 | "repository": {
26 | "type": "git",
27 | "url": "git+https://github.com/rasendubi/uniorg.git"
28 | },
29 | "scripts": {
30 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
31 | "clean": "rm -rf ./lib",
32 | "compile": "tsc -p tsconfig.build.json",
33 | "prepublishOnly": "npm run build",
34 | "test": "jest"
35 | },
36 | "bugs": {
37 | "url": "https://github.com/rasendubi/uniorg/issues"
38 | },
39 | "dependencies": {
40 | "github-slugger": "^2.0.0",
41 | "orgast-util-to-string": "workspace:^1.1.0",
42 | "unified": "^11.0.4",
43 | "unist-util-visit": "^5.0.0",
44 | "uniorg": "workspace:^1.3.0"
45 | },
46 | "devDependencies": {
47 | "@types/jest": "29.5.12",
48 | "@types/unist": "3.0.2",
49 | "jest": "29.7.0",
50 | "rehype-stringify": "10.0.0",
51 | "typescript": "5.4.5",
52 | "uniorg-parse": "workspace:^3.2.0",
53 | "uniorg-rehype": "workspace:^2.2.0",
54 | "unist-util-find": "^3.0.0",
55 | "vfile": "^6.0.1"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import type { Node } from 'unist';
2 | import { find } from 'unist-util-find';
3 | import { unified } from 'unified';
4 | import uniorg from 'uniorg-parse';
5 | import { VFile } from 'vfile';
6 | import uniorg2rehype from 'uniorg-rehype';
7 | import html from 'rehype-stringify';
8 |
9 | import { uniorgSlug, Options } from './';
10 |
11 | const process = (s: string, options?: Options): Node => {
12 | const processor = unified().use(uniorg).use(uniorgSlug, options);
13 |
14 | const f = new VFile(s);
15 |
16 | return processor.runSync(processor.parse(f), f);
17 | };
18 |
19 | describe('uniorg-slug', () => {
20 | test('does not crash on empty document', () => {
21 | const document = ``;
22 |
23 | process(document);
24 | });
25 |
26 | test('simple header', () => {
27 | const document = `* some headline`;
28 |
29 | const n = process(document);
30 |
31 | const h: any = find(n, { type: 'headline' });
32 |
33 | expect(h.data.hProperties.id).toBe('some-headline');
34 | });
35 |
36 | test('header with formatting', () => {
37 | const document = `* some /emphasis/ and [[https://example.com][link]]`;
38 |
39 | const n = process(document);
40 |
41 | const h: any = find(n, { type: 'headline' });
42 |
43 | expect(h.data.hProperties.id).toBe('some-emphasis-and-link');
44 | });
45 |
46 | test('respects CUSTOM_ID', () => {
47 | const document = `* headline
48 | :PROPERTIES:
49 | :CUSTOM_ID: blah
50 | :END:`;
51 |
52 | const n = process(document);
53 |
54 | const h: any = find(n, { type: 'headline' });
55 |
56 | expect(h.data.hProperties.id).toBe('blah');
57 | });
58 |
59 | test('with uniorg-rehype', () => {
60 | const processor = unified()
61 | .use(uniorg)
62 | .use(uniorgSlug)
63 | .use(uniorg2rehype)
64 | .use(html);
65 |
66 | const s = processor
67 | .processSync(
68 | `* headline
69 | ** nested headline
70 | :PROPERTIES:
71 | :CUSTOM_ID: blah
72 | :END:
73 | ** headline
74 | :PROPERTIES:
75 | :ID: my-id
76 | :END:
77 | ~id~ property is ignored.`
78 | )
79 | .toString();
80 |
81 | expect(s).toMatchInlineSnapshot(
82 | `"headline nested headline headline id
property is ignored.
"`
83 | );
84 | });
85 |
86 | test('preserves data.hProperties.id', () => {
87 | const processor = unified()
88 | .use(uniorg)
89 | .use(() => (node) => {
90 | const headline: any = find(node, { type: 'headline' });
91 | headline.data = { hProperties: { id: 'my-custom-id' } };
92 | })
93 | .use(uniorgSlug)
94 | .use(uniorg2rehype)
95 | .use(html);
96 |
97 | const document = `* some headline`;
98 |
99 | const s = String(processor.processSync(document));
100 |
101 | expect(s).toMatchInlineSnapshot(
102 | `"some headline "`
103 | );
104 | });
105 | });
106 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/src/index.ts:
--------------------------------------------------------------------------------
1 | import { visit } from 'unist-util-visit';
2 | import type { Plugin } from 'unified';
3 | import type { Node } from 'unist';
4 | import GithubSlugger from 'github-slugger';
5 |
6 | import { Headline, Section } from 'uniorg';
7 | import { toString } from 'orgast-util-to-string';
8 |
9 | export interface Options {}
10 |
11 | export const uniorgSlug: Plugin<[Options?]> = (options: Options = {}) => {
12 | return transformer;
13 |
14 | function transformer(tree: Node, _file: unknown) {
15 | const slugger = new GithubSlugger();
16 |
17 | visit(tree, 'section', (section: Section) => {
18 | const headline = section.children[0] as Headline;
19 | const data: any = (headline.data = headline.data || {});
20 | const props = (data.hProperties = data.hProperties || {});
21 |
22 | if (!props.id) {
23 | const id = customId(section) ?? slugger.slug(toString(headline));
24 | props.id = id;
25 | }
26 | });
27 | }
28 | };
29 |
30 | function customId(section: Section): string | null {
31 | const drawer: any = section.children.find(
32 | (node: any) => node.type === 'property-drawer'
33 | );
34 | const property = drawer?.children?.find(
35 | (node: any) => node.type === 'node-property' && node.key === 'CUSTOM_ID'
36 | );
37 |
38 | return property?.value;
39 | }
40 |
41 | export default uniorgSlug;
42 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/src/unist-util-find.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'unist-util-find' {
2 | import { Node } from 'unist';
3 |
4 | export const find: (node: Node, condition: any) => Node | undefined;
5 | }
6 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-slug/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg-stringify`
2 |
3 | uniorg plugin to serialize org-mode.
4 |
5 | ## Install
6 |
7 | ```sh
8 | npm install uniorg-stringify
9 | ```
10 |
11 | ## Use
12 |
13 | ```js
14 | import { unified } from 'unified';
15 | import uniorgParse from 'uniorg-parse';
16 | import { uniorgStringify } from 'uniorg-stringify';
17 |
18 | const result = unified()
19 | .use(uniorgParse)
20 | .use(uniorgStringify)
21 | .processSync('Some /emphasis/, *importance*, and ~code~.');
22 |
23 | console.log(String(result)); //=> Some /emphasis/, *importance*, and ~code~.
24 | ```
25 |
26 | ## API
27 |
28 | ### `processor().use(uniorgStringify[, options])`
29 |
30 | **uniorg** plugin to serialize uniast into string.
31 |
32 | ### `stringify(uniast[, options])`
33 |
34 | Convert uniorg AST into a string.
35 |
36 | ```js
37 | import { parse } from 'uniorg-parse/lib/parser';
38 | import { stringify } from 'uniorg-stringify/lib/stringify';
39 |
40 | stringify(parse(`* headline`));
41 | ```
42 |
43 | ### `options`
44 |
45 | #### `handlers`
46 | Allow overriding rendering for any uniorg type. Each handler receives the node of the corresponding type and should return a string.
47 |
48 | For example to output bold emphasis with dollar signs instead of stars:
49 | ```js
50 | const processor = unified()
51 | .use(uniorgParse)
52 | .use(uniorgStringify, {
53 | handlers: {
54 | 'bold': (org, options) => {
55 | return `$${stringify(org.children, options)}$`;
56 | },
57 | },
58 | });
59 | ```
60 | ## License
61 |
62 | [GNU General Public License v3.0 or later](./LICENSE)
63 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/jest.config.js:
--------------------------------------------------------------------------------
1 | import config from '../../jest-base.mjs';
2 | export default { ...config };
3 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg-stringify",
3 | "version": "1.4.0",
4 | "description": "uniorg plugin to serialize org-mode",
5 | "type": "module",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "uniorg-plugin",
10 | "plugin",
11 | "org-mode",
12 | "stringify",
13 | "serialize"
14 | ],
15 | "author": "Oleksii Shmalko ",
16 | "homepage": "https://github.com/rasendubi/uniorg",
17 | "license": "GPL-3.0-or-later",
18 | "main": "lib/index.js",
19 | "types": "lib/index.d.ts",
20 | "directories": {
21 | "lib": "lib",
22 | "test": "__tests__"
23 | },
24 | "files": [
25 | "lib"
26 | ],
27 | "repository": {
28 | "type": "git",
29 | "url": "git+https://github.com/rasendubi/uniorg.git"
30 | },
31 | "scripts": {
32 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
33 | "clean": "rm -rf ./lib",
34 | "compile": "tsc -p tsconfig.build.json",
35 | "prepublishOnly": "npm run build",
36 | "test": "jest"
37 | },
38 | "bugs": {
39 | "url": "https://github.com/rasendubi/uniorg/issues"
40 | },
41 | "devDependencies": {
42 | "@types/jest": "29.5.12",
43 | "@types/unist": "3.0.2",
44 | "jest": "29.7.0",
45 | "typescript": "^5.4.5",
46 | "uniorg-parse": "workspace:^3.2.0",
47 | "vfile": "6.0.1"
48 | },
49 | "dependencies": {
50 | "unified": "^11.0.4",
51 | "uniorg": "workspace:^1.3.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import uniorgParse from 'uniorg-parse';
2 | import { unified } from 'unified';
3 |
4 | import { uniorgStringify } from './index';
5 |
6 | const processor = unified().use(uniorgParse).use(uniorgStringify);
7 |
8 | describe('uniorg-stringify', () => {
9 | it('serializes uniorg', () => {
10 | const result = processor.processSync('* hello, world!');
11 | expect(String(result)).toMatchInlineSnapshot(`
12 | "* hello, world!
13 | "
14 | `);
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/src/index.ts:
--------------------------------------------------------------------------------
1 | import { stringify } from './stringify.js';
2 | import type { StringifyOptions } from './stringify.js';
3 | import type { OrgData } from 'uniorg';
4 | import type { Plugin } from 'unified';
5 | import { Node } from 'unist';
6 |
7 | export const uniorgStringify: Plugin<[Partial?], OrgData, string> = function (
8 | options: Partial = {}
9 | ): void {
10 | this.compiler = (tree): string => {
11 | if (!isOrgData(tree)) {
12 | throw new Error('Expected an OrgData node, but received an incompatible node type');
13 | }
14 | return stringify(tree, options);
15 | };
16 | }
17 |
18 | function isOrgData(node: Node | undefined): node is OrgData {
19 | return Boolean(
20 | node &&
21 | 'type' in node &&
22 | node.type === 'org-data'
23 | );
24 | }
--------------------------------------------------------------------------------
/packages/uniorg-stringify/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg-stringify/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /lib/
3 |
--------------------------------------------------------------------------------
/packages/uniorg/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # uniorg
2 |
3 | ## 1.3.0
4 |
5 | ### Minor Changes
6 |
7 | - [#134](https://github.com/rasendubi/uniorg/pull/134) [`392ec12`](https://github.com/rasendubi/uniorg/commit/392ec12e3e2a019d40b2d6efea1456097b25e317) Thanks [@rasendubi](https://github.com/rasendubi)! - Move public-facing type definitions from `devDependencies` to normal `dependencies` to ensure type safety for users without requiring manual installation of types.
8 |
9 | TypeScript will now have more complete type information available, which may surface previously hidden type conflicts but leads to more accurate type checking overall.
10 |
11 | ## 1.2.0
12 |
13 | ### Minor Changes
14 |
15 | - [#109](https://github.com/rasendubi/uniorg/pull/109) [`dbf6452`](https://github.com/rasendubi/uniorg/commit/dbf6452921ad03120bb9df87746aef52ac72b5fb) Thanks [@rasendubi](https://github.com/rasendubi)! - Support `export-snippet` in uniorg, uniorg-parse, uniorg-rehype, and uniorg-stringify.
16 |
17 | `export-snippet` has the following form: `@@backend:value@@`. Example: `@@html:@@some text@@html: `.
18 |
19 | This is a breaking change for uniorg-parse as it may output nodes unknown to downstream users (uniorg-rehype and uniorg-stringify). If you upgrade uniorg-parse, you should also upgrade uniorg-rehype and uniorg-stringify to the corresponding versions.
20 |
21 | - [#111](https://github.com/rasendubi/uniorg/pull/111) [`b45baf9`](https://github.com/rasendubi/uniorg/commit/b45baf992db4659e2732e888bd3860b9eff25504) Thanks [@rasendubi](https://github.com/rasendubi)! - Support `line-break` in uniorg, uniorg-parse, uniorg-rehype, and uniorg-stringify.
22 |
23 | This is a breaking change for uniorg-parse as it may output nodes unknown to downstream users (uniorg-rehype and uniorg-stringify). If you upgrade uniorg-parse, you should also upgrade uniorg-rehype and uniorg-stringify to the corresponding versions.
24 |
25 | ## 1.1.1
26 |
27 | ### Patch Changes
28 |
29 | - [#94](https://github.com/rasendubi/uniorg/pull/94) [`e71a8a8`](https://github.com/rasendubi/uniorg/commit/e71a8a85f4921d53fdf112df17bd37b92af1ed5d) Thanks [@rasendubi](https://github.com/rasendubi)! - Upgrade dependencies.
30 |
31 | Most notably, this upgrades vfile version. This does not change the code and the old code should continue working. But it might break the types so you might need to upgrade vfile version as well (if you're manipulating vfiles directly).
32 |
33 | ## 1.1.0
34 |
35 | ### Minor Changes
36 |
37 | - [#33](https://github.com/rasendubi/uniorg/pull/33) [`67420e7`](https://github.com/rasendubi/uniorg/commit/67420e7fe05defc99b52aecce75fcc3831d39ff6) Thanks [@rasendubi](https://github.com/rasendubi)! - Support native org-mode citations in uniorg, uniorg-parse, uniorg-rehype, uniorg-stringify.
38 |
39 | This is a breaking change for uniorg-parse as it may output nodes unknown to downstream packages (uniorg-rehype, uniorg-stringify).
40 |
41 | If you upgrade uniorg-parse to >=2, you also need to bump uniorg-rehype to >=1.1 and uniorg-stringify to >=1.1 (if you use these). Upgrading uniorg-rehype and uniorg-stringify does not require bumping uniorg-parse.
42 |
43 | The default rendering of citations in uniorg-rehype is quite primitive and citations are transformed into `cite:` links (to keep some compatibility with org-ref). The handling can be overridden by specifying your own `handlers`.
44 |
--------------------------------------------------------------------------------
/packages/uniorg/README.md:
--------------------------------------------------------------------------------
1 | # `uniorg`
2 |
3 | Type definitions for uniorg Abstract Syntax Tree.
4 |
5 | ## License
6 |
7 | [GNU General Public License v3.0 or later](./LICENSE)
8 |
--------------------------------------------------------------------------------
/packages/uniorg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uniorg",
3 | "version": "1.3.0",
4 | "type": "module",
5 | "description": "uniorg type definitions",
6 | "keywords": [
7 | "uniorg",
8 | "unified",
9 | "org-mode",
10 | "ast"
11 | ],
12 | "author": "Oleksii Shmalko ",
13 | "homepage": "https://github.com/rasendubi/uniorg",
14 | "license": "GPL-3.0-or-later",
15 | "main": "lib/index.js",
16 | "types": "lib/index.d.ts",
17 | "directories": {
18 | "lib": "lib",
19 | "test": "__tests__"
20 | },
21 | "files": [
22 | "lib"
23 | ],
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/rasendubi/uniorg.git"
27 | },
28 | "scripts": {
29 | "build": "rm -rf ./lib && tsc -p tsconfig.build.json",
30 | "clean": "rm -rf ./lib",
31 | "compile": "tsc -p tsconfig.build.json",
32 | "prepublishOnly": "npm run build"
33 | },
34 | "bugs": {
35 | "url": "https://github.com/rasendubi/uniorg/issues"
36 | },
37 | "dependencies": {
38 | "@types/unist": "^3.0.0"
39 | },
40 | "devDependencies": {
41 | "typescript": "^5.4.5"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/uniorg/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.build.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages/uniorg/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./lib"
5 | },
6 | "include": ["./src"]
7 | }
8 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - packages/*
3 | - examples/*
4 |
--------------------------------------------------------------------------------
/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "ES2020",
4 | "noImplicitAny": true,
5 | "noLib": false,
6 | "target": "ES2020",
7 | "sourceMap": true,
8 | "noEmitOnError": true,
9 | "strict": true,
10 | "noFallthroughCasesInSwitch": true,
11 | "moduleResolution": "node",
12 | "esModuleInterop": true,
13 | "declaration": true,
14 | "isolatedModules": true,
15 | "allowJs": true,
16 | "lib": ["ES2020", "dom"]
17 | },
18 | "exclude": ["node_modules", "lib", "**/*.spec.ts", "**/*.config.js"]
19 | }
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.build.json",
3 | "exclude": ["node_modules", "lib", "**/*.config.js"],
4 |
5 | "compilerOptions": {
6 | "baseUrl": ".",
7 | "paths": {
8 | "uniorg": ["packages/uniorg/src"],
9 | "uniorg-parse": ["packages/uniorg-parse/src"],
10 | "uniorg-rehype": ["packages/uniorg-rehype/src"],
11 | "orgast-util-to-string": ["packages/orgast-util-to-string/src"]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://turbo.build/schema.json",
3 | "globalDependencies": [
4 | "./tsconfig.json",
5 | "./tsconfig.build.json",
6 | "./jest-base.mjs",
7 | "./jest.config.js"
8 | ],
9 | "tasks": {
10 | "dev": {
11 | "persistent": true
12 | },
13 | "build": {
14 | "dependsOn": ["^build"],
15 | "outputs": ["lib/**", "dist/**", ".next/**"]
16 | },
17 | "@uniorgjs/orgx#build": {
18 | "dependsOn": ["^build"],
19 | "outputs": ["types/**"]
20 | },
21 | "lint": {
22 | "outputs": []
23 | },
24 | "test": {
25 | "dependsOn": ["^build"],
26 | "outputs": []
27 | },
28 | "clean": {
29 | "cache": false
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------