pyvbaanalysis 1.4.2__tar.gz → 2.0.0__tar.gz

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 (179) hide show
  1. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/CHANGELOG.md +86 -0
  2. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/PKG-INFO +19 -11
  3. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/README.md +16 -8
  4. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/docs/api-reference.md +6 -3
  5. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/docs/usage.md +43 -10
  6. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyproject.toml +1 -1
  7. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/__init__.py +13 -2
  8. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/cli.py +6 -4
  9. pyvbaanalysis-2.0.0/pyvbaanalysis/data/access_host_model.json +1 -0
  10. pyvbaanalysis-2.0.0/pyvbaanalysis/data/powerpoint_host_model.json +1 -0
  11. pyvbaanalysis-2.0.0/pyvbaanalysis/data/word_host_model.json +1 -0
  12. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/analyze_module.py +39 -10
  13. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/context.py +5 -0
  14. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/registry.py +14 -4
  15. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/duplicates.py +4 -2
  16. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/late_binding.py +5 -3
  17. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/undeclared.py +8 -5
  18. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/host/__init__.py +17 -1
  19. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/host/host_model.py +72 -29
  20. pyvbaanalysis-2.0.0/pyvbaanalysis/host/host_registry.py +115 -0
  21. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/project.py +10 -0
  22. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/reader/__init__.py +14 -1
  23. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/reader/vbe_module.py +27 -7
  24. pyvbaanalysis-2.0.0/pyvbaanalysis/reader/workbook.py +230 -0
  25. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_cli.py +1 -1
  26. pyvbaanalysis-2.0.0/tests/test_host_seam.py +469 -0
  27. pyvbaanalysis-2.0.0/tools/extract_host_model.mjs +31 -0
  28. pyvbaanalysis-1.4.2/pyvbaanalysis/reader/workbook.py +0 -106
  29. pyvbaanalysis-1.4.2/tools/extract_host_model.mjs +0 -12
  30. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/.gitattributes +0 -0
  31. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/.github/dependabot.yml +0 -0
  32. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/.github/workflows/ci.yml +0 -0
  33. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/.github/workflows/publish.yml +0 -0
  34. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/.gitignore +0 -0
  35. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/CONTRIBUTING.md +0 -0
  36. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/LICENSE +0 -0
  37. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/docs/diagnostics-catalogue.md +0 -0
  38. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/__main__.py +0 -0
  39. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/call/__init__.py +0 -0
  40. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/call/call_context.py +0 -0
  41. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/completion/__init__.py +0 -0
  42. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/completion/cursor_context.py +0 -0
  43. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/completion/event_handlers.py +0 -0
  44. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/completion/member_access.py +0 -0
  45. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/completion/type_completion.py +0 -0
  46. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/conditional/__init__.py +0 -0
  47. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/conditional/conditional_compilation.py +0 -0
  48. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/constants/__init__.py +0 -0
  49. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/constants/integer_constant_expression.py +0 -0
  50. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/diagnostic_influence_audit.json +0 -0
  51. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/event_definitions.json +0 -0
  52. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/excel_host_model.json +0 -0
  53. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/manifest.json +0 -0
  54. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/rule_metadata.json +0 -0
  55. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/vba_runtime_tables.json +0 -0
  56. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/data/vbe_oracle_cases.json +0 -0
  57. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/__init__.py +0 -0
  58. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/argument_inference.py +0 -0
  59. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/call_extraction.py +0 -0
  60. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/callable_signatures.py +0 -0
  61. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/const_expr.py +0 -0
  62. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/dataflow.py +0 -0
  63. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/exprwalk.py +0 -0
  64. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/inline_suppression.py +0 -0
  65. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/model.py +0 -0
  66. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rule_metadata.py +0 -0
  67. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/__init__.py +0 -0
  68. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/argument_shape.py +0 -0
  69. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/argument_types.py +0 -0
  70. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/arrays.py +0 -0
  71. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/assignments.py +0 -0
  72. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/binary_operand_scalar.py +0 -0
  73. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/call_arity.py +0 -0
  74. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/control_flow.py +0 -0
  75. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/declarations.py +0 -0
  76. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/expressions.py +0 -0
  77. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/lexical.py +0 -0
  78. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/module_kind.py +0 -0
  79. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/numeric_literals.py +0 -0
  80. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/object_state.py +0 -0
  81. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/parameter_defaults.py +0 -0
  82. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/runtime_values.py +0 -0
  83. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/shared.py +0 -0
  84. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/rules/type_of_is.py +0 -0
  85. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/diagnostics/walker.py +0 -0
  86. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/evidence.py +0 -0
  87. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/flow/__init__.py +0 -0
  88. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/flow/procedure_labels.py +0 -0
  89. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/flow/procedure_unstructured.py +0 -0
  90. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/identity_cache.py +0 -0
  91. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/__init__.py +0 -0
  92. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/keyword_table.py +0 -0
  93. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/stripped_lines.py +0 -0
  94. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/token_helpers.py +0 -0
  95. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/token_kinds.py +0 -0
  96. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/tokenize.py +0 -0
  97. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/lexer/trivia.py +0 -0
  98. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/__init__.py +0 -0
  99. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/fixed_length_string.py +0 -0
  100. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/nodes.py +0 -0
  101. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/parse_expression.py +0 -0
  102. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/parse_module.py +0 -0
  103. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/parser_state.py +0 -0
  104. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/parser/type_declaration_suffix.py +0 -0
  105. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/py.typed +0 -0
  106. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/reader/loose_file.py +0 -0
  107. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/runtime/__init__.py +0 -0
  108. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/runtime/vba_runtime.py +0 -0
  109. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/symbols/__init__.py +0 -0
  110. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/symbols/build_module_symbols.py +0 -0
  111. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/symbols/name_resolution.py +0 -0
  112. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/symbols/project_index.py +0 -0
  113. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/symbols/symbol_model.py +0 -0
  114. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/types/__init__.py +0 -0
  115. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/types/type_inference.py +0 -0
  116. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/pyvbaanalysis/types/type_names.py +0 -0
  117. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/conftest.py +0 -0
  118. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/oracle_support.py +0 -0
  119. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_conditional_compilation.py +0 -0
  120. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_dataflow.py +0 -0
  121. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_diagnostics_engine.py +0 -0
  122. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_evidence.py +0 -0
  123. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_host_model.py +0 -0
  124. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_inline_suppression.py +0 -0
  125. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_integer_constant_expression.py +0 -0
  126. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_language_matrix.py +0 -0
  127. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_lexer.py +0 -0
  128. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_member_access_chains.py +0 -0
  129. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_parser.py +0 -0
  130. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_project.py +0 -0
  131. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_project_index.py +0 -0
  132. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_public_api.py +0 -0
  133. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_reader.py +0 -0
  134. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_real_world_false_positives.py +0 -0
  135. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_registry_parity.py +0 -0
  136. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rule_metadata.py +0 -0
  137. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_ambiguous_enum_member.py +0 -0
  138. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_argument_shape.py +0 -0
  139. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_argument_types.py +0 -0
  140. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_arrays.py +0 -0
  141. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_assignments.py +0 -0
  142. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_assignments_types.py +0 -0
  143. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_binary_operand_scalar.py +0 -0
  144. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_call_arity.py +0 -0
  145. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_control_flow.py +0 -0
  146. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_declarations.py +0 -0
  147. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_division_by_zero.py +0 -0
  148. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_duplicates.py +0 -0
  149. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_event_handler_module_scope.py +0 -0
  150. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_expression_calls.py +0 -0
  151. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_expressions.py +0 -0
  152. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_invalid_as_type_names.py +0 -0
  153. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_is_operator_non_object.py +0 -0
  154. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_late_binding.py +0 -0
  155. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_lexical.py +0 -0
  156. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_member_not_found.py +0 -0
  157. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_module_kind.py +0 -0
  158. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_numeric_literals.py +0 -0
  159. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_object_state.py +0 -0
  160. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_parameter_defaults.py +0 -0
  161. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_property_setter_value_parameters.py +0 -0
  162. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_runtime_values.py +0 -0
  163. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_scalar_and_foreach.py +0 -0
  164. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_type_of_is.py +0 -0
  165. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_typeof_is_always_false.py +0 -0
  166. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_rules_undeclared.py +0 -0
  167. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_runtime_tables.py +0 -0
  168. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_statement_token_derivation.py +0 -0
  169. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_stripped_lines.py +0 -0
  170. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_symbols.py +0 -0
  171. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_token_helpers.py +0 -0
  172. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_type_completion.py +0 -0
  173. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tests/test_type_names.py +0 -0
  174. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/extract_event_definitions.mjs +0 -0
  175. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/extract_rule_metadata.mjs +0 -0
  176. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/extract_runtime_tables.mjs +0 -0
  177. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/generate_diagnostics_catalogue.py +0 -0
  178. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/generate_manifest.py +0 -0
  179. {pyvbaanalysis-1.4.2 → pyvbaanalysis-2.0.0}/tools/oracle/build_combining_mark_probe.py +0 -0
