Skip to content

Commit

Permalink
feat(pkg::compiler): support sys.inputs (#595)
Browse files Browse the repository at this point in the history
  • Loading branch information
Myriad-Dreamin authored Oct 19, 2024
1 parent 3382633 commit 3e3c088
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 29 deletions.
54 changes: 40 additions & 14 deletions packages/compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use reflexo_typst::package::browser::ProxyRegistry;
use reflexo_typst::parser::OffsetEncoding;
use reflexo_typst::typst::{foundations::IntoValue, prelude::EcoVec};
use reflexo_typst::vfs::browser::ProxyAccessModel;
use typst::diag::SourceResult;
use wasm_bindgen::prelude::*;

use crate::{incr::IncrServer, utils::console_log};
Expand Down Expand Up @@ -329,16 +330,34 @@ impl TypstCompiler {
})
}

pub fn set_compiler_options(
&mut self,
main_file_path: String,
inputs: Option<Vec<js_sys::Array>>,
) -> Result<(), JsValue> {
self.driver
.universe
.increment_revision(|verse| -> SourceResult<()> {
verse.set_entry_file(Path::new(&main_file_path).into())?;

if let Some(inputs) = inputs {
verse.set_inputs(Arc::new(LazyHash::new(convert_inputs(&inputs))));
}

Ok(())
})
.map_err(|e| format!("{e:?}"))?;
Ok(())
}

pub fn query(
&mut self,
main_file_path: String,
inputs: Option<Vec<js_sys::Array>>,
selector: String,
field: Option<String>,
) -> Result<String, JsValue> {
self.driver
.universe_mut()
.increment_revision(|verse| verse.set_entry_file(Path::new(&main_file_path).into()))
.map_err(|e| format!("{e:?}"))?;
self.set_compiler_options(main_file_path, inputs)?;

let doc = self
.driver
Expand All @@ -363,14 +382,11 @@ impl TypstCompiler {
pub fn compile(
&mut self,
main_file_path: String,
inputs: Option<Vec<js_sys::Array>>,
fmt: String,
diagnostics_format: u8,
) -> Result<JsValue, JsValue> {
self.driver
.universe
.increment_revision(|verse| verse.set_entry_file(Path::new(&main_file_path).into()))
.map_err(|e| format!("{e:?}"))?;

self.set_compiler_options(main_file_path, inputs)?;
self.get_artifact(fmt, diagnostics_format)
}

Expand All @@ -381,14 +397,11 @@ impl TypstCompiler {
pub fn incr_compile(
&mut self,
main_file_path: String,
inputs: Option<Vec<js_sys::Array>>,
state: &mut IncrServer,
diagnostics_format: u8,
) -> Result<JsValue, JsValue> {
self.driver
.universe
.increment_revision(|verse| verse.set_entry_file(Path::new(&main_file_path).into()))
.map_err(|e| format!("{e:?}"))?;

self.set_compiler_options(main_file_path, inputs)?;
let world = self.driver.snapshot();
let doc = take_diag!(
diagnostics_format,
Expand All @@ -407,6 +420,19 @@ impl TypstCompiler {
}
}

// Convert the input pairs to a dictionary.
fn convert_inputs(inputs: &[js_sys::Array]) -> typst::foundations::Dict {
inputs
.iter()
.map(|j| {
(
j.get(0).as_string().unwrap_or_default().into(),
j.get(1).as_string().into_value(),
)
})
.collect()
}

#[cfg(test)]
#[cfg(target_arch = "wasm32")]
mod tests {
Expand Down
60 changes: 48 additions & 12 deletions packages/typst.ts/src/compiler.mts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,27 @@ export type DiagnosticsData = {
full: DiagnosticMessage;
};

interface TransientCompileOptions<
F extends CompileFormat = any,
Diagnostics extends DiagnosticsFormat = DiagnosticsFormat,
> {
interface CompileOptionsCommon {
/**
* The path of the main file.
*/
mainFilePath: string;
/**
* Adds a string key-value pair visible through `sys.inputs`
*
* Note: pass `{}` to clear `sys.inputs`
*
* Note: When passing `undefined`, compiler will use last set `sys.inputs`.
*
* Note: This means you should always specify inputs when using compiler for concurrent tasks.
*/
inputs?: Record<string, string>;
}

interface TransientCompileOptions<
F extends CompileFormat = any,
Diagnostics extends DiagnosticsFormat = DiagnosticsFormat,
> extends CompileOptionsCommon {
/**
* The format of the artifact.
* - 'vector': can then load to the renderer to render the document.
Expand All @@ -79,11 +92,8 @@ interface TransientCompileOptions<
diagnostics: Diagnostics;
}

interface IncrementalCompileOptions<Diagnostics extends DiagnosticsFormat = DiagnosticsFormat> {
/**
* The path of the main file.
*/
mainFilePath: string;
interface IncrementalCompileOptions<Diagnostics extends DiagnosticsFormat = DiagnosticsFormat>
extends CompileOptionsCommon {
/**
* The format of the incrementally exported artifact.
* @default 'vector'
Expand All @@ -102,6 +112,17 @@ interface IncrementalCompileOptions<Diagnostics extends DiagnosticsFormat = Diag
diagnostics: Diagnostics;
}

export interface QueryOptions extends CompileOptionsCommon {
/**
* select part of document for query.
*/
selector: string;
/**
* cast result by accessing single field.
*/
field?: string;
}

/**
* The options for compiling the document.
*/
Expand Down Expand Up @@ -193,7 +214,7 @@ export interface TypstCompiler {
* experimental
* Query the result with document
*/
query<T>(options: { mainFilePath: string; selector: string; field?: string }): Promise<T>;
query<T>(options: QueryOptions): Promise<T>;

/**
* Print the AST of the main file.
Expand Down Expand Up @@ -325,6 +346,7 @@ class TypstCompilerDriver {
resolve(
this.compiler.incr_compile(
options.mainFilePath,
convertInputs(options.inputs),
options.incrementalServer[kObject],
getDiagnosticsArg(options.diagnostics),
),
Expand All @@ -334,17 +356,25 @@ class TypstCompilerDriver {
resolve(
this.compiler.compile(
options.mainFilePath,
convertInputs(options.inputs),
options.format || 'vector',
getDiagnosticsArg(options.diagnostics),
),
);
});
}

query(options: { mainFilePath: string; selector: string; field?: string }): Promise<any> {
query(options: QueryOptions): Promise<any> {
return new Promise<any>(resolve => {
resolve(
JSON.parse(this.compiler.query(options.mainFilePath, options.selector, options.field)),
JSON.parse(
this.compiler.query(
options.mainFilePath,
convertInputs(options.inputs),
options.selector,
options.field,
),
),
);
});
}
Expand Down Expand Up @@ -418,6 +448,12 @@ class TypstCompilerDriver {
throw new Error('Please use the api TypstRenderer.renderToCanvas in v0.4.0');
}
}

// todo: caching inputs
function convertInputs(inputs?: Record<string, string>): [string, string][] | undefined {
return inputs ? Object.entries(inputs) : undefined;
}

function getDiagnosticsArg(diagnostics: string | undefined): number {
switch (diagnostics) {
case 'none':
Expand Down
21 changes: 18 additions & 3 deletions packages/typst.ts/src/contrib/snippet.mts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,23 @@ import { randstr } from '../utils.mjs';
*/
type PromiseJust<T> = (() => Promise<T>) | T;

interface CompileOptionsCommon {
/**
* Adds a string key-value pair visible through `sys.inputs`
*
* Note: pass `{}` to clear `sys.inputs`
*
* Note: When passing `undefined`, compiler will use last set `sys.inputs`.
*
* Note: This means you should always specify inputs when using compiler for concurrent tasks.
*/
inputs?: Record<string, string>;
}

/**
* The sweet options for compiling and rendering the document.
*/
export type SweetCompileOptions =
export type SweetCompileOptions = (
| {
/**
* The path of the main file.
Expand All @@ -38,7 +51,9 @@ export type SweetCompileOptions =
* The source content of the main file.
*/
mainContent: string;
};
}
) &
CompileOptionsCommon;

/**
* The sweet options for compiling and rendering the document.
Expand Down Expand Up @@ -466,7 +481,7 @@ export class TypstSnippet {
} else {
const destFile = `/tmp/${randstr()}.typ`;
await this.addSource(destFile, opts.mainContent);
return { mainFilePath: destFile, diagnostics: 'none' };
return { mainFilePath: destFile, inputs: opts.inputs, diagnostics: 'none' };
}
}

Expand Down

0 comments on commit 3e3c088

Please sign in to comment.