@danielx/civet 0.3.16 → 0.4.1-8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ Code Sample
26
26
  ---
27
27
 
28
28
  ```typescript
29
- import ts, {CompilerOptions} from "typescript"
29
+ ts, {CompilerOptions} from typescript
30
30
 
31
31
  DefaultCompilerOptions : CompilerOptions :=
32
32
  allowNonTsExtensions: true
@@ -41,29 +41,10 @@ fileCache : Record<string, any> := {}
41
41
 
42
42
  createCompilerHost := (options: CompilerOptions, moduleSearchLocations : string[]) ->
43
43
  fileExists := (fileName: string) : boolean ->
44
- return fileCache[fileName]?
44
+ fileCache[fileName]?
45
45
 
46
46
  readFile := (fileName: string) ->
47
- return fileCache[fileName]
48
- ```
49
-
50
- ESBuild Plugin
51
- ---
52
-
53
- ```coffee
54
- esbuild = require "esbuild"
55
- civetPlugin = require "@danielx/civet/esbuild-plugin"
56
-
57
- esbuild.build
58
- entryPoints: ['source/main.civet']
59
- bundle: true
60
- platform: 'node'
61
- outfile: 'dist/main.js'
62
- plugins: [
63
- civetPlugin
64
- ]
65
- .catch -> process.exit 1
66
-
47
+ fileCache[fileName]
67
48
  ```
68
49
 
69
50
  Things Kept from CoffeeScript
@@ -73,7 +54,7 @@ Things Kept from CoffeeScript
73
54
  - `or` -> `||`
74
55
  - `and` -> `&&`
75
56
  - `loop` -> `while(true)`
76
- - `unless` conditional (without the `else`)
57
+ - `unless exp` -> `if(!exp)`
77
58
  - `until condition` -> `while(!condition)`
78
59
  - Object literal syntax
