* Ingest an element AST from the template into the given `ViewCompilation`.
(unit: ViewCompilationUnit, element: t.Element)
| 318 | * Ingest an element AST from the template into the given `ViewCompilation`. |
| 319 | */ |
| 320 | function ingestElement(unit: ViewCompilationUnit, element: t.Element): void { |
| 321 | if ( |
| 322 | element.i18n !== undefined && |
| 323 | !(element.i18n instanceof i18n.Message || element.i18n instanceof i18n.TagPlaceholder) |
| 324 | ) { |
| 325 | throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`); |
| 326 | } |
| 327 | |
| 328 | const id = unit.job.allocateXrefId(); |
| 329 | |
| 330 | const foreignComp = unit.job.getForeignComponent(element); |
| 331 | if (foreignComp) { |
| 332 | ingestForeignComponent(unit, id, element, foreignComp); |
| 333 | return; |
| 334 | } |
| 335 | |
| 336 | const [namespaceKey, elementName] = splitNsName(element.name); |
| 337 | const startOp = ir.createElementStartOp( |
| 338 | elementName, |
| 339 | id, |
| 340 | namespaceForKey(namespaceKey), |
| 341 | element.i18n instanceof i18n.TagPlaceholder ? element.i18n : undefined, |
| 342 | element.startSourceSpan, |
| 343 | element.sourceSpan, |
| 344 | ); |
| 345 | unit.create.push(startOp); |
| 346 | |
| 347 | ingestElementBindings(unit, startOp, element); |
| 348 | ingestReferences(startOp, element); |
| 349 | |
| 350 | // Start i18n, if needed, goes after the element create and bindings, but before the nodes |
| 351 | let i18nBlockId: ir.XrefId | null = null; |
| 352 | if (element.i18n instanceof i18n.Message) { |
| 353 | i18nBlockId = unit.job.allocateXrefId(); |
| 354 | unit.create.push( |
| 355 | ir.createI18nStartOp(i18nBlockId, element.i18n, undefined, element.startSourceSpan), |
| 356 | ); |
| 357 | } |
| 358 | |
| 359 | ingestNodes(unit, element.children); |
| 360 | |
| 361 | // The source span for the end op is typically the element closing tag. However, if no closing tag |
| 362 | // exists, such as in `<input>`, we use the start source span instead. Usually the start and end |
| 363 | // instructions will be collapsed into one `element` instruction, negating the purpose of this |
| 364 | // fallback, but in cases when it is not collapsed (such as an input with a binding), we still |
| 365 | // want to map the end instruction to the main element. |
| 366 | const endOp = ir.createElementEndOp(id, element.endSourceSpan ?? element.startSourceSpan); |
| 367 | unit.create.push(endOp); |
| 368 | |
| 369 | // If there is an i18n message associated with this element, insert i18n start and end ops. |
| 370 | if (i18nBlockId !== null) { |
| 371 | ir.OpList.insertBefore<ir.CreateOp>( |
| 372 | ir.createI18nEndOp(i18nBlockId, element.endSourceSpan ?? element.startSourceSpan), |
| 373 | endOp, |
| 374 | ); |
| 375 | } |
| 376 | } |
| 377 |
no test coverage detected