@@ -5,6 +5,92 @@ All notable changes to pyVBAanalysis are recorded here. The format follows
5
5
  follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html): a minor version
6
6
  per milestone.
7
7
 
8
+ ## 2.0.0 - 2026-08-19
9
+
10
+ Multi-host analysis: VBA is now measured against the object model of the Office
11
+ host it actually belongs to. Ports the XLIDE host-model seam and the Word,
12
+ PowerPoint and Access models (xlide_vscode 790e6ea and e56098b, its issues #24
13
+ and #25).
14
+
15
+ ### Added
16
+
17
+ * A host seam on the analysis entry points. `analyze_project` and
18
+ `analyze_module_options_for` take a `host` token (`"excel"`, `"word"`,
19
+ `"powerpoint"`, `"access"`, ...), and `AnalyzeModuleOptions` carries `host`
20
+ alongside the existing `host_model`. The semantics are deliberately
21
+ asymmetric: absent means Excel, so every existing caller is unchanged, while a
22
+ NAMED host with no model asserts no host knowledge rather than falling back to
23
+ Excel's. An explicit `host_model` still outranks the token.
24
+ * Word, PowerPoint and Access object models, vendored as
25
+ `data/{word,powerpoint,access}_host_model.json` and extracted mechanically by
26
+ `tools/extract_host_model.mjs` from the generated XLIDE host modules, the same
27
+ pipeline that has always produced the Excel model. 364, 201 and 188
28
+ member-bearing types; 3,742, 1,480 and 1,116 enum constants. Every type is
29
+ non-exhaustive by construction, so absence never becomes a finding.
30
+ * `analyze_office_file(path)` and `read_office_modules(path)` read any container
31
+ pyOpenVBA opens: Excel (`.xlsm`, `.xlsb`, `.xlam`, `.xls`), Word (`.docm`,
32
+ `.dotm`, `.doc`), PowerPoint (`.pptm`, `.potm`) and Access (`.accdb`, `.mdb`,
33
+ read-only). The extension selects the host, so a Word document is analyzed
34
+ against Word's model without the caller saying anything. The CLI accepts them
35
+ all on the same footing.
36
+ * `host_token_for_file_name` and `host_object_model_for_token` on the public API.
37
+
38
+ ### Fixed
39
+
40
+ * Word VBA no longer false-positives against Excel's object model. Analyzing a
41
+ Word module as a project previously reported four findings on legal code:
42
+ `ActiveDocument` twice and `wdOrientPortrait` as undeclared variables, and
43
+ `Selection.TypeText` as `member-not-found` against `Excel.Range`. Under the
44
+ Word host it reports none.
45
+ * Host metadata is per-model throughout, closing the Excel defaults that
46
+ remained under the seam. Application-member injection is keyed by model
47
+ (`Volatile` is a known bare call under Excel and unknown under Word), and the
48
+ four rules that consulted host metadata with a bare Excel default now take the
49
+ caller's model: undeclared variables, unknown call, ambiguous enum references,
50
+ and late-bound Friend members. `Me` types host-correctly in a document module:
51
+ `ThisWorkbook` is `Excel.Workbook` under Excel, `ThisDocument` is
52
+ `Word.Document` under Word, and nothing is asserted anywhere else.
53
+ * Word's `ThisDocument` classifies as a document module. It declares
54
+ `VB_Base = "1Normal.ThisDocument"`, naming no CLSID, so GUID matching missed
55
+ it; the host-generic signature is the `VB_PredeclaredId` + `VB_Exposed` pair
56
+ that Office gives every document module. A `.bas` extension or the container's
57
+ own standard-module flag still outranks that signature, since either states
58
+ outright that the module is standard. Differentialled across 116 modules in 16
59
+ real workbooks: nothing reclassified.
60
+ * A named host with no object model no longer reports what it cannot know. An
61
+ empty model is not uniformly quieter than Excel's: member lookups go silent
62
+ because no type resolves, but the rules that ask whether a bare name is legal
63
+ would answer no for every global the host injects, turning an Outlook
64
+ project's own surface into a wall of `undeclared-variable` findings. The four
65
+ rules that need host knowledge now stay silent under an unmodelled host, for
66
+ the same reason they already do on a partial project view.
67
+ * The host-model memos no longer key on a bare `id(model)`. Three caches
68
+ (`_host_model_index`, `_host_constant_index`, and the host-member name set)
69
+ used a plain `dict[int, ...]` that kept no reference to the model, so entries
70
+ accumulated one per model object ever seen and a collected model's id could be
71
+ recycled by a later one, serving one model's index for another. They now use
72
+ the repo's `IdentityLru`, which holds its keys alive and stays bounded. Latent
73
+ before this release, since only the permanently-live Excel singleton was ever
74
+ passed; reachable now that callers choose models.
75
+
76
+ ### Changed
77
+
78
+ * `analyze_workbook` and `read_workbook_modules` keep their Excel-only contract
79
+ unchanged. Handed a container the generic reader could open, they now name
80
+ `analyze_office_file` in the error rather than only rejecting the extension.
81
+ * README, the usage guide, the API reference and agent.md describe the four
82
+ hosts; agent.md's pyOpenVBA floor was stale at 3.0.1 and now reads 3.4.0.
83
+
84
+ ### Known limits
85
+
86
+ * Legacy `.ppt` is not readable. pyOpenVBA 3.4.0 lists it but reads it as a
87
+ plain CFB, while the VBA project lives in a zlib-compressed CFB inside an
88
+ `ExOleObjStg` record, so every open fails on the missing `dir` stream. The
89
+ extension is rejected up front rather than failing later with a parse error
90
+ that reads like file corruption. Reported as pyOpenVBA issue #17.
91
+ * Access is read-only, following pyOpenVBA: Access executes compiled p-code, so
92
+ a source write would silently change nothing.
93
+
8
94
  ## 1.4.2 - 2026-08-03
9
95
 
10
96
  ### Fixed
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: pyvbaanalysis
3
- Version: 1.4.2
3
+ Version: 2.0.0
4
4
  Summary: Pure-Python static analysis for Excel VBA
5
5
  Project-URL: Homepage, https://github.com/WilliamSmithEdward/pyVBAanalysis
6
6
  Project-URL: Repository, https://github.com/WilliamSmithEdward/pyVBAanalysis
@@ -24,16 +24,18 @@ Requires-Dist: twine>=5; extra == 'build'
24
24
  Provides-Extra: dev
25
25
  Requires-Dist: mypy==2.3.0; extra == 'dev'
26
26
  Requires-Dist: pytest==9.1.1; extra == 'dev'
27
- Requires-Dist: ruff==0.16.0; extra == 'dev'
27
+ Requires-Dist: ruff==0.16.2; extra == 'dev'
28
28
  Description-Content-Type: text/markdown
29
29
 
30
30
  # pyVBAanalysis
31
31
 
32
- Static analysis for Excel VBA. It reads your macros and reports likely bugs and the
33
- errors the VBA compiler would catch, without opening Excel or running any code.
32
+ Static analysis for Office VBA. It reads your macros and reports likely bugs and the
33
+ errors the VBA compiler would catch, without opening Office or running any code.
34
34
 
35
- Point it at a workbook or a set of exported module files, and it returns the
36
- problems it finds, each with the exact line and a plain explanation.
35
+ Point it at an Excel workbook, a Word document, a PowerPoint deck, an Access
36
+ database, or a set of exported module files, and it returns the problems it finds,
37
+ each with the exact line and a plain explanation. Each file is measured against its
38
+ own host's object model, so Word code is never judged by Excel's surface.
37
39
 
38
40
  ## What it checks
39
41
 
@@ -63,9 +65,9 @@ Python 3.10 or later. Nothing else to set up.
63
65
  Analyze a workbook:
64
66
 
65
67
  ```python
66
- from pyvbaanalysis import analyze_workbook
68
+ from pyvbaanalysis import analyze_office_file
67
69
 
68
- for module, problems in analyze_workbook("Budget.xlsm").items():
70
+ for module, problems in analyze_office_file("Budget.xlsm").items():
69
71
  for p in problems:
70
72
  print(module, p.severity.value, p.code, p.message)
71
73
  ```
@@ -105,8 +107,14 @@ clean, so it drops into a CI check.
105
107
 
106
108
  ## Scope
107
109
 
108
- This analyzes Excel VBA. It does not run macros and does not need Excel installed.
109
- Word and PowerPoint are not supported.
110
+ This analyzes the VBA inside Office files. It does not run macros and does not need
111
+ Office installed.
112
+
113
+ Each file is measured against its own host's object model, so a Word document is
114
+ never judged by Excel's surface. Readable containers: Excel (.xlsm, .xlsb, .xlam,
115
+ .xls), Word (.docm, .dotm, .doc), PowerPoint (.pptm, .potm) and Access (.accdb,
116
+ .mdb, read-only). Legacy .ppt is not readable yet, because its VBA project sits in
117
+ a compressed record the reader does not open.
110
118
 
