oxedyne/daimond/dev/probe_typstproj.mjs
3.7 KiB, 1 run
created by r2519314175:107, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | // probe_typstproj.mjs — establish, empirically, what the vendored compiler will accept. |
| 2 | // |
| 3 | // Not a verifier. Four questions had to be answered before any design could be |
| 4 | // written, and guessing at them is how the single-file bug got shipped: |
| 5 | // |
| 6 | // 1. Where is the compiler's project root? `compile()` takes no root argument, |
| 7 | // so the answer decides whether "/" is the root and shadow paths are |
| 8 | // root-relative. |
| 9 | // 2. Does a relative import that climbs (`../style/x.typ`) resolve against the |
| 10 | // IMPORTING file's directory, as it does on the CLI? |
| 11 | // 3. Does an absolute reference (`/assets/x.svg`) resolve against the root? |
| 12 | // 4. Does this build accept font bytes AFTER `build()` -- `TypstFontResolverBuilder` |
| 13 | // plus `TypstCompiler.set_fonts` -- and what does `get_font_info` report? |
| 14 | import { open } from './harness.mjs'; |
| 15 | |
| 16 | const s = await open({ name: 'typstprobe' }); |
| 17 | const p = s.page; |
| 18 | await p.waitForTimeout(1200); |
| 19 | await p.evaluate(async () => { |
| 20 | const mod = await import('../pkg/oxedyne_daimond.js'); |
| 21 | mod.set_locked_packs(''); |
| 22 | }); |
| 23 | |
| 24 | const out = await p.evaluate(async () => { |
| 25 | const VENDOR = new URL('/vendor/typst/', location.href); |
| 26 | const mod = await import(new URL('typst_ts_web_compiler.mjs', VENDOR).href); |
| 27 | await mod.default(new URL('typst_ts_web_compiler_bg.wasm', VENDOR)); |
| 28 | const b = new mod.TypstCompilerBuilder(); |
| 29 | b.set_dummy_access_model(); |
| 30 | const FONTS = ['LibertinusSerif-Regular.otf', 'LibertinusSerif-Bold.otf', |
| 31 | 'LibertinusSerif-Italic.otf', 'LibertinusSerif-BoldItalic.otf', 'NewCMMath-Regular.otf']; |
| 32 | const bytes = {}; |
| 33 | for (const n of FONTS) { |
| 34 | const r = await fetch(new URL('fonts/' + n, VENDOR)); |
| 35 | bytes[n] = new Uint8Array(await r.arrayBuffer()); |
| 36 | await b.add_raw_font(bytes[n]); |
| 37 | } |
| 38 | const c = await b.build(); |
| 39 | const res = {}; |
| 40 | |
| 41 | const run = (main) => { |
| 42 | try { |
| 43 | const r = c.compile(main, undefined, 'pdf', 3); |
| 44 | const pdf = r instanceof Uint8Array ? r : (r && (r.result || r.artifact)); |
| 45 | if (pdf && pdf.length > 4) return { bytes: pdf.length }; |
| 46 | return { err: JSON.stringify(r && r.diagnostics ? r.diagnostics : r).slice(0, 400) }; |
| 47 | } catch (e) { return { err: 'threw: ' + (e && e.message ? e.message : e) }; } |
| 48 | }; |
| 49 | |
| 50 | // Q1+Q2+Q3 in one document: main sits in a sub-directory, imports a sibling, |
| 51 | // climbs to a sibling directory, and names an asset absolutely. |
| 52 | c.reset_shadow(); |
| 53 | c.add_source('/book/main.typ', [ |
| 54 | '#import "tpl.typ": tag', |
| 55 | '#import "../style/glo.typ": glo', |
| 56 | '= #tag() #glo()', |
| 57 | '#include "chap01.typ"', |
| 58 | '#image("/assets/dot.svg", width: 10pt)', |
| 59 | ].join('\n')); |
| 60 | c.add_source('/book/tpl.typ', '#let tag() = [T]\n'); |
| 61 | c.add_source('/book/chap01.typ', '== Chapter one\n\nText.\n'); |
| 62 | c.add_source('/style/glo.typ', '#let glo() = [G]\n'); |
| 63 | c.map_shadow('/assets/dot.svg', new TextEncoder().encode( |
| 64 | '<svg xmlns="http://www.w3.org/2000/svg" width="4" height="4"><rect width="4" height="4"/></svg>')); |
| 65 | res.projectAtSlashRoot = run('/book/main.typ'); |
| 66 | |
| 67 | // The same, with the asset withheld: does it say something usable? |
| 68 | c.unmap_shadow('/assets/dot.svg'); |
| 69 | res.assetWithheld = run('/book/main.typ'); |
| 70 | |
| 71 | // Q4: fonts after build. |
| 72 | try { |
| 73 | const fb = new mod.TypstFontResolverBuilder(); |
| 74 | res.fontInfo = JSON.stringify(fb.get_font_info(bytes['LibertinusSerif-Regular.otf'])).slice(0, 600); |
| 75 | for (const n of FONTS) fb.add_raw_font(bytes[n]); |
| 76 | const rr = await fb.build(); |
| 77 | c.set_fonts(rr); |
| 78 | res.setFonts = 'ok'; |
| 79 | res.loaded = c.get_loaded_fonts().slice(0, 12); |
| 80 | } catch (e) { res.setFonts = 'threw: ' + (e && e.message ? e.message : e); } |
| 81 | |
| 82 | // And does a document naming an unknown font still compile (silent fallback)? |
| 83 | c.reset_shadow(); |
| 84 | c.add_source('/m.typ', '#set text(font: "Radley")\n= Hello\n'); |
| 85 | res.unknownFont = run('/m.typ'); |
| 86 | |
| 87 | return res; |
| 88 | }); |
| 89 | |
| 90 | console.log(JSON.stringify(out, null, 2)); |
| 91 | await s.close(); |