-
-
Notifications
You must be signed in to change notification settings - Fork 23
Coding Standards
Mecha mostly contains CSS, HTML, JavaScript, JSON, PHP, and YAML files. Mecha is open-source where anyone can contribute to the code. The purpose of these coding standards is to make the source code appear as if it was written by one person.
The core application will probably be much more restrictive so there’s not much you can contribute to it. However, Mecha can be enriched by extensions and layouts which you are free to develop without my intervention.
You will probably have a popular extension and/or layout in the future and it is not impossible that I will also contribute to your code. And when I write the code, it will most likely look like this.
TL;DR:
- Braces with control statement.
- Space after property colon.
- Space before control statement.
aaa {
bbb: ccc;
ddd: eee;
}
@aaa (bbb: ccc) {
ddd {
eee: fff;
}
}
Always use HEX color code to declare a solid color, and RGBA color code to declare a color with opacity. Always use lower-case letter, and use the shortest color code version:
button {
background-color: #b4d455;
border-color: rgba(255, 255, 0, .5);
color: #def;
}
Sort declarations alphabetically, unless you want to override the previous declaration:
button {
border: 1px solid #000;
border-top-width: 0;
margin-left: 1px;
margin-right: 1px;
}
Always remove zero prefix in fractions:
button {
margin: 1.25em;
padding: .25em .5em;
}
Use two <Space>
s to represent single indent:
@media print {
.hidden-print {
display: none;
}
}
Add a <Space>
after colon:
@media (max-width: 1024px) {
body {
font-size: 80%;
}
}f
Pseudo classes don’t have to be in alphabetical order. In common, they will be ordered like this:
button {}
button:focus {}
button:hover {}
button:active {}
But you can also order them like this to make sure that focus state will remain as-is when hovered:
button {}
button:hover {}
button:focus {}
button:active {}
Be sure to put disabled states at the end, so it will be easier to override other states:
input {}
input:hover {}
input:focus {}
input:active {}
input:valid {}
input:invalid {}
input:read-only {}
input:disabled {}
Add a line-break after comma, sort selectors alphabetically:
h1,
h2,
h3,
h4,
h5,
h6 {}
Use single quote for attribute selector value, and for non-empty string value. Use double quote for empty string value (except for @charset
rule value that must be using double quote):
@charset "utf-8";
@import url('./style.css');
[rel='nofollow']::before {
background-image: url('./image.jpg');
content: "";
}
Ensure semi-colon at the end of declaration:
body {
margin-bottom: 1px;
margin-top: 1px;
}
Remove unit in zero values except 0%
and 0deg
:
body {
margin: 0 0 1px 1px;
margin-top: 0%;
}
Use lower-case letter, sort attributes alphabetically:
<input class="input" id="input-0" name="input-0" type="text">
Always use double quote, even on empty value:
<img alt="" src="./image.jpg">
Exception for attribute that contains JSON or JavaScript commands:
<div class="gallery" data-state='{"caption":true,"overlay":true}'></div>
Always remove values:
<button disabled type="submit">
Use two <Space>
s to represent single indent:
<ul>
<li></li>
<li></li>
</ul>
Do not add /
before >
in void elements:
<img alt="" src="/photo.jpg">
<hr>
TL;DR:
- Braces with control statement.
- Space after object property colon.
- Space before control statement.
function aaa() {}
if (bbb) {
ccc();
} else {
ddd();
}
switch (eee) {
case fff:
case ggg:
hhh();
break;
}
try {
iii();
} catch (jjj) {
kkk();
}
while (lll) {
mmm();
}
const nnn = function () {};
Use Yoda notation in equal/not-equal comparison to quickly detect typos:
if (-1 !== pairs.indexOf(pair)) {}
Use parseFloat()
and parseInt()
sparingly, simply prefix your variable with a +
sign if you know that the value will always be a valid number:
const value = input.value;
// :(
console.log(parseFloat(value));
// :)
console.log(+value);
Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for
loop:
// :(
for (let i = 0, j = data.length; i < j; i++) {}
// :)
for (let i = 0, j = data.length; i < j; ++i) {}
Use four <Space>
s to represent single indent:
function foo(bar = 'baz') {
return bar ?? 'qux';
}
Always add a <Space>
around operators:
let value = a + b * (1 / (c - 2));
let value = a + 'asdf' + b;
value += 'asdf';
value += 'asdf';
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"
Only use backtick-style string for templating. E.g. to write a block of CSS and HTML snippet in a JavaScript file.
Join multiple variables, unless its indentation looks ugly such as when used with const
, or when making undefined variables. Sort them aplhabetically where possible:
let bar = 1,
baz = 2,
x, y, z;
const bar = 1;
const baz = 2;
TL;DR:
- Braces with control statement.
- Space after property colon.
- Space before control statement.
function aaa() {}
if ($bbb) {
ccc();
} else {
ddd();
}
switch ($eee) {
case $fff:
case $ggg:
hhh();
break;
}
try {
iii();
} catch (Throwable $jjj) {
kkk();
}
while ($lll) {
mmm();
}
const nnn = static function () {};
Order constants, methods and properties alphabetically, including the visibility state:
class Foo implements A, B, C {
private function _internal() {}
public function get() {}
public function let() {}
public function set() {}
public function __construct() {}
public static function __callStatic() {}
}
Use Yoda notation in equal/not-equal comparison to quickly detect typos:
if (false !== strpos($foo, $bar)) {}
Use is_dir
or is_file
instead of file_exists
:
// :(
if (file_exists($path)) {}
// :)
if (is_file($path)) {}
If you just want to check whether a path does exist, use stream_resolve_include_path
instead of file_exists
:
// :(
if (file_exists($path)) {}
// :\
if (is_dir($path) || is_file($path)) {}
// :)
if (stream_resolve_include_path($path)) {}
Use strtr
instead of str_replace
:
// :(
echo str_replace('a', 'b', $value);
echo str_replace('a', "", $value);
echo str_replace(['a', 'b'], ['c', 'd'], $value);
echo str_replace(['aa', 'bb'], ["", ""], $value);
// :)
echo strtr($value, 'a', 'b');
echo strtr($value, ['a' => ""]);
echo strtr($value, 'ab', 'cd');
echo strtr($value, [
'aa' => "",
'bb' => ""
]);
If you know that a path exists, use stream_resolve_include_path
to normalize the path instead of realpath
:
$path = stream_resolve_include_path($path);
If you just want to escape/un-escape HTML, use htmlspecialchars
and htmlspecialchars_decode
instead of htmlentities
:
// :(
echo '<input value="' . htmlentities($value) . '">';
// :)
echo '<input value="' . htmlspecialchars($value) . '">';
Prefers static anonymous function if $this
context is not used:
$map = static function (array $array, callable $fn) {
foreach ($array as &$v) {
$v = $fn($v);
}
unset($v);
return $array;
};
Do not use count()
to detect empty array, and strlen()
to detect empty string. These should be enough:
if (!$array) {}
if ("" === $string) {}
Prefers pre-increment/decrement over post-increment/decrement; always cache the data length before iteration using for
loop:
// :(
for ($i = 0, $j = count($data); $i < $j; $i++) {}
// :)
for ($i = 0, $j = count($data); $i < $j; ++$i) {}
Use four <Space>
s to represent single indent:
function foo(string $bar = 'baz') {
return $bar ?? 'qux';
}
Use isset()
sparingly:
// :(
echo '<' . $m[1] . (isset($m[2]) ? $m[2] : "") . '>';
// :)
echo '<' . $m[1] . ($m[2] ?? "") . '>';
Do not use empty()
to detect empty string. Use empty()
as a shortcut for !(isset($var) && $var)
:
$name = $_POST['name'] ?? "";
// :(
// If `$name` contains `0` string, this will return `true`
if (empty($name)) {}
// :)
// Use `trim()` as a guard, since even a single space is not considered empty
if ("" !== trim($name)) {}
// :)
// You don’t have to use `empty()` to detect empty array. This should be enough!
if (!$array) {}
Use empty()
and isset()
only to detect undefined variable as a whole.
Always think of PHP statements as other kind of HTML markup. They should get the same indentation treatment as the surrounding HTML markup.
<!-- :( -->
<h1>
<a href="<?= $link; ?>"><?= $title; ?></a>
</h1>
<!-- :) -->
<h1>
<a href="<?= $link; ?>">
<?= $title; ?>
</a>
</h1>
<!-- :( -->
<?php foreach ($pages as $page): ?>
<article>
<h2><?= $page->title; ?></h2>
<div><?= $page->content; ?></div>
</article>
<?php endforeach; ?>
<!-- :) -->
<?php foreach ($pages as $page): ?>
<article>
<h2>
<?= $page->title; ?>
</h2>
<div>
<?= $page->content; ?>
</div>
</article>
<?php endforeach; ?>
Always add a <Space>
around operators:
$value = $a + $b * (1 / ($c - 2));
$value = $a . 'asdf' . $b;
$value .= 'asdf';
$value .= 'asdf';
Use echo
or not at all. Always add a semi-colon at the end of declaration, even if you are using the <?=
syntax:
<h1>
<?php
$title = do_task(1);
$title .= do_task(2);
$title .= do_task(3);
echo $title;
?>
</h1>
<h1>
<?= $title; ?>
</h1>
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
'asdf'
"asdf's"
""
'"asdf"'
'"asdf\'s"'
"'asdf'"
"'asdf\"s'"
Only use HEREDOC-style string for templating. E.g. to write a block of CSS and HTML snippet in a PHP region.
Always store HEREDOC string in a variable to overcome our first home-made PHP minifier bug.
// :(
echo implode("\n", ['<b></b>', <<<HTML
<div></div>
HTML
]);
// :)
$content = <<<HTML
<div></div>
HTML;
echo implode("\n", ['<b></b>', $content]);
Combine all variables with the same predefined value into one line. Sort them alphabetically:
$current = $next = $prev = "";
Use two <Space>
s to represent single indent:
SELECT
*
FROM
"page"
WHERE
"id" = 1
AND
"parent" IS NULL
;
Always add a <Space>
around operators:
SELECT "content", "title" FROM "page" WHERE "name" = 'lorem-ipsum';
TODO
Use two <Space>
s to represent single indent:
foo:
bar: 1
baz: 2
qux: 3
Do not indent sequence list:
# :(
foo:
- bar
- baz
- qux
# :)
foo:
- bar
- baz
- qux
Enclose values containing special characters in quotation marks:
foo: Bar Baz
qux: '[email protected]'
Use single quote for non-empty string or for string that contains "
character, so you don’t have to escape. Use double quote for empty string or for string that contains '
character, so you don’t have to escape:
foo:
bar: 'http://example.com'
baz: ""
To be continued… 🧠