Split up comment printing (#3575)
* Split up comment printing * Refactor plugin handling * Allow multiparser to use options normalization * Rename to canAttachComment * Add inline comment * Format code * Use prettier.__debug to get ASTmaster
parent
358984ef0c
commit
ee148bfded
45
index.js
45
index.js
|
@ -1,17 +1,22 @@
|
|||
"use strict";
|
||||
|
||||
const comments = require("./src/main/comments");
|
||||
const docblock = require("jest-docblock");
|
||||
|
||||
const version = require("./package.json").version;
|
||||
const printAstToDoc = require("./src/main/ast-to-doc");
|
||||
|
||||
const util = require("./src/common/util");
|
||||
const getSupportInfo = require("./src/common/support").getSupportInfo;
|
||||
|
||||
const comments = require("./src/main/comments");
|
||||
const printAstToDoc = require("./src/main/ast-to-doc");
|
||||
const normalizeOptions = require("./src/main/options").normalize;
|
||||
const parser = require("./src/main/parser");
|
||||
|
||||
const config = require("./src/config/resolve-config");
|
||||
|
||||
const doc = require("./src/doc");
|
||||
const printDocToString = doc.printer.printDocToString;
|
||||
const printDocToDebug = doc.debug.printDocToDebug;
|
||||
const normalizeOptions = require("./src/common/options").normalize;
|
||||
const parser = require("./src/main/parser");
|
||||
const config = require("./src/config/resolve-config");
|
||||
const getSupportInfo = require("./src/common/support").getSupportInfo;
|
||||
const docblock = require("jest-docblock");
|
||||
|
||||
function guessLineEnding(text) {
|
||||
const index = text.indexOf("\n");
|
||||
|
@ -101,7 +106,7 @@ function formatWithCursor(text, opts, addAlignmentSize) {
|
|||
|
||||
let cursorOffset;
|
||||
if (opts.cursorOffset >= 0) {
|
||||
const cursorNodeAndParents = findNodeAtOffset(ast, opts.cursorOffset);
|
||||
const cursorNodeAndParents = findNodeAtOffset(ast, opts.cursorOffset, opts);
|
||||
const cursorNode = cursorNodeAndParents.node;
|
||||
if (cursorNode) {
|
||||
cursorOffset = opts.cursorOffset - util.locStart(cursorNode);
|
||||
|
@ -179,16 +184,21 @@ function findSiblingAncestors(startNodeAndParents, endNodeAndParents) {
|
|||
};
|
||||
}
|
||||
|
||||
function findNodeAtOffset(node, offset, predicate, parentNodes) {
|
||||
function findNodeAtOffset(node, offset, options, predicate, parentNodes) {
|
||||
predicate = predicate || (() => true);
|
||||
parentNodes = parentNodes || [];
|
||||
const start = util.locStart(node);
|
||||
const end = util.locEnd(node);
|
||||
if (start <= offset && offset <= end) {
|
||||
for (const childNode of comments.getSortedChildNodes(node)) {
|
||||
for (const childNode of comments.getSortedChildNodes(
|
||||
node,
|
||||
undefined /* text */,
|
||||
options
|
||||
)) {
|
||||
const childResult = findNodeAtOffset(
|
||||
childNode,
|
||||
offset,
|
||||
options,
|
||||
predicate,
|
||||
[node].concat(parentNodes)
|
||||
);
|
||||
|
@ -301,11 +311,17 @@ function calculateRange(text, opts, ast) {
|
|||
}
|
||||
}
|
||||
|
||||
const startNodeAndParents = findNodeAtOffset(ast, startNonWhitespace, node =>
|
||||
isSourceElement(opts, node)
|
||||
const startNodeAndParents = findNodeAtOffset(
|
||||
ast,
|
||||
startNonWhitespace,
|
||||
opts,
|
||||
node => isSourceElement(opts, node)
|
||||
);
|
||||
const endNodeAndParents = findNodeAtOffset(ast, endNonWhitespace, node =>
|
||||
isSourceElement(opts, node)
|
||||
const endNodeAndParents = findNodeAtOffset(
|
||||
ast,
|
||||
endNonWhitespace,
|
||||
opts,
|
||||
node => isSourceElement(opts, node)
|
||||
);
|
||||
|
||||
if (!startNodeAndParents || !endNodeAndParents) {
|
||||
|
@ -398,6 +414,7 @@ module.exports = {
|
|||
/* istanbul ignore next */
|
||||
__debug: {
|
||||
parse: function(text, opts) {
|
||||
opts = normalizeOptions(opts);
|
||||
return parser.parse(text, opts);
|
||||
},
|
||||
formatAST: function(ast, opts) {
|
||||
|
|
|
@ -16,7 +16,7 @@ const cleanAST = require("../common/clean-ast").cleanAST;
|
|||
const resolver = require("../config/resolve-config");
|
||||
const constant = require("./constant");
|
||||
const validator = require("./validator");
|
||||
const apiDefaultOptions = require("../common/options").defaults;
|
||||
const apiDefaultOptions = require("../main/options").defaults;
|
||||
const errors = require("../common/errors");
|
||||
const logger = require("./logger");
|
||||
const thirdParty = require("../common/third-party");
|
||||
|
|
|
@ -12,9 +12,15 @@ function loadPlugins(options) {
|
|||
require("../language-markdown"),
|
||||
require("../language-html"),
|
||||
require("../language-vue")
|
||||
];
|
||||
].filter(plugin => {
|
||||
return options.plugins.indexOf(plugin) < 0;
|
||||
});
|
||||
|
||||
const externalPlugins = options.plugins.map(plugin => {
|
||||
if (typeof plugin !== "string") {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
const pluginPath = resolve.sync(plugin, { basedir: process.cwd() });
|
||||
return eval("require")(pluginPath);
|
||||
});
|
||||
|
|
|
@ -539,7 +539,24 @@ function printSequence(sequencePath, options, print) {
|
|||
});
|
||||
}
|
||||
|
||||
function canAttachComment(node) {
|
||||
return node.kind && node.kind !== "Comment";
|
||||
}
|
||||
|
||||
function printComment(commentPath) {
|
||||
const comment = commentPath.getValue();
|
||||
|
||||
switch (comment.kind) {
|
||||
case "Comment":
|
||||
return "#" + comment.value.trimRight();
|
||||
default:
|
||||
throw new Error("Not a comment: " + JSON.stringify(comment));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print: genericPrint,
|
||||
hasPrettierIgnore: util.hasIgnoreComment
|
||||
hasPrettierIgnore: util.hasIgnoreComment,
|
||||
printComment,
|
||||
canAttachComment
|
||||
};
|
||||
|
|
|
@ -5167,9 +5167,77 @@ function willPrintOwnComments(path) {
|
|||
);
|
||||
}
|
||||
|
||||
function canAttachComment(node) {
|
||||
return (
|
||||
node.type &&
|
||||
node.type !== "CommentBlock" &&
|
||||
node.type !== "CommentLine" &&
|
||||
node.type !== "Line" &&
|
||||
node.type !== "Block" &&
|
||||
node.type !== "EmptyStatement" &&
|
||||
node.type !== "TemplateElement" &&
|
||||
node.type !== "Import" &&
|
||||
!(node.callee && node.callee.type === "Import")
|
||||
);
|
||||
}
|
||||
|
||||
function printComment(commentPath, options) {
|
||||
const comment = commentPath.getValue();
|
||||
|
||||
switch (comment.type) {
|
||||
case "CommentBlock":
|
||||
case "Block": {
|
||||
if (isJsDocComment(comment)) {
|
||||
return printJsDocComment(comment);
|
||||
}
|
||||
|
||||
const isInsideFlowComment =
|
||||
options.originalText.substr(util.locEnd(comment) - 3, 3) === "*-/";
|
||||
|
||||
return "/*" + comment.value + (isInsideFlowComment ? "*-/" : "*/");
|
||||
}
|
||||
case "CommentLine":
|
||||
case "Line":
|
||||
// Print shebangs with the proper comment characters
|
||||
if (options.originalText.slice(util.locStart(comment)).startsWith("#!")) {
|
||||
return "#!" + comment.value.trimRight();
|
||||
}
|
||||
return "//" + comment.value.trimRight();
|
||||
default:
|
||||
throw new Error("Not a comment: " + JSON.stringify(comment));
|
||||
}
|
||||
}
|
||||
|
||||
function isJsDocComment(comment) {
|
||||
const lines = comment.value.split("\n");
|
||||
return (
|
||||
lines.length > 1 &&
|
||||
lines.slice(0, lines.length - 1).every(line => line.trim()[0] === "*")
|
||||
);
|
||||
}
|
||||
|
||||
function printJsDocComment(comment) {
|
||||
const lines = comment.value.split("\n");
|
||||
|
||||
return concat([
|
||||
"/*",
|
||||
join(
|
||||
hardline,
|
||||
lines.map(
|
||||
(line, index) =>
|
||||
(index > 0 ? " " : "") +
|
||||
(index < lines.length - 1 ? line.trim() : line.trimLeft())
|
||||
)
|
||||
),
|
||||
"*/"
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print: genericPrint,
|
||||
embed,
|
||||
hasPrettierIgnore,
|
||||
willPrintOwnComments
|
||||
willPrintOwnComments,
|
||||
canAttachComment,
|
||||
printComment
|
||||
};
|
||||
|
|
|
@ -12,12 +12,11 @@ const concat = docBuilders.concat;
|
|||
const hardline = docBuilders.hardline;
|
||||
const addAlignmentToDoc = docBuilders.addAlignmentToDoc;
|
||||
const docUtils = doc.utils;
|
||||
const getPrinter = require("./get-printer");
|
||||
|
||||
function printAstToDoc(ast, options, addAlignmentSize) {
|
||||
addAlignmentSize = addAlignmentSize || 0;
|
||||
|
||||
const printer = getPrinter(options);
|
||||
const printer = options.printer;
|
||||
const cache = new Map();
|
||||
|
||||
function printGenerically(path, args) {
|
||||
|
@ -32,11 +31,11 @@ function printAstToDoc(ast, options, addAlignmentSize) {
|
|||
// UnionTypeAnnotation has to align the child without the comments
|
||||
let res;
|
||||
if (printer.willPrintOwnComments && printer.willPrintOwnComments(path)) {
|
||||
res = genericPrint(path, options, printer, printGenerically, args);
|
||||
res = genericPrint(path, options, printGenerically, args);
|
||||
} else {
|
||||
res = comments.printComments(
|
||||
path,
|
||||
p => genericPrint(p, options, printer, printGenerically, args),
|
||||
p => genericPrint(p, options, printGenerically, args),
|
||||
options,
|
||||
args && args.needsSemi
|
||||
);
|
||||
|
@ -68,10 +67,11 @@ function printAstToDoc(ast, options, addAlignmentSize) {
|
|||
return doc;
|
||||
}
|
||||
|
||||
function genericPrint(path, options, printer, printPath, args) {
|
||||
function genericPrint(path, options, printPath, args) {
|
||||
assert.ok(path instanceof FastPath);
|
||||
|
||||
const node = path.getValue();
|
||||
const printer = options.printer;
|
||||
|
||||
// Escape hatch
|
||||
if (printer.hasPrettierIgnore && printer.hasPrettierIgnore(path)) {
|
||||
|
@ -81,7 +81,7 @@ function genericPrint(path, options, printer, printPath, args) {
|
|||
if (node) {
|
||||
try {
|
||||
// Potentially switch to a different parser
|
||||
const sub = multiparser.printSubtree(printer, path, printPath, options);
|
||||
const sub = multiparser.printSubtree(path, printPath, options);
|
||||
if (sub) {
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -18,25 +18,14 @@ const getNextNonSpaceNonCommentCharacter =
|
|||
const getNextNonSpaceNonCommentCharacterIndex =
|
||||
util.getNextNonSpaceNonCommentCharacterIndex;
|
||||
|
||||
function getSortedChildNodes(node, text, resultArray) {
|
||||
function getSortedChildNodes(node, text, options, resultArray) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const printer = options.printer;
|
||||
|
||||
if (resultArray) {
|
||||
if (
|
||||
node &&
|
||||
((node.type &&
|
||||
node.type !== "CommentBlock" &&
|
||||
node.type !== "CommentLine" &&
|
||||
node.type !== "Line" &&
|
||||
node.type !== "Block" &&
|
||||
node.type !== "EmptyStatement" &&
|
||||
node.type !== "TemplateElement" &&
|
||||
node.type !== "Import" &&
|
||||
!(node.callee && node.callee.type === "Import")) ||
|
||||
(node.kind && node.kind !== "Comment"))
|
||||
) {
|
||||
if (node && printer.canAttachComment && printer.canAttachComment(node)) {
|
||||
// This reverse insertion sort almost always takes constant
|
||||
// time because we almost always (maybe always?) append the
|
||||
// nodes in order anyway.
|
||||
|
@ -74,7 +63,7 @@ function getSortedChildNodes(node, text, resultArray) {
|
|||
}
|
||||
|
||||
for (let i = 0, nameCount = names.length; i < nameCount; ++i) {
|
||||
getSortedChildNodes(node[names[i]], text, resultArray);
|
||||
getSortedChildNodes(node[names[i]], text, options, resultArray);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
|
@ -83,8 +72,8 @@ function getSortedChildNodes(node, text, resultArray) {
|
|||
// As efficiently as possible, decorate the comment object with
|
||||
// .precedingNode, .enclosingNode, and/or .followingNode properties, at
|
||||
// least one of which is guaranteed to be defined.
|
||||
function decorateComment(node, comment, text) {
|
||||
const childNodes = getSortedChildNodes(node, text);
|
||||
function decorateComment(node, comment, text, options) {
|
||||
const childNodes = getSortedChildNodes(node, text, options);
|
||||
let precedingNode;
|
||||
let followingNode;
|
||||
// Time to dust off the old binary search robes and wizard hat.
|
||||
|
@ -101,7 +90,7 @@ function decorateComment(node, comment, text) {
|
|||
// The comment is completely contained by this child node.
|
||||
comment.enclosingNode = child;
|
||||
|
||||
decorateComment(child, comment, text);
|
||||
decorateComment(child, comment, text, options);
|
||||
return; // Abandon the binary search at this level.
|
||||
}
|
||||
|
||||
|
@ -174,7 +163,7 @@ function attach(comments, ast, text, options) {
|
|||
return;
|
||||
}
|
||||
|
||||
decorateComment(ast, comment, text);
|
||||
decorateComment(ast, comment, text, options);
|
||||
|
||||
const precedingNode = comment.precedingNode;
|
||||
const enclosingNode = comment.enclosingNode;
|
||||
|
@ -923,56 +912,7 @@ function handleVariableDeclaratorComments(
|
|||
function printComment(commentPath, options) {
|
||||
const comment = commentPath.getValue();
|
||||
comment.printed = true;
|
||||
|
||||
switch (comment.type || comment.kind) {
|
||||
case "Comment":
|
||||
return "#" + comment.value.trimRight();
|
||||
case "CommentBlock":
|
||||
case "Block": {
|
||||
if (isJsDocComment(comment)) {
|
||||
return printJsDocComment(comment);
|
||||
}
|
||||
|
||||
const isInsideFlowComment =
|
||||
options.originalText.substr(util.locEnd(comment) - 3, 3) === "*-/";
|
||||
|
||||
return "/*" + comment.value + (isInsideFlowComment ? "*-/" : "*/");
|
||||
}
|
||||
case "CommentLine":
|
||||
case "Line":
|
||||
// Print shebangs with the proper comment characters
|
||||
if (options.originalText.slice(util.locStart(comment)).startsWith("#!")) {
|
||||
return "#!" + comment.value.trimRight();
|
||||
}
|
||||
return "//" + comment.value.trimRight();
|
||||
default:
|
||||
throw new Error("Not a comment: " + JSON.stringify(comment));
|
||||
}
|
||||
}
|
||||
|
||||
function isJsDocComment(comment) {
|
||||
const lines = comment.value.split("\n");
|
||||
return (
|
||||
lines.length > 1 &&
|
||||
lines.slice(0, lines.length - 1).every(line => line.trim()[0] === "*")
|
||||
);
|
||||
}
|
||||
|
||||
function printJsDocComment(comment) {
|
||||
const lines = comment.value.split("\n");
|
||||
|
||||
return concat([
|
||||
"/*",
|
||||
join(
|
||||
hardline,
|
||||
lines.map(
|
||||
(line, index) =>
|
||||
(index > 0 ? " " : "") +
|
||||
(index < lines.length - 1 ? line.trim() : line.trimLeft())
|
||||
)
|
||||
),
|
||||
"*/"
|
||||
]);
|
||||
return options.printer.printComment(commentPath, options);
|
||||
}
|
||||
|
||||
function findExpressionIndexForComment(quasis, comment) {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
const loadPlugins = require("../common/load-plugins");
|
||||
const parser = require("./parser");
|
||||
|
||||
function getPrinter(options) {
|
||||
const plugins = loadPlugins(options);
|
||||
const parsers = parser.getParsers(plugins, options);
|
||||
const astFormat = parser.resolveParser(parsers, options).astFormat;
|
||||
const printerPlugin = plugins.find(plugin => plugin.printers[astFormat]);
|
||||
const astFormat = options.astFormat;
|
||||
|
||||
if (!astFormat) {
|
||||
throw new Error("getPrinter() requires astFormat to be set");
|
||||
}
|
||||
const printerPlugin = options.plugins.find(
|
||||
plugin => plugin.printers[astFormat]
|
||||
);
|
||||
if (!printerPlugin) {
|
||||
throw new Error(
|
||||
`Couldn't find printer plugin for AST format "${astFormat}"`
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
const normalize = require("./options").normalize;
|
||||
const comments = require("./comments");
|
||||
|
||||
function printSubtree(printer, path, print, options) {
|
||||
if (printer.embed) {
|
||||
return printer.embed(
|
||||
function printSubtree(path, print, options) {
|
||||
if (options.printer.embed) {
|
||||
return options.printer.embed(
|
||||
path,
|
||||
print,
|
||||
(text, partialNextOptions) =>
|
||||
|
@ -15,13 +16,12 @@ function printSubtree(printer, path, print, options) {
|
|||
}
|
||||
|
||||
function textToDoc(text, partialNextOptions, parentOptions) {
|
||||
const nextOptions = Object.assign({}, parentOptions, partialNextOptions, {
|
||||
parentParser: parentOptions.parser,
|
||||
originalText: text
|
||||
});
|
||||
if (nextOptions.parser === "json") {
|
||||
nextOptions.trailingComma = "none";
|
||||
}
|
||||
const nextOptions = normalize(
|
||||
Object.assign({}, parentOptions, partialNextOptions, {
|
||||
parentParser: parentOptions.parser,
|
||||
originalText: text
|
||||
})
|
||||
);
|
||||
|
||||
const ast = require("./parser").parse(text, nextOptions);
|
||||
const astComments = ast.comments;
|
||||
|
|
|
@ -4,7 +4,10 @@ const path = require("path");
|
|||
|
||||
const validate = require("jest-validate").validate;
|
||||
const deprecatedConfig = require("./deprecated");
|
||||
const getSupportInfo = require("./support").getSupportInfo;
|
||||
const getSupportInfo = require("../common/support").getSupportInfo;
|
||||
const loadPlugins = require("../common/load-plugins");
|
||||
const resolveParser = require("./parser").resolveParser;
|
||||
const getPrinter = require("./get-printer");
|
||||
|
||||
const defaults = {
|
||||
cursorOffset: -1,
|
||||
|
@ -18,12 +21,16 @@ const defaults = {
|
|||
bracketSpacing: true,
|
||||
jsxBracketSameLine: false,
|
||||
parser: "babylon",
|
||||
parentParser: "",
|
||||
insertPragma: false,
|
||||
requirePragma: false,
|
||||
semi: true,
|
||||
proseWrap: "preserve",
|
||||
arrowParens: "avoid",
|
||||
plugins: []
|
||||
plugins: [],
|
||||
astFormat: "estree",
|
||||
printer: {},
|
||||
__inJsTemplate: false
|
||||
};
|
||||
|
||||
const exampleConfig = Object.assign({}, defaults, {
|
||||
|
@ -39,6 +46,7 @@ function normalize(options) {
|
|||
|
||||
if (
|
||||
filepath &&
|
||||
!normalized.parentParser &&
|
||||
(!normalized.parser || normalized.parser === defaults.parser)
|
||||
) {
|
||||
const extension = path.extname(filepath);
|
||||
|
@ -114,6 +122,10 @@ function normalize(options) {
|
|||
delete normalized.useFlowParser;
|
||||
}
|
||||
|
||||
normalized.plugins = loadPlugins(normalized);
|
||||
normalized.astFormat = resolveParser(normalized).astFormat;
|
||||
normalized.printer = getPrinter(normalized);
|
||||
|
||||
Object.keys(defaults).forEach(k => {
|
||||
if (normalized[k] == null) {
|
||||
normalized[k] = defaults[k];
|
|
@ -2,16 +2,17 @@
|
|||
|
||||
const path = require("path");
|
||||
const ConfigError = require("../common/errors").ConfigError;
|
||||
const loadPlugins = require("../common/load-plugins");
|
||||
|
||||
function getParsers(plugins) {
|
||||
return plugins.reduce(
|
||||
function getParsers(options) {
|
||||
return options.plugins.reduce(
|
||||
(parsers, plugin) => Object.assign({}, parsers, plugin.parsers),
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
function resolveParser(parsers, opts) {
|
||||
function resolveParser(opts, parsers) {
|
||||
parsers = parsers || getParsers(opts);
|
||||
|
||||
if (typeof opts.parser === "function") {
|
||||
// Custom parser API always works with JavaScript.
|
||||
return {
|
||||
|
@ -39,7 +40,7 @@ function resolveParser(parsers, opts) {
|
|||
}
|
||||
|
||||
function parse(text, opts) {
|
||||
const parsers = getParsers(loadPlugins(opts), opts);
|
||||
const parsers = getParsers(opts);
|
||||
|
||||
// Copy the "parse" function from parser to a new object whose values are
|
||||
// functions. Use defineProperty()/getOwnPropertyDescriptor() such that we
|
||||
|
@ -54,7 +55,7 @@ function parse(text, opts) {
|
|||
{}
|
||||
);
|
||||
|
||||
const parser = resolveParser(parsers, opts);
|
||||
const parser = resolveParser(opts, parsers);
|
||||
|
||||
try {
|
||||
return parser.parse(text, parsersForCustomParserApi, opts);
|
||||
|
@ -75,4 +76,4 @@ function parse(text, opts) {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = { getParsers, parse, resolveParser };
|
||||
module.exports = { parse, resolveParser };
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
const fs = require("fs");
|
||||
const extname = require("path").extname;
|
||||
const prettier = require("./require_prettier");
|
||||
const parser = require("../src/main/parser");
|
||||
const massageAST = require("../src/common/clean-ast.js").massageAST;
|
||||
|
||||
const AST_COMPARE = process.env["AST_COMPARE"];
|
||||
|
@ -116,7 +115,7 @@ function stripLocation(ast) {
|
|||
}
|
||||
|
||||
function parse(string, opts) {
|
||||
return stripLocation(parser.parse(string, opts));
|
||||
return stripLocation(prettier.__debug.parse(string, opts));
|
||||
}
|
||||
|
||||
function prettyprint(src, filename, options) {
|
||||
|
|
Loading…
Reference in New Issue