/test/formatting.coffee

http://github.com/jashkenas/coffee-script · CoffeeScript · 497 lines · 429 code · 47 blank · 21 comment · 15 complexity · 610d45795b6915100d88143d87d5cf86 MD5 · raw file

  1. # Formatting
  2. # ----------
  3. # TODO: maybe this file should be split up into their respective sections:
  4. # operators -> operators
  5. # array literals -> array literals
  6. # string literals -> string literals
  7. # function invocations -> function invocations
  8. doesNotThrowCompileError "a = then b"
  9. test "multiple semicolon-separated statements in parentheticals", ->
  10. nonce = {}
  11. eq nonce, (1; 2; nonce)
  12. eq nonce, (-> return (1; 2; nonce))()
  13. # * Line Continuation
  14. # * Property Accesss
  15. # * Operators
  16. # * Array Literals
  17. # * Function Invocations
  18. # * String Literals
  19. # Property Access
  20. test "chained accesses split on period/newline, backwards and forwards", ->
  21. str = 'abc'
  22. result = str.
  23. split('').
  24. reverse().
  25. reverse().
  26. reverse()
  27. arrayEq ['c','b','a'], result
  28. arrayEq ['c','b','a'], str.
  29. split('').
  30. reverse().
  31. reverse().
  32. reverse()
  33. result = str
  34. .split('')
  35. .reverse()
  36. .reverse()
  37. .reverse()
  38. arrayEq ['c','b','a'], result
  39. arrayEq ['c','b','a'],
  40. str
  41. .split('')
  42. .reverse()
  43. .reverse()
  44. .reverse()
  45. arrayEq ['c','b','a'],
  46. str.
  47. split('')
  48. .reverse().
  49. reverse()
  50. .reverse()
  51. # Operators
  52. test "newline suppression for operators", ->
  53. six =
  54. 1 +
  55. 2 +
  56. 3
  57. eq 6, six
  58. test "`?.` and `::` should continue lines", ->
  59. ok not (
  60. Date
  61. ::
  62. ?.foo
  63. )
  64. ok not (
  65. Date
  66. ?::
  67. ?.foo
  68. )
  69. #eq Object::toString, Date?.
  70. #prototype
  71. #::
  72. #?.foo
  73. doesNotThrowCompileError """
  74. oh. yes
  75. oh?. true
  76. oh:: return
  77. """
  78. doesNotThrowCompileError """
  79. a?[b..]
  80. a?[...b]
  81. a?[b..c]
  82. """
  83. test "#1768: space between `::` and index is ignored", ->
  84. eq 'function', typeof String:: ['toString']
  85. # Array Literals
  86. test "indented array literals don't trigger whitespace rewriting", ->
  87. getArgs = -> arguments
  88. result = getArgs(
  89. [[[[[],
  90. []],
  91. [[]]]],
  92. []])
  93. eq 1, result.length
  94. # Function Invocations
  95. doesNotThrowCompileError """
  96. obj = then fn 1,
  97. 1: 1
  98. a:
  99. b: ->
  100. fn c,
  101. d: e
  102. f: 1
  103. """
  104. # String Literals
  105. test "indented heredoc", ->
  106. result = ((_) -> _)(
  107. """
  108. abc
  109. """)
  110. eq "abc", result
  111. # Chaining - all open calls are closed by property access starting a new line
  112. # * chaining after
  113. # * indented argument
  114. # * function block
  115. # * indented object
  116. #
  117. # * single line arguments
  118. # * inline function literal
  119. # * inline object literal
  120. #
  121. # * chaining inside
  122. # * implicit object literal
  123. test "chaining after outdent", ->
  124. id = (x) -> x
  125. # indented argument
  126. ff = id parseInt "ff",
  127. 16
  128. .toString()
  129. eq '255', ff
  130. # function block
  131. str = 'abc'
  132. zero = parseInt str.replace /\w/, (letter) ->
  133. 0
  134. .toString()
  135. eq '0', zero
  136. # indented object
  137. a = id id
  138. a: 1
  139. .a
  140. eq 1, a
  141. test "#1495, method call chaining", ->
  142. str = 'abc'
  143. result = str.split ''
  144. .join ', '
  145. eq 'a, b, c', result
  146. result = str
  147. .split ''
  148. .join ', '
  149. eq 'a, b, c', result
  150. eq 'a, b, c', (str
  151. .split ''
  152. .join ', '
  153. )
  154. eq 'abc',
  155. 'aaabbbccc'.replace /(\w)\1\1/g, '$1$1'
  156. .replace /([abc])\1/g, '$1'
  157. # Nested calls
  158. result = [1..3]
  159. .slice Math.max 0, 1
  160. .concat [3]
  161. arrayEq [2, 3, 3], result
  162. # Single line function arguments
  163. result = [1..6]
  164. .map (x) -> x * x
  165. .filter (x) -> x % 2 is 0
  166. .reverse()
  167. arrayEq [36, 16, 4], result
  168. # Single line implicit objects
  169. id = (x) -> x
  170. result = id a: 1
  171. .a
  172. eq 1, result
  173. # The parens are forced
  174. result = str.split(''.
  175. split ''
  176. .join ''
  177. ).join ', '
  178. eq 'a, b, c', result
  179. test "chaining should not wrap spilling ternary", ->
  180. throwsCompileError """
  181. if 0 then 1 else g
  182. a: 42
  183. .h()
  184. """
  185. test "chaining should wrap calls containing spilling ternary", ->
  186. f = (x) -> h: x
  187. id = (x) -> x
  188. result = f if true then 42 else id
  189. a: 2
  190. .h
  191. eq 42, result
  192. test "chaining should work within spilling ternary", ->
  193. f = (x) -> h: x
  194. id = (x) -> x
  195. result = f if false then 1 else id
  196. a: 3
  197. .a
  198. eq 3, result.h
  199. test "method call chaining inside objects", ->
  200. f = (x) -> c: 42
  201. result =
  202. a: f 1
  203. b: f a: 1
  204. .c
  205. eq 42, result.b
  206. test "#4568: refine sameLine implicit object tagging", ->
  207. condition = yes
  208. fn = -> yes
  209. x =
  210. fn bar: {
  211. foo: 123
  212. } if not condition
  213. eq x, undefined
  214. # Nested blocks caused by paren unwrapping
  215. test "#1492: Nested blocks don't cause double semicolons", ->
  216. js = CoffeeScript.compile '(0;0)'
  217. eq -1, js.indexOf ';;'
  218. test "#1195 Ignore trailing semicolons (before newlines or as the last char in a program)", ->
  219. preNewline = (numSemicolons) ->
  220. """
  221. nonce = {}; nonce2 = {}
  222. f = -> nonce#{Array(numSemicolons+1).join(';')}
  223. nonce2
  224. unless f() is nonce then throw new Error('; before linebreak should = newline')
  225. """
  226. CoffeeScript.run(preNewline(n), bare: true) for n in [1,2,3]
  227. lastChar = '-> lastChar;'
  228. doesNotThrowCompileError lastChar, bare: true
  229. test "#1299: Disallow token misnesting", ->
  230. try
  231. CoffeeScript.compile '''
  232. [{
  233. ]}
  234. '''
  235. ok no
  236. catch e
  237. eq 'unmatched ]', e.message
  238. test "#2981: Enforce initial indentation", ->
  239. try
  240. CoffeeScript.compile ' a\nb-'
  241. ok no
  242. catch e
  243. eq 'missing indentation', e.message
  244. test "'single-line' expression containing multiple lines", ->
  245. doesNotThrowCompileError """
  246. (a, b) -> if a
  247. -a
  248. else if b
  249. then -b
  250. else null
  251. """
  252. test "#1275: allow indentation before closing brackets", ->
  253. array = [
  254. 1
  255. 2
  256. 3
  257. ]
  258. eq array, array
  259. do ->
  260. (
  261. a = 1
  262. )
  263. eq 1, a
  264. test "don’t allow mixing of spaces and tabs for indentation", ->
  265. try
  266. CoffeeScript.compile '''
  267. new Layer
  268. x: 0
  269. y: 1
  270. '''
  271. ok no
  272. catch e
  273. eq 'indentation mismatch', e.message
  274. test "each code block that starts at indentation 0 can use a different style", ->
  275. doesNotThrowCompileError '''
  276. new Layer
  277. x: 0
  278. y: 1
  279. new Layer
  280. x: 0
  281. y: 1
  282. '''
  283. test "tabs and spaces cannot be mixed for indentation", ->
  284. try
  285. CoffeeScript.compile '''
  286. new Layer
  287. x: 0
  288. y: 1
  289. '''
  290. ok no
  291. catch e
  292. eq 'mixed indentation', e.message
  293. test "#4487: Handle unusual outdentation", ->
  294. a =
  295. switch 1
  296. when 2
  297. no
  298. when 3 then no
  299. when 1 then yes
  300. eq yes, a
  301. b = do ->
  302. if no
  303. if no
  304. 1
  305. 2
  306. 3
  307. eq b, undefined
  308. test "#3906: handle further indentation inside indented chain", ->
  309. eq 1, CoffeeScript.eval '''
  310. z = b: -> d: 2
  311. e = ->
  312. f = 3
  313. z
  314. .b ->
  315. c
  316. .d
  317. e(
  318. f
  319. )
  320. 1
  321. '''
  322. eq 1, CoffeeScript.eval '''
  323. z = -> b: -> e: ->
  324. z()
  325. .b
  326. c: 'd'
  327. .e()
  328. f = [
  329. 'g'
  330. ]
  331. 1
  332. '''
  333. eq 1, CoffeeScript.eval '''
  334. z = -> c: -> c: ->
  335. z('b')
  336. .c 'a',
  337. {b: 'a'}
  338. .c()
  339. z(
  340. 'b'
  341. )
  342. 1
  343. '''
  344. test "#3199: throw multiline implicit object", ->
  345. x = do ->
  346. if no then throw
  347. type: 'a'
  348. msg: 'b'
  349. eq undefined, x
  350. y = do ->
  351. if no then return
  352. type: 'a'
  353. msg: 'b'
  354. eq undefined, y
  355. y = do ->
  356. yield
  357. type: 'a'
  358. msg: 'b'
  359. if no then yield
  360. type: 'c'
  361. msg: 'd'
  362. 1
  363. {value, done} = y.next()
  364. ok value.type is 'a' and done is no
  365. {value, done} = y.next()
  366. ok value is 1 and done is yes
  367. test "#4576: multiple row function chaining", ->
  368. ->
  369. eq @a, 3
  370. .call a: 3
  371. test "#4576: function chaining on separate rows", ->
  372. do ->
  373. Promise
  374. .resolve()
  375. .then ->
  376. yes
  377. .then ok
  378. test "#3736: chaining after do IIFE", ->
  379. eq 3,
  380. do ->
  381. a: 3
  382. .a
  383. eq 3,
  384. do (b = (c) -> c) -> a: 3
  385. ?.a
  386. b = 3
  387. eq 3,
  388. do (
  389. b
  390. {d} = {}
  391. ) ->
  392. a: b
  393. .a
  394. # preserve existing chaining behavior for non-IIFE `do`
  395. b = c: -> 4
  396. eq 4,
  397. do b
  398. .c
  399. test "#5168: allow indented property index", ->
  400. a = b: 3
  401. eq 3, a[
  402. if yes
  403. 'b'
  404. else
  405. 'c'
  406. ]
  407. d = [1, 2, 3]
  408. arrayEq [1, 2], d[
  409. ...2
  410. ]
  411. class A
  412. b: -> 3
  413. class B extends A
  414. c: ->
  415. super[
  416. 'b'
  417. ]()
  418. eq 3, new B().c()