111
119
  ## Documentation
112
120
 
@@ -1,10 +1,12 @@
1
1
  # pyVBAanalysis
2
2
 
3
- Static analysis for Excel VBA. It reads your macros and reports likely bugs and the
4
- errors the VBA compiler would catch, without opening Excel or running any code.
3
+ Static analysis for Office VBA. It reads your macros and reports likely bugs and the
4
+ errors the VBA compiler would catch, without opening Office or running any code.
5
5
 
6
- Point it at a workbook or a set of exported module files, and it returns the
7
- problems it finds, each with the exact line and a plain explanation.
6
+ Point it at an Excel workbook, a Word document, a PowerPoint deck, an Access
7
+ database, or a set of exported module files, and it returns the problems it finds,
8
+ each with the exact line and a plain explanation. Each file is measured against its
9
+ own host's object model, so Word code is never judged by Excel's surface.
8
10
 
9
11
  ## What it checks
10
12
 
@@ -34,9 +36,9 @@ Python 3.10 or later. Nothing else to set up.
34
36
  Analyze a workbook:
35
37
 
36
38
  ```python
37
- from pyvbaanalysis import analyze_workbook
39
+ from pyvbaanalysis import analyze_office_file
38
40
 
39
- for module, problems in analyze_workbook("Budget.xlsm").items():
41
+ for module, problems in analyze_office_file("Budget.xlsm").items():
40
42
  for p in problems:
41
43
  print(module, p.severity.value, p.code, p.message)
42
44
  ```
