asc-hap 0.2.0

HarmonyOS package metadata for asc-rs: module.json, pack.info, pkgContextInfo.json and resources.index.
Documentation
//! HarmonyOS package metadata: the descriptors at the root of a HAP/HSP,
//! read from bytes the caller supplies (no zip or file IO here).
//!
//! - [`ModuleJson`]: `module.json`, the manifest. Abilities and extension
//!   abilities with their `exported` flag, required permissions, skills
//!   and deep-link URIs; requested and defined permissions.
//! - [`PackInfo`]: `pack.info`, the packing tool's digest of the bundle.
//! - [`PkgContextInfo`]: `pkgContextInfo.json`, the package table that
//!   `.abc` record names and import requests refer to.
//! - [`PageList`] and [`RouterMap`]: the page list and the navigation route
//!   table `module.json` names (`$profile:main_pages`, `$profile:router_map`).
//! - [`ResourceIndex`]: `resources.index`, the compiled resource table:
//!   what the ids in compiled `$r(...)` calls and the `$string:name`
//!   references of `module.json` stand for.
//! - [`SourceMaps`]: `ets/sourceMaps.map` of a debug build, from the lines of
//!   the compiled files the code was made from to the source.
//!
//! Every JSON type offers the same two texts: `summary()`, one fact per line
//! for `grep`, and `pretty()`, the document itself re-indented. The
//! summaries state what the documents say and pass no judgement.
//!
//! Parsing the JSON documents is tolerant: only input that is not a JSON object is an error.
//! A wrongly typed field is skipped and recorded in `notes`; a field the
//! model does not cover is listed in `unmodelled` and stays reachable
//! through `raw()`.
//!
//! ```
//! use asc_hap::ModuleJson;
//!
//! let manifest = ModuleJson::parse(
//!     br#"{"app": {"bundleName": "com.x.y"},
//!          "module": {"name": "entry", "abilities": [{
//!              "name": "EntryAbility", "exported": true, "srcEntry": "./ets/entryability/EntryAbility.ets",
//!              "skills": [{"actions": ["ohos.want.action.viewData"], "uris": [{"scheme": "xy", "host": "open"}]}]}]}}"#,
//! )?;
//! let ability = &manifest.module.abilities[0];
//! assert!(ability.is_exported());
//! assert_eq!(ability.deep_links(), ["xy://open"]);
//! assert!(manifest.summary().contains("deeplink EntryAbility xy://open\n"));
//! let records = manifest.record_names("./ets/entryability/EntryAbility.ets", None);
//! assert_eq!(records.candidates(), ["com.x.y/entry/ets/entryability/EntryAbility", "&entry/src/main/ets/entryability/EntryAbility&"]);
//! # Ok::<(), asc_hap::HapError>(())
//! ```

mod module;
mod pack;
mod pkg_context;
mod profile;
mod record;
mod resource;
mod source_map;
mod value;

pub use module::{
    Ability, AbilityKind, ApiVersion, App, AtomicService, DefinePermission, Dependency, Metadata, Module, ModuleJson, MultiAppMode,
    NameValue, ProxyData, RequestPermission, Skill, SkillUri, TestRunner,
};
pub use pack::{PackAbility, PackApp, PackExtension, PackForm, PackInfo, PackModule, PackPackage};
pub use pkg_context::{PkgContext, PkgContextInfo, RecordOwner};
pub use profile::{PageList, Route, RouterMap};
pub use record::RecordNames;
pub use resource::{
    Attr, IndexFormat, Qualifier, QualifierKey, Qualifiers, Resource, ResourceIndex, ResourceIndexError, ResourceRef, ResourceType,
    ResourceValue, Resources, UnknownResourceType,
};
pub use source_map::{ModuleMap, SourceLine, SourceMapError, SourceMaps};
pub use value::Note;

/// Why a metadata document could not be read at all.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum HapError {
    /// Not JSON: empty, truncated, malformed, or nested past
    /// `serde_json`'s recursion limit.
    #[error("invalid JSON: {0}")]
    Json(#[from] serde_json::Error),
    /// The document parsed but its root is an array, string or other non-object.
    #[error("expected a JSON object at the root, found {found}")]
    NotAnObject {
        /// JSON type of the root value.
        found: &'static str,
    },
}

fn join_lines(lines: &[String]) -> String {
    lines.iter().flat_map(|line| [line.as_str(), "\n"]).collect()
}

#[cfg(test)]
mod tests;