android2harmony 0.1.6 → 0.1.8

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.
Files changed (227) hide show
  1. package/agents/api-analyzer.md +113 -0
  2. package/agents/app-action.md +122 -0
  3. package/agents/code-reviewer.md +191 -295
  4. package/agents/coder.md +377 -0
  5. package/agents/self-tester.md +8 -8
  6. package/agents/spec-designer.md +56 -0
  7. package/package.json +1 -1
  8. package/skills/a2h-app-req-gen/SKILL.md +174 -0
  9. package/skills/a2h-app-req-gen/references/spec-handoff.md +99 -0
  10. package/skills/a2h-app-req-gen/references/subagent-render.md +115 -0
  11. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/build.gradle.kts +41 -0
  12. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.jar +0 -0
  13. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle/wrapper/gradle-wrapper.properties +8 -0
  14. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradle.properties +3 -0
  15. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew +251 -0
  16. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/gradlew.bat +94 -0
  17. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/settings.gradle.kts +17 -0
  18. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawAnalysisDetector.java +1911 -0
  19. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawIssueRegistry.java +37 -0
  20. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawJson.java +146 -0
  21. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawLocation.java +96 -0
  22. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/java/dev/reqgen/analyzer/jvm/RawRecordWriter.java +227 -0
  23. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry +1 -0
  24. package/skills/a2h-app-req-gen/scripts/reqgen/analyzer-jvm/src/main/resources/dev/reqgen/analyzer/jvm/raw-record-v1.schema.json +93 -0
  25. package/skills/a2h-app-req-gen/scripts/reqgen/assets/dashboard.html +151 -0
  26. package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-lint.init.gradle +60 -0
  27. package/skills/a2h-app-req-gen/scripts/reqgen/gradle/reqgen-model.init.gradle +204 -0
  28. package/skills/a2h-app-req-gen/scripts/reqgen/package.json +14 -0
  29. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/backend.js +323 -0
  30. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/cli.js +811 -0
  31. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/gap-audit-link.js +62 -0
  32. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/index.js +66 -0
  33. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/merge.js +605 -0
  34. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/name-trace.js +153 -0
  35. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/orchestrate.js +1324 -0
  36. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/output-parse.js +50 -0
  37. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/overview.js +10 -0
  38. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/pool.js +23 -0
  39. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/post-merge-fix.js +146 -0
  40. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt-loader.js +51 -0
  41. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompt.js +967 -0
  42. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/prompts.md +301 -0
  43. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/serve.js +78 -0
  44. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/short-id.js +46 -0
  45. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/snapshot.js +267 -0
  46. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/types.js +1 -0
  47. package/skills/a2h-app-req-gen/scripts/reqgen/src/agent-render/validate.js +122 -0
  48. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/callback-call-sites.js +62 -0
  49. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/build.js +1291 -0
  50. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/gap-audit/index.js +1 -0
  51. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/area-ownership.js +392 -0
  52. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/build.js +1995 -0
  53. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/callback-flow.js +277 -0
  54. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/component-variants.js +725 -0
  55. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/graph/index.js +15 -0
  56. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/index.js +12 -0
  57. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/policy.js +469 -0
  58. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/names/traceability.js +468 -0
  59. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/build.js +1066 -0
  60. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/req-model/index.js +1 -0
  61. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android-interaction-registry.js +174 -0
  62. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/android.js +1062 -0
  63. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/area-titles.js +678 -0
  64. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/builder.js +350 -0
  65. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-api-registry.js +395 -0
  66. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose-call-sites.js +2008 -0
  67. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/compose.js +9059 -0
  68. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/dynamic-repeated-call-sites.js +529 -0
  69. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/index.js +1 -0
  70. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/interaction-effects.js +1149 -0
  71. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/jvm.js +6272 -0
  72. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/normalize.js +33 -0
  73. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/pending-intents.js +565 -0
  74. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/resource-id.js +42 -0
  75. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/route-state-variants.js +781 -0
  76. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/state.js +234 -0
  77. package/skills/a2h-app-req-gen/scripts/reqgen/src/analysis/source-facts/types.js +1 -0
  78. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/extract.js +40 -0
  79. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/index.js +6 -0
  80. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/manifest.js +513 -0
  81. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/resources.js +398 -0
  82. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/types.js +1 -0
  83. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/views.js +447 -0
  84. package/skills/a2h-app-req-gen/scripts/reqgen/src/android/xml-parser.js +175 -0
  85. package/skills/a2h-app-req-gen/scripts/reqgen/src/cli.js +398 -0
  86. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/area-graph.js +1 -0
  87. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/artifact.js +1 -0
  88. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/common.js +16 -0
  89. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/diagnostic.js +10 -0
  90. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/gap-audit.js +14 -0
  91. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/index.js +11 -0
  92. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/name-traceability.js +26 -0
  93. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/raw-fact.js +40 -0
  94. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/req-model.js +1 -0
  95. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/run.js +19 -0
  96. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/semantic-completeness.js +11 -0
  97. package/skills/a2h-app-req-gen/scripts/reqgen/src/contracts/source-facts.js +1 -0
  98. package/skills/a2h-app-req-gen/scripts/reqgen/src/core/output-guard.js +41 -0
  99. package/skills/a2h-app-req-gen/scripts/reqgen/src/core/stable-id.js +92 -0
  100. package/skills/a2h-app-req-gen/scripts/reqgen/src/dashboard-cli.js +169 -0
  101. package/skills/a2h-app-req-gen/scripts/reqgen/src/diagnostics.js +104 -0
  102. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/dump.js +1028 -0
  103. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump/index.js +1 -0
  104. package/skills/a2h-app-req-gen/scripts/reqgen/src/dump-cli.js +251 -0
  105. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/artifacts.js +49 -0
  106. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/index.js +18 -0
  107. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/quality-report.js +125 -0
  108. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/render.js +353 -0
  109. package/skills/a2h-app-req-gen/scripts/reqgen/src/generation/types.js +2 -0
  110. package/skills/a2h-app-req-gen/scripts/reqgen/src/graph/paths.js +474 -0
  111. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/index.js +15 -0
  112. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/protocol.js +408 -0
  113. package/skills/a2h-app-req-gen/scripts/reqgen/src/jvm/runner.js +452 -0
  114. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/index.js +8 -0
  115. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/output.js +165 -0
  116. package/skills/a2h-app-req-gen/scripts/reqgen/src/pipeline/run-stage1.js +891 -0
  117. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/discovery.js +299 -0
  118. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-model.js +358 -0
  119. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/gradle-runner.js +165 -0
  120. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/resource-profile.js +60 -0
  121. package/skills/a2h-app-req-gen/scripts/reqgen/src/project/types.js +1 -0
  122. package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff-cli.js +151 -0
  123. package/skills/a2h-app-req-gen/scripts/reqgen/src/spec-handoff.js +1004 -0
  124. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-cli.js +109 -0
  125. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-input.js +419 -0
  126. package/skills/a2h-app-req-gen/scripts/reqgen/src/stage2-name-trace-input.js +95 -0
  127. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/area-graph.js +444 -0
  128. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/index.js +7 -0
  129. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-model.js +580 -0
  130. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/req-text.js +195 -0
  131. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/semantic-area-graph.js +1431 -0
  132. package/skills/a2h-app-req-gen/scripts/reqgen/src/validation/types.js +1 -0
  133. package/skills/a2h-app-req-gen/scripts/reqgen-audit.mjs +298 -0
  134. package/skills/a2h-app-req-gen/scripts/reqgen-selfcheck.mjs +555 -0
  135. package/skills/a2h-code-review/SKILL.md +379 -0
  136. package/skills/{hmos-integration-test → a2h-integration-test}/README.md +6 -6
  137. package/skills/{hmos-integration-test → a2h-integration-test}/SKILL.md +6 -6
  138. package/skills/{hmos-integration-test → a2h-integration-test}/scripts/report-tool.mjs +1 -1
  139. package/skills/a2h-spec-design/SKILL.md +330 -0
  140. package/skills/a2h-spec-design/scripts/inspect_spec_design_inputs.mjs +207 -0
  141. package/skills/a2h-spec-design/scripts/move_spec_technical_reference.mjs +198 -0
  142. package/skills/a2h-spec-design/scripts/validate_spec_design_output.mjs +256 -0
  143. package/skills/a2h-spec-generate/SKILL.md +696 -0
  144. package/skills/a2h-spec-generate/references/trace-template.md +115 -0
  145. package/skills/a2h-spec-generate/scripts/parse_requirements.mjs +537 -0
  146. package/skills/a2h-spec-generate/template/REQ.txt +22 -0
  147. package/skills/a2h-spec-generate/template/REQ.xlsx +0 -0
  148. package/skills/a2h-spec-implement/SKILL.md +548 -0
  149. package/skills/a2h-spec-implement/references/harmony-pitfalls.md +186 -0
  150. package/skills/a2h-spec-implement/references/l1-unit-test.md +185 -0
  151. package/skills/a2h-spec-implement/references/l3-e2e-uitest.md +167 -0
  152. package/skills/a2h-spec-implement/references/test-core.md +132 -0
  153. package/skills/a2h-spec-implement/rules/arkts/arkts-standards.md +184 -0
  154. package/skills/a2h-spec-implement/rules/arkts/conventions/coding-style.md +96 -0
  155. package/skills/a2h-spec-implement/rules/arkts/conventions/security.md +126 -0
  156. package/skills/a2h-spec-implement/rules/arkts/language/arkts-rules.md +650 -0
  157. package/skills/a2h-spec-implement/rules/arkts/language/arkui-structure-rules.md +173 -0
  158. package/skills/a2h-spec-implement/rules/arkts/language/ts-to-arkts-rewrites.md +58 -0
  159. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -0
  160. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2089 -0
  161. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -0
  162. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -0
  163. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -0
  164. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -0
  165. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -0
  166. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +903 -0
  167. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -0
  168. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -0
  169. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -0
  170. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +355 -0
  171. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v1//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -0
  172. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md +216 -0
  173. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md +442 -0
  174. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md +169 -0
  175. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md +763 -0
  176. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md +2088 -0
  177. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md +1258 -0
  178. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Once/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md +175 -0
  179. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Param/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md +850 -0
  180. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md +862 -0
  181. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md +110 -0
  182. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md +301 -0
  183. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md +1411 -0
  184. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +1392 -0
  185. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/getTarget/346/216/245/345/217/243/357/274/232/350/216/267/345/217/226/347/212/266/346/200/201/347/256/241/347/220/206/346/241/206/346/236/266/344/273/243/347/220/206/345/211/215/347/232/204/345/216/237/345/247/213/345/257/271/350/261/241.md +288 -0
  186. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2/makeObserved/346/216/245/345/217/243/357/274/232/345/260/206/351/235/236/350/247/202/345/257/237/346/225/260/346/215/256/345/217/230/344/270/272/345/217/257/350/247/202/345/257/237/346/225/260/346/215/256.md +768 -0
  187. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/222/214V2/346/267/267/347/224/250/346/214/207/345/257/274/357/274/210API version 19/345/217/212/344/271/213/345/220/216/357/274/211.md" +829 -0
  188. package/skills/a2h-spec-implement/rules/arkts/official/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206/346/246/202/350/277/260.md +184 -0
  189. package/skills/a2h-spec-implement/rules/arkts/ui/component-cookbook.md +431 -0
  190. package/skills/a2h-spec-implement/rules/arkts/ui/state-management.md +152 -0
  191. package/skills/a2h-spec-implement/rules/arkts/ui/ui-quality.md +67 -0
  192. package/skills/a2h-spec-implement/rules/arkts/ui/ui-runtime-diagnosis.md +32 -0
  193. package/skills/a2h-spec-implement/rules/pipeline/build/package-set-collection.md +43 -0
  194. package/skills/a2h-spec-implement/scripts/_lib/common.mjs +97 -0
  195. package/skills/a2h-spec-implement/scripts/_lib/config.mjs +70 -0
  196. package/skills/a2h-spec-implement/scripts/_lib/lessons_cli.mjs +48 -0
  197. package/skills/a2h-spec-implement/scripts/build_lessons.mjs +24 -0
  198. package/skills/a2h-spec-implement/scripts/code_pattern_lessons.mjs +26 -0
  199. package/skills/a2h-spec-implement/scripts/device_ui.mjs +433 -0
  200. package/skills/a2h-spec-implement/scripts/device_ui_core.mjs +895 -0
  201. package/skills/a2h-spec-implement/scripts/ledger/aggregate_run.mjs +207 -0
  202. package/skills/a2h-spec-implement/scripts/manifest/emit_summary_line.mjs +37 -0
  203. package/skills/a2h-spec-implement/scripts/manifest/finalize_run.mjs +115 -0
  204. package/skills/a2h-spec-implement/scripts/manifest/render_final_summary.mjs +78 -0
  205. package/skills/a2h-spec-implement/scripts/manifest/root_mirror.mjs +137 -0
  206. package/skills/a2h-spec-implement/scripts/package.json +12 -0
  207. package/skills/a2h-spec-implement/scripts/state_propagation_check.mjs +676 -0
  208. package/skills/a2h-spec-implement/scripts/test/l2_run.mjs +244 -0
  209. package/skills/a2h-spec-implement/scripts/test/tp_coverage.mjs +231 -0
  210. package/skills/a2h-spec-implement/scripts/ui_memory.mjs +161 -0
  211. package/skills/a2h-spec-implement/scripts/utils/ensure_app.mjs +134 -0
  212. package/skills/a2h-ui-transfer/SKILL.md +20 -9
  213. package/skills/a2h-ui-transfer/scripts/arkts_static_check.js +80 -0
  214. package/skills/hmos-convert-pipeline/SKILL.md +7 -5
  215. package/skills/hmos-incremental-ui-align/README.md +7 -7
  216. package/skills/hmos-incremental-ui-align/SKILL.md +1 -1
  217. package/skills/hmos-incremental-ui-align/page_align.md +1 -1
  218. package/skills/hmos-spec-generate/SKILL.md +2 -2
  219. package/skills/hmos-spec-generate/scripts/parse_requirements.mjs +537 -0
  220. package/skills/hmos-fix-build-errors/SKILL.md +0 -266
  221. package/skills/hmos-fix-build-errors/references/arkts-strict-patterns.md +0 -219
  222. package/skills/hmos-fix-build-errors/references/known-patterns.md +0 -157
  223. package/skills/hmos-fix-build-errors/references/rdb-entity-pattern.md +0 -131
  224. package/skills/hmos-spec-generate/scripts/parse_requirements.ts +0 -515
  225. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/resolve-metadata-tool.mjs +0 -0
  226. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/self-test-runner.mjs +0 -0
  227. /package/skills/{hmos-integration-test → a2h-integration-test}/scripts/testcases-tool.mjs +0 -0
