Skip to content

feat(extract): add ActionScript 3 and MXML extractors#2035

Open
nitrobear wants to merge 1 commit into
Graphify-Labs:v8from
nitrobear:feat/actionscript-mxml
Open

feat(extract): add ActionScript 3 and MXML extractors#2035
nitrobear wants to merge 1 commit into
Graphify-Labs:v8from
nitrobear:feat/actionscript-mxml

Conversation

@nitrobear

Copy link
Copy Markdown

ActionScript/Flex has no extractor today, and because classify_file returns None for an unknown extension, a .as or .mxml file currently produces no node at all — not even a file node. Pointing graphify at a Flex or AIR application yields a graph with no application structure in it.

There is no tree-sitter grammar to build on: the two on GitHub are unmaintained and one targets decompiler output, so this follows the regex route dart.py, razor.py and pascal.py already take. The pairing mirrors pascal.py + pascal_forms.py — a legacy language plus its UI format.

Three things carry the value:

  • Node identity. AS3 requires the package path to mirror the directory layout, so com.example.util.Tools resolves to its defining file and the import edge points at that file's own node. Reference nodes are attributed to the file that DEFINES the symbol, and shared entities with no defining file (SDK types, events, singletons) are marked type: "module", so _disambiguate_colliding_node_ids leaves them alone. Without both, one event dispatched from N files becomes N nodes.

  • Event wiring. Flex couples components through string constants, which no import graph records. Dispatch sites usually write the literal and listen sites the constant, so constants are resolved to their value (reading the declaring file, cached) and both halves meet on one node. A file that both emits and subscribes to an event gets a single relays edge, since the build keeps one edge per node pair and arbitrating would report a dispatcher with no listener.

  • MXML. xmlns:ui="com.example.ui.*" maps a tag prefix to a package, so a <ui:Widget/> is a reference with no import line; includeIn= binds a component to a view state; @Embed(...), skinClass= and resourceManager.getString() are compile-time dependencies. Script blocks are handed to the ActionScript extractor rather than re-parsed, so the two cannot drift. Tags in SDK namespaces and Spark skin interaction states (up, over, disabled) are skipped: they would bury an application's own components under hundreds of layout nodes.

Relations emitted: imports, inherits, implements, contains, instantiates, references, embeds, dispatches, listens, relays, declares_event, uses_global, declares_state, renders, references_i18n.

Validated on a 264-file Flex point-of-sale application: 1536 of 1536 import statements extracted, 163 of 163 files with extends, and 78% of events resolved to both a dispatcher and a listener (the rest are SDK events whose constants live outside the corpus).

tests/test_actionscript.py adds 17 tests, covering declarations, node identity, event convergence, edge arbitration and MXML.

Full suite on v8: 3401 passed / 15 failed. With this branch: 3418 passed / 15 failed — the same 15 (test_skillgen.py, test_ollama_retry_cap.py) fail on a clean v8 worktree and are unrelated to extraction.

ActionScript/Flex has no extractor today, and because `classify_file` returns
None for an unknown extension, a `.as` or `.mxml` file currently produces no
node at all — not even a file node. Pointing graphify at a Flex or AIR
application yields a graph with no application structure in it.

There is no tree-sitter grammar to build on: the two on GitHub are unmaintained
and one targets decompiler output, so this follows the regex route dart.py,
razor.py and pascal.py already take. The pairing mirrors pascal.py +
pascal_forms.py — a legacy language plus its UI format.

Three things carry the value:

- Node identity. AS3 requires the package path to mirror the directory layout,
  so `com.example.util.Tools` resolves to its defining file and the import edge
  points at that file's own node. Reference nodes are attributed to the file
  that DEFINES the symbol, and shared entities with no defining file (SDK types,
  events, singletons) are marked `type: "module"`, so
  `_disambiguate_colliding_node_ids` leaves them alone. Without both, one event
  dispatched from N files becomes N nodes.

- Event wiring. Flex couples components through string constants, which no
  import graph records. Dispatch sites usually write the literal and listen
  sites the constant, so constants are resolved to their value (reading the
  declaring file, cached) and both halves meet on one node. A file that both
  emits and subscribes to an event gets a single `relays` edge, since the build
  keeps one edge per node pair and arbitrating would report a dispatcher with
  no listener.

- MXML. `xmlns:ui="com.example.ui.*"` maps a tag prefix to a package, so a
  `<ui:Widget/>` is a reference with no import line; `includeIn=` binds a
  component to a view state; `@Embed(...)`, `skinClass=` and
  `resourceManager.getString()` are compile-time dependencies. Script blocks are
  handed to the ActionScript extractor rather than re-parsed, so the two cannot
  drift. Tags in SDK namespaces and Spark skin interaction states (`up`, `over`,
  `disabled`) are skipped: they would bury an application's own components under
  hundreds of layout nodes.

Relations emitted: imports, inherits, implements, contains, instantiates,
references, embeds, dispatches, listens, relays, declares_event, uses_global,
declares_state, renders, references_i18n.

Validated on a 264-file Flex point-of-sale application: 1536 of 1536 import
statements extracted, 163 of 163 files with `extends`, and 78% of events
resolved to both a dispatcher and a listener (the rest are SDK events whose
constants live outside the corpus).

tests/test_actionscript.py adds 17 tests, covering declarations, node identity,
event convergence, edge arbitration and MXML.

Full suite on v8: 3401 passed / 15 failed. With this branch: 3418 passed / 15
failed — the same 15 (test_skillgen.py, test_ollama_retry_cap.py) fail on a
clean v8 worktree and are unrelated to extraction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant