@lincyaw/kernel 1.0.0-rc.13 → 1.0.0-rc.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lincyaw/kernel",
3
- "version": "1.0.0-rc.13",
3
+ "version": "1.0.0-rc.14",
4
4
  "description": "Presmium's shared kernel: the IR and plugin contracts, the service registry, anchors and checks",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -15,6 +15,7 @@
15
15
  "ir"
16
16
  ],
17
17
  "type": "module",
18
+ "sideEffects": false,
18
19
  "engines": {
19
20
  "node": ">=22.19"
20
21
  },
@@ -94,6 +94,8 @@ export interface DocumentSummary {
94
94
  description?: string
95
95
  lang?: string
96
96
  tags?: string[]
97
+ /** Whether its metadata asks for a presentation (`renderers.slides`), which a site serves below its pages. */
98
+ slides?: boolean
97
99
  }
98
100
 
99
101
  /** @experimental The workspace service's answer to `documents`. */
package/src/embed.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * What a page tells the page that embeds it in a frame, as `postMessage` to its parent: whether its current slide is
3
+ * drawn (no component is still loading) and the state of its lecture. An embedding page (a site's home page playing a
4
+ * document's presentation) keeps its own cover until `drawn`, and offers Play when the lecture is `waiting`.
5
+ */
6
+ export const EMBED_MESSAGE = 'presmium:state'
7
+
8
+ export type EmbeddedLecture = 'loading' | 'waiting' | 'playing' | 'paused' | 'failed'
9
+
10
+ export interface EmbedState {
11
+ type: typeof EMBED_MESSAGE
12
+ drawn: boolean
13
+ section?: string
14
+ step?: number
15
+ /** Absent when the page plays no lecture. `waiting`: the browser refused autoplay; the reader's Play starts it. */
16
+ lecture?: EmbeddedLecture
17
+ }
18
+
19
+ let last: EmbedState = { type: EMBED_MESSAGE, drawn: false }
20
+
21
+ /** Sends the page's state, merged with what was sent before, to the embedding page; nothing when not in a frame. */
22
+ export function notifyEmbedder(change: Partial<Omit<EmbedState, 'type'>>): void {
23
+ if (typeof window === 'undefined' || window.parent === window) return
24
+ last = { ...last, ...change }
25
+ window.parent.postMessage(last, '*')
26
+ }
@@ -0,0 +1,4 @@
1
+ /** Text as it reads in HTML, in an element or an attribute's value; apart from `html.ts`, so that escaping loads no HTML parser. */
2
+ export function escapeHtml(text: string): string {
3
+ return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
4
+ }
package/src/html.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { parseFragment } from 'parse5'
2
2
  import type { DefaultTreeAdapterMap } from 'parse5'
3
-
4
- export function escapeHtml(text: string): string {
5
- return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
6
- }
3
+ import { escapeHtml } from './escape-html.ts'
7
4
 
8
5
  export interface HtmlAttribute {
9
6
  name: string
package/src/index.ts CHANGED
@@ -25,7 +25,8 @@ export { errorMessage, isRecord, PreviewPreparing } from './errors.ts'
25
25
  export { createEventBus } from './events.ts'
26
26
  export { CREDENTIAL_VARIABLE, environmentExecutor, failedRun, languageId } from './execution.ts'
27
27
  export { gitConfigArgs, gitEnvironment } from './git.ts'
28
- export { escapeHtml, htmlAttributes, mapHtmlUrls, URL_ATTRIBUTES } from './html.ts'
28
+ export { escapeHtml } from './escape-html.ts'
29
+ export { htmlAttributes, mapHtmlUrls, URL_ATTRIBUTES } from './html.ts'
29
30
  export type { HtmlAttribute } from './html.ts'
30
31
  export { hostName, localRequestRefusal } from './requests.ts'
31
32
  export type { RequestHeaders } from './requests.ts'
@@ -39,9 +40,13 @@ export type { KernelOptions } from './kernel.ts'
39
40
  export { deckLocale, localeOf } from './locale.ts'
40
41
  export { ANCHOR_LOCK_PATH, AnchorLock } from './lock.ts'
41
42
  export { prefixedLogger } from './logging.ts'
42
- export { lowerMyst, roleMark } from './lower-myst.ts'
43
+ export { lowerMyst } from './lower-myst.ts'
43
44
  export type { LinkedType, LoweredMarkdown, LowerOptions } from './lower-myst.ts'
44
- export { connectPreviewFrame, isPreviewActive, isPreviewEmbedded, previewAppearance, previewFrameAncestors, reportPreview, reportStaleModule } from './preview-frame.ts'
45
+ export { isPreviewActive, isPreviewEmbedded, previewAppearance, reportPreview, siteFrameAncestors } from './preview-frame.ts'
46
+ export { connectPreviewFrame } from './preview-frame-connect.ts'
47
+ export { reportStaleModule, STALE_MODULE_EVENT, STALE_MODULE_PATTERN } from './stale-module.ts'
48
+ export { EMBED_MESSAGE, notifyEmbedder } from './embed.ts'
49
+ export type { EmbeddedLecture, EmbedState } from './embed.ts'
45
50
  export { keyBelongsToTarget, watchFocusSource } from './keyboard.ts'
46
51
  export type { PreviewFrame, PreviewPage, PreviewProblem, PreviewTextEdit, PreviewTextHandle } from './preview-frame.ts'
47
52
  export { previewEditBinding } from './preview-edit.ts'
@@ -65,7 +70,7 @@ export type { StepKeys } from './step-keys.ts'
65
70
  export { parseDuration } from './durations.ts'
66
71
  export { stepStateAt } from './steps.ts'
67
72
  export { ABSOLUTE_URL, NON_FILE_URL, urlSlug } from './urls.ts'
68
- export { isButton } from './lower-myst.ts'
73
+ export { isButton, roleMark } from './myst-marks.ts'
69
74
  export { componentProps, findComponentRenderer, hasRendererExtension, WEB_RENDERER_PACKAGE, withPublishedAssets } from './renderer-components.ts'
70
75
  export { htmlAsText, isProseRun } from './run-outputs.ts'
71
76
  export { safeDecodeURIComponent } from './uri-decoding.ts'
package/src/ir.ts CHANGED
@@ -326,11 +326,23 @@ export interface SiteDocument {
326
326
  description?: string
327
327
  lang?: string
328
328
  tags?: string[]
329
+ /** Whether it has a presentation, before its IR is compiled (`DocumentSummary.slides`). */
330
+ slides?: boolean
329
331
  doc?: IRDocument
330
332
  translations?: { lang: string, doc: IRDocument }[]
331
333
  nodeVitePlugins?: NodeVitePlugin[]
332
334
  }
333
335
 
336
+ /**
337
+ * A built site keeps its viewer apps below its path, each at `<APP_DIR>/<key>/` by its content. A presentation built as
338
+ * part of a site (renderer option `appBase`, the site's path) names its app there, so the site's pages and all its
339
+ * presentations load one app.
340
+ */
341
+ export const APP_DIR = '_app'
342
+
343
+ /** A site serves a document's presentation (`renderers.slides`) below the document's pages, at `<document>/<SLIDES_DIR>/`. */
344
+ export const SLIDES_DIR = 'slides'
345
+
334
346
  export interface SiteSpec {
335
347
  title: string
336
348
  documents: SiteDocument[]
package/src/lower-myst.ts CHANGED
@@ -1,4 +1,6 @@
1
- import { escapeHtml as escape, mapHtmlUrls } from './html.ts'
1
+ import { escapeHtml as escape } from './escape-html.ts'
2
+ import { mapHtmlUrls } from './html.ts'
3
+ import { isButton, roleMark } from './myst-marks.ts'
2
4
  import type { MdastNode } from './ir.ts'
3
5
 
4
6
  export type LinkedType = 'image' | 'link' | 'definition'
@@ -198,11 +200,6 @@ function cardsAs(options: LowerOptions): 'element' | 'headings' {
198
200
  return options.cards ?? (options.iframes === 'element' ? 'element' : 'headings')
199
201
  }
200
202
 
201
- /** Whether a MyST node has the class `button`, which renders a link or span as a button. */
202
- export function isButton(node: MdastNode): boolean {
203
- return typeof node.class === 'string' && node.class.split(/\s+/).includes('button')
204
- }
205
-
206
203
  function layout(node: MdastNode, ctx: Lowering): MdastNode[] {
207
204
  const all = (nodes: MdastNode[] = []) => nodes.flatMap(child => lower(child, ctx))
208
205
  const element = cardsAs(ctx.options) === 'element'
@@ -248,12 +245,6 @@ function layout(node: MdastNode, ctx: Lowering): MdastNode[] {
248
245
  return all(items)
249
246
  }
250
247
 
251
- export function roleMark(node: MdastNode): string {
252
- const options = typeof node.options === 'object' && node.options !== null ? node.options as Record<string, unknown> : {}
253
- const value = typeof options.value === 'string' ? options.value.trim() : ''
254
- return `〔${String(node.name ?? '')}${value ? ` ${value}` : ''}〕`
255
- }
256
-
257
248
  function footnoteNumber(node: MdastNode): string {
258
249
  return String(node.enumerator ?? node.label ?? node.identifier)
259
250
  }
@@ -0,0 +1,15 @@
1
+ import type { MdastNode } from './ir.ts'
2
+
3
+ // What a viewer reads from MyST nodes as they are, apart from their lowering (`lower-myst.ts`), which rewrites HTML.
4
+
5
+ /** Whether a MyST node has the class `button`, which renders a link or span as a button. */
6
+ export function isButton(node: MdastNode): boolean {
7
+ return typeof node.class === 'string' && node.class.split(/\s+/).includes('button')
8
+ }
9
+
10
+ /** The mark a role without content shows: its name and value. */
11
+ export function roleMark(node: MdastNode): string {
12
+ const options = typeof node.options === 'object' && node.options !== null ? node.options as Record<string, unknown> : {}
13
+ const value = typeof options.value === 'string' ? options.value.trim() : ''
14
+ return `〔${String(node.name ?? '')}${value ? ` ${value}` : ''}〕`
15
+ }