Separate entry for web bundle (#4386)

master
Lucas Duailibe 2018-04-26 13:38:57 -03:00 committed by GitHub
parent 9cc5d4f162
commit 8015e417c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 514 additions and 428 deletions

450
index.js
View File

@ -2,413 +2,39 @@
const version = require("./package.json").version;
const privateUtil = require("./src/common/util");
const sharedUtil = require("./src/common/util-shared");
const core = require("./src/main/core");
const getSupportInfo = require("./src/main/support").getSupportInfo;
const sharedUtil = require("./src/common/util-shared");
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 rawNormalizeOptions = 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;
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") {
return "\r\n";
}
return "\n";
}
function attachComments(text, ast, opts) {
const astComments = ast.comments;
if (astComments) {
delete ast.comments;
comments.attach(astComments, ast, text, opts);
}
ast.tokens = [];
opts.originalText = text.trimRight();
return astComments;
}
function ensureAllCommentsPrinted(astComments) {
if (!astComments) {
return;
}
for (let i = 0; i < astComments.length; ++i) {
if (astComments[i].value.trim() === "prettier-ignore") {
// If there's a prettier-ignore, we're not printing that sub-tree so we
// don't know if the comments was printed or not.
return;
}
}
astComments.forEach(comment => {
if (!comment.printed) {
throw new Error(
'Comment "' +
comment.value.trim() +
'" was not printed. Please report this error!'
);
}
delete comment.printed;
});
}
function formatWithCursor(text, opts, addAlignmentSize) {
const selectedParser = parser.resolveParser(opts);
const hasPragma = !selectedParser.hasPragma || selectedParser.hasPragma(text);
if (opts.requirePragma && !hasPragma) {
return { formatted: text };
}
const UTF8BOM = 0xfeff;
const hasUnicodeBOM = text.charCodeAt(0) === UTF8BOM;
if (hasUnicodeBOM) {
text = text.substring(1);
}
if (
opts.insertPragma &&
opts.printer.insertPragma &&
!hasPragma &&
opts.rangeStart === 0 &&
opts.rangeEnd === Infinity
) {
text = opts.printer.insertPragma(text);
}
addAlignmentSize = addAlignmentSize || 0;
const result = parser.parse(text, opts);
const ast = result.ast;
text = result.text;
const formattedRangeOnly = formatRange(text, opts, ast);
if (formattedRangeOnly) {
return { formatted: formattedRangeOnly };
}
let cursorOffset;
if (opts.cursorOffset >= 0) {
const cursorNodeAndParents = findNodeAtOffset(ast, opts.cursorOffset, opts);
const cursorNode = cursorNodeAndParents.node;
if (cursorNode) {
cursorOffset = opts.cursorOffset - opts.locStart(cursorNode);
opts.cursorNode = cursorNode;
}
}
const astComments = attachComments(text, ast, opts);
const doc = printAstToDoc(ast, opts, addAlignmentSize);
opts.newLine = guessLineEnding(text);
const toStringResult = printDocToString(doc, opts);
let str = toStringResult.formatted;
if (hasUnicodeBOM) {
str = String.fromCharCode(UTF8BOM) + str;
}
const cursorOffsetResult = toStringResult.cursor;
ensureAllCommentsPrinted(astComments);
// Remove extra leading indentation as well as the added indentation after last newline
if (addAlignmentSize > 0) {
return { formatted: str.trim() + opts.newLine };
}
if (cursorOffset !== undefined) {
return {
formatted: str,
cursorOffset: cursorOffsetResult + cursorOffset
};
}
return { formatted: str };
}
function format(text, opts, addAlignmentSize) {
return formatWithCursor(text, opts, addAlignmentSize).formatted;
}
function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
let resultStartNode = startNodeAndParents.node;
let resultEndNode = endNodeAndParents.node;
if (resultStartNode === resultEndNode) {
return {
startNode: resultStartNode,
endNode: resultEndNode
};
}
for (const endParent of endNodeAndParents.parentNodes) {
if (
endParent.type !== "Program" &&
endParent.type !== "File" &&
opts.locStart(endParent) >= opts.locStart(startNodeAndParents.node)
) {
resultEndNode = endParent;
} else {
break;
}
}
for (const startParent of startNodeAndParents.parentNodes) {
if (
startParent.type !== "Program" &&
startParent.type !== "File" &&
opts.locEnd(startParent) <= opts.locEnd(endNodeAndParents.node)
) {
resultStartNode = startParent;
} else {
break;
}
}
return {
startNode: resultStartNode,
endNode: resultEndNode
// Luckily `opts` is always the 2nd argument
function withPlugins(fn) {
return function() {
const args = Array.from(arguments);
const opts = args[1] || {};
args[1] = Object.assign({}, opts, {
plugins: loadPlugins(opts.plugins)
});
return fn.apply(null, args);
};
}
function findNodeAtOffset(node, offset, options, predicate, parentNodes) {
predicate = predicate || (() => true);
parentNodes = parentNodes || [];
const start = options.locStart(node, options.locStart);
const end = options.locEnd(node, options.locEnd);
if (start <= offset && offset <= end) {
for (const childNode of comments.getSortedChildNodes(
node,
undefined /* text */,
options
)) {
const childResult = findNodeAtOffset(
childNode,
offset,
options,
predicate,
[node].concat(parentNodes)
);
if (childResult) {
return childResult;
}
}
if (predicate(node)) {
return {
node: node,
parentNodes: parentNodes
};
}
}
}
// See https://www.ecma-international.org/ecma-262/5.1/#sec-A.5
function isSourceElement(opts, node) {
if (node == null) {
return false;
}
// JS and JS like to avoid repetitions
const jsSourceElements = [
"FunctionDeclaration",
"BlockStatement",
"BreakStatement",
"ContinueStatement",
"DebuggerStatement",
"DoWhileStatement",
"EmptyStatement",
"ExpressionStatement",
"ForInStatement",
"ForStatement",
"IfStatement",
"LabeledStatement",
"ReturnStatement",
"SwitchStatement",
"ThrowStatement",
"TryStatement",
"VariableDeclaration",
"WhileStatement",
"WithStatement",
"ClassDeclaration", // ES 2015
"ImportDeclaration", // Module
"ExportDefaultDeclaration", // Module
"ExportNamedDeclaration", // Module
"ExportAllDeclaration", // Module
"TypeAlias", // Flow
"InterfaceDeclaration", // Flow, TypeScript
"TypeAliasDeclaration", // TypeScript
"ExportAssignment", // TypeScript
"ExportDeclaration" // TypeScript
];
const jsonSourceElements = [
"ObjectExpression",
"ArrayExpression",
"StringLiteral",
"NumericLiteral",
"BooleanLiteral",
"NullLiteral"
];
const graphqlSourceElements = [
"OperationDefinition",
"FragmentDefinition",
"VariableDefinition",
"TypeExtensionDefinition",
"ObjectTypeDefinition",
"FieldDefinition",
"DirectiveDefinition",
"EnumTypeDefinition",
"EnumValueDefinition",
"InputValueDefinition",
"InputObjectTypeDefinition",
"SchemaDefinition",
"OperationTypeDefinition",
"InterfaceTypeDefinition",
"UnionTypeDefinition",
"ScalarTypeDefinition"
];
switch (opts.parser) {
case "flow":
case "babylon":
case "typescript":
return jsSourceElements.indexOf(node.type) > -1;
case "json":
return jsonSourceElements.indexOf(node.type) > -1;
case "graphql":
return graphqlSourceElements.indexOf(node.kind) > -1;
}
return false;
}
function calculateRange(text, opts, ast) {
// Contract the range so that it has non-whitespace characters at its endpoints.
// This ensures we can format a range that doesn't end on a node.
const rangeStringOrig = text.slice(opts.rangeStart, opts.rangeEnd);
const startNonWhitespace = Math.max(
opts.rangeStart + rangeStringOrig.search(/\S/),
opts.rangeStart
);
let endNonWhitespace;
for (
endNonWhitespace = opts.rangeEnd;
endNonWhitespace > opts.rangeStart;
--endNonWhitespace
) {
if (text[endNonWhitespace - 1].match(/\S/)) {
break;
}
}
const startNodeAndParents = findNodeAtOffset(
ast,
startNonWhitespace,
opts,
node => isSourceElement(opts, node)
);
const endNodeAndParents = findNodeAtOffset(
ast,
endNonWhitespace,
opts,
node => isSourceElement(opts, node)
);
if (!startNodeAndParents || !endNodeAndParents) {
return {
rangeStart: 0,
rangeEnd: 0
};
}
const siblingAncestors = findSiblingAncestors(
startNodeAndParents,
endNodeAndParents,
opts
);
const startNode = siblingAncestors.startNode;
const endNode = siblingAncestors.endNode;
const rangeStart = Math.min(
opts.locStart(startNode, opts.locStart),
opts.locStart(endNode, opts.locStart)
);
const rangeEnd = Math.max(
opts.locEnd(startNode, opts.locEnd),
opts.locEnd(endNode, opts.locEnd)
);
return {
rangeStart: rangeStart,
rangeEnd: rangeEnd
};
}
function formatRange(text, opts, ast) {
if (opts.rangeStart <= 0 && text.length <= opts.rangeEnd) {
return;
}
const range = calculateRange(text, opts, ast);
const rangeStart = range.rangeStart;
const rangeEnd = range.rangeEnd;
const rangeString = text.slice(rangeStart, rangeEnd);
// Try to extend the range backwards to the beginning of the line.
// This is so we can detect indentation correctly and restore it.
// Use `Math.min` since `lastIndexOf` returns 0 when `rangeStart` is 0
const rangeStart2 = Math.min(
rangeStart,
text.lastIndexOf("\n", rangeStart) + 1
);
const indentString = text.slice(rangeStart2, rangeStart);
const alignmentSize = privateUtil.getAlignmentSize(
indentString,
opts.tabWidth
);
const rangeFormatted = format(
rangeString,
Object.assign({}, opts, {
rangeStart: 0,
rangeEnd: Infinity,
printWidth: opts.printWidth - alignmentSize
}),
alignmentSize
);
// Since the range contracts to avoid trailing whitespace,
// we need to remove the newline that was inserted by the `format` call.
const rangeTrimmed = rangeFormatted.trimRight();
return text.slice(0, rangeStart) + rangeTrimmed + text.slice(rangeEnd);
}
const formatWithCursor = withPlugins(core.formatWithCursor);
module.exports = {
formatWithCursor: function(text, opts) {
return formatWithCursor(text, normalizeOptions(opts));
},
formatWithCursor,
format: function(text, opts) {
return format(text, normalizeOptions(opts));
format(text, opts) {
return formatWithCursor(text, opts).formatted;
},
check: function(text, opts) {
try {
const formatted = format(text, normalizeOptions(opts));
const formatted = formatWithCursor(text, opts).formatted;
return formatted === text;
} catch (e) {
return false;
@ -421,9 +47,7 @@ module.exports = {
resolveConfigFile: config.resolveConfigFile,
clearConfigCache: config.clearCache,
getSupportInfo(version, opts) {
return getSupportInfo(version, withPlugins(opts));
},
getSupportInfo: withPlugins(getSupportInfo),
version,
@ -431,40 +55,10 @@ module.exports = {
/* istanbul ignore next */
__debug: {
parse: function(text, opts, massage) {
opts = normalizeOptions(opts);
const parsed = parser.parse(text, opts);
if (massage) {
parsed.ast = massageAST(parsed.ast, opts);
}
return parsed;
},
formatAST: function(ast, opts) {
opts = normalizeOptions(opts);
const doc = printAstToDoc(ast, opts);
const str = printDocToString(doc, opts);
return str;
},
// Doesn't handle shebang for now
formatDoc: function(doc, opts) {
opts = normalizeOptions(opts);
const debug = printDocToDebug(doc);
const str = format(debug, opts);
return str;
},
printToDoc: function(text, opts) {
opts = normalizeOptions(opts);
const result = parser.parse(text, opts);
const ast = result.ast;
text = result.text;
attachComments(text, ast, opts);
const doc = printAstToDoc(ast, opts);
return doc;
},
printDocToString: function(doc, opts) {
opts = normalizeOptions(opts);
const str = printDocToString(doc, opts);
return str;
}
parse: withPlugins(core.parse),
formatAST: withPlugins(core.formatAST),
formatDoc: withPlugins(core.formatDoc),
printToDoc: withPlugins(core.printToDoc),
printDocToString: withPlugins(core.printDocToString)
}
};

View File

@ -10,6 +10,7 @@ module.exports = {
collectCoverage: ENABLE_COVERAGE,
collectCoverageFrom: ["src/**/*.js", "index.js", "!<rootDir>/node_modules/"],
coveragePathIgnorePatterns: [
"<rootDir>/web.js",
"<rootDir>/src/doc/doc-debug.js",
"<rootDir>/src/main/massage-ast.js"
],

213
src/main/core.js Normal file
View File

@ -0,0 +1,213 @@
"use strict";
const normalizeOptions = require("./options").normalize;
const massageAST = require("./massage-ast");
const comments = require("./comments");
const parser = require("./parser");
const printAstToDoc = require("./ast-to-doc");
const rangeUtil = require("./range-util");
const privateUtil = require("../common/util");
const doc = require("../doc");
const printDocToString = doc.printer.printDocToString;
const printDocToDebug = doc.debug.printDocToDebug;
const UTF8BOM = 0xfeff;
function guessLineEnding(text) {
const index = text.indexOf("\n");
if (index >= 0 && text.charAt(index - 1) === "\r") {
return "\r\n";
}
return "\n";
}
function ensureAllCommentsPrinted(astComments) {
if (!astComments) {
return;
}
for (let i = 0; i < astComments.length; ++i) {
if (astComments[i].value.trim() === "prettier-ignore") {
// If there's a prettier-ignore, we're not printing that sub-tree so we
// don't know if the comments was printed or not.
return;
}
}
astComments.forEach(comment => {
if (!comment.printed) {
throw new Error(
'Comment "' +
comment.value.trim() +
'" was not printed. Please report this error!'
);
}
delete comment.printed;
});
}
function attachComments(text, ast, opts) {
const astComments = ast.comments;
if (astComments) {
delete ast.comments;
comments.attach(astComments, ast, text, opts);
}
ast.tokens = [];
opts.originalText = text.trimRight();
return astComments;
}
function coreFormat(text, opts, addAlignmentSize) {
addAlignmentSize = addAlignmentSize || 0;
const parsed = parser.parse(text, opts);
const ast = parsed.ast;
text = parsed.text;
let cursorOffset;
if (opts.cursorOffset >= 0) {
const cursorNodeAndParents = rangeUtil.findNodeAtOffset(
ast,
opts.cursorOffset,
opts
);
const cursorNode = cursorNodeAndParents.node;
if (cursorNode) {
cursorOffset = opts.cursorOffset - opts.locStart(cursorNode);
opts.cursorNode = cursorNode;
}
}
const astComments = attachComments(text, ast, opts);
const doc = printAstToDoc(ast, opts, addAlignmentSize);
opts.newLine = guessLineEnding(text);
const result = printDocToString(doc, opts);
const formatted = result.formatted;
const cursorOffsetResult = result.cursor;
ensureAllCommentsPrinted(astComments);
// Remove extra leading indentation as well as the added indentation after last newline
if (addAlignmentSize > 0) {
return { formatted: formatted.trim() + opts.newLine };
}
if (cursorOffset !== undefined) {
return {
formatted,
cursorOffset: cursorOffsetResult + cursorOffset
};
}
return { formatted };
}
function formatRange(text, opts) {
const parsed = parser.parse(text, opts);
const ast = parsed.ast;
text = parsed.text;
const range = rangeUtil.calculateRange(text, opts, ast);
const rangeStart = range.rangeStart;
const rangeEnd = range.rangeEnd;
const rangeString = text.slice(rangeStart, rangeEnd);
// Try to extend the range backwards to the beginning of the line.
// This is so we can detect indentation correctly and restore it.
// Use `Math.min` since `lastIndexOf` returns 0 when `rangeStart` is 0
const rangeStart2 = Math.min(
rangeStart,
text.lastIndexOf("\n", rangeStart) + 1
);
const indentString = text.slice(rangeStart2, rangeStart);
const alignmentSize = privateUtil.getAlignmentSize(
indentString,
opts.tabWidth
);
const rangeFormatted = coreFormat(
rangeString,
Object.assign({}, opts, {
rangeStart: 0,
rangeEnd: Infinity,
printWidth: opts.printWidth - alignmentSize
}),
alignmentSize
).formatted;
// Since the range contracts to avoid trailing whitespace,
// we need to remove the newline that was inserted by the `format` call.
const rangeTrimmed = rangeFormatted.trimRight();
return text.slice(0, rangeStart) + rangeTrimmed + text.slice(rangeEnd);
}
function format(text, opts) {
if (opts.rangeStart > 0 || opts.rangeEnd < text.length) {
return { formatted: formatRange(text, opts) };
}
const selectedParser = parser.resolveParser(opts);
const hasPragma = !selectedParser.hasPragma || selectedParser.hasPragma(text);
if (opts.requirePragma && !hasPragma) {
return { formatted: text };
}
const hasUnicodeBOM = text.charCodeAt(0) === UTF8BOM;
if (hasUnicodeBOM) {
text = text.substring(1);
}
if (opts.insertPragma && opts.printer.insertPragma && !hasPragma) {
text = opts.printer.insertPragma(text);
}
const result = coreFormat(text, opts);
if (hasUnicodeBOM) {
result.formatted = String.fromCharCode(UTF8BOM) + result.formatted;
}
return result;
}
module.exports = {
formatWithCursor(text, opts) {
return format(text, normalizeOptions(opts));
},
parse(text, opts, massage) {
opts = normalizeOptions(opts);
const parsed = parser.parse(text, opts);
if (massage) {
parsed.ast = massageAST(parsed.ast, opts);
}
return parsed;
},
formatAST(ast, opts) {
opts = normalizeOptions(opts);
const doc = printAstToDoc(ast, opts);
return printDocToString(doc, opts);
},
// Doesn't handle shebang for now
formatDoc(doc, opts) {
opts = normalizeOptions(opts);
const debug = printDocToDebug(doc);
return format(debug, opts).formatted;
},
printToDoc(text, opts) {
opts = normalizeOptions(opts);
const parsed = parser.parse(text, opts);
const ast = parsed.ast;
text = parsed.text;
attachComments(text, ast, opts);
return printAstToDoc(ast, opts);
},
printDocToString(doc, opts) {
return printDocToString(doc, normalizeOptions(opts));
}
};

218
src/main/range-util.js Normal file
View File

@ -0,0 +1,218 @@
"use strict";
const comments = require("./comments");
function findSiblingAncestors(startNodeAndParents, endNodeAndParents, opts) {
let resultStartNode = startNodeAndParents.node;
let resultEndNode = endNodeAndParents.node;
if (resultStartNode === resultEndNode) {
return {
startNode: resultStartNode,
endNode: resultEndNode
};
}
for (const endParent of endNodeAndParents.parentNodes) {
if (
endParent.type !== "Program" &&
endParent.type !== "File" &&
opts.locStart(endParent) >= opts.locStart(startNodeAndParents.node)
) {
resultEndNode = endParent;
} else {
break;
}
}
for (const startParent of startNodeAndParents.parentNodes) {
if (
startParent.type !== "Program" &&
startParent.type !== "File" &&
opts.locEnd(startParent) <= opts.locEnd(endNodeAndParents.node)
) {
resultStartNode = startParent;
} else {
break;
}
}
return {
startNode: resultStartNode,
endNode: resultEndNode
};
}
function findNodeAtOffset(node, offset, options, predicate, parentNodes) {
predicate = predicate || (() => true);
parentNodes = parentNodes || [];
const start = options.locStart(node, options.locStart);
const end = options.locEnd(node, options.locEnd);
if (start <= offset && offset <= end) {
for (const childNode of comments.getSortedChildNodes(
node,
undefined /* text */,
options
)) {
const childResult = findNodeAtOffset(
childNode,
offset,
options,
predicate,
[node].concat(parentNodes)
);
if (childResult) {
return childResult;
}
}
if (predicate(node)) {
return {
node: node,
parentNodes: parentNodes
};
}
}
}
// See https://www.ecma-international.org/ecma-262/5.1/#sec-A.5
function isSourceElement(opts, node) {
if (node == null) {
return false;
}
// JS and JS like to avoid repetitions
const jsSourceElements = [
"FunctionDeclaration",
"BlockStatement",
"BreakStatement",
"ContinueStatement",
"DebuggerStatement",
"DoWhileStatement",
"EmptyStatement",
"ExpressionStatement",
"ForInStatement",
"ForStatement",
"IfStatement",
"LabeledStatement",
"ReturnStatement",
"SwitchStatement",
"ThrowStatement",
"TryStatement",
"VariableDeclaration",
"WhileStatement",
"WithStatement",
"ClassDeclaration", // ES 2015
"ImportDeclaration", // Module
"ExportDefaultDeclaration", // Module
"ExportNamedDeclaration", // Module
"ExportAllDeclaration", // Module
"TypeAlias", // Flow
"InterfaceDeclaration", // Flow, TypeScript
"TypeAliasDeclaration", // TypeScript
"ExportAssignment", // TypeScript
"ExportDeclaration" // TypeScript
];
const jsonSourceElements = [
"ObjectExpression",
"ArrayExpression",
"StringLiteral",
"NumericLiteral",
"BooleanLiteral",
"NullLiteral"
];
const graphqlSourceElements = [
"OperationDefinition",
"FragmentDefinition",
"VariableDefinition",
"TypeExtensionDefinition",
"ObjectTypeDefinition",
"FieldDefinition",
"DirectiveDefinition",
"EnumTypeDefinition",
"EnumValueDefinition",
"InputValueDefinition",
"InputObjectTypeDefinition",
"SchemaDefinition",
"OperationTypeDefinition",
"InterfaceTypeDefinition",
"UnionTypeDefinition",
"ScalarTypeDefinition"
];
switch (opts.parser) {
case "flow":
case "babylon":
case "typescript":
return jsSourceElements.indexOf(node.type) > -1;
case "json":
return jsonSourceElements.indexOf(node.type) > -1;
case "graphql":
return graphqlSourceElements.indexOf(node.kind) > -1;
}
return false;
}
function calculateRange(text, opts, ast) {
// Contract the range so that it has non-whitespace characters at its endpoints.
// This ensures we can format a range that doesn't end on a node.
const rangeStringOrig = text.slice(opts.rangeStart, opts.rangeEnd);
const startNonWhitespace = Math.max(
opts.rangeStart + rangeStringOrig.search(/\S/),
opts.rangeStart
);
let endNonWhitespace;
for (
endNonWhitespace = opts.rangeEnd;
endNonWhitespace > opts.rangeStart;
--endNonWhitespace
) {
if (text[endNonWhitespace - 1].match(/\S/)) {
break;
}
}
const startNodeAndParents = findNodeAtOffset(
ast,
startNonWhitespace,
opts,
node => isSourceElement(opts, node)
);
const endNodeAndParents = findNodeAtOffset(
ast,
endNonWhitespace,
opts,
node => isSourceElement(opts, node)
);
if (!startNodeAndParents || !endNodeAndParents) {
return {
rangeStart: 0,
rangeEnd: 0
};
}
const siblingAncestors = findSiblingAncestors(
startNodeAndParents,
endNodeAndParents,
opts
);
const startNode = siblingAncestors.startNode;
const endNode = siblingAncestors.endNode;
const rangeStart = Math.min(
opts.locStart(startNode, opts.locStart),
opts.locStart(endNode, opts.locStart)
);
const rangeEnd = Math.max(
opts.locEnd(startNode, opts.locEnd),
opts.locEnd(endNode, opts.locEnd)
);
return {
rangeStart: rangeStart,
rangeEnd: rangeEnd
};
}
module.exports = {
calculateRange,
findNodeAtOffset
};

60
web.js Normal file
View File

@ -0,0 +1,60 @@
"use strict";
const version = require("./package.json").version;
const core = require("./src/main/core");
const getSupportInfo = require("./src/main/support").getSupportInfo;
const internalPlugins = [
require("./src/language-js"),
require("./src/language-css"),
require("./src/language-handlebars"),
require("./src/language-graphql"),
require("./src/language-markdown"),
require("./src/language-html"),
require("./src/language-vue")
];
const externalPlugins = {};
// Luckily `opts` is always the 2nd argument
function withPlugins(fn) {
return function() {
const args = Array.from(arguments);
const opts = args[1] || {};
args[1] = Object.assign({}, opts, {
plugins: internalPlugins.concat(
(opts.plugins || [])
.map(
plugin =>
typeof plugin === "string" ? externalPlugins[plugin] : plugin
)
.filter(Boolean)
)
});
return fn.apply(null, args);
};
}
module.exports = {
registerPlugin(pluginName, pluginBundle) {
if (!externalPlugins.hasOwnProperty(pluginName)) {
externalPlugins[pluginName] = pluginBundle;
}
},
format(text, opts) {
return withPlugins(core.formatWithCursor)(text, opts).formatted;
},
getSupportInfo: withPlugins(getSupportInfo),
version,
__debug: {
parse: withPlugins(core.parse),
formatAST: withPlugins(core.formatAST),
formatDoc: withPlugins(core.formatDoc),
printToDoc: withPlugins(core.printToDoc),
printDocToString: withPlugins(core.printDocToString)
}
};