@lincyaw/workspace 1.0.0-rc.2 → 1.0.0-rc.4

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.
Files changed (2) hide show
  1. package/package.json +5 -5
  2. package/src/node/build.ts +39 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lincyaw/workspace",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.0.0-rc.4",
4
4
  "description": "Presmium's workspace service (presmium serve): documents, their history, reviews and the workspace site",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -33,12 +33,12 @@
33
33
  "image-size": "2.0.4",
34
34
  "mime-types": "3.0.2",
35
35
  "yaml": "^2.9.1",
36
- "@lincyaw/compiler": "1.0.0-rc.2",
37
- "@lincyaw/server": "1.0.0-rc.2",
38
- "@lincyaw/kernel": "1.0.0-rc.2"
36
+ "@lincyaw/compiler": "1.0.0-rc.4",
37
+ "@lincyaw/kernel": "1.0.0-rc.4",
38
+ "@lincyaw/server": "1.0.0-rc.4"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/mime-types": "^3.0.1",
42
- "@lincyaw/mcp": "1.0.0-rc.2"
42
+ "@lincyaw/mcp": "1.0.0-rc.4"
43
43
  }
44
44
  }
package/src/node/build.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import { cpSync, existsSync, rmSync } from 'node:fs'
1
2
  import { join, resolve } from 'node:path'
2
- import { Compiler } from '@lincyaw/compiler'
3
- import type { RunStats } from '@lincyaw/compiler'
4
- import { errorMessage } from '@lincyaw/kernel'
3
+ import { build, Compiler } from '@lincyaw/compiler'
4
+ import type { Compilation, RunStats } from '@lincyaw/compiler'
5
+ import { errorMessage, isRecord } from '@lincyaw/kernel'
5
6
  import type { Finding } from '@lincyaw/kernel'
6
7
  import { listDocuments, readWorkspaceConfig } from './config.ts'
7
8
  import { siteContext, siteDocument, siteIR, siteSpec, siteTranslations, webRenderer } from './site.ts'
@@ -18,8 +19,12 @@ export async function buildWorkspace(root: string, options: { outDir?: string, b
18
19
  const findings: Finding[] = []
19
20
  const documents: WorkspaceBuild['documents'] = []
20
21
  const site = siteSpec(config, [])
22
+ const base = siteBase(config.site.base)
23
+ const forms: { dir: string, compilation: Compilation, to: string[] }[] = []
21
24
  for (const document of found) {
22
25
  const compilation = await new Compiler(join(config.root, document.entry), { bundled: options.bundled, settings: config.settings }).compile({ pruneCache: true })
26
+ const to = presentations(compilation, `${base}${document.dir.split('/').map(encodeURIComponent).join('/')}/`)
27
+ if (to.length > 0) forms.push({ dir: document.dir, compilation, to })
23
28
  const translated = await siteTranslations(compilation)
24
29
  findings.push(...compilation.doc.diagnostics, ...translated.findings)
25
30
  documents.push({ dir: document.dir, title: document.title, runs: compilation.runStats })
@@ -27,15 +32,45 @@ export async function buildWorkspace(root: string, options: { outDir?: string, b
27
32
  }
28
33
  const outDir = join(resolve(options.outDir ?? join(config.root, 'dist')), 'web')
29
34
  const renderer = await webRenderer(config.root, options.bundled)
30
- const ctx = siteContext({ root: config.root, outDir, workDir: join(config.root, '.presmium', 'site'), base: siteBase(config.site.base), findings })
35
+ const ctx = siteContext({ root: config.root, outDir, workDir: join(config.root, '.presmium', 'site'), base, findings })
31
36
  try {
32
37
  await renderer.buildSite!(site, ctx)
33
38
  } catch (error) {
34
39
  findings.push({ checkId: 'presmium.render', severity: 'error', message: `the workspace site failed: ${errorMessage(error)}` })
40
+ return { outDir, documents, findings }
41
+ }
42
+ // A document's presentation and its narrated lecture are built beside its pages: `<dir>/slides/` and `<dir>/lecture/`.
43
+ for (const { dir, compilation, to } of forms) {
44
+ const work = join(config.root, '.presmium', 'forms', dir)
45
+ rmSync(work, { recursive: true, force: true })
46
+ try {
47
+ const report = await build(compilation, { outDir: work, to })
48
+ findings.push(...report.findings)
49
+ for (const form of to) if (existsSync(join(work, form))) cpSync(join(work, form), join(outDir, dir, form), { recursive: true })
50
+ } catch (error) {
51
+ findings.push({ checkId: 'presmium.render', severity: 'error', message: `document ${dir}: its ${to.join(' and ')} failed: ${errorMessage(error)}` })
52
+ }
35
53
  }
36
54
  return { outDir, documents, findings }
37
55
  }
38
56
 
57
+ const PRESENTATIONS = ['slides', 'lecture']
58
+
59
+ /**
60
+ * The presentation forms a document asks for (`metadata.renderers.slides` or `lecture`), set to be served below its
61
+ * pages at `prefix`: the slides at `slides/`, and the web pages and the slides linked to each other.
62
+ */
63
+ function presentations(compilation: Compilation, prefix: string): string[] {
64
+ const { renderers } = compilation.doc.config
65
+ const to = PRESENTATIONS.filter(form => renderers[form] !== undefined)
66
+ if (to.length === 0) return to
67
+ if (to.includes('slides')) renderers.slides = { ...isRecord(renderers.slides) ? renderers.slides : {}, base: `${prefix}slides/` }
68
+ const settings = compilation.doc.config.presmium ??= {}
69
+ const web = isRecord(settings['presmium.web']) ? settings['presmium.web'] : {}
70
+ settings['presmium.web'] = { ...web, webUrl: prefix, ...to.includes('slides') ? { slidesUrl: `${prefix}slides/` } : {} }
71
+ return to
72
+ }
73
+
39
74
  function siteBase(value: unknown): string {
40
75
  const path = typeof value === 'string' ? value.trim().replace(/^\/+|\/+$/g, '') : ''
41
76
  return path ? `/${path}/` : '/'