| 
									
										
										
										
											2018-09-21 15:42:07 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							| 
									
										
										
										
											2020-05-19 12:08:49 -07:00
										 |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2018-09-21 15:42:07 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import * as e from '../../../src/expression_parser/ast'; | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  | import {Lexer} from '../../../src/expression_parser/lexer'; | 
					
						
							|  |  |  | import {Parser} from '../../../src/expression_parser/parser'; | 
					
						
							|  |  |  | import * as html from '../../../src/ml_parser/ast'; | 
					
						
							| 
									
										
										
										
											2019-10-01 12:34:04 +01:00
										 |  |  | import {HtmlParser, ParseTreeResult} from '../../../src/ml_parser/html_parser'; | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  | import {WhitespaceVisitor} from '../../../src/ml_parser/html_whitespaces'; | 
					
						
							| 
									
										
										
										
											2019-10-01 12:34:04 +01:00
										 |  |  | import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../src/ml_parser/interpolation_config'; | 
					
						
							| 
									
										
										
										
											2018-09-21 15:42:07 -07:00
										 |  |  | import * as a from '../../../src/render3/r3_ast'; | 
					
						
							| 
									
										
										
										
											2020-04-08 10:14:18 -07:00
										 |  |  | import {htmlAstToRender3Ast, Render3ParseResult} from '../../../src/render3/r3_template_transform'; | 
					
						
							| 
									
										
										
										
											2019-10-01 12:34:04 +01:00
										 |  |  | import {I18nMetaVisitor} from '../../../src/render3/view/i18n/meta'; | 
					
						
							| 
									
										
										
										
											2021-01-21 21:48:42 +01:00
										 |  |  | import {LEADING_TRIVIA_CHARS} from '../../../src/render3/view/template'; | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  | import {BindingParser} from '../../../src/template_parser/binding_parser'; | 
					
						
							|  |  |  | import {MockSchemaRegistry} from '../../../testing'; | 
					
						
							| 
									
										
										
										
											2018-09-21 15:42:07 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export function findExpression(tmpl: a.Node[], expr: string): e.AST|null { | 
					
						
							|  |  |  |   const res = tmpl.reduce((found, node) => { | 
					
						
							|  |  |  |     if (found !== null) { | 
					
						
							|  |  |  |       return found; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return findExpressionInNode(node, expr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, null as e.AST | null); | 
					
						
							|  |  |  |   if (res instanceof e.ASTWithSource) { | 
					
						
							|  |  |  |     return res.ast; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function findExpressionInNode(node: a.Node, expr: string): e.AST|null { | 
					
						
							|  |  |  |   if (node instanceof a.Element || node instanceof a.Template) { | 
					
						
							|  |  |  |     return findExpression( | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |           ...node.inputs, | 
					
						
							|  |  |  |           ...node.outputs, | 
					
						
							|  |  |  |           ...node.children, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         expr); | 
					
						
							|  |  |  |   } else if (node instanceof a.BoundAttribute || node instanceof a.BoundText) { | 
					
						
							|  |  |  |     const ts = toStringExpression(node.value); | 
					
						
							|  |  |  |     return toStringExpression(node.value) === expr ? node.value : null; | 
					
						
							|  |  |  |   } else if (node instanceof a.BoundEvent) { | 
					
						
							|  |  |  |     return toStringExpression(node.handler) === expr ? node.handler : null; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function toStringExpression(expr: e.AST): string { | 
					
						
							|  |  |  |   while (expr instanceof e.ASTWithSource) { | 
					
						
							|  |  |  |     expr = expr.ast; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (expr instanceof e.PropertyRead) { | 
					
						
							|  |  |  |     if (expr.receiver instanceof e.ImplicitReceiver) { | 
					
						
							|  |  |  |       return expr.name; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return `${toStringExpression(expr.receiver)}.${expr.name}`; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else if (expr instanceof e.ImplicitReceiver) { | 
					
						
							|  |  |  |     return ''; | 
					
						
							|  |  |  |   } else if (expr instanceof e.Interpolation) { | 
					
						
							|  |  |  |     let str = '{{'; | 
					
						
							|  |  |  |     for (let i = 0; i < expr.expressions.length; i++) { | 
					
						
							|  |  |  |       str += expr.strings[i] + toStringExpression(expr.expressions[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     str += expr.strings[expr.strings.length - 1] + '}}'; | 
					
						
							|  |  |  |     return str; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     throw new Error(`Unsupported type: ${(expr as any).constructor.name}`); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Parse an html string to IVY specific info
 | 
					
						
							|  |  |  | export function parseR3( | 
					
						
							| 
									
										
										
										
											2020-12-02 11:14:07 +08:00
										 |  |  |     input: string, | 
					
						
							|  |  |  |     options: {preserveWhitespaces?: boolean, | 
					
						
							|  |  |  |               leadingTriviaChars?: string[], | 
					
						
							|  |  |  |               ignoreError?: boolean} = {}): Render3ParseResult { | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  |   const htmlParser = new HtmlParser(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-21 21:48:42 +01:00
										 |  |  |   const parseResult = htmlParser.parse(input, 'path:://to/template', { | 
					
						
							|  |  |  |     tokenizeExpansionForms: true, | 
					
						
							|  |  |  |     leadingTriviaChars: options.leadingTriviaChars ?? LEADING_TRIVIA_CHARS, | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 11:14:07 +08:00
										 |  |  |   if (parseResult.errors.length > 0 && !options.ignoreError) { | 
					
						
							| 
									
										
										
										
											2018-10-18 10:08:51 -07:00
										 |  |  |     const msg = parseResult.errors.map(e => e.toString()).join('\n'); | 
					
						
							|  |  |  |     throw new Error(msg); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   let htmlNodes = processI18nMeta(parseResult).rootNodes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!options.preserveWhitespaces) { | 
					
						
							|  |  |  |     htmlNodes = html.visitAll(new WhitespaceVisitor(), htmlNodes); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const expressionParser = new Parser(new Lexer()); | 
					
						
							|  |  |  |   const schemaRegistry = new MockSchemaRegistry( | 
					
						
							|  |  |  |       {'invalidProp': false}, {'mappedAttr': 'mappedProp'}, {'unknown': false, 'un-known': false}, | 
					
						
							|  |  |  |       ['onEvent'], ['onEvent']); | 
					
						
							|  |  |  |   const bindingParser = | 
					
						
							|  |  |  |       new BindingParser(expressionParser, DEFAULT_INTERPOLATION_CONFIG, schemaRegistry, null, []); | 
					
						
							| 
									
										
										
										
											2021-03-17 23:18:30 +04:00
										 |  |  |   const r3Result = htmlAstToRender3Ast(htmlNodes, bindingParser, {collectCommentNodes: false}); | 
					
						
							| 
									
										
										
										
											2020-08-25 09:46:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-02 11:14:07 +08:00
										 |  |  |   if (r3Result.errors.length > 0 && !options.ignoreError) { | 
					
						
							| 
									
										
										
										
											2020-08-25 09:46:40 -04:00
										 |  |  |     const msg = r3Result.errors.map(e => e.toString()).join('\n'); | 
					
						
							|  |  |  |     throw new Error(msg); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return r3Result; | 
					
						
							| 
									
										
										
										
											2019-10-01 12:34:04 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function processI18nMeta( | 
					
						
							|  |  |  |     htmlAstWithErrors: ParseTreeResult, | 
					
						
							|  |  |  |     interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG): ParseTreeResult { | 
					
						
							|  |  |  |   return new ParseTreeResult( | 
					
						
							|  |  |  |       html.visitAll( | 
					
						
							|  |  |  |           new I18nMetaVisitor(interpolationConfig, /* keepI18nAttrs */ false), | 
					
						
							|  |  |  |           htmlAstWithErrors.rootNodes), | 
					
						
							|  |  |  |       htmlAstWithErrors.errors); | 
					
						
							|  |  |  | } |