orga-build 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__tests__/build.test.js +9 -0
- package/lib/files.d.ts +6 -1
- package/lib/files.d.ts.map +1 -1
- package/lib/files.js +17 -15
- package/lib/orga.d.ts +3 -1
- package/lib/orga.d.ts.map +1 -1
- package/lib/orga.js +60 -8
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +5 -1
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ const outDir = path.join(__dirname, '.test-output')
|
|
|
12
12
|
describe('orga-build', () => {
|
|
13
13
|
before(async () => {
|
|
14
14
|
await fs.mkdir(fixtureDir, { recursive: true })
|
|
15
|
+
await fs.mkdir(path.join(fixtureDir, 'docs'), { recursive: true })
|
|
15
16
|
// Create minimal fixture
|
|
16
17
|
await fs.writeFile(
|
|
17
18
|
path.join(fixtureDir, 'index.org'),
|
|
@@ -20,8 +21,14 @@ describe('orga-build', () => {
|
|
|
20
21
|
* Hello World
|
|
21
22
|
|
|
22
23
|
This is a test page.
|
|
24
|
+
|
|
25
|
+
Here's [[file:./docs/index.org][index page]].
|
|
26
|
+
|
|
27
|
+
Here's [[file:more.org][another page]].
|
|
23
28
|
`
|
|
24
29
|
)
|
|
30
|
+
await fs.writeFile(path.join(fixtureDir, 'docs', 'index.org'), 'Docs index page.')
|
|
31
|
+
await fs.writeFile(path.join(fixtureDir, 'more.org'), 'Another page.')
|
|
25
32
|
})
|
|
26
33
|
|
|
27
34
|
after(async () => {
|
|
@@ -51,6 +58,8 @@ This is a test page.
|
|
|
51
58
|
const html = await fs.readFile(indexPath, 'utf-8')
|
|
52
59
|
assert.ok(html.includes('<title>Test Page</title>'), 'should have title')
|
|
53
60
|
assert.ok(html.includes('Hello World'), 'should have heading content')
|
|
61
|
+
assert.ok(html.includes('href="/docs"'), 'should rewrite docs/index.org to /docs')
|
|
62
|
+
assert.ok(html.includes('href="/more"'), 'should rewrite more.org to /more')
|
|
54
63
|
})
|
|
55
64
|
|
|
56
65
|
test('generates assets directory', async () => {
|
package/lib/files.d.ts
CHANGED
|
@@ -7,11 +7,16 @@ export function setup(dir: string, { outDir }?: {
|
|
|
7
7
|
outDir?: string | undefined;
|
|
8
8
|
}): {
|
|
9
9
|
pages: () => Promise<Record<string, Page>>;
|
|
10
|
-
page: (
|
|
10
|
+
page: (slug: string) => Promise<Page>;
|
|
11
11
|
components: () => Promise<string | null>;
|
|
12
12
|
layouts: () => Promise<Record<string, string>>;
|
|
13
13
|
contentEntries: () => Promise<ContentEntry[]>;
|
|
14
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Convert a content file path (relative to content root) to the canonical page slug.
|
|
17
|
+
* @param {string} contentFilePath
|
|
18
|
+
*/
|
|
19
|
+
export function getSlugFromContentFilePath(contentFilePath: string): string;
|
|
15
20
|
export type Page = {
|
|
16
21
|
dataPath: string;
|
|
17
22
|
/**
|
package/lib/files.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["files.js"],"names":[],"mappings":"AA8EA;;;;GAIG;AACH,2BAJW,MAAM,eAEd;IAAyB,MAAM;CACjC;;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["files.js"],"names":[],"mappings":"AA8EA;;;;GAIG;AACH,2BAJW,MAAM,eAEd;IAAyB,MAAM;CACjC;;iBAiIY,MAAM;;;;EAKlB;AAsBD;;;GAGG;AACH,4DAFW,MAAM,UAoBhB;;cA7Pa,MAAM;;;;YACN,MAAM;;;QAMN,MAAM;UACN,MAAM;UACN,MAAM;cACN,MAAM;SACN,KAAK,GAAG,KAAK,GAAG,KAAK;UACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC"}
|
package/lib/files.js
CHANGED
|
@@ -106,8 +106,8 @@ export function setup(dir, { outDir } = {}) {
|
|
|
106
106
|
/** @type {Record<string, Page>} */
|
|
107
107
|
const pages = {}
|
|
108
108
|
for (const file of files) {
|
|
109
|
-
const
|
|
110
|
-
pages[
|
|
109
|
+
const pageSlug = getSlugFromContentFilePath(file)
|
|
110
|
+
pages[pageSlug] = {
|
|
111
111
|
dataPath: path.join(dir, file)
|
|
112
112
|
}
|
|
113
113
|
}
|
|
@@ -131,8 +131,8 @@ export function setup(dir, { outDir } = {}) {
|
|
|
131
131
|
|
|
132
132
|
return layoutFiles.reduce(
|
|
133
133
|
(/** @type {Record<string, string>} */ result, file) => {
|
|
134
|
-
const
|
|
135
|
-
result[
|
|
134
|
+
const layoutSlug = path.dirname(getSlugFromContentFilePath(file))
|
|
135
|
+
result[layoutSlug] = path.join(dir, file)
|
|
136
136
|
return result
|
|
137
137
|
},
|
|
138
138
|
/** @type {Record<string, string>} */ {}
|
|
@@ -209,10 +209,10 @@ export function setup(dir, { outDir } = {}) {
|
|
|
209
209
|
|
|
210
210
|
return files
|
|
211
211
|
|
|
212
|
-
/** @param {string}
|
|
213
|
-
async function page(
|
|
212
|
+
/** @param {string} slug */
|
|
213
|
+
async function page(slug) {
|
|
214
214
|
const all = await pages()
|
|
215
|
-
return all[
|
|
215
|
+
return all[slug]
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -237,16 +237,18 @@ function cache(fn) {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
/**
|
|
240
|
-
*
|
|
240
|
+
* Convert a content file path (relative to content root) to the canonical page slug.
|
|
241
|
+
* @param {string} contentFilePath
|
|
241
242
|
*/
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
export function getSlugFromContentFilePath(contentFilePath) {
|
|
244
|
+
const normalizedFilePath = contentFilePath.replace(/\\/g, '/')
|
|
245
|
+
let slug = normalizedFilePath.replace(/\.(org|md|mdx|js|jsx|ts|tsx)$/, '')
|
|
246
|
+
slug = slug.replace(/index$/, '')
|
|
245
247
|
// remove trailing slash
|
|
246
|
-
|
|
248
|
+
slug = slug.replace(/\/$/, '')
|
|
247
249
|
// ensure starting slash
|
|
248
|
-
|
|
249
|
-
|
|
250
|
+
slug = slug.replace(/^\//, '')
|
|
251
|
+
slug = `/${slug}`
|
|
250
252
|
|
|
251
253
|
// turn [id] into :id
|
|
252
254
|
// so that react-router can recognize it as url params
|
|
@@ -255,5 +257,5 @@ function getPagePublicPath(file) {
|
|
|
255
257
|
// (_, paramName) => `:${paramName}`
|
|
256
258
|
// )
|
|
257
259
|
|
|
258
|
-
return
|
|
260
|
+
return slug
|
|
259
261
|
}
|
package/lib/orga.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @param {Object} options
|
|
3
3
|
* @param {string|string[]} options.containerClass - CSS class name(s) to wrap the rendered content
|
|
4
|
+
* @param {string} options.root - Root directory for content files
|
|
4
5
|
*/
|
|
5
|
-
export function setupOrga({ containerClass }: {
|
|
6
|
+
export function setupOrga({ containerClass, root }: {
|
|
6
7
|
containerClass: string | string[];
|
|
8
|
+
root: string;
|
|
7
9
|
}): import("@orgajs/rollup").Plugin;
|
|
8
10
|
//# sourceMappingURL=orga.d.ts.map
|
package/lib/orga.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orga.d.ts","sourceRoot":"","sources":["orga.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"orga.d.ts","sourceRoot":"","sources":["orga.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,oDAHG;IAAiC,cAAc,EAAvC,MAAM,GAAC,MAAM,EAAE;IACC,IAAI,EAApB,MAAM;CAChB,mCAYA"}
|
package/lib/orga.js
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @import {Root as HastTree} from 'hast'
|
|
3
3
|
*/
|
|
4
|
+
import path from 'node:path'
|
|
4
5
|
import _orga from '@orgajs/rollup'
|
|
5
6
|
import { visitParents } from 'unist-util-visit-parents'
|
|
7
|
+
import { getSlugFromContentFilePath } from './files.js'
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @param {Object} options
|
|
9
11
|
* @param {string|string[]} options.containerClass - CSS class name(s) to wrap the rendered content
|
|
12
|
+
* @param {string} options.root - Root directory for content files
|
|
10
13
|
*/
|
|
11
|
-
export function setupOrga({ containerClass }) {
|
|
14
|
+
export function setupOrga({ containerClass, root }) {
|
|
12
15
|
return _orga({
|
|
13
|
-
rehypePlugins: [
|
|
16
|
+
rehypePlugins: [
|
|
17
|
+
[rehypeWrap, { className: containerClass }],
|
|
18
|
+
[rewriteOrgFileLinks, { root }],
|
|
19
|
+
image
|
|
20
|
+
],
|
|
14
21
|
reorgRehypeOptions: {
|
|
15
|
-
linkHref: (link) =>
|
|
16
|
-
if (link.path.protocol === 'file') {
|
|
17
|
-
return link.path.value.replace(/\.org$/, '')
|
|
18
|
-
}
|
|
19
|
-
return link.path.value
|
|
20
|
-
}
|
|
22
|
+
linkHref: (link) => link.path.value
|
|
21
23
|
}
|
|
22
24
|
})
|
|
23
25
|
}
|
|
@@ -83,6 +85,56 @@ function image() {
|
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
/**
|
|
89
|
+
* @param {Object} options
|
|
90
|
+
* @param {string} options.root
|
|
91
|
+
*/
|
|
92
|
+
function rewriteOrgFileLinks({ root }) {
|
|
93
|
+
/**
|
|
94
|
+
* @param {any} tree
|
|
95
|
+
* @param {import('vfile').VFile} [file]
|
|
96
|
+
*/
|
|
97
|
+
return function (tree, file) {
|
|
98
|
+
const filePath = file?.path
|
|
99
|
+
if (!filePath) return
|
|
100
|
+
|
|
101
|
+
visitParents(tree, { tagName: 'a' }, (node) => {
|
|
102
|
+
const href = node?.properties?.href
|
|
103
|
+
if (typeof href !== 'string') return
|
|
104
|
+
if (!href.endsWith('.org')) return
|
|
105
|
+
|
|
106
|
+
const targetSlug = resolveOrgHrefToContentSlug({
|
|
107
|
+
root,
|
|
108
|
+
filePath,
|
|
109
|
+
href
|
|
110
|
+
})
|
|
111
|
+
if (!targetSlug) return
|
|
112
|
+
node.properties.href = targetSlug
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @param {Object} options
|
|
119
|
+
* @param {string} options.root
|
|
120
|
+
* @param {string} options.filePath
|
|
121
|
+
* @param {string} options.href
|
|
122
|
+
* @returns {string|null}
|
|
123
|
+
*/
|
|
124
|
+
function resolveOrgHrefToContentSlug({ root, filePath, href }) {
|
|
125
|
+
const decodedHrefPath = decodeURI(href)
|
|
126
|
+
const absoluteTargetPath = decodedHrefPath.startsWith('/')
|
|
127
|
+
? path.resolve(root, `.${decodedHrefPath}`)
|
|
128
|
+
: path.resolve(path.dirname(filePath), decodedHrefPath)
|
|
129
|
+
|
|
130
|
+
const relativeTargetPath = path.relative(root, absoluteTargetPath)
|
|
131
|
+
if (relativeTargetPath.startsWith('..') || path.isAbsolute(relativeTargetPath)) {
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return getSlugFromContentFilePath(relativeTargetPath)
|
|
136
|
+
}
|
|
137
|
+
|
|
86
138
|
function genId(length = 8) {
|
|
87
139
|
const array = new Uint8Array(length)
|
|
88
140
|
crypto.getRandomValues(array)
|
package/lib/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["plugin.js"],"names":[],"mappings":"AAoBA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,kEAHW,sBAAsB,GACpB,OAAO,MAAM,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["plugin.js"],"names":[],"mappings":"AAoBA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,kEAHW,sBAAsB,GACpB,OAAO,MAAM,EAAE,YAAY,EAAE,CAQzC;AAED;;;;;;GAMG;AACH,uHAHW,sBAAsB,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5I;IAAE,OAAO,EAAE,OAAO,MAAM,EAAE,YAAY,EAAE,CAAC;IAAC,OAAO,EAAE;QAAE,KAAK,EAAE,OAAO,KAAK,CAAA;KAAE,CAAA;CAAE,CAoBxF;AAiBD;;;;;;;;;;;;GAYG;AACH,gDAHW,MAAM,GACJ,OAAO,MAAM,EAAE,MAAM,CA8CjC;AAlID;;GAEG;AACH;;;;EAIC;;;;;UAIa,MAAM;;;;aACN,MAAM,GAAG,SAAS;;;;qBAClB,MAAM,GAAC,MAAM,EAAE"}
|
package/lib/plugin.js
CHANGED
|
@@ -33,7 +33,11 @@ export const alias = {
|
|
|
33
33
|
* @returns {import('vite').PluginOption[]}
|
|
34
34
|
*/
|
|
35
35
|
export function orgaBuildPlugin({ root, outDir, containerClass = [] }) {
|
|
36
|
-
return [
|
|
36
|
+
return [
|
|
37
|
+
setupOrga({ containerClass, root }),
|
|
38
|
+
react(),
|
|
39
|
+
pluginFactory({ dir: root, outDir })
|
|
40
|
+
]
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
/**
|