webmat
Version:
Formats your entire project with clang-format
117 lines • 4.75 kB
JavaScript
"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 clangFormat = require("clang-format");
const dom5 = require("dom5");
const fastGlob = require("fast-glob");
const fs = require("fs");
const parse5 = require("parse5");
const path = require("path");
const stream = require("stream");
const util_1 = require("util");
const util_2 = require("./util");
const write_output_1 = require("./write-output");
const readFile = util_1.promisify(fs.readFile);
/**
* Runs the files through the formatter, and overwrites them.
*
* @param filePaths Paths of the files to be formatted.
*/
async function formatFiles(filePaths, style) {
const htmlFiles = filePaths.filter((file) => path.extname(file) === '.html');
const nonHtmlFiles = filePaths.filter((file) => path.extname(file) !== '.html');
const formatPromises = [];
for (const path of htmlFiles) {
const htmlFormatted = formatHTMLFiles(path, style).then(function (formattedContent) {
return write_output_1.writeTofile(formattedContent);
});
formatPromises.push(htmlFormatted);
}
for (const path of nonHtmlFiles) {
formatInPlace(path, style);
}
// wait for all HTML files to be formatted as well
await Promise.all(formatPromises);
}
exports.formatFiles = formatFiles;
/**
* Runs the contents of the script tags in an HTML document through the
* formatter and returns their unindented, formatted contents.
*
* @param filePath Path of HTML file.
*/
async function formatHTMLFiles(filePath, style) {
const scriptContent = await getInlineScriptContents(filePath);
const formattedContent = {
filePath: filePath,
contents: [],
dom: scriptContent.dom
};
for (const contentChunk of scriptContent.contents) {
const cfChildProcess = clangFormat.spawnClangFormat(['-assume-filename=.js', `-style=${JSON.stringify(style)}`], function () { }, ['pipe', 'pipe', process.stderr]);
const cachedStdout = new util_2.ReadableStreamCache(cfChildProcess.stdout);
const readable = new stream.PassThrough();
readable.pipe(cfChildProcess.stdin);
readable.push(await contentChunk.streamReader.streamCached);
readable.push(null);
const formattedChunk = {
node: contentChunk.node,
streamReader: cachedStdout
};
formattedContent.contents.push(formattedChunk);
}
return formattedContent;
}
/**
* Runs the given file through the formatter which overwrites the file's
* contents.
*
* @param filePath Path of file to be formatted in place.
*/
function formatInPlace(filePath, style) {
clangFormat.spawnClangFormat([filePath, '-i', `-style=${JSON.stringify(style)}`], function () { }, ['ignore', 'pipe', process.stderr]);
}
/**
* Gathers all the contents of an HTML file's inline scripts.
*
* @param filePath Path of the flile to be searched.
*/
async function getInlineScriptContents(filePath) {
const htmlContent = await readFile(filePath, 'utf-8');
const dom = parse5.parse(htmlContent, { locationInfo: true });
const matcher = dom5.predicates.AND(dom5.predicates.hasTagName('script'), dom5.predicates.OR(dom5.predicates.NOT(dom5.predicates.hasAttr('type')), dom5.predicates.hasAttrValue('type', 'text/javascript'), dom5.predicates.hasAttrValue('type', 'application/javascript'), dom5.predicates.hasAttrValue('type', 'module')));
const scriptNodes = dom5.queryAll(dom, matcher);
const contentChunks = { filePath: filePath, contents: [], dom: htmlContent };
for (const scriptNode of scriptNodes) {
const content = dom5.getTextContent(scriptNode);
const contentStream = new stream.PassThrough();
const cachedContentStream = new util_2.ReadableStreamCache(contentStream);
contentStream.push(content);
contentStream.push(null);
const contentChunk = {
node: scriptNode,
streamReader: cachedContentStream
};
contentChunks.contents.push(contentChunk);
}
return contentChunks;
}
/**
* Executes the globs inside of a given format config.
*
* @param config Config file to be executed.
*/
function getFilesToFormat(config) {
const filesToFormat = fastGlob.sync(config.include, { ignore: config.exclude });
return filesToFormat;
}
exports.getFilesToFormat = getFilesToFormat;
//# sourceMappingURL=format.js.map