nextlua 3.0.0 → 3.2.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.
Files changed (3) hide show
  1. package/index.js +75 -13
  2. package/package.json +36 -3
  3. package/src/main.js +39 -6
package/index.js CHANGED
@@ -4,12 +4,18 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
  const { beautify, minify } = require("./src/main");
6
6
 
7
- const commandId = "nextlua.beautifyDocument";
7
+ const beautifyCommandId = "nextlua.beautifyDocument";
8
+ const minifyCommandId = "nextlua.minifyDocument";
9
+ const menuCommandId = "nextlua.showMenu";
8
10
 
9
11
  function beautifyText(input) {
10
12
  return beautify(input);
11
13
  }
12
14
 
15
+ function minifyText(input) {
16
+ return minify(input);
17
+ }
18
+
13
19
  function activate(context) {
14
20
  const vscode = require("vscode");
15
21
  const selector = [
@@ -32,26 +38,81 @@ function activate(context) {
32
38
  }
33
39
  });
34
40
 
35
- const command = vscode.commands.registerCommand(commandId, async () => {
41
+ function registerTransformCommand(commandId, transform) {
42
+ return vscode.commands.registerCommand(commandId, async () => {
43
+ const editor = vscode.window.activeTextEditor;
44
+ if (!editor) {
45
+ vscode.window.showInformationMessage("Open a Lua or Luau file first.");
46
+ return;
47
+ }
48
+
49
+ const document = editor.document;
50
+ const fullRange = new vscode.Range(
51
+ document.positionAt(0),
52
+ document.lineAt(document.lineCount - 1).range.end
53
+ );
54
+ const output = transform(document.getText());
55
+
56
+ await editor.edit(editBuilder => {
57
+ editBuilder.replace(fullRange, output);
58
+ });
59
+ });
60
+ }
61
+
62
+ const beautifyCommand = registerTransformCommand(beautifyCommandId, beautifyText);
63
+ const minifyCommand = registerTransformCommand(minifyCommandId, minifyText);
64
+
65
+ const transforms = {
66
+ Beautify: beautifyText,
67
+ Minify: minifyText
68
+ };
69
+
70
+ const menuCommand = vscode.commands.registerCommand(menuCommandId, async () => {
36
71
  const editor = vscode.window.activeTextEditor;
37
72
  if (!editor) {
38
- vscode.window.showInformationMessage("Open a Lua or Luau file first.");
73
+ vscode.window.showErrorMessage("No script content in current file");
39
74
  return;
40
75
  }
41
76
 
42
- const document = editor.document;
43
- const fullRange = new vscode.Range(
44
- document.positionAt(0),
45
- document.lineAt(document.lineCount - 1).range.end
46
- );
47
- const output = beautifyText(document.getText());
77
+ const script = editor.document.getText();
78
+ if (!script.length) {
79
+ vscode.window.showErrorMessage("No script content in current file");
80
+ return;
81
+ }
48
82
 
49
- await editor.edit(editBuilder => {
50
- editBuilder.replace(fullRange, output);
51
- });
83
+ const type = await vscode.window.showQuickPick(["Beautify", "Minify"]);
84
+ if (!type) return;
85
+
86
+ let output;
87
+ try {
88
+ output = transforms[type](script);
89
+ } catch (error) {
90
+ console.log(error);
91
+ vscode.window.showErrorMessage(`Failed to ${type}`);
92
+ return;
93
+ }
94
+
95
+ const range = new vscode.Range(
96
+ editor.document.positionAt(0),
97
+ editor.document.positionAt(script.length)
98
+ );
99
+ await editor.edit(editBuilder => editBuilder.replace(range, output));
100
+ vscode.window.showInformationMessage("Completed!");
52
101
  });
53
102
 
54
- context.subscriptions.push(formatProvider, command);
103
+ const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0);
104
+ statusBarItem.text = "nextlua";
105
+ statusBarItem.tooltip = "Lua Formatter";
106
+ statusBarItem.command = menuCommandId;
107
+ statusBarItem.show();
108
+
109
+ context.subscriptions.push(
110
+ formatProvider,
111
+ beautifyCommand,
112
+ minifyCommand,
113
+ menuCommand,
114
+ statusBarItem
115
+ );
55
116
  }
56
117
 
57
118
  function deactivate() {}
@@ -137,6 +198,7 @@ module.exports = {
137
198
  activate,
138
199
  deactivate,
139
200
  beautifyText,
201
+ minifyText,
140
202
  minify,
141
203
  beautify
142
204
  };
