Multipart parsing, upload contracts, compatibility analysis, conformance suites, and regression baselines for MoonBit.
| 能力层 | MoonFormData | 现有 moon-multipart 公开定位 |
|---|---|---|
| 数据处理 | 有界内存请求体、结构化字段与文件模型 | Bytes、分块事件、流式 writer |
| 端点规则 | 命名 Schema、未知项策略、风险阈值、接受/拒绝决策 | RFC framing 与传输限制 |
| API 演进 | 契约版本差异、破坏性变更分级 | 未作为主要能力公开 |
| 回归治理 | 批量一致性套件、多端点目录、可保存基线、Markdown 报告 | 未作为主要能力公开 |
| 项目 | 状态 |
|---|---|
| 包名与版本 | ouoankang/moonformdata 0.1.0 |
| 主要语言 | 核心功能全部使用 MoonBit 实现 |
| 代码规模 | 9,000 行以上有效 MoonBit 代码 |
| 自动测试 | 112 个,覆盖解析、错误、边界、安全、契约和治理流程 |
| 回归语料 | 84 组项目自有合成 multipart fixture |
| 示例 | cmd/main、examples/basic、examples/governance |
| CI | 格式、零警告检查、构建、测试、JS 目标、接口漂移和示例 |
| 许可证 | Apache-2.0 |
moon add ouoankang/moonformdataimport {
"ouoankang/moonformdata" @moonformdata,
}let body =
"--demo\r\n" +
"Content-Disposition: form-data; name=\"title\"\r\n" +
"\r\n" +
"MoonFormData\r\n" +
"--demo--\r\n"
match @moonformdata.parse_multipart(body, "demo") {
Ok(form) => println(form.require_field("title").unwrap())
Err(err) => println(err.message())
}let schema = @moonformdata.strict_form_schema()
.add_field_rule(@moonformdata.required_field_rule("title"))
.add_file_rule(
@moonformdata.required_file_rule("upload")
.with_max_files(1)
.allow_content_type("text/plain")
.allow_extension("txt"),
)
let contract = @moonformdata.upload_contract(schema)
.with_max_risk(@moonformdata.LowRisk)
match @moonformdata.inspect_upload_request(request, contract) {
Ok(result) => println(result.decision_line())
Err(err) => println(err.message())
}let diff = @moonformdata.compare_upload_contracts(v1_contract, v2_contract)
println(diff.summary())
let suite = @moonformdata.run_conformance_suite("avatar-v2", v2_contract, cases)
let baseline = @moonformdata.conformance_baseline(suite)
println(baseline.to_text())moon run cmd/main
moon run examples/basic
moon run examples/governance| 分类 | 主要 API |
|---|---|
| 解析 | boundary_from_content_type, parse_multipart, parse_multipart_with_options, parse_multipart_request |
| 生成 | encode_multipart, encode_fields_and_files, build_upload_request |
| 查询 | field_value, field_values, files, require_field, require_file, summary |
| 安全 | safe_filename, sanitize_filename_with_policy, strict_filename_policy |
| 校验 | validate_form, validate_form_schema, field_rule, file_rule |
| 分析 | analyze_form, FormAnalysis::to_lines, form_content_type_counts |
| 上传契约 | upload_contract, inspect_upload, inspect_upload_request, UploadInspection::decision_line |
| 契约演进 | compare_upload_contracts, ContractDiff::has_breaking_changes, ContractDiff::to_markdown |
| 一致性套件 | upload_conformance_case, run_conformance_suite, ConformanceSuiteResult::to_markdown |
| 多端点目录 | upload_endpoint, upload_contract_catalog, inspect_route, run_catalog_conformance |
| 回归基线 | conformance_baseline, parse_conformance_baseline, compare_conformance_baseline |
moon fmt --check
moon check --deny-warn
moon build
moon test --deny-warn
moon check --target js
moon build --target js
moon test --target js
moon run cmd/main
moon run examples/basic
moon run examples/governance
moon info
moon package --listpub(all) struct BaselineChange {
impact : BaselineChangeImpact
kind : BaselineChangeKind
case_name : String
before : String
after : String
} derive(Eq, Debug)pub(all) struct BaselineDiff {
suite_name : String
changes : Array[BaselineChange]
} derive(Eq, Debug)pub(all) struct CatalogConformanceReport {
catalog_name : String
suites : Array[ConformanceSuiteResult]
issues : Array[String]
} derive(Eq, Debug)pub(all) struct CatalogInspection {
endpoint_id : String
endpoint_version : String
inspection : UploadInspection
} derive(Eq, Debug)pub(all) enum CatalogInspectionError {
CatalogRoutingError(CatalogError)
CatalogUploadError(MultipartError)
} derive(Eq, Debug)pub(all) struct ConformanceBaseline {
suite_name : String
entries : Array[ConformanceBaselineEntry]
} derive(Eq, Debug)pub(all) struct ConformanceBaselineEntry {
name : String
expectation : ConformanceExpectation
actual : ConformanceActual
passed : Bool
issue_codes : Array[String]
} derive(Eq, Debug)pub(all) struct ConformanceCaseResult {
name : String
expectation : ConformanceExpectation
actual : ConformanceActual
passed : Bool
issue_codes : Array[String]
details : Array[String]
} derive(Eq, Debug)pub(all) struct ConformanceSuiteResult {
name : String
cases : Array[ConformanceCaseResult]
} derive(Eq, Debug)fn ConformanceSuiteResult::failed_cases(self : ConformanceSuiteResult) -> Array[ConformanceCaseResult]pub(all) struct ContractChange {
impact : ContractChangeImpact
code : String
path : String
message : String
} derive(Eq, Debug)pub(all) struct EndpointConformancePlan {
endpoint_id : String
suite_name : String
cases : Array[UploadConformanceCase]
} derive(Eq, Debug)pub(all) struct FieldProfile {
name : String
values : Int
total_length : Int
max_length : Int
empty_values : Int
duplicated : Bool
size_class : BodySizeClass
} derive(Eq, Debug)pub(all) struct FileProfile {
name : String
filename : String
content_type : String
length : Int
empty : Bool
extension : String?
risk : UploadRisk
notes : Array[String]
size_class : BodySizeClass
} derive(Eq, Debug)pub(all) struct FormAnalysis {
summary : FormSummary
fields : Array[FieldProfile]
files : Array[FileProfile]
content_types : Array[NameCount]
headers : Array[HeaderProfile]
risk : UploadRisk
notes : Array[String]
} derive(Eq, Debug)fn FormBuilder::add_empty_file(self : FormBuilder, name : String, filename : String, content_type? : String) -> FormBuilderfn FormBuilder::add_file(self : FormBuilder, name : String, filename : String, body : String, content_type? : String) -> FormBuilderfn FormBuilder::with_boundary(self : FormBuilder, boundary : String) -> Result[FormBuilder, MultipartError]fn MultipartForm::require_field(self : MultipartForm, name : String) -> Result[String, MultipartError]fn MultipartForm::require_file(self : MultipartForm, name : String) -> Result[FormPart, MultipartError]pub(all) struct ParseAndValidateResult {
form : MultipartForm
report : ValidationReport
} derive(Eq, Debug)pub(all) struct UploadConformanceCase {
name : String
content_type : String
body : String
expectation : ConformanceExpectation
required_issue_codes : Array[String]
expected_risk : UploadRisk?
} derive(Eq, Debug)fn UploadConformanceCase::require_issue_code(self : UploadConformanceCase, code : String) -> UploadConformanceCasefn UploadConformanceCase::with_expected_risk(self : UploadConformanceCase, risk : UploadRisk) -> UploadConformanceCasepub(all) struct UploadContract {
parse_options : ParseOptions
schema : FormSchema
max_risk : UploadRisk
} derive(Eq, Debug)fn UploadContract::with_parse_options(self : UploadContract, parse_options : ParseOptions) -> UploadContractfn UploadContractCatalog::add(self : UploadContractCatalog, endpoint : UploadEndpoint) -> Result[UploadContractCatalog, CatalogError]fn UploadContractCatalog::find_route(self : UploadContractCatalog, http_method : String, path : String) -> UploadEndpoint?fn UploadContractCatalog::inspect_route(self : UploadContractCatalog, http_method : String, path : String, request : MultipartRequest) -> Result[CatalogInspection, CatalogInspectionError]pub(all) struct UploadEndpoint {
id : String
http_method : String
path : String
version : String
contract : UploadContract
} derive(Eq, Debug)pub(all) struct UploadInspection {
form : MultipartForm
validation : ValidationReport
analysis : FormAnalysis
max_risk : UploadRisk
decision : UploadDecision
} derive(Eq, Debug)pub(all) struct ValidationPolicy {
required_fields : Array[String]
required_files : Array[String]
allowed_file_content_types : Array[String]
max_text_length : Int
max_file_length : Int
max_filename_length : Int
allow_empty_files : Bool
allow_duplicate_fields : Bool
allow_duplicate_files : Bool
} derive(Eq, Debug)fn ValidationReport::issues_for_field(self : ValidationReport, name : String) -> Array[ValidationIssue]fn accept_upload_request(request : MultipartRequest, policy : ValidationPolicy) -> Result[String, MultipartError]fn build_request_from_fields(fields : Array[(String, String)], boundary? : String) -> Result[MultipartRequest, MultipartError]fn build_upload_request(fields : Array[(String, String)], files : Array[FileSpec], boundary? : String) -> Result[MultipartRequest, MultipartError]fn compare_conformance_baseline(previous : ConformanceBaseline, current : ConformanceSuiteResult) -> BaselineDifffn encode_fields(fields : Array[(String, String)], boundary? : String) -> Result[EncodedForm, MultipartError]fn encode_fields_and_files(fields : Array[(String, String)], files : Array[FileSpec], boundary? : String) -> Result[EncodedForm, MultipartError]fn encode_multipart(parts : Array[FormPart], boundary? : String) -> Result[EncodedForm, MultipartError]fn endpoint_conformance_plan(endpoint_id : String, suite_name : String, cases : Array[UploadConformanceCase]) -> EndpointConformancePlanfn filename_contains_path_separator(filename : String) -> Boolfn filename_has_extension(filename : String, extension : String) -> Boolfn filename_looks_like_windows_drive(filename : String) -> Boolfn inspect_upload(content_type : String, body : String, contract : UploadContract) -> Result[UploadInspection, MultipartError]fn inspect_upload_request(request : MultipartRequest, contract : UploadContract) -> Result[UploadInspection, MultipartError]fn is_multipart_form_data_content_type(header : String) -> Boolfn parse_and_validate_request(content_type : String, body : String, policy : ValidationPolicy) -> Result[ParseAndValidateResult, MultipartError]fn parse_and_validate_schema_request(content_type : String, body : String, schema : FormSchema) -> Result[ParseAndValidateResult, MultipartError]fn parse_multipart_request(content_type : String, body : String) -> Result[MultipartForm, MultipartError]fn parse_multipart_request_with_options(content_type : String, body : String, options : ParseOptions) -> Result[MultipartForm, MultipartError]fn parse_multipart_with_options(body : String, boundary : String, options : ParseOptions) -> Result[MultipartForm, MultipartError]fn part_add_header(part : FormPart, name : String, value : String) -> Result[FormPart, MultipartError]fn part_replace_header(part : FormPart, name : String, value : String) -> Result[FormPart, MultipartError]fn raw_upload_conformance_case(name : String, content_type : String, body : String, expectation : ConformanceExpectation) -> UploadConformanceCasefn run_catalog_conformance(catalog_name : String, catalog : UploadContractCatalog, plans : Array[EndpointConformancePlan]) -> CatalogConformanceReportfn run_conformance_suite(name : String, contract : UploadContract, cases : Array[UploadConformanceCase]) -> ConformanceSuiteResultfn safe_filename(filename : String) -> Stringfn set_header(headers : Array[(String, String)], name : String, value : String) -> Result[Array[(String, String)], MultipartError]fn upload_conformance_case(name : String, request : MultipartRequest, expectation : ConformanceExpectation) -> UploadConformanceCasefn upload_endpoint(id : String, http_method : String, path : String, version : String, contract : UploadContract) -> Result[UploadEndpoint, CatalogError]fn validate_upload_request(request : MultipartRequest, policy : ValidationPolicy) -> Result[ValidationReport, MultipartError]fn validation_issue(code : String, message : String, part_index? : Int, field_name? : String) -> ValidationIssuefn validation_policy_allow_file_type(policy : ValidationPolicy, content_type : String) -> ValidationPolicyMultipart parsing, upload contracts, compatibility analysis, conformance suites, and regression baselines for MoonBit.