79
60
  ```coffee
@@ -90,49 +71,82 @@ Things Kept from CoffeeScript
90
71
  - `?=` null-coalescing assignment shorthand
91
72
  - `@` `this` shorthand `@` -> `this`, `@id` -> `this.id`
92
73
  - Prototype shorthand `X::` -> `X.prototype`, `X::a` -> `X.prototype.a`
93
- - Postfix `if/unless`
74
+ - Class static shorthand `@`
75
+ - Chained comparisons `a < b < c` -> `a < b && b < c`
76
+ - Postfix `if/unless/while/until/for`
94
77
  - Block Strings `"""` / `'''`
78
+ - `#{exp}` interpolation in `"""` strings
79
+ - `when` inside `switch` automatically breaks
80
+ - Multiple `,` separated `case`/`when` expressions
81
+ - `else` -> `default` in `switch`
82
+ - Array slices `list[0...2]` -> `list.slice(0, 2)`
83
+ - Slice assignment `numbers[3..6] = [-3, -4, -5, -6]` -> `numbers.splice(3, 4, ...[-3, -4, -5, -6])`
84
+ - Implicit returns
85
+ - Simplified number method calls `1.toFixed()` -> `1..toFixed()`
86
+ - `if`/`switch` expressions
87
+ - Destructuring object assignment doesn't require being wrapped in parens at the statement level `{a, b} = c` -> `({a, b} = c)`
95
88
  - JSX 😿
96
- - TODO
97
- - [ ] `"""` String interpolation (for compatibility with existing .coffee code)
98
- - [ ] Chained comparisons
99
89
 
100
90
  Things Removed from CoffeeScript
101
91
  ---
102
92
 
103
- - `on/yes/off/no` (use `true/false`)
104
- - `isnt` (use `!==`)
105
- - `not` (use `!`)
106
- - `do` keyword (replaced with JS `do`)
107
- - `for from` (use JS `for of`)
93
+ - Implicit `var` declarations (use `civet coffeeCompat` or `"civet autoVar"`)
94
+ - `on/yes/off/no` (use `true/false`, `"civet coffeeCompat"`, or `"civet coffeeBooleans"` to add them back)
95
+ - `isnt` (use `!==`, `"civet coffeeCompat"`, or `"civet coffeeIsnt"`)
96
+ - `not` (use `!`, `"civet coffeeCompat"`, or `"civet coffeeNot"`)
97
+ - `not instanceof` (use `!(a instanceof b)`)
98
+ - `not in`
99
+ - `not of`
100
+ - NOTE: CoffeeScript `not` precedence is dubious. `not a < b` should be equivalent to `!(a < b)` but it is in fact `!a < b`
101
+ - `do` keyword (replaced with JS `do`, invoke using existing `(-> ...)()` syntax)
102
+ - `for from` (use JS `for of`, `"civet coffeeCompat"`, or `"civet coffeeForLoops"`)
103
+ - `for own of` (use JS `for in` and check manually, switch to `Map#keys/values/entries`, or use `Object.create(null)`, or `"civet coffeeCompat"`, or `"civet coffeeForLoops"`)
104
+ - `for ... when <condition>` (use `continue if exp` inside loop, `"civet coffeeCompat"`, or `"civet coffeeForLoops"`)
108
105
  - `and=`, `or=` (don't mix and match words and symbols)
109
- - Array slices `list[0...2]` (use `list.slice(0, 2)`)
110
- - Slice assignment `numbers[3..6] = [-3, -4, -5, -6]` (use `numbers.splice(3, 4, -3, -4, -5, -6)`)
111
- - Ranges `[0...10]`
112
- - Comprensions (a case could be made for keeping them)
106
+ - `a ? b` (use `a ?? b`, though it doesn't check for undeclared variables)
107
+ - `a of b` (use `a in b` matching JS, or `"civet coffeeCompat"`, or `"civet coffeeOf"`)
113
108
  - Iteration expression results
114
- - Implicit declarations
115
- - Implicit returns (will probably add later at least for single line functions)
116
- - Rest parameter in any assignment position (might add later)
117
- - Postfix `while/until`
118
- - `///` Heregexp
119
- - Embedded JS
109
+ - Backtick embedded JS (replaced by template literals)
110
+ - Will likely add later
111
+ - Optional assignment `x?.y = 3` -> `x != null ? x.y = 3 : undefined`
112
+ - Loop expressions (at least in compatibility mode)
113
+ - Conditional assignment `a?[x] = 3` -> `a ? a[x] = 3 : undefined`
114
+ - Might add later
115
+ - Braceless inline objects `x = coolStory: true`
116
+ - `///` Heregexp
117
+ - Ranges `[0...10]`
118
+ - Rest parameter in any assignment position
119
+ - Multiple slice assignment `otherNumbers[0...] = numbers[3..6] = [-3, -4, -5, -6]`
120
120
 
121
121
  Things Changed from CoffeeScript
122
122
  ---
123
123
 
124
- - `==` -> `==` rather than `===` (can be kept with `"use coffee-compat"`)
125
- - `!=` -> `!=` rather than `!==` (can be kept with `"use coffee-compat"`)
124
+ - `==` -> `==` rather than `===` (can be kept with `"civet coffeeCompat"`)
125
+ - `!=` -> `!=` rather than `!==` (can be kept with `"civet coffeeCompat"`)
126
126
  - `for in` and `for of` are no longer swapped and become their JS equivalents.
127
127
  - `a...` is now `...a` just like JS
128
+ - `a in b` is now `a in b` rather than `b.indexOf(a) >= 0`
128
129
  - `x?.y` now compiles to `x?.y` rather than the `if typeof x !== 'undefined' && x !== null` if check
129
130
  - Existential `x?` -> `(x != null)` no longer checks for undeclared variables.
130
- - Embedded JS `\`\`` has been replaced with JS template literals.
131
- - No longer allowing multiple postfix `if/unless` on the same line.
132
- - No `else` block on `unless` (negate condition and use `if`)
131
+ - `x?()` -> `x?.()` instead of `if (typeof x === 'function') { x() }`
132
+ - Backtick embedded JS has been replaced with JS template literals.
133
+ - No longer allowing multiple postfix `if/unless` on the same line (use `&&` or `and` to combine conditions).
134
+ - `#{}` interpolation in `""` strings only when `"civet coffeeCompat"` or `"civet coffeeInterpolation"`
135
+ - Expanded chained comparisons to work on more operators `a in b instanceof C` -> `a in b && b instanceof C`
136
+ - Postfix iteration/conditionals always wrap the statement [#5431](https://github.com/jashkenas/coffeescript/issues/5431)
137
+ `try x() if y` -> `if (y) try x()`
133
138
  - Civet tries to keep the transpiled output verbatim as much as possible.
134
139
  In Coffee `(x)` -> `x;` but in Civet `(x)` -> `(x);`.
135
- Also in Coffee `x + 3` -> `x + 3` but in Civet `x + 3` remains as is.
140
+ Also in Coffee
141
+ ```coffee
142
+ x + 3
143
+ ```
144
+ -> `x + 3` without the spacing
145
+ In Civet
146
+ ```typescript
147
+ x + 3
148
+ ```
149
+ remains as is.
136
150
 
137
151
  Things Added that CoffeeScript didn't
138
152
  ---
@@ -157,19 +171,29 @@ Things Added that CoffeeScript didn't
157
171
  - JS Compatability
158
172
  - `var`, `let`, `const`
159
173
  - JS Comment Syntax `//` and `/* */`
174
+ - `function` keyword
160
175
  - Braced Blocks
161
- - OptionalChain longhand
162
- - ConditionalExpression
176
+ - `f?.(x)` function application and `a?.[x]` index OptionalChain longhand
177
+ - `a ? b : c` ConditionalExpression
163
178
  - `case` statement
164
179
  - `do`, `do { ... } until condition`
165
- - Const assignment shorthand `a := b` -> `const a = b`; `{a, b} := c` -> `const {a, b} = c`
180
+ - `get`/`set` method definitions
181
+ - Private identifiers `#id`
166
182
  - Convenience for ES6+ Features
167
- - `<` as `extends` shorthand
183
+ - Const assignment shorthand `a := b` -> `const a = b`; `{a, b} := c` -> `const {a, b} = c`
168
184
  - `@#id` -> `this.#id` shorthand for private identifiers
169
185
  - `import` shorthand `x from ./x` -> `import x from "./x"`
170
- - ClassStaticBlock
171
- - `get`/`set` method definitions
172
- - Private identifiers `#id`
186
+ - Triple backtick Template Strings remove leading indentation for clarity
187
+ - Class constructor shorthand `@( ... )`
188
+ - ClassStaticBlock `@ { ... }`
189
+ - `<` as `extends` shorthand
190
+ - Short function block syntax like [Ruby symbol to proc](https://ruby-doc.org/core-3.1.2/Symbol.html#method-i-to_proc), [Crystal](https://crystal-lang.org/reference/1.6/syntax_and_semantics/blocks_and_procs.html#short-one-parameter-syntax), [Elm record access](https://elm-lang.org/docs/records#access)
191
+ - access `x.map &.name` -> `x.map(a => a.name)`
192
+ - nested access + slices `x.map &.profile?.name[0...3]` -> `x.map(a => a.profile?.name.slice(0, 3))`
193
+ - function call `x.map &.callback a, b` -> `x.map($ => $.callback(a, b))`
194
+ - unary operators `x.map !!&`, -> `x.map($ => !!$)`
195
+ - binary operators `x.map &+1` -> `x.map($ => $+1)`
196
+ - Postfix loop `run() loop` -> `while(true) run()`
173
197
  - Shebang line is kept unmodified in output
174
198
  ```civet
175
199
  #!./node_modules/.bin/ts-node
@@ -179,7 +203,139 @@ Things Added that CoffeeScript didn't
179
203
  Things Changed from ES6
180
204
  ---
181
205
 
206
+ - Implicit returns
182
207
  - Disallow no parens on single argument arrow function. `x => ...` must become `(x) => ...`
183
208
  The reasoning is `x -> ...` => `x(function() ...)` in CoffeeScript and having `->` and `=>`
184
209
  behave more differently than they already do is bad. Passing an anonymous function to an
185
210
  application without parens is also convenient.
211
+ - `for(i of x) ...` defaults to const declaration -> `for(const i of x) ...`
212
+ - Disallow comma operator in conditionals and many other places. `if x, y` is not allowed.
213
+ - Comma operator in `case`/`when` instead becomes multiple conditions.
214
+ - Numbers can't end with a dot (otherwise would be ambiguous with CoffeeScript slices `y[0..x]`). This also implies that you can't access properties
215
+ of numbers with `1..toString()` use `1.toString()` instead. When exponent follows a dot it is treated as a property access since an exponent
216
+ could be a valid property `1.e10` -> `1..e10`. The workaround is to add a trailing zero `1.0e10` or remove the dot before the exponent `1e10`.
217
+ - Additional reserved words `and`, `or`, `loop`, `until`, `unless`
218
+ - No whitespace between unary operators and operands. Mandatory whitespace between condition and ternary `?` ex. `x ? a : b` since `x?` is the unary existential operator.
219
+
220
+ CoffeeScript Compatibility
221
+ ---
222
+
223
+ Civet provides a compatability prologue directive that aims to be 97+% compatible with existing CoffeeScript2 code (still a work in progress).
224
+
225
+ ```
226
+ coffeeBooleans (yes/no/on/off)
227
+ coffeeComment (# single line comments)
228
+ coffeeEq (`==` -> `===`, `!=` -> `!==`)
229
+ coffeeInterpolation (`"a string with {myVar}"`)
230
+ coffeeIsnt (`isnt` -> `!==`)
231
+ ```
232
+
233
+ You can use these with `"civet coffeeCompat"` to opt in to all or use them bit by bit with `"civet coffeeComment coffeeEq coffeeInterpolation"`.
234
+ Another posibility is to slowly remove them to provide a way to migrate files a little at a time `"civet coffeeCompat -coffeeBooleans -coffeeComment -coffeeEq"`.
235
+ Both camel case and hyphens work when specifying options `"civet coffee-compat"`. More options will be added over time until 97+% compatibility is achieved.
236
+
237
+ Using Civet in your Node.js Environment
238
+ ---
239
+
240
+ You have now been convinced that Civet is right for your current/next project. Here is how
241
+ to set up your environment to get productive right away and have a Good Time℠.
242
+
243
+ ### Testing
244
+
245
+ Code coverage with [c8](https://github.com/bcoe/c8) "just works" thanks to their source map
246
+ integration and Civet's source maps.
247
+
248
+ Currently Civet's ESM loader depends on [ts-node](https://www.npmjs.com/package/ts-node)
249
+
250
+ #### c8 + Mocha
251
+
252
+ `package.json`
253
+ ```json
254
+ "scripts": {
255
+ "test": "c8 mocha",
256
+ ...
257
+ },
258
+ "c8": {
259
+ "extension": [
260
+ ".civet"
261
+ ]
262
+ },
263
+ "mocha": {
264
+ "extension": [
265
+ "civet"
266
+ ],
267
+ "loader": [
268
+ "ts-node/esm",
269
+ "@danielx/civet/esm.mjs"
270
+ ],
271
+ ...
272
+ ...
273
+ ```
274
+
275
+ `ts-node` must be configured with `transpileOnly` (it can't resolve alternative extensions). Also I think `module` needs to be at least `ES2020` for the Civet ESM loader to work.
276
+
277
+ `tsconfig.json`
278
+ ```json
279
+ ...
280
+ "ts-node": {
281
+ "transpileOnly": true,
282
+ "compilerOptions": {
283
+ "module": "ES2020"
284
+ }
285
+ }
286
+ ```
287
+
288
+ If you don't care for code coverage you can skip c8 (but it is so easy why not keep it?).
289
+
290
+ You can also add `.js` and `.ts` extensions if you want to mix and match! Even `.coffee` will work if you require `coffeescript/register` or add a loader for it.
291
+
292
+ Execute the tests
293
+
294
+ ```bash
295
+ yarn test
296
+ ```
297
+
298
+ Step 4: Enjoy!
299
+
300
+ ### Developing
301
+
302
+ Use the alpha version of [Civet Language Server](https://marketplace.visualstudio.com/items?itemName=DanielX.civet)
303
+
304
+ The language server provides syntax highlighting, completions, hover documentation, symbols outline, red squigglies, and go to definition.
305
+
306
+ ---
307
+
308
+ *Q?* Why can't I just use the built-in VSCode TypeScript LSP?
309
+
310
+ *A:* VSCode's built in TypeScript LSP can't resolve non `.ts/.js`, not even with plugins. Maybe one day they'll allow for
311
+ plugins that let you adjust the resolver and insert a transpilation step but until then a separate language server is necessary.
312
+
313
+ ---
314
+
315
+ *Q?* Sometimes the file outline disappears and the red squigglies are all in the wrong place and maybe a notification pops up
316
+ about some kind of LSP error.
317
+
318
+ *A:* I'm sorry that happened to you but the Civet Language Server is still alpha and improving rapidly. Please let me know
319
+ exactly what happened and I'll try to do better next time.
320
+
321
+ It may happen when there is a syntax error in your Civet file. You can check and see if it compiles using the CLI tool in the meantime.
322
+
323
+ Please do submit bug reports / feature requests.
324
+
325
+ ### Building
326
+
327
+ I strongly recommend using [esbuild](https://esbuild.github.io/) for building / packaging your Civet project.
328
+
329
+ ```javascript
330
+ import esbuild from 'esbuild'
331
+ import civetPlugin from '@danielx/civet/esbuild-plugin'
332
+
333
+ esbuild.build({
334
+ ...,
335
+ plugins: [
336
+ civetPlugin
337
+ ]
338
+ }).catch(() => process.exit(1))
339
+ ```
340
+
341
+ It's super fast and works great!