Extract a FROM instruction. `FROM image AS alias` creates a Module node for the named stage. `FROM image` (no alias) creates a Module node named by stage index. When a named stage is created, subsequent instructions until the next FROM are considered children of that stage.
(state: &mut ExtractionState, node: TsNode<'_>)
| 183 | /// When a named stage is created, subsequent instructions until the next |
| 184 | /// FROM are considered children of that stage. |
| 185 | fn visit_from(state: &mut ExtractionState, node: TsNode<'_>) { |
| 186 | let start_line = node.start_position().row as u32; |
| 187 | let end_line = node.end_position().row as u32; |
| 188 | let start_column = node.start_position().column as u32; |
| 189 | let end_column = node.end_position().column as u32; |
| 190 | let stage_index = state.stage_count; |
| 191 | state.stage_count += 1; |
| 192 | |
| 193 | // If there's a previous stage on the stack (not the file root), pop it |
| 194 | // so the new FROM starts a new scope. The file root is always at index 0. |
| 195 | if state.node_stack.len() > 1 { |
| 196 | state.node_stack.pop(); |
| 197 | } |
| 198 | |
| 199 | // Check for AS alias (named stage). |
| 200 | let alias = node.child_by_field_name("as").map(|n| state.node_text(n)); |
| 201 | |
| 202 | let text = state.node_text(node); |
| 203 | |
| 204 | if let Some(alias_name) = alias { |
| 205 | // Named stage -> Module node. |
| 206 | let kind = NodeKind::Module; |
| 207 | let qualified_name = format!("{}::{}", state.qualified_prefix(), alias_name); |
| 208 | let id = generate_node_id(&state.file_path, &kind, &alias_name, start_line); |
| 209 | |
| 210 | let graph_node = Node { |
| 211 | id: id.clone(), |
| 212 | kind, |
| 213 | name: alias_name.clone(), |
| 214 | qualified_name, |
| 215 | file_path: state.file_path.clone(), |
| 216 | start_line, |
| 217 | attrs_start_line: start_line, |
| 218 | end_line, |
| 219 | start_column, |
| 220 | end_column, |
| 221 | signature: Some(text.trim().to_string()), |
| 222 | docstring: None, |
| 223 | visibility: Visibility::Pub, |
| 224 | is_async: false, |
| 225 | branches: 0, |
| 226 | loops: 0, |
| 227 | returns: 0, |
| 228 | max_nesting: 0, |
| 229 | unsafe_blocks: 0, |
| 230 | unchecked_calls: 0, |
| 231 | assertions: 0, |
| 232 | updated_at: state.timestamp, |
| 233 | parent_id: None, |
| 234 | }; |
| 235 | state.nodes.push(graph_node); |
| 236 | state.register_stage_target(stage_index.to_string(), &id); |
| 237 | state.register_stage_target(alias_name.clone(), &id); |
| 238 | |
| 239 | // Contains edge from parent. |
| 240 | if let Some(parent_id) = state.parent_node_id() { |
| 241 | state.edges.push(Edge { |
| 242 | source: parent_id.to_string(), |
nothing calls this directly
no test coverage detected