@thigasdevelopment/luam 0.19.0 → 0.19.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 CHANGED
@@ -275,12 +275,12 @@ VSCodium and Windsurf. The language server itself is editor-agnostic and speaks
275
275
 
276
276
  ## Known limitations
277
277
 
278
- - **Narrowing reaches names, not fields.** `if value ~= nil then` refines a local;
279
- `self.value` keeps its declared type however you test it.
278
+ - **Narrowing follows a path, not an alias.** `if self.value ~= nil then` refines
279
+ the field inside the block; storing the test in a variable does not carry it.
280
280
  - **A class is a type everywhere, a value from its declaration** — `extends` may
281
281
  name a parent written further down, a top-level `new` may not.
282
282
  - **The MTA catalog can lag a release** — a newer function stays `any`.
283
- - **No static members, declared metamethods, or generic classes.**
283
+ - **No declared metamethods or generic classes.**
284
284
  - **The editor re-checks by declaration** — a declaration change re-analyzes every
285
285
  file that can see it, an edit inside a function body only its own file.
286
286
  - **An export is named, never verified** against the side that calls it.
package/lua/class.lua CHANGED
@@ -73,7 +73,7 @@ local function create(name, struct, options)
73
73
 
74
74
  definition = definition or { __name = name }
75
75
 
76
- definition.__pending = nil
76
+ definition.__pending = false
77
77
  definition.__super = options.super
78
78
  definition.__metamethods = options.metamethods
79
79
 
package/luam.mjs CHANGED
@@ -4521,7 +4521,7 @@ function parseDecorators(stream) {
4521
4521
  }
4522
4522
  return decorators;
4523
4523
  }
