@shundoo-ai/dsh-cosmic 1.0.19 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cordis.patch.yml +5 -5
- package/package.json +1 -1
- package/skills/cosmic-build/CHANGELOG.md +4 -0
- package/skills/cosmic-build/LOCAL-PATCHES.md +91 -40
- package/skills/cosmic-build/SKILL.md +46 -13
- package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +169 -0
- package/skills/cosmic-build/assets/platform-report-filters/platform.patch +98 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportAlgoBenchmark.java +48 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportBenchmarkLogFactory.java +7 -0
- package/skills/cosmic-build/examples/java-rules/CosmicEntryQuery.java +26 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +35 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +77 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapter.java +25 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapterCheck.java +26 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/algo/GroupbyDataSet.md +47 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterInfo.md +12 -12
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterItemInfo.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +2 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/java-type-contracts.md +11 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +18 -14
- package/skills/cosmic-build/knowledge/cosmic/platform/operation-plugin.md +4 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +17 -9
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/cross-entity-aggregate-writeback.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/pre-post-operation.md +15 -7
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +24 -68
- package/skills/cosmic-build/knowledge/cosmic/platform/workflow-plugin.md +2 -7
- package/skills/cosmic-build/references/application-context.md +35 -1
- package/skills/cosmic-build/references/common-reference.md +1 -1
- package/skills/cosmic-build/references/compile-guide.md +55 -68
- package/skills/cosmic-build/references/delivery.md +59 -7
- package/skills/cosmic-build/references/execution-contract.md +38 -0
- package/skills/cosmic-build/references/form-discovery.md +7 -1
- package/skills/cosmic-build/references/java-plugin-delivery.md +32 -162
- package/skills/cosmic-build/references/operation-dispatch.md +17 -0
- package/skills/cosmic-build/references/plugin-handoff-input.md +131 -0
- package/skills/cosmic-build/references/plugin-runtime-routing.md +1 -1
- package/skills/cosmic-build/references/report-filter-contract.md +78 -0
- package/skills/cosmic-build/references/sdk-inspection.md +23 -0
- package/skills/cosmic-build/schemas/data-model-authoring.schema.json +2 -3
- package/skills/cosmic-build/scripts/_http_client.py +55 -55
- package/skills/cosmic-build/scripts/appconfig_load.py +2 -2
- package/skills/cosmic-build/scripts/apply_report_filter_extension.py +39 -0
- package/skills/cosmic-build/scripts/bootstrap_cosmic_context.py +37 -2
- package/skills/cosmic-build/scripts/compile_plugin_source.py +279 -156
- package/skills/cosmic-build/scripts/execution_binding.py +40 -0
- package/skills/cosmic-build/scripts/inspect_platform_sdk.py +169 -0
- package/skills/cosmic-build/scripts/kd_api.py +23 -22
- package/skills/cosmic-build/scripts/kd_auth.py +1 -1
- package/skills/cosmic-build/scripts/kd_env_loader.py +19 -10
- package/skills/cosmic-build/scripts/kd_token_cache.py +2 -2
- package/skills/cosmic-build/scripts/kingscript_sdk_sync.py +350 -0
- package/skills/cosmic-build/scripts/kingscript_source_gate.py +11 -8
- package/skills/cosmic-build/scripts/platform_api_contract.py +246 -11
- package/skills/cosmic-build/scripts/plugin_corpus/build_index.py +403 -0
- package/skills/cosmic-build/scripts/plugin_corpus/jvm_classfile.py +281 -0
- package/skills/cosmic-build/scripts/plugin_corpus/measure_api_usage.py +446 -0
- package/skills/cosmic-build/scripts/plugin_source_gate.py +48 -7
- package/skills/cosmic-build/scripts/plugin_target_sdk.py +45 -0
- package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +493 -47
- package/skills/cosmic-build/scripts/preview_url.py +35 -6
- package/skills/cosmic-build/scripts/query_plugin_handoff.py +250 -0
- package/skills/cosmic-build/scripts/register_plugins.py +28 -2
- package/skills/cosmic-build/scripts/render_output_cards.py +42 -9
- package/skills/cosmic-build/scripts/report_algo_benchmark.py +46 -0
- package/skills/cosmic-build/scripts/run.py +2 -2
- package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +43 -0
- package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +64 -0
- package/skills/cosmic-build/scripts/test/fixtures/java_context_booking_native.json +541 -0
- package/skills/cosmic-build/scripts/test/test_add_rule_business_contract.py +85 -14
- package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +12 -3
- package/skills/cosmic-build/scripts/test/test_build_meta_order.py +0 -16
- package/skills/cosmic-build/scripts/test/test_cli_continuation.py +87 -0
- package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +224 -3
- package/skills/cosmic-build/scripts/test/test_control_authoring.py +123 -4
- package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +141 -0
- package/skills/cosmic-build/scripts/test/test_data_model_contract.py +30 -5
- package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +2 -10
- package/skills/cosmic-build/scripts/test/test_dym_sync_background.py +11 -0
- package/skills/cosmic-build/scripts/test/test_dynamic_form_metadata_only_contract.py +59 -1
- package/skills/cosmic-build/scripts/test/test_guide_skeleton_contract.py +87 -43
- package/skills/cosmic-build/scripts/test/test_inspect_platform_sdk.py +71 -0
- package/skills/cosmic-build/scripts/test/test_kd_api.py +67 -19
- package/skills/cosmic-build/scripts/test/test_kingscript_sdk_sync.py +221 -0
- package/skills/cosmic-build/scripts/test/test_kingscript_source_gate.py +10 -0
- package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +18 -0
- package/skills/cosmic-build/scripts/test/test_long_session_regressions.py +116 -0
- package/skills/cosmic-build/scripts/test/test_mcp_cli.py +524 -0
- package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +141 -0
- package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +36 -2
- package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +161 -1
- package/skills/cosmic-build/scripts/test/test_plugin_business_contract.py +91 -0
- package/skills/cosmic-build/scripts/test/test_plugin_corpus.py +195 -0
- package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +346 -1
- package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +70 -0
- package/skills/cosmic-build/scripts/test/test_preview_url.py +44 -1
- package/skills/cosmic-build/scripts/test/test_property_batch.py +22 -0
- package/skills/cosmic-build/scripts/test/test_property_input_discovery.py +13 -11
- package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +160 -0
- package/skills/cosmic-build/scripts/test/test_register_plugins.py +31 -1
- package/skills/cosmic-build/scripts/test/test_render_output_cards.py +50 -4
- package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -0
- package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +5 -4
- package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +36 -0
- package/skills/cosmic-build/scripts/test/test_rule_batch_evidence.py +1 -1
- package/skills/cosmic-build/scripts/test/test_rule_domain_contract.py +20 -0
- package/skills/cosmic-build/scripts/test/test_rule_function_formula.py +16 -6
- package/skills/cosmic-build/scripts/test/test_skill_entry_contract.py +1 -0
- package/skills/cosmic-build/scripts/test/test_test_environment.py +45 -0
- package/skills/cosmic-build/scripts/test/test_verify_plugin_loading.py +79 -0
- package/skills/cosmic-build/scripts/test_environment.py +49 -0
- package/skills/cosmic-build/scripts/verify_plugin_loading.py +71 -0
- package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +86 -162
- package/skills/cosmic-build/skills/cosmic-coding-script/ATTRIBUTION.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/SKILL.md +45 -14
- package/skills/cosmic-build/skills/cosmic-coding-script/references/kwc-controller-authoring.md +6 -0
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/README.md +29 -19
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/docs//350/204/232/346/234/254SDK.md +3 -4
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/indexes/package-index.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/strategy.md +27 -18
- package/skills/cosmic-build/skills/cosmic-meta-api/SKILL.md +11 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/app_menu.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/meta_log.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/control-authoring.json +45 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/form-control-traits.json +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/layout-ui.json +18 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/menu-publish.json +8 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-batch.json +7 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-input-index.json +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +37 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-event-contract.json +24 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/run-build-meta.json +61 -12
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/dropdown-menu.schema.json +69 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +2 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-set.schema.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-write.schema.json +14 -7
- package/skills/cosmic-build/skills/cosmic-meta-api/docs/api-summary.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/app-action/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/develop/SKILL.md +1 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/export/SKILL.md +5 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/init/SKILL.md +13 -36
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/SKILL.md +8 -9
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/config.json.example +5 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/reset/SKILL.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/usage/SKILL.md +20 -148
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/build_receipts.py +171 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +25 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_controls.py +55 -21
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_fields.py +10 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +63 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_forms.py +59 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +36 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_plugins.py +115 -90
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +666 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +1415 -87
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/commands.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +28 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +40 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +32 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_policy_contract.py +6 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +113 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/reset.py +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/rule_contract.py +107 -26
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/build_meta_order.py +50 -49
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +856 -150
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +47 -14
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +374 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_cli_failure_contract.py +24 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_creation_identity_boundary.py +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_dropdown_menu_contract.py +382 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_existing_form_ui.py +0 -25
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_field_decorator.py +50 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_functional_group_resolution.py +83 -16
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_identity_template_resolution.py +103 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +28 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +22 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +1041 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +17 -0
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/api-param-checklist.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/rule-modeling-guide.md +7 -4
- package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +61 -13
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/app-menu/SKILL.md +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/SKILL.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/dynamic-form-artifact-schema.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +21 -9
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-entity-graphs.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-storage-constraints.md +5 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-ui-composition.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/creation-recovery.md +13 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/parse-core.md +3 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +135 -87
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/field_type_registry.py +11 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/isv_resolver.py +1 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +29 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/context/SKILL.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/execute/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/SKILL.md +5 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/operation-write.md +6 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/validation.md +2 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/SKILL.md +20 -5
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/complex-apis.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/policy-grammar.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +9 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +61 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/raw-rule-authoring.md +3 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-actions.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-reference.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/state.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/unit/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +4 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/SKILL.md +9 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/modules/button/SKILL.md +3 -0
- package/skills/cosmic-build/skills/mcp-server/SKILL.md +210 -0
- package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +431 -0
- package/skills/cosmic-build/skills/openapi-gen/SKILL.md +3 -3
- package/skills/cosmic-build/skills/openapi-gen/scripts/api/gen_runner.py +2 -2
- package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +19 -9
- package/skills/cosmic-dev-best-practices/references/cosmic-meta-api.md +14 -11
- package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/AssistantField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/BasedataField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/BasedataPropField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/CreaterField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CurrencyField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/FlexField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/MaterielField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/OrgField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/UnitField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/UserField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +16 -11
- package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +5 -4
- package/skills/erp-analysis/references/delivery-contract.md +4 -2
- package/skills/erp-analysis/templates/AGENTS.template.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/.dsh/cosmic/.kd/config.json +0 -21
|
@@ -73,7 +73,7 @@ def test_every_screenshot_control_has_one_published_status() -> None:
|
|
|
73
73
|
assert not released & deferred
|
|
74
74
|
assert not specialized & deferred
|
|
75
75
|
assert released | specialized | deferred == SCREENSHOT_TYPES
|
|
76
|
-
assert len(released) ==
|
|
76
|
+
assert len(released) == 26
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
def test_aliases_compile_to_deterministic_keys_and_closed_properties() -> None:
|
|
@@ -104,6 +104,99 @@ def test_aliases_compile_to_deterministic_keys_and_closed_properties() -> None:
|
|
|
104
104
|
"parent": "基本信息",
|
|
105
105
|
"controls": [{"type": "按钮", "name": "普通按钮"}],
|
|
106
106
|
})["controls"][0]["type"] == "ButtonAp"
|
|
107
|
+
assert cmd_controls.validate_control_batch_input({
|
|
108
|
+
"parent": "uhyl_test09",
|
|
109
|
+
"controls": [{"type": "通用过滤", "name": "通用过滤"}],
|
|
110
|
+
})["controls"][0]["type"] == "FilterGridAp"
|
|
111
|
+
assert cmd_controls.validate_control_batch_input({
|
|
112
|
+
"parent": "uhyl_test09",
|
|
113
|
+
"controls": [{"type": "Common Filter", "name": "Common Filter"}],
|
|
114
|
+
})["controls"][0]["type"] == "FilterGridAp"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@pytest.mark.parametrize("locale", ["", ".locales/zh"])
|
|
118
|
+
def test_command_description_contains_complete_control_input(locale) -> None:
|
|
119
|
+
cli = ROOT / locale / "skills/cosmic-meta-api/scripts/cosmic_api.py"
|
|
120
|
+
completed = subprocess.run(
|
|
121
|
+
[sys.executable, str(cli), "--stdout", "describeCommand", "addControls"],
|
|
122
|
+
capture_output=True, text=True, check=True,
|
|
123
|
+
)
|
|
124
|
+
schema = json.loads(completed.stdout)["action"]["payloadSchema"]
|
|
125
|
+
|
|
126
|
+
assert schema["required"] == ["controls"]
|
|
127
|
+
assert schema["$defs"]["control"]["required"] == ["type", "name"]
|
|
128
|
+
assert schema["$defs"]["panel"]["required"] == ["name"]
|
|
129
|
+
assert "live form root" in schema["properties"]["parent"]["description"]
|
|
130
|
+
assert set(schema["x-controlTypes"]) == set(cmd_controls.control_catalog()["data"]["releasedTypes"])
|
|
131
|
+
assert "通用过滤" in schema["x-controlTypes"]["FilterGridAp"]["aliases"]
|
|
132
|
+
assert schema["x-commonProperties"]["width"]["type"] == "string"
|
|
133
|
+
assert schema["x-controlTypes"]["LabelAp"]["properties"]["autoTextWrap"]["type"] == "boolean"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.mark.parametrize("intent, missing_fields", [
|
|
137
|
+
({"panel": {}, "controls": [{}, {"type": "LabelAp"}]},
|
|
138
|
+
["controls[0].type", "controls[0].name", "controls[1].name", "panel.name"]),
|
|
139
|
+
({"panel": {}}, ["controls", "panel.name"]),
|
|
140
|
+
])
|
|
141
|
+
def test_cli_reports_all_missing_fields_before_authentication(intent, missing_fields) -> None:
|
|
142
|
+
completed = subprocess.run(
|
|
143
|
+
[sys.executable, str(CLI), "--stdout", "addControls", "--formNumber", "demo",
|
|
144
|
+
"--input", json.dumps(intent)],
|
|
145
|
+
capture_output=True, text=True, check=False,
|
|
146
|
+
)
|
|
147
|
+
result = json.loads(completed.stdout)
|
|
148
|
+
|
|
149
|
+
assert completed.returncode != 0
|
|
150
|
+
assert result["errorCode"] == "CONTROL_INPUT_INVALID"
|
|
151
|
+
assert result["recovery"]["missingFields"] == missing_fields
|
|
152
|
+
assert result["recovery"]["describeCommand"] == "describeCommand addControls"
|
|
153
|
+
assert "[auth]" not in completed.stderr
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@pytest.mark.parametrize("control_type", sorted(cmd_controls.control_catalog()["data"]["releasedTypes"]))
|
|
157
|
+
def test_default_root_creation_and_exact_key_retry(control_type) -> None:
|
|
158
|
+
before = _schema()
|
|
159
|
+
before["data"]["formLayout"]["children"].append({
|
|
160
|
+
"key": "manual_control", "name": "Control", "type": control_type,
|
|
161
|
+
})
|
|
162
|
+
after = json.loads(json.dumps(before))
|
|
163
|
+
after["data"]["formLayout"]["children"].append({
|
|
164
|
+
"key": "new_control", "name": "Control", "type": control_type,
|
|
165
|
+
})
|
|
166
|
+
intent = {"controls": [{"key": "new_control", "type": control_type, "name": "Control"}]}
|
|
167
|
+
with (
|
|
168
|
+
mock.patch.object(cmd_controls, "do_get_form_schema", side_effect=[before, after, after, after]) as reader,
|
|
169
|
+
mock.patch.object(cmd_controls, "do_modify_meta", return_value={"status": True}) as writer,
|
|
170
|
+
):
|
|
171
|
+
created = cmd_controls.do_add_controls({}, "token", "FORM-ID", "demo", intent)
|
|
172
|
+
retried = cmd_controls.do_add_controls({}, "token", "FORM-ID", "demo", intent)
|
|
173
|
+
|
|
174
|
+
writer.assert_called_once()
|
|
175
|
+
assert writer.call_args.args[3][0]["target"]["parentScope"] == "demo"
|
|
176
|
+
assert reader.call_count == 4
|
|
177
|
+
assert created["data"]["createdCount"] == 1
|
|
178
|
+
assert created["data"]["changed"] is True
|
|
179
|
+
assert retried["data"]["alreadyPresentCount"] == 1
|
|
180
|
+
assert retried["data"]["changed"] is False
|
|
181
|
+
assert created["verification"]["verified"] is True
|
|
182
|
+
assert retried["verification"]["verified"] is True
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@pytest.mark.parametrize("parent", [None, "unknown_container"])
|
|
186
|
+
def test_unresolved_parent_never_falls_back_to_another_container(parent) -> None:
|
|
187
|
+
before = _schema()
|
|
188
|
+
if parent is None:
|
|
189
|
+
before["data"]["formLayout"].pop("key")
|
|
190
|
+
with (
|
|
191
|
+
mock.patch.object(cmd_controls, "do_get_form_schema", return_value=before),
|
|
192
|
+
mock.patch.object(cmd_controls, "do_modify_meta") as writer,
|
|
193
|
+
):
|
|
194
|
+
with pytest.raises(ValueError, match="CONTROL_PARENT_UNRESOLVED"):
|
|
195
|
+
cmd_controls.do_add_controls({}, "token", "FORM-ID", "demo", {
|
|
196
|
+
**({"parent": parent} if parent is not None else {}),
|
|
197
|
+
"controls": [{"type": "LabelAp", "name": "Control"}],
|
|
198
|
+
})
|
|
199
|
+
writer.assert_not_called()
|
|
107
200
|
|
|
108
201
|
|
|
109
202
|
@pytest.mark.parametrize(
|
|
@@ -247,10 +340,35 @@ def test_existing_key_conflict_blocks_the_complete_batch() -> None:
|
|
|
247
340
|
writer.assert_not_called()
|
|
248
341
|
|
|
249
342
|
|
|
250
|
-
def
|
|
343
|
+
def test_common_filter_tile_uses_form_control_writer_not_list_filters() -> None:
|
|
344
|
+
before = {"status": True, "data": {"formLayout": {
|
|
345
|
+
"key": "uhyl_test09", "type": "FormAp", "name": "test09", "children": [],
|
|
346
|
+
}}}
|
|
347
|
+
after = {"status": True, "data": {"formLayout": {
|
|
348
|
+
"key": "uhyl_test09", "type": "FormAp", "name": "test09", "children": [
|
|
349
|
+
{"key": "ctl_filter", "type": "FilterGridAp", "name": "通用过滤"},
|
|
350
|
+
],
|
|
351
|
+
}}}
|
|
352
|
+
with (
|
|
353
|
+
mock.patch.object(cmd_controls, "do_get_form_schema", side_effect=[before, after]),
|
|
354
|
+
mock.patch.object(cmd_controls, "do_modify_meta", return_value={"status": True, "errorCode": "0"}) as writer,
|
|
355
|
+
):
|
|
356
|
+
result = cmd_controls.do_add_controls({}, "token", "FORM-ID", "uhyl_test09", {
|
|
357
|
+
"parent": "uhyl_test09",
|
|
358
|
+
"controls": [{"key": "ctl_filter", "type": "通用过滤", "name": "通用过滤"}],
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
assert result["verification"] == {"verified": True, "controlCount": 1}
|
|
362
|
+
operation = writer.call_args.args[3][0]
|
|
363
|
+
assert operation["target"]["parentScope"] == "uhyl_test09"
|
|
364
|
+
assert operation["value"]["controlType"] == "FilterGridAp"
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
@pytest.mark.parametrize("parent", [None, "Content"])
|
|
368
|
+
def test_titled_panel_and_palette_button_compile_as_one_verified_batch(parent) -> None:
|
|
251
369
|
before = _schema()
|
|
252
370
|
after = _schema()
|
|
253
|
-
content = after["data"]["formLayout"]["children"][0]
|
|
371
|
+
content = after["data"]["formLayout"] if parent is None else after["data"]["formLayout"]["children"][0]
|
|
254
372
|
content["children"].append({
|
|
255
373
|
"key": "panel_general", "name": "识别控件", "type": "FlexPanelAp",
|
|
256
374
|
"children": [
|
|
@@ -316,7 +434,7 @@ def test_titled_panel_and_palette_button_compile_as_one_verified_batch() -> None
|
|
|
316
434
|
{}, "token", "FORM-ID", "demo", {
|
|
317
435
|
"panel": {
|
|
318
436
|
"key": "panel_general", "name": "识别控件",
|
|
319
|
-
"parent":
|
|
437
|
+
**({"parent": parent} if parent is not None else {}),
|
|
320
438
|
},
|
|
321
439
|
"controls": [
|
|
322
440
|
{"key": "ctl_button", "type": "按钮", "name": "按钮"},
|
|
@@ -328,6 +446,7 @@ def test_titled_panel_and_palette_button_compile_as_one_verified_batch() -> None
|
|
|
328
446
|
assert result["status"] is True
|
|
329
447
|
assert result["verification"] == {"verified": True, "controlCount": 2}
|
|
330
448
|
assert result["data"]["panel"]["verified"] is True
|
|
449
|
+
assert result["data"]["panel"]["parent"] == ("demo" if parent is None else "contentpanel")
|
|
331
450
|
assert result["data"]["panel"]["presentation"] == "auto"
|
|
332
451
|
assert result["data"]["runtimeVerification"] == {
|
|
333
452
|
"performed": False,
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Compile the Cosmic SDK examples and run the time adapter's value assertions."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import shlex
|
|
6
|
+
import subprocess
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
EXAMPLE = Path(__file__).resolve().parents[2] / "examples" / "java-rules"
|
|
13
|
+
SDK_JAR = os.environ.get("COSMIC_SDK_DATAENTITY_JAR", "")
|
|
14
|
+
QUERY_CLASSPATH = os.environ.get("COSMIC_SDK_QUERY_CLASSPATH", "")
|
|
15
|
+
OPERATION_CLASSPATH = os.environ.get("COSMIC_SDK_OPERATION_CLASSPATH", "")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.skipif(not shutil.which("javac") or not shutil.which("java") or not Path(SDK_JAR).is_file(),
|
|
19
|
+
reason="target SDK JAR or JDK unavailable")
|
|
20
|
+
def test_cosmic_time_adapter_compiles_against_target_sdk_and_rejects_bad_values(tmp_path):
|
|
21
|
+
subprocess.run([
|
|
22
|
+
"javac", "-source", "8", "-target", "8", "-cp", SDK_JAR, "-d", str(tmp_path),
|
|
23
|
+
str(EXAMPLE / "CosmicTimeAdapter.java"),
|
|
24
|
+
str(EXAMPLE / "CosmicTimeAdapterCheck.java"),
|
|
25
|
+
], check=True, capture_output=True, text=True)
|
|
26
|
+
result = subprocess.run(
|
|
27
|
+
["java", "-cp", os.pathsep.join([str(tmp_path), SDK_JAR]), "CosmicTimeAdapterCheck"],
|
|
28
|
+
check=True, capture_output=True, text=True,
|
|
29
|
+
)
|
|
30
|
+
assert result.stdout.strip() == "CosmicTimeAdapter: 6 cases passed"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.skipif(not shutil.which("javac") or not QUERY_CLASSPATH,
|
|
34
|
+
reason="target query SDK classpath unavailable")
|
|
35
|
+
def test_cosmic_entry_query_compiles_against_the_target_sdk(tmp_path):
|
|
36
|
+
subprocess.run([
|
|
37
|
+
"javac", "-source", "8", "-target", "8", "-cp", QUERY_CLASSPATH, "-d", str(tmp_path),
|
|
38
|
+
str(EXAMPLE / "CosmicEntryQuery.java"),
|
|
39
|
+
], check=True, capture_output=True, text=True)
|
|
40
|
+
assert (tmp_path / "CosmicEntryQuery.class").is_file()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _compile_report_filter_check(tmp_path, example=EXAMPLE):
|
|
44
|
+
check = tmp_path / "ReportFilterCheck.java"
|
|
45
|
+
check.write_text('''
|
|
46
|
+
import kd.bos.entity.report.FilterInfo;
|
|
47
|
+
import kd.bos.dataentity.entity.DynamicObject;
|
|
48
|
+
import kd.bos.dataentity.entity.DynamicObjectCollection;
|
|
49
|
+
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
|
|
50
|
+
import java.util.Arrays;
|
|
51
|
+
import java.util.Date;
|
|
52
|
+
public class ReportFilterCheck {
|
|
53
|
+
static void reject(Runnable call) {
|
|
54
|
+
try { call.run(); } catch (IllegalArgumentException expected) { return; }
|
|
55
|
+
throw new AssertionError("invalid value accepted");
|
|
56
|
+
}
|
|
57
|
+
public static void main(String[] args) {
|
|
58
|
+
FilterInfo filter = new FilterInfo();
|
|
59
|
+
filter.addFilterItem("shfz_mode", "0");
|
|
60
|
+
if (!"0".equals(CosmicReportFilters.value(filter, "flt_mode", "shfz_mode"))) throw new AssertionError("zero enum");
|
|
61
|
+
if (CosmicReportFilters.value(filter, "unknown") != null) throw new AssertionError("missing key");
|
|
62
|
+
filter.addFilterItem("flt_mode", "2");
|
|
63
|
+
reject(() -> CosmicReportFilters.value(filter, "flt_mode", "shfz_mode"));
|
|
64
|
+
Date start = new Date(1000L);
|
|
65
|
+
filter.addFilterItem("flt_date_startdate", start, ">=");
|
|
66
|
+
if (CosmicReportFilters.value(filter, "flt_date") != null) throw new AssertionError("unsplit key");
|
|
67
|
+
if (!start.equals(CosmicReportFilters.date(filter, "flt_date_startdate"))) throw new AssertionError("split Date");
|
|
68
|
+
if (!start.equals(filter.getValue("flt_date_startdate"))) throw new AssertionError("getValue delegates to item");
|
|
69
|
+
if (CosmicReportFilters.date(filter, "flt_date_enddate") != null) throw new AssertionError("open end");
|
|
70
|
+
filter.addFilterItem("bad_date", "2026-10-01");
|
|
71
|
+
reject(() -> CosmicReportFilters.date(filter, "bad_date"));
|
|
72
|
+
reject(() -> CosmicReportFilters.numbers(10L));
|
|
73
|
+
if (!CosmicReportFilters.numbers(null).isEmpty()) throw new AssertionError("empty F7");
|
|
74
|
+
if (args.length == 0) { System.out.println("report filter SDK checks passed"); return; }
|
|
75
|
+
DynamicObjectType type = new DynamicObjectType("supplier");
|
|
76
|
+
type.registerProperty("number", String.class, null, false);
|
|
77
|
+
type.registerProperty("id", Long.class, null, false);
|
|
78
|
+
DynamicObject first = new DynamicObject(type);
|
|
79
|
+
first.set("number", "0012"); first.set("id", 10L);
|
|
80
|
+
DynamicObject second = new DynamicObject(type);
|
|
81
|
+
second.set("number", "0012"); second.set("id", 20L);
|
|
82
|
+
if (!CosmicReportFilters.numbers(first).equals(Arrays.asList("0012"))) throw new AssertionError("single F7");
|
|
83
|
+
DynamicObjectCollection values = new DynamicObjectCollection(type, null);
|
|
84
|
+
values.add(first); values.add(second);
|
|
85
|
+
if (!CosmicReportFilters.numbers(values).equals(Arrays.asList("0012"))) throw new AssertionError("assigned ids differ");
|
|
86
|
+
second.set("number", "0034");
|
|
87
|
+
if (!CosmicReportFilters.numbers(values).equals(Arrays.asList("0012", "0034"))) throw new AssertionError("multi F7");
|
|
88
|
+
second.set("number", ""); reject(() -> CosmicReportFilters.numbers(values));
|
|
89
|
+
System.out.println("report filter SDK checks passed");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
''')
|
|
93
|
+
subprocess.run(["javac", "-source", "8", "-target", "8", "-cp", QUERY_CLASSPATH, "-d", str(tmp_path),
|
|
94
|
+
str(example / "CosmicReportFilters.java"), str(check)], check=True, capture_output=True, text=True)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@pytest.mark.skipif(not shutil.which("javac") or not QUERY_CLASSPATH,
|
|
98
|
+
reason="target query SDK classpath unavailable")
|
|
99
|
+
@pytest.mark.parametrize("example", [EXAMPLE, EXAMPLE.parents[1] / ".locales" / "zh" / "examples" / "java-rules"])
|
|
100
|
+
def test_report_filter_adapter_against_real_sdk_objects(tmp_path, example):
|
|
101
|
+
_compile_report_filter_check(tmp_path, example)
|
|
102
|
+
result = subprocess.run(["java", "-cp", os.pathsep.join([str(tmp_path), QUERY_CLASSPATH]), "ReportFilterCheck"],
|
|
103
|
+
cwd=tmp_path, timeout=20, check=True, capture_output=True, text=True)
|
|
104
|
+
assert result.stdout.strip() == "report filter SDK checks passed"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@pytest.mark.skipif(not shutil.which("javac") or not QUERY_CLASSPATH
|
|
108
|
+
or not os.environ.get("COSMIC_SDK_RUNTIME_JAVA_OPTIONS"),
|
|
109
|
+
reason="F7 metadata runtime needs the authorized target configuration/logging service")
|
|
110
|
+
def test_report_f7_records_with_target_runtime_configuration(tmp_path):
|
|
111
|
+
_compile_report_filter_check(tmp_path)
|
|
112
|
+
result = subprocess.run(["java", *shlex.split(os.environ["COSMIC_SDK_RUNTIME_JAVA_OPTIONS"]), "-cp",
|
|
113
|
+
os.pathsep.join([str(tmp_path), QUERY_CLASSPATH]), "ReportFilterCheck", "f7"],
|
|
114
|
+
cwd=tmp_path, timeout=20, check=True, capture_output=True, text=True)
|
|
115
|
+
assert "report filter SDK checks passed" in result.stdout
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@pytest.mark.skipif(not shutil.which("javac") or not OPERATION_CLASSPATH,
|
|
119
|
+
reason="target operation SDK classpath unavailable")
|
|
120
|
+
def test_operation_receivers_expose_their_own_keys_in_the_target_sdk(tmp_path):
|
|
121
|
+
source = tmp_path / "OperationAccessorCheck.java"
|
|
122
|
+
source.write_text('''
|
|
123
|
+
import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
|
|
124
|
+
import kd.bos.entity.validate.AbstractValidator;
|
|
125
|
+
public class OperationAccessorCheck {
|
|
126
|
+
public static void main(String[] args) {
|
|
127
|
+
BeginOperationTransactionArgs event = new BeginOperationTransactionArgs("test.confirm", null);
|
|
128
|
+
if (!"test.confirm".equals(event.getOperationKey())) throw new AssertionError("event key");
|
|
129
|
+
AbstractValidator validator = new AbstractValidator() { public void validate() {} };
|
|
130
|
+
validator.setOperateKey("test.validate");
|
|
131
|
+
if (!"test.validate".equals(validator.getOperateKey())) throw new AssertionError("validator key");
|
|
132
|
+
if ("test.confirm".equals(validator.getOperateKey())) throw new AssertionError("receiver keys mixed");
|
|
133
|
+
System.out.println("operation accessor contracts passed");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
''')
|
|
137
|
+
subprocess.run(["javac", "-source", "8", "-target", "8", "-cp", OPERATION_CLASSPATH,
|
|
138
|
+
"-d", str(tmp_path), str(source)], check=True, capture_output=True, text=True)
|
|
139
|
+
result = subprocess.run(["java", "-cp", os.pathsep.join([str(tmp_path), OPERATION_CLASSPATH]),
|
|
140
|
+
"OperationAccessorCheck"], cwd=tmp_path, timeout=15, check=True, capture_output=True, text=True)
|
|
141
|
+
assert result.stdout.strip() == "operation accessor contracts passed"
|
|
@@ -180,6 +180,17 @@ def test_section_singleton_row_requires_explicit_full_line() -> None:
|
|
|
180
180
|
]
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
@pytest.mark.parametrize("row", [
|
|
184
|
+
{"fields": ["Description"], "fullLine": True},
|
|
185
|
+
{"field": "Description", "fullLine": True},
|
|
186
|
+
])
|
|
187
|
+
def test_ui_composition_rejects_row_level_full_line_with_nested_shape(row: dict) -> None:
|
|
188
|
+
with pytest.raises(ValueError, match=r'fullLine inside a fields\[\] item'):
|
|
189
|
+
_normalize_ui_composition_contract({
|
|
190
|
+
"sections": [{"caption": "Details", "rows": [row]}],
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
|
|
183
194
|
def test_ui_composition_flattens_one_anonymous_tab_section() -> None:
|
|
184
195
|
authored = {
|
|
185
196
|
"tabs": [{
|
|
@@ -350,6 +361,17 @@ def test_dynamic_template_conflict_fails_without_rewriting_to_blank(
|
|
|
350
361
|
assert any("DYN-CROSS-TPL" in error for error in logs.errors)
|
|
351
362
|
|
|
352
363
|
|
|
364
|
+
def test_authoring_rejects_base_owned_bill_reference_before_emit():
|
|
365
|
+
data = _valid_authoring()
|
|
366
|
+
root = data["artifact"]["entities"][0]
|
|
367
|
+
root["type"] = "BaseEntity"
|
|
368
|
+
root["templateKey"] = "bos_basetpl"
|
|
369
|
+
root["fields"].append({"bizWord": "bill", "displayName": "单据", "dataType": "RefBillField",
|
|
370
|
+
"reference": {"mode": "platform", "formNumber": "sample_bill"}})
|
|
371
|
+
issues = validate_authoring_contract(data, known_field_types={"ComboField", "TextField", "RefBillField"})
|
|
372
|
+
assert any(issue.code == "REF_BILL_OWNER_UNSUPPORTED" for issue in issues)
|
|
373
|
+
|
|
374
|
+
|
|
353
375
|
def _valid_authoring() -> dict:
|
|
354
376
|
return {
|
|
355
377
|
"artifact": {
|
|
@@ -1685,14 +1707,17 @@ def test_direct_basedata_delegated_authoring_contract() -> None:
|
|
|
1685
1707
|
) == []
|
|
1686
1708
|
|
|
1687
1709
|
|
|
1688
|
-
def
|
|
1710
|
+
def test_authoring_allows_omitted_default_template_but_rejects_empty_explicit_value() -> None:
|
|
1689
1711
|
data = _valid_authoring()
|
|
1690
1712
|
del data["artifact"]["entities"][0]["templateKey"]
|
|
1691
|
-
|
|
1713
|
+
assert not any(
|
|
1714
|
+
issue.path == "$.artifact.entities[0].templateKey"
|
|
1715
|
+
for issue in validate_authoring_contract(data)
|
|
1716
|
+
)
|
|
1717
|
+
data["artifact"]["entities"][0]["templateKey"] = ""
|
|
1692
1718
|
assert any(
|
|
1693
|
-
issue.
|
|
1694
|
-
|
|
1695
|
-
for issue in issues
|
|
1719
|
+
issue.path == "$.artifact.entities[0].templateKey"
|
|
1720
|
+
for issue in validate_authoring_contract(data)
|
|
1696
1721
|
)
|
|
1697
1722
|
|
|
1698
1723
|
|
|
@@ -33,7 +33,7 @@ def test_execution_skills_preserve_the_terminal_menu_boundary() -> None:
|
|
|
33
33
|
assert "Do not configure a menu or render artifact cards here" in java
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
def
|
|
36
|
+
def test_plugin_delivery_uses_the_package_root() -> None:
|
|
37
37
|
for relative in (
|
|
38
38
|
"references/java-plugin-delivery.md",
|
|
39
39
|
".locales/zh/references/java-plugin-delivery.md",
|
|
@@ -44,14 +44,6 @@ def test_plugin_delivery_uses_the_package_root_and_clean_schema_files() -> None:
|
|
|
44
44
|
assert "APP_BUILD_ROOT" in text
|
|
45
45
|
assert "{ROOT_DIR}" not in text
|
|
46
46
|
|
|
47
|
-
for relative in (
|
|
48
|
-
"references/java-plugin-delivery.md",
|
|
49
|
-
".locales/zh/references/java-plugin-delivery.md",
|
|
50
|
-
):
|
|
51
|
-
text = _read(relative)
|
|
52
|
-
assert '--output "{entity.schema.json}" getFormSchema' in text
|
|
53
|
-
assert '--output "{operations.json}" listOperations' in text
|
|
54
|
-
assert "--stdout getFormSchema" not in text
|
|
55
47
|
|
|
56
48
|
|
|
57
49
|
def test_chinese_delivery_reference_is_mirrored() -> None:
|
|
@@ -63,7 +55,7 @@ def test_chinese_delivery_reference_is_mirrored() -> None:
|
|
|
63
55
|
|
|
64
56
|
assert "references/delivery.md" in root
|
|
65
57
|
assert "只有所选元数据入口无法表达" in root
|
|
66
|
-
assert "
|
|
58
|
+
assert "每个本轮可交付目标分别传一次" in delivery
|
|
67
59
|
assert "最后一次写入后执行一次" in delivery
|
|
68
60
|
assert "只出现在工具结果中不代表已经" in delivery
|
|
69
61
|
assert "原样放进最终答复" in delivery
|
|
@@ -43,3 +43,14 @@ def test_worker_refuses_changed_app_identity(tmp_path):
|
|
|
43
43
|
with mock.patch("render_output_cards.sync_existing_dym_at_session_close") as sync:
|
|
44
44
|
assert run_request(pending["requestPath"])["status"] == "failed"
|
|
45
45
|
sync.assert_not_called()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_worker_passes_all_current_forms_to_sync(tmp_path):
|
|
49
|
+
(tmp_path / "archive.json").write_text(json.dumps({"appId": "APP"}))
|
|
50
|
+
pending = enqueue_dym_sync(str(tmp_path), ["created", "changed", "created"], {"appId": "APP"})
|
|
51
|
+
with mock.patch("render_output_cards.sync_existing_dym_at_session_close",
|
|
52
|
+
return_value={"status": "synced", "formNumbers": ["created", "changed"]}) as sync:
|
|
53
|
+
result = run_request(pending["requestPath"])
|
|
54
|
+
assert result["status"] == "succeeded"
|
|
55
|
+
assert result["formNumbers"] == ["created", "changed"]
|
|
56
|
+
assert sync.call_args.args[1] == ["created", "changed"]
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import copy
|
|
6
|
+
import json
|
|
6
7
|
import runpy
|
|
7
8
|
import sys
|
|
8
9
|
from pathlib import Path
|
|
@@ -20,6 +21,63 @@ from field_decorator import decorate_artifact # noqa: E402
|
|
|
20
21
|
from dynamic_form_validator import validate_dynamic_form # noqa: E402
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
def test_dynamic_reference_targets_use_the_entity_resolver_and_preserve_field_types():
|
|
25
|
+
from cosmic_api import _resolve_dynamic_reference_fields
|
|
26
|
+
queries = []
|
|
27
|
+
def query(selector):
|
|
28
|
+
queries.append(selector)
|
|
29
|
+
return [{"formNumber": "uhyl_drug", "formName": "药品档案", "modelType": "BaseFormModel"}]
|
|
30
|
+
artifact = _artifact()
|
|
31
|
+
artifact["entities"][0]["fields"] = [
|
|
32
|
+
{"bizWord": "imm", "displayName": "疫苗/药品", "dataType": "BasedataField",
|
|
33
|
+
"reference": {"mode": "platform", "formNumber": "uhyl_drug"}},
|
|
34
|
+
{"bizWord": "drugs", "dataType": "MulBasedataField", "prdRef": "uhyl_drug"},
|
|
35
|
+
]
|
|
36
|
+
assert _resolve_dynamic_reference_fields(artifact, isv="uhyl", query_forms=query, entity_exists=lambda _: False) is None
|
|
37
|
+
fields = artifact["entities"][0]["fields"]
|
|
38
|
+
assert [field["basedataNumber"] for field in fields] == ["uhyl_drug", "uhyl_drug"]
|
|
39
|
+
assert [field["dataType"] for field in fields] == ["BasedataField", "MulBasedataField"]
|
|
40
|
+
assert queries == ["uhyl_drug"]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_unresolved_dynamic_reference_stops_before_creation_without_removing_the_field():
|
|
44
|
+
from cosmic_api import _resolve_dynamic_reference_fields
|
|
45
|
+
artifact = _artifact()
|
|
46
|
+
artifact["entities"][0]["fields"] = [{"bizWord": "imm", "dataType": "BasedataField", "prdRef": "不存在的药品"}]
|
|
47
|
+
failure = _resolve_dynamic_reference_fields(artifact, query_forms=lambda _: [], entity_exists=lambda _: False)
|
|
48
|
+
assert failure["writeAttempted"] is False
|
|
49
|
+
assert failure["errorCode"] == "DYNAMIC_REFERENCE_TARGET_UNRESOLVED"
|
|
50
|
+
assert failure["data"]["unresolvedReferences"][0]["selector"] == "不存在的药品"
|
|
51
|
+
assert artifact["entities"][0]["fields"][0]["dataType"] == "BasedataField"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_retained_dynamic_creation_rejects_a_changed_artifact_before_auth_or_another_build(tmp_path, monkeypatch):
|
|
55
|
+
from unittest import mock
|
|
56
|
+
import cosmic_api
|
|
57
|
+
source = tmp_path / "page.json"
|
|
58
|
+
source.write_text(json.dumps(_artifact()), encoding="utf-8")
|
|
59
|
+
retained = {"status": False, "metadataRetained": True, "writeAttempted": True,
|
|
60
|
+
"data": {"entityResults": [{"formId": "retained-id", "formNumber": "uhyl_task_register"}]}}
|
|
61
|
+
cosmic_api._dynamic_creation_receipt(str(tmp_path), str(source), retained)
|
|
62
|
+
assert cosmic_api._dynamic_creation_receipt(str(tmp_path), str(tmp_path / "another-page.json")) is None
|
|
63
|
+
assert cosmic_api._dynamic_creation_receipt(str(tmp_path), str(source))["data"]["entityResults"][0]["formId"] == "retained-id"
|
|
64
|
+
source.write_text(json.dumps({**_artifact(), "propertySettings": []}), encoding="utf-8")
|
|
65
|
+
monkeypatch.setattr(sys, "argv", ["cosmic_api.py", "--stdout", "run", "--app-root", str(tmp_path), "--artifact", str(source)])
|
|
66
|
+
with mock.patch.object(cosmic_api, "load_config", return_value={}), \
|
|
67
|
+
mock.patch.object(cosmic_api, "_retarget_runtime_dir"), \
|
|
68
|
+
mock.patch.object(cosmic_api, "pjson") as emit, \
|
|
69
|
+
mock.patch.object(cosmic_api, "do_auth") as auth, \
|
|
70
|
+
mock.patch.object(cosmic_api, "do_build_meta") as build:
|
|
71
|
+
assert cosmic_api._main_impl() == 3
|
|
72
|
+
failure = emit.call_args.args[0]
|
|
73
|
+
assert failure["errorCode"] == "DYNAMIC_FORM_RECOVERY_REQUIRED"
|
|
74
|
+
assert failure["writeAttempted"] is False
|
|
75
|
+
assert failure["metadataRetained"] is True
|
|
76
|
+
assert failure["reconciliation"][0]["arguments"][-2:] == ["--formId", "retained-id"]
|
|
77
|
+
auth.assert_not_called()
|
|
78
|
+
build.assert_not_called()
|
|
79
|
+
|
|
80
|
+
|
|
23
81
|
def _artifact() -> dict:
|
|
24
82
|
return {
|
|
25
83
|
"status": "REVIEW_PENDING",
|
|
@@ -150,7 +208,7 @@ def test_dynamic_explicit_form_number_over_limit_requires_user_input() -> None:
|
|
|
150
208
|
|
|
151
209
|
def test_dynamic_explicit_form_number_at_limit_is_preserved() -> None:
|
|
152
210
|
artifact = _artifact()
|
|
153
|
-
exact = "x" *
|
|
211
|
+
exact = "uhyl_" + "x" * 31
|
|
154
212
|
artifact["entities"][0]["logicalName"] = exact
|
|
155
213
|
|
|
156
214
|
for locale_root in (APP_BUILD, APP_BUILD / ".locales/zh"):
|