@@ -76,8 +78,14 @@ clean, so it drops into a CI check.
76
78
 
77
79
  ## Scope
78
80
 
79
- This analyzes Excel VBA. It does not run macros and does not need Excel installed.
80
- Word and PowerPoint are not supported.
81
+ This analyzes the VBA inside Office files. It does not run macros and does not need
82
+ Office installed.
83
+
84
+ Each file is measured against its own host's object model, so a Word document is
85
+ never judged by Excel's surface. Readable containers: Excel (.xlsm, .xlsb, .xlam,
86
+ .xls), Word (.docm, .dotm, .doc), PowerPoint (.pptm, .potm) and Access (.accdb,
87
+ .mdb, read-only). Legacy .ppt is not readable yet, because its VBA project sits in
88
+ a compressed record the reader does not open.
81
89
 
82
90
  ## Documentation
83
91
 
@@ -11,11 +11,14 @@ These are re-exported at the package root for convenience:
11
11
  | Symbol | Role |
12
12
  | --- | --- |
13
13
  | `analyze_module(source, opts=None)` | Analyze one module's source; returns `list[VbaDiagnostic]`. Never raises. |
14
- | `analyze_project(modules, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True)` | Analyze a set of `ModuleInput`s with cross-module context; returns `dict[str, list[VbaDiagnostic]]`. `whole_project=False` for a partial set. |
14
+ | `analyze_project(modules, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None)` | Analyze a set of `ModuleInput`s with cross-module context; returns `dict[str, list[VbaDiagnostic]]`. `whole_project=False` for a partial set. `host` names the Office host (absent means Excel). |
15
15
  | `analyze_loose_file(path, *, severity_overrides=None, conditional_compilation=None, whole_project=False, inline_suppression=True)` | Analyze one `.bas`/`.cls`/`.frm` file (partial by default; the whole-project checks are skipped). |
