Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@canva/prettier
Advanced tools
@canva/prettier
This is Canva's fork of prettier
so that we can customize it to suit our style.
Prettier is (by intentional design) not very customizable, so in order for us to tweak the formatting we need to fork it.
Because forking is a very heavy process to maintain whilst keeping up-to-date with upstream, we aim to make as few changes as possible.
Prettier places logical operators at the end of the line. The canva style prefers operators at the start of the line.
Input:
function f() {
const appEntities = getAppEntities(loadObject).filter(
(entity) =>
entity
&& entity.isInstallAvailable()
&& !entity.isQueue()
&& entity.isDisabled()
);
}
prettier
Upstream:
function f() {
const appEntities = getAppEntities(loadObject).filter(
(entity) =>
entity &&
entity.isInstallAvailable() &&
!entity.isQueue() &&
entity.isDisabled()
);
}
@canva/prettier
:
function f() {
const appEntities = getAppEntities(loadObject).filter(
(entity) =>
entity
&& entity.isInstallAvailable()
&& !entity.isQueue()
&& entity.isDisabled()
);
}
Prettier will forcefully remove newlines from array patterns and object patterns unless the node does not fit onto one line.
Our previous formatter, dprint
, would retain the manual newline. In order to reduce migration churn, we opted to retain these newlines.
Input:
// array
const [x, y] = [x, y];
const [
x, y] = [x, y];
const [x, y] = [
x, y];
const [
x, y] = [
x, y];
// object
const {x, y} = {x, y};
const {
x, y} = {x, y};
const {x, y} = {
x, y};
const {
x, y} = {
x, y};
prettier
Upstream:
// array
const [x, y] = [x, y];
const [x, y] = [x, y];
const [x, y] = [x, y];
const [x, y] = [x, y];
// object
const { x, y } = { x, y };
const { x, y } = { x, y };
const { x, y } = {
x,
y,
};
const { x, y } = {
x,
y,
};
@canva/prettier
:
// array
const [x, y] = [x, y];
const [
x,
y,
] = [x, y];
const [x, y] = [
x,
y,
];
const [
x,
y,
] = [
x,
y,
];
// object
const {x, y} = {x, y};
const {
x,
y,
} = {x, y};
const {x, y} = {
x,
y,
};
const {
x,
y,
} = {
x,
y,
};
,
and Interfaces with ;
Prettier uses ;
to delimit all object type-like members. The canva style uses ,
for object literal types so they look closer to object expressions.
Input:
type T = {
a: 1
b(): void
new(): T
[c: string]: 1
};
interface T {
a: 1
b(): void
new(): T
[c: string]: 1
}
prettier
Upstream:
type T = {
a: 1;
b(): void;
new(): T;
[c: string]: 1;
};
interface T {
a: 1;
b(): void;
new(): T;
[c: string]: 1;
}
@canva/prettier
:
type T = {
a: 1,
b(): void,
new(): T,
[c: string]: 1,
};
interface T {
a: 1;
b(): void;
new(): T;
[c: string]: 1;
}
Prettier formats intersections in their own, bespoke style that doesn't match union types or binary expressions.. This leads to many edge-cases of subpar formatting and also creates inconsistent styling between types.
Input:
type T1 = 'type one' & 'type two' & 'type three' & 'type four' & 'type five' & 'type six';
type T2 = Pick<TTTTTTTTTTTTTTTTTTTTTTTTTTT, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'> & Fooooooooo;
type T3 =
& {
type: JSONSchema4TypeName[];
}
& JSONSchema4ObjectSchema
& JSONSchema4ArraySchema
& JSONSchema4StringSchema
& JSONSchema4NumberSchema
& JSONSchema4BoleanSchema
& JSONSchema4NullSchema
& JSONSchema4AnySchema;
prettier
Upstream:
type T1 = "type one" &
"type two" &
"type three" &
"type four" &
"type five" &
"type six";
type T2 = Pick<
TTTTTTTTTTTTTTTTTTTTTTTTTTT,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
> &
Fooooooooo;
type T3 = {
type: JSONSchema4TypeName[],
} & JSONSchema4ObjectSchema &
JSONSchema4ArraySchema &
JSONSchema4StringSchema &
JSONSchema4NumberSchema &
JSONSchema4BoleanSchema &
JSONSchema4NullSchema &
JSONSchema4AnySchema;
@canva/prettier
:
type T1 =
& "type one"
& "type two"
& "type three"
& "type four"
& "type five"
& "type six";
type T2 =
& Pick<TTTTTTTTTTTTTTTTTTTTTTTTTTT, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa">
& Fooooooooo;
type T3 =
& {
type: JSONSchema4TypeName[],
}
& JSONSchema4ObjectSchema
& JSONSchema4ArraySchema
& JSONSchema4StringSchema
& JSONSchema4NumberSchema
& JSONSchema4BoleanSchema
& JSONSchema4NullSchema
& JSONSchema4AnySchema;
Prettier applies special logic to detect 2-dimensional arrays and enforces that each sub-array is placed on its own line. This detection is inconsistent, however, as it requires all sub-arrays to be at least of length 2; if even one sub-array isn't that long then the formatting uses different.
Input:
const x = [[1, 2], [1, 2], [1, 2]];
const x = [[1, 2], [1, 2], [1]];
prettier
Upstream:
const x = [
[1, 2],
[1, 2],
[1, 2],
];
const x = [[1, 2], [1, 2], [1]];
@canva/prettier
:
const x = [[1, 2], [1, 2], [1, 2]];
const x = [[1, 2], [1, 2], [1]];
Prettier endeavors to avoid changing the AST with its formatting pass. It does this on purpose because it makes it easy to prevent accidental runtime changes, however it does limit the scope of formats a little. In our ESLint config we use the curly
ESLint rule which enforce that all control flow statements have their body "wrapped in curly braces".
Instead of relying on a lint rule and applying its fixer after prettier runs, we instead integrate this directly into prettier itself so that the formatting can be done in one pass.
Input:
if (true) expression;
if (true) expression; else expression;
if (true) expression; else if (true) expression;
while (true) expression;
for (; ;) expression;
for (let x of y) expression;
for (let x in y) expression;
do expression; while (true);
prettier
Upstream:
if (true) expression;
if (true) expression;
else expression;
if (true) expression;
else if (true) expression;
while (true) expression;
for (;;) expression;
for (let x of y) expression;
for (let x in y) expression;
do expression;
while (true);
@canva/prettier
:
if (true) {
expression;
}
if (true) {
expression;
} else {
expression;
}
if (true) {
expression;
} else if (true) {
expression;
}
while (true) {
expression;
}
for (;;) {
expression;
}
for (let x of y) {
expression;
}
for (let x in y) {
expression;
}
do {
expression;
} while (true);
// @formatter:off
in their contentsBy default prettier formats every single file unless it's listed in the .prettierignore
.
At canva this can be cumbersome to list every ignored file in the config and sometimes we opt files out by adding a
// @formatter:off
comment in the code.
Input:
// @formatter:off
const yolo = "";
prettier
Upstream:
// @formatter:off
const yolo = '';
@canva/prettier
:
// @formatter:off
const yolo = "";
upstream
git remote add upstream git@github.com:prettier/prettier.git
git fetch upstream
git switch -c prettier/main origin/prettier/main
git merge upstream/main
git push
git checkout main
git merge prettier/main
git push
yarn install
yarn test -u
yarn lint
Prettiest: <change you made>
X.X.X-canva.Y
- where X.X.X
is the current prettier version and Y
is the incremental release number starting at 0.canva-npm-publish
workflow on the tag and do the actual publish to npm.FAQs
Prettier is an opinionated code formatter
We found that @canva/prettier demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.