Class: JsxRosetta::IR::Lowering
- Inherits:
-
Object
- Object
- JsxRosetta::IR::Lowering
- Defined in:
- lib/jsx_rosetta/ir/lowering.rb
Overview
Lowers a parsed AST::File into an IR::Component tree.
Phase 2 scope:
- Single function-declaration component per file.
- JSX elements with lowercase tags lower to IR::Element; others to
IR::ComponentInvocation.
- className attributes lower to IR::StyleBinding; everything else
to IR::Attribute (event handlers like onClick are passed through
as Attribute for now and will be re-lowered to EventBinding in
a later phase).
- JS expressions are preserved as opaque source text via
IR::Interpolation. No JS-to-Ruby translation.
- Pure-whitespace JSXText between elements is dropped (matches
JSX runtime behavior); other text is preserved verbatim.
Phase 4a additions:
- {children} where `children` is a prop lowers to IR::Slot.
- {cond && X}, {cond ? X : null}, and {cond ? X : Y} lower to
IR::Conditional. Other LogicalExpression operators (||, ??) are
left as opaque interpolations.
Defined Under Namespace
Classes: LoweringError
Constant Summary collapse
- REACT_HOOKS =
%w[ useState useEffect useRef useContext useMemo useCallback useReducer useImperativeHandle useLayoutEffect useDebugValue ].freeze
- EXPORT_TYPES =
%w[ExportNamedDeclaration ExportDefaultDeclaration].freeze
- JSX_NODE_TYPES =
%w[JSXElement JSXFragment JSXText JSXExpressionContainer].freeze
- HOC_NAMES =
%w[memo forwardRef lazy observer].freeze
- JSX_RETURN_PROBES =
Pre-lowering AST scan: maps a node type to a callable returning the AST nodes that contribute return values. Used by body_returns_jsx?.
{ "ReturnStatement" => ->(n) { [n[:argument]] }, "BlockStatement" => ->(n) { n[:body] }, "IfStatement" => ->(n) { [n[:consequent], n[:alternate]] }, "TryStatement" => ->(n) { [n[:block]] }, "ConditionalExpression" => ->(n) { [n[:consequent], n[:alternate]] }, "LogicalExpression" => ->(n) { [n[:left], n[:right]] } }.freeze
- SHAPE_MESSAGES =
{ hoc_wrapped: "looks like a HOC-wrapped component (React.memo / forwardRef / lazy / observer) — " \ "this version doesn't peel HOC wrappers; remove the wrapper or upgrade when supported", class_component: "looks like a class component — this version translates only function components " \ "(rewrite as a function or wait for class-component support)", hooks_only: "looks like a custom-hooks module — hooks encode behavior and state, not view markup; " \ "translate behavior to a Stimulus controller and state to server-rendered ivars", columns_data: "looks like a data export (top-level array literal) — not a component; " \ "data lives in the model or a presenter, not a ViewComponent", types_only: "looks like a types/constants module — no functions to translate; " \ "TypeScript types erase, and Ruby constants belong elsewhere", side_effects_only: "looks like a side-effect-only module (top-level calls, no exported functions) — " \ "register the equivalent setup in a Rails initializer instead", utils_only: "looks like a utility module — only function components and JSX-returning helpers translate; " \ "pure-data helpers don't have a ViewComponent equivalent", mixed_exports: "module mixes shapes (utilities + hooks + types + non-JSX helpers) — " \ "split into separate files so each module has a single shape", unknown: nil }.freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(source) ⇒ Lowering
constructor
A new instance of Lowering.
- #lower_all_components(file) ⇒ Object
- #lower_file(file) ⇒ Object
Constructor Details
#initialize(source) ⇒ Lowering
Returns a new instance of Lowering.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/jsx_rosetta/ir/lowering.rb', line 104 def initialize(source) @source = source @prop_names = [] @local_jsx = {} @local_bindings = [] @local_arrows = {} @local_polymorphic_tags = {} @stimulus_methods = [] @stimulus_seen_names = {} @react_hooks = [] end |
Class Method Details
.lower(file, source:) ⇒ Object
56 57 58 |
# File 'lib/jsx_rosetta/ir/lowering.rb', line 56 def self.lower(file, source:) new(source).lower_file(file) end |
.lower_all(file, source:) ⇒ Object
60 61 62 |
# File 'lib/jsx_rosetta/ir/lowering.rb', line 60 def self.lower_all(file, source:) new(source).lower_all_components(file) end |
Instance Method Details
#lower_all_components(file) ⇒ Object
124 125 126 127 128 129 |
# File 'lib/jsx_rosetta/ir/lowering.rb', line 124 def lower_all_components(file) candidates = find_component_functions(file.program) raise no_component_error(file.program) if candidates.empty? candidates.map { |name, function| lower_component(name, function) } end |
#lower_file(file) ⇒ Object
116 117 118 119 120 121 122 |
# File 'lib/jsx_rosetta/ir/lowering.rb', line 116 def lower_file(file) candidates = find_component_functions(file.program) raise no_component_error(file.program) if candidates.empty? name, function = candidates.first lower_component(name, function) end |