moonjcamp

    JCAMP-DX spectral data interchange, checked ASDF decoding and offline validation for MoonBit

    jcamp-dx
    spectroscopy
    interchange
    validation
    Download zip
    Author
    Version
    0.1.0
    License
    MIT
    Last updated
    15 hours ago
    Downloads
    10

    No dependencies

    #MoonJCAMP

    JCAMP-DX spectral data interchange and validation in MoonBit.

    MoonJCAMP 0.1.0 reads, checks and rewrites one-dimensional real spectra. It implements JCAMP-DX label records, scaled XYDATA and explicit pairs, AFFN/PAC/SQZ/DIF/DUP numbers, DIF checkpoints, and nested LINK documents. It includes metadata audits, compound split/combine, versioned JSON and CSV exchange, bounded transformations, quality admission and semantic comparison.

    This is a scoped implementation, not complete JCAMP-DX certification, an instrument driver, a full NMR processor or a chemical-identification system. See the compatibility profile and related work.

    #Install And Use

    Requires MoonBit compiler 0.10.16 or newer. The core has no third-party runtime dependencies and is tested on JavaScript and wasm-gc. The filesystem CLI also requires Node.js 24. Python/NumPy are test-only dependencies.

    moon add zbhzs1/moonjcamp@0.1.0

    Add "zbhzs1/moonjcamp" @jcamp to your package's import block in moon.pkg. The runnable MoonBit example demonstrates reading, cropping, writing and checking a spectrum:

    let spectra = @jcamp.read_spectra(text)
    let selected = @jcamp.crop(spectra[0], 1001.0, 1002.0)
    let output = @jcamp.write_spectrum(selected)

    These functions raise @jcamp.JcampError; catch @jcamp.Invalid(diagnostic) to obtain its stable error code and source line. inspect, audit, handle_request and protocol instead return diagnostic results.

    For the CLI, clone this repository and build once:

    git clone https://github.com/zbhzs1/moonjcamp.git cd moonjcamp moon build --target js --release node bin/moonjcamp.mjs inspect examples/data/ir-compressed.jdx node bin/moonjcamp.mjs to-json examples/data/ir-compressed.jdx --out spectrum.json node bin/moonjcamp.mjs from-json spectrum.json --out normalized.jdx node bin/moonjcamp.mjs verify examples/data/ir-compressed.jdx normalized.jdx moon run examples/basic --target js

    Outputs are created exclusively: existing files are not overwritten. Exit codes are 0 for success, 1 for invalid data or rejected policy, and 2 for host I/O/usage failures. A split/CSV operation can leave partial new output files if the filesystem fails partway through; it does not provide a transaction. --protocol accepts bounded UTF-8 JSON on stdin and returns one result envelope.

    Three reproducible file workflows are in docs/workflows.md. Public API contracts and request examples are in docs/api.md.

    #Development

    MoonBit compiler 0.10.16 or later is required. The core uses only MoonBit's standard library. Node.js is the filesystem adapter for the portable CLI; Python is used only by independent tests.

    moon check --target js --deny-warn moon test --target js moon test --target wasm-gc moon build --target js --release node scripts/cli-test.mjs python -m pip install numpy==2.4.4 python scripts/interop.py node scripts/source-count.mjs

    #Scope And Sources

    The central task is standard file interchange: labels, data tables, compressed numeric streams, compound documents, and explicit diagnostics. General FFT, optical simulation, resampling, CSV conversion, and CLI wrappers are not claimed as novel algorithms. See docs/related.md.

    The CI checks formatting, strict type checking, building, JS/wasm-gc tests, both example targets, three complete CLI workflows, and a pinned independent Python reader/writer. Verification limits are in docs/verification.md.

    MIT licensed. Standards references, independent tools and external-data restrictions are listed in THIRD_PARTY.md.

    JcampError

    pub(all) suberror JcampError {
    Invalid(Diagnostic)
    } derive(
    Debug
    )

    AuditPolicy

    pub(all) struct AuditPolicy {
    require_origin : Bool
    require_owner : Bool
    check_extrema : Bool
    check_nmr_metadata : Bool
    max_diagnostics : Int
    } derive(ToJson,
    Debug
    )

    AuditPolicy::default

    fn AuditPolicy::default() -> AuditPolicy

    AuditPolicy::to_json

    fn AuditPolicy::to_json(AuditPolicy) -> Json

    AuditReport

    pub(all) struct AuditReport {
    valid : Bool
    spectra : Int
    errors : Int
    warnings : Int
    truncated : Bool
    diagnostics : Array[Diagnostic]
    } derive(ToJson,
    Debug
    )

    AuditReport::to_json

    fn AuditReport::to_json(AuditReport) -> Json

    BatchInput

    pub(all) struct BatchInput {
    name : String
    text : String
    } derive(ToJson,
    Debug
    )

    BatchInput::to_json

    fn BatchInput::to_json(BatchInput) -> Json

    BatchItem

    pub(all) struct BatchItem {
    name : String
    accepted : Bool
    spectra : Array[Summary]
    diagnostics : Array[Diagnostic]
    } derive(ToJson,
    Debug
    )

    BatchItem::to_json

    fn BatchItem::to_json(BatchItem) -> Json

    BatchReport

    pub(all) struct BatchReport {
    accepted : Int
    rejected : Int
    items : Array[BatchItem]
    } derive(ToJson,
    Debug
    )

    BatchReport::to_json

    fn BatchReport::to_json(BatchReport) -> Json

    Block

    pub(all) struct Block {
    records : Array[Record]
    tables : Array[DataTable]
    children : Array[Block]
    start_line : Int
    end_line : Int
    } derive(ToJson,
    Debug
    )

    Block::to_json

    fn Block::to_json(Block) -> Json

    Block::to_repr

    Comparison

    pub(all) struct Comparison {
    equivalent : Bool
    compared_points : Int
    issue_count : Int
    truncated : Bool
    issues : Array[ComparisonIssue]
    } derive(ToJson,
    Debug
    )

    Comparison::to_json

    fn Comparison::to_json(Comparison) -> Json

    ComparisonIssue

    pub(all) struct ComparisonIssue {
    code : String
    message : String
    spectrum : Int
    point : Int
    } derive(ToJson,
    Debug
    )

    ComparisonIssue::to_json

    CsvBundle

    pub(all) struct CsvBundle {
    csv : String
    metadata : Json
    } derive(ToJson,
    Debug
    )

    CsvBundle::to_json

    fn CsvBundle::to_json(CsvBundle) -> Json

    DataLine

    pub(all) struct DataLine {
    text : String
    line : Int
    } derive(Eq, ToJson,
    Debug
    )

    DataLine::equal

    fn DataLine::equal(DataLine, DataLine) -> Bool

    DataLine::not_equal

    fn DataLine::not_equal(x : DataLine, y : DataLine) -> Bool

    DataLine::to_json

    fn DataLine::to_json(DataLine) -> Json

    DataLine::to_repr

    DataTable

    pub(all) struct DataTable {
    label : String
    descriptor : String
    rows : Array[DataLine]
    line : Int
    } derive(Eq, ToJson,
    Debug
    )

    DataTable::equal

    fn DataTable::equal(DataTable, DataTable) -> Bool

    DataTable::not_equal

    fn DataTable::not_equal(x : DataTable, y : DataTable) -> Bool

    DataTable::to_json

    fn DataTable::to_json(DataTable) -> Json

    Diagnostic

    pub(all) struct Diagnostic {
    severity : Severity
    code : String
    message : String
    line : Int
    column : Int
    } derive(Eq, ToJson,
    Debug
    )

    Diagnostic::equal

    fn Diagnostic::equal(Diagnostic, Diagnostic) -> Bool

    Diagnostic::not_equal

    fn Diagnostic::not_equal(x : Diagnostic, y : Diagnostic) -> Bool

    Diagnostic::to_json

    fn Diagnostic::to_json(Diagnostic) -> Json

    Document

    pub(all) struct Document {
    blocks : Array[Block]
    } derive(ToJson,
    Debug
    )

    Document::to_json

    fn Document::to_json(Document) -> Json

    Document::to_repr

    Encoding

    pub(all) enum Encoding {
    Plain
    Packed
    Squeezed
    Difference
    } derive(Eq, ToJson,
    Debug
    )

    Encoding::equal

    fn Encoding::equal(Encoding, Encoding) -> Bool

    Encoding::not_equal

    fn Encoding::not_equal(x : Encoding, y : Encoding) -> Bool

    Encoding::to_json

    fn Encoding::to_json(Encoding) -> Json

    Encoding::to_repr

    Limits

    pub(all) struct Limits {
    max_chars : Int
    max_lines : Int
    max_line_chars : Int
    max_records : Int
    max_blocks : Int
    max_depth : Int
    max_points : Int
    max_tokens_per_line : Int
    } derive(Eq, ToJson,
    Debug
    )

    Limits::default

    fn Limits::default() -> Limits

    Limits::equal

    fn Limits::equal(Limits, Limits) -> Bool

    Limits::not_equal

    fn Limits::not_equal(x : Limits, y : Limits) -> Bool

    Limits::to_json

    fn Limits::to_json(Limits) -> Json

    Limits::to_repr

    MetadataEdit

    pub(all) enum MetadataEdit {
    Set(String, String)
    Remove(String)
    } derive(
    Debug
    )

    NumericMode

    pub(all) enum NumericMode {
    Auto
    Affn
    Asdf
    } derive(Eq, ToJson,
    Debug
    )

    NumericMode::equal

    fn NumericMode::equal(NumericMode, NumericMode) -> Bool

    NumericMode::not_equal

    fn NumericMode::not_equal(x : NumericMode, y : NumericMode) -> Bool

    NumericMode::to_json

    fn NumericMode::to_json(NumericMode) -> Json

    ParseOptions

    pub(all) struct ParseOptions {
    limits : Limits
    numeric_mode : NumericMode
    relative_tolerance : Double
    absolute_tolerance : Double
    } derive(ToJson,
    Debug
    )

    ParseOptions::default

    fn ParseOptions::default() -> ParseOptions

    ParseOptions::to_json

    Point

    pub(all) struct Point {
    x : Double
    y : Double?
    } derive(Eq,
    Debug
    ,
    FromJson
    )

    impl ToJson for Point

    Point::equal

    fn Point::equal(Point, Point) -> Bool

    Point::not_equal

    fn Point::not_equal(x : Point, y : Point) -> Bool

    Point::to_json

    fn Point::to_json(self : Point) -> Json

    Point::to_repr

    QualityPolicy

    pub(all) struct QualityPolicy {
    max_missing_fraction : Double
    require_monotone : Bool
    require_uniform : Bool
    min_points : Int
    } derive(ToJson,
    Debug
    )

    QualityPolicy::default

    fn QualityPolicy::default() -> QualityPolicy

    QualityPolicy::to_json

    Record

    pub(all) struct Record {
    label : String
    value : String
    line : Int
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Record::equal

    fn Record::equal(Record, Record) -> Bool

    Record::not_equal

    fn Record::not_equal(x : Record, y : Record) -> Bool

    Record::to_json

    fn Record::to_json(Record) -> Json

    Record::to_repr

    Report

    pub(all) struct Report {
    valid : Bool
    spectra : Int
    points : Int
    missing : Int
    diagnostics : Array[Diagnostic]
    } derive(ToJson,
    Debug
    )

    Report::to_json

    fn Report::to_json(Report) -> Json

    Report::to_repr

    Severity

    pub(all) enum Severity {
    Error
    Warning
    } derive(Eq, ToJson,
    Debug
    )

    Severity::equal

    fn Severity::equal(Severity, Severity) -> Bool

    Severity::not_equal

    fn Severity::not_equal(x : Severity, y : Severity) -> Bool

    Severity::to_json

    fn Severity::to_json(Severity) -> Json

    Severity::to_repr

    Spectrum

    pub(all) struct Spectrum {
    title : String
    data_type : String
    x_units : String
    y_units : String
    points : Array[Point]
    records : Array[Record]
    source_line : Int
    } derive(ToJson,
    Debug
    ,
    FromJson
    )

    Summary

    pub(all) struct Summary {
    title : String
    points : Int
    missing : Int
    x_min : Double
    x_max : Double
    y_min : Double?
    y_max : Double?
    y_mean : Double?
    direction : Int
    uniform : Bool
    longest_missing_run : Int
    diagnostics : Array[Diagnostic]
    accepted : Bool
    } derive(ToJson,
    Debug
    )

    Summary::to_json

    fn Summary::to_json(Summary) -> Json

    Summary::to_repr

    TableStyle

    pub(all) enum TableStyle {
    Automatic
    Incremental
    Pairs
    } derive(Eq, ToJson,
    Debug
    )

    TableStyle::equal

    fn TableStyle::equal(TableStyle, TableStyle) -> Bool

    TableStyle::not_equal

    fn TableStyle::not_equal(x : TableStyle, y : TableStyle) -> Bool

    TableStyle::to_json

    fn TableStyle::to_json(TableStyle) -> Json

    WriteOptions

    pub(all) struct WriteOptions {
    encoding : Encoding
    table_style : TableStyle
    points_per_line : Int
    x_factor : Double
    y_factor : Double
    } derive(ToJson,
    Debug
    )

    WriteOptions::default

    fn WriteOptions::default() -> WriteOptions

    WriteOptions::to_json

    audit

    fn audit(text : String, policy? : AuditPolicy, options? : ParseOptions) -> AuditReport

    audit_document

    fn audit_document(document : Document, policy? : AuditPolicy, options? : ParseOptions) -> AuditReport raise JcampError

    block_kind

    fn block_kind(block : Block) -> String

    block_title

    fn block_title(block : Block) -> String

    canonical_label

    fn canonical_label(label : String) -> String

    combine_documents

    fn combine_documents(documents : Array[Document], title? : String, read_options? : ParseOptions) -> Document raise JcampError

    compare_documents

    fn compare_documents(left : String, right : String, options? : ParseOptions, compare_records? : Bool, max_issues? : Int) -> Comparison raise JcampError

    compare_spectra

    fn compare_spectra(left : Array[Spectrum], right : Array[Spectrum], options? : ParseOptions, compare_records? : Bool, max_issues? : Int) -> Comparison raise JcampError

    convert_x

    fn convert_x(spectrum : Spectrum, target : String) -> Spectrum raise JcampError

    convert_y

    fn convert_y(spectrum : Spectrum, target : String) -> Spectrum raise JcampError

    crop

    fn crop(spectrum : Spectrum, minimum : Double, maximum : Double) -> Spectrum raise JcampError

    decode_numbers

    fn decode_numbers(text : String, mode? : NumericMode, max_values? : Int) -> Array[Double?] raise JcampError

    document_block_count

    fn document_block_count(document : Document, max_depth? : Int) -> Int raise JcampError

    edit_metadata

    fn edit_metadata(spectrum : Spectrum, edits : Array[MetadataEdit]) -> Spectrum raise JcampError

    export_csv

    fn export_csv(spectrum : Spectrum) -> CsvBundle raise JcampError

    export_json

    fn export_json(spectra : Array[Spectrum]) -> Json raise JcampError

    handle_request

    fn handle_request(request : Json) -> Json

    import_csv

    fn import_csv(text : String, metadata : Json) -> Spectrum raise JcampError

    import_json

    fn import_json(value : Json) -> Array[Spectrum] raise JcampError

    inspect

    fn inspect(text : String, options? : ParseOptions) -> Report

    inspect_batch

    fn inspect_batch(inputs : Array[BatchInput], policy? : QualityPolicy, options? : ParseOptions) -> BatchReport raise JcampError

    parse_csv

    fn parse_csv(text : String) -> Array[Array[String]] raise JcampError

    parse_document

    fn parse_document(text : String, options? : ParseOptions) -> Document raise JcampError

    parse_interchange

    fn parse_interchange(text : String) -> Array[Spectrum] raise JcampError

    protocol

    fn protocol(text : String) -> String

    read_spectra

    fn read_spectra(text : String, options? : ParseOptions) -> Array[Spectrum] raise JcampError

    record_value

    fn record_value(records : Array[Record], label : String) -> String?

    render_document

    fn render_document(document : Document, read_options? : ParseOptions) -> String raise JcampError

    resample

    fn resample(spectrum : Spectrum, start : Double, end : Double, count : Int) -> Spectrum raise JcampError

    rewrite_document

    fn rewrite_document(document : Document, options? : WriteOptions, read_options? : ParseOptions) -> String raise JcampError

    set_record

    fn set_record(records : Array[Record], label : String, value : String) -> Array[Record]

    spectra_from_document

    fn spectra_from_document(document : Document, options? : ParseOptions) -> Array[Spectrum] raise JcampError

    spectrum_from_block

    fn spectrum_from_block(block : Block, options? : ParseOptions) -> Spectrum raise JcampError

    spectrum_from_json

    fn spectrum_from_json(value : Json) -> Spectrum raise JcampError

    split_document

    fn split_document(document : Document, read_options? : ParseOptions) -> Array[Document] raise JcampError

    summarize

    fn summarize(spectrum : Spectrum, policy? : QualityPolicy) -> Summary raise JcampError

    write_collection

    fn write_collection(spectra : Array[Spectrum], title? : String, options? : WriteOptions) -> String raise JcampError

    write_spectrum

    fn write_spectrum(spectrum : Spectrum, options? : WriteOptions) -> String raise JcampError

    Powered by MoonBit

    Site sourceReport issueModulesSkillsBuild queueStatistics

    © 2026 mooncakes.io