@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
|
@@ -120,10 +120,15 @@ _FRONT_MATTER_FIELD_RE = re.compile(r'^(?P<key>\w+):\s*"?(?P<value>[^"\n]*)"?\s*
|
|
|
120
120
|
# One registered signature inside a ```java block. The return type may carry generics or array
|
|
121
121
|
# markers; the generic body excludes parentheses so it can never swallow the parameter list. The
|
|
122
122
|
# parameter list closes on the same line: every page signature is written that way, and requiring
|
|
123
|
-
# the closing parenthesis keeps a prose fragment from parsing as a signature.
|
|
123
|
+
# the closing parenthesis keeps a prose fragment from parsing as a signature. A generic method
|
|
124
|
+
# declares its type parameters before the return type (`public <T extends Control> T
|
|
125
|
+
# getControl(String key)`); without that optional group IFormView.getControl and
|
|
126
|
+
# IDataModel.getContextVariable looked unregistered, and an ordinary call to either was reported
|
|
127
|
+
# as a remembered spelling of some other member.
|
|
124
128
|
_SIGNATURE_RE = re.compile(
|
|
125
129
|
r"^\s*(?:public|protected)\s+"
|
|
126
130
|
r"(?:(?:static|final|abstract|synchronized|native|default|strictfp)\s+)*"
|
|
131
|
+
r"(?:(?P<tparams><[^;{}()]*>)\s+)?"
|
|
127
132
|
r"(?P<ret>[\w.$]+(?:\s*<[^;{}()]*>)?(?:\s*\[\s*\])*)\s+"
|
|
128
133
|
r"(?P<name>[A-Za-z_$][\w$]*)\s*\((?P<params>[^)]*)\)",
|
|
129
134
|
re.MULTILINE,
|
|
@@ -153,6 +158,26 @@ _ALWAYS_ASSIGNABLE = {"Object", "var"}
|
|
|
153
158
|
_GENERIC_RE = re.compile(r"<[^<>]*>")
|
|
154
159
|
|
|
155
160
|
|
|
161
|
+
def _type_variables(type_parameters: str) -> set[str]:
|
|
162
|
+
"""`<T extends Control, K>` -> {"T", "K"}: only top-level names, not bounds."""
|
|
163
|
+
body = type_parameters.strip()[1:-1]
|
|
164
|
+
names, depth, current = set(), 0, ""
|
|
165
|
+
for char in body + ",":
|
|
166
|
+
if char == "<":
|
|
167
|
+
depth += 1
|
|
168
|
+
elif char == ">":
|
|
169
|
+
depth -= 1
|
|
170
|
+
elif char == "," and depth == 0:
|
|
171
|
+
match = re.match(r"\s*([A-Za-z_$][\w$]*)", current)
|
|
172
|
+
if match:
|
|
173
|
+
names.add(match.group(1))
|
|
174
|
+
current = ""
|
|
175
|
+
continue
|
|
176
|
+
if depth == 0:
|
|
177
|
+
current += char
|
|
178
|
+
return names
|
|
179
|
+
|
|
180
|
+
|
|
156
181
|
def _normalized(type_text: str) -> str:
|
|
157
182
|
"""A type as a signature comparison sees it: no package, no generics, array markers kept."""
|
|
158
183
|
bare = type_text.strip()
|
|
@@ -195,10 +220,16 @@ def _page(fqcn: str) -> dict | None:
|
|
|
195
220
|
# a no-argument signature and stays registered, because "overrides nothing" is exactly the
|
|
196
221
|
# finding for a no-arg method that declares a parameter.
|
|
197
222
|
signatures: dict[str, set[tuple[str, ...]]] = {}
|
|
223
|
+
# Names with an overload whose return type is one of its own type variables: the caller's
|
|
224
|
+
# declared type is the type argument, so no declared type contradicts that overload.
|
|
225
|
+
generic_returns: set[str] = set()
|
|
198
226
|
for match in _SIGNATURE_RE.finditer(text):
|
|
199
227
|
returns.setdefault(match.group("name"), set()).add(_normalized(match.group("ret")))
|
|
200
228
|
signatures.setdefault(match.group("name"), set()).add(
|
|
201
229
|
tuple(_param_types(match.group("params"))))
|
|
230
|
+
if match.group("tparams") and _normalized(match.group("ret")).rstrip("[]") in _type_variables(
|
|
231
|
+
match.group("tparams")):
|
|
232
|
+
generic_returns.add(match.group("name"))
|
|
202
233
|
supertypes: set[str] = set()
|
|
203
234
|
for match in _SUPERTYPE_RE.finditer(text[: front.end() + 4000]):
|
|
204
235
|
supertypes.update(_TYPE_TOKEN_RE.findall(match.group("names")))
|
|
@@ -207,9 +238,11 @@ def _page(fqcn: str) -> dict | None:
|
|
|
207
238
|
"className": class_name,
|
|
208
239
|
"fqcn": fqcn,
|
|
209
240
|
"returns": returns,
|
|
241
|
+
"genericReturns": generic_returns,
|
|
210
242
|
"signatures": signatures,
|
|
211
243
|
"supertypes": supertypes,
|
|
212
244
|
"path": path,
|
|
245
|
+
"text": text,
|
|
213
246
|
}
|
|
214
247
|
|
|
215
248
|
|
|
@@ -236,6 +269,168 @@ def _page_by_simple_name(simple_name: str) -> dict | None:
|
|
|
236
269
|
return _page(f"{PLATFORM_PACKAGE}{relative}.{simple_name}" if relative else f"{PLATFORM_PACKAGE}{simple_name}")
|
|
237
270
|
|
|
238
271
|
|
|
272
|
+
def describe_api(selector: str, members: list[str] | None = None) -> dict:
|
|
273
|
+
"""Expose bounded API evidence for one receiver, including inherited declarations."""
|
|
274
|
+
page = _page(selector) if "." in selector else _page_by_simple_name(selector)
|
|
275
|
+
if page is None:
|
|
276
|
+
candidate = _page_by_simple_name(selector.rsplit(".", 1)[-1]) if "." in selector else None
|
|
277
|
+
return {"status": False, "errorCode": "API_CLASS_NOT_DOCUMENTED", "class": selector,
|
|
278
|
+
"message": "No unique registered API page; this does not prove the class is absent from the SDK.",
|
|
279
|
+
"sdkLookup": {"script": str(Path(__file__).with_name("inspect_platform_sdk.py")),
|
|
280
|
+
"arguments": ["--class", selector, "--sdk-dir", "<bound target SDK directory>",
|
|
281
|
+
*[arg for member in members or [] for arg in ("--member", member)]]},
|
|
282
|
+
**({"candidateClass": candidate["fqcn"], "candidateReference": str(candidate["path"])} if candidate else {})}
|
|
283
|
+
evidence = []
|
|
284
|
+
sources = {}
|
|
285
|
+
seen = set()
|
|
286
|
+
for owner in _lineage_pages(page["fqcn"]):
|
|
287
|
+
sections = re.split(r"(?m)^###\s+", owner["text"])
|
|
288
|
+
notes = {section.splitlines()[0].strip(): section.split("```", 1)[0].split("\n", 1)[-1].strip()
|
|
289
|
+
for section in sections[1:]}
|
|
290
|
+
for match in _SIGNATURE_RE.finditer(owner["text"]):
|
|
291
|
+
name = match.group("name")
|
|
292
|
+
identity = (name, tuple(_param_types(match.group("params"))))
|
|
293
|
+
if identity in seen or members and name not in members:
|
|
294
|
+
continue
|
|
295
|
+
seen.add(identity)
|
|
296
|
+
note = notes.get(name, "")
|
|
297
|
+
evidence.append({"name": name, "declaredBy": owner["fqcn"],
|
|
298
|
+
"signature": re.sub(r"\s+", " ", match.group(0)).strip(),
|
|
299
|
+
"deprecated": bool(re.search(r"deprecated|已弃用|废弃|过时", note, re.IGNORECASE)),
|
|
300
|
+
"notes": note[:600]})
|
|
301
|
+
sources[owner["fqcn"]] = str(owner["path"])
|
|
302
|
+
found = {item["name"] for item in evidence}
|
|
303
|
+
return {"status": True, "class": page["fqcn"], "import": "import " + page["fqcn"] + ";",
|
|
304
|
+
"reference": str(page["path"]), "members": evidence, "sources": sources,
|
|
305
|
+
"undocumentedMembers": [name for name in members or [] if name not in found],
|
|
306
|
+
**({"sdkLookup": {"script": str(Path(__file__).with_name("inspect_platform_sdk.py")),
|
|
307
|
+
"arguments": ["--class", page["fqcn"], "--sdk-dir", "<bound target SDK directory>",
|
|
308
|
+
*[arg for name in members or [] if name not in found for arg in ("--member", name)]]}}
|
|
309
|
+
if any(name not in found for name in members or []) else {}),
|
|
310
|
+
"evidenceScope": "Registered declarations and documented supertypes; undocumented members are not proof of SDK absence."}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def plugin_coding_evidence(plugin_type: str, scenes: list[str] | None = None) -> dict:
|
|
314
|
+
"""Resolve coding references from the existing type and API registries."""
|
|
315
|
+
registry = json.loads(TYPE_REGISTRY_PAGE.read_text(encoding="utf-8-sig"))
|
|
316
|
+
definition = next((item for item in registry["types"] if item["type"] == plugin_type), None)
|
|
317
|
+
if definition is None:
|
|
318
|
+
return {}
|
|
319
|
+
root = TYPE_REGISTRY_PAGE.parent.parent
|
|
320
|
+
evidence = {
|
|
321
|
+
"codingEntry": str(root / "skills" / "cosmic-coding-impl" / "SKILL.md"),
|
|
322
|
+
"guide": str(root / definition["guide"]) if definition.get("guide") else None,
|
|
323
|
+
"typeKnowledge": str(TYPE_CONTRACTS_PAGE),
|
|
324
|
+
"standards": str(STANDARDS_PAGE),
|
|
325
|
+
"filterOperators": [{"literal": literal, "constant": "QCP." + constant, "preferred": preferred}
|
|
326
|
+
for literal, (constant, preferred) in _qcp_constants().items()],
|
|
327
|
+
"apiLookup": {"script": str(Path(__file__).resolve()),
|
|
328
|
+
"arguments": ["--describe-class", "<receiver class>", "--member", "<required member>"]},
|
|
329
|
+
"sdkLookup": {"script": str(Path(__file__).with_name("inspect_platform_sdk.py")),
|
|
330
|
+
"arguments": ["--class", "<receiver class>", "--sdk-dir", "<bound target SDK directory>",
|
|
331
|
+
"--member", "<required member>"]},
|
|
332
|
+
}
|
|
333
|
+
if plugin_type == "operation":
|
|
334
|
+
evidence["operationDispatch"] = {
|
|
335
|
+
"transactionEvent": {"class": "kd.bos.entity.plugin.args.OperationArgs", "accessor": "event.getOperationKey()",
|
|
336
|
+
"reference": describe_api("kd.bos.entity.plugin.args.OperationArgs")["reference"]},
|
|
337
|
+
"validator": {"class": "kd.bos.entity.validate.AbstractValidator", "accessor": "this.getOperateKey()",
|
|
338
|
+
"reference": describe_api("kd.bos.entity.validate.AbstractValidator")["reference"]},
|
|
339
|
+
"guide": str(root / "references" / "operation-dispatch.md"),
|
|
340
|
+
"evidenceScope": "8.0 SDK accessor signatures checked with javap; these do not verify any operateMeta Map key or actual event execution",
|
|
341
|
+
}
|
|
342
|
+
base = definition.get("baseImport")
|
|
343
|
+
if base:
|
|
344
|
+
evidence["baseContract"] = describe_api(base)
|
|
345
|
+
evidence["baseContract"]["members"] = [
|
|
346
|
+
{key: value for key, value in item.items() if key != "notes" or item["deprecated"]}
|
|
347
|
+
for item in evidence["baseContract"].get("members", [])
|
|
348
|
+
]
|
|
349
|
+
guide_text = (root / definition["guide"]).read_text(encoding="utf-8-sig")
|
|
350
|
+
guide_signatures = list(_SIGNATURE_RE.finditer(guide_text))
|
|
351
|
+
evidence["guideSignatures"] = list(dict.fromkeys(
|
|
352
|
+
re.sub(r"\s+", " ", match.group(0)).strip() for match in guide_signatures
|
|
353
|
+
))
|
|
354
|
+
parameters = {}
|
|
355
|
+
for match in guide_signatures:
|
|
356
|
+
for parameter in _param_types(match.group("params")):
|
|
357
|
+
page = _page_by_simple_name(parameter.removesuffix("[]"))
|
|
358
|
+
if page:
|
|
359
|
+
parameters[page["fqcn"]] = {"class": page["fqcn"], "reference": str(page["path"])}
|
|
360
|
+
for owner in _lineage_pages(base):
|
|
361
|
+
for signatures in owner["signatures"].values():
|
|
362
|
+
for signature in signatures:
|
|
363
|
+
for parameter in signature:
|
|
364
|
+
page = _page_by_simple_name(parameter.removesuffix("[]"))
|
|
365
|
+
if page:
|
|
366
|
+
parameters[page["fqcn"]] = {"class": page["fqcn"], "reference": str(page["path"])}
|
|
367
|
+
evidence["parameterTypes"] = sorted(parameters.values(), key=lambda item: item["class"])
|
|
368
|
+
scene_root = (root / "knowledge" / "cosmic" / "platform" / "scenes").resolve()
|
|
369
|
+
selected = []
|
|
370
|
+
apis: dict[str, set[str]] = {}
|
|
371
|
+
for selector in scenes or []:
|
|
372
|
+
target = (scene_root / (selector if selector.endswith(".md") else selector + ".md")).resolve()
|
|
373
|
+
if not target.is_relative_to(scene_root) or not target.is_file():
|
|
374
|
+
raise ValueError(f"unknown coding scene: {selector}")
|
|
375
|
+
selected.append(str(target))
|
|
376
|
+
text = target.read_text(encoding="utf-8-sig")
|
|
377
|
+
# Scene metadata and its explicit evidence links are existing knowledge authorities.
|
|
378
|
+
references = re.findall(r"`((?:data-access|operation)/[A-Za-z0-9_/.-]+\.md)`", text)
|
|
379
|
+
texts = [text] + [(scene_root / reference).read_text(encoding="utf-8-sig")
|
|
380
|
+
for reference in references if (scene_root / reference).is_file()]
|
|
381
|
+
for content in texts:
|
|
382
|
+
related = re.search(r"(?m)^related_apis:\s*\[([^]]*)\]", content)
|
|
383
|
+
tokens = [token.strip().strip("\"'") for token in
|
|
384
|
+
(related.group(1).split(",") if related else [])]
|
|
385
|
+
owners = [token for token in tokens if _page_by_simple_name(token)]
|
|
386
|
+
for owner in owners:
|
|
387
|
+
apis.setdefault(owner, set()).update(token for token in tokens
|
|
388
|
+
if re.fullmatch(r"[a-z][A-Za-z0-9_]*", token))
|
|
389
|
+
for token in tokens:
|
|
390
|
+
value = token
|
|
391
|
+
owner, separator, member = value.partition(".")
|
|
392
|
+
if not _page_by_simple_name(owner):
|
|
393
|
+
continue
|
|
394
|
+
apis.setdefault(owner, set())
|
|
395
|
+
if separator:
|
|
396
|
+
apis[owner].add(member)
|
|
397
|
+
for owner, member in re.findall(r"\b([A-Z][A-Za-z0-9_]*)\.([a-z][A-Za-z0-9_]*)\s*\(", content):
|
|
398
|
+
if _page_by_simple_name(owner):
|
|
399
|
+
apis.setdefault(owner, set()).add(member)
|
|
400
|
+
if selected:
|
|
401
|
+
evidence["scenes"] = selected
|
|
402
|
+
evidence["apiContracts"] = [describe_api(owner, sorted(members))
|
|
403
|
+
for owner, members in sorted(apis.items()) if members
|
|
404
|
+
and _page_by_simple_name(owner)["fqcn"] != base]
|
|
405
|
+
for contract in evidence["apiContracts"]:
|
|
406
|
+
contract["members"] = [{key: value for key, value in item.items()
|
|
407
|
+
if key != "notes" or item["deprecated"]}
|
|
408
|
+
for item in contract.get("members", [])]
|
|
409
|
+
# Parameter evidence alone misses types such as AbstractValidator.getDataEntities()'s
|
|
410
|
+
# ExtendedDataEntity[] return value. Resolve only names proven by a unique SDK page.
|
|
411
|
+
signature_types = {item["class"]: {**item, "import": "import " + item["class"] + ";"}
|
|
412
|
+
for item in evidence.get("parameterTypes", [])}
|
|
413
|
+
signatures = evidence.get("guideSignatures", []) + [
|
|
414
|
+
member["signature"] for contract in
|
|
415
|
+
[evidence.get("baseContract", {}), *evidence.get("apiContracts", [])]
|
|
416
|
+
for member in contract.get("members", [])
|
|
417
|
+
]
|
|
418
|
+
for signature in signatures:
|
|
419
|
+
match = _SIGNATURE_RE.search(signature)
|
|
420
|
+
if not match:
|
|
421
|
+
continue
|
|
422
|
+
for name in re.findall(r"\b(?:kd\.bos\.[\w.$]+|[A-Z][\w$]*)\b",
|
|
423
|
+
match.group("ret") + " " + match.group("params")):
|
|
424
|
+
page = _page(name) if "." in name else _page_by_simple_name(name)
|
|
425
|
+
if page:
|
|
426
|
+
signature_types[page["fqcn"]] = {
|
|
427
|
+
"class": page["fqcn"], "import": "import " + page["fqcn"] + ";",
|
|
428
|
+
"reference": str(page["path"]),
|
|
429
|
+
}
|
|
430
|
+
evidence["signatureTypes"] = sorted(signature_types.values(), key=lambda item: item["class"])
|
|
431
|
+
return evidence
|
|
432
|
+
|
|
433
|
+
|
|
239
434
|
def _imports(code: str) -> dict[str, str]:
|
|
240
435
|
resolved: dict[str, str] = {}
|
|
241
436
|
for match in _IMPORT_RE.finditer(code):
|
|
@@ -285,9 +480,10 @@ def return_type_issues(source_text: str) -> list[dict]:
|
|
|
285
480
|
if not page:
|
|
286
481
|
continue
|
|
287
482
|
registered = page["returns"].get(match.group("method"))
|
|
288
|
-
if not registered:
|
|
483
|
+
if not registered or match.group("method") in page["genericReturns"]:
|
|
289
484
|
# The overload set may simply be unregistered — the javadoc export omits everything
|
|
290
|
-
# that is not @SdkPublic. Unknown is not wrong.
|
|
485
|
+
# that is not @SdkPublic. Unknown is not wrong. A generic return (`<T> T`) takes its
|
|
486
|
+
# type from the declaration, so the declared type is never a contradiction.
|
|
291
487
|
continue
|
|
292
488
|
end = _call_end(code, code.index("(", match.end() - 1))
|
|
293
489
|
if end is None or code[end:].lstrip()[:1] != ";":
|
|
@@ -409,6 +605,13 @@ def filter_operator_issues(source_text: str) -> list[dict]:
|
|
|
409
605
|
continue
|
|
410
606
|
operator = _OPERATOR_ARG_RE.match(arguments[1])
|
|
411
607
|
if not operator:
|
|
608
|
+
# Confirmed javac failure from the recorded delivery; do not treat this typo as a
|
|
609
|
+
# valid constant or offer a string literal that would trigger the next guard.
|
|
610
|
+
if (arguments[1] == "kd.bos.orm.query.QCP.equal" or arguments[1] == "QCP.equal"
|
|
611
|
+
and _imports(code).get("QCP") == "kd.bos.orm.query.QCP") and "=" in constants:
|
|
612
|
+
issues.append({"line": code[:match.start()].count("\n") + 1,
|
|
613
|
+
"operator": arguments[1], "constant": "QCP." + constants["="][0],
|
|
614
|
+
"message": "QCP.equal is not the SDK equality constant; use QCP.equals. Keep the typed operator instead of replacing it with a string."})
|
|
412
615
|
# Already a constant, or a variable / concatenation this scan must not judge.
|
|
413
616
|
continue
|
|
414
617
|
entry = constants.get(operator.group("operator").strip().lower())
|
|
@@ -564,7 +767,7 @@ _PROPERTY_WRITE_RE = re.compile(
|
|
|
564
767
|
r"(?:\bgetModel\s*\(\s*\)\s*\.\s*setValue|\.\s*setValueFast)\s*\(")
|
|
565
768
|
_PROPERTY_GUARD_RE = re.compile(r"getProperty\s*\(\s*\)|getChangeSet\s*\(\s*\)")
|
|
566
769
|
|
|
567
|
-
_OPERATION_PLUGIN_RE = re.compile(r"\bextends\s+AbstractOperationServicePlugIn\b")
|
|
770
|
+
_OPERATION_PLUGIN_RE = re.compile(r"\bextends\s+(?:[\w$]+\.)*AbstractOperationServicePlugIn\b")
|
|
568
771
|
# The plugin's own inherited accessor, not the one on an event argument. The lookbehind rejects any
|
|
569
772
|
# qualified call so `e.getDataEntities()` — the correct form — is never matched, while `this.` is
|
|
570
773
|
# matched explicitly.
|
|
@@ -618,17 +821,22 @@ def scene_misuse_issues(source_text: str) -> list[dict]:
|
|
|
618
821
|
"write when the new value already equals the current one",
|
|
619
822
|
)
|
|
620
823
|
|
|
621
|
-
#
|
|
622
|
-
#
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
# validator's correct call would block a delivery that has nothing wrong with it.
|
|
626
|
-
if _OPERATION_PLUGIN_RE.search(code) and "AbstractValidator" not in code:
|
|
824
|
+
# A validator's same-named method is valid; determine the actual enclosing receiver
|
|
825
|
+
# instead of waiving the operation-plugin check for the entire file.
|
|
826
|
+
classes = _class_bodies(code)
|
|
827
|
+
if _OPERATION_PLUGIN_RE.search(code):
|
|
627
828
|
for match in _INHERITED_DATA_ENTITIES_RE.finditer(code):
|
|
628
829
|
# Only a call inside a method body: the same text outside one is the class declaring
|
|
629
830
|
# its own override, which is not this defect.
|
|
630
831
|
if not any(body["start"] <= match.start() < body["end"] for body in bodies):
|
|
631
832
|
continue
|
|
833
|
+
scopes = [scope for scope in classes if scope["start"] <= match.start() < scope["end"]]
|
|
834
|
+
qualifier = re.search(r"([A-Za-z_$][\w$]*)\s*\.\s*$", code[:match.start()])
|
|
835
|
+
if qualifier:
|
|
836
|
+
scopes = [scope for scope in scopes if scope["name"] == qualifier.group(1)]
|
|
837
|
+
owner = max(scopes, key=lambda scope: scope["start"]) if scopes else None
|
|
838
|
+
if not owner or owner["base"].rsplit(".", 1)[-1] != "AbstractOperationServicePlugIn":
|
|
839
|
+
continue
|
|
632
840
|
add(
|
|
633
841
|
match.start(),
|
|
634
842
|
"AbstractOperationServicePlugIn.getDataEntities",
|
|
@@ -642,6 +850,26 @@ def scene_misuse_issues(source_text: str) -> list[dict]:
|
|
|
642
850
|
return issues
|
|
643
851
|
|
|
644
852
|
|
|
853
|
+
def _class_bodies(code: str) -> list[dict]:
|
|
854
|
+
"""Locate named and anonymous class scopes in comment/literal-free Java."""
|
|
855
|
+
pattern = re.compile(
|
|
856
|
+
r"\b(?:class\s+(?P<name>[\w$]+)(?:\s+extends\s+(?P<base>[\w$.]+))?[^;{}]*"
|
|
857
|
+
r"|new\s+(?P<anonymous>[\w$.]+)\s*\([^;{}]*\))\s*\{")
|
|
858
|
+
scopes = []
|
|
859
|
+
for match in pattern.finditer(code):
|
|
860
|
+
opening = match.end() - 1
|
|
861
|
+
depth = 1
|
|
862
|
+
end = opening + 1
|
|
863
|
+
while end < len(code) and depth:
|
|
864
|
+
depth += (code[end] == "{") - (code[end] == "}")
|
|
865
|
+
end += 1
|
|
866
|
+
if depth == 0:
|
|
867
|
+
scopes.append({"name": match.group("name"),
|
|
868
|
+
"base": match.group("base") or match.group("anonymous") or "",
|
|
869
|
+
"start": opening + 1, "end": end - 1})
|
|
870
|
+
return scopes
|
|
871
|
+
|
|
872
|
+
|
|
645
873
|
# The outermost class declaration's `extends` clause. Generic bounds are skipped rather than
|
|
646
874
|
# parsed: a plugin class never carries them, and a missed base is one finding fewer, never a
|
|
647
875
|
# false one.
|
|
@@ -1177,8 +1405,15 @@ def unverified_member_issues(source_text: str) -> list[dict]:
|
|
|
1177
1405
|
def main() -> int:
|
|
1178
1406
|
parser = argparse.ArgumentParser(
|
|
1179
1407
|
description="Check platform API contracts in one Java plugin source")
|
|
1180
|
-
parser.
|
|
1408
|
+
mode = parser.add_mutually_exclusive_group(required=True)
|
|
1409
|
+
mode.add_argument("--source-path")
|
|
1410
|
+
mode.add_argument("--describe-class", action="append", help="Exact SDK class name or fully qualified name; repeat to batch lookups")
|
|
1411
|
+
parser.add_argument("--member", action="append", help="Limit API evidence to named members")
|
|
1181
1412
|
args = parser.parse_args()
|
|
1413
|
+
if args.describe_class:
|
|
1414
|
+
results = [describe_api(selector, args.member) for selector in args.describe_class]
|
|
1415
|
+
print(json.dumps({"status": all(item["status"] for item in results), "classes": results}, ensure_ascii=False))
|
|
1416
|
+
return 0 if all(item["status"] for item in results) else 2
|
|
1182
1417
|
source = Path(args.source_path)
|
|
1183
1418
|
if not source.is_file():
|
|
1184
1419
|
print(json.dumps({
|