4524
- function parseClassMethod(stream, token, decorators) {
4524
+ function parseClassMethod(stream, token, decorators, isStatic) {
4525
4525
  stream.expect("operator", "=");
4526
4526
  const expression = parseFunctionExpression(stream);
4527
4527
  return {
@@ -4529,6 +4529,7 @@ function parseClassMethod(stream, token, decorators) {
4529
4529
  name: token.value,
4530
4530
  isConstructor: token.value === "constructor",
4531
4531
  isSynthetic: false,
4532
+ isStatic,
4532
4533
  parameters: expression.parameters,
4533
4534
  returnAnnotation: expression.returnAnnotation,
4534
4535
  body: expression.body,
@@ -4536,7 +4537,7 @@ function parseClassMethod(stream, token, decorators) {
4536
4537
  position: token.position
4537
4538
  };
4538
4539
  }
4539
- function parseBraceClassMethod(stream, token, decorators) {
4540
+ function parseBraceClassMethod(stream, token, decorators, isStatic) {
4540
4541
  const parameters = parseParameters(stream);
4541
4542
  const returnAnnotation = parseOptionalAnnotation(stream);
4542
4543
  const body = parseBraceBlock(stream);
@@ -4545,6 +4546,7 @@ function parseBraceClassMethod(stream, token, decorators) {
4545
4546
  name: token.value,
4546
4547
  isConstructor: token.value === "constructor",
4547
4548
  isSynthetic: false,
4549
+ isStatic,
4548
4550
  parameters,
4549
4551
  returnAnnotation,
4550
4552
  body,
@@ -4563,20 +4565,35 @@ function expectClassFieldBoundary(stream, token) {
4563
4565
  }
4564
4566
  throw stream.error(`Expected a line break or separator after class member "${token.value}".`, "parse-unexpected-token");
4565
4567
  }
4568
+ var STATIC_MODIFIER = "static";
4569
+ function parseStaticModifier(stream) {
4570
+ if (!stream.check("identifier", STATIC_MODIFIER)) {
4571
+ return false;
4572
+ }
4573
+ const modifier = stream.current();
4574
+ if (!stream.checkName(1) || stream.peek(1).position.line !== modifier.position.line) {
4575
+ return false;
4576
+ }
4577
+ const checkpoint = stream.checkpoint();
4578
+ stream.next();
4579
+ stream.eraseToCurrent(checkpoint);
4580
+ return true;
4581
+ }
4566
4582
  function parseClassMember(stream) {
4567
4583
  const decorators = parseDecorators(stream);
4584
+ const isStatic = parseStaticModifier(stream);
4568
4585
  const token = stream.expectName();
4569
4586
  if (stream.check("punctuation", "(")) {
4570
4587
  stream.report("parse-class-method-form", `Write class member "${token.value}" as "${token.value} = function (...) ... end".`, token.position);
4571
- return parseBraceClassMethod(stream, token, decorators);
4588
+ return parseBraceClassMethod(stream, token, decorators, isStatic);
4572
4589
  }
4573
4590
  if (stream.check("operator", "=") && stream.checkAhead(1, "keyword", "function")) {
4574
- return parseClassMethod(stream, token, decorators);
4591
+ return parseClassMethod(stream, token, decorators, isStatic);
4575
4592
  }
4576
4593
  const annotation = parseFieldAnnotation(stream);
4577
4594
  const value = stream.match("operator", "=") ? parseExpression(stream) : null;
4578
4595
  expectClassFieldBoundary(stream, token);
4579
- return { kind: "class-field", name: token.value, annotation, value, decorators, position: token.position };
4596
+ return { kind: "class-field", name: token.value, annotation, value, decorators, isStatic, position: token.position };
4580
4597
  }
4581
4598
  function parseClassModifiers(stream, declaration) {
4582
4599
  while (stream.check("keyword") && CLASS_MODIFIERS.has(stream.current().value)) {
@@ -6584,7 +6601,7 @@ import { tmpdir } from "node:os";
6584
6601
  import { join as join2 } from "node:path";
6585
6602
 
6586
6603
  // src/cli/version.ts
6587
- var VERSION = true ? "0.19.0" : "0.0.0-dev";
6604
+ var VERSION = true ? "0.19.1" : "0.0.0-dev";
6588
6605
  var PROGRAM_NAME = "luam";
6589
6606
  var PROGRAM_DESCRIPTION = "luam \u2014 the Luam compiler for Multi Theft Auto resources.";
6590
6607
 
@@ -8455,8 +8472,8 @@ var MTA_AUDIO_CLIENT = {
8455
8472
  isSoundPaused: fn([named("Element")], BOOLEAN, 1),
8456
8473
  playSFX: fn([STRING, NUMBER, NUMBER, BOOLEAN], named("Element"), 3),
8457
8474
  playSFX3D: fn([STRING, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN], named("Element"), 6),
8458
- playSound: fn([STRING, BOOLEAN, BOOLEAN], named("Element"), 1),
8459
- playSound3D: fn([STRING, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Element"), 4),
8475
+ playSound: fn([STRING, BOOLEAN, BOOLEAN], named("Sound"), 1),
8476
+ playSound3D: fn([STRING, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Sound3D"), 4),
8460
8477
  playSoundFrontEnd: fn([NUMBER], BOOLEAN, 1),
8461
8478
  setRadioChannel: fn([NUMBER], BOOLEAN, 1),
8462
8479
  setSoundEffectEnabled: fn(
@@ -8521,7 +8538,7 @@ var MTA_BLIP_CLIENT = {
8521
8538
  var MTA_BROWSER_CLIENT = {
8522
8539
  canBrowserNavigateBack: fn([named("Browser")], BOOLEAN, 1),
8523
8540
  canBrowserNavigateForward: fn([named("Browser")], BOOLEAN, 1),
8524
- createBrowser: fn([NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Element"), 3),
8541
+ createBrowser: fn([NUMBER, NUMBER, BOOLEAN, BOOLEAN], named("Browser"), 3),
8525
8542
  executeBrowserJavascript: fn([named("Browser"), STRING], BOOLEAN, 2),
8526
8543
  focusBrowser: fn([named("Browser")], BOOLEAN, 1),
8527
8544
  getBrowserProperty: fn([named("Browser"), STRING], BOOLEAN, 2),
@@ -8611,10 +8628,10 @@ var MTA_DISCORD_CLIENT = {
8611
8628
  // ../mta-types/src/generated/api/mta-drawing-client.ts
8612
8629
  var MTA_DRAWING_CLIENT = {
8613
8630
  dxConvertPixels: fn([STRING, STRING, NUMBER], STRING, 2),
8614
- dxCreateFont: fn([STRING, NUMBER, BOOLEAN, STRING], named("Element"), 1),
8615
- dxCreateRenderTarget: fn([NUMBER, NUMBER, BOOLEAN], named("Element"), 2),
8616
- dxCreateScreenSource: fn([NUMBER, NUMBER], named("Element"), 2),
8617
- dxCreateShader: fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], tupleOf([named("Element"), STRING]), 1),
8631
+ dxCreateFont: fn([STRING, NUMBER, BOOLEAN, STRING], named("DxFont"), 1),
8632
+ dxCreateRenderTarget: fn([NUMBER, NUMBER, BOOLEAN], named("DxRenderTarget"), 2),
8633
+ dxCreateScreenSource: fn([NUMBER, NUMBER], named("DxScreenSource"), 2),
8634
+ dxCreateShader: fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], tupleOf([named("DxShader"), STRING]), 1),
8618
8635
  dxCreateTexture: fn(
8619
8636
  [
8620
8637
  STRING,
@@ -9232,22 +9249,22 @@ var MTA_GUI_CLIENT = {
9232
9249
  guiComboBoxSetOpen: fn([named("Element"), BOOLEAN], BOOLEAN, 2),
9233
9250
  guiComboBoxSetSelected: fn([named("Element"), NUMBER], BOOLEAN, 2),
9234
9251
  guiCreateBrowser: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiBrowser"), 6),
9235
- guiCreateButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9236
- guiCreateCheckBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, BOOLEAN, named("GuiElement")], named("Element"), 6),
9237
- guiCreateComboBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9238
- guiCreateEdit: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9239
- guiCreateFont: fn([STRING, NUMBER], named("Element"), 1),
9240
- guiCreateGridList: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
9241
- guiCreateLabel: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9252
+ guiCreateButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiButton"), 5),
9253
+ guiCreateCheckBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiCheckbox"), 6),
9254
+ guiCreateComboBox: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiCombobox"), 5),
9255
+ guiCreateEdit: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiEdit"), 5),
9256
+ guiCreateFont: fn([STRING, NUMBER], named("GuiFont"), 1),
9257
+ guiCreateGridList: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("GuiGridList"), 4),
9258
+ guiCreateLabel: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiLabel"), 5),
9242
9259
  guiCreateMemo: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiMemo"), 5),
9243
9260
  guiCreateProgressBar: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
9244
- guiCreateRadioButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9261
+ guiCreateRadioButton: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiRadioButton"), 5),
9245
9262
  guiCreateScrollBar: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, BOOLEAN, named("GuiElement")], named("GuiElement"), 5),
9246
9263
  guiCreateScrollPane: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
9247
- guiCreateStaticImage: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("Element"), 5),
9248
- guiCreateTab: fn([STRING, named("GuiElement")], named("Element"), 2),
9249
- guiCreateTabPanel: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("Element"), 4),
9250
- guiCreateWindow: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN], named("Element"), 5),
9264
+ guiCreateStaticImage: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("GuiElement")], named("GuiStaticImage"), 5),
9265
+ guiCreateTab: fn([STRING, named("GuiElement")], named("GuiTab"), 2),
9266
+ guiCreateTabPanel: fn([NUMBER, NUMBER, NUMBER, NUMBER, BOOLEAN, named("GuiElement")], named("GuiTabPanel"), 4),
9267
+ guiCreateWindow: fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN], named("GuiWindow"), 5),
9251
9268
  guiDeleteTab: fn([named("Element"), named("Element")], BOOLEAN, 2),
9252
9269
  guiEditGetCaretIndex: fn([named("Element")], NUMBER, 1),
9253
9270
  guiEditGetMaxLength: fn([named("GuiEdit")], NUMBER, 1),
@@ -11590,7 +11607,7 @@ var MTA_OOP_1 = [
11590
11607
  ),
11591
11608
  oopClass(
11592
11609
  "DxFont",
11593
- null,
11610
+ "Element",
11594
11611
  [
11595
11612
  oopMethod("getHeight", "client", "dxGetFontHeight", fn([NUMBER, ANY], NUMBER, 0)),
11596
11613
  oopMethod("getSize", "client", "dxGetTextSize", fn([STRING, NUMBER, NUMBER, NUMBER, ANY, BOOLEAN, BOOLEAN], tupleOf([NUMBER, NUMBER]), 1)),
@@ -11601,14 +11618,14 @@ var MTA_OOP_1 = [
11601
11618
  ),
11602
11619
  oopClass(
11603
11620
  "DxRenderTarget",
11604
- null,
11621
+ "Element",
11605
11622
  [],
11606
11623
  [],
11607
11624
  oopConstructor("client", fn([NUMBER, NUMBER, BOOLEAN], named("DxRenderTarget"), 2), "dxCreateRenderTarget")
11608
11625
  ),
11609
11626
  oopClass(
11610
11627
  "DxScreenSource",
11611
- null,
11628
+ "Element",
11612
11629
  [
11613
11630
  oopMethod("update", "client", "dxUpdateScreenSource", fn([BOOLEAN], BOOLEAN, 0))
11614
11631
  ],
@@ -11621,14 +11638,14 @@ var MTA_OOP_1 = [
11621
11638
  var MTA_OOP_2 = [
11622
11639
  oopClass(
11623
11640
  "DxShader",
11624
- null,
11641
+ "Element",
11625
11642
  [],
11626
11643
  [],
11627
11644
  oopConstructor("client", fn([STRING, NUMBER, NUMBER, BOOLEAN, STRING], named("DxShader"), 1), "dxCreateShader")
11628
11645
  ),
11629
11646
  oopClass(
11630
11647
  "DxTexture",
11631
- null,
11648
+ "Element",
11632
11649
  [
11633
11650
  oopMethod("getPixels", "client", "dxGetTexturePixels", fn([ANY, ANY, NUMBER, NUMBER, NUMBER, ANY], STRING, 1)),
11634
11651
  oopMethod("setEdge", "client", "dxSetTextureEdge", fn([STRING, NUMBER], BOOLEAN, 1)),
@@ -11917,7 +11934,7 @@ var MTA_OOP_3 = [
11917
11934
  ),
11918
11935
  oopClass(
11919
11936
  "GuiButton",
11920
- null,
11937
+ "GuiElement",
11921
11938
  [],
11922
11939
  [],
11923
11940
  oopConstructor("client", fn([NUMBER, NUMBER, NUMBER, NUMBER, STRING, BOOLEAN, named("Element")], named("GuiButton"), 6), "guiCreateButton")
@@ -11974,7 +11991,7 @@ var MTA_OOP_3 = [
11974
11991
  ),
11975
11992
  oopClass(
11976
11993
  "GuiElement",
11977
- null,
11994
+ "Element",
11978
11995
  [
11979
11996
  oopProperty("alpha", "client", "guiGetAlpha", NUMBER),
11980
11997
  oopMethod("blur", "client", "guiBlur", fn([], BOOLEAN, 0)),
@@ -12027,7 +12044,7 @@ var MTA_OOP_3 = [
12027
12044
  ),
12028
12045
  oopClass(
12029
12046
  "GuiFont",
12030
- null,
12047
+ "Element",
12031
12048
  [],
12032
12049
  [],
12033
12050
  oopConstructor("client", fn([STRING, NUMBER], named("GuiFont"), 1), "guiCreateFont")
@@ -12115,7 +12132,7 @@ var MTA_OOP_3 = [
12115
12132
  ),
12116
12133
  oopClass(
12117
12134
  "GuiRadioButton",
12118
- null,
12135
+ "GuiElement",
12119
12136
  [
12120
12137
  oopMethod("getSelected", "client", "guiRadioButtonGetSelected", fn([], BOOLEAN, 0)),
12121
12138
  oopProperty("selected", "client", "guiRadioButtonGetSelected", BOOLEAN),
@@ -12176,7 +12193,7 @@ var MTA_OOP_4 = [
12176
12193
  ),
12177
12194
  oopClass(
12178
12195
  "Light",
12179
- null,
12196
+ "Element",
12180
12197
  [
12181
12198
  oopProperty("color", "client", "getLightColor", tupleOf([NUMBER, NUMBER, NUMBER])),
12182
12199
  oopProperty("direction", "client", "getLightDirection", tupleOf([NUMBER, NUMBER, NUMBER])),
@@ -13186,6 +13203,34 @@ var DeclarationRegistry = class {
13186
13203
  }
13187
13204
  return null;
13188
13205
  }
13206
+ lookupStaticMember(name, member) {
13207
+ const visited = /* @__PURE__ */ new Set();
13208
+ let current = this.lookupClass(name);
13209
+ while (current !== null && !visited.has(current.name)) {
13210
+ const found = current.statics.get(member);
13211
+ if (found !== void 0) {
13212
+ return found;
13213
+ }
13214
+ visited.add(current.name);
13215
+ current = current.superClass === null ? null : this.lookupClass(current.superClass);
13216
+ }
13217
+ return null;
13218
+ }
13219
+ collectStatics(name) {
13220
+ const collected = /* @__PURE__ */ new Map();
13221
+ const visited = /* @__PURE__ */ new Set();
13222
+ let current = this.lookupClass(name);
13223
+ while (current !== null && !visited.has(current.name)) {
13224
+ for (const [member, info] of current.statics) {
13225
+ if (!collected.has(member)) {
13226
+ collected.set(member, info);
13227
+ }
13228
+ }
13229
+ visited.add(current.name);
13230
+ current = current.superClass === null ? null : this.lookupClass(current.superClass);
13231
+ }
13232
+ return [...collected.values()];
13233
+ }
13189
13234
  lookupMember(name, member) {
13190
13235
  const visited = /* @__PURE__ */ new Set();
13191
13236
  const found = this.lookupClassMember(name, member, visited);
@@ -13217,7 +13262,7 @@ function buildRegistry() {
13217
13262
  procedural: member.procedural
13218
13263
  });
13219
13264
  }
13220
- registry.declareClass({ name: declaration.name, superClass: declaration.parent, interfaces: [], members, position: MTA_POSITION });
13265
+ registry.declareClass({ name: declaration.name, superClass: declaration.parent, interfaces: [], members, statics: /* @__PURE__ */ new Map(), position: MTA_POSITION });
13221
13266
  }
13222
13267
  return registry;
13223
13268
  }
@@ -13424,6 +13469,7 @@ var CheckContext = class {
13424
13469
  externalReferences = /* @__PURE__ */ new Map();
13425
13470
  unknownTypes = /* @__PURE__ */ new Map();
13426
13471
  calledMembers = /* @__PURE__ */ new Set();
13472
+ staticAccess = /* @__PURE__ */ new Set();
13427
13473
  typeParameters = /* @__PURE__ */ new Set();
13428
13474
  generatedMembers = /* @__PURE__ */ new Map();
13429
13475
  mode;
@@ -13490,20 +13536,20 @@ var CheckContext = class {
13490
13536
  this.predeclared.delete(name);
13491
13537
  return info;
13492
13538
  }
13493
- isPredeclaredClass(name) {
13494
- return this.predeclared.has(name);
13495
- }
13496
- awaitsDeclaration(name) {
13539
+ pendingDeclarationOf(name) {
13497
13540
  const seen = /* @__PURE__ */ new Set();
13498
13541
  let current = this.declarations.lookupClass(name);
13499
13542
  while (current !== null && !seen.has(current.name)) {
13500
13543
  if (this.predeclared.has(current.name)) {
13501
- return true;
13544
+ return current.name;
13502
13545
  }
13503
13546
  seen.add(current.name);
13504
13547
  current = current.superClass === null ? null : this.declarations.lookupClass(current.superClass);
13505
13548
  }
13506
- return false;
13549
+ return null;
13550
+ }
13551
+ awaitsDeclaration(name) {
13552
+ return this.pendingDeclarationOf(name) !== null;
13507
13553
  }
13508
13554
  insideFunction() {
13509
13555
  return this.returnStack.length > 0;
@@ -14163,6 +14209,7 @@ function accessorMethod(field2, decorator, name) {
14163
14209
  name,
14164
14210
  isConstructor: false,
14165
14211
  isSynthetic: true,
14212
+ isStatic: false,
14166
14213
  parameters: decorator === "Getter" ? [] : [value],
14167
14214
  returnAnnotation: decorator === "Getter" ? field2.annotation : voidAnnotation,
14168
14215
  body,
@@ -14171,7 +14218,7 @@ function accessorMethod(field2, decorator, name) {
14171
14218
  };
14172
14219
  }
14173
14220
  function generatedMethod(field2, name, parameters, returnAnnotation, kind, fields) {
14174
- return { kind: "class-method", name, isConstructor: false, isSynthetic: true, parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
14221
+ return { kind: "class-method", name, isConstructor: false, isSynthetic: true, isStatic: false, parameters, returnAnnotation, body: [], decorators: [], generated: { kind, fields }, position: field2.position };
14175
14222
  }
14176
14223
  function typeName(name, node) {
14177
14224
  return { kind: "type-name", name, typeArguments: [], position: node.position };
@@ -17731,11 +17778,11 @@ var ELEMENT_TYPES = [
17731
17778
  { name: "Camera", parent: "Element" },
17732
17779
  { name: "ColShape", parent: "Element" },
17733
17780
  { name: "Connection", parent: null },
17734
- { name: "DxFont", parent: null },
17735
- { name: "DxRenderTarget", parent: null },
17736
- { name: "DxScreenSource", parent: null },
17737
- { name: "DxShader", parent: null },
17738
- { name: "DxTexture", parent: null },
17781
+ { name: "DxFont", parent: "Element" },
17782
+ { name: "DxRenderTarget", parent: "Element" },
17783
+ { name: "DxScreenSource", parent: "Element" },
17784
+ { name: "DxShader", parent: "Element" },
17785
+ { name: "DxTexture", parent: "Element" },
17739
17786
  { name: "Effect", parent: "Element" },
17740
17787
  { name: "Element", parent: null },
17741
17788
  { name: "Engine", parent: null },
@@ -17744,21 +17791,21 @@ var ELEMENT_TYPES = [
17744
17791
  { name: "EngineTXD", parent: null },
17745
17792
  { name: "File", parent: null },
17746
17793
  { name: "GuiBrowser", parent: "GuiElement" },
17747
- { name: "GuiButton", parent: null },
17794
+ { name: "GuiButton", parent: "GuiElement" },
17748
17795
  { name: "GuiCheckbox", parent: "GuiElement" },
17749
17796
  { name: "GuiCombobox", parent: "GuiElement" },
17750
17797
  { name: "GuiEdit", parent: "GuiElement" },
17751
- { name: "GuiElement", parent: null },
17752
- { name: "GuiFont", parent: null },
17798
+ { name: "GuiElement", parent: "Element" },
17799
+ { name: "GuiFont", parent: "Element" },
17753
17800
  { name: "GuiGridList", parent: "GuiElement" },
17754
17801
  { name: "GuiLabel", parent: "GuiElement" },
17755
17802
  { name: "GuiMemo", parent: "GuiElement" },
17756
- { name: "GuiRadioButton", parent: null },
17803
+ { name: "GuiRadioButton", parent: "GuiElement" },
17757
17804
  { name: "GuiStaticImage", parent: "GuiElement" },
17758
17805
  { name: "GuiTab", parent: "GuiElement" },
17759
17806
  { name: "GuiTabPanel", parent: "GuiElement" },
17760
17807
  { name: "GuiWindow", parent: "GuiElement" },
17761
- { name: "Light", parent: null },
17808
+ { name: "Light", parent: "Element" },
17762
17809
  { name: "Marker", parent: "Element" },
17763
17810
  { name: "Material", parent: "Element" },
17764
17811
  { name: "Object", parent: "Element" },
@@ -17914,6 +17961,28 @@ function checkInterfaceMember(context, name, members, expression) {
17914
17961
  context.report("check-unknown-member", `Interface "${name}" has no member "${expression.property}". Declared members: ${keys}.`, expression.position);
17915
17962
  return ANY_TYPE;
17916
17963
  }
17964
+ function isUserClassReference(context, name) {
17965
+ const symbol = context.binder.lookup(name);
17966
+ return symbol !== null && !symbol.isLocal && context.declarations.lookupClass(name) !== null;
17967
+ }
17968
+ function resolveStaticMember(context, className, expression) {
17969
+ const member = context.declarations.lookupStaticMember(className, expression.property);
17970
+ if (member !== null) {
17971
+ if (member.deprecated === true) {
17972
+ context.warn("check-deprecated-use", `Member "${expression.property}" is deprecated.`, expression.position);
17973
+ }
17974
+ context.staticAccess.add(expression);
17975
+ return member.type;
17976
+ }
17977
+ if (context.awaitsDeclaration(className)) {
17978
+ context.staticAccess.add(expression);
17979
+ return ANY_TYPE;
17980
+ }
17981
+ const instance = context.declarations.lookupMember(className, expression.property);
17982
+ const hint = instance === null ? "" : ` It is an instance member, so read it from a value of "${className}".`;
17983
+ context.report("check-unknown-member", `Class "${className}" has no static member "${expression.property}".${hint}`, expression.position);
17984
+ return ANY_TYPE;
17985
+ }
17917
17986
  function resolveNamedMember(context, name, expression) {
17918
17987
  const enumeration = context.declarations.lookupEnum(name);
17919
17988
  if (enumeration !== null) {
@@ -17929,6 +17998,12 @@ function resolveNamedMember(context, name, expression) {
17929
17998
  if (isMtaElement(context, name)) {
17930
17999
  return resolveMtaMember(context, name, expression.property, expression.position)?.type ?? ANY_TYPE;
17931
18000
  }
18001
+ const staticMember = context.declarations.lookupStaticMember(name, expression.property);
18002
+ if (staticMember !== null) {
18003
+ const message = `"${expression.property}" is a static member of class "${name}". Read it as "${name}.${expression.property}".`;
18004
+ context.report("check-static-receiver", message, expression.position);
18005
+ return staticMember.type;
18006
+ }
17932
18007
  if (context.awaitsDeclaration(name)) {
17933
18008
  return ANY_TYPE;
17934
18009
  }
@@ -17961,9 +18036,10 @@ function checkNewExpression(context, expression) {
17961
18036
  context.report("check-unknown-class", `Class "${expression.className}" is not defined.`, expression.position);
17962
18037
  return ANY_TYPE;
17963
18038
  }
17964
- if (context.isPredeclaredClass(expression.className) && !context.insideFunction()) {
17965
- const message = `Class "${expression.className}" is declared further down this file, so it does not exist yet at this point.`;
17966
- context.report("check-class-before-declaration", message, expression.position);
18039
+ const pending = context.insideFunction() ? null : context.pendingDeclarationOf(expression.className);
18040
+ if (pending !== null) {
18041
+ const subject = pending === expression.className ? `Class "${pending}"` : `Class "${expression.className}" extends "${pending}", which`;
18042
+ context.report("check-class-before-declaration", `${subject} is declared further down this file, so it does not exist yet at this point.`, expression.position);
17967
18043
  }
17968
18044
  const constructor = context.declarations.lookupMember(expression.className, "constructor");
17969
18045
  if (constructor !== null && constructor.type.kind === "function") {
@@ -18681,6 +18757,10 @@ function checkMember(context, expression) {
18681
18757
  checkExpression(context, expression.object);
18682
18758
  return context.record(expression, narrowed);
18683
18759
  }
18760
+ if (expression.object.kind === "identifier" && isUserClassReference(context, expression.object.name)) {
18761
+ context.references.add(expression.object.name);
18762
+ return context.record(expression, resolveStaticMember(context, expression.object.name, expression));
18763
+ }
18684
18764
  if (expression.object.kind === "identifier" && isMtaClassReference(context, expression.object.name)) {
18685
18765
  context.references.add(expression.object.name);
18686
18766
  return context.record(expression, resolveMtaStaticMember(context, expression.object.name, expression.property, expression.position)?.type ?? ANY_TYPE);
@@ -18804,6 +18884,13 @@ function checkCall(context, expression) {
18804
18884
  }
18805
18885
  return context.record(expression, checkSignature(context, expression.args, constructor, expression.position));
18806
18886
  }
18887
+ if (expression.method !== null && expression.callee.kind === "identifier" && isUserClassReference(context, expression.callee.name)) {
18888
+ const name = expression.callee.name;
18889
+ const message = `Call the static member "${expression.method}" as "${name}.${expression.method}(...)". A class value has no "self" to pass.`;
18890
+ context.report("check-static-receiver", message, expression.position);
18891
+ checkValueList(context, expression.args);
18892
+ return context.record(expression, ANY_TYPE);
18893
+ }
18807
18894
  if (expression.method === null) {
18808
18895
  context.calledMembers.add(expression.callee);
18809
18896
  }
@@ -18960,6 +19047,26 @@ function syntheticMethodType(context, member, fieldTypes) {
18960
19047
  }
18961
19048
  return buildFunctionType(context, member.parameters, member.returnAnnotation);
18962
19049
  }
19050
+ function checkMemberSpaces(context, info, statement) {
19051
+ for (const member of statement.members) {
19052
+ if (member.isStatic && info.members.has(member.name)) {
19053
+ context.report("check-duplicate-class-member", `Class "${info.name}" declares "${member.name}" as both a static and an instance member.`, member.position);
19054
+ }
19055
+ if (!member.isStatic || info.superClass === null) {
19056
+ continue;
19057
+ }
19058
+ const inherited = context.declarations.lookupStaticMember(info.superClass, member.name);
19059
+ const declared = info.statics.get(member.name);
19060
+ if (inherited === void 0 || inherited === null || declared === void 0) {
19061
+ continue;
19062
+ }
19063
+ const options = { allowNil: context.allowNil };
19064
+ if (!isAssignable(declared.type, inherited.type, options) || !isAssignable(inherited.type, declared.type, options)) {
19065
+ const message = `Static member "${member.name}" must match "${typeToString(inherited.type)}" declared by class "${info.superClass}".`;
19066
+ context.report("check-invalid-override", message, member.position);
19067
+ }
19068
+ }
19069
+ }
18963
19070
  function registerMembers(context, info, statement) {
18964
19071
  const fieldTypes = /* @__PURE__ */ new Map();
18965
19072
  for (const member of statement.members) {
@@ -18972,7 +19079,8 @@ function registerMembers(context, info, statement) {
18972
19079
  for (const member of [...statement.members, ...generated]) {
18973
19080
  const type = member.kind === "class-field" ? fieldTypes.get(member) ?? ANY_TYPE : member.isSynthetic ? syntheticMethodType(context, member, fieldTypes) : buildFunctionType(context, member.parameters, member.returnAnnotation);
18974
19081
  const decorators = member.decorators.map((decorator) => decorator.name);
18975
- info.members.set(member.name, {
19082
+ const space = member.isStatic ? info.statics : info.members;
19083
+ space.set(member.name, {
18976
19084
  name: member.name,
18977
19085
  type,
18978
19086
  isMethod: member.kind === "class-method",
@@ -18981,6 +19089,7 @@ function registerMembers(context, info, statement) {
18981
19089
  deprecated: decorators.includes("Deprecated")
18982
19090
  });
18983
19091
  }
19092
+ checkMemberSpaces(context, info, statement);
18984
19093
  return generated;
18985
19094
  }
18986
19095
  function declareBuilder(context, info, statement) {
@@ -18997,7 +19106,7 @@ function declareBuilder(context, info, statement) {
18997
19106
  }
18998
19107
  }
18999
19108
  members.set("build", { name: "build", type: { kind: "function", parameters: [], minimumArguments: 0, isVariadic: false, returnType: createNamed(statement.name) }, isMethod: true, position: statement.position });
19000
- context.declarations.declareClass({ name, superClass: null, interfaces: [], members, position: statement.position });
19109
+ context.declarations.declareClass({ name, superClass: null, interfaces: [], members, statics: /* @__PURE__ */ new Map(), position: statement.position });
19001
19110
  context.declareModuleGlobal({ name, type: createNamed(name), isLocal: false, position: statement.position });
19002
19111
  }
19003
19112
  function checkMethodBody(context, info, member) {
@@ -19005,10 +19114,14 @@ function checkMethodBody(context, info, member) {
19005
19114
  if (explicitSelf !== void 0) {
19006
19115
  context.report("check-explicit-self-parameter", 'Class methods receive "self" automatically; remove it from the parameter list.', explicitSelf.position);
19007
19116
  }
19008
- const signature = info.members.get(member.name)?.type;
19117
+ const signature = (member.isStatic ? info.statics : info.members).get(member.name)?.type;
19009
19118
  if (signature?.kind !== "function") {
19010
19119
  return;
19011
19120
  }
19121
+ if (member.isStatic) {
19122
+ checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature, null);
19123
+ return;
19124
+ }
19012
19125
  context.pushClassMethod({ className: info.name, methodName: member.name });
19013
19126
  checkFunctionBody(context, member.parameters, member.returnAnnotation, member.body, signature, createNamed(info.name));
19014
19127
  context.popClassMethod();
@@ -19047,6 +19160,7 @@ function declareClassInfo(context, statement) {
19047
19160
  superClass: null,
19048
19161
  interfaces: statement.interfaces,
19049
19162
  members: /* @__PURE__ */ new Map(),
19163
+ statics: /* @__PURE__ */ new Map(),
19050
19164
  position: statement.position
19051
19165
  };
19052
19166
  context.declarations.declareClass(info);
@@ -19246,6 +19360,7 @@ function check(program2, mode, environment = DEFAULT_ENVIRONMENT, options = {})
19246
19360
  diagnostics: sortDiagnostics([...structure, ...directives.diagnostics, ...context.diagnostics]),
19247
19361
  types: context.types,
19248
19362
  references: context.references,
19363
+ staticAccess: context.staticAccess,
19249
19364
  declarations: context.declarations,
19250
19365
  aliases: context.binder.resolvedAliases(),
19251
19366
  declaredGlobals: context.declaredGlobals,
@@ -19362,8 +19477,8 @@ function finalizeEmission(code, markers, sourceLineOffset = 0) {
19362
19477
 
19363
19478
  // ../compiler/src/emitter/state.ts
19364
19479
  var INDENT2 = " ";
19365
- function createEmitState(types, references, generatedMembers) {
19366
- return { types, references, generatedMembers, helpers: /* @__PURE__ */ new Set(), indent: 0, markers: [], symbol: void 0, loopWrap: false };
19480
+ function createEmitState(types, references, generatedMembers, staticAccess = /* @__PURE__ */ new Set()) {
19481
+ return { types, references, staticAccess, generatedMembers, helpers: /* @__PURE__ */ new Set(), indent: 0, markers: [], symbol: void 0, loopWrap: false };
19367
19482
  }
19368
19483
  function requireHelper(state, helper) {
19369
19484
  if (helper !== null) {
@@ -19515,6 +19630,10 @@ function emitTable(state, expression) {
19515
19630
  return `{ ${fields.join(", ")} }`;
19516
19631
  }
19517
19632
  function emitMember(state, expression) {
19633
+ if (state.staticAccess.has(expression) && expression.object.kind === "identifier") {
19634
+ requireHelper(state, "class");
19635
+ return `getClass(${emitString(expression.object.name)}).${expression.property}`;
19636
+ }
19518
19637
  const extension = resolvePropertyExtension(typeOf(state, expression.object), expression.property);
19519
19638
  const object = emitExpression(state, expression.object, UNARY_PRECEDENCE);
19520
19639
  if (extension === null) {
@@ -19609,7 +19728,8 @@ function emitMethod(state, className, member) {
19609
19728
  if (member.generated !== void 0) {
19610
19729
  return emitGeneratedMethod(state, className, member);
19611
19730
  }
19612
- return withSymbol(state, `${className}:${member.name}`, () => emitFunctionBody(state, [self, ...member.parameters], member.body, `${member.name} = function`));
19731
+ const parameters = member.isStatic ? member.parameters : [self, ...member.parameters];
19732
+ return withSymbol(state, `${className}${member.isStatic ? "." : ":"}${member.name}`, () => emitFunctionBody(state, parameters, member.body, `${member.name} = function`));
19613
19733
  }
19614
19734
  function emitGeneratedMethod(state, className, member) {
19615
19735
  const fields = member.generated?.fields ?? [];
@@ -19681,7 +19801,7 @@ function emitMembers(state, statement) {
19681
19801
  state.indent += 1;
19682
19802
  for (const member of statement.members) {
19683
19803
  if (member.kind === "class-method") {
19684
- entries2.push(indentLine(state, `${markSource(state, member.position.line, `${statement.name}:${member.name}`)}${emitMethod(state, statement.name, member)}`));
19804
+ entries2.push(indentLine(state, `${markSource(state, member.position.line, `${statement.name}${member.isStatic ? "." : ":"}${member.name}`)}${emitMethod(state, statement.name, member)}`));
19685
19805
  continue;
19686
19806
  }
19687
19807
  if (member.decorators.some((decorator) => decorator.name === "Lazy")) {
@@ -19923,8 +20043,8 @@ function emitBlock(state, statements) {
19923
20043
  }
19924
20044
  return lines;
19925
20045
  }
19926
- function emit2(program2, types, references, generatedMembers = /* @__PURE__ */ new Map(), sourceLineOffset = 0) {
19927
- const state = createEmitState(types, references, generatedMembers);
20046
+ function emit2(program2, types, references, generatedMembers = /* @__PURE__ */ new Map(), sourceLineOffset = 0, staticAccess = /* @__PURE__ */ new Set()) {
20047
+ const state = createEmitState(types, references, generatedMembers, staticAccess);
19928
20048
  const lines = emitBlock(state, program2.body);
19929
20049
  const markedCode = lines.length === 0 ? "" : `${lines.join("\n")}
19930
20050
  `;
@@ -20176,7 +20296,7 @@ function erasedEdit(source, span) {
20176
20296
  }
20177
20297
  function canonicalEdit(input, statement, span) {
20178
20298
  const { source } = input;
20179
- const emitted = emit2({ ...input.program, body: [statement] }, input.types, input.references, input.generatedMembers, statement.position.line - 1);
20299
+ const emitted = emit2({ ...input.program, body: [statement] }, input.types, input.references, input.generatedMembers, statement.position.line - 1, input.staticAccess);
20180
20300
  const trimmed = span.end < source.length && emitted.code.endsWith("\n") ? emitted.code.slice(0, -1) : emitted.code;
20181
20301
  if (trimmed.length === 0) {
20182
20302
  return erasedEdit(source, span);
@@ -20211,15 +20331,16 @@ function builderClassText(input, statement) {
20211
20331
  }
20212
20332
 
20213
20333
  // ../compiler/src/emitter/preserve-guards.ts
20214
- function isPreservableExpression(expression, types) {
20334
+ var NO_STATIC_ACCESS = /* @__PURE__ */ new Set();
20335
+ function isPreservableExpression(expression, types, statics = NO_STATIC_ACCESS) {
20215
20336
  switch (expression.kind) {
20216
20337
  case "template-literal":
20217
20338
  case "new-expression":
20218
20339
  return false;
20219
20340
  case "member-expression":
20220
- return resolvePropertyExtension(types.get(expression.object) ?? null, expression.property) === null && isPreservableExpression(expression.object, types);
20341
+ return !statics.has(expression) && resolvePropertyExtension(types.get(expression.object) ?? null, expression.property) === null && isPreservableExpression(expression.object, types, statics);
20221
20342
  case "index-expression":
20222
- return isPreservableExpression(expression.object, types) && isPreservableExpression(expression.index, types);
20343
+ return isPreservableExpression(expression.object, types, statics) && isPreservableExpression(expression.index, types, statics);
20223
20344
  case "call-expression":
20224
20345
  if (expression.method === null && expression.callee.kind === "identifier" && expression.callee.name === "super") {
20225
20346
  return false;
@@ -20227,43 +20348,43 @@ function isPreservableExpression(expression, types) {
20227
20348
  if (expression.callee.kind === "member-expression" && resolveCallExtension(types.get(expression.callee.object) ?? null, expression.callee.property) !== null) {
20228
20349
  return false;
20229
20350
  }
20230
- return isPreservableExpression(expression.callee, types) && expression.args.every((argument) => isPreservableExpression(argument, types));
20351
+ return isPreservableExpression(expression.callee, types, statics) && expression.args.every((argument) => isPreservableExpression(argument, types, statics));
20231
20352
  case "table-expression":
20232
20353
  return expression.fields.every(
20233
- (field2) => (field2.key === null || isPreservableExpression(field2.key, types)) && isPreservableExpression(field2.value, types)
20354
+ (field2) => (field2.key === null || isPreservableExpression(field2.key, types, statics)) && isPreservableExpression(field2.value, types, statics)
20234
20355
  );
20235
20356
  case "binary-expression":
20236
- return isPreservableExpression(expression.left, types) && isPreservableExpression(expression.right, types);
20357
+ return isPreservableExpression(expression.left, types, statics) && isPreservableExpression(expression.right, types, statics);
20237
20358
  case "unary-expression":
20238
- return isPreservableExpression(expression.operand, types);
20359
+ return isPreservableExpression(expression.operand, types, statics);
20239
20360
  case "group-expression":
20240
- return isPreservableExpression(expression.expression, types);
20361
+ return isPreservableExpression(expression.expression, types, statics);
20241
20362
  default:
20242
20363
  return true;
20243
20364
  }
20244
20365
  }
20245
- function every(expressions, types) {
20246
- return expressions.every((expression) => isPreservableExpression(expression, types));
20366
+ function every(expressions, types, statics) {
20367
+ return expressions.every((expression) => isPreservableExpression(expression, types, statics));
20247
20368
  }
20248
- function isPreservableStatement(statement, types) {
20369
+ function isPreservableStatement(statement, types, statics = NO_STATIC_ACCESS) {
20249
20370
  switch (statement.kind) {
20250
20371
  case "local-statement":
20251
- return every(statement.values, types);
20372
+ return every(statement.values, types, statics);
20252
20373
  case "assignment-statement":
20253
- return statement.operator === "=" && every(statement.targets, types) && every(statement.values, types);
20374
+ return statement.operator === "=" && every(statement.targets, types, statics) && every(statement.values, types, statics);
20254
20375
  case "call-statement":
20255
- return isPreservableExpression(statement.expression, types);
20376
+ return isPreservableExpression(statement.expression, types, statics);
20256
20377
  case "return-statement":
20257
- return every(statement.values, types);
20378
+ return every(statement.values, types, statics);
20258
20379
  case "while-statement":
20259
20380
  case "repeat-statement":
20260
- return isPreservableExpression(statement.condition, types);
20381
+ return isPreservableExpression(statement.condition, types, statics);
20261
20382
  case "if-statement":
20262
- return statement.clauses.every((clause) => isPreservableExpression(clause.condition, types));
20383
+ return statement.clauses.every((clause) => isPreservableExpression(clause.condition, types, statics));
20263
20384
  case "numeric-for-statement":
20264
- return isPreservableExpression(statement.start, types) && isPreservableExpression(statement.limit, types) && (statement.step === null || isPreservableExpression(statement.step, types));
20385
+ return isPreservableExpression(statement.start, types, statics) && isPreservableExpression(statement.limit, types, statics) && (statement.step === null || isPreservableExpression(statement.step, types, statics));
20265
20386
  case "generic-for-statement":
20266
- return every(statement.iterators, types);
20387
+ return every(statement.iterators, types, statics);
20267
20388
  case "break-statement":
20268
20389
  case "declare-statement":
20269
20390
  case "do-statement":
@@ -20391,7 +20512,7 @@ function classEdits(input, statement, spans) {
20391
20512
  edits.push({ start: span.start, end, replacement: isLazyField(member) ? longComment(text) : blankSpan(text) });
20392
20513
  continue;
20393
20514
  }
20394
- if (member.kind === "class-method") {
20515
+ if (member.kind === "class-method" && !member.isStatic) {
20395
20516
  const self = selfEdit(source, member, span);
20396
20517
  if (self === null) {
20397
20518
  return null;
@@ -20505,7 +20626,7 @@ function surgery(collector, statement) {
20505
20626
  const edits2 = classEdits(input, statement, { span, members: input.spans });
20506
20627
  return edits2 === null ? null : { edits: edits2, wrapsBody: false };
20507
20628
  }
20508
- if (loopBody(statement) === null || !isPreservableStatement(statement, input.types)) {
20629
+ if (loopBody(statement) === null || !isPreservableStatement(statement, input.types, input.staticAccess)) {
20509
20630
  return null;
20510
20631
  }
20511
20632
  const edits = loopEdits(input, statement);
@@ -20534,7 +20655,7 @@ function visit(collector, statement, wrapped) {
20534
20655
  descend(collector, statement, false, surgical.wrapsBody);
20535
20656
  return;
20536
20657
  }
20537
- if (isPreservableStatement(statement, collector.input.types) && keepsScaffolding(statement)) {
20658
+ if (isPreservableStatement(statement, collector.input.types, collector.input.staticAccess) && keepsScaffolding(statement)) {
20538
20659
  const inherited = statement.kind === "do-statement" || statement.kind === "if-statement" ? wrapped : false;
20539
20660
  descend(collector, statement, inherited, false);
20540
20661
  return;
@@ -20687,7 +20808,7 @@ function compile(source, options = {}) {
20687
20808
  return { ...shared, code: null, requiredHelpers: [], lines: [] };
20688
20809
  }
20689
20810
  const references = reachedNames(checked.references, options.projectReferences);
20690
- const emitted = emit2(parsed.program, checked.types, references, checked.generatedMembers);
20811
+ const emitted = emit2(parsed.program, checked.types, references, checked.generatedMembers, 0, checked.staticAccess);
20691
20812
  const preserved = emitPreservingSource({
20692
20813
  source,
20693
20814
  program: parsed.program,
@@ -20697,6 +20818,7 @@ function compile(source, options = {}) {
20697
20818
  types: checked.types,
20698
20819
  references,
20699
20820
  generatedMembers: checked.generatedMembers,
20821
+ staticAccess: checked.staticAccess,
20700
20822
  development: options.development === true
20701
20823
  });
20702
20824
  const required = new Set(emitted.requiredHelpers);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thigasdevelopment/luam",
3
- "version": "0.19.0",
3
+ "version": "0.19.1",
4
4
  "description": "The Luam compiler for Multi Theft Auto resources.",
5
5
  "keywords": [
6
6
  "mta",