16
16
  | `analyze_loose_files(paths, *, only=None, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True)` | Analyze several loose files as one project. |
17
17
  | `analyze_workbook(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` | Analyze the VBA in an Excel workbook (via pyOpenVBA). |
18
- | `analyze_module_options_for(index, name, kind, *, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True)` | Build per-module `AnalyzeModuleOptions` from a populated `ProjectIndex`. |
18
+ | `analyze_office_file(path, *, only=None, severity_overrides=None, conditional_compilation=None, inline_suppression=True)` | The same for any readable Office container (Excel, Word, PowerPoint, Access); the extension selects the host model. |
19
+ | `host_token_for_file_name(name)` | The host a container implies (`excel`, `word`, `powerpoint`, `access`), or `None`. |
20
+ | `host_object_model_for_token(host)` | The model a host token selects: `None` for Excel (the default), the host's own model, or the empty model when a named host has none. |
21
+ | `analyze_module_options_for(index, name, kind, *, severity_overrides=None, conditional_compilation=None, whole_project=True, inline_suppression=True, host=None)` | Build per-module `AnalyzeModuleOptions` from a populated `ProjectIndex`. |
19
22
  | `build_project_index(modules)` | A `ProjectIndex` with every module registered. |
20
23
  | `AnalyzeModuleOptions` | Inputs for `analyze_module` (name, kind, project context, overrides). |
