@thigasdevelopment/luam 0.4.0 → 0.4.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/luam.mjs +158 -35
- package/package.json +1 -1
package/luam.mjs
CHANGED
|
@@ -190,7 +190,7 @@ function parseArguments(argv) {
|
|
|
190
190
|
continue;
|
|
191
191
|
}
|
|
192
192
|
if (parsed.command !== null) {
|
|
193
|
-
if (parsed.command === "trace" && parsed.operand === null) {
|
|
193
|
+
if ((parsed.command === "init" || parsed.command === "trace") && parsed.operand === null) {
|
|
194
194
|
parsed.operand = token;
|
|
195
195
|
continue;
|
|
196
196
|
}
|
|
@@ -212,12 +212,13 @@ var EXIT_DIAGNOSTICS = 1;
|
|
|
212
212
|
var EXIT_USAGE = 2;
|
|
213
213
|
|
|
214
214
|
// src/cli/usage.ts
|
|
215
|
-
var VERSION = true ? "0.4.
|
|
215
|
+
var VERSION = true ? "0.4.1" : "0.0.0-dev";
|
|
216
216
|
var USAGE = [
|
|
217
217
|
"luam \u2014 the Luam compiler for Multi Theft Auto resources.",
|
|
218
218
|
"",
|
|
219
219
|
"Usage:",
|
|
220
220
|
" luam <command> [options]",
|
|
221
|
+
" luam init [path] [options]",
|
|
221
222
|
"",
|
|
222
223
|
"Commands:",
|
|
223
224
|
" build Compile the project and write the resource to the output directory.",
|
|
@@ -225,16 +226,16 @@ var USAGE = [
|
|
|
225
226
|
" dev Build, sync, restart, watch, and stream resource development logs.",
|
|
226
227
|
" doctor Check the CLI, supported editors, and the Luam extension.",
|
|
227
228
|
" ensure Build, sync the resource into the MTA server, and restart it.",
|
|
228
|
-
" init
|
|
229
|
+
" init Interactively scaffold a new resource project.",
|
|
229
230
|
" setup Detect supported editors and install the Luam extension with consent.",
|
|
230
231
|
" trace Resolve generated Lua positions back to Luam source positions.",
|
|
231
232
|
"",
|
|
232
233
|
"Options:",
|
|
233
234
|
" --cwd <path> Project directory that contains luam.json. Defaults to the current directory.",
|
|
234
235
|
" --config <path> Configuration file to load instead of luam.json.",
|
|
235
|
-
" --name <name> Resource name for init. Defaults to the
|
|
236
|
+
" --name <name> Resource name for init. Defaults to the destination directory name.",
|
|
236
237
|
" --force Let init overwrite files that already exist.",
|
|
237
|
-
" -y, --yes
|
|
238
|
+
" -y, --yes Accept init defaults or install every detected editor without prompting.",
|
|
238
239
|
" --watch Keep ensure or dev running and rebuild on source changes.",
|
|
239
240
|
" --no-watch Run ensure or dev once and exit.",
|
|
240
241
|
" --bundle Build or ensure with bundled output.",
|
|
@@ -1164,8 +1165,8 @@ var Binder = class {
|
|
|
1164
1165
|
isDeclaredInCurrentScope(name) {
|
|
1165
1166
|
return this.scopes[this.scopes.length - 1]?.has(name) ?? false;
|
|
1166
1167
|
}
|
|
1167
|
-
declareAlias(name, type) {
|
|
1168
|
-
this.aliases.set(name, type);
|
|
1168
|
+
declareAlias(name, type, parameters = []) {
|
|
1169
|
+
this.aliases.set(name, { type, parameters });
|
|
1169
1170
|
}
|
|
1170
1171
|
lookupAlias(name) {
|
|
1171
1172
|
return this.aliases.get(name) ?? null;
|
|
@@ -5005,6 +5006,35 @@ function mtaMember(className, member) {
|
|
|
5005
5006
|
return mtaClassRegistry().lookupMember(className, member);
|
|
5006
5007
|
}
|
|
5007
5008
|
|
|
5009
|
+
// ../compiler/src/checker/type-substitution.ts
|
|
5010
|
+
function substituteType(type, substitutions) {
|
|
5011
|
+
if (type.kind === "named") {
|
|
5012
|
+
return substitutions.get(type.name) ?? type;
|
|
5013
|
+
}
|
|
5014
|
+
if (type.kind === "array") {
|
|
5015
|
+
return createArray(substituteType(type.element, substitutions));
|
|
5016
|
+
}
|
|
5017
|
+
if (type.kind === "optional") {
|
|
5018
|
+
return createOptional(substituteType(type.element, substitutions));
|
|
5019
|
+
}
|
|
5020
|
+
if (type.kind === "union") {
|
|
5021
|
+
return createUnion(type.options.map((option) => substituteType(option, substitutions)));
|
|
5022
|
+
}
|
|
5023
|
+
if (type.kind === "function") {
|
|
5024
|
+
const parameters = type.parameters.map((parameter) => substituteType(parameter, substitutions));
|
|
5025
|
+
const returnType = substituteType(type.returnType, substitutions);
|
|
5026
|
+
return createFunction(parameters, returnType, type.minimumArguments, type.isVariadic);
|
|
5027
|
+
}
|
|
5028
|
+
if (type.kind === "tuple") {
|
|
5029
|
+
return createTuple(type.elements.map((element) => substituteType(element, substitutions)));
|
|
5030
|
+
}
|
|
5031
|
+
if (type.kind === "record") {
|
|
5032
|
+
const members = new Map([...type.members].map(([name, member]) => [name, substituteType(member, substitutions)]));
|
|
5033
|
+
return createRecord(type.name, members, type.origin);
|
|
5034
|
+
}
|
|
5035
|
+
return type;
|
|
5036
|
+
}
|
|
5037
|
+
|
|
5008
5038
|
// ../compiler/src/checker/context.ts
|
|
5009
5039
|
var BUILTIN_TYPES = {
|
|
5010
5040
|
any: ANY_TYPE,
|
|
@@ -5086,13 +5116,32 @@ var CheckContext = class {
|
|
|
5086
5116
|
return this.types.get(expression) ?? UNKNOWN_TYPE;
|
|
5087
5117
|
}
|
|
5088
5118
|
pushReturnType(type) {
|
|
5089
|
-
this.returnStack.push(type);
|
|
5119
|
+
this.returnStack.push({ expected: type, inferred: [] });
|
|
5090
5120
|
}
|
|
5091
5121
|
popReturnType() {
|
|
5092
|
-
this.returnStack.pop();
|
|
5122
|
+
const frame = this.returnStack.pop();
|
|
5123
|
+
if (frame === void 0 || frame.inferred.length === 0) {
|
|
5124
|
+
return VOID_TYPE;
|
|
5125
|
+
}
|
|
5126
|
+
const tuples = frame.inferred.filter((type) => type.kind === "tuple");
|
|
5127
|
+
const tupleSize = tuples[0]?.kind === "tuple" ? tuples[0].elements.length : null;
|
|
5128
|
+
const sameTupleSize = tuples.length === frame.inferred.length && tuples.every((type) => type.kind === "tuple" && type.elements.length === tupleSize);
|
|
5129
|
+
if (sameTupleSize) {
|
|
5130
|
+
const first = tuples[0];
|
|
5131
|
+
if (first?.kind === "tuple") {
|
|
5132
|
+
const elements = first.elements.map(
|
|
5133
|
+
(_, index) => createUnion(tuples.map((type) => type.kind === "tuple" ? type.elements[index] ?? ANY_TYPE : ANY_TYPE))
|
|
5134
|
+
);
|
|
5135
|
+
return createTuple(elements);
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
return createUnion(frame.inferred);
|
|
5093
5139
|
}
|
|
5094
5140
|
currentReturnType() {
|
|
5095
|
-
return this.returnStack[this.returnStack.length - 1] ?? null;
|
|
5141
|
+
return this.returnStack[this.returnStack.length - 1]?.expected ?? null;
|
|
5142
|
+
}
|
|
5143
|
+
inferReturnType(type) {
|
|
5144
|
+
this.returnStack[this.returnStack.length - 1]?.inferred.push(type);
|
|
5096
5145
|
}
|
|
5097
5146
|
pushClassMethod(frame) {
|
|
5098
5147
|
this.methodStack.push(frame);
|
|
@@ -5132,7 +5181,7 @@ var CheckContext = class {
|
|
|
5132
5181
|
const minimum = optional === -1 ? parameters.length : optional;
|
|
5133
5182
|
return createFunction(parameters, this.resolveAnnotation(annotation.returnType), minimum, annotation.isVariadic);
|
|
5134
5183
|
}
|
|
5135
|
-
return this.resolveNamedAnnotation(annotation.name);
|
|
5184
|
+
return this.resolveNamedAnnotation(annotation.name, annotation.typeArguments, annotation.position);
|
|
5136
5185
|
}
|
|
5137
5186
|
expectAssignable(source, target, position2, subject) {
|
|
5138
5187
|
if (isAssignable(source, target, { allowNil: this.allowNil })) {
|
|
@@ -5168,12 +5217,25 @@ var CheckContext = class {
|
|
|
5168
5217
|
this.binder.declareGlobal({ name: info.name, type: info.type, isLocal: false, position: info.position });
|
|
5169
5218
|
}
|
|
5170
5219
|
}
|
|
5171
|
-
resolveNamedAnnotation(name) {
|
|
5220
|
+
resolveNamedAnnotation(name, typeArguments, position2) {
|
|
5172
5221
|
const builtin = BUILTIN_TYPES[name];
|
|
5173
5222
|
if (builtin !== void 0) {
|
|
5223
|
+
if (typeArguments.length > 0) {
|
|
5224
|
+
this.report("check-generic-arity", `Type "${name}" does not accept type arguments.`, position2);
|
|
5225
|
+
}
|
|
5174
5226
|
return builtin;
|
|
5175
5227
|
}
|
|
5176
|
-
|
|
5228
|
+
const alias = this.binder.lookupAlias(name);
|
|
5229
|
+
if (alias === null) {
|
|
5230
|
+
return createNamed(name);
|
|
5231
|
+
}
|
|
5232
|
+
if (typeArguments.length !== alias.parameters.length) {
|
|
5233
|
+
const expected = alias.parameters.length === 1 ? "1 type argument" : `${alias.parameters.length} type arguments`;
|
|
5234
|
+
this.report("check-generic-arity", `Type "${name}" expects ${expected} but received ${typeArguments.length}.`, position2);
|
|
5235
|
+
}
|
|
5236
|
+
const resolved = typeArguments.map((argument) => this.resolveAnnotation(argument));
|
|
5237
|
+
const substitutions = new Map(alias.parameters.map((parameter, index) => [parameter, resolved[index] ?? ANY_TYPE]));
|
|
5238
|
+
return substituteType(alias.type, substitutions);
|
|
5177
5239
|
}
|
|
5178
5240
|
};
|
|
5179
5241
|
|
|
@@ -6347,7 +6409,7 @@ function checkMultiValueExpression(context, expression) {
|
|
|
6347
6409
|
return checkTable(context, expression);
|
|
6348
6410
|
case "function-expression": {
|
|
6349
6411
|
const type = buildFunctionType(context, expression.parameters, expression.returnAnnotation);
|
|
6350
|
-
checkFunctionBody(context, expression.parameters, expression.returnAnnotation, expression.body, null);
|
|
6412
|
+
checkFunctionBody(context, expression.parameters, expression.returnAnnotation, expression.body, type, null);
|
|
6351
6413
|
return context.record(expression, type);
|
|
6352
6414
|
}
|
|
6353
6415
|
case "binary-expression": {
|
|
@@ -6412,8 +6474,12 @@ function checkMethodBody(context, info, member) {
|
|
|
6412
6474
|
if (explicitSelf !== void 0) {
|
|
6413
6475
|
context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
|
|
6414
6476
|
}
|
|
6477
|
+
const signature = info.members.get(member.name)?.type;
|
|
6478
|
+
if (signature?.kind !== "function") {
|
|
6479
|
+
return;
|
|
6480
|
+
}
|
|
6415
6481
|
context.pushClassMethod({ className: info.name, methodName: member.name });
|
|
6416
|
-
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, createNamed(info.name));
|
|
6482
|
+
checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature, createNamed(info.name));
|
|
6417
6483
|
context.popClassMethod();
|
|
6418
6484
|
}
|
|
6419
6485
|
function checkContract(context, info, contract, member) {
|
|
@@ -6600,9 +6666,9 @@ function buildFunctionType(context, parameters, returnAnnotation) {
|
|
|
6600
6666
|
const types = parameters.filter((parameter) => !parameter.isVararg).map((parameter) => context.resolveAnnotation(parameter.annotation));
|
|
6601
6667
|
return createFunction(types, context.resolveAnnotation(returnAnnotation), minimumArguments(context, parameters), isVariadic);
|
|
6602
6668
|
}
|
|
6603
|
-
function checkFunctionBody(context, parameters, returnAnnotation, body, selfType) {
|
|
6669
|
+
function checkFunctionBody(context, parameters, returnAnnotation, body, signature, selfType) {
|
|
6604
6670
|
context.binder.pushScope();
|
|
6605
|
-
context.pushReturnType(context.resolveAnnotation(returnAnnotation));
|
|
6671
|
+
context.pushReturnType(returnAnnotation === null ? null : context.resolveAnnotation(returnAnnotation));
|
|
6606
6672
|
if (selfType !== null) {
|
|
6607
6673
|
context.binder.declare({ name: "self", type: selfType, isLocal: true, position: ORIGIN });
|
|
6608
6674
|
}
|
|
@@ -6611,7 +6677,10 @@ function checkFunctionBody(context, parameters, returnAnnotation, body, selfType
|
|
|
6611
6677
|
context.binder.declare({ name: parameter.name, type, isLocal: true, position: parameter.position });
|
|
6612
6678
|
}
|
|
6613
6679
|
checkStatements(context, body);
|
|
6614
|
-
context.popReturnType();
|
|
6680
|
+
const inferred = context.popReturnType();
|
|
6681
|
+
if (returnAnnotation === null) {
|
|
6682
|
+
signature.returnType = inferred;
|
|
6683
|
+
}
|
|
6615
6684
|
context.binder.popScope();
|
|
6616
6685
|
}
|
|
6617
6686
|
function valueAt(values, valueTypes, index) {
|
|
@@ -6681,12 +6750,16 @@ function checkFunctionDeclaration(context, statement) {
|
|
|
6681
6750
|
}
|
|
6682
6751
|
}
|
|
6683
6752
|
context.record(statement.name, type);
|
|
6684
|
-
checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, statement.isMethod ? ANY_TYPE : null);
|
|
6753
|
+
checkFunctionBody(context, statement.parameters, statement.returnAnnotation, statement.body, type, statement.isMethod ? ANY_TYPE : null);
|
|
6685
6754
|
}
|
|
6686
6755
|
function checkReturn(context, statement) {
|
|
6687
6756
|
const valueTypes = checkValueList(context, statement.values);
|
|
6688
6757
|
const expected = context.currentReturnType();
|
|
6689
|
-
if (expected === null
|
|
6758
|
+
if (expected === null) {
|
|
6759
|
+
context.inferReturnType(createTuple(valueTypes));
|
|
6760
|
+
return;
|
|
6761
|
+
}
|
|
6762
|
+
if (expected.kind === "any") {
|
|
6690
6763
|
return;
|
|
6691
6764
|
}
|
|
6692
6765
|
if (expected.kind === "void") {
|
|
@@ -6761,7 +6834,7 @@ function checkStatement(context, statement) {
|
|
|
6761
6834
|
case "type-alias-statement": {
|
|
6762
6835
|
const resolved = context.resolveAnnotation(statement.annotation);
|
|
6763
6836
|
const named2 = statement.annotation.kind === "type-object" ? renameRecord(resolved, statement.name) : resolved;
|
|
6764
|
-
context.binder.declareAlias(statement.name, named2);
|
|
6837
|
+
context.binder.declareAlias(statement.name, named2, statement.typeParameters);
|
|
6765
6838
|
return;
|
|
6766
6839
|
}
|
|
6767
6840
|
case "declare-statement":
|
|
@@ -8483,6 +8556,14 @@ function parseLegacyClassMethod(stream, token, decorators) {
|
|
|
8483
8556
|
function parseFieldAnnotation(stream) {
|
|
8484
8557
|
return parseNamedAnnotation(stream, "field");
|
|
8485
8558
|
}
|
|
8559
|
+
function expectClassFieldBoundary(stream, token) {
|
|
8560
|
+
const current = stream.current();
|
|
8561
|
+
const delimiter = current.kind === "punctuation" && (current.value === "}" || current.value === ";" || current.value === ",");
|
|
8562
|
+
if (current.kind === "eof" || delimiter || current.position.line > token.position.line) {
|
|
8563
|
+
return;
|
|
8564
|
+
}
|
|
8565
|
+
throw stream.error(`Expected a line break or separator after class member "${token.value}".`, "parse-unexpected-token");
|
|
8566
|
+
}
|
|
8486
8567
|
function parseClassMember(stream) {
|
|
8487
8568
|
const decorators = parseDecorators(stream);
|
|
8488
8569
|
const token = stream.expectName();
|
|
@@ -8494,6 +8575,7 @@ function parseClassMember(stream) {
|
|
|
8494
8575
|
}
|
|
8495
8576
|
const annotation = parseFieldAnnotation(stream);
|
|
8496
8577
|
const value = stream.match("operator", "=") ? parseExpression(stream) : null;
|
|
8578
|
+
expectClassFieldBoundary(stream, token);
|
|
8497
8579
|
return { kind: "class-field", name: token.value, annotation, value, decorators, position: token.position };
|
|
8498
8580
|
}
|
|
8499
8581
|
function parseClassModifiers(stream, declaration) {
|
|
@@ -11002,6 +11084,28 @@ async function runDevCommand(context, options) {
|
|
|
11002
11084
|
// src/commands/init-command.ts
|
|
11003
11085
|
import { basename } from "node:path";
|
|
11004
11086
|
|
|
11087
|
+
// src/commands/init-prompt.ts
|
|
11088
|
+
import { createInterface } from "node:readline/promises";
|
|
11089
|
+
async function question(prompt, label2, fallback) {
|
|
11090
|
+
const answer = (await prompt.question(`${label2}${fallback === "" ? "" : ` (${fallback})`}: `)).trim();
|
|
11091
|
+
return answer === "" ? fallback : answer;
|
|
11092
|
+
}
|
|
11093
|
+
async function promptForProject(defaults, nameLocked) {
|
|
11094
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
11095
|
+
return defaults;
|
|
11096
|
+
}
|
|
11097
|
+
const prompt = createInterface({ input: process.stdin, output: process.stdout });
|
|
11098
|
+
try {
|
|
11099
|
+
const name = nameLocked ? defaults.name : await question(prompt, "Project name", defaults.name);
|
|
11100
|
+
const version = await question(prompt, "Version", defaults.version);
|
|
11101
|
+
const description = await question(prompt, "Description", defaults.description ?? "");
|
|
11102
|
+
const author = await question(prompt, "Author", defaults.author ?? "");
|
|
11103
|
+
return { name, version, description: description || null, author: author || null };
|
|
11104
|
+
} finally {
|
|
11105
|
+
prompt.close();
|
|
11106
|
+
}
|
|
11107
|
+
}
|
|
11108
|
+
|
|
11005
11109
|
// src/config/config-schema.ts
|
|
11006
11110
|
var CONFIG_FILE_NAME = "luam.json";
|
|
11007
11111
|
var DEFAULT_SOURCE_DIRS = ["src"];
|
|
@@ -11049,21 +11153,29 @@ function readTemplateSource(source) {
|
|
|
11049
11153
|
}
|
|
11050
11154
|
|
|
11051
11155
|
// src/scaffold/scaffold-plan.ts
|
|
11052
|
-
function renderConfig(source,
|
|
11156
|
+
function renderConfig(source, details) {
|
|
11053
11157
|
const parsed = JSON.parse(source);
|
|
11054
11158
|
const config = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
11055
|
-
|
|
11159
|
+
const { name: _name, version: _version, description: _description, author: _author, ...template } = config;
|
|
11160
|
+
const metadata = {
|
|
11161
|
+
...template,
|
|
11162
|
+
name: details.name,
|
|
11163
|
+
version: details.version,
|
|
11164
|
+
...details.description === null ? {} : { description: details.description },
|
|
11165
|
+
...details.author === null ? {} : { author: details.author }
|
|
11166
|
+
};
|
|
11167
|
+
return `${JSON.stringify(metadata, null, 4)}
|
|
11056
11168
|
`;
|
|
11057
11169
|
}
|
|
11058
|
-
function renderFile(file,
|
|
11170
|
+
function renderFile(file, details) {
|
|
11059
11171
|
const source = readTemplateSource(file.source);
|
|
11060
11172
|
if (file.path !== CONFIG_FILE_NAME) {
|
|
11061
11173
|
return { path: file.path, content: source };
|
|
11062
11174
|
}
|
|
11063
|
-
return { path: file.path, content: renderConfig(source,
|
|
11175
|
+
return { path: file.path, content: renderConfig(source, details) };
|
|
11064
11176
|
}
|
|
11065
|
-
function buildScaffoldPlan(
|
|
11066
|
-
return { name, files: TEMPLATE_FILES.map((file) => renderFile(file,
|
|
11177
|
+
function buildScaffoldPlan(details) {
|
|
11178
|
+
return { name: details.name, files: TEMPLATE_FILES.map((file) => renderFile(file, details)) };
|
|
11067
11179
|
}
|
|
11068
11180
|
|
|
11069
11181
|
// src/scaffold/scaffold-writer.ts
|
|
@@ -11094,21 +11206,31 @@ function resolveResourceName(root, requested) {
|
|
|
11094
11206
|
const folder = basename(root);
|
|
11095
11207
|
return isValidResourceName(folder) ? folder : FALLBACK_RESOURCE_NAME;
|
|
11096
11208
|
}
|
|
11097
|
-
function runInitCommand(root, logger, options) {
|
|
11209
|
+
async function runInitCommand(root, logger, options) {
|
|
11098
11210
|
if (options.name !== null && !isValidResourceName(options.name)) {
|
|
11099
11211
|
logger.error(`"--name" must be a valid MTA resource name but received "${options.name}".`);
|
|
11100
11212
|
return EXIT_USAGE;
|
|
11101
11213
|
}
|
|
11102
|
-
const
|
|
11103
|
-
|
|
11214
|
+
const defaults = {
|
|
11215
|
+
name: resolveResourceName(root, options.name),
|
|
11216
|
+
version: "1.0.0",
|
|
11217
|
+
description: null,
|
|
11218
|
+
author: null
|
|
11219
|
+
};
|
|
11220
|
+
const details = options.yes ? defaults : await options.prompt(defaults, options.name !== null);
|
|
11221
|
+
if (!isValidResourceName(details.name)) {
|
|
11222
|
+
logger.error(`"Project name" must be a valid MTA resource name but received "${details.name}".`);
|
|
11223
|
+
return EXIT_USAGE;
|
|
11224
|
+
}
|
|
11225
|
+
const result = writeScaffold(root, buildScaffoldPlan(details), options.force);
|
|
11104
11226
|
for (const path of result.skipped) {
|
|
11105
11227
|
logger.warn(`Kept the existing "${path}". Pass "--force" to overwrite it.`);
|
|
11106
11228
|
}
|
|
11107
11229
|
if (result.written.length === 0) {
|
|
11108
|
-
logger.info(`The project "${name}" already exists in "${root}". Nothing was written.`);
|
|
11230
|
+
logger.info(`The project "${details.name}" already exists in "${root}". Nothing was written.`);
|
|
11109
11231
|
return EXIT_OK;
|
|
11110
11232
|
}
|
|
11111
|
-
logger.info(`Scaffolded "${name}" into "${root}" (${result.written.length} files, ${result.skipped.length} kept).`);
|
|
11233
|
+
logger.info(`Scaffolded "${details.name}" into "${root}" (${result.written.length} files, ${result.skipped.length} kept).`);
|
|
11112
11234
|
logger.info('Next: run "luam check", then "luam build".');
|
|
11113
11235
|
return EXIT_OK;
|
|
11114
11236
|
}
|
|
@@ -11720,12 +11842,12 @@ function createEditorService() {
|
|
|
11720
11842
|
}
|
|
11721
11843
|
|
|
11722
11844
|
// src/editor/installation-prompt.ts
|
|
11723
|
-
import { createInterface } from "node:readline/promises";
|
|
11845
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
11724
11846
|
async function promptForInstallation(editorName) {
|
|
11725
11847
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
11726
11848
|
return null;
|
|
11727
11849
|
}
|
|
11728
|
-
const prompt =
|
|
11850
|
+
const prompt = createInterface2({ input: process.stdin, output: process.stdout });
|
|
11729
11851
|
try {
|
|
11730
11852
|
const answer = (await prompt.question(`Install the Luam extension in ${editorName}? [Y/n] `)).trim().toLowerCase();
|
|
11731
11853
|
return answer === "" || answer === "y" || answer === "yes";
|
|
@@ -11848,7 +11970,8 @@ async function runCli(argv, overrides = {}) {
|
|
|
11848
11970
|
}
|
|
11849
11971
|
const root = resolve12(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
11850
11972
|
if (parsed.command === "init") {
|
|
11851
|
-
|
|
11973
|
+
const target = parsed.operand === null ? root : resolve12(root, parsed.operand);
|
|
11974
|
+
return runInitCommand(target, logger, { name: parsed.name, force: parsed.force, yes: parsed.yes, prompt: overrides.initPrompt ?? promptForProject });
|
|
11852
11975
|
}
|
|
11853
11976
|
const editorService = overrides.editorService ?? createEditorService();
|
|
11854
11977
|
if (parsed.command === "doctor") {
|