English • Español (Latinoamérica) • Français • Bahasa Indonesia • Italiano (Italian) • 日本語 (Japanese) • 한국어 (Korean) • Português (Brasil) • 简体中文 (Simplified Chinese) • 繁體中文 (Taiwanese Mandarin)
これは、standardなJavaScriptのルールの概要です。
standard
を学ぶための最も良い方法は、ただインストールしてあなたのコードで試してみることです。
-
インデントには2個のスペースを使用する。
eslint:
indent
function hello (name) { console.log('hi', name) }
-
エスケープを避ける場合を除いて、文字列にはシングルクォートを使用する。
eslint:
quotes
console.log('hello there') // ✓ ok console.log("hello there") // ✗ avoid console.log(`hello there`) // ✗ avoid $("<div class='box'>") // ✓ ok console.log(`hello ${name}`) // ✓ ok
-
未使用の変数は定義しない。
eslint:
no-unused-vars
function myFunction () { var result = something() // ✗ avoid }
-
キーワードの後にはスペースを入れる。
eslint:
keyword-spacing
if (condition) { ... } // ✓ ok if(condition) { ... } // ✗ avoid
-
関数宣言の括弧の前にはスペースを入れる。
eslint:
space-before-function-paren
function name (arg) { ... } // ✓ ok function name(arg) { ... } // ✗ avoid run(function () { ... }) // ✓ ok run(function() { ... }) // ✗ avoid
-
常に
==
ではなく===
を使用する。
例外:obj == null
はnull || undefined
をチェックするために許容されます。eslint:
eqeqeq
if (name === 'John') // ✓ ok if (name == 'John') // ✗ avoid
if (name !== 'John') // ✓ ok if (name != 'John') // ✗ avoid
-
演算子の間には 空白を入れる。
eslint:
space-infix-ops
// ✓ ok var x = 2 var message = 'hello, ' + name + '!'
// ✗ avoid var x=2 var message = 'hello, '+name+'!'
-
カンマの後にはスペース を置くことを推奨。
eslint:
comma-spacing
// ✓ ok var list = [1, 2, 3, 4] function greet (name, options) { ... }
// ✗ avoid var list = [1,2,3,4] function greet (name,options) { ... }
-
else文は 波括弧と 同じ行に 書く。
eslint:
brace-style
// ✓ ok if (condition) { // ... } else { // ... }
// ✗ avoid if (condition) { // ... } else { // ... }
-
複数行のif文には、 波括弧を付ける。
eslint:
curly
// ✓ ok if (options.quiet !== true) console.log('done')
// ✓ ok if (options.quiet !== true) { console.log('done') }
// ✗ avoid if (options.quiet !== true) console.log('done')
-
関数のパラメーターに
err
がある場合、常に処理する。eslint:
handle-callback-err
// ✓ ok run(function (err) { if (err) throw err window.alert('done') })
// ✗ avoid run(function (err) { window.alert('done') })
-
ブラウザのグローバルオブジェクトは
/* global */
コメントで宣言する。
例外:window
、document
、navigator
。
open
、length
、event
、name
のような不適切な名前のグローバルオブジェクトの誤用を防ぎます。/* global alert, prompt */ alert('hi') prompt('ok?')
明示的に
window
の関数またはプロパティを参照するのも良いですが、そのようなコードはwindow
の代わりにself
を使うWorkerでは動作しません。eslint:
no-undef
window.alert('hi') // ✓ ok
-
複数行の空行はしないこと。
eslint:
no-multiple-empty-lines
// ✓ ok var value = 'hello world' console.log(value)
// ✗ avoid var value = 'hello world' console.log(value)
-
複数行の三項演算子では、
?
と:
を各行に書いてください。eslint:
operator-linebreak
// ✓ ok var location = env.development ? 'localhost' : 'www.api.com' // ✓ ok var location = env.development ? 'localhost' : 'www.api.com' // ✗ avoid var location = env.development ? 'localhost' : 'www.api.com'
-
var宣言では、 各宣言を個別に書く。
eslint:
one-var
// ✓ ok var silent = true var verbose = true // ✗ avoid var silent = true, verbose = true // ✗ avoid var silent = true, verbose = true
-
条件式での代入は追加の括弧でラップする。 これは、式が等価演算子(
===
)のタイプミスではなく意図的な代入(=
)であることを明確にします。eslint:
no-cond-assign
// ✓ ok while ((m = text.match(expr))) { // ... } // ✗ avoid while (m = text.match(expr)) { // ... }
-
単一行ブロックの内側にはスペースを入れる。
eslint:
block-spacing
function foo () {return true} // ✗ avoid function foo () { return true } // ✓ ok
-
変数と関数の命名にはキャメルケースを使う。
eslint:
camelcase
function my_function () { } // ✗ avoid function myFunction () { } // ✓ ok var my_var = 'hello' // ✗ avoid var myVar = 'hello' // ✓ ok
-
末尾のカンマはしないこと。
eslint:
comma-dangle
var obj = { message: 'hello', // ✗ avoid }
-
カンマは必ず行末に置く
eslint:
comma-style
var obj = { foo: 'foo' ,bar: 'bar' // ✗ avoid } var obj = { foo: 'foo', bar: 'bar' // ✓ ok }
-
ドットはプロパティと同じ行に置くことを推奨。
eslint:
dot-location
console. log('hello') // ✗ avoid console .log('hello') // ✓ ok
-
ファイルは必ず改行で終わる。
eslint:
eol-last
-
関数の識別子とその呼び出しの間にスペースを置かない。
eslint:
func-call-spacing
console.log ('hello') // ✗ avoid console.log('hello') // ✓ ok
-
オブジェクトリテラルのコロンと値の間にスペースを入れる。
eslint:
key-spacing
var obj = { 'key' : 'value' } // ✗ avoid var obj = { 'key' :'value' } // ✗ avoid var obj = { 'key':'value' } // ✗ avoid var obj = { 'key': 'value' } // ✓ ok
-
コストラクタ名は必ず大文字で始める。
eslint:
new-cap
function animal () {} var dog = new animal() // ✗ avoid function Animal () {} var dog = new Animal() // ✓ ok
-
引数なしコンストラクタは必ず括弧付きで実行する。
eslint:
new-parens
function Animal () {} var dog = new Animal // ✗ avoid var dog = new Animal() // ✓ ok
-
setterが定義されている場合、getterを必ず含むこと。
eslint:
accessor-pairs
var person = { set name (value) { // ✗ avoid this._name = value } } var person = { set name (value) { this._name = value }, get name () { // ✓ ok return this._name } }
-
派生クラスのコンストラクタでは
super
を必ず呼び出す。eslint:
constructor-super
class Dog { constructor () { super() // ✗ avoid this.legs = 4 } } class Dog extends Animal { constructor () { // ✗ avoid this.legs = 4 } } class Dog extends Animal { constructor () { super() // ✓ ok this.legs = 4 } }
-
配列初期化にはArrayコンストラクタではなく配列リテラルを使用する。
eslint:
no-array-constructor
var nums = new Array(1, 2, 3) // ✗ avoid var nums = [1, 2, 3] // ✓ ok
-
arguments.callee
とarguments.caller
は使用しない。eslint:
no-caller
function foo (n) { if (n <= 0) return arguments.callee(n - 1) // ✗ avoid } function foo (n) { if (n <= 0) return foo(n - 1) // ✓ ok }
-
クラス宣言した名前を上書きしない。
eslint:
no-class-assign
class Dog {} Dog = 'Fido' // ✗ avoid
-
const
を使って宣言された変数を上書きしない。eslint:
no-const-assign
const score = 100 score = 125 // ✗ avoid
-
条件式に定数を使用しない(ループを除く)。
eslint:
no-constant-condition
if (false) { // ✗ avoid // ... } if (x === 0) { // ✓ ok // ... } while (true) { // ✓ ok // ... }
-
正規表現に制御文字は禁止。
eslint:
no-control-regex
var pattern = /\x1f/ // ✗ avoid var pattern = /\x20/ // ✓ ok
-
debugger文は禁止。
eslint:
no-debugger
function sum (a, b) { debugger // ✗ avoid return a + b }
-
delete
演算子を変数に使うことは禁止。eslint:
no-delete-var
var name delete name // ✗ avoid
-
関数の引数の重複は禁止。
eslint:
no-dupe-args
function sum (a, b, a) { // ✗ avoid // ... } function sum (a, b, c) { // ✓ ok // ... }
-
クラスのメンバーに重複する名前は禁止。
eslint:
no-dupe-class-members
class Dog { bark () {} bark () {} // ✗ avoid }
-
オブジェクトリテラルに重複するキーは禁止。
eslint:
no-dupe-keys
var user = { name: 'Jane Doe', name: 'John Doe' // ✗ avoid }
-
switch文に重複するラベルは禁止。
eslint:
no-duplicate-case
switch (id) { case 1: // ... case 1: // ✗ avoid }
-
ひとつのモジュールにはひとつのimport文を使用する。
eslint:
no-duplicate-imports
import { myFunc1 } from 'module' import { myFunc2 } from 'module' // ✗ avoid import { myFunc1, myFunc2 } from 'module' // ✓ ok
-
正規表現に空の文字クラスは禁止。
eslint:
no-empty-character-class
const myRegex = /^abc[]/ // ✗ avoid const myRegex = /^abc[a-z]/ // ✓ ok
-
空の分割代入は禁止。
eslint:
no-empty-pattern
const { a: {} } = foo // ✗ avoid const { a: { b } } = foo // ✓ ok
-
eval()
は使用禁止。eslint:
no-eval
eval( "var result = user." + propName ) // ✗ avoid var result = user[propName] // ✓ ok
-
catch節で例外の再代入は禁止。
eslint:
no-ex-assign
try { // ... } catch (e) { e = 'new value' // ✗ avoid } try { // ... } catch (e) { const newVal = 'new value' // ✓ ok }
-
ネイティブオブジェクトの拡張禁止。
eslint:
no-extend-native
Object.prototype.age = 21 // ✗ avoid
-
不要な関数バインディングをしない。
eslint:
no-extra-bind
const name = function () { getName() }.bind(user) // ✗ avoid const name = function () { this.getName() }.bind(user) // ✓ ok
-
不要なbooleanのキャストをしない。
eslint:
no-extra-boolean-cast
const result = true if (!!result) { // ✗ avoid // ... } const result = true if (result) { // ✓ ok // ... }
-
関数式の周囲の不要な括弧は禁止。
eslint:
no-extra-parens
const myFunc = (function () { }) // ✗ avoid const myFunc = function () { } // ✓ ok
-
switch文のcase節でフォールスルーを防ぐため
break
を使用する。eslint:
no-fallthrough
switch (filter) { case 1: doSomething() // ✗ avoid case 2: doSomethingElse() } switch (filter) { case 1: doSomething() break // ✓ ok case 2: doSomethingElse() } switch (filter) { case 1: doSomething() // fallthrough // ✓ ok case 2: doSomethingElse() }
-
浮動小数点数のゼロ省略は禁止。
eslint:
no-floating-decimal
const discount = .5 // ✗ avoid const discount = 0.5 // ✓ ok
-
関数宣言を上書きしない。
eslint:
no-func-assign
function myFunc () { } myFunc = myOtherFunc // ✗ avoid
-
読み取り専用のグローバル変数を上書きしない。
eslint:
no-global-assign
window = {} // ✗ avoid
-
暗黙の
eval()
は禁止。eslint:
no-implied-eval
setTimeout("alert('Hello world')") // ✗ avoid setTimeout(function () { alert('Hello world') }) // ✓ ok
-
ネストされたブロック内に関数宣言は禁止。
eslint:
no-inner-declarations
if (authenticated) { function setAuthUser () {} // ✗ avoid }
-
RegExp
クラスのコンストラクタに無効な正規表現文字列は禁止。eslint:
no-invalid-regexp
RegExp('[a-z') // ✗ avoid RegExp('[a-z]') // ✓ ok
-
イレギュラーな空白は禁止。
eslint:
no-irregular-whitespace
function myFunc () /*<NBSP>*/{} // ✗ avoid
-
__iterator__
は使用禁止。eslint:
no-iterator
Foo.prototype.__iterator__ = function () {} // ✗ avoid
-
スコープ変数と名前を共有するラベルは禁止。
eslint:
no-label-var
var score = 100 function game () { score: while (true) { // ✗ avoid score -= 10 if (score > 0) continue score break } }
-
label文は禁止。
eslint:
no-labels
label: while (true) { break label // ✗ avoid }
-
不必要にネストされたブロックは禁止。
eslint:
no-lone-blocks
function myFunc () { { // ✗ avoid myOtherFunc() } } function myFunc () { myOtherFunc() // ✓ ok }
-
インデントにスペースとタブを混ぜない。
eslint:
no-mixed-spaces-and-tabs
-
インデント以外に複数のスペースを使用しない。
eslint:
no-multi-spaces
const id = 1234 // ✗ avoid const id = 1234 // ✓ ok
-
複数行の文字列は禁止。
eslint:
no-multi-str
const message = 'Hello \ world' // ✗ avoid
-
オブジェクトを変数に代入しないnew演算子は禁止。
eslint:
no-new
new Character() // ✗ avoid const character = new Character() // ✓ ok
-
Function
クラスのコンストラクタは使用禁止。eslint:
no-new-func
var sum = new Function('a', 'b', 'return a + b') // ✗ avoid
-
Object
クラスのコンストラクタは使用禁止。eslint:
no-new-object
let config = new Object() // ✗ avoid
-
new require
は使用禁止。eslint:
no-new-require
const myModule = new require('my-module') // ✗ avoid
-
Symbol
クラスのコンストラクタは使用禁止。eslint:
no-new-symbol
const foo = new Symbol('foo') // ✗ avoid
-
プリミティブ型のラッパーインスタンスは使用禁止。
eslint:
no-new-wrappers
const message = new String('hello') // ✗ avoid
-
関数としてグローバルオブジェクトのプロパティを呼び出さない。
eslint:
no-obj-calls
const math = Math() // ✗ avoid
-
8進数リテラルは禁止。
eslint:
no-octal
const octal = 042 // ✗ avoid const decimal = 34 // ✓ ok const octalString = '042' // ✓ ok
-
文字列リテラルに8進数エスケープシーケンスは禁止。
eslint:
no-octal-escape
const copyright = 'Copyright \251' // ✗ avoid
-
__dirname
と__filename
は、文字列結合を避ける。eslint:
no-path-concat
const pathToFile = __dirname + '/app.js' // ✗ avoid const pathToFile = path.join(__dirname, 'app.js') // ✓ ok
-
__proto__
を使用しない。 代わりにgetPrototypeOf
を使用する。eslint:
no-proto
const foo = obj.__proto__ // ✗ avoid const foo = Object.getPrototypeOf(obj) // ✓ ok
-
変数を再宣言してはいけない。
eslint:
no-redeclare
let name = 'John' let name = 'Jane' // ✗ avoid let name = 'John' name = 'Jane' // ✓ ok
-
正規表現リテラルに複数のスペースは禁止。
eslint:
no-regex-spaces
const regexp = /test value/ // ✗ avoid const regexp = /test {3}value/ // ✓ ok const regexp = /test value/ // ✓ ok
-
return文における代入は括弧で囲まれていなければならない。
eslint:
no-return-assign
function sum (a, b) { return result = a + b // ✗ avoid } function sum (a, b) { return (result = a + b) // ✓ ok }
-
変数を自身に代入しない。
eslint:
no-self-assign
name = name // ✗ avoid
-
変数を自身と比較しない。
eslint:
no-self-compare
if (score === score) {} // ✗ avoid
-
カンマ演算子を使用しない。
eslint:
no-sequences
if (doSomething(), !!test) {} // ✗ avoid
-
制限付きの名前(訳注: restricted-name. strict mode の対象であるES5の予約語)を上書きして隠蔽するべきではない。
eslint:
no-shadow-restricted-names
let undefined = 'value' // ✗ avoid
-
疎配列は許容されない。
eslint:
no-sparse-arrays
let fruits = ['apple',, 'orange'] // ✗ avoid
-
タブの使用は推奨されない。
eslint:
no-tabs
-
通常の文字列にテンプレートリテラルのプレースホルダーを含んではいけない。
eslint:
no-template-curly-in-string
const message = 'Hello ${name}' // ✗ avoid const message = `Hello ${name}` // ✓ ok
-
super()
はthis
を使う前に呼び出さなければならない。eslint:
no-this-before-super
class Dog extends Animal { constructor () { this.legs = 4 // ✗ avoid super() } }
-
Error
オブジェクトのみをスローしてください。eslint:
no-throw-literal
throw 'error' // ✗ avoid throw new Error('error') // ✓ ok
-
行末の空白はしないこと。
eslint:
no-trailing-spaces
-
undefined
での初期化はしないこと。eslint:
no-undef-init
let name = undefined // ✗ avoid let name name = 'value' // ✓ ok
-
更新されないループ条件は禁止。
eslint:
no-unmodified-loop-condition
for (let i = 0; i < items.length; j++) {...} // ✗ avoid for (let i = 0; i < items.length; i++) {...} // ✓ ok
-
よりシンプルな書き方がある場合は、三項演算子は使用禁止。
eslint:
no-unneeded-ternary
let score = val ? val : 0 // ✗ avoid let score = val || 0 // ✓ ok
-
return文、throw文、continue文、break文の後に到達不能なコードは禁止。
eslint:
no-unreachable
function doSomething () { return true console.log('never called') // ✗ avoid }
-
finallyブロックにフロー制御文は禁止。
eslint:
no-unsafe-finally
try { // ... } catch (e) { // ... } finally { return 42 // ✗ avoid }
-
関係演算子の左オペランドを否定することは禁止。
eslint:
no-unsafe-negation
if (!key in obj) {} // ✗ avoid if (!(key in obj)) {} // ✓ ok
-
.call()
と.apply()
を不必要に使用しない。eslint:
no-useless-call
sum.call(null, 1, 2, 3) // ✗ avoid
-
オブジェクトの計算されたプロパティ名(Computed Property)を不必要に使用しない。
eslint:
no-useless-computed-key
const user = { ['name']: 'John Doe' } // ✗ avoid const user = { name: 'John Doe' } // ✓ ok
-
不要なコンストラクタは禁止。
eslint:
no-useless-constructor
class Car { constructor () { // ✗ avoid } }
-
エスケープを不必要に使用しない。
eslint:
no-useless-escape
let message = 'Hell\o' // ✗ avoid
-
import、export、分割代入での、同じ名前へのリネームはしないこと。
eslint:
no-useless-rename
import { config as config } from './config' // ✗ avoid import { config } from './config' // ✓ ok
-
プロパティの前に空白は禁止。
eslint:
no-whitespace-before-property
user .name // ✗ avoid user.name // ✓ ok
-
with文は使用禁止。
eslint:
no-with
with (val) {...} // ✗ avoid
-
オブジェクトのプロパティ間で、改行の一貫性を保つこと
eslint:
object-property-newline
const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' // ✗ avoid } const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' } // ✓ ok const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' } // ✓ ok
-
ブロックの内側にパディングは禁止。
eslint:
padded-blocks
if (user) { // ✗ avoid const name = getName() } if (user) { const name = getName() // ✓ ok }
-
スプレッド演算子とその式の間に空白は禁止。
eslint:
rest-spread-spacing
fn(... args) // ✗ avoid fn(...args) // ✓ ok
-
セミコロンの後にはスペースが必要。また、セミコロン前のスペースは不要
eslint:
semi-spacing
for (let i = 0 ;i < items.length ;i++) {...} // ✗ avoid for (let i = 0; i < items.length; i++) {...} // ✓ ok
-
ブロックの中括弧の前にはスペースが必要。
eslint:
space-before-blocks
if (admin){...} // ✗ avoid if (admin) {...} // ✓ ok
-
括弧の内側にスペースは禁止。
eslint:
space-in-parens
getName( name ) // ✗ avoid getName(name) // ✓ ok
-
単項演算子の後にはスペースが必要。
eslint:
space-unary-ops
typeof!admin // ✗ avoid typeof !admin // ✓ ok
-
コメントの内側にスペースを入れること。
eslint:
spaced-comment
//comment // ✗ avoid // comment // ✓ ok /*comment*/ // ✗ avoid /* comment */ // ✓ ok
-
テンプレート文字列のプレースホルダーの内側にスペースは禁止。
eslint:
template-curly-spacing
const message = `Hello, ${ name }` // ✗ avoid const message = `Hello, ${name}` // ✓ ok
-
NaN
のチェックにはisNaN()
を使用する。eslint:
use-isnan
if (price === NaN) { } // ✗ avoid if (isNaN(price)) { } // ✓ ok
-
typeof
は有効な文字列と比較しなければならない。eslint:
valid-typeof
typeof name === 'undefimed' // ✗ avoid typeof name === 'undefined' // ✓ ok
-
即時実行関数式(IIFE)はラップしなければならない。
eslint:
wrap-iife
const getName = function () { }() // ✗ avoid const getName = (function () { }()) // ✓ ok const getName = (function () { })() // ✓ ok
-
yield*式の
*
は前後にスペースが必要。eslint:
yield-star-spacing
yield* increment() // ✗ avoid yield * increment() // ✓ ok
-
ヨーダ記法を使用しない。
eslint:
yoda
if (42 === age) { } // ✗ avoid if (age === 42) { } // ✓ ok
-
eslint:
semi
window.alert('hi') // ✓ ok window.alert('hi'); // ✗ avoid
-
決して
(
、[
、`
(または下記の起こりうる可能性の低い一部の文字)で行を始めないでください。これはセミコロンを省略する際の唯一の問題点ですが、
standard
はこの潜在的な問題からあなたを保護します。(完全なリストは
[
、(
、`
、+
、*
、/
、-
、,
、.
ですが、これらのほとんどは実際のコードでは行頭には現れません。)eslint:
no-unexpected-multiline
// ✓ ok ;(function () { window.alert('ok') }()) // ✗ avoid (function () { window.alert('ok') }())
// ✓ ok ;[1, 2, 3].forEach(bar) // ✗ avoid [1, 2, 3].forEach(bar)
// ✓ ok ;`hello`.indexOf('o') // ✗ avoid `hello`.indexOf('o')
注:もしあなたがこのようなコードをよく書くのであれば、あなたはあまりにも賢明な書き方をしようとしているのかもしれません。
賢明なショートハンドは推奨されません。可能な限り明確で読みやすい表現を心がけてください。
これのかわりに:
;[1, 2, 3].forEach(bar)
これが強く推奨されます。:
var nums = [1, 2, 3] nums.forEach(bar)
- An Open Letter to JavaScript Leaders Regarding Semicolons
- JavaScript Semicolon Insertion – Everything you need to know
今日使用されている一般的なコードミニファイアー(圧縮ツール)はASTベースのミニフィケーションを使用しているので、セミコロンレスなJavaScriptを問題なく扱うことができます(JavaScriptではセミコロンは不要であるため)。
[Relying on automatic semicolon insertion] is quite safe, and perfectly valid JS that every browser understands. Closure compiler, yuicompressor, packer, and jsmin all can properly minify it. There is no performance impact anywhere.
I am sorry that, instead of educating you, the leaders in this language community have given you lies and fear. That was shameful. I recommend learning how statements in JS are actually terminated (and in which cases they are not terminated), so that you can write code that you find beautiful.
In general,
\n
ends a statement unless:
- The statement has an unclosed paren, array literal, or object literal or ends in some other way that is not a valid way to end a statement. (For instance, ending with
.
or,
.)- The line is
--
or++
(in which case it will decrement/increment the next token.)- It is a
for()
,while()
,do
,if()
, orelse
, and there is no{
- The next line starts with
[
,(
,+
,*
,/
,-
,,
,.
, or some other binary operator that can only be found between two tokens in a single expression.The first is pretty obvious. Even JSLint is ok with
\n
chars in JSON and parenthesized constructs, and withvar
statements that span multiple lines ending in,
.The second is super weird. I’ve never seen a case (outside of these sorts of conversations) where you’d want to do write
i\n++\nj
, but, point of fact, that’s parsed asi; ++j
, noti++; j
.The third is well understood, if generally despised.
if (x)\ny()
is equivalent toif (x) { y() }
. The construct doesn’t end until it reaches either a block, or a statement.
;
is a valid JavaScript statement, soif(x);
is equivalent toif(x){}
or, “If x, do nothing.” This is more commonly applied to loops where the loop check also is the update function. Unusual, but not unheard of.The fourth is generally the fud-inducing “oh noes, you need semicolons!” case. But, as it turns out, it’s quite easy to prefix those lines with semicolons if you don’t mean them to be continuations of the previous line. For example, instead of this:
foo(); [1,2,3].forEach(bar);you could do this:
foo() ;[1,2,3].forEach(bar)The advantage is that the prefixes are easier to notice, once you are accustomed to never seeing lines starting with
(
or[
without semis.