21
24
  | `VbaDiagnostic` | A single diagnostic (`code`, `message`, `severity`, `span`, `spec_reference`). |
@@ -69,7 +72,7 @@ them directly, but they are public and stable.
69
72
  | `pyvbaanalysis.conditional` | Conditional-compilation indexing and activity (`index_conditional_compilation`, `evaluate_conditional_expression`, ...). |
70
73
  | `pyvbaanalysis.types` | Type-name helpers: `normalize_type`, `is_known_scalar_type`, `is_numeric_type`, `numeric_literal_bounds`. |
71
74
  | `pyvbaanalysis.completion` | Member-completion surface and project-type resolution (`resolve_member_surface_at`, `resolve_type_name`, ...). |
72
- | `pyvbaanalysis.host` | The Excel host object model (`get_excel_object_model`, `resolve_host_alias`, ...). |
75
+ | `pyvbaanalysis.host` | The Excel, Word, PowerPoint and Access host object models and the host registry (`get_excel_object_model`, `host_object_model_for_token`, `resolve_host_alias`, ...). |
73
76
  | `pyvbaanalysis.runtime` | VBA runtime functions, constants, and objects (`resolve_runtime_function`, ...). |
74
77
  | `pyvbaanalysis.call` | Call-statement shape helpers. |
75
78
  | `pyvbaanalysis.flow` | Procedure labels and unstructured-flow detection. |
@@ -136,21 +136,53 @@ analyze_loose_files(["Module1.bas", "Widget.cls"]) # several, as one project
136
136
  skipped for it (see "Whole project vs a single file" below). Use `analyze_loose_files`
137
137
  to analyze several files together with shared cross-module context.
138
138
 
139
- ### Excel workbooks (.xlsm / .xlsb / .xlam / .xls)
139
+ ### Office macro containers
140
140
 
