Refactoring: better boundaries for different parts of the project (#4364)

master
Lucas Duailibe 2018-04-25 13:29:35 -03:00 committed by GitHub
parent 289b98c125
commit 67f1c4877e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 334 additions and 306 deletions

View File

@ -57,6 +57,17 @@ If `options.editorconfig` is `true` and an [`.editorconfig` file](http://editorc
Use `prettier.resolveConfig.sync(filePath [, options])` if you'd like to use sync version.
## `prettier.resolveConfigFile(filePath [, options])`
`resolveConfigFile` can be used to find the path of the Prettier's configuration file will be used when resolving the config (i.e. when calling `resolveConfig`). A promise is returned which will resolve to:
* The path of the configuration file.
* `null`, if no file was found.
The promise will be rejected if there was an error parsing the configuration file.
If `options.useCache` is `false`, all caching will be bypassed.
## `prettier.clearConfigCache()`
As you repeatedly call `resolveConfig`, the file system structure will be cached for performance. This function will clear the cache. Generally this is only needed for editor integrations that know that the file system has changed since the last format took place.

View File

@ -4,11 +4,13 @@ const version = require("./package.json").version;
const privateUtil = require("./src/common/util");
const sharedUtil = require("./src/common/util-shared");
const getSupportInfo = require("./src/common/support").getSupportInfo;
const getSupportInfo = require("./src/main/support").getSupportInfo;
const loadPlugins = require("./src/common/load-plugins");
const massageAST = require("./src/main/massage-ast");
const comments = require("./src/main/comments");
const printAstToDoc = require("./src/main/ast-to-doc");
const normalizeOptions = require("./src/main/options").normalize;
const rawNormalizeOptions = require("./src/main/options").normalize;
const parser = require("./src/main/parser");
const config = require("./src/config/resolve-config");
@ -17,6 +19,16 @@ const doc = require("./src/doc");
const printDocToString = doc.printer.printDocToString;
const printDocToDebug = doc.debug.printDocToDebug;
function withPlugins(opts) {
return Object.assign({}, opts, {
plugins: loadPlugins(opts && opts.plugins)
});
}
function normalizeOptions(opts) {
return rawNormalizeOptions(withPlugins(opts));
}
function guessLineEnding(text) {
const index = text.indexOf("\n");
if (index >= 0 && text.charAt(index - 1) === "\r") {
@ -406,9 +418,12 @@ module.exports = {
doc,
resolveConfig: config.resolveConfig,
resolveConfigFile: config.resolveConfigFile,
clearConfigCache: config.clearCache,
getSupportInfo,
getSupportInfo(version, opts) {
return getSupportInfo(version, withPlugins(opts));
},
version,
@ -416,9 +431,13 @@ module.exports = {
/* istanbul ignore next */
__debug: {
parse: function(text, opts) {
parse: function(text, opts, massage) {
opts = normalizeOptions(opts);
return parser.parse(text, opts);
const parsed = parser.parse(text, opts);
if (massage) {
parsed.ast = massageAST(parsed.ast, opts);
}
return parsed;
},
formatAST: function(ast, opts) {
opts = normalizeOptions(opts);

View File

@ -10,9 +10,8 @@ module.exports = {
collectCoverage: ENABLE_COVERAGE,
collectCoverageFrom: ["src/**/*.js", "index.js", "!<rootDir>/node_modules/"],
coveragePathIgnorePatterns: [
"<rootDir>/src/doc-debug.js",
"<rootDir>/src/clean-ast.js",
"<rootDir>/src/deprecated.js"
"<rootDir>/src/doc/doc-debug.js",
"<rootDir>/src/main/massage-ast.js"
],
moduleNameMapper: {
// Jest wires `fs` to `graceful-fs`, which causes a memory leak when

View File

@ -1,19 +1,14 @@
"use strict";
const dedent = require("dedent");
const CATEGORY_CONFIG = "Config";
const CATEGORY_EDITOR = "Editor";
const CATEGORY_FORMAT = "Format";
const CATEGORY_OTHER = "Other";
const CATEGORY_OUTPUT = "Output";
const coreOptions = require("../main/core-options");
const categoryOrder = [
CATEGORY_OUTPUT,
CATEGORY_FORMAT,
CATEGORY_CONFIG,
CATEGORY_EDITOR,
CATEGORY_OTHER
coreOptions.CATEGORY_OUTPUT,
coreOptions.CATEGORY_FORMAT,
coreOptions.CATEGORY_CONFIG,
coreOptions.CATEGORY_EDITOR,
coreOptions.CATEGORY_OTHER
];
/**
@ -87,14 +82,14 @@ const options = {
},
config: {
type: "path",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
description:
"Path to a Prettier configuration file (.prettierrc, package.json, prettier.config.js).",
oppositeDescription: "Do not look for a configuration file."
},
"config-precedence": {
type: "choice",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
default: "cli-override",
choices: [
{
@ -124,7 +119,7 @@ const options = {
},
editorconfig: {
type: "boolean",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
description: "Take .editorconfig into account when parsing configuration.",
oppositeDescription:
"Don't take .editorconfig into account when parsing configuration.",
@ -132,7 +127,7 @@ const options = {
},
"find-config-path": {
type: "path",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
description:
"Find and print the path to a configuration file for the given input file."
},
@ -146,13 +141,13 @@ const options = {
},
"ignore-path": {
type: "path",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
default: ".prettierignore",
description: "Path to a file with patterns describing files to ignore."
},
"list-different": {
type: "boolean",
category: CATEGORY_OUTPUT,
category: coreOptions.CATEGORY_OUTPUT,
alias: "l",
description:
"Print the names of files that are different from Prettier's formatting."
@ -178,12 +173,12 @@ const options = {
},
"with-node-modules": {
type: "boolean",
category: CATEGORY_CONFIG,
category: coreOptions.CATEGORY_CONFIG,
description: "Process files inside 'node_modules' directory."
},
write: {
type: "boolean",
category: CATEGORY_OUTPUT,
category: coreOptions.CATEGORY_OUTPUT,
description: "Edit files in-place. (Beware!)"
}
};
@ -196,11 +191,6 @@ const usageSummary = dedent`
`;
module.exports = {
CATEGORY_CONFIG,
CATEGORY_EDITOR,
CATEGORY_FORMAT,
CATEGORY_OTHER,
CATEGORY_OUTPUT,
categoryOrder,
options,
usageSummary

View File

@ -12,15 +12,13 @@ const leven = require("leven");
const minimist = require("./minimist");
const prettier = require("../../index");
const cleanAST = require("../common/clean-ast").cleanAST;
const errors = require("../common/errors");
const resolver = require("../config/resolve-config");
const constant = require("./constant");
const coreOptions = require("../main/core-options");
const optionsModule = require("../main/options");
const optionsNormalizer = require("../main/options-normalizer");
const thirdParty = require("../common/third-party");
const getSupportInfo = require("../common/support").getSupportInfo;
const util = require("../common/util");
const arrayify = require("../utils/arrayify");
const OPTION_USAGE_THRESHOLD = 25;
const CHOICE_USAGE_MARGIN = 3;
@ -79,7 +77,7 @@ function handleError(context, filename, error) {
}
function logResolvedConfigPathOrDie(context, filePath) {
const configFile = resolver.resolveConfigFile.sync(filePath);
const configFile = prettier.resolveConfigFile.sync(filePath);
if (configFile) {
context.logger.log(path.relative(process.cwd(), configFile));
} else {
@ -127,14 +125,12 @@ function format(context, input, opt) {
"prettier(input) !== prettier(prettier(input))\n" + diff(pp, pppp)
);
} else {
const normalizedOpts = optionsModule.normalize(opt);
const ast = cleanAST(
prettier.__debug.parse(input, opt).ast,
normalizedOpts
const stringify = obj => JSON.stringify(obj, null, 2);
const ast = stringify(
prettier.__debug.parse(input, opt, /* massage */ true).ast
);
const past = cleanAST(
prettier.__debug.parse(pp, opt).ast,
normalizedOpts
const past = stringify(
prettier.__debug.parse(pp, opt, /* massage */ true).ast
);
if (ast !== past) {
@ -172,7 +168,7 @@ function getOptionsOrDie(context, filePath) {
: `resolve config from '${filePath}'`
);
const options = resolver.resolveConfig.sync(filePath, {
const options = prettier.resolveConfig.sync(filePath, {
editorconfig: context.argv["editorconfig"],
config: context.argv["config"]
});
@ -713,7 +709,7 @@ function createLogger(logLevel) {
}
function normalizeDetailedOption(name, option) {
return Object.assign({ category: constant.CATEGORY_OTHER }, option, {
return Object.assign({ category: coreOptions.CATEGORY_OTHER }, option, {
choices:
option.choices &&
option.choices.map(choice => {
@ -782,7 +778,7 @@ function createDetailedOptionMap(supportOptions) {
const newOption = Object.assign({}, option, {
name: option.cliName || dashify(option.name),
description: option.cliDescription || option.description,
category: option.cliCategory || constant.CATEGORY_FORMAT,
category: option.cliCategory || coreOptions.CATEGORY_FORMAT,
forwardToApi: option.name
});
@ -828,7 +824,7 @@ function initContext(context) {
}
function updateContextOptions(context, plugins) {
const supportOptions = getSupportInfo(null, {
const supportOptions = prettier.getSupportInfo(null, {
showDeprecated: true,
showUnreleased: true,
showInternal: true,
@ -839,7 +835,7 @@ function updateContextOptions(context, plugins) {
Object.assign({}, createDetailedOptionMap(supportOptions), constant.options)
);
const detailedOptions = util.arrayify(detailedOptionMap, "name");
const detailedOptions = arrayify(detailedOptionMap, "name");
const apiDefaultOptions = supportOptions
.filter(optionInfo => !optionInfo.deprecated)

View File

@ -713,14 +713,6 @@ function hasNodeIgnoreComment(node) {
);
}
function arrayify(object, keyName) {
return Object.keys(object).reduce(
(array, key) =>
array.concat(Object.assign({ [keyName]: key }, object[key])),
[]
);
}
function addCommentHelper(node, comment) {
const comments = node.comments || (node.comments = []);
comments.push(comment);
@ -753,7 +745,6 @@ function addTrailingComment(node, comment) {
}
module.exports = {
arrayify,
punctuationRegex,
punctuationCharRange,
getStringWidth,

View File

@ -2,7 +2,7 @@
const jsOptions = require("../language-js/options");
// format based on https://github.com/prettier/prettier/blob/master/src/common/support.js
// format based on https://github.com/prettier/prettier/blob/master/src/main/core-options.js
module.exports = {
singleQuote: jsOptions.singleQuote
};

View File

@ -2,7 +2,7 @@
const jsOptions = require("../language-js/options");
// format based on https://github.com/prettier/prettier/blob/master/src/common/support.js
// format based on https://github.com/prettier/prettier/blob/master/src/main/core-options.js
module.exports = {
bracketSpacing: jsOptions.bracketSpacing
};

View File

@ -0,0 +1,7 @@
"use strict";
module.exports = function(ast) {
if (ast.type === "text") {
return null;
}
};

View File

@ -9,12 +9,32 @@ function parse(text /*, parsers, opts*/) {
treeAdapter: parse5.treeAdapters.htmlparser2,
locationInfo: true
});
return extendAst(ast);
return normalize(extendAst(ast));
} catch (error) {
throw error;
}
}
function normalize(ast) {
if (Array.isArray(ast)) {
return ast.map(normalize);
}
if (!ast || typeof ast !== "object") {
return ast;
}
delete ast.parent;
delete ast.next;
delete ast.prev;
for (const key of Object.keys(ast)) {
ast[key] = normalize(ast[key]);
}
return ast;
}
function extendAst(ast) {
if (!ast || !ast.children) {
return ast;

View File

@ -1,6 +1,7 @@
"use strict";
const embed = require("./embed");
const clean = require("./clean");
const privateUtil = require("../common/util");
const docBuilders = require("../doc").builders;
const concat = docBuilders.concat;
@ -116,6 +117,7 @@ function printChildren(path, print) {
module.exports = {
print: genericPrint,
massageAstNode: clean,
embed,
hasPrettierIgnore: privateUtil.hasIgnoreComment
};

View File

@ -2,7 +2,7 @@
const CATEGORY_JAVASCRIPT = "JavaScript";
// format based on https://github.com/prettier/prettier/blob/master/src/common/support.js
// format based on https://github.com/prettier/prettier/blob/master/src/main/core-options.js
module.exports = {
arrowParens: {
since: "1.9.0",

View File

@ -2,7 +2,7 @@
const docUtils = require("../doc/doc-utils");
const util = require("../common/util");
const support = require("../common/support");
const support = require("../main/support");
const doc = require("../doc");
const docBuilders = doc.builders;
const hardline = docBuilders.hardline;
@ -39,8 +39,7 @@ function embed(path, print, textToDoc, options) {
function getParserName(lang) {
const supportInfo = support.getSupportInfo(null, {
plugins: options.plugins,
pluginsLoaded: true
plugins: options.plugins
});
const language = supportInfo.languages.find(
language =>

View File

@ -4,7 +4,7 @@ const jsOptions = require("../language-js/options");
const CATEGORY_MARKDOWN = "Markdown";
// format based on https://github.com/prettier/prettier/blob/master/src/common/support.js
// format based on https://github.com/prettier/prettier/blob/master/src/main/core-options.js
module.exports = {
proseWrap: {
since: "1.8.2",

View File

@ -1,12 +1,12 @@
"use strict";
const util = require("./util");
const dedent = require("dedent");
const semver = require("semver");
const currentVersion = require("../../package.json").version;
const loadPlugins = require("./load-plugins");
const cliConstant = require("../cli/constant");
const CATEGORY_CONFIG = "Config";
const CATEGORY_EDITOR = "Editor";
const CATEGORY_FORMAT = "Format";
const CATEGORY_OTHER = "Other";
const CATEGORY_OUTPUT = "Output";
const CATEGORY_GLOBAL = "Global";
const CATEGORY_SPECIAL = "Special";
@ -49,7 +49,7 @@ const CATEGORY_SPECIAL = "Special";
* @property {string?} cliDescription
*/
/** @type {{ [name: string]: OptionInfo } */
const supportOptions = {
const options = {
cursorOffset: {
since: "1.4.0",
category: CATEGORY_SPECIAL,
@ -60,7 +60,7 @@ const supportOptions = {
Print (to stderr) where a cursor at the given position would move to after formatting.
This option cannot be used with --range-start and --range-end.
`,
cliCategory: cliConstant.CATEGORY_EDITOR
cliCategory: CATEGORY_EDITOR
},
filepath: {
since: "1.4.0",
@ -70,7 +70,7 @@ const supportOptions = {
description:
"Specify the input filepath. This will be used to do parser inference.",
cliName: "stdin-filepath",
cliCategory: cliConstant.CATEGORY_OTHER,
cliCategory: CATEGORY_OTHER,
cliDescription: "Path to the file to pretend that stdin comes from."
},
insertPragma: {
@ -79,7 +79,7 @@ const supportOptions = {
type: "boolean",
default: false,
description: "Insert @format pragma into file's first docblock comment.",
cliCategory: cliConstant.CATEGORY_OTHER
cliCategory: CATEGORY_OTHER
},
parser: {
since: "0.0.10",
@ -120,7 +120,7 @@ const supportOptions = {
"Add a plugin. Multiple plugins can be passed as separate `--plugin`s.",
exception: value => typeof value === "string" || typeof value === "object",
cliName: "plugin",
cliCategory: cliConstant.CATEGORY_CONFIG
cliCategory: CATEGORY_CONFIG
},
printWidth: {
since: "0.0.0",
@ -141,7 +141,7 @@ const supportOptions = {
The range will extend forwards to the end of the selected statement.
This option cannot be used with --cursor-offset.
`,
cliCategory: cliConstant.CATEGORY_EDITOR
cliCategory: CATEGORY_EDITOR
},
rangeStart: {
since: "1.4.0",
@ -154,7 +154,7 @@ const supportOptions = {
The range will extend backwards to the start of the first line containing the selected statement.
This option cannot be used with --cursor-offset.
`,
cliCategory: cliConstant.CATEGORY_EDITOR
cliCategory: CATEGORY_EDITOR
},
requirePragma: {
since: "1.7.0",
@ -165,7 +165,7 @@ const supportOptions = {
Require either '@prettier' or '@format' to be present in the file's first docblock comment
in order for it to be formatted.
`,
cliCategory: cliConstant.CATEGORY_OTHER
cliCategory: CATEGORY_OTHER
},
tabWidth: {
type: "int",
@ -193,143 +193,13 @@ const supportOptions = {
}
};
function getSupportInfo(version, opts) {
opts = Object.assign(
{
plugins: [],
pluginsLoaded: false,
showUnreleased: false,
showDeprecated: false,
showInternal: false
},
opts
);
if (!version) {
version = currentVersion;
}
const plugins = opts.pluginsLoaded ? opts.plugins : loadPlugins(opts.plugins);
const options = util
.arrayify(
Object.assign(
plugins.reduce(
(currentOptions, plugin) =>
Object.assign(currentOptions, plugin.options),
{}
),
supportOptions
),
"name"
)
.sort((a, b) => (a.name === b.name ? 0 : a.name < b.name ? -1 : 1))
.filter(filterSince)
.filter(filterDeprecated)
.map(mapDeprecated)
.map(mapInternal)
.map(option => {
const newOption = Object.assign({}, option);
if (Array.isArray(newOption.default)) {
newOption.default =
newOption.default.length === 1
? newOption.default[0].value
: newOption.default
.filter(filterSince)
.sort((info1, info2) =>
semver.compare(info2.since, info1.since)
)[0].value;
}
if (Array.isArray(newOption.choices)) {
newOption.choices = newOption.choices
.filter(filterSince)
.filter(filterDeprecated)
.map(mapDeprecated);
}
return newOption;
})
.map(option => {
const filteredPlugins = plugins.filter(
plugin => plugin.defaultOptions && plugin.defaultOptions[option.name]
);
const pluginDefaults = filteredPlugins.reduce((reduced, plugin) => {
reduced[plugin.name] = plugin.defaultOptions[option.name];
return reduced;
}, {});
return Object.assign(option, { pluginDefaults });
});
const usePostCssParser = semver.lt(version, "1.7.1");
const languages = plugins
.reduce((all, plugin) => all.concat(plugin.languages), [])
.filter(
language =>
language.since
? semver.gte(version, language.since)
: language.since !== null
)
.map(language => {
// Prevent breaking changes
if (language.name === "Markdown") {
return Object.assign({}, language, {
parsers: ["markdown"]
});
}
if (language.name === "TypeScript") {
return Object.assign({}, language, {
parsers: ["typescript"]
});
}
if (usePostCssParser && language.group === "CSS") {
return Object.assign({}, language, {
parsers: ["postcss"]
});
}
return language;
});
return { languages, options };
function filterSince(object) {
return (
opts.showUnreleased ||
!("since" in object) ||
(object.since && semver.gte(version, object.since))
);
}
function filterDeprecated(object) {
return (
opts.showDeprecated ||
!("deprecated" in object) ||
(object.deprecated && semver.lt(version, object.deprecated))
);
}
function mapDeprecated(object) {
if (!object.deprecated || opts.showDeprecated) {
return object;
}
const newObject = Object.assign({}, object);
delete newObject.deprecated;
delete newObject.redirect;
return newObject;
}
function mapInternal(object) {
if (opts.showInternal) {
return object;
}
const newObject = Object.assign({}, object);
delete newObject.cliName;
delete newObject.cliCategory;
delete newObject.cliDescription;
return newObject;
}
}
module.exports = {
getSupportInfo
CATEGORY_CONFIG,
CATEGORY_EDITOR,
CATEGORY_FORMAT,
CATEGORY_OTHER,
CATEGORY_OUTPUT,
CATEGORY_GLOBAL,
CATEGORY_SPECIAL,
options
};

View File

@ -1,13 +0,0 @@
"use strict";
const deprecated = {
useFlowParser: config =>
` The ${'"useFlowParser"'} option is deprecated. Use ${'"parser"'} instead.
Prettier now treats your configuration as:
{
${'"parser"'}: ${config.useFlowParser ? '"flow"' : '"babylon"'}
}`
};
module.exports = deprecated;

View File

@ -1,19 +0,0 @@
"use strict";
function getPlugin(options) {
const astFormat = options.astFormat;
if (!astFormat) {
throw new Error("getPlugin() requires astFormat to be set");
}
const printerPlugin = options.plugins.find(
plugin => plugin.printers[astFormat]
);
if (!printerPlugin) {
throw new Error(`Couldn't find plugin for AST format "${astFormat}"`);
}
return printerPlugin;
}
module.exports = getPlugin;

View File

@ -1,9 +1,5 @@
"use strict";
function cleanAST(ast, options) {
return JSON.stringify(massageAST(ast, options), null, 2);
}
function massageAST(ast, options, parent) {
if (Array.isArray(ast)) {
return ast.map(e => massageAST(e, options, parent)).filter(e => e);
@ -14,7 +10,7 @@ function massageAST(ast, options, parent) {
}
const newObj = {};
for (const key in ast) {
for (const key of Object.keys(ast)) {
if (typeof ast[key] !== "function") {
newObj[key] = massageAST(ast[key], options, ast);
}
@ -59,4 +55,4 @@ function massageAST(ast, options, parent) {
return newObj;
}
module.exports = { cleanAST, massageAST };
module.exports = massageAST;

View File

@ -1,11 +1,9 @@
"use strict";
const path = require("path");
const getSupportInfo = require("../common/support").getSupportInfo;
const getSupportInfo = require("../main/support").getSupportInfo;
const normalizer = require("./options-normalizer");
const loadPlugins = require("../common/load-plugins");
const resolveParser = require("./parser").resolveParser;
const getPlugin = require("./get-plugin");
const hiddenDefaults = {
astFormat: "estree",
@ -20,12 +18,8 @@ function normalize(options, opts) {
const rawOptions = Object.assign({}, options);
const plugins = loadPlugins(rawOptions.plugins);
rawOptions.plugins = plugins;
const supportOptions = getSupportInfo(null, {
plugins,
pluginsLoaded: true,
plugins: options.plugins,
showUnreleased: true,
showDeprecated: true
}).options;
@ -99,13 +93,28 @@ function normalize(options, opts) {
);
}
function getPlugin(options) {
const astFormat = options.astFormat;
if (!astFormat) {
throw new Error("getPlugin() requires astFormat to be set");
}
const printerPlugin = options.plugins.find(
plugin => plugin.printers[astFormat]
);
if (!printerPlugin) {
throw new Error(`Couldn't find plugin for AST format "${astFormat}"`);
}
return printerPlugin;
}
function inferParser(filepath, plugins) {
const extension = path.extname(filepath);
const filename = path.basename(filepath).toLowerCase();
const language = getSupportInfo(null, {
plugins,
pluginsLoaded: true
plugins
}).languages.find(
language =>
language.since !== null &&

145
src/main/support.js Normal file
View File

@ -0,0 +1,145 @@
"use strict";
const semver = require("semver");
const arrayify = require("../utils/arrayify");
const currentVersion = require("../../package.json").version;
const coreOptions = require("./core-options").options;
function getSupportInfo(version, opts) {
opts = Object.assign(
{
plugins: [],
showUnreleased: false,
showDeprecated: false,
showInternal: false
},
opts
);
if (!version) {
version = currentVersion;
}
const plugins = opts.plugins;
const options = arrayify(
Object.assign(
plugins.reduce(
(currentOptions, plugin) =>
Object.assign(currentOptions, plugin.options),
{}
),
coreOptions
),
"name"
)
.sort((a, b) => (a.name === b.name ? 0 : a.name < b.name ? -1 : 1))
.filter(filterSince)
.filter(filterDeprecated)
.map(mapDeprecated)
.map(mapInternal)
.map(option => {
const newOption = Object.assign({}, option);
if (Array.isArray(newOption.default)) {
newOption.default =
newOption.default.length === 1
? newOption.default[0].value
: newOption.default
.filter(filterSince)
.sort((info1, info2) =>
semver.compare(info2.since, info1.since)
)[0].value;
}
if (Array.isArray(newOption.choices)) {
newOption.choices = newOption.choices
.filter(filterSince)
.filter(filterDeprecated)
.map(mapDeprecated);
}
return newOption;
})
.map(option => {
const filteredPlugins = plugins.filter(
plugin => plugin.defaultOptions && plugin.defaultOptions[option.name]
);
const pluginDefaults = filteredPlugins.reduce((reduced, plugin) => {
reduced[plugin.name] = plugin.defaultOptions[option.name];
return reduced;
}, {});
return Object.assign(option, { pluginDefaults });
});
const usePostCssParser = semver.lt(version, "1.7.1");
const languages = plugins
.reduce((all, plugin) => all.concat(plugin.languages), [])
.filter(
language =>
language.since
? semver.gte(version, language.since)
: language.since !== null
)
.map(language => {
// Prevent breaking changes
if (language.name === "Markdown") {
return Object.assign({}, language, {
parsers: ["markdown"]
});
}
if (language.name === "TypeScript") {
return Object.assign({}, language, {
parsers: ["typescript"]
});
}
if (usePostCssParser && language.group === "CSS") {
return Object.assign({}, language, {
parsers: ["postcss"]
});
}
return language;
});
return { languages, options };
function filterSince(object) {
return (
opts.showUnreleased ||
!("since" in object) ||
(object.since && semver.gte(version, object.since))
);
}
function filterDeprecated(object) {
return (
opts.showDeprecated ||
!("deprecated" in object) ||
(object.deprecated && semver.lt(version, object.deprecated))
);
}
function mapDeprecated(object) {
if (!object.deprecated || opts.showDeprecated) {
return object;
}
const newObject = Object.assign({}, object);
delete newObject.deprecated;
delete newObject.redirect;
return newObject;
}
function mapInternal(object) {
if (opts.showInternal) {
return object;
}
const newObject = Object.assign({}, object);
delete newObject.cliName;
delete newObject.cliCategory;
delete newObject.cliDescription;
return newObject;
}
}
module.exports = {
getSupportInfo
};

9
src/utils/arrayify.js Normal file
View File

@ -0,0 +1,9 @@
"use strict";
module.exports = function(object, keyName) {
return Object.keys(object).reduce(
(array, key) =>
array.concat(Object.assign({ [keyName]: key }, object[key])),
[]
);
};

View File

@ -3,8 +3,6 @@
const fs = require("fs");
const extname = require("path").extname;
const prettier = require("./require_prettier");
const massageAST = require("../src/common/clean-ast.js").massageAST;
const normalizeOptions = require("../src/main/options").normalize;
const AST_COMPARE = process.env["AST_COMPARE"];
@ -58,17 +56,14 @@ function run_spec(dirname, parsers, options) {
});
if (AST_COMPARE) {
const normalizedOptions = normalizeOptions(mergedOptions);
const ast = parse(source, mergedOptions);
const astMassaged = massageAST(ast, normalizedOptions);
const astMassaged = parse(source, mergedOptions);
let ppastMassaged;
let pperr = null;
try {
const ppast = parse(
ppastMassaged = parse(
prettyprint(source, path, mergedOptions),
mergedOptions
);
ppastMassaged = massageAST(ppast, normalizedOptions);
} catch (e) {
pperr = e.stack;
}
@ -76,7 +71,7 @@ function run_spec(dirname, parsers, options) {
test(path + " parse", () => {
expect(pperr).toBe(null);
expect(ppastMassaged).toBeDefined();
if (!ast.errors || ast.errors.length === 0) {
if (!astMassaged.errors || astMassaged.errors.length === 0) {
expect(astMassaged).toEqual(ppastMassaged);
}
});
@ -95,12 +90,15 @@ function stripLocation(ast) {
const newObj = {};
for (const key in ast) {
if (
key === "loc" ||
key === "range" ||
key === "raw" ||
key === "comments" ||
key === "parent" ||
key === "prev"
[
"loc",
"range",
"raw",
"comments",
"parent",
"prev",
"__location"
].indexOf(key) !== -1
) {
continue;
}
@ -112,7 +110,9 @@ function stripLocation(ast) {
}
function parse(string, opts) {
return stripLocation(prettier.__debug.parse(string, opts).ast);
return stripLocation(
prettier.__debug.parse(string, opts, /* massage */ true).ast
);
}
function prettyprint(src, filename, options) {

View File

@ -4,8 +4,7 @@ const prettier = require("../../tests_config/require_prettier");
const runPrettier = require("../runPrettier");
const constant = require("../../src/cli/constant");
const util = require("../../src/cli/util");
const commonUtil = require("../../src/common/util");
const getSupportInfo = require("../../src/common/support").getSupportInfo;
const arrayify = require("../../src/utils/arrayify");
describe("show version with --version", () => {
runPrettier("cli/with-shebang", ["--version"]).test({
@ -47,35 +46,33 @@ describe(`show detailed usage with plugin options (manual resolution)`, () => {
});
});
commonUtil
.arrayify(
Object.assign(
{},
util.createDetailedOptionMap(
getSupportInfo(null, {
showDeprecated: true,
showUnreleased: true,
showInternal: true
}).options
),
util.normalizeDetailedOptionMap(constant.options)
arrayify(
Object.assign(
{},
util.createDetailedOptionMap(
prettier.getSupportInfo(null, {
showDeprecated: true,
showUnreleased: true,
showInternal: true
}).options
),
"name"
)
.forEach(option => {
const optionNames = [
option.description ? option.name : null,
option.oppositeDescription ? `no-${option.name}` : null
].filter(Boolean);
util.normalizeDetailedOptionMap(constant.options)
),
"name"
).forEach(option => {
const optionNames = [
option.description ? option.name : null,
option.oppositeDescription ? `no-${option.name}` : null
].filter(Boolean);
optionNames.forEach(optionName => {
describe(`show detailed usage with --help ${optionName}`, () => {
runPrettier("cli", ["--help", optionName]).test({
status: 0
});
optionNames.forEach(optionName => {
describe(`show detailed usage with --help ${optionName}`, () => {
runPrettier("cli", ["--help", optionName]).test({
status: 0
});
});
});
});
describe("show warning with --help not-found", () => {
runPrettier("cli", ["--help", "not-found"]).test({