coffeehaml 0.7.0 → 0.7.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 +21 -5
- package/dist/ast.js +334 -125
- package/dist/cli.js +363 -291
- package/dist/compiler.js +126 -89
- package/dist/emitter.js +771 -736
- package/dist/errors.js +5 -2
- package/dist/expressions.js +211 -154
- package/dist/index.js +22 -6
- package/dist/lexer.js +536 -340
- package/dist/parser.js +533 -438
- package/dist/prettier/coffeescript-formatter.js +292 -392
- package/dist/prettier/index.js +96 -60
- package/dist/prettier/options.js +179 -147
- package/dist/prettier/printer.js +549 -642
- package/dist/src/ast.js +338 -0
- package/dist/src/cli.js +430 -0
- package/dist/src/compiler.js +132 -0
- package/dist/src/emitter.js +791 -0
- package/dist/src/errors.js +5 -0
- package/dist/src/expressions.js +223 -0
- package/dist/src/index.js +22 -0
- package/dist/src/lexer.js +504 -0
- package/dist/src/parser.js +575 -0
- package/dist/src/types.js +122 -0
- package/dist/src/vite-plugin.js +78 -0
- package/dist/types.js +122 -12
- package/dist/vite-plugin.js +78 -63
- package/package.json +4 -9
- package/dist/ast.d.ts +0 -123
- package/dist/ast.d.ts.map +0 -1
- package/dist/ast.js.map +0 -1
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/compiler.d.ts +0 -10
- package/dist/compiler.d.ts.map +0 -1
- package/dist/compiler.js.map +0 -1
- package/dist/emitter.d.ts +0 -4
- package/dist/emitter.d.ts.map +0 -1
- package/dist/emitter.js.map +0 -1
- package/dist/errors.d.ts +0 -3
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/expressions.d.ts +0 -22
- package/dist/expressions.d.ts.map +0 -1
- package/dist/expressions.js.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lexer.d.ts +0 -30
- package/dist/lexer.d.ts.map +0 -1
- package/dist/lexer.js.map +0 -1
- package/dist/parser.d.ts +0 -10
- package/dist/parser.d.ts.map +0 -1
- package/dist/parser.js.map +0 -1
- package/dist/prettier/coffeescript-formatter.d.ts +0 -31
- package/dist/prettier/coffeescript-formatter.d.ts.map +0 -1
- package/dist/prettier/coffeescript-formatter.js.map +0 -1
- package/dist/prettier/index.d.ts +0 -8
- package/dist/prettier/index.d.ts.map +0 -1
- package/dist/prettier/index.js.map +0 -1
- package/dist/prettier/options.d.ts +0 -10
- package/dist/prettier/options.d.ts.map +0 -1
- package/dist/prettier/options.js.map +0 -1
- package/dist/prettier/printer.d.ts +0 -45
- package/dist/prettier/printer.d.ts.map +0 -1
- package/dist/prettier/printer.js.map +0 -1
- package/dist/types.d.ts +0 -76
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/vite-plugin.d.ts +0 -7
- package/dist/vite-plugin.d.ts.map +0 -1
- package/dist/vite-plugin.js.map +0 -1
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
//!/usr/bin/env node
|
|
3
|
+
// cli.coffee — CoffeeHaml command-line interface
|
|
4
|
+
var _require, args, ask, cmd, compileFn, doCompile, doInit, file, files, findFiles, formatError, formatWarning, getVersion, i, initial, len, ok, opts, parseArgs, parseWrapFlag, rest, stats, target, timers, watchDir, watcher,
|
|
5
|
+
indexOf = [].indexOf;
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
compileFile
|
|
9
|
+
} from './index.js';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
writeFileSync,
|
|
13
|
+
readFileSync,
|
|
14
|
+
existsSync,
|
|
15
|
+
watch,
|
|
16
|
+
statSync,
|
|
17
|
+
readdirSync,
|
|
18
|
+
mkdirSync
|
|
19
|
+
} from 'fs';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
fileURLToPath
|
|
23
|
+
} from 'url';
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
dirname,
|
|
27
|
+
join,
|
|
28
|
+
resolve,
|
|
29
|
+
relative
|
|
30
|
+
} from 'path';
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
createInterface
|
|
34
|
+
} from 'readline';
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
createRequire
|
|
38
|
+
} from 'module';
|
|
39
|
+
|
|
40
|
+
_require = createRequire(import.meta.url);
|
|
41
|
+
|
|
42
|
+
getVersion = function() {
|
|
43
|
+
var __dirname, pkg;
|
|
44
|
+
try {
|
|
45
|
+
__dirname = dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
47
|
+
return pkg.version || '0.0.0';
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return '0.0.0';
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
args = process.argv.slice(2);
|
|
54
|
+
|
|
55
|
+
if (args.length === 0 || indexOf.call(args, '--help') >= 0 || indexOf.call(args, '-h') >= 0) {
|
|
56
|
+
console.log(`CoffeeHaml v${getVersion()}
|
|
57
|
+
Haml structure. CoffeeScript semantics. React runtime.
|
|
58
|
+
|
|
59
|
+
Usage:
|
|
60
|
+
coffeehaml init scaffold a new project
|
|
61
|
+
coffeehaml compile <input> [-o <output>] [--source-map] [--wrap <mode>]
|
|
62
|
+
coffeehaml watch <input> [-o <output>] [--source-map] [--wrap <mode>]
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
-o, --output <file> Write output to file instead of stdout
|
|
66
|
+
--source-map Emit inline source map
|
|
67
|
+
--wrap <mode> Wrap output: 'component', 'observer', or comma-separated HOC list
|
|
68
|
+
-h, --help Show this help
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
coffeehaml init
|
|
72
|
+
coffeehaml compile app.chaml -o app.js --wrap component
|
|
73
|
+
coffeehaml compile app.chaml # prints to stdout
|
|
74
|
+
coffeehaml watch src/ --wrap observer # watch and recompile on change`);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
parseWrapFlag = function(args) {
|
|
79
|
+
var idx, val;
|
|
80
|
+
idx = args.indexOf('--wrap');
|
|
81
|
+
if (idx === -1) {
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
84
|
+
val = args[idx + 1];
|
|
85
|
+
if (!(val && !val.startsWith('-'))) {
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
if (val === 'component' || val === 'observer' || val === 'none') {
|
|
89
|
+
return val;
|
|
90
|
+
}
|
|
91
|
+
return val.split(',').map(function(s) {
|
|
92
|
+
return s.trim();
|
|
93
|
+
}).filter(Boolean);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
parseArgs = function(args) {
|
|
97
|
+
var outIdx, output, sourceMap, wrap;
|
|
98
|
+
outIdx = args.indexOf('-o') !== -1 ? args.indexOf('-o') : args.indexOf('--output');
|
|
99
|
+
output = outIdx !== -1 ? args[outIdx + 1] : void 0;
|
|
100
|
+
sourceMap = indexOf.call(args, '--source-map') >= 0;
|
|
101
|
+
wrap = parseWrapFlag(args);
|
|
102
|
+
return {
|
|
103
|
+
input: args[0],
|
|
104
|
+
output,
|
|
105
|
+
sourceMap,
|
|
106
|
+
wrap
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
formatError = function(err, filename) {
|
|
111
|
+
var loc, msg;
|
|
112
|
+
loc = err.location;
|
|
113
|
+
msg = loc ? `${filename}:${loc.start.line + 1}:${loc.start.column + 1}: [${err.code}] ${err.message}` : `[${err.code}] ${err.message}`;
|
|
114
|
+
if (err.hint) {
|
|
115
|
+
msg += `\n Hint: ${err.hint}`;
|
|
116
|
+
}
|
|
117
|
+
return msg;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
formatWarning = function(warn, filename) {
|
|
121
|
+
var loc;
|
|
122
|
+
loc = warn.location;
|
|
123
|
+
if (loc) {
|
|
124
|
+
return `Warning: ${filename}:${loc.start.line + 1}:${loc.start.column + 1}: ${warn.message}`;
|
|
125
|
+
} else {
|
|
126
|
+
return `Warning: ${warn.message}`;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
doCompile = function(input, opts) {
|
|
131
|
+
var err, i, j, len, len1, ref, ref1, result, warn;
|
|
132
|
+
result = compileFile(input, {
|
|
133
|
+
filename: input,
|
|
134
|
+
sourceMap: opts.sourceMap,
|
|
135
|
+
wrap: opts.wrap
|
|
136
|
+
});
|
|
137
|
+
if (result.errors.length > 0) {
|
|
138
|
+
ref = result.errors;
|
|
139
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
140
|
+
err = ref[i];
|
|
141
|
+
console.error(formatError(err, input));
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
ref1 = result.warnings;
|
|
146
|
+
for (j = 0, len1 = ref1.length; j < len1; j++) {
|
|
147
|
+
warn = ref1[j];
|
|
148
|
+
console.error(formatWarning(warn, input));
|
|
149
|
+
}
|
|
150
|
+
if (opts.output) {
|
|
151
|
+
writeFileSync(opts.output, result.code);
|
|
152
|
+
if (result.sourceMap) {
|
|
153
|
+
writeFileSync(opts.output + '.map', result.sourceMap);
|
|
154
|
+
}
|
|
155
|
+
console.error(`Compiled: ${input} → ${opts.output}`);
|
|
156
|
+
} else {
|
|
157
|
+
process.stdout.write(result.code);
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// ─── Init ──────────────────────────────────────────────────
|
|
163
|
+
ask = function(q) {
|
|
164
|
+
var rl;
|
|
165
|
+
rl = createInterface({
|
|
166
|
+
input: process.stdin,
|
|
167
|
+
output: process.stdout
|
|
168
|
+
});
|
|
169
|
+
return new Promise(function(resolve) {
|
|
170
|
+
return rl.question(q, function(answer) {
|
|
171
|
+
rl.close();
|
|
172
|
+
return resolve(answer.trim());
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
doInit = async function() {
|
|
178
|
+
var addDep, addScripts, ans, configPath, content, createSample, cwd, detections, execSync, existing, ext, hasImport, hasPkg, hasPlugin, hasTsConfig, hasViteConfig, pkg, pkgPath, sample, samplePath, setupVite, srcDir;
|
|
179
|
+
cwd = process.cwd();
|
|
180
|
+
hasPkg = existsSync(join(cwd, 'package.json'));
|
|
181
|
+
hasViteConfig = existsSync(join(cwd, 'vite.config.ts')) || existsSync(join(cwd, 'vite.config.js'));
|
|
182
|
+
hasTsConfig = existsSync(join(cwd, 'tsconfig.json'));
|
|
183
|
+
console.log("\n ☕ CoffeeHaml init — project scaffold\n");
|
|
184
|
+
console.log(` Working directory: ${cwd}`);
|
|
185
|
+
detections = [];
|
|
186
|
+
if (hasPkg) {
|
|
187
|
+
detections.push('package.json');
|
|
188
|
+
}
|
|
189
|
+
if (hasViteConfig) {
|
|
190
|
+
detections.push('Vite');
|
|
191
|
+
}
|
|
192
|
+
if (hasTsConfig) {
|
|
193
|
+
detections.push('TypeScript');
|
|
194
|
+
}
|
|
195
|
+
if (!hasPkg) {
|
|
196
|
+
detections.push('bare project');
|
|
197
|
+
}
|
|
198
|
+
console.log(` Detected: ${detections.join(', ')}\n`);
|
|
199
|
+
addDep = true;
|
|
200
|
+
if (hasPkg) {
|
|
201
|
+
ans = (await ask(' Add coffeehaml as devDependency? (Y/n): '));
|
|
202
|
+
addDep = !/^n/i.test(ans);
|
|
203
|
+
} else {
|
|
204
|
+
console.log(' No package.json found — skipping dependency install.');
|
|
205
|
+
addDep = false;
|
|
206
|
+
}
|
|
207
|
+
setupVite = false;
|
|
208
|
+
if (hasViteConfig) {
|
|
209
|
+
ans = (await ask(' Configure Vite plugin? (Y/n): '));
|
|
210
|
+
setupVite = !/^n/i.test(ans);
|
|
211
|
+
} else if (hasPkg) {
|
|
212
|
+
ans = (await ask(' No vite.config detected. Create one with CoffeeHaml plugin? (y/N): '));
|
|
213
|
+
setupVite = /^y/i.test(ans);
|
|
214
|
+
}
|
|
215
|
+
createSample = true;
|
|
216
|
+
ans = (await ask(' Create sample .chaml component? (Y/n): '));
|
|
217
|
+
createSample = !/^n/i.test(ans);
|
|
218
|
+
addScripts = false;
|
|
219
|
+
if (hasPkg) {
|
|
220
|
+
ans = (await ask(' Add build/watch scripts to package.json? (Y/n): '));
|
|
221
|
+
addScripts = !/^n/i.test(ans);
|
|
222
|
+
}
|
|
223
|
+
console.log('');
|
|
224
|
+
// Execute
|
|
225
|
+
if (addDep) {
|
|
226
|
+
console.log(' ⚡ Installing coffeehaml...');
|
|
227
|
+
({execSync} = _require('child_process'));
|
|
228
|
+
try {
|
|
229
|
+
execSync('npm install --save-dev coffeehaml', {
|
|
230
|
+
cwd: cwd,
|
|
231
|
+
stdio: 'inherit'
|
|
232
|
+
});
|
|
233
|
+
console.log(' ✓ coffeehaml installed\n');
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.log(' ✗ Install failed — continuing anyway\n');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (setupVite) {
|
|
239
|
+
configPath = hasViteConfig ? existsSync(join(cwd, 'vite.config.ts')) ? join(cwd, 'vite.config.ts') : join(cwd, 'vite.config.js') : join(cwd, 'vite.config.ts');
|
|
240
|
+
ext = configPath.endsWith('.ts') ? 'ts' : 'js';
|
|
241
|
+
if (hasViteConfig) {
|
|
242
|
+
existing = readFileSync(configPath, 'utf-8');
|
|
243
|
+
hasImport = /coffeehaml/.test(existing);
|
|
244
|
+
hasPlugin = /coffeehaml\(\)/.test(existing);
|
|
245
|
+
if (!hasImport) {
|
|
246
|
+
existing = "import coffeehaml from 'coffeehaml/vite-plugin';\n" + existing;
|
|
247
|
+
}
|
|
248
|
+
if (!hasPlugin) {
|
|
249
|
+
existing = existing.replace(/(plugins\s*:\s*\[)/, '$1\n coffeehaml(),');
|
|
250
|
+
if (!/plugins\s*:\s*\[/.test(existing)) {
|
|
251
|
+
existing = existing.replace(/(defineConfig\s*\(\s*\{)/, '$1\n plugins: [coffeehaml()],');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
writeFileSync(configPath, existing);
|
|
255
|
+
console.log(` ✓ Updated ${relative(cwd, configPath)}\n`);
|
|
256
|
+
} else {
|
|
257
|
+
content = `import { defineConfig } from 'vite';
|
|
258
|
+
import react from '@vitejs/plugin-react';
|
|
259
|
+
import coffeehaml from 'coffeehaml/vite-plugin';
|
|
260
|
+
|
|
261
|
+
export default defineConfig({
|
|
262
|
+
plugins: [
|
|
263
|
+
react(),
|
|
264
|
+
coffeehaml(),
|
|
265
|
+
],
|
|
266
|
+
});`;
|
|
267
|
+
writeFileSync(configPath, content);
|
|
268
|
+
console.log(` ✓ Created ${relative(cwd, configPath)}\n`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (createSample) {
|
|
272
|
+
srcDir = join(cwd, 'src');
|
|
273
|
+
if (!existsSync(srcDir)) {
|
|
274
|
+
mkdirSync(srcDir, {
|
|
275
|
+
recursive: true
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
samplePath = join(srcDir, 'App.chaml');
|
|
279
|
+
if (existsSync(samplePath)) {
|
|
280
|
+
console.log(` ⚠ ${relative(cwd, samplePath)} already exists — skipping\n`);
|
|
281
|
+
} else {
|
|
282
|
+
sample = `-# App.chaml — a sample CoffeeHaml component
|
|
283
|
+
import { useState } from 'react'
|
|
284
|
+
|
|
285
|
+
%div.app
|
|
286
|
+
%header
|
|
287
|
+
%h1= "CoffeeHaml ✨"
|
|
288
|
+
%p.subtitle Haml structure. CoffeeScript semantics. React runtime.
|
|
289
|
+
|
|
290
|
+
%main
|
|
291
|
+
- name = 'World'
|
|
292
|
+
%section.card
|
|
293
|
+
%h2= "Hello, \#{name}!"
|
|
294
|
+
%p= "Counter: 0"
|
|
295
|
+
|
|
296
|
+
%footer
|
|
297
|
+
%small Built with coffeehaml v${getVersion()}`;
|
|
298
|
+
writeFileSync(samplePath, sample);
|
|
299
|
+
console.log(` ✓ Created ${relative(cwd, samplePath)}\n`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (addScripts && hasPkg) {
|
|
303
|
+
pkgPath = join(cwd, 'package.json');
|
|
304
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
305
|
+
pkg.scripts = pkg.scripts || {};
|
|
306
|
+
if (!pkg.scripts['build:chaml']) {
|
|
307
|
+
pkg.scripts['build:chaml'] = 'coffeehaml compile src/ -o dist/';
|
|
308
|
+
}
|
|
309
|
+
if (!pkg.scripts['watch:chaml']) {
|
|
310
|
+
pkg.scripts['watch:chaml'] = 'coffeehaml watch src/ --wrap component';
|
|
311
|
+
}
|
|
312
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
313
|
+
console.log(' ✓ Added build:chaml and watch:chaml scripts\n');
|
|
314
|
+
}
|
|
315
|
+
console.log(' 🎉 Done! Start building:\n');
|
|
316
|
+
console.log(' npm run build:chaml # compile once');
|
|
317
|
+
console.log(' npm run watch:chaml # watch and recompile');
|
|
318
|
+
return console.log(' npx coffeehaml watch src/ # ad-hoc watch\n');
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// ─── Main ──────────────────────────────────────────────────
|
|
322
|
+
cmd = args[0];
|
|
323
|
+
|
|
324
|
+
rest = args.slice(1);
|
|
325
|
+
|
|
326
|
+
switch (cmd) {
|
|
327
|
+
case 'compile':
|
|
328
|
+
opts = parseArgs(rest);
|
|
329
|
+
if (!opts.input) {
|
|
330
|
+
console.error('Error: no input file specified');
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
ok = doCompile(opts.input, opts);
|
|
334
|
+
process.exit(ok ? 0 : 1);
|
|
335
|
+
break;
|
|
336
|
+
case 'watch':
|
|
337
|
+
opts = parseArgs(rest);
|
|
338
|
+
if (!opts.input) {
|
|
339
|
+
console.error('Error: no input path specified');
|
|
340
|
+
process.exit(1);
|
|
341
|
+
}
|
|
342
|
+
target = resolve(opts.input);
|
|
343
|
+
stats = existsSync(target) ? statSync(target) : null;
|
|
344
|
+
files = [];
|
|
345
|
+
findFiles = function(dir) {
|
|
346
|
+
var entry, full, i, len, ref, results, stat;
|
|
347
|
+
if (!existsSync(dir)) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
stat = statSync(dir);
|
|
351
|
+
if (stat.isDirectory()) {
|
|
352
|
+
ref = readdirSync(dir, {
|
|
353
|
+
withFileTypes: true
|
|
354
|
+
});
|
|
355
|
+
results = [];
|
|
356
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
|
357
|
+
entry = ref[i];
|
|
358
|
+
full = join(dir, entry.name);
|
|
359
|
+
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules') {
|
|
360
|
+
results.push(findFiles(full));
|
|
361
|
+
} else if (entry.isFile() && /\.(chaml|coffeehaml)$/.test(entry.name)) {
|
|
362
|
+
results.push(files.push(full));
|
|
363
|
+
} else {
|
|
364
|
+
results.push(void 0);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return results;
|
|
368
|
+
} else if (/\.(chaml|coffeehaml)$/.test(dir)) {
|
|
369
|
+
return files.push(dir);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
findFiles(target);
|
|
373
|
+
if (files.length === 0) {
|
|
374
|
+
console.error(`Error: no .chaml/.coffeehaml files found in ${opts.input}`);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
console.error(`Watching ${files.length} file(s)...`);
|
|
378
|
+
initial = true;
|
|
379
|
+
compileFn = function(file) {
|
|
380
|
+
var outFile, rel;
|
|
381
|
+
rel = relative(process.cwd(), file);
|
|
382
|
+
if (!initial) {
|
|
383
|
+
console.error(`\n[recompile] ${rel}`);
|
|
384
|
+
}
|
|
385
|
+
initial = false;
|
|
386
|
+
outFile = opts.output || file.replace(/\.(chaml|coffeehaml)$/, '.js');
|
|
387
|
+
ok = doCompile(file, {
|
|
388
|
+
...opts,
|
|
389
|
+
output: outFile,
|
|
390
|
+
input: file
|
|
391
|
+
});
|
|
392
|
+
if (!ok) {
|
|
393
|
+
return console.error(` ✗ ${rel}`);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
for (i = 0, len = files.length; i < len; i++) {
|
|
397
|
+
file = files[i];
|
|
398
|
+
compileFn(file);
|
|
399
|
+
}
|
|
400
|
+
timers = new Map();
|
|
401
|
+
watchDir = (stats != null ? stats.isDirectory() : void 0) ? target : dirname(target);
|
|
402
|
+
watcher = watch(watchDir, {
|
|
403
|
+
recursive: true
|
|
404
|
+
}, function(_event, filename) {
|
|
405
|
+
var full;
|
|
406
|
+
if (!(filename && /\.(chaml|coffeehaml)$/.test(filename))) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
full = resolve(watchDir, filename);
|
|
410
|
+
if (timers.has(full)) {
|
|
411
|
+
clearTimeout(timers.get(full));
|
|
412
|
+
}
|
|
413
|
+
return timers.set(full, setTimeout((function() {
|
|
414
|
+
timers.delete(full);
|
|
415
|
+
return compileFn(full);
|
|
416
|
+
}), 100));
|
|
417
|
+
});
|
|
418
|
+
process.on('SIGINT', function() {
|
|
419
|
+
watcher.close();
|
|
420
|
+
console.error('\nStopped watching.');
|
|
421
|
+
return process.exit(0);
|
|
422
|
+
});
|
|
423
|
+
break;
|
|
424
|
+
case 'init':
|
|
425
|
+
doInit();
|
|
426
|
+
break;
|
|
427
|
+
default:
|
|
428
|
+
console.error(`Unknown command: ${cmd}`);
|
|
429
|
+
process.exit(1);
|
|
430
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Generated by CoffeeScript 2.7.0
|
|
2
|
+
// compiler.coffee — compile pipeline orchestration
|
|
3
|
+
var wrapError;
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
tokenize
|
|
7
|
+
} from './lexer.js';
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
parse
|
|
11
|
+
} from './parser.js';
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
emit
|
|
15
|
+
} from './emitter.js';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
CompileError
|
|
19
|
+
} from './types.js';
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
isCoffeeScriptAvailable,
|
|
23
|
+
getCoffeeScriptUnavailableReason
|
|
24
|
+
} from './expressions.js';
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
readFileSync,
|
|
28
|
+
existsSync
|
|
29
|
+
} from 'fs';
|
|
30
|
+
|
|
31
|
+
// Supported extensions
|
|
32
|
+
export var COFFEEHAML_EXTENSIONS = ['.coffeehaml', '.cohaml', '.chaml'];
|
|
33
|
+
|
|
34
|
+
// Resolve a CoffeeHaml file path
|
|
35
|
+
export var resolveCoffeeHamlFile = function(filepath) {
|
|
36
|
+
var ext, i, len, withExt;
|
|
37
|
+
if (existsSync(filepath)) {
|
|
38
|
+
return filepath;
|
|
39
|
+
}
|
|
40
|
+
for (i = 0, len = COFFEEHAML_EXTENSIONS.length; i < len; i++) {
|
|
41
|
+
ext = COFFEEHAML_EXTENSIONS[i];
|
|
42
|
+
withExt = filepath + ext;
|
|
43
|
+
if (existsSync(withExt)) {
|
|
44
|
+
return withExt;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Compile CoffeeHaml source to JavaScript
|
|
51
|
+
export var compile = function(source, options = {}) {
|
|
52
|
+
var ast, e, errors, parsed, result, tokens, warnings;
|
|
53
|
+
errors = [];
|
|
54
|
+
warnings = [];
|
|
55
|
+
// Warn if CoffeeScript unavailable
|
|
56
|
+
if (!isCoffeeScriptAvailable()) {
|
|
57
|
+
warnings.push({
|
|
58
|
+
message: `CoffeeScript expression compiler unavailable: ${getCoffeeScriptUnavailableReason()}. CoffeeScript expressions will passthrough raw and may produce invalid JavaScript. Install coffeescript as a peer dependency.`,
|
|
59
|
+
phase: 'compiler'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
// Phase 1: Lex
|
|
64
|
+
tokens = tokenize(source, options.filename);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
e = error;
|
|
67
|
+
return {
|
|
68
|
+
code: '',
|
|
69
|
+
errors: [wrapError(e, 'lexer')],
|
|
70
|
+
warnings: []
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Phase 2: Parse
|
|
74
|
+
parsed = parse(tokens, options.filename);
|
|
75
|
+
ast = parsed.document;
|
|
76
|
+
if (parsed.errors.length > 0) {
|
|
77
|
+
errors.push(...parsed.errors);
|
|
78
|
+
if (ast.children.length === 0) {
|
|
79
|
+
return {
|
|
80
|
+
code: '',
|
|
81
|
+
errors,
|
|
82
|
+
warnings
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
// Phase 3: Emit
|
|
88
|
+
result = emit(ast, {
|
|
89
|
+
sourceMap: options.sourceMap,
|
|
90
|
+
filename: options.filename,
|
|
91
|
+
jsxRuntime: options.jsxRuntime,
|
|
92
|
+
filters: options.filters,
|
|
93
|
+
wrap: options.wrap,
|
|
94
|
+
componentName: options.componentName
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
e = error;
|
|
98
|
+
return {
|
|
99
|
+
code: '',
|
|
100
|
+
errors: [wrapError(e, 'emitter')],
|
|
101
|
+
warnings
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (result.warnings) {
|
|
105
|
+
warnings.push(...result.warnings);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
code: result.code,
|
|
109
|
+
sourceMap: result.sourceMap,
|
|
110
|
+
errors,
|
|
111
|
+
warnings
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Compile from disk
|
|
116
|
+
export var compileFile = function(filepath, options = {}) {
|
|
117
|
+
var source;
|
|
118
|
+
source = readFileSync(filepath, 'utf-8');
|
|
119
|
+
return compile(source, {
|
|
120
|
+
...options,
|
|
121
|
+
filename: filepath
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// ─── Helpers ───────────────────────────────────────────────
|
|
126
|
+
wrapError = function(e, phase) {
|
|
127
|
+
if (e instanceof CompileError) {
|
|
128
|
+
e.phase = phase;
|
|
129
|
+
return e;
|
|
130
|
+
}
|
|
131
|
+
return new CompileError(e instanceof Error ? e.message : String(e), phase, 'INTERNAL_ERROR');
|
|
132
|
+
};
|