UNPKG

5.4 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16 return new (P || (P = Promise))(function (resolve, reject) {
17 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
20 step((generator = generator.apply(thisArg, _arguments || [])).next());
21 });
22};
23Object.defineProperty(exports, "__esModule", { value: true });
24const model_1 = require("../model/model");
25const ast_value_1 = require("./ast-value");
26/**
27 * Finds inline HTML documents in Javascript source.
28 *
29 * e.g.
30 * html`<div></div>`;
31 */
32class InlineHtmlDocumentScanner {
33 scan(document, visit) {
34 return __awaiter(this, void 0, void 0, function* () {
35 const features = [];
36 const myVisitor = {
37 enterTaggedTemplateExpression(node) {
38 const tagName = ast_value_1.getIdentifierName(node.tag);
39 if (tagName === undefined || !/(^|\.)html$/.test(tagName)) {
40 return;
41 }
42 const inlineDocument = getInlineDocument(node, document);
43 if (inlineDocument !== undefined) {
44 features.push(inlineDocument);
45 }
46 }
47 };
48 yield visit(myVisitor);
49 return { features };
50 });
51 }
52}
53exports.InlineHtmlDocumentScanner = InlineHtmlDocumentScanner;
54/**
55 * Parses the given string as an inline HTML document.
56 */
57function getInlineDocument(node, parsedDocument, options = {}) {
58 const sourceRangeForLiteral = parsedDocument.sourceRangeForNode(node.quasi);
59 if (sourceRangeForLiteral === undefined) {
60 return;
61 }
62 const sourceRangeForContents = {
63 file: sourceRangeForLiteral.file,
64 start: {
65 line: sourceRangeForLiteral.start.line,
66 column: sourceRangeForLiteral.start.column + 1
67 },
68 end: {
69 line: sourceRangeForLiteral.end.line,
70 column: sourceRangeForLiteral.end.column - 1
71 }
72 };
73 let contents = '';
74 let previousEnd;
75 for (const quasi of node.quasi.quasis) {
76 if (previousEnd !== undefined) {
77 const fullExpressionTextWithDelimitors = parsedDocument.contents.slice(previousEnd, quasi.start);
78 /**
79 * Replace everything but whitespace in ${expressions} (including the
80 * ${} delimitor part) with whitespace.
81 * This skips over the problem of handling expressions, and there's lots
82 * of cases it doesn't handle correctly, but it's a start.
83 * Consider the js file:
84 * ```js
85 * html`<div>${
86 * 'Hello world'
87 * }</div>
88 * ```
89 *
90 * If we remove the expression entirely, the html parser receives
91 * `<div></div>` and when we ask for the source range of the closing tag
92 * it'll give one on the first line, and starting just after the `<div>`.
93 * By preserving whitespace and replacing every other character with a
94 * space, the HTML parser will receive
95 *
96 * ```html
97 * <div>
98 * (a bunch of spaces on this line)
99 * </div>
100 * ```
101 *
102 * and so the html parser's source locations will map cleanly onto offsets
103 * in the original template literal (excluding characters like `\n`). We
104 * could do something more sophisticated later, but this works for most
105 * cases and is quick and easy to implement.
106 */
107 contents += fullExpressionTextWithDelimitors.replace(/\S/g, ' ');
108 }
109 if (options.useRawContents) {
110 contents += quasi.value.raw;
111 }
112 else {
113 contents += quasi.value.cooked;
114 }
115 previousEnd = quasi.end;
116 }
117 let commentText;
118 if (node.leadingComments != null) {
119 commentText = node.leadingComments.map((c) => c.value).join('\n');
120 }
121 else {
122 commentText = '';
123 }
124 return new model_1.ScannedInlineDocument('html', contents, {
125 filename: sourceRangeForContents.file,
126 col: sourceRangeForContents.start.column,
127 line: sourceRangeForContents.start.line
128 }, commentText, sourceRangeForContents, { language: 'js', node, containingDocument: parsedDocument });
129}
130exports.getInlineDocument = getInlineDocument;
131//# sourceMappingURL=html-template-literal-scanner.js.map
\No newline at end of file