webmat
Version:
Formats your entire project with clang-format
120 lines (99 loc) • 3.31 kB
text/typescript
/**
* @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
*/
import * as fs from 'fs';
import * as path from 'path';
import {promisify} from 'util';
import {ClangFormatStyle} from '../custom_typings/clang-format-style';
const readFile = promisify(fs.readFile);
const CONFIG_FILENAME = 'formatconfig.json';
export const DEFAULT_CONFIG_FILENAME =
path.join(__dirname, '..', 'default_config.json');
export interface FormatConfig {
include: string[];
exclude: string[];
ignoreDefaultGlobs: boolean;
style: ClangFormatStyle;
}
interface ParsedConfig {
include?: string[];
exclude?: string[];
ignoreDefaultGlobs?: boolean;
style?: ClangFormatStyle;
}
/**
* Resolves a user config against the default config. If the user config has the
* `ignoreDefaults` flag, then it returns the user config. If not, then it
* merges the user config with the default config.
*
* @param defaultConfig default_config.json parsed file contents.
* @param userConfig user config (formatconfig.json) parsed file contents.
*/
export function resolveConfigs(
defaultConfig: FormatConfig|null,
userConfig: FormatConfig|null): FormatConfig {
let activeConfig: FormatConfig|null = null;
if (userConfig && userConfig.ignoreDefaultGlobs) {
const style: ClangFormatStyle = {};
if (defaultConfig) {
Object.assign(style, defaultConfig.style);
}
Object.assign(style, userConfig.style);
userConfig.style = style;
return userConfig;
}
if (defaultConfig) {
activeConfig = defaultConfig;
if (userConfig) {
activeConfig.include = activeConfig.include.concat(userConfig.include);
activeConfig.exclude = activeConfig.exclude.concat(userConfig.exclude);
Object.assign(activeConfig.style, userConfig.style);
}
}
if (!activeConfig) {
throw new Error(`Default config file could not be found at ${
DEFAULT_CONFIG_FILENAME}.`);
}
return activeConfig;
}
/**
* Reads and parses a format config file.
*
* @param path path of the file to be parsed (defaults to formatconfig.json).
*/
export async function readConfigFile(path: string = CONFIG_FILENAME):
Promise<FormatConfig|null> {
let configContents: string|null;
try {
configContents = await readFile(path, 'utf8');
} catch (e) {
configContents = null;
}
const formatConfig: FormatConfig =
{include: [], exclude: [], ignoreDefaultGlobs: false, style: {}};
if (configContents) {
let parsedContents: ParsedConfig;
try {
parsedContents = JSON.parse(configContents) as ParsedConfig;
} catch (e) {
throw new Error(
`${CONFIG_FILENAME} is not valid JSON.` +
'\n' + e);
}
if (parsedContents) {
formatConfig.include = parsedContents.include || [];
formatConfig.exclude = parsedContents.exclude || [];
formatConfig.ignoreDefaultGlobs =
parsedContents.ignoreDefaultGlobs || false;
formatConfig.style = parsedContents.style || {};
}
return formatConfig;
}
return null;
}