Tillägg
Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →
Tillägg är sätt att lägga till nya språk eller formateringsregler till Prettier. Prettiers egna implementationer av alla språk uttrycks med plugin-API:t. Grundpaketet prettier innehåller JavaScript och andra webbinriktade språk inbyggda. För ytterligare språk behöver du installera ett tillägg.
Använda tillägg
Du kan ladda tillägg via:
-
CLI:n med
--plugin:prettier --write main.foo --plugin=prettier-plugin-footipsDu kan ange
--plugin-flaggan flera gånger. -
API:t via
plugins-alternativet:await prettier.format("code", {
parser: "foo",
plugins: ["prettier-plugin-foo"],
}); -
{
"plugins": ["prettier-plugin-foo"]
}
Strängar som anges till plugins skickas slutligen till import()-uttrycket, så du kan ange ett modul-/paketnamn, en sökväg eller annat som import() accepterar.
Officiella tillägg
Community-tillägg
-
prettier-plugin-tomlav @JounQin och @so1ve
Utveckla plugin
Prettier-plugin är vanliga JavaScript-moduler som exporterar följande fem element, eller en standardexport med dessa egenskaper:
-
languages -
parsers -
printers -
options -
defaultOptions
languages
Languages är en array med språkdefinitioner som din plugin tillför till Prettier. Den kan innehålla alla fält som specificeras i prettier.getSupportInfo().
Den måste innehålla name och parsers.
export const languages = [
{
// The language name
name: "InterpretedDanceScript",
// Parsers that can parse this language.
// This can be built-in parsers, or parsers you have contributed via this plugin.
parsers: ["dance-parse"],
},
];
parsers
Parsers omvandlar kod som sträng till ett AST.
Nyckeln måste matcha namnet i parsers-arrayen från languages. Värdet innehåller en parse-funktion, ett AST-formatnamn och två funktioner för platsutvinning (locStart och locEnd).
export const parsers = {
"dance-parse": {
parse,
// The name of the AST that the parser produces.
astFormat: "dance-ast",
hasPragma,
hasIgnorePragma,
locStart,
locEnd,
preprocess,
},
};
Signatur för parse-funktionen är:
function parse(text: string, options: object): Promise<AST> | AST;
Platsutvinningsfunktionerna (locStart och locEnd) returnerar start- och slutpositionen för en given AST-nod:
function locStart(node: object): number;
(Valfritt) Pragma-detekteringsfunktionen (hasPragma) ska returnera om texten innehåller pragma-kommentaren.
function hasPragma(text: string): boolean;
(Valfritt) "Ignorera pragma"-detekteringsfunktionen (hasIgnorePragma) ska returnera om texten innehåller ett pragma som indikerar att texten inte ska formateras.
function hasIgnorePragma(text: string): boolean;
(Valfritt) Preprocess-funktionen kan bearbeta inmatningstexten innan den skickas till parse-funktionen.
function preprocess(text: string, options: object): string | Promise<string>;
Stöd för asynkron förbearbetning lades till först i v3.7.0
printers
Printers omvandlar AST-träd till Prettiers intermediära representation, även känd som ett Doc.
Nyckeln måste matcha det astFormat som parsern producerar. Värdet innehåller ett objekt med en print-funktion. Alla andra egenskaper (embed, preprocess, etc.) är valfria.
export const printers = {
"dance-ast": {
print,
embed,
preprocess,
getVisitorKeys,
insertPragma,
canAttachComment,
isBlockComment,
printComment,
getCommentChildNodes,
hasPrettierIgnore,
printPrettierIgnored,
handleComments: {
ownLine,
endOfLine,
remaining,
},
},
};
Utskriftsprocessen
Prettier använder en intermediär representation kallad Doc, som sedan omvandlas till en sträng (baserat på alternativ som printWidth). En printers uppgift är att ta AST:n genererad av parsers[<parser name>].parse och returnera ett Doc. Ett Doc konstrueras med hjälp av byggarkommandon:
import * as prettier from "prettier";
const { join, line, ifBreak, group } = prettier.doc.builders;
Utskriftsprocessen består av följande steg:
-
AST-förbearbetning (valfritt). Se
preprocess. -
Kommentarsfäste (valfritt). Se Hantera kommentarer i en printer.
-
Bearbetning av inbäddade språk (valfritt). Metoden
embed, om definierad, anropas för varje nod, djup-först. Trots att rekursionen är synkron av prestandaskäl kanembedreturnera asynkrona funktioner som kan anropa andra parsers och printers för att skapa docs för inbäddade syntaxer som CSS-in-JS. Dessa returnerade funktioner köas upp och exekveras sekventiellt före nästa steg. -
Rekursiv utskrift. Ett doc konstrueras rekursivt från AST:n. Startar från rotnoden:
- Om det från steg 3 finns ett inbäddat språkdoc associerat med aktuell nod, används detta doc.
- Annars anropas
print(path, options, print): Doc-metoden. Den komponerar ett doc för aktuell nod, ofta genom att skriva ut barnnoder medprint-återanropet.
print
Mesta delen av en plugin-printers arbete sker i dess print-funktion, med signatur:
function print(
// Path to the AST node to print
path: AstPath,
options: object,
// Recursively print a child node
print: (selector?: string | number | Array<string | number> | AstPath) => Doc,
): Doc;
print-funktionen får följande parametrar:
-
path: Ett objekt som används för att komma åt noder i AST:n. Det är en stackliknande datastruktur som håller reda på det aktuella rekursionstillståndet. Kallas "path" eftersom det representerar vägen till aktuell nod från AST:ns rot. Aktuell nod returneras avpath.node. -
options: Ett beständigt objekt som innehåller globala alternativ och som en plugin kan mutera för att lagra kontextuell data. -
print: Ett återanrop för utskrift av undernoder. Denna funktion innehåller kärnlogik för utskrift vars implementering tillhandahålls av plugins. Specifikt anropar den printernsprint-funktion och skickar sig själv vidare. Således anropar de tvåprint-funktionerna – den från kärnan och den från pluginen – varandra medan de rekursivt traverserar neråt i AST:n.
Här är ett förenklat exempel som ger en uppfattning om hur en typisk print-implementation kan se ut:
import * as prettier from "prettier";
const { group, indent, join, line, softline } = prettier.doc.builders;
function print(path, options, print) {
const node = path.node;
switch (node.type) {
case "list":
return group([
"(",
indent([softline, join(line, path.map(print, "elements"))]),
softline,
")",
]);
case "pair":
return group([
"(",
indent([softline, print("left"), line, ". ", print("right")]),
softline,
")",
]);
case "symbol":
return node.name;
}
throw new Error(`Unknown node type: ${node.type}`);
}
Kolla in prettier-pythons printer för några exempel på vad som är möjligt.
(valfritt) embed
En printer kan ha embed-metoden för att skriva ut ett språk inuti ett annat. Exempel på detta är CSS-in-JS eller kodblock i Markdown. Signatur:
function embed(
// Path to the current AST node
path: AstPath,
// Current options
options: Options,
):
| ((
// Parses and prints the passed text using a different parser.
// You should set `options.parser` to specify which parser to use.
textToDoc: (text: string, options: Options) => Promise<Doc>,
// Prints the current node or its descendant node with the current printer
print: (
selector?: string | number | Array<string | number> | AstPath,
) => Doc,
// The following two arguments are passed for convenience.
// They're the same `path` and `options` that are passed to `embed`.
path: AstPath,
options: Options,
) => Promise<Doc | undefined> | Doc | undefined)
| Doc
| undefined;
embed-metoden liknar print i att den mappar AST-noder till dokument, men till skillnad från print kan den utföra asynkront arbete genom att returnera en asynkron funktion. Denna funktions första parameter, textToDoc (en asynkron funktion), kan användas för att rendera ett dokument med ett annat plugin.
Om en funktion som returneras från embed returnerar ett dokument eller ett löfte som löser till ett dokument, kommer detta dokument att användas vid utskrift och print-metoden kommer inte att anropas för denna nod. Det är också möjligt och i sällsynta fall praktiskt att returnera ett dokument synkront direkt från embed, men då är textToDoc och print-återanropet inte tillgängliga. Returnera en funktion för att få tillgång till dem.
Om embed returnerar undefined, eller om en returnerad funktion returnerar undefined eller ett löfte som löser till undefined, kommer noden att skrivas ut normalt med print-metoden. Samma sak händer om en returnerad funktion kastar ett fel eller returnerar ett avvisat löfte (t.ex. vid parsningsfel). Sätt miljövariabeln PRETTIER_DEBUG till ett icke-tomt värde om du vill att Prettier ska kasta om dessa fel.
Till exempel kan ett plugin med noder med inbäddad JavaScript ha följande embed-metod:
function embed(path, options) {
const node = path.node;
if (node.type === "javascript") {
return async (textToDoc) => {
return [
"<script>",
hardline,
await textToDoc(node.javaScriptCode, { parser: "babel" }),
hardline,
"</script>",
];
};
}
}
Om alternativet --embedded-language-formatting är satt till off, hoppas inbäddningssteget över helt, embed anropas inte och alla noder skrivs ut med print-metoden.
(valfritt) preprocess
preprocess-metoden kan bearbeta AST-trädet från parsern innan det skickas till print-metoden.
function preprocess(ast: AST, options: Options): AST | Promise<AST>;
(valfritt) getVisitorKeys
Den här egenskapen kan vara användbar om pluginet använder kommentarsfäste eller inbäddade språk. Dessa funktioner traverserar AST-trädet genom att iterera genom alla egna uppräkningsbara egenskaper från rotnoden. Om AST-trädet innehåller cykler kan en sådan traversering fastna i en oändlig loop. Noder kan också innehålla icke-nodobjekt (t.ex. positionsdata), vilket är resurskrävande att iterera igenom. För att lösa detta kan printem definiera en funktion som returnerar egenskapsnamn som ska traverseras.
Signatur:
function getVisitorKeys(node, nonTraversableKeys: Set<string>): string[];
Standardimplementering av getVisitorKeys:
function getVisitorKeys(node, nonTraversableKeys) {
return Object.keys(node).filter((key) => !nonTraversableKeys.has(key));
}
Den andra parametern nonTraversableKeys är en mängd med vanliga nycklar och nycklar som Prettier använder internt.
Om du har en fullständig lista med traverseringsnycklar:
const visitorKeys = {
Program: ["body"],
Identifier: [],
// ...
};
function getVisitorKeys(node /* , nonTraversableKeys*/) {
// Return `[]` for unknown node to prevent Prettier fallback to use `Object.keys()`
return visitorKeys[node.type] ?? [];
}
Om du bara behöver exkludera en liten uppsättning nycklar:
const ignoredKeys = new Set(["prev", "next", "range"]);
function getVisitorKeys(node, nonTraversableKeys) {
return Object.keys(node).filter(
(key) => !nonTraversableKeys.has(key) && !ignoredKeys.has(key),
);
}
(valfritt) insertPragma
Ett plugin kan implementera hur en pragmakommentar infogas i resultatkoden när alternativet --insert-pragma används, via funktionen insertPragma. Signatur:
function insertPragma(text: string): string;
Hantera kommentarer i en printer
Kommentarer är ofta inte en del av ett språks AST och utgör en utmaning för printers. Ett Prettier-plugin kan antingen skriva ut kommentarer själv i sin print-funktion eller förlita sig på Prettiers kommentarsalgoritm.
Som standard, om AST:et har en toppnivåegenskap comments, antar Prettier att comments innehåller en array av kommentarsnoder. Prettier kommer sedan att använda de tillhandahållna funktionerna parsers[<plugin>].locStart/locEnd för att söka efter den AST-nod som varje kommentar "tillhör". Kommentarer bifogas sedan till dessa noder medan AST:et muteras, och comments-egenskapen tas bort från AST-roten. *Comment-funktionerna används för att justera Prettiers algoritm. När kommentarerna är bifogade till AST:et kommer Prettier automatiskt att anropa funktionen printComment(path, options): Doc och sätta in det returnerade dokumentet på (förhoppningsvis) rätt plats.
(valfritt) getCommentChildNodes
Som standard söker Prettier rekursivt igenom alla objektegenskaper (förutom några fördefinierade) för varje nod. Denna funktion kan tillhandahållas för att åsidosätta det beteendet. Den har signaturen:
function getCommentChildNodes(
// The node whose children should be returned.
node: AST,
// Current options
options: object,
): AST[] | undefined;
Returnera [] om noden inte har några barn eller undefined för att återgå till standardbeteendet.
(valfritt) hasPrettierIgnore
function hasPrettierIgnore(path: AstPath): boolean;
Returnerar om AST-noden är prettier-ignore-markerad eller inte.
(valfritt) printPrettierIgnored
Om AST-noden är prettier-ignore-markerad kommer Prettier som standard att extrahera texten för tolkning utan att anropa print-funktionen. Dock kan tillägg också hantera utskriften av prettier-ignore-markerade noder genom att lägga till denna egenskap.
Denna egenskap har samma signatur som print-egenskapen.
Först tillgänglig i v3.7.0
(valfritt) printComment
Anropas när en kommentarsnod behöver skrivas ut. Den har signaturen:
function printComment(
// Path to the current comment node
commentPath: AstPath,
// Current options
options: object,
): Doc;
(valfri) canAttachComment
function canAttachComment(node: AST, ancestors: T[]): boolean;
Denna funktion används för att avgöra om en kommentar kan bifogas till en specifik AST-nod. Som standard genomsöks alla AST-egenskaper efter noder där kommentarer kan bifogas. Denna funktion används för att förhindra att kommentarer bifogas till en viss nod. En typisk implementation ser ut så här:
function canAttachComment(node, [parent]) {
return !(
node.type === "comment" ||
(parent?.type === "shorthand-property" &&
parent.key === node &&
parent.key !== parent.value)
);
}
Den andra parametern ancestors lades till först i v3.7.0.
(valfri) isBlockComment
function isBlockComment(node: AST): boolean;
Returnerar om AST-noden är en blockkommentar eller inte.
(valfritt) handleComments: Returnerar om AST-noden är en blockkommentar eller inte.
(valfritt) handleComments
(
// The AST node corresponding to the comment
comment: AST,
// The full source code text
text: string,
// The global options object
options: object,
// The AST
ast: AST,
// Whether this comment is the last comment
isLastComment: boolean,
) => boolean;
Dessa funktioner används för att åsidosätta Prettiers standardalgoritm för kommentarsfästning. ownLine/endOfLine/remaining förväntas antingen manuellt fästa en kommentar vid en nod och returnera true, eller returnera false och låta Prettier fästa kommentaren.
Baserat på texten runt en kommentarsnod delegerar Prettier:
-
ownLineom en kommentar endast har blanksteg före sig och en ny rad efteråt, -
endOfLineom en kommentar har en ny rad efteråt men något icke-blanksteg före sig, -
remainingi alla andra fall.
Vid dispatchen kommer Prettier att ha annoterat varje AST-kommentarsnod (dvs skapat nya egenskaper) med minst en av enclosingNode, precedingNode eller followingNode. Dessa kan användas för att underlätta plugin:ens beslutsprocess (hela AST:et och originaltexten skickas naturligtvis också med för mer komplexa beslut).
Manuellt bifoga kommentarer
Funktionerna prettier.util.addTrailingComment/addLeadingComment/addDanglingComment kan användas för att manuellt bifoga kommentarer till AST-noder. En exempel-ownLine-funktion som säkerställer att en kommentar inte följer en "punctuation"-nod (skapat för demonstration) kan se ut så här:
import * as prettier from "prettier";
function ownLine(comment, text, options, ast, isLastComment) {
const { precedingNode } = comment;
if (precedingNode && precedingNode.type === "punctuation") {
prettier.util.addTrailingComment(precedingNode, comment);
return true;
}
return false;
}
Noder med kommentarer förväntas ha en comments-egenskap som innehåller en array av kommentarer. Varje kommentar förväntas ha följande egenskaper: leading, trailing, printed.
Exemplet ovan använder prettier.util.addTrailingComment, som automatiskt sätter comment.leading/trailing/printed till lämpliga värden och lägger till kommentaren i AST-nodens comments-array.
CLI-flaggan --debug-print-comments kan hjälpa till med att felsöka problem med kommentarsfästen. Den skriver ut en detaljerad lista över kommentarer som innehåller information om hur varje kommentar klassificerades (ownLine/endOfLine/remaining, leading/trailing/dangling) och vilken nod den var fäst vid. För Prettiers inbyggda språk finns denna information också tillgänglig i Playground (kryssrutan 'show comments' i Debug-avsnittet).
options
options är ett objekt som innehåller de anpassade alternativ som ditt plugin stöder.
Exempel:
export default {
// ... plugin implementation
options: {
openingBraceNewLine: {
type: "boolean",
category: "Global",
default: true,
description: "Move open brace for code blocks onto new line.",
},
},
};
defaultOptions
defaultOptions
export default {
// ... plugin implementation
defaultOptions: {
tabWidth: 4,
},
};
Hjälpfunktioner
prettier.util ger följande begränsade uppsättning verktygsfunktioner för plugins:
type Quote = '"' | "'";
type SkipOptions = { backwards?: boolean };
function getMaxContinuousCount(text: string, searchString: string): number;
function getStringWidth(text: string): number;
function getAlignmentSize(
text: string,
tabWidth: number,
startIndex?: number,
): number;
function getIndentSize(value: string, tabWidth: number): number;
function skip(
characters: string | RegExp,
): (
text: string,
startIndex: number | false,
options?: SkipOptions,
) => number | false;
function skipWhitespace(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipSpaces(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipToLineEnd(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipEverythingButNewLine(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function skipInlineComment(
text: string,
startIndex: number | false,
): number | false;
function skipTrailingComment(
text: string,
startIndex: number | false,
): number | false;
function skipNewline(
text: string,
startIndex: number | false,
options?: SkipOptions,
): number | false;
function hasNewline(
text: string,
startIndex: number,
options?: SkipOptions,
): boolean;
function hasNewlineInRange(
text: string,
startIndex: number,
startIndex: number,
): boolean;
function hasSpaces(
text: string,
startIndex: number,
options?: SkipOptions,
): boolean;
function getPreferredQuote(
text: string,
preferredQuoteOrPreferSingleQuote: Quote | boolean,
): Quote;
function makeString(
rawText: string,
enclosingQuote: Quote,
unescapeUnnecessaryEscapes?: boolean,
): string;
function getNextNonSpaceNonCommentCharacter(
text: string,
startIndex: number,
): string;
function getNextNonSpaceNonCommentCharacterIndex(
text: string,
startIndex: number,
): number | false;
function isNextLineEmpty(text: string, startIndex: number): boolean;
function isPreviousLineEmpty(text: string, startIndex: number): boolean;
Handledningar
Handledningar
- Hur man skapar ett plugin för Prettier: Lär dig att skapa ett grundläggande Prettier-plugin för TOML.
Testa plugins
Eftersom plugins kan lösas med relativa sökvägar kan du när du arbetar med ett plugin göra följande:
import * as prettier from "prettier";
const code = "(add 1 2)";
await prettier.format(code, {
parser: "lisp",
plugins: ["./index.js"],
});
Detta kommer att lösa en plugin relativt till den aktuella arbetskatalogen.