coffeehaml 0.6.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 -123
- 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 -4
- package/dist/lexer.js +536 -340
- package/dist/parser.js +533 -432
- package/dist/prettier/coffeescript-formatter.js +309 -0
- package/dist/prettier/index.js +105 -0
- package/dist/prettier/options.js +232 -0
- package/dist/prettier/printer.js +559 -0
- 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/docs/examples.md +201 -1
- package/docs/grammar.md +90 -1
- package/docs/index.html +260 -37
- package/package.json +12 -10
- package/syntaxes/CoffeeHaml.tmLanguage +815 -868
- package/syntaxes/coffeehaml.tmLanguage.json +352 -161
- package/dist/ast.d.ts +0 -117
- 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 -5
- 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/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/cli.js
CHANGED
|
@@ -1,22 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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()}
|
|
20
57
|
Haml structure. CoffeeScript semantics. React runtime.
|
|
21
58
|
|
|
22
59
|
Usage:
|
|
@@ -31,178 +68,193 @@ Options:
|
|
|
31
68
|
-h, --help Show this help
|
|
32
69
|
|
|
33
70
|
Examples:
|
|
34
|
-
coffeehaml init
|
|
71
|
+
coffeehaml init
|
|
35
72
|
coffeehaml compile app.chaml -o app.js --wrap component
|
|
36
73
|
coffeehaml compile app.chaml # prints to stdout
|
|
37
|
-
coffeehaml watch src/ --wrap observer # watch and recompile on change
|
|
38
|
-
|
|
39
|
-
process.exit(0);
|
|
74
|
+
coffeehaml watch src/ --wrap observer # watch and recompile on change`);
|
|
75
|
+
process.exit(0);
|
|
40
76
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return val
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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 {
|
|
76
126
|
return `Warning: ${warn.message}`;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
writeFileSync(opts.output + '.map', result.sourceMap);
|
|
93
|
-
}
|
|
94
|
-
console.error(`Compiled: ${input} → ${opts.output}`);
|
|
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));
|
|
95
142
|
}
|
|
96
|
-
|
|
97
|
-
|
|
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);
|
|
98
154
|
}
|
|
99
|
-
|
|
100
|
-
}
|
|
155
|
+
console.error(`Compiled: ${input} → ${opts.output}`);
|
|
156
|
+
} else {
|
|
157
|
+
process.stdout.write(result.code);
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
};
|
|
161
|
+
|
|
101
162
|
// ─── Init ──────────────────────────────────────────────────
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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());
|
|
109
173
|
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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');
|
|
133
236
|
}
|
|
134
|
-
|
|
135
|
-
|
|
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';
|
|
136
241
|
if (hasViteConfig) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
createSample = !/^n/i.test(ans);
|
|
148
|
-
// Question 4: npm scripts?
|
|
149
|
-
let addScripts = false;
|
|
150
|
-
if (hasPkg) {
|
|
151
|
-
const ans = await ask(' Add build/watch scripts to package.json? (Y/n): ');
|
|
152
|
-
addScripts = !/^n/i.test(ans);
|
|
153
|
-
}
|
|
154
|
-
console.log();
|
|
155
|
-
// ── Execute ──
|
|
156
|
-
// 1. Install dependency
|
|
157
|
-
if (addDep) {
|
|
158
|
-
console.log(' ⚡ Installing coffeehaml...');
|
|
159
|
-
const { execSync } = await import('child_process');
|
|
160
|
-
try {
|
|
161
|
-
execSync('npm install --save-dev coffeehaml', { cwd, stdio: 'inherit' });
|
|
162
|
-
console.log(' ✓ coffeehaml installed\n');
|
|
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()],');
|
|
163
252
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (setupVite) {
|
|
170
|
-
const configPath = join(cwd, hasViteConfig
|
|
171
|
-
? (existsSync(join(cwd, 'vite.config.ts')) ? 'vite.config.ts' : 'vite.config.js')
|
|
172
|
-
: 'vite.config.ts');
|
|
173
|
-
const ext = configPath.endsWith('.ts') ? 'ts' : 'js';
|
|
174
|
-
if (hasViteConfig) {
|
|
175
|
-
// Modify existing vite config — inject the import and plugin
|
|
176
|
-
let existing = readFileSync(configPath, 'utf-8');
|
|
177
|
-
const hasImport = /coffeehaml/.test(existing);
|
|
178
|
-
const hasPlugin = /coffeehaml\(\)/.test(existing);
|
|
179
|
-
if (!hasImport) {
|
|
180
|
-
existing = `import coffeehaml from 'coffeehaml/vite-plugin';\n` + existing;
|
|
181
|
-
}
|
|
182
|
-
if (!hasPlugin) {
|
|
183
|
-
// Insert coffeehaml() into plugins array
|
|
184
|
-
existing = existing.replace(/(plugins\s*:\s*\[)/, '$1\n coffeehaml(),');
|
|
185
|
-
if (!/plugins\s*:\s*\[/.test(existing)) {
|
|
186
|
-
// No plugins array — add one after defineConfig({
|
|
187
|
-
existing = existing.replace(/(defineConfig\s*\(\s*\{)/, '$1\n plugins: [coffeehaml()],');
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
writeFileSync(configPath, existing);
|
|
191
|
-
console.log(` ✓ Updated ${relative(cwd, configPath)}\n`);
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
// Create new vite config
|
|
195
|
-
const tsContent = `import { defineConfig } from 'vite';
|
|
196
|
-
import react from '@vitejs/plugin-react';
|
|
197
|
-
import coffeehaml from 'coffeehaml/vite-plugin';
|
|
198
|
-
|
|
199
|
-
export default defineConfig({
|
|
200
|
-
plugins: [
|
|
201
|
-
react(),
|
|
202
|
-
coffeehaml(),
|
|
203
|
-
],
|
|
204
|
-
});`;
|
|
205
|
-
const jsContent = `import { defineConfig } from 'vite';
|
|
253
|
+
}
|
|
254
|
+
writeFileSync(configPath, existing);
|
|
255
|
+
console.log(` ✓ Updated ${relative(cwd, configPath)}\n`);
|
|
256
|
+
} else {
|
|
257
|
+
content = `import { defineConfig } from 'vite';
|
|
206
258
|
import react from '@vitejs/plugin-react';
|
|
207
259
|
import coffeehaml from 'coffeehaml/vite-plugin';
|
|
208
260
|
|
|
@@ -212,23 +264,22 @@ export default defineConfig({
|
|
|
212
264
|
coffeehaml(),
|
|
213
265
|
],
|
|
214
266
|
});`;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
267
|
+
writeFileSync(configPath, content);
|
|
268
|
+
console.log(` ✓ Created ${relative(cwd, configPath)}\n`);
|
|
218
269
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
|
232
283
|
import { useState } from 'react'
|
|
233
284
|
|
|
234
285
|
%div.app
|
|
@@ -239,120 +290,141 @@ import { useState } from 'react'
|
|
|
239
290
|
%main
|
|
240
291
|
- name = 'World'
|
|
241
292
|
%section.card
|
|
242
|
-
%h2= "Hello,
|
|
293
|
+
%h2= "Hello, \#{name}!"
|
|
243
294
|
%p= "Counter: 0"
|
|
244
295
|
|
|
245
296
|
%footer
|
|
246
|
-
%small Built with coffeehaml v${getVersion()}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.log(` ✓ Created ${relative(cwd, samplePath)}\n`);
|
|
250
|
-
}
|
|
297
|
+
%small Built with coffeehaml v${getVersion()}`;
|
|
298
|
+
writeFileSync(samplePath, sample);
|
|
299
|
+
console.log(` ✓ Created ${relative(cwd, samplePath)}\n`);
|
|
251
300
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
if (!pkg.scripts['watch:chaml']) {
|
|
261
|
-
pkg.scripts['watch:chaml'] = 'coffeehaml watch src/ --wrap component';
|
|
262
|
-
}
|
|
263
|
-
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
264
|
-
console.log(' ✓ Added build:chaml and watch:chaml scripts\n');
|
|
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/';
|
|
265
308
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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);
|
|
275
329
|
if (!opts.input) {
|
|
276
|
-
|
|
277
|
-
|
|
330
|
+
console.error('Error: no input file specified');
|
|
331
|
+
process.exit(1);
|
|
278
332
|
}
|
|
279
|
-
|
|
333
|
+
ok = doCompile(opts.input, opts);
|
|
280
334
|
process.exit(ok ? 0 : 1);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
335
|
+
break;
|
|
336
|
+
case 'watch':
|
|
337
|
+
opts = parseArgs(rest);
|
|
284
338
|
if (!opts.input) {
|
|
285
|
-
|
|
286
|
-
|
|
339
|
+
console.error('Error: no input path specified');
|
|
340
|
+
process.exit(1);
|
|
287
341
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
files.push(
|
|
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
|
+
}
|
|
309
366
|
}
|
|
310
|
-
|
|
367
|
+
return results;
|
|
368
|
+
} else if (/\.(chaml|coffeehaml)$/.test(dir)) {
|
|
369
|
+
return files.push(dir);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
311
372
|
findFiles(target);
|
|
312
373
|
if (files.length === 0) {
|
|
313
|
-
|
|
314
|
-
|
|
374
|
+
console.error(`Error: no .chaml/.coffeehaml files found in ${opts.input}`);
|
|
375
|
+
process.exit(1);
|
|
315
376
|
}
|
|
316
377
|
console.error(`Watching ${files.length} file(s)...`);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
+
}
|
|
328
395
|
};
|
|
329
|
-
for (
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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));
|
|
344
417
|
});
|
|
345
|
-
process.on('SIGINT', ()
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
418
|
+
process.on('SIGINT', function() {
|
|
419
|
+
watcher.close();
|
|
420
|
+
console.error('\nStopped watching.');
|
|
421
|
+
return process.exit(0);
|
|
349
422
|
});
|
|
350
|
-
|
|
351
|
-
|
|
423
|
+
break;
|
|
424
|
+
case 'init':
|
|
352
425
|
doInit();
|
|
353
|
-
|
|
354
|
-
|
|
426
|
+
break;
|
|
427
|
+
default:
|
|
355
428
|
console.error(`Unknown command: ${cmd}`);
|
|
356
429
|
process.exit(1);
|
|
357
430
|
}
|
|
358
|
-
//# sourceMappingURL=cli.js.map
|