funcity-cli 0.5.0 → 0.6.0

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
@@ -61,8 +61,8 @@ const script = "Today is {{cond weather.sunny ‘nice’ 'bad'}} weather.";
61
61
 
62
62
  // Run the interpreter
63
63
  const variables = buildCandidateVariables();
64
- const errors: FunCityErrorInfo[] = [];
65
- const text = await runScriptOnce(script, variables, errors);
64
+ const logs: FunCityLogEntry[] = [];
65
+ const text = await runScriptOnceToText(script, variables, logs);
66
66
 
67
67
  // Display the result text
68
68
  console.log(text);
package/dist/cli.d.ts CHANGED
@@ -1,16 +1,18 @@
1
- import { FunCityErrorInfo } from 'funcity';
1
+ import { FunCityLogEntry } from 'funcity';
2
2
  export interface ReplEvaluationResult {
3
3
  readonly output: string | undefined;
4
- readonly errors: FunCityErrorInfo[];
4
+ readonly logs: FunCityLogEntry[];
5
+ readonly shouldExit: boolean;
5
6
  }
6
7
  export interface ReplSession {
8
+ evaluateLine: (line: string, signal: AbortSignal) => Promise<ReplEvaluationResult>;
7
9
  getPrompt: () => Promise<string>;
8
- evaluateLine: (line: string) => Promise<ReplEvaluationResult>;
10
+ setVariable: (name: string, value: unknown) => void;
9
11
  }
10
12
  export declare const createReplSession: () => ReplSession;
11
- export declare const runScriptToText: (script: string) => Promise<{
13
+ export declare const runScriptToText: (script: string, basePath?: string) => Promise<{
12
14
  output: string | undefined;
13
- errors: FunCityErrorInfo[];
15
+ logs: FunCityLogEntry[];
14
16
  }>;
15
17
  export declare const runMain: (argv?: string[]) => Promise<void>;
16
18
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEL,gBAAgB,EAGjB,MAAM,SAAS,CAAC;AAsCjB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC/D;AAED,eAAO,MAAM,iBAAiB,QAAO,WAiDpC,CAAC;AAkEF,eAAO,MAAM,eAAe,GAAU,QAAQ,MAAM;;;EAKnD,CAAC;AAgFF,eAAO,MAAM,OAAO,GAAU,OAAM,MAAM,EAAiB,KAAG,OAAO,CAAC,IAAI,CAmCzE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,eAAe,EAIhB,MAAM,SAAS,CAAC;AAkNjB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,CACZ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,KAChB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACrD;AAED,eAAO,MAAM,iBAAiB,QAAO,WA6EpC,CAAC;AAwJF,eAAO,MAAM,eAAe,GAAU,QAAQ,MAAM,EAAE,WAAW,MAAM;;;EAQtE,CAAC;AA8HF,eAAO,MAAM,OAAO,GAAU,OAAM,MAAM,EAAiB,KAAG,OAAO,CAAC,IAAI,CAsCzE,CAAC"}
@@ -1,8 +1,8 @@
1
1
  export declare const name = "funcity-cli";
2
- export declare const version = "0.5.0";
2
+ export declare const version = "0.6.0";
3
3
  export declare const description = "A functional language interpreter with text processing";
4
4
  export declare const author = "Kouji Matsui (@kekyo@mi.kekyo.net)";
5
5
  export declare const license = "MIT";
6
- export declare const repository_url = "https://github.com/kekyo/funcity.git";
7
- export declare const git_commit_hash = "68a2ab1ac86b865b1c2ea37aa43816ee34d29540";
6
+ export declare const repository_url = "https://github.com/kekyo/funcity";
7
+ export declare const git_commit_hash = "0ead9e15b1d6951acb7bf50d4850def586a23c47";
8
8
  //# sourceMappingURL=packageMetadata.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageMetadata.d.ts","sourceRoot":"","sources":["../../src/generated/packageMetadata.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAClC,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,WAAW,2DAA2D,CAAC;AACpF,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAC3D,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,cAAc,yCAAyC,CAAC;AACrE,eAAO,MAAM,eAAe,6CAA6C,CAAC"}
1
+ {"version":3,"file":"packageMetadata.d.ts","sourceRoot":"","sources":["../../src/generated/packageMetadata.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAClC,eAAO,MAAM,OAAO,UAAU,CAAC;AAC/B,eAAO,MAAM,WAAW,2DAA2D,CAAC;AACpF,eAAO,MAAM,MAAM,uCAAuC,CAAC;AAC3D,eAAO,MAAM,OAAO,QAAQ,CAAC;AAC7B,eAAO,MAAM,cAAc,qCAAqC,CAAC;AACjE,eAAO,MAAM,eAAe,6CAA6C,CAAC"}
package/dist/index.cjs CHANGED
@@ -1,24 +1,102 @@
1
1
  #!/usr/bin/env node
2
2
  /*!
3
3
  * name: funcity-cli
4
- * version: 0.5.0
4
+ * version: 0.6.0
5
5
  * description: A functional language interpreter with text processing
6
6
  * author: Kouji Matsui (@kekyo@mi.kekyo.net)
7
7
  * license: MIT
8
- * repository.url: https://github.com/kekyo/funcity.git
9
- * git.commit.hash: 68a2ab1ac86b865b1c2ea37aa43816ee34d29540
8
+ * repository.url: https://github.com/kekyo/funcity
9
+ * git.commit.hash: 0ead9e15b1d6951acb7bf50d4850def586a23c47
10
10
  */
11
11
 
12
12
  "use strict";
13
13
  const promises = require("fs/promises");
14
+ const os = require("os");
15
+ const path = require("path");
14
16
  const readline = require("readline");
15
17
  const commander = require("commander");
16
18
  const funcity = require("funcity");
19
+ const node = require("funcity/node");
20
+ function _interopNamespaceDefault(e) {
21
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
22
+ if (e) {
23
+ for (const k in e) {
24
+ if (k !== "default") {
25
+ const d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: () => e[k]
29
+ });
30
+ }
31
+ }
32
+ }
33
+ n.default = e;
34
+ return Object.freeze(n);
35
+ }
36
+ const os__namespace = /* @__PURE__ */ _interopNamespaceDefault(os);
37
+ const path__namespace = /* @__PURE__ */ _interopNamespaceDefault(path);
17
38
  const name = "funcity-cli";
18
- const version = "0.5.0";
39
+ const version = "0.6.0";
19
40
  const description = "A functional language interpreter with text processing";