package/package.json CHANGED
@@ -1,17 +1,50 @@
1
1
  {
2
2
  "name": "nextlua",
3
- "version": "3.0.0",
3
+ "displayName": "nextlua",
4
+ "version": "3.2.0",
4
5
  "description": "A luau beautifier and minifier.",
5
- "main": "index.js",
6
+ "publisher": "centurion",
7
+ "main": "./index.js",
6
8
  "bin": {
7
9
  "nextlua": "./index.js"
8
10
  },
11
+ "engines": {
12
+ "vscode": "^1.75.0"
13
+ },
14
+ "categories": [
15
+ "Formatters"
16
+ ],
17
+ "activationEvents": [
18
+ "onLanguage:lua",
19
+ "onLanguage:luau"
20
+ ],
21
+ "contributes": {
22
+ "commands": [
23
+ {
24
+ "command": "nextlua.beautifyDocument",
25
+ "title": "Beautify"
26
+ },
27
+ {
28
+ "command": "nextlua.minifyDocument",
29
+ "title": "Minify"
30
+ },
31
+ {
32
+ "command": "nextlua.showMenu",
33
+ "title": "nextlua"
34
+ }
35
+ ]
36
+ },
9
37
  "files": [
10
38
  "index.js",
11
39
  "src"
12
40
  ],
13
41
  "scripts": {
14
- "test": "echo \"Error: no test specified\" && exit 1"
42
+ "test": "echo \"Error: no test specified\" && exit 1",
43
+ "package": "vsce package"
44
+ },
45
+ "devDependencies": {
46
+ "@types/vscode": "^1.75.0",
47
+ "@vscode/vsce": "^3.0.0"
15
48
  },
16
49
  "keywords": [],
17
50
  "author": "",
package/src/main.js CHANGED
@@ -409,10 +409,11 @@ function needsSpace(prev, current) {
409
409
  }
410
410
 
411
411
  if (current === "(") {
412
- // Control-flow keywords read better with a space before the paren
413
- // (`if (`, `while (`, `elseif (`), but calls like `function(` and
414
- // `foo(` stay tight.
415
- return keywordsSpacedBeforeParen.has(prev);
412
+ // Control-flow keywords and binary operators read better with a space
413
+ // before the paren (`if (`, `while (`, `a * (`, `x = (`), but calls
414
+ // like `function(` and `foo(` stay tight. A unary sign before `(` is
415
+ // handled by joinTokens, which suppresses the space (`-(x)`).
416
+ return keywordsSpacedBeforeParen.has(prev) || binaryOperators.has(prev);
416
417
  }
417
418
 
418
419
  if (current === "[" && isValueEnd(prev)) {
@@ -429,7 +430,9 @@ function needsSpace(prev, current) {
429
430
  return false;
430
431
  }
431
432
 
432
- if (prev === "#" || current === "#") {
433
+ if (prev === "#") {
434
+ // The length operator binds tightly to its operand: `#h`, never `# h`.
435
+ // The space *before* `#` still follows the normal rules (`= #h`).
433
436
  return false;
434
437
  }
435
438
 
@@ -454,6 +457,18 @@ function isGenericOpen(tokens, index) {
454
457
  !reservedKeywords.has(prev);
455
458
  }
456
459
 
460
+ function isUnarySign(tokens, index) {
461
+ // tokens[index] is "-" or "+". It is unary (binding tightly to its operand
462
+ // with no following space: `-1`, `-x`, `-(y)`, `-#t`) when it does not
463
+ // follow a complete value. Otherwise it is the binary operator (`a - 1`).
464
+ const token = tokens[index];
465
+ if (token !== "-" && token !== "+") {
466
+ return false;
467
+ }
468
+ const before = tokens[index - 1];
469
+ return before === undefined || !isValueEnd(before);
470
+ }
471
+
457
472
  function joinTokens(tokens) {
458
473
  let text = "";
459
474
  let prev = null;
@@ -465,7 +480,14 @@ function joinTokens(tokens) {
465
480
  const inGeneric = genericDepth > 0;
466
481
  const opensGeneric = !inGeneric && token === "<" && isGenericOpen(tokens, idx);
467
482
 
468
- if (prev !== null && !inGeneric && !opensGeneric && needsSpace(prev, token)) {
483
+ // A unary +/- binds to its operand, so suppress the space after it.
484
+ // (Skip the suppression when the next token is itself a +/- so we never
485
+ // fuse two signs into a `--` comment or a `+-` run.)
486
+ const prevIsUnarySign = prev !== null &&
487
+ token !== "-" && token !== "+" &&
488
+ isUnarySign(tokens, idx - 1);
489
+
490
+ if (prev !== null && !inGeneric && !opensGeneric && !prevIsUnarySign && needsSpace(prev, token)) {
469
491
  text += " ";
470
492
  }
471
493
  text += token;
@@ -571,6 +593,17 @@ function layout(input) {
571
593
  flushCurrent();
572
594
  }
573
595
 
596
+ if (token === "else" && inlineIfStack.length && inlineIfStack[inlineIfStack.length - 1] === "else") {
597
+ // The `else` of an inline `if ... then ... else ...` expression.
598
+ // It can appear nested inside parens/brackets (e.g. `x = (if c then
599
+ // a else b)`), so it must be matched regardless of bracket depth —
600
+ // otherwise inlineIfStack never empties and statement-splitting
601
+ // stays disabled for the rest of the block.
602
+ inlineIfStack.pop();
603
+ current.push(token);
604
+ continue;
605
+ }
606
+
574
607
  if (blockMiddle.has(token) && atStatementLevel()) {
575
608
  if (token === "else" && inlineIfStack.length) {
576
609
  inlineIfStack.pop();