UNPKG

webmat

Version:

Formats your entire project with clang-format

139 lines 5.44 kB
"use strict"; /** * @license * Copyright (c) 2018 Google Inc. All rights reserved. * This code may only be used under the BSD style license found at * http://polymer.github.io/LICENSE.txt * Code distributed by Google as part of this project is also * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ Object.defineProperty(exports, "__esModule", { value: true }); const dom5 = require("dom5"); const esprima = require("esprima"); const fs = require("fs"); const parse5 = require("parse5"); const SINGLE_TAB = ' '; /** * Indents and writes the content to the file. * * @param formattedContent Content to be written to the file. */ async function writeTofile(formattedContent) { const writableStream = fs.createWriteStream(formattedContent.filePath); await updateAst(formattedContent); const formattedDom = generateDom(formattedContent); writableStream.write(formattedDom); writableStream.end(); } exports.writeTofile = writeTofile; /** * Tabs the given content and writes it to the AST in the content chunks * * @param formattedContent Content to be written to the AST */ function updateAst(formattedContent) { const updatePromises = []; for (const chunk of formattedContent.contents) { const nodeLocation = chunk.node.__location; let numTabs = 1; if (nodeLocation.col) { numTabs = Math.floor(nodeLocation.col / SINGLE_TAB.length) + 1; } const tabbedString = SINGLE_TAB.repeat(numTabs); const updatePromise = chunk.streamReader.streamCached.then((data) => { const allTokens = esprima.tokenize(data, { loc: true }); const templateTokens = allTokens.filter((token) => { return token.type === 'Template'; }); let stringifiedContents = ''; let splitData = data.split('\n'); const nonIndentableLines = []; for (const templateToken of templateTokens) { const firstNonIndentableLine = templateToken.loc.start.line; const lastNonIndentableLine = templateToken.loc.end.line; // just indent if it is all the same line if (templateToken.loc.start.line !== templateToken.loc.end.line) { nonIndentableLines.push({ start: firstNonIndentableLine, end: lastNonIndentableLine, }); } } // only tab nonempty lines and non-templates for (let lineNumber = 1; lineNumber <= splitData.length; lineNumber++) { const index = lineNumber - 1; let line = splitData[index]; let isIndentable = true; for (const nonIndentableLine of nonIndentableLines) { // first line of a template string is indentable if (lineNumber > nonIndentableLine.start && lineNumber <= nonIndentableLine.end) { isIndentable = false; break; } } if (line.length && isIndentable) { line = `${tabbedString}${line}`; } splitData[index] = line; } splitData = splitData.map((line) => { return line; }); const tabbedData = splitData.join(`\n`); stringifiedContents += tabbedData; const trimmedContents = stringifiedContents.trim(); // deal with tabs at the beginning and end if the script is not empty if (stringifiedContents) { stringifiedContents = `\n${tabbedString}${trimmedContents}` + `\n${SINGLE_TAB.repeat(numTabs - 1)}`; } dom5.setTextContent(chunk.node, stringifiedContents); }); updatePromises.push(updatePromise); } return Promise.all(updatePromises); } /** * Transforms the content into a dom string with prpoper spacing around the * spliced inline scripts. * * @param formattedContent Content to be transformed into a dom string. */ function generateDom(formattedContent) { const sortedChunks = formattedContent.contents.sort((a, b) => { const aLine = a.node.__location.startTag.line; const bLine = b.node.__location.startTag.line; if (aLine > bLine) { return -1; } else if (aLine < bLine) { return 1; } return 0; }); const splitDom = formattedContent.dom.split('\n'); for (const chunk of sortedChunks) { const location = chunk.node.__location; const startTag = location.startTag; const endTag = location.endTag; const numLines = endTag.line - startTag.line + 1; const scriptTagWhitespace = { attrs: [], nodeName: '#text', value: ' '.repeat(startTag.col - 1), __location: {} }; const fakeNode = { attrs: [], childNodes: [scriptTagWhitespace, chunk.node], nodeName: 'div', __location: {} }; const formattedChunk = parse5.serialize(fakeNode); splitDom.splice(startTag.line - 1, numLines, formattedChunk); } return splitDom.join('\n'); } //# sourceMappingURL=write-output.js.map