141
- The workbook reader reads VBA directly out of an Excel file via pyOpenVBA (the one
141
+ The container reader reads VBA directly out of an Office file via pyOpenVBA (the one
142
142
  runtime dependency). pyOpenVBA is imported lazily, so `import pyvbaanalysis` stays
143
- light. The analyzer targets Excel VBA; Word and PowerPoint are out of scope.
143
+ light.
144
+
145
+ | Host | Extensions |
146
+ | --- | --- |
147
+ | Excel | `.xlsm`, `.xlsb`, `.xlam`, `.xls` |
148
+ | Word | `.docm`, `.dotm`, `.doc` |
149
+ | PowerPoint | `.pptm`, `.potm` |
150
+ | Access | `.accdb`, `.mdb` (read-only) |
144
151
 
145
152
  ```python
146
- from pyvbaanalysis import analyze_workbook
153
+ from pyvbaanalysis import analyze_office_file
147
154
 
148
- analyze_workbook("Book.xlsm") # dict: module name -> diagnostics
149
- analyze_workbook("Book.xlsm", only=["Sheet1"]) # one module by name, full context
155
+ analyze_office_file("Book.xlsm") # dict: module name -> diagnostics
156
+ analyze_office_file("Report.docm") # resolved against Word's model
157
+ analyze_office_file("Book.xlsm", only=["Sheet1"]) # one module by name, full context
150
158
  ```
151
159
 
152
- A path that is not an Excel workbook, or a container with no readable VBA, raises
153
- `WorkbookReadError`.
160
+ The extension selects the host, so Word code is measured against Word's object model
161
+ and never against Excel's. Analyzing a Word module under Excel's model reports
162
+ members and constants that are perfectly legal in Word (`Selection.TypeText`,
163
+ `ActiveDocument`, `wdOrientPortrait`), which is the false positive this avoids.
164
+
165
+ `analyze_workbook` remains the Excel-only entry point and is unchanged.
166
+
167
+ A path that is not a readable container, or a container with no readable VBA, raises
168
+ `WorkbookReadError`. Legacy `.ppt` is not readable: pyOpenVBA reads it as a plain
169
+ CFB, but its VBA project sits inside a compressed record, so the extension is
170
+ rejected rather than failing later with a parse error
171
+ ([pyOpenVBA #17](https://github.com/WilliamSmithEdward/pyOpenVBA/issues/17)).
172
+
173
+ ### Choosing the host yourself
174
+
175
+ When you already have the module text, name the host directly. Absent means Excel,
176
+ so existing calls are unchanged; a named host with no model asserts no host
177
+ knowledge at all rather than falling back to Excel's.
178
+
179
+ ```python
180
+ from pyvbaanalysis import analyze_project
181
+
182
+ analyze_project(modules, host="word") # Word's object model
183
+ analyze_project(modules, host="outlook") # no model yet: stays quiet, never Excel's
184
+ analyze_project(modules) # Excel, exactly as before
185
+ ```
154
186
 
155
187
  The reader loads the workbook and its VBA into memory and does not bound the input
156
188
  size, so impose your own limit (for example a maximum file size) before pointing it
@@ -227,8 +259,9 @@ pyvbaanalysis Book.xlsm --format json
227
259
  ```
228
260
 
229
261
  A path may be a loose file, a folder of loose files (analyzed together as one
230
- project), or an Excel workbook. `pyvbaanalysis --version` prints the version, and
231
- `python -m pyvbaanalysis` is equivalent to the `pyvbaanalysis` command.
262
+ project), or an Office macro container, whose extension selects the host model.
263
+ `pyvbaanalysis --version` prints the version, and `python -m pyvbaanalysis` is
264
+ equivalent to the `pyvbaanalysis` command.
232
265
 
233
266
  Flags:
234
267
 
@@ -38,7 +38,7 @@ dependencies = ["pyOpenVBA>=3.4.0"]
38
38
  # underneath main (ruff 0.16 broke a green tree with zero repo commits).
39
39
  # Dependabot's weekly pip updates turn each tool upgrade into its own gated
40
40
  # PR, where a red CI run blocks the bump instead of breaking main.
41
- dev = ["pytest==9.1.1", "ruff==0.16.0", "mypy==2.3.0"]
41
+ dev = ["pytest==9.1.1", "ruff==0.16.2", "mypy==2.3.0"]
42
42
  build = ["build>=1.2", "twine>=5"]
43
43
 
44
44
  [project.scripts]
@@ -9,6 +9,8 @@ The headline entry points are re-exported here for convenience:
9
9
  * analyze_project(modules): analyze a set of modules with cross-module context.
10
10
  * analyze_workbook(path): analyze the VBA in an Excel workbook (read via pyOpenVBA,
11
11
  the one external runtime dependency).
12
+ * analyze_office_file(path): the same for any Office macro container (Excel, Word,
13
+ PowerPoint, or read-only Access), resolving against that host's object model.
12
14
  * analyze_loose_file(path) / analyze_loose_files(paths): analyze loose
13
15
  .bas / .cls / .frm export files.
14
16
 
@@ -30,10 +32,16 @@ from .diagnostics import (
30
32
  validate_severity_overrides,
31
33
  )
32
34
  from .project import analyze_module_options_for, analyze_project, build_project_index
33
- from .reader import analyze_loose_file, analyze_loose_files, analyze_workbook
35
+ from .host import host_object_model_for_token, host_token_for_file_name
36
+ from .reader import (
37
+ analyze_loose_file,
38
+ analyze_loose_files,
39
+ analyze_office_file,
40
+ analyze_workbook,
41
+ )
34
42
  from .symbols import ModuleInput, ModuleSymbolKind, ProjectIndex, ProjectIndexOptions
35
43
 
36
- __version__ = "1.4.2"
44
+ __version__ = "2.0.0"
37
45
 
38
46
  __all__ = [
39
47
  "AnalyzeModuleOptions",
@@ -50,9 +58,12 @@ __all__ = [
50
58
  "analyze_loose_files",
51
59
  "analyze_module",
52
60
  "analyze_module_options_for",
61
+ "analyze_office_file",
53
62
  "analyze_project",
54
63
  "analyze_workbook",
55
64
  "build_project_index",
65
+ "host_object_model_for_token",
66
+ "host_token_for_file_name",
56
67
  "line_col",
57
68
  "rule_metadata_by_code",
58
69
  "validate_severity_overrides",
@@ -30,13 +30,14 @@ from .diagnostics import (
30
30
  validate_severity_overrides,
31
31
  )
32
32
  from .project import analyze_project
33
+ from .host import host_token_for_file_name
33
34
  from .reader import (
34
- EXCEL_EXTENSIONS,
35
35
  LOOSE_EXTENSIONS,
36
+ OFFICE_EXTENSIONS,
36
37
  LooseFileReadError,
37
38
  WorkbookReadError,
38
39
  load_loose_module,
39
- read_workbook_modules,
40
+ read_office_modules,
40
41
  )
41
42
  from .symbols import ModuleInput
42
43
 
@@ -151,7 +152,7 @@ def _analyze_workbook_group(
151
152
  errors: list[str] = []
152
153
  for path in paths:
153
154
  try:
154
- modules = read_workbook_modules(path)
155
+ modules = read_office_modules(path)
155
156
  except WorkbookReadError as exc:
156
157
  errors.append(f"{path}: {exc}")
157
158
  continue
@@ -163,6 +164,7 @@ def _analyze_workbook_group(
163
164
  only=only or None,
164
165
  severity_overrides=severity_overrides or None,
165
166
  inline_suppression=inline_suppression,
167
+ host=host_token_for_file_name(path.name),
166
168
  )
167
169
  sources = {m.name: m.source for m in modules}
168
170
  results.append(_ProjectResult(str(path), diagnostics, sources))
@@ -332,7 +334,7 @@ def main(argv: Sequence[str] | None = None) -> int:
332
334
  print("error: unknown diagnostic code(s): " + ", ".join(unknown_codes), file=sys.stderr)
333
335
  return 2
334
336
 
335
- workbook_paths = [p for p in paths if p.is_file() and p.suffix.lower() in EXCEL_EXTENSIONS]
337
+ workbook_paths = [p for p in paths if p.is_file() and p.suffix.lower() in OFFICE_EXTENSIONS]
336
338
  other_paths = [p for p in paths if p not in workbook_paths]
337
339
  loose_paths = _gather_loose_paths(other_paths)
338
340
  unknown = [p for p in loose_paths if p.suffix.lower() not in LOOSE_EXTENSIONS]