20
- const git_commit_hash = "68a2ab1ac86b865b1c2ea37aa43816ee34d29540";
41
+ const repository_url = "https://github.com/kekyo/funcity";
42
+ const git_commit_hash = "0ead9e15b1d6951acb7bf50d4850def586a23c47";
21
43
  const continuationPromptText = "? ";
44
+ let replReadlineInterface;
45
+ const createReplReadline = () => {
46
+ const fallbackReadline = node.nodeJsVariables.readline;
47
+ return async function(prompt) {
48
+ if (!replReadlineInterface) {
49
+ return await fallbackReadline.call(this, prompt);
50
+ }
51
+ const question = prompt === void 0 ? "" : this.convertToString(prompt);
52
+ const signal = this.abortSignal;
53
+ if (signal?.aborted) {
54
+ const abortError = new Error("Aborted");
55
+ abortError.name = "AbortError";
56
+ throw abortError;
57
+ }
58
+ return await new Promise((resolve, reject) => {
59
+ const rl = replReadlineInterface;
60
+ let settled = false;
61
+ const cleanup = () => {
62
+ if (signal) {
63
+ signal.removeEventListener("abort", onAbort);
64
+ }
65
+ };
66
+ const finishResolve = (value) => {
67
+ if (settled) {
68
+ return;
69
+ }
70
+ settled = true;
71
+ cleanup();
72
+ resolve(value);
73
+ };
74
+ const finishReject = (error) => {
75
+ if (settled) {
76
+ return;
77
+ }
78
+ settled = true;
79
+ cleanup();
80
+ reject(error);
81
+ };
82
+ const onAbort = () => {
83
+ const abortError = new Error("Aborted");
84
+ abortError.name = "AbortError";
85
+ finishReject(abortError);
86
+ };
87
+ if (signal) {
88
+ signal.addEventListener("abort", onAbort, { once: true });
89
+ rl.question(question, { signal }, (answer) => {
90
+ finishResolve(answer);
91
+ });
92
+ } else {
93
+ rl.question(question, (answer) => {
94
+ finishResolve(answer);
95
+ });
96
+ }
97
+ });
98
+ };
99
+ };
22
100
  const readStream = async (stream) => {
23
101
  return await new Promise((resolve, reject) => {
24
102
  let data = "";
@@ -36,10 +114,29 @@ const readStream = async (stream) => {
36
114
  });
37
115
  });
38
116
  };