@@ -0,0 +1,862 @@
1
+ # \@Provider装饰器和\@Consumer装饰器:跨组件层级双向同步
2
+ <!--Kit: ArkUI-->
3
+ <!--Subsystem: ArkUI-->
4
+ <!--Owner: @liwenzhen3-->
5
+ <!--Designer: @zhangboren-->
6
+ <!--Tester: @TerryTsao-->
7
+ <!--Adviser: @zhang_yixin13-->
8
+
9
+ \@Provider和\@Consumer用于跨组件层级数据双向同步,可以使得开发者不用拘泥于组件层级。
10
+
11
+ \@Provider和\@Consumer属于状态管理V2装饰器,所以只能在\@ComponentV2中才能使用,在\@Component中使用会编译报错。
12
+
13
+ \@Provider和\@Consumer提供了跨组件层级数据双向同步的能力。在阅读本文档前,建议提前阅读:[\@ComponentV2](./arkts-create-custom-components.md#componentv2)。常见问题请参考[组件内状态变量常见问题](./arkts-state-management-faq-inner-component.md)。
14
+
15
+ >**说明:**
16
+ >
17
+ > \@Provider和\@Consumer装饰器从API version 12开始支持。
18
+ >
19
+ > 从API version 12开始,\@Provider和\@Consumer装饰器支持在原子化服务中使用。
20
+ >
21
+ > 从API version 23开始,通过配置[BuilderNode](../../reference/apis-arkui/js-apis-arkui-builderNode.md)的[BuildOptions](../../reference/apis-arkui/js-apis-arkui-builderNode.md#buildoptions12)参数`enableProvideConsumeCrossing`为true,使得\@Provider和\@Consumer支持跨[BuilderNode](../../reference/apis-arkui/js-apis-arkui-builderNode.md)双向同步。在BuilderNode挂载到自定义组件节点树之后,\@Consumer会重新获取最近的\@Provider数据,与之建立双向同步关系。具体可见[\@Consumer在跨BuilderNode场景下和\@Provider建立双向同步](#consumer在跨buildernode场景下和provider建立双向同步过程)。
22
+ >
23
+ > 从API version 23开始,\@Provider和\@Consumer装饰器支持在ArkTS卡片中使用。
24
+
25
+ ## 概述
26
+
27
+ \@Provider,即数据提供方,其所有的子组件都可以通过\@Consumer绑定相同的key来获取\@Provider提供的数据。
28
+
29
+ \@Consumer,即数据消费方,可以通过绑定同样的key获取其最近父节点的\@Provider的数据,当查找不到\@Provider的数据时,使用本地默认值。图示如下。
30
+
31
+ ![ProviderConsumer_1](./figures/Provider_Consumer_1.png)
32
+
33
+ \@Provider和\@Consumer装饰的数据类型需要一致。
34
+
35
+ 开发者在使用\@Provider和\@Consumer时要注意:
36
+ - \@Provider和\@Consumer强依赖自定义组件层级,\@Consumer会因为所在组件的父组件不同,而被初始化为不同的值。
37
+ - \@Provider和\@Consumer相当于把组件粘合在一起了,从组件独立角度考虑,应减少使用\@Provider和\@Consumer。
38
+
39
+ ## \@Provider和\@Consumer vs \@Provide和\@Consume能力对比
40
+ 在状态管理V1版本中,提供跨组件层级双向的装饰器为[\@Provide和\@Consume](./arkts-provide-and-consume.md),当前文档介绍的是状态管理V2装饰器\@Provider和\@Consumer。虽然两者名字和功能类似,但在特性上还存在一些差异。
41
+
42
+ 如果开发者不了解状态管理V1中的\@Provide和\@Consume,可以直接跳过本节。
43
+
44
+ | 能力 | V2装饰器\@Provider和\@Consumer |V1装饰器\@Provide和\@Consume|
45
+ | ------------------ | ----------------------------------------------------- |----------------------------------------------------- |
46
+ | \@Consume(r) |必须本地初始化,当找不到\@Provider时使用本地默认值。| API version 20以前,@Consume禁止本地初始化,当找不到对应\@Provide的时候,会抛出异常;从API version 20开始,@Consume支持设置默认值,如果没有设置默认值,且找不到对应\@Provide时,会抛出异常。 |
47
+ | 支持类型 | 支持function。 | 不支持function。 |
48
+ | 观察能力 | 仅能观察自身赋值变化,如果要观察嵌套场景,配合[\@Trace](arkts-new-observedV2-and-trace.md)一起使用。 | 观察第一层变化,如果要观察嵌套场景,配合[\@Observed和\@ObjectLink](arkts-observed-and-objectlink.md)一起使用。 |
49
+ | alias和属性名 | alias是唯一匹配的key,缺省时默认属性名为alias。 | alias和属性名都为key,优先匹配alias,匹配不到可以匹配属性名。|
50
+ | \@Provide(r) 从父组件初始化 | 不允许。 | 允许。|
51
+ | \@Provide(r)支持重载 | 默认开启,即\@Provider可以重名,\@Consumer向上查找最近的\@Provider。 | 默认关闭,即在组件树上不允许有同名\@Provide。如果需要重载,则需要配置allowOverride。|
52
+
53
+ ## 装饰器说明
54
+
55
+ ### 基本规则
56
+ \@Provider语法:
57
+
58
+ `@Provider(aliasName?: string) varName : varType = initValue`
59
+
60
+ | \@Provider属性装饰器 | 说明 |
61
+ | ------------------ | ----------------------------------------------------- |
62
+ | 装饰器参数 | `aliasName?: string`,别名,缺省时默认为属性名。|
63
+ | 支持类型 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、[Array](#装饰array类型变量)、[Date](#装饰date类型变量)、[Map](#装饰map类型变量)、[Set](#装饰set类型变量)等类型。支持装饰[箭头函数](#provider和consumer装饰回调事件用于组件之间完成行为抽象)。 |
64
+ | 从父组件初始化 | 禁止。 |
65
+ | 本地初始化 | 必须本地初始化。 |
66
+ | 观察能力 | 能力等同于\@Trace。变化会同步给对应的\@Consumer。 |
67
+
68
+ \@Consumer语法:
69
+
70
+ `@Consumer(aliasName?: string) varName : varType = initValue`
71
+
72
+ | \@Consumer属性装饰器 | 说明 |
73
+ | --------------------- | ------------------------------------------------------------ |
74
+ | 装饰器参数 | `aliasName?: string`,别名,缺省时默认为属性名,向上查找最近的\@Provider。 |
75
+ | 可装饰的变量 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、Array、Date、Map、Set等类型。支持装饰箭头函数。 |
76
+ | 从父组件初始化 | 禁止。 |
77
+ | 本地初始化 | 必须本地初始化。 |
78
+ | 观察能力 | 能力等同于\@Trace。变化会同步给对应的\@Provider。 |
79
+
80
+ ### aliasName和属性名
81
+
82
+ \@Provider和\@Consumer接受可选参数aliasName,没有配置参数时,使用属性名作为默认的aliasName。
83
+
84
+ >**说明:**
85
+ >
86
+ > aliasName是用于\@Provider和\@Consumer进行匹配的唯一指定key。
87
+
88
+ 以下三个例子可清楚介绍\@Provider和\@Consumer如何使用aliasName进行查找匹配。
89
+
90
+ ```ts
91
+ @ComponentV2
92
+ struct Parent {
93
+ // 未定义aliasName, 使用属性名'str'作为aliasName
94
+ @Provider() str: string = 'hello';
95
+ }
96
+
97
+ @ComponentV2
98
+ struct Child {
99
+ // 定义aliasName为'str',使用aliasName去寻找
100
+ // 能够在Parent组件上找到, 使用@Provider的值'hello'
101
+ @Consumer('str') str: string = 'world';
102
+ }
103
+ ```
104
+
105
+ ```ts
106
+ @ComponentV2
107
+ struct Parent {
108
+ // 定义aliasName为'alias'
109
+ @Provider('alias') str: string = 'hello';
110
+ }
111
+
112
+ @ComponentV2
113
+ struct Child {
114
+ // 定义aliasName为 'alias',找到@Provider并获得值'hello'
115
+ @Consumer('alias') str: string = 'world';
116
+ }
117
+ ```
118
+
119
+ ```ts
120
+ @ComponentV2
121
+ struct Parent {
122
+ // 定义aliasName为'alias'
123
+ @Provider('alias') str: string = 'hello';
124
+ }
125
+
126
+ @ComponentV2
127
+ struct Child {
128
+ // 未定义aliasName,使用属性名'str'作为aliasName
129
+ // 没有找到对应的@Provider,使用本地值'world'
130
+ @Consumer() str: string = 'world';
131
+ }
132
+ ```
133
+
134
+ ## 变量传递
135
+
136
+ | 传递规则 | 说明 |
137
+ | -------------- | ------------------------------------------------------------ |
138
+ | 从父组件初始化 | \@Provider和\@Consumer装饰的变量仅允许本地初始化,不允许从外部传入初始化。 |
139
+ | 初始化子组件 | \@Provider和\@Consumer装饰的变量可以初始化子组件中\@Param装饰的变量。 |
140
+
141
+ ## 使用限制
142
+
143
+ 1. \@Provider和\@Consumer为自定义组件的属性装饰器,只能装饰自定义组件内的属性,不能装饰class的属性。
144
+ 2. \@Provider和\@Consumer为状态管理V2装饰器,只能在\@ComponentV2中使用,不能在\@Component中使用。
145
+ 3. \@Provider和\@Consumer只支持本地初始化,不支持外部传入初始化。
146
+
147
+ ## 使用场景
148
+
149
+ ### \@Provider和\@Consumer双向同步
150
+
151
+ **建立双向绑定**
152
+
153
+ 1. 自定义组件Parent和Child初始化:
154
+ - Child中`@Consumer() str: string = 'world'`向上查找,查找到Parent中声明的`@Provider() str: string = 'hello'`。
155
+ - `@Consumer() str: string = 'world'`初始化为其查找到的`@Provider`的值,即'hello'。
156
+ - 两者建立双向同步关系。
157
+ 2. 点击Parent中的按钮,改变\@Provider装饰的str,通知其对应的\@Consumer,对应UI刷新。
158
+ 3. 点击Child中的按钮,改变\@Consumer装饰的str,通知其对应的\@Provider,对应UI刷新。
159
+
160
+ <!-- @[Twoway_Binding](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/TwowayBinding.ets) -->
161
+
162
+ ``` TypeScript
163
+ @Entry
164
+ @ComponentV2
165
+ struct Parent {
166
+ @Provider() str: string = 'hello';
167
+
168
+ build() {
169
+ Column() {
170
+ Button(this.str)
171
+ .onClick(() => {
172
+ this.str += '0';
173
+ })
174
+ Child()
175
+ }
176
+ }
177
+ }
178
+
179
+ @ComponentV2
180
+ struct Child {
181
+ // @Consumer装饰的属性str和Parent组件中@Provider装饰的属性str名称相同,因此建立了双向绑定关系
182
+ @Consumer() str: string = 'world';
183
+
184
+ build() {
185
+ Column() {
186
+ Button(this.str)
187
+ .onClick(() => {
188
+ this.str += '0';
189
+ })
190
+ }
191
+ }
192
+ }
193
+ ```
194
+
195
+ **未建立双向绑定**
196
+
197
+ 下面的例子中,\@Provider和\@Consumer由于aliasName值不同,无法建立双向同步关系。
198
+ 1. 自定义组件Parent和Child初始化:
199
+ - Child中`@Consumer() str: string = 'world'`向上查找,未查找到其数据提供方@Provider。
200
+ - `@Consumer() str: string = 'world'`使用其本地默认值为'world'。
201
+ - 两者未建立双向同步关系。
202
+ 2. 点击Parent中的按钮,改变\@Provider装饰的str1,仅刷新\@Provider关联的Button组件。
203
+ 3. 点击Child中的按钮,改变\@Consumer装饰的str,仅刷新\@Consumer关联的Button组件。
204
+
205
+ <!-- @[No_Twoway_Binding](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/NoTwowayBinding.ets) -->
206
+
207
+ ``` TypeScript
208
+ @Entry
209
+ @ComponentV2
210
+ struct Parent {
211
+ @Provider() str1: string = 'hello';
212
+
213
+ build() {
214
+ Column() {
215
+ Button(this.str1)
216
+ .onClick(() => {
217
+ this.str1 += '0';
218
+ })
219
+ Child()
220
+ }
221
+ }
222
+ }
223
+
224
+ @ComponentV2
225
+ struct Child {
226
+ // @Consumer装饰的属性str和Parent组件中@Provider装饰的属性str1名称不同,无法建立双向绑定关系
227
+ @Consumer() str: string = 'world';
228
+
229
+ build() {
230
+ Column() {
231
+ Button(this.str)
232
+ .onClick(() => {
233
+ this.str += '0';
234
+ })
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ### 装饰Array类型变量
241
+
242
+ 当装饰的对象是Array时,可以观察到Array整体的赋值,同时可以通过调用Array的接口`push`, `pop`, `shift`, `unshift`, `splice`, `copyWithin`, `fill`, `reverse`, `sort`更新Array中的数据。
243
+
244
+ <!-- @[Decorative_Array](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeArray.ets) -->
245
+
246
+ ``` TypeScript
247
+ @Entry
248
+ @ComponentV2
249
+ struct Parent {
250
+ @Provider() count: number[] = [1, 2, 3];
251
+
252
+ build() {
253
+ Row() {
254
+ Column() {
255
+ ForEach(this.count, (item: number) => {
256
+ Text(`parent: ${item}`).fontSize(30)
257
+ Divider()
258
+ })
259
+ // count被@Provider装饰,可以被观察到Array整体的赋值以及调用Array接口带来的变化
260
+ Button('push').onClick(() => {
261
+ this.count.push(111);
262
+ })
263
+ Button('reverse').onClick(() => {
264
+ this.count.reverse();
265
+ })
266
+ Button('fill').onClick(() => {
267
+ this.count.fill(6);
268
+ })
269
+ Child()
270
+ }
271
+ .width('100%')
272
+ }
273
+ .height('100%')
274
+ }
275
+ }
276
+
277
+ @ComponentV2
278
+ struct Child {
279
+ @Consumer() count: number[] = [9, 8, 7];
280
+
281
+ build() {
282
+ Column() {
283
+ ForEach(this.count, (item: number) => {
284
+ Text(`child: ${item}`).fontSize(30)
285
+ Divider()
286
+ })
287
+ // count被@Consumer装饰,可以被观察到Array整体的赋值以及调用Array接口带来的变化
288
+ Button('push').onClick(() => {
289
+ this.count.push(222);
290
+ })
291
+ Button('reverse').onClick(() => {
292
+ this.count.reverse();
293
+ })
294
+ Button('fill').onClick(() => {
295
+ this.count.fill(8);
296
+ })
297
+ }
298
+ .width('100%')
299
+ }
300
+ }
301
+ ```
302
+
303
+ ### 装饰Date类型变量
304
+
305
+ 当装饰Date类型变量时,可以观察到数据源对Date整体的赋值,以及调用Date的接口`setFullYear`, `setMonth`, `setDate`, `setHours`, `setMinutes`, `setSeconds`, `setMilliseconds`, `setTime`, `setUTCFullYear`, `setUTCMonth`, `setUTCDate`, `setUTCHours`, `setUTCMinutes`, `setUTCSeconds`, `setUTCMilliseconds`带来的变化。
306
+
307
+ <!-- @[Decorative_Date](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeDate.ets) -->
308
+
309
+ ``` TypeScript
310
+ @Entry
311
+ @ComponentV2
312
+ struct Parent {
313
+ @Provider() selectedDate: Date = new Date('2021-08-08');
314
+
315
+ build() {
316
+ Column() {
317
+ Text(`parent: ${this.selectedDate}`)
318
+ // selectedDate被@Provider装饰,可以被观察到Date整体的赋值以及调用Date接口带来的变化
319
+ Button('update the new date')
320
+ .onClick(() => {
321
+ this.selectedDate = new Date('2023-07-07');
322
+ })
323
+ Button('increase the year by 1')
324
+ .onClick(() => {
325
+ this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
326
+ })
327
+ Button('increase the month by 1')
328
+ .onClick(() => {
329
+ this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
330
+ })
331
+ Button('increase the day by 1')
332
+ .onClick(() => {
333
+ this.selectedDate.setDate(this.selectedDate.getDate() + 1);
334
+ })
335
+ Child()
336
+ }
337
+ }
338
+ }
339
+
340
+ @ComponentV2
341
+ struct Child {
342
+ @Consumer() selectedDate: Date = new Date('2022-07-07');
343
+
344
+ build() {
345
+ Column() {
346
+ Text(`child: ${this.selectedDate}`)
347
+ // selectedDate被@Consumer装饰,可以被观察到Date整体的赋值以及调用Date接口带来的变化
348
+ Button('update the new date')
349
+ .onClick(() => {
350
+ this.selectedDate = new Date('2025-01-01');
351
+ })
352
+ Button('increase the year by 1')
353
+ .onClick(() => {
354
+ this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
355
+ })
356
+ Button('increase the month by 1')
357
+ .onClick(() => {
358
+ this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
359
+ })
360
+ Button('increase the day by 1')
361
+ .onClick(() => {
362
+ this.selectedDate.setDate(this.selectedDate.getDate() + 1);
363
+ })
364
+ }
365
+ }
366
+ }
367
+ ```
368
+
369
+ ### 装饰Map类型变量
370
+
371
+ 当装饰Map类型变量时,可以观察到数据源对Map整体的赋值,以及调用Map的接口`set`, `clear`, `delete`带来的变化。
372
+
373
+ <!-- @[Decorative_Map](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeMap.ets) -->
374
+
375
+ ``` TypeScript
376
+ @Entry
377
+ @ComponentV2
378
+ struct Parent {
379
+ @Provider() message: Map<number, string> = new Map([[0, 'a'], [1, 'b'], [3, 'c']]);
380
+
381
+ build() {
382
+ Column() {
383
+ Text('Parent').fontSize(30)
384
+ ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
385
+ Text(`${item[0]}`).fontSize(30)
386
+ Text(`${item[1]}`).fontSize(30)
387
+ Divider()
388
+ })
389
+ // message被@Provider装饰,可以被观察到Map整体的赋值以及调用Map接口带来的变化
390
+ Button('init map').onClick(() => {
391
+ this.message = new Map([[0, 'aa'], [1, 'bb'], [3, 'cc']]);
392
+ })
393
+ Button('set new one').onClick(() => {
394
+ this.message.set(4, 'd');
395
+ })
396
+ Button('clear').onClick(() => {
397
+ this.message.clear();
398
+ })
399
+ Button('replace the first one').onClick(() => {
400
+ this.message.set(0, 'a~');
401
+ })
402
+ Button('delete the first one').onClick(() => {
403
+ this.message.delete(0);
404
+ })
405
+ Child()
406
+ }
407
+ }
408
+ }
409
+
410
+ @ComponentV2
411
+ struct Child {
412
+ @Consumer() message: Map<number, string> = new Map([[0, 'd'], [1, 'e'], [3, 'f']]);
413
+
414
+ build() {
415
+ Column() {
416
+ Text('Child').fontSize(30)
417
+ ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
418
+ Text(`${item[0]}`).fontSize(30)
419
+ Text(`${item[1]}`).fontSize(30)
420
+ Divider()
421
+ })
422
+ // message被@Consumer装饰,可以被观察到Map整体的赋值以及调用Map接口带来的变化
423
+ Button('init map').onClick(() => {
424
+ this.message = new Map([[0, 'dd'], [1, 'ee'], [3, 'ff']]);
425
+ })
426
+ Button('set new one').onClick(() => {
427
+ this.message.set(4, 'g');
428
+ })
429
+ Button('clear').onClick(() => {
430
+ this.message.clear();
431
+ })
432
+ Button('replace the first one').onClick(() => {
433
+ this.message.set(0, 'a*');
434
+ })
435
+ Button('delete the first one').onClick(() => {
436
+ this.message.delete(0);
437
+ })
438
+ }
439
+ }
440
+ }
441
+ ```
442
+
443
+ ### 装饰Set类型变量
444
+
445
+ 当装饰Set类型变量时,可以观察到数据源对Set整体的赋值,以及调用Set的接口 `add`, `clear`, `delete`带来的变化。
446
+
447
+ <!-- @[Decorative_Set](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeSet.ets) -->
448
+
449
+ ``` TypeScript
450
+ @Entry
451
+ @ComponentV2
452
+ struct Parent {
453
+ @Provider() message: Set<number> = new Set([1, 2, 3, 4]);
454
+
455
+ build() {
456
+ Column() {
457
+ Text('Parent').fontSize(30)
458
+ ForEach(Array.from(this.message.entries()), (item: [number, number]) => {
459
+ Text(`${item[0]}`).fontSize(30)
460
+ Divider()
461
+ })
462
+ // message被@Provider装饰,可以被观察到Set整体的赋值以及调用Set接口带来的变化
463
+ Button('init set').onClick(() => {
464
+ this.message = new Set([1, 2, 3, 4]);
465
+ })
466
+ Button('set new one').onClick(() => {
467
+ this.message.add(5);
468
+ })
469
+ Button('clear').onClick(() => {
470
+ this.message.clear();
471
+ })
472
+ Button('delete the first one').onClick(() => {
473
+ this.message.delete(1);
474
+ })
475
+ Child()
476
+ }
477
+ }
478
+ }
479
+
480
+ @ComponentV2
481
+ struct Child {
482
+ @Consumer() message: Set<number> = new Set([1, 2, 3, 4, 5, 6]);
483
+
484
+ build() {
485
+ Column() {
486
+ Text('Child').fontSize(30)
487
+ ForEach(Array.from(this.message.entries()), (item: [number, number]) => {
488
+ Text(`${item[0]}`).fontSize(30)
489
+ Divider()
490
+ })
491
+ // message被@Consumer装饰,可以被观察到Set整体的赋值以及调用Set接口带来的变化
492
+ Button('init set').onClick(() => {
493
+ this.message = new Set([1, 2, 3, 4, 5, 6]);
494
+ })
495
+ Button('set new one').onClick(() => {
496
+ this.message.add(7);
497
+ })
498
+ Button('clear').onClick(() => {
499
+ this.message.clear();
500
+ })
501
+ Button('delete the first one').onClick(() => {
502
+ this.message.delete(1);
503
+ })
504
+ }
505
+ }
506
+ }
507
+ ```
508
+
509
+
510
+ ### \@Provider和\@Consumer装饰回调事件用于组件之间完成行为抽象
511
+
512
+ 当需要在父组件中向子组件注册回调函数时,可以使用\@Provider和\@Consumer装饰回调方法来实现。
513
+
514
+ 在拖拽场景中,若需将子组件的拖拽起始位置信息同步给父组件,可参考以下示例。
515
+
516
+ <!-- @[Drag_Drop](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DragDrop.ets) -->
517
+
518
+ ``` TypeScript
519
+ @Entry
520
+ @ComponentV2
521
+ struct Parent {
522
+ @Local childX: number = 0;
523
+ @Local childY: number = 1;
524
+ @Provider() onDrag: (x: number, y: number) => void = (x: number, y: number) => {
525
+ console.info(`onDrag event at x=${x} y:${y}`);
526
+ this.childX = x;
527
+ this.childY = y;
528
+ }
529
+
530
+ build() {
531
+ Column() {
532
+ Text(`child position x: ${this.childX}, y: ${this.childY}`)
533
+ Child()
534
+ }
535
+ }
536
+ }
537
+
538
+ @ComponentV2
539
+ struct Child {
540
+ @Consumer() onDrag: (x: number, y: number) => void = (x: number, y: number) => {};
541
+
542
+ build() {
543
+ Button('changed')
544
+ .draggable(true)
545
+ .onDragStart((event: DragEvent) => {
546
+ // 当前预览器上不支持通用拖拽事件
547
+ this.onDrag(event.getDisplayX(), event.getDisplayY());
548
+ })
549
+ }
550
+ }
551
+ ```
552
+
553
+
554
+ ### \@Provider和\@Consumer装饰复杂类型,配合\@Trace一起使用
555
+
556
+ 1. \@Provider和\@Consumer只能观察到数据本身的变化。如果需要观察其装饰的复杂数据类型的属性变化,可以配合\@Trace一起使用,也可以使用[makeObserved](./arkts-new-makeObserved.md)将非可观察数据变为可观察数据。
557
+ 2. 装饰内置类型:Array、Map、Set、Date时,可以观察到某些API的变化,观察能力同[\@Trace](./arkts-new-observedV2-and-trace.md#观察变化)。
558
+
559
+ <!-- @[Decorative_Complex](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeComplex.ets) -->
560
+
561
+ ``` TypeScript
562
+ @ObservedV2
563
+ class User {
564
+ // 复杂数据类型的属性被@Trace装饰,可以被观察到属性变化
565
+ @Trace public name: string;
566
+ @Trace public age: number;
567
+
568
+ constructor(name: string, age: number) {
569
+ this.name = name;
570
+ this.age = age;
571
+ }
572
+ }
573
+ const data: User[] = [new User('Json', 10), new User('Eric', 15)];
574
+ @Entry
575
+ @ComponentV2
576
+ struct Parent {
577
+ @Provider('data') users: User[] = data;
578
+
579
+ build() {
580
+ Column() {
581
+ Child()
582
+ Button('add new user')
583
+ .onClick(() => {
584
+ this.users.push(new User('Molly', 18));
585
+ })
586
+ Button('age++')
587
+ .onClick(() => {
588
+ this.users[0].age++;
589
+ })
590
+ Button('change name')
591
+ .onClick(() => {
592
+ this.users[0].name = 'Shelly';
593
+ })
594
+ }
595
+ }
596
+ }
597
+
598
+ @ComponentV2
599
+ struct Child {
600
+ @Consumer('data') users: User[] = [];
601
+
602
+ build() {
603
+ Column() {
604
+ ForEach(this.users, (item: User) => {
605
+ Column() {
606
+ Text(`name: ${item.name}`).fontSize(30)
607
+ Text(`age: ${item.age}`).fontSize(30)
608
+ Divider()
609
+ }
610
+ })
611
+ }
612
+ }
613
+ }
614
+ ```
615
+
616
+ ### \@Provider重名时,\@Consumer向上查找其最近的\@Provider
617
+
618
+ \@Provider可以在组件树上重名,\@Consumer会向上查找其最近父节点的\@Provider的数据。
619
+
620
+ <!-- @[Provider_Same](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/ProviderSame.ets) -->
621
+
622
+ ``` TypeScript
623
+ @Entry
624
+ @ComponentV2
625
+ struct Index {
626
+ @Provider() val: number = 10;
627
+
628
+ build() {
629
+ Column() {
630
+ Parent()
631
+ }
632
+ }
633
+ }
634
+
635
+ @ComponentV2
636
+ struct Parent {
637
+ @Provider() val: number = 20;
638
+ @Consumer('val') val2: number = 0; // 10
639
+
640
+ build() {
641
+ Column() {
642
+ Text(`${this.val2}`)
643
+ Child()
644
+ }
645
+ }
646
+ }
647
+
648
+ @ComponentV2
649
+ struct Child {
650
+ @Consumer() val: number = 0; // 20
651
+
652
+ build() {
653
+ Column() {
654
+ Text(`${this.val}`)
655
+ }
656
+ }
657
+ }
658
+ ```
659
+
660
+ 上面的例子中:
661
+
662
+ - Parent中的\@Consumer向上查找,查找到Index中定义的`@Provider() val: number = 10`,初始化为10。
663
+ - Child中的\@Consumer向上查找,查找到Parent中定义的`@Provider() val: number = 20`后停止,初始化为20。
664
+
665
+ ### \@Provider和\@Consumer初始化\@Param
666
+
667
+ \@Provider和\@Consumer装饰的变量可以初始化子组件中\@Param装饰的变量。
668
+
669
+ <!-- @[Decorative_Initialized](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeInitialized.ets) -->
670
+
671
+ ``` TypeScript
672
+ @Entry
673
+ @ComponentV2
674
+ struct Index {
675
+ @Provider() val: number = 10;
676
+
677
+ build() {
678
+ Column() {
679
+ Text(`Index @Provider val: ${this.val}`).fontSize(30)
680
+ // @Provider装饰的变量val可以初始化@Param装饰的变量val2
681
+ Parent({ val2: this.val })
682
+ }
683
+ }
684
+ }
685
+
686
+ @ComponentV2
687
+ struct Parent {
688
+ @Consumer() val: number = 0;
689
+ @Require @Param val2: number;
690
+
691
+ build() {
692
+ Column() {
693
+ Text(`Parent @Consumer val: ${this.val}`).fontSize(30)
694
+ Button('change val').onClick(() => {
695
+ this.val++;
696
+ })
697
+ Text(`Parent @Param val2: ${this.val2}`).fontSize(30)
698
+ // @Consumer装饰的变量val可以初始化@Param装饰的变量val
699
+ Child({ val: this.val })
700
+ }.border({ width: 2, color: Color.Green })
701
+ }
702
+ }
703
+
704
+ @ComponentV2
705
+ struct Child {
706
+ @Require @Param val: number;
707
+
708
+ build() {
709
+ Column() {
710
+ Text(`Child @Param val ${this.val}`).fontSize(30)
711
+ }.border({ width: 2, color: Color.Pink })
712
+ }
713
+ }
714
+ ```
715
+
716
+ 上面的例子中:
717
+
718
+ - Index中\@Provider装饰的变量val与Parent中\@Consumer装饰的变量val建立双向数据绑定。Parent中\@Param装饰的变量val2接收Index中数据源val的数据,并同步其变化。Child中\@Param装饰的变量val接收Parent中数据源val的数据,并同步其变化。
719
+ - 点击Parent中的按钮,触发`@Consumer() val`的变化,变化同步给Index中的`@Provider() val`和Child中的`@Param val`,对应UI刷新。
720
+ - Index中`@Provider() val`的变化同步给Parent中的`@Param val2`,对应UI刷新。
721
+
722
+ ### \@Consumer在跨BuilderNode场景下和\@Provider建立双向同步过程
723
+
724
+ > **说明:**
725
+ >
726
+ > 从API version 23开始,支持跨BuilderNode配对\@Provider和\@Consumer。
727
+
728
+ 下面给出一个示例,实现如下功能:
729
+ 1. BuilderNode通过[全局自定义构建函数](arkts-builder.md#全局自定义构建函数)构建组件树,组件树的根[FrameNode](../../reference/apis-arkui/js-apis-arkui-frameNode.md)节点可通过[getFrameNode](../../reference/apis-arkui/js-apis-arkui-builderNode.md#getframenode)获取,该节点可直接由[NodeController](../../reference/apis-arkui/js-apis-arkui-nodeController.md)返回并挂载于[NodeContainer](../../reference/apis-arkui/arkui-ts/ts-basic-components-nodecontainer.md)节点下。
730
+ 2. 挂载到自定义组件节点树时,BuilderNode会通过addBuilderNode方法挂载在自定义组件下,此时BuilderNode节点下的\@Consumer会向上查找\@Provider,根据key的匹配规则找到最近的\@Provider后,会和\@Provider建立双向同步关系。如果找不到配对的\@Provider,则\@Consumer仍使用默认值。
731
+ 3. 建立双向同步的关系后,如果\@Provider装饰变量的值和\@Consumer的默认值不同,则会回调\@Consumer的\@Monitor方法,以及与\@Consumer有同步关系的变量的\@Monitor方法,例如:\@Consumer通知其子组件中的\@Param触发\@Monitor方法。
732
+ 4. BuilderNode从组件树卸载后,\@Consumer会再次试图查找对应的\@Provider,如果发现从组件树卸载后无法再找到之前配对的\@Provider,则断开和\@Provider的双向同步关系,\@Consumer装饰的变量恢复成默认值。
733
+ 5. \@Consumer断开和\@Provider的连接,恢复成默认值时,会判断\@Consumer装饰变量的值相对于从\@Provider变为\@Consumer的默认值是否有变化,如果有变化,则会回调\@Consumer的\@Monitor方法以及与该\@Consumer存在同步关系的变量的\@Monitor方法。
734
+
735
+ <!-- @[Builder_Node](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/BuilderNode.ets) -->
736
+
737
+ ``` TypeScript
738
+ import { BuilderNode, FrameNode, NodeController } from '@kit.ArkUI';
739
+
740
+ @Builder
741
+ function buildText() {
742
+ TestRemove()
743
+ }
744
+
745
+ let globalBuilderNode: BuilderNode<[]> | null = null;
746
+
747
+ class TextNodeController extends NodeController {
748
+ private rootNode: FrameNode | null = null;
749
+ private uiContext: UIContext | null = null;
750
+
751
+ constructor() {
752
+ super();
753
+ }
754
+
755
+ makeNode(context: UIContext): FrameNode | null {
756
+ this.rootNode = new FrameNode(context);
757
+ this.uiContext = context;
758
+ return this.rootNode;
759
+ }
760
+
761
+ addBuilderNode(): void {
762
+ if (globalBuilderNode === null && this.uiContext) {
763
+ globalBuilderNode = new BuilderNode(this.uiContext);
764
+ // 构建BuilderNode,TestRemove作为子组件
765
+ globalBuilderNode.build(wrapBuilder<[]>(buildText), undefined, { enableProvideConsumeCrossing: true });
766
+ }
767
+ if (this.rootNode && globalBuilderNode) {
768
+ this.rootNode.appendChild(globalBuilderNode.getFrameNode());
769
+ }
770
+ }
771
+
772
+ removeBuilderNode(): void {
773
+ if (this.rootNode && globalBuilderNode) {
774
+ this.rootNode.removeChild(globalBuilderNode.getFrameNode());
775
+ }
776
+ }
777
+
778
+ disposeNode(): void {
779
+ if (this.rootNode && globalBuilderNode) {
780
+ globalBuilderNode.dispose();
781
+ }
782
+ }
783
+ }
784
+
785
+ @Entry
786
+ @ComponentV2
787
+ struct RemoChildDisconnectProvider {
788
+ @Provider() content: string = 'Index: hello world';
789
+ @Monitor('content')
790
+ providerWatch() {
791
+ console.info(`Provider change ${this.content}`);
792
+ }
793
+
794
+ controllerIndex: TextNodeController = new TextNodeController();
795
+
796
+ build() {
797
+ Column({ space: 8 }) {
798
+ Text(`Provider: ${this.content}`)
799
+
800
+ // 添加BuilderNode,@Consumer与@Provider建立双向同步
801
+ Button('add child')
802
+ .onClick(() => {
803
+ this.controllerIndex.addBuilderNode();
804
+ })
805
+
806
+ // 移除BuilderNode,@Consumer与@Provider断开连接,恢复默认值
807
+ Button('remove child')
808
+ .onClick(() => {
809
+ this.controllerIndex.removeBuilderNode();
810
+ })
811
+
812
+ // 释放BuilderNode的子节点TestRemove,随后该子节点销毁,触发子节点的aboutToDisappear回调
813
+ Button('dispose child')
814
+ .onClick(() => {
815
+ this.controllerIndex.disposeNode();
816
+ })
817
+
818
+ // @Provider/@Consumer双向同步更新
819
+ Button('change Provider')
820
+ .onClick(() => {
821
+ this.content += 'Pro';
822
+ })
823
+ NodeContainer(this.controllerIndex)
824
+ }
825
+ .width('100%')
826
+ .height('100%')
827
+ }
828
+ }
829
+
830
+ @ComponentV2
831
+ struct TestRemove {
832
+ @Consumer() content: string = 'default value';
833
+ @Monitor('content')
834
+ consumerWatch() {
835
+ console.info(`Consumer change ${this.content}`);
836
+ }
837
+
838
+ aboutToDisappear() {
839
+ console.info(`TestRemove aboutToDisappear`);
840
+ }
841
+
842
+ build() {
843
+ Column() {
844
+ Text('Consumer ' + this.content)
845
+
846
+ // @Provider和@Consumer绑定的Text组件刷新,并回调@Provider和@Consumer的@Monitor方法
847
+ Button('change cc')
848
+ .onClick(() => {
849
+ this.content += 'cc';
850
+ })
851
+ }
852
+ }
853
+ }
854
+ ```
855
+
856
+
857
+ 上面的例子中:
858
+
859
+ - 点击`add Child`,`TestRemove`中\@Consumer向上找到最近的`RemoChildDisconnectProvider`中的\@Provider,将\@Consumer从默认值更新为\@Provider的值,并回调\@Consumer的\@Monitor方法。
860
+ - \@Provider和\@Consumer配对后,建立双向同步关系。点击`change Provider`和`Text(`change cc`)`,\@Provider和\@Consumer绑定的Text组件刷新,并回调\@Provider和\@Consumer的\@Monitor方法。
861
+ - 点击`remove Child`,BuilderNode子节点从组件树卸载,`TestRemove`中的\@Consumer和`RemoChildDisconnectProvider`中的\@Provider断开连接,`TestRemove`中的\@Consumer恢复成默认值,并回调\@Consumer的\@Monitor方法。
862
+ - 点击`dispose Child`,释放BuilderNode下的子节点`TestRemove`,随后该子节点销毁,执行aboutToDisappear回调。