39
- const reduceAndCollectResults = async (context, nodes) => {
117
+ const getErrorCode = (error) => {
118
+ if (!error || typeof error !== "object") {
119
+ return void 0;
120
+ }
121
+ return error.code;
122
+ };
123
+ const readRcScript = async () => {
124
+ const rcPath = path__namespace.join(os__namespace.homedir(), ".funcityrc");
125
+ try {
126
+ const script = await promises.readFile(rcPath, "utf8");
127
+ return { path: rcPath, script };
128
+ } catch (error) {
129
+ if (getErrorCode(error) !== "ENOENT") {
130
+ const message = error instanceof Error ? error.message : String(error);
131
+ console.warn(`warning: failed to read ${rcPath}: ${message}`);
132
+ }
133
+ return { path: rcPath };
134
+ }
135
+ };
136
+ const reduceAndCollectResults = async (context, nodes, signal) => {
40
137
  const resultList = [];
41
- for (const node of nodes) {
42
- const results = await funcity.reduceNode(context, node);
138
+ for (const node2 of nodes) {
139
+ const results = await funcity.reduceNode(context, node2, signal);
43
140
  for (const result of results) {
44
141
  if (result !== void 0) {
45
142
  resultList.push(result);
@@ -48,35 +145,90 @@ const reduceAndCollectResults = async (context, nodes) => {
48
145
  }
49
146
  return resultList;
50
147
  };
148
+ const runCodeWithContext = async (context, warningLogs, script, signal) => {
149
+ const logs = [];
150
+ const tokens = funcity.runCodeTokenizer(script, logs);
151
+ const nodes = funcity.parseExpressions(tokens, logs);
152
+ if (logs.length >= 1) {
153
+ return { output: void 0, logs };
154
+ }
155
+ try {
156
+ warningLogs.length = 0;
157
+ const results = await reduceAndCollectResults(context, nodes, signal);
158
+ const output = results.length > 0 ? results.map((result) => context.convertToString(result)).join("\n") : "";
159
+ return { output, logs: [...warningLogs] };
160
+ } catch (error) {
161
+ if (error instanceof funcity.FunCityReducerError) {
162
+ return { output: void 0, logs: [...warningLogs, error.info] };
163
+ }
164
+ throw error;
165
+ }
166
+ };
167
+ const runScriptWithContext = async (context, warningLogs, script, signal) => {
168
+ const logs = [];
169
+ const tokens = funcity.runTokenizer(script, logs);
170
+ const nodes = funcity.runParser(tokens, logs);
171
+ if (logs.length >= 1) {
172
+ return { output: void 0, logs };
173
+ }
174
+ try {
175
+ warningLogs.length = 0;
176
+ const results = await reduceAndCollectResults(context, nodes, signal);
177
+ const output = results.map((result) => context.convertToString(result)).join("");
178
+ return { output, logs: [...warningLogs] };
179
+ } catch (error) {
180
+ if (error instanceof funcity.FunCityReducerError) {
181
+ return { output: void 0, logs: [...warningLogs, error.info] };
182
+ }
183
+ throw error;
184
+ }
185
+ };
51
186
  const createReplSession = () => {
52
- const variables = funcity.buildCandidateVariables(funcity.nodeJsVariables, {
53
- prompt: "funcity> "
187
+ const exitSymbol = /* @__PURE__ */ Symbol("exit");
188
+ const replReadline = createReplReadline();
189
+ const require2 = node.createRequireFunction();
190
+ const variables = funcity.buildCandidateVariables(funcity.fetchVariables, node.nodeJsVariables, {
191
+ require: require2,
192
+ prompt: "funcity> ",
193
+ exit: exitSymbol,
194
+ readline: replReadline
54
195
  });
55
- const errors = [];
56
- const reducerContext = funcity.createReducerContext(variables);
57
- const evaluateLine = async (line) => {
58
- errors.length = 0;
59
- const tokens = funcity.runCodeTokenizer(line, errors);
60
- const nodes = funcity.parseExpressions(tokens, errors);
61
- if (errors.length >= 1) {
196
+ const warningLogs = [];
197
+ const reducerContext = funcity.createReducerContext(variables, warningLogs);
198
+ const evaluateLine = async (line, signal) => {
199
+ const logs = [];
200
+ const tokens = funcity.runCodeTokenizer(line, logs);
201
+ const nodes = funcity.parseExpressions(tokens, logs);
202
+ if (logs.length >= 1) {
62
203
  return {
63
204
  output: void 0,
64
- errors: [...errors]
205
+ logs,
206
+ shouldExit: false
65
207
  };
66
208
  }
67
209
  try {
68
- const results = await reduceAndCollectResults(reducerContext, nodes);
69
- const output = results.length > 0 ? results.map((result) => funcity.convertToString(result)).join("\n") : "";
210
+ warningLogs.length = 0;
211
+ const results = await reduceAndCollectResults(
212
+ reducerContext,
213
+ nodes,
214
+ signal
215
+ );
216
+ const shouldExit = results.some((result) => result === exitSymbol);
217
+ const outputResults = results.filter((result) => result !== exitSymbol);
218
+ const output = outputResults.length > 0 ? outputResults.map((result) => funcity.convertToString(result)).join("\n") : "";
70
219
  return {
71
220
  output,
72
- errors: [...errors]
221
+ logs: [...warningLogs],
222
+ shouldExit
73
223
  };
74
224
  } catch (error) {
75
225
  if (error instanceof funcity.FunCityReducerError) {
76
- errors.push(error.info);
226
+ const logs2 = [...warningLogs];
227
+ logs2.push(error.info);
77
228
  return {
78
229
  output: void 0,
79
- errors: [...errors]
230
+ logs: logs2,
231
+ shouldExit: false
80
232
  };
81
233
  }
82
234
  throw error;
@@ -90,38 +242,103 @@ const createReplSession = () => {
90
242
  });
91
243
  return reducerContext.convertToString(prompt);
92
244
  };
93
- return { evaluateLine, getPrompt };
245
+ const setVariable = (name2, value) => {
246
+ reducerContext.setValue(name2, value, void 0);
247
+ };
248
+ return { evaluateLine, getPrompt, setVariable };
249
+ };
250
+ const isAbortError = (error) => {
251
+ if (!error || typeof error !== "object") {
252
+ return false;
253
+ }
254
+ const errorRecord = error;
255
+ return errorRecord.name === "AbortError" || errorRecord.code === "ABORT_ERR";
94
256
  };
95
- const runRepl = async () => {
257
+ const loadRcForRepl = async (session) => {
258
+ const { path: rcPath, script } = await readRcScript();
259
+ if (!script) {
260
+ return;
261
+ }
262
+ session.setVariable("require", node.createRequireFunction(os__namespace.homedir()));
263
+ const { output, logs } = await session.evaluateLine(
264
+ script,
265
+ new AbortController().signal
266
+ );
267
+ if (logs.length > 0) {
268
+ funcity.outputErrors(rcPath, logs, console);
269
+ }
270
+ if (output) {
271
+ console.log(output);
272
+ }
273
+ };
274
+ const runRepl = async (loadRc) => {
275
+ console.log(
276
+ `${name} [${version}-${git_commit_hash}]`
277
+ );
278
+ console.log(`Copyright (c) kouji Matsui (@kekyo@mi.kekyo.net)`);
279
+ console.log(`${repository_url}`);
280
+ console.log(`Type 'exit' to exit CLI`);
281
+ console.log("");
96
282
  const session = createReplSession();
283
+ if (loadRc) {
284
+ await loadRcForRepl(session);
285
+ }
286
+ session.setVariable("require", node.createRequireFunction(process.cwd()));
97
287
  const rl = readline.createInterface({
98
288
  input: process.stdin,
99
289
  output: process.stdout,
100
290
  prompt: await session.getPrompt()
101
291
  });
292
+ replReadlineInterface = rl;
102
293
  let bufferedLine = "";
294
+ let isEvaluating = false;
295
+ let abortController = new AbortController();
103
296
  const setPrompt = async (isContinuation) => {
104
297
  rl.setPrompt(
105
298
  isContinuation ? continuationPromptText : await session.getPrompt()
106
299
  );
107
300
  };
108
301
  const hasLineContinuation = (line) => line.endsWith("\\");
109
- const evaluateAndPrint = async (line) => {
302
+ const evaluateAndPrint = async (line, signal) => {
110
303
  try {
111
- const { output, errors } = await session.evaluateLine(line);
112
- if (errors.length > 0) {
113
- funcity.outputErrors("<repl>", errors, console);
304
+ const { output, logs, shouldExit: shouldExit2 } = await session.evaluateLine(
305
+ line,
306
+ signal
307
+ );
308
+ if (logs.length > 0) {
309
+ funcity.outputErrors("<repl>", logs, console);
114
310
  }
115
311
  if (output) {
116
312
  console.log(output);
117
313
  }
314
+ return shouldExit2;
118
315
  } catch (error) {
316
+ if (isAbortError(error)) {
317
+ return false;
318
+ }
119
319
  const message = error instanceof Error ? error.message : String(error);
120
320
  console.error(message);
321
+ return false;
121
322
  }
122
323
  };
123
324
  await setPrompt(false);
124
325
  rl.prompt();
326
+ const handleInterrupt = async () => {
327
+ if (!abortController.signal.aborted) {
328
+ abortController.abort();
329
+ }
330
+ abortController = new AbortController();
331
+ bufferedLine = "";
332
+ process.stdout.write("\nInterrupted\n");
333
+ if (!isEvaluating) {
334
+ await setPrompt(false);
335
+ rl.prompt();
336
+ }
337
+ };
338
+ rl.on("SIGINT", () => {
339
+ void handleInterrupt();
340
+ });
341
+ let shouldExit = false;
125
342
  for await (const line of rl) {
126
343
  if (bufferedLine) {
127
344
  bufferedLine += `
@@ -136,27 +353,74 @@ ${line}`;
136
353
  }
137
354
  const logicalLine = bufferedLine;
138
355
  bufferedLine = "";
139
- await evaluateAndPrint(logicalLine);
356
+ isEvaluating = true;
357
+ try {
358
+ shouldExit = await evaluateAndPrint(logicalLine, abortController.signal);
359
+ } finally {
360
+ isEvaluating = false;
361
+ }
362
+ if (shouldExit) {
363
+ bufferedLine = "";
364
+ break;
365
+ }
140
366
  await setPrompt(false);
141
367
  rl.prompt();
142
368
  }
143
- if (bufferedLine) {
144
- await evaluateAndPrint(bufferedLine);
369
+ if (!shouldExit && bufferedLine) {
370
+ isEvaluating = true;
371
+ try {
372
+ await evaluateAndPrint(bufferedLine, abortController.signal);
373
+ } finally {
374
+ isEvaluating = false;
375
+ }
145
376
  }
146
377
  rl.close();
378
+ replReadlineInterface = void 0;
147
379
  };
148
- const runScriptToText = async (script) => {
149
- const variables = funcity.buildCandidateVariables(funcity.fetchVariables, funcity.nodeJsVariables);
150
- const errors = [];
151
- const output = await funcity.runScriptOnceToText(script, { variables, errors });
152
- return { output, errors };
380
+ const loadRcForContext = async (context, warningLogs) => {
381
+ const { path: rcPath, script } = await readRcScript();
382
+ if (!script) {
383
+ return;
384
+ }
385
+ context.setValue("require", node.createRequireFunction(os__namespace.homedir()), void 0);
386
+ const { output, logs } = await runCodeWithContext(
387
+ context,
388
+ warningLogs,
389
+ script,
390
+ new AbortController().signal
391
+ );
392
+ if (logs.length > 0) {
393
+ funcity.outputErrors(rcPath, logs, console);
394
+ }
395
+ if (output) {
396
+ console.log(output);
397
+ }
153
398
  };
154
- const runScript = async (input) => {
399
+ const runScript = async (input, loadRc) => {
155
400
  const isStdin = input === "-";
156
401
  const source = isStdin ? "<stdin>" : input;
157
402
  const script = isStdin ? await readStream(process.stdin) : await promises.readFile(input, "utf8");
158
- const { output, errors } = await runScriptToText(script);
159
- const hasError = funcity.outputErrors(source, errors, console);
403
+ const basePath = isStdin ? process.cwd() : path__namespace.dirname(path__namespace.resolve(input));
404
+ const variables = funcity.buildCandidateVariables(funcity.fetchVariables, node.nodeJsVariables, {
405
+ require: node.createRequireFunction(loadRc ? os__namespace.homedir() : basePath)
406
+ });
407
+ const warningLogs = [];
408
+ const reducerContext = funcity.createReducerContext(variables, warningLogs);
409
+ if (loadRc) {
410
+ await loadRcForContext(reducerContext, warningLogs);
411
+ }
412
+ reducerContext.setValue(
413
+ "require",
414
+ node.createRequireFunction(basePath),
415
+ void 0
416
+ );
417
+ const { output, logs } = await runScriptWithContext(
418
+ reducerContext,
419
+ warningLogs,
420
+ script,
421
+ new AbortController().signal
422
+ );
423
+ const hasError = funcity.outputErrors(source, logs, console);
160
424
  if (hasError) {
161
425
  process.exitCode = 1;
162
426
  }
@@ -229,16 +493,19 @@ ${description}
229
493
  `${version}-${git_commit_hash}`
230
494
  );
231
495
  program.showHelpAfterError(true);
232
- program.command("repl").summary("Start an interactive REPL session").action(async () => {
233
- await runRepl();
496
+ program.addOption(new commander.Option("--no-rc", "Do not load ~/.funcityrc"));
497
+ program.command("repl").summary("Start an interactive REPL session").action(async (_options, command) => {
498
+ const { rc } = command.parent?.opts() ?? { rc: true };
499
+ await runRepl(rc);
234
500
  });
235
501
  program.command("run").summary("Run a script from a file or stdin").addOption(
236
502
  new commander.Option(
237
503
  "-i, --input <path>",
238
504
  'Input file path or "-" for stdin'
239
505
  ).default("-")
240
- ).action(async (options) => {
241
- await runScript(options.input);
506
+ ).action(async (options, command) => {
507
+ const { rc } = command.parent?.opts() ?? { rc: true };
508
+ await runScript(options.input, rc);
242
509
  });
243
510
  await program.parseAsync(injectDefaultCommand(argv));
244
511
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/generated/packageMetadata.ts","../src/cli.ts","../src/index.ts"],"sourcesContent":["// @ts-nocheck\n// This file is auto-generated by screw-up plugin\n// Do not edit manually\n\nexport const name = \"funcity-cli\";\nexport const version = \"0.5.0\";\nexport const description = \"A functional language interpreter with text processing\";\nexport const author = \"Kouji Matsui (@kekyo@mi.kekyo.net)\";\nexport const license = \"MIT\";\nexport const repository_url = \"https://github.com/kekyo/funcity.git\";\nexport const git_commit_hash = \"68a2ab1ac86b865b1c2ea37aa43816ee34d29540\";\n","// funcity - A functional language interpreter with text processing\n// Copyright (c) Kouji Matsui (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/funcity/\n\nimport { readFile } from 'fs/promises';\nimport readline from 'readline';\nimport { Command, Option } from 'commander';\nimport * as packageMetadata from './generated/packageMetadata';\nimport {\n buildCandidateVariables,\n convertToString,\n createReducerContext,\n emptyRange,\n nodeJsVariables,\n fetchVariables,\n outputErrors,\n parseExpressions,\n reduceExpressionNode,\n reduceNode,\n runCodeTokenizer,\n runScriptOnceToText,\n} from 'funcity';\nimport {\n FunCityBlockNode,\n FunCityErrorInfo,\n FunCityReducerError,\n FunCityReducerContext,\n} from 'funcity';\n\nconst continuationPromptText = '? ';\n\nconst readStream = async (stream: NodeJS.ReadableStream): Promise<string> => {\n return await new Promise((resolve, reject) => {\n let data = '';\n if (typeof stream.setEncoding === 'function') {\n stream.setEncoding('utf8');\n }\n stream.on('data', (chunk) => {\n data += String(chunk);\n });\n stream.on('end', () => {\n resolve(data);\n });\n stream.on('error', (error) => {\n reject(error);\n });\n });\n};\n\nconst reduceAndCollectResults = async (\n context: FunCityReducerContext,\n nodes: readonly FunCityBlockNode[]\n): Promise<unknown[]> => {\n const resultList: unknown[] = [];\n for (const node of nodes) {\n const results = await reduceNode(context, node);\n for (const result of results) {\n if (result !== undefined) {\n resultList.push(result);\n }\n }\n }\n return resultList;\n};\n\nexport interface ReplEvaluationResult {\n readonly output: string | undefined;\n readonly errors: FunCityErrorInfo[];\n}\n\nexport interface ReplSession {\n getPrompt: () => Promise<string>;\n evaluateLine: (line: string) => Promise<ReplEvaluationResult>;\n}\n\nexport const createReplSession = (): ReplSession => {\n const variables = buildCandidateVariables(nodeJsVariables, {\n prompt: 'funcity> ',\n });\n\n const errors: FunCityErrorInfo[] = [];\n const reducerContext = createReducerContext(variables);\n\n const evaluateLine = async (line: string): Promise<ReplEvaluationResult> => {\n errors.length = 0;\n const tokens = runCodeTokenizer(line, errors);\n const nodes = parseExpressions(tokens, errors);\n if (errors.length >= 1) {\n return {\n output: undefined,\n errors: [...errors],\n };\n }\n try {\n const results = await reduceAndCollectResults(reducerContext, nodes);\n const output =\n results.length > 0\n ? results.map((result) => convertToString(result)).join('\\n')\n : '';\n return {\n output,\n errors: [...errors],\n };\n } catch (error: unknown) {\n if (error instanceof FunCityReducerError) {\n errors.push(error.info);\n return {\n output: undefined,\n errors: [...errors],\n };\n }\n throw error;\n }\n };\n const getPrompt = async () => {\n const prompt = await reduceExpressionNode(reducerContext, {\n kind: 'variable',\n name: 'prompt',\n range: emptyRange,\n });\n return reducerContext.convertToString(prompt);\n };\n\n return { evaluateLine, getPrompt };\n};\n\nconst runRepl = async (): Promise<void> => {\n const session = createReplSession();\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: await session.getPrompt(),\n });\n\n let bufferedLine = '';\n\n const setPrompt = async (isContinuation: boolean) => {\n rl.setPrompt(\n isContinuation ? continuationPromptText : await session.getPrompt()\n );\n };\n\n const hasLineContinuation = (line: string): boolean => line.endsWith('\\\\');\n\n const evaluateAndPrint = async (line: string) => {\n try {\n const { output, errors } = await session.evaluateLine(line);\n if (errors.length > 0) {\n outputErrors('<repl>', errors, console);\n }\n if (output) {\n console.log(output);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n }\n };\n\n await setPrompt(false);\n rl.prompt();\n\n for await (const line of rl) {\n if (bufferedLine) {\n bufferedLine += `\\n${line}`;\n } else {\n bufferedLine = line;\n }\n\n if (hasLineContinuation(line)) {\n await setPrompt(true);\n rl.prompt();\n continue;\n }\n\n const logicalLine = bufferedLine;\n bufferedLine = '';\n await evaluateAndPrint(logicalLine);\n await setPrompt(false);\n rl.prompt();\n }\n\n if (bufferedLine) {\n await evaluateAndPrint(bufferedLine);\n }\n\n rl.close();\n};\n\nexport const runScriptToText = async (script: string) => {\n const variables = buildCandidateVariables(fetchVariables, nodeJsVariables);\n const errors: FunCityErrorInfo[] = [];\n const output = await runScriptOnceToText(script, { variables, errors });\n return { output, errors };\n};\n\nconst runScript = async (input: string): Promise<void> => {\n const isStdin = input === '-';\n const source = isStdin ? '<stdin>' : input;\n const script = isStdin\n ? await readStream(process.stdin)\n : await readFile(input, 'utf8');\n\n const { output, errors } = await runScriptToText(script);\n\n const hasError = outputErrors(source, errors, console);\n if (hasError) {\n process.exitCode = 1;\n }\n\n if (output) {\n process.stdout.write(output);\n }\n};\n\nconst findExplicitCommand = (\n args: readonly string[]\n): 'repl' | 'run' | undefined => {\n for (let index = 0; index < args.length; index++) {\n const arg = args[index]!;\n if (arg === '--') {\n const next = args[index + 1];\n if (next === 'repl' || next === 'run') {\n return next;\n }\n return undefined;\n }\n if (arg === '-i' || arg === '--input') {\n index += 1;\n continue;\n }\n if (arg.startsWith('--input=')) {\n continue;\n }\n if (arg.startsWith('-')) {\n continue;\n }\n return arg === 'repl' || arg === 'run' ? arg : undefined;\n }\n return undefined;\n};\n\nconst hasInputOption = (args: readonly string[]): boolean => {\n for (const arg of args) {\n if (arg === '--') {\n break;\n }\n if (arg === '-i' || arg === '--input' || arg.startsWith('--input=')) {\n return true;\n }\n }\n return false;\n};\n\nconst injectDefaultCommand = (argv: string[]): string[] => {\n const args = argv.slice(2);\n const explicitCommand = findExplicitCommand(args);\n if (explicitCommand) {\n return argv;\n }\n\n const hasHelp = args.some(\n (arg) =>\n arg === '-h' || arg === '--help' || arg === '-V' || arg === '--version'\n );\n if (hasHelp) {\n return argv;\n }\n\n const command = hasInputOption(args) ? 'run' : 'repl';\n const [execPath = 'node', scriptPath = 'funcity'] = argv;\n return [execPath, scriptPath, command, ...args];\n};\n\nexport const runMain = async (argv: string[] = process.argv): Promise<void> => {\n const program = new Command();\n\n program.name(packageMetadata.name);\n program.summary(packageMetadata.description);\n program.addHelpText(\n 'beforeAll',\n `${packageMetadata.name}\\n${packageMetadata.description}\\n`\n );\n program.version(\n `${packageMetadata.version}-${packageMetadata.git_commit_hash}`\n );\n program.showHelpAfterError(true);\n\n program\n .command('repl')\n .summary('Start an interactive REPL session')\n .action(async () => {\n await runRepl();\n });\n\n program\n .command('run')\n .summary('Run a script from a file or stdin')\n .addOption(\n new Option(\n '-i, --input <path>',\n 'Input file path or \"-\" for stdin'\n ).default('-')\n )\n .action(async (options: { input: string }) => {\n await runScript(options.input);\n });\n\n await program.parseAsync(injectDefaultCommand(argv));\n};\n","// funcity - A functional language interpreter with text processing\n// Copyright (c) Kouji Matsui (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/funcity/\n\nimport { runMain } from './cli';\n\nrunMain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n process.exitCode = 1;\n});\n"],"names":["reduceNode","buildCandidateVariables","nodeJsVariables","createReducerContext","runCodeTokenizer","parseExpressions","convertToString","FunCityReducerError","reduceExpressionNode","emptyRange","outputErrors","fetchVariables","runScriptOnceToText","readFile","Command","packageMetadata.name","packageMetadata.description","packageMetadata.version","packageMetadata.git_commit_hash","Option"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/generated/packageMetadata.ts","../src/cli.ts","../src/index.ts"],"sourcesContent":["// @ts-nocheck\n// This file is auto-generated by screw-up plugin\n// Do not edit manually\n\nexport const name = \"funcity-cli\";\nexport const version = \"0.6.0\";\nexport const description = \"A functional language interpreter with text processing\";\nexport const author = \"Kouji Matsui (@kekyo@mi.kekyo.net)\";\nexport const license = \"MIT\";\nexport const repository_url = \"https://github.com/kekyo/funcity\";\nexport const git_commit_hash = \"0ead9e15b1d6951acb7bf50d4850def586a23c47\";\n","// funcity - A functional language interpreter with text processing\n// Copyright (c) Kouji Matsui (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/funcity/\n\nimport { readFile } from 'fs/promises';\nimport * as os from 'os';\nimport * as path from 'path';\nimport readline from 'readline';\nimport { Command, Option } from 'commander';\n\nimport * as packageMetadata from './generated/packageMetadata';\nimport {\n FunCityBlockNode,\n FunCityFunctionContext,\n FunCityLogEntry,\n FunCityReducerError,\n FunCityReducerContext,\n FunCityWarningEntry,\n} from 'funcity';\nimport {\n buildCandidateVariables,\n convertToString,\n createReducerContext,\n emptyRange,\n fetchVariables,\n outputErrors,\n parseExpressions,\n reduceExpressionNode,\n reduceNode,\n runParser,\n runCodeTokenizer,\n runTokenizer,\n runScriptOnceToText,\n} from 'funcity';\nimport { createRequireFunction, nodeJsVariables } from 'funcity/node';\n\n//////////////////////////////////////////////////////////////////////////////\n\nconst continuationPromptText = '? ';\n\nlet replReadlineInterface: readline.Interface | undefined;\n\nconst createReplReadline = () => {\n const fallbackReadline = nodeJsVariables.readline as (\n this: FunCityFunctionContext,\n prompt?: unknown\n ) => Promise<string>;\n\n return async function (this: FunCityFunctionContext, prompt?: unknown) {\n if (!replReadlineInterface) {\n return await fallbackReadline.call(this, prompt);\n }\n\n const question = prompt === undefined ? '' : this.convertToString(prompt);\n const signal = this.abortSignal;\n\n if (signal?.aborted) {\n const abortError = new Error('Aborted');\n (abortError as { name?: string }).name = 'AbortError';\n throw abortError;\n }\n\n return await new Promise<string>((resolve, reject) => {\n const rl = replReadlineInterface!;\n let settled = false;\n\n const cleanup = () => {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n };\n\n const finishResolve = (value: string) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n resolve(value);\n };\n\n const finishReject = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n reject(error);\n };\n\n const onAbort = () => {\n const abortError = new Error('Aborted');\n (abortError as { name?: string }).name = 'AbortError';\n finishReject(abortError);\n };\n\n if (signal) {\n signal.addEventListener('abort', onAbort, { once: true });\n rl.question(question, { signal }, (answer) => {\n finishResolve(answer);\n });\n } else {\n rl.question(question, (answer) => {\n finishResolve(answer);\n });\n }\n });\n };\n};\n\nconst readStream = async (stream: NodeJS.ReadableStream): Promise<string> => {\n return await new Promise((resolve, reject) => {\n let data = '';\n if (typeof stream.setEncoding === 'function') {\n stream.setEncoding('utf8');\n }\n stream.on('data', (chunk) => {\n data += String(chunk);\n });\n stream.on('end', () => {\n resolve(data);\n });\n stream.on('error', (error) => {\n reject(error);\n });\n });\n};\n\nconst getErrorCode = (error: unknown): string | undefined => {\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n return (error as { code?: string }).code;\n};\n\nconst readRcScript = async (): Promise<{\n path: string;\n script?: string;\n}> => {\n const rcPath = path.join(os.homedir(), '.funcityrc');\n try {\n const script = await readFile(rcPath, 'utf8');\n return { path: rcPath, script };\n } catch (error) {\n if (getErrorCode(error) !== 'ENOENT') {\n const message = error instanceof Error ? error.message : String(error);\n console.warn(`warning: failed to read ${rcPath}: ${message}`);\n }\n return { path: rcPath };\n }\n};\n\nconst reduceAndCollectResults = async (\n context: FunCityReducerContext,\n nodes: readonly FunCityBlockNode[],\n signal: AbortSignal\n): Promise<unknown[]> => {\n const resultList: unknown[] = [];\n for (const node of nodes) {\n const results = await reduceNode(context, node, signal);\n for (const result of results) {\n if (result !== undefined) {\n resultList.push(result);\n }\n }\n }\n return resultList;\n};\n\nconst runCodeWithContext = async (\n context: FunCityReducerContext,\n warningLogs: FunCityWarningEntry[],\n script: string,\n signal: AbortSignal\n): Promise<{ output: string | undefined; logs: FunCityLogEntry[] }> => {\n const logs: FunCityLogEntry[] = [];\n const tokens = runCodeTokenizer(script, logs);\n const nodes = parseExpressions(tokens, logs);\n if (logs.length >= 1) {\n return { output: undefined, logs };\n }\n\n try {\n warningLogs.length = 0;\n const results = await reduceAndCollectResults(context, nodes, signal);\n const output =\n results.length > 0\n ? results.map((result) => context.convertToString(result)).join('\\n')\n : '';\n return { output, logs: [...warningLogs] };\n } catch (error: unknown) {\n if (error instanceof FunCityReducerError) {\n return { output: undefined, logs: [...warningLogs, error.info] };\n }\n throw error;\n }\n};\n\nconst runScriptWithContext = async (\n context: FunCityReducerContext,\n warningLogs: FunCityWarningEntry[],\n script: string,\n signal: AbortSignal\n): Promise<{ output: string | undefined; logs: FunCityLogEntry[] }> => {\n const logs: FunCityLogEntry[] = [];\n const tokens = runTokenizer(script, logs);\n const nodes = runParser(tokens, logs);\n if (logs.length >= 1) {\n return { output: undefined, logs };\n }\n\n try {\n warningLogs.length = 0;\n const results = await reduceAndCollectResults(context, nodes, signal);\n const output = results\n .map((result) => context.convertToString(result))\n .join('');\n return { output, logs: [...warningLogs] };\n } catch (error: unknown) {\n if (error instanceof FunCityReducerError) {\n return { output: undefined, logs: [...warningLogs, error.info] };\n }\n throw error;\n }\n};\n\n//////////////////////////////////////////////////////////////////////////////\n\nexport interface ReplEvaluationResult {\n readonly output: string | undefined;\n readonly logs: FunCityLogEntry[];\n readonly shouldExit: boolean;\n}\n\nexport interface ReplSession {\n evaluateLine: (\n line: string,\n signal: AbortSignal\n ) => Promise<ReplEvaluationResult>;\n getPrompt: () => Promise<string>;\n setVariable: (name: string, value: unknown) => void;\n}\n\nexport const createReplSession = (): ReplSession => {\n const exitSymbol = Symbol('exit');\n const replReadline = createReplReadline();\n const require = createRequireFunction();\n const variables = buildCandidateVariables(fetchVariables, nodeJsVariables, {\n require,\n prompt: 'funcity> ',\n exit: exitSymbol,\n readline: replReadline,\n });\n\n const warningLogs: FunCityWarningEntry[] = [];\n const reducerContext = createReducerContext(variables, warningLogs);\n\n const evaluateLine = async (\n line: string,\n signal: AbortSignal\n ): Promise<ReplEvaluationResult> => {\n // Tokenize and parse step\n const logs: FunCityLogEntry[] = [];\n const tokens = runCodeTokenizer(line, logs);\n const nodes = parseExpressions(tokens, logs);\n if (logs.length >= 1) {\n return {\n output: undefined,\n logs,\n shouldExit: false,\n };\n }\n\n // Reduce step\n try {\n warningLogs.length = 0;\n const results = await reduceAndCollectResults(\n reducerContext,\n nodes,\n signal\n );\n const shouldExit = results.some((result) => result === exitSymbol);\n const outputResults = results.filter((result) => result !== exitSymbol);\n const output =\n outputResults.length > 0\n ? outputResults.map((result) => convertToString(result)).join('\\n')\n : '';\n return {\n output,\n logs: [...warningLogs],\n shouldExit,\n };\n } catch (error: unknown) {\n if (error instanceof FunCityReducerError) {\n const logs: FunCityLogEntry[] = [...warningLogs];\n logs.push(error.info);\n return {\n output: undefined,\n logs,\n shouldExit: false,\n };\n }\n throw error;\n }\n };\n\n const getPrompt = async () => {\n const prompt = await reduceExpressionNode(reducerContext, {\n kind: 'variable',\n name: 'prompt',\n range: emptyRange,\n });\n return reducerContext.convertToString(prompt);\n };\n\n const setVariable = (name: string, value: unknown) => {\n reducerContext.setValue(name, value, undefined);\n };\n\n return { evaluateLine, getPrompt, setVariable };\n};\n\nconst isAbortError = (error: unknown): boolean => {\n if (!error || typeof error !== 'object') {\n return false;\n }\n const errorRecord = error as { name?: string; code?: string };\n return errorRecord.name === 'AbortError' || errorRecord.code === 'ABORT_ERR';\n};\n\nconst loadRcForRepl = async (session: ReplSession): Promise<void> => {\n const { path: rcPath, script } = await readRcScript();\n if (!script) {\n return;\n }\n\n session.setVariable('require', createRequireFunction(os.homedir()));\n const { output, logs } = await session.evaluateLine(\n script,\n new AbortController().signal\n );\n if (logs.length > 0) {\n outputErrors(rcPath, logs, console);\n }\n if (output) {\n console.log(output);\n }\n};\n\nconst runRepl = async (loadRc: boolean): Promise<void> => {\n console.log(\n `${packageMetadata.name} [${packageMetadata.version}-${packageMetadata.git_commit_hash}]`\n );\n console.log(`Copyright (c) kouji Matsui (@kekyo@mi.kekyo.net)`);\n console.log(`${packageMetadata.repository_url}`);\n console.log(`Type 'exit' to exit CLI`);\n console.log('');\n\n const session = createReplSession();\n if (loadRc) {\n await loadRcForRepl(session);\n }\n session.setVariable('require', createRequireFunction(process.cwd()));\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: await session.getPrompt(),\n });\n replReadlineInterface = rl;\n\n let bufferedLine = '';\n let isEvaluating = false;\n let abortController = new AbortController();\n\n const setPrompt = async (isContinuation: boolean) => {\n rl.setPrompt(\n isContinuation ? continuationPromptText : await session.getPrompt()\n );\n };\n\n const hasLineContinuation = (line: string): boolean => line.endsWith('\\\\');\n\n const evaluateAndPrint = async (line: string, signal: AbortSignal) => {\n try {\n const { output, logs, shouldExit } = await session.evaluateLine(\n line,\n signal\n );\n if (logs.length > 0) {\n outputErrors('<repl>', logs, console);\n }\n if (output) {\n console.log(output);\n }\n return shouldExit;\n } catch (error) {\n if (isAbortError(error)) {\n return false;\n }\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n return false;\n }\n };\n\n await setPrompt(false);\n rl.prompt();\n\n const handleInterrupt = async () => {\n if (!abortController.signal.aborted) {\n abortController.abort();\n }\n abortController = new AbortController();\n bufferedLine = '';\n process.stdout.write('\\nInterrupted\\n');\n if (!isEvaluating) {\n await setPrompt(false);\n rl.prompt();\n }\n };\n\n rl.on('SIGINT', () => {\n void handleInterrupt();\n });\n\n let shouldExit = false;\n\n for await (const line of rl) {\n if (bufferedLine) {\n bufferedLine += `\\n${line}`;\n } else {\n bufferedLine = line;\n }\n\n if (hasLineContinuation(line)) {\n await setPrompt(true);\n rl.prompt();\n continue;\n }\n\n const logicalLine = bufferedLine;\n bufferedLine = '';\n isEvaluating = true;\n try {\n shouldExit = await evaluateAndPrint(logicalLine, abortController.signal);\n } finally {\n isEvaluating = false;\n }\n if (shouldExit) {\n bufferedLine = '';\n break;\n }\n await setPrompt(false);\n rl.prompt();\n }\n\n if (!shouldExit && bufferedLine) {\n isEvaluating = true;\n try {\n await evaluateAndPrint(bufferedLine, abortController.signal);\n } finally {\n isEvaluating = false;\n }\n }\n\n rl.close();\n replReadlineInterface = undefined;\n};\n\n//////////////////////////////////////////////////////////////////////////////\n\nexport const runScriptToText = async (script: string, basePath?: string) => {\n const require = createRequireFunction(basePath);\n const variables = buildCandidateVariables(fetchVariables, nodeJsVariables, {\n require,\n });\n const logs: FunCityLogEntry[] = [];\n const output = await runScriptOnceToText(script, { variables, logs });\n return { output, logs };\n};\n\nconst loadRcForContext = async (\n context: FunCityReducerContext,\n warningLogs: FunCityWarningEntry[]\n): Promise<void> => {\n const { path: rcPath, script } = await readRcScript();\n if (!script) {\n return;\n }\n\n context.setValue('require', createRequireFunction(os.homedir()), undefined);\n const { output, logs } = await runCodeWithContext(\n context,\n warningLogs,\n script,\n new AbortController().signal\n );\n if (logs.length > 0) {\n outputErrors(rcPath, logs, console);\n }\n if (output) {\n console.log(output);\n }\n};\n\nconst runScript = async (input: string, loadRc: boolean): Promise<void> => {\n const isStdin = input === '-';\n const source = isStdin ? '<stdin>' : input;\n const script = isStdin\n ? await readStream(process.stdin)\n : await readFile(input, 'utf8');\n\n const basePath = isStdin ? process.cwd() : path.dirname(path.resolve(input));\n const variables = buildCandidateVariables(fetchVariables, nodeJsVariables, {\n require: createRequireFunction(loadRc ? os.homedir() : basePath),\n });\n const warningLogs: FunCityWarningEntry[] = [];\n const reducerContext = createReducerContext(variables, warningLogs);\n\n if (loadRc) {\n await loadRcForContext(reducerContext, warningLogs);\n }\n reducerContext.setValue(\n 'require',\n createRequireFunction(basePath),\n undefined\n );\n const { output, logs } = await runScriptWithContext(\n reducerContext,\n warningLogs,\n script,\n new AbortController().signal\n );\n\n const hasError = outputErrors(source, logs, console);\n if (hasError) {\n process.exitCode = 1;\n }\n\n if (output) {\n process.stdout.write(output);\n }\n};\n\n//////////////////////////////////////////////////////////////////////////////\n\nconst findExplicitCommand = (\n args: readonly string[]\n): 'repl' | 'run' | undefined => {\n for (let index = 0; index < args.length; index++) {\n const arg = args[index]!;\n if (arg === '--') {\n const next = args[index + 1];\n if (next === 'repl' || next === 'run') {\n return next;\n }\n return undefined;\n }\n if (arg === '-i' || arg === '--input') {\n index += 1;\n continue;\n }\n if (arg.startsWith('--input=')) {\n continue;\n }\n if (arg.startsWith('-')) {\n continue;\n }\n return arg === 'repl' || arg === 'run' ? arg : undefined;\n }\n return undefined;\n};\n\nconst hasInputOption = (args: readonly string[]): boolean => {\n for (const arg of args) {\n if (arg === '--') {\n break;\n }\n if (arg === '-i' || arg === '--input' || arg.startsWith('--input=')) {\n return true;\n }\n }\n return false;\n};\n\nconst injectDefaultCommand = (argv: string[]): string[] => {\n const args = argv.slice(2);\n const explicitCommand = findExplicitCommand(args);\n if (explicitCommand) {\n return argv;\n }\n\n const hasHelp = args.some(\n (arg) =>\n arg === '-h' || arg === '--help' || arg === '-V' || arg === '--version'\n );\n if (hasHelp) {\n return argv;\n }\n\n const command = hasInputOption(args) ? 'run' : 'repl';\n const [execPath = 'node', scriptPath = 'funcity'] = argv;\n return [execPath, scriptPath, command, ...args];\n};\n\nexport const runMain = async (argv: string[] = process.argv): Promise<void> => {\n const program = new Command();\n\n program.name(packageMetadata.name);\n program.summary(packageMetadata.description);\n program.addHelpText(\n 'beforeAll',\n `${packageMetadata.name}\\n${packageMetadata.description}\\n`\n );\n program.version(\n `${packageMetadata.version}-${packageMetadata.git_commit_hash}`\n );\n program.showHelpAfterError(true);\n program.addOption(new Option('--no-rc', 'Do not load ~/.funcityrc'));\n\n program\n .command('repl')\n .summary('Start an interactive REPL session')\n .action(async (_options, command) => {\n const { rc } = command.parent?.opts() ?? { rc: true };\n await runRepl(rc);\n });\n\n program\n .command('run')\n .summary('Run a script from a file or stdin')\n .addOption(\n new Option(\n '-i, --input <path>',\n 'Input file path or \"-\" for stdin'\n ).default('-')\n )\n .action(async (options: { input: string }, command) => {\n const { rc } = command.parent?.opts() ?? { rc: true };\n await runScript(options.input, rc);\n });\n\n await program.parseAsync(injectDefaultCommand(argv));\n};\n","// funcity - A functional language interpreter with text processing\n// Copyright (c) Kouji Matsui (@kekyo@mi.kekyo.net)\n// Under MIT.\n// https://github.com/kekyo/funcity/\n\nimport { runMain } from './cli';\n\nrunMain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(message);\n process.exitCode = 1;\n});\n"],"names":["nodeJsVariables","path","os","readFile","node","reduceNode","runCodeTokenizer","parseExpressions","FunCityReducerError","runTokenizer","runParser","require","createRequireFunction","buildCandidateVariables","fetchVariables","createReducerContext","convertToString","logs","reduceExpressionNode","emptyRange","name","outputErrors","packageMetadata.name","packageMetadata.version","packageMetadata.git_commit_hash","packageMetadata.repository_url","shouldExit","Command","packageMetadata.description","Option"],"mappings":"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"}
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
1
  {
2
2
  "git": {
3
3
  "tags": [
4
- "0.5.0"
4
+ "0.6.0"
5
5
  ],
6
6
  "branches": [
7
7
  "main"
8
8
  ],
9
- "version": "0.5.0",
9
+ "version": "0.6.0",
10
10
  "commit": {
11
- "hash": "68a2ab1ac86b865b1c2ea37aa43816ee34d29540",
12
- "shortHash": "68a2ab1",
13
- "date": "2026-01-13T22:04:47+09:00",
11
+ "hash": "0ead9e15b1d6951acb7bf50d4850def586a23c47",
12
+ "shortHash": "0ead9e1",
13
+ "date": "2026-01-14T20:03:18+09:00",
14
14
  "message": "Merge branch 'develop'"
15
15
  }
16
16
  },
17
- "version": "0.5.0",
17
+ "version": "0.6.0",
18
18
  "author": "Kouji Matsui (@kekyo@mi.kekyo.net)",
19
19
  "license": "MIT",
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/kekyo/funcity.git"
22
+ "url": "https://github.com/kekyo/funcity"
23
23
  },
24
24
  "homepage": "https://github.com/kekyo/funcity#readme",
25
25
  "files": [
@@ -69,5 +69,5 @@
69
69
  "vite-plugin-dts": ">=3.0.0",
70
70
  "vitest": ">=1.0.0"
71
71
  },
72
- "buildDate": "2026-01-13T22:05:43+09:00"
72
+ "buildDate": "2026-01-14T20:07:34+09:00"
73
73
  }