Replace the luals lint config with emmylua

fmtk 2.1.4 onwards generates typedefs targeting emmylua that luals
misreads, and every fmtk changelog since 2.1.5 states luals support is
being dropped. luals 3.18.2 is already the latest release, so there is
nothing to bump.

The `--clusterio-modules` plugin has no emmylua equivalent, as emmylua
has no plugin interface, so it is reimplemented as `workspace.moduleMap`.
Those rules rewrite each file's own module path rather than the require
string, hence the reversed direction.

type.patch.lua is obsolete: `raise_event` now takes `LuaEventType` in
the generated typedefs, and `LuaObject` has become `LuaObject.base`.
exp_scenario/.luacheckrc was already dead, luacheck is never invoked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
bbassie
2026-08-07 15:31:18 +00:00
co-authored by Claude Opus 5
parent 70471c5085
commit c6da1fd9ac
6 changed files with 136 additions and 1915 deletions
+42
View File
@@ -0,0 +1,42 @@
{
"$schema": "https://raw.githubusercontent.com/EmmyLuaLs/emmylua-analyzer-rust/refs/heads/main/crates/emmylua_code_analysis/resources/schema.json",
"runtime": {
"version": "Lua5.2",
"requirePattern": [ "?", "?.lua" ]
},
"workspace": {
"$comment-moduleMap": "Replaces the fmtk --clusterio-modules plugin, rewrites each file's own module path rather than the require string",
"ignoreDir": [ ".github", "web", "dist", "factorio" ],
"ignoreGlobs": [ "**/node_modules/**", "**/dist/**" ],
"moduleMap": [
{ "pattern": "^([^.]+)\\.module\\.module_exports$", "replace": "modules.$1" },
{ "pattern": "^([^.]+)\\.module\\.(.+)$", "replace": "modules.$1.$2" }
]
},
"doc": {
"privateName": [ "__*" ]
},
"$comment-disable": "Carried over from the luals config, which had these as editor only rather than checked in ci",
"$comment-unnecessary-if": "Disabled by the config fmtk generates for itself, the api union types make it unreliable",
"diagnostics": {
"globals": [ "__DebugAdapter", "__Profiler" ],
"disable": [
"assign-type-mismatch",
"await-in-sync",
"invert-if",
"missing-parameter",
"missing-return-value",
"param-type-mismatch",
"preferred-local-alias",
"redefined-local",
"redundant-parameter",
"redundant-return-value",
"return-type-mismatch",
"unbalanced-assignments",
"undefined-doc-param",
"unnecessary-assert",
"unnecessary-if",
"unused"
]
}
}
+45 -28
View File
@@ -1,76 +1,93 @@
name: FMTK Lint name: Lua Lint
on: on:
push: push:
pull_request: pull_request:
env:
EMMYLUA_CHECK_VERSION: "0.24.0"
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Checkout clusterio modules
uses: actions/checkout@v4
with:
repository: clusterio/clusterio
path: .clusterio
sparse-checkout: packages/host/modules
sparse-checkout-cone-mode: false
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:
version: 10 version: 10
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: lts/* node-version: lts/*
- name: Install FMTK - name: Generate Factorio typedefs
run: | run: |
# Pinned: 2.1.4+ generates typedefs targeting EmmyLua that LuaLS misreads pnpm install factoriomod-debug
pnpm install factoriomod-debug@2.1.3 pnpm exec fmtk luals-addon "$RUNNER_TEMP/factorio"
pnpm exec fmtk luals-addon - name: Install emmylua_check
jq '.["workspace.library"] += ["${{ github.workspace }}/factorio/library"] | .["runtime.plugin"] = "${{ github.workspace }}/factorio/plugin.lua"' .luarc.json > temp.luarc.json
jq -s '.[0] * .[1].settings' temp.luarc.json ${{ github.workspace }}/factorio/config.json > check.luarc.json
- name: Install LuaLS
run: | run: |
wget https://github.com/LuaLS/lua-language-server/releases/download/3.18.2/lua-language-server-3.18.2-linux-x64.tar.gz -q -O lusls.tar.gz curl -fsSL "https://github.com/EmmyLuaLs/emmylua-analyzer-rust/releases/download/${EMMYLUA_CHECK_VERSION}/emmylua_check-linux-x64.tar.gz" \
mkdir luals && tar -xf lusls.tar.gz -C luals && rm lusls.tar.gz | tar -xz -C "$RUNNER_TEMP"
- name: Run Lint Report - name: Run Lint Report
shell: bash shell: bash
run: | run: |
./luals/bin/lua-language-server --check=. --logpath=. --configpath=check.luarc.json --checklevel=Information --check_out_path=check.json # Library paths are machine specific, so they are merged in rather than committed
jq -n --arg lib "$RUNNER_TEMP/factorio/library" --arg clusterio "$PWD/.clusterio/packages/host" \
'{ workspace: { library: [ $lib, $clusterio ], ignoreGlobs: [ ".clusterio/**" ] } }' \
> "$RUNNER_TEMP/ci.emmyrc.json"
# Exits non zero on error severity, so the gate below is used instead
"$RUNNER_TEMP/emmylua_check" . --config ".emmyrc.json,$RUNNER_TEMP/ci.emmyrc.json" \
--output-format json --output check.json || true
# Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml # Credit to https://github.com/Krealle/luals-check-action/blob/main/action.yml
# Although some minor fixes were needed # Although some minor fixes were needed
# Format and print the messages (would be nice to format as a table, but that's too complex for jq) # Format and print the messages (would be nice to format as a table, but that's too complex for jq)
cat check.json | \ jq -r --arg root "$PWD/" \
jq -r \ '.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
'to_entries | map(.key as $file | .value[] |
{ {
file: $file | sub("file://${{ github.workspace }}/./"; ""), file: $file,
code: .code, code: .code,
line: .range.start.line, line: .range.start.line,
message: (.message | split("\n") message: (.message | split("\n")
| map(if startswith("- ") then .[2:] else . end) | map(if startswith("- ") then .[2:] else . end)
| join("\n")), | join("\n")),
severity: (if .severity <= 1 then "ERR" else "WARN" end) severity: (if .severity <= 1 then "ERR" else "WARN" end)
}) | } |
map("**[\(.severity)] \(.code):** \(.file)#L\(.line)<br><code>\(.message)</code>") | .[]' \ "**[\(.severity)] \(.code):** \(.file)#L\(.line + 1)<br><code>\(.message)</code>"' \
> $GITHUB_STEP_SUMMARY check.json > "$GITHUB_STEP_SUMMARY"
echo "" echo ""
# Github Annotations (limited to 10) # Github Annotations (limited to 10)
cat check.json | \ jq -r --arg root "$PWD/" \
jq -r \ '.[] | (.file | ltrimstr($root)) as $file | .diagnostics[] |
'to_entries | map(.key as $file | .value[] |
{ {
file: $file | sub("file://${{ github.workspace }}/./"; ""), file: $file,
title: .code, title: .code,
line: .range.start.line, line: .range.start.line,
endLine: .range.end.line, endLine: .range.end.line,
col: .range.start.character, col: .range.start.character,
endColumn: .range.end.character, endColumn: .range.end.character,
message: .message | gsub("\n"; "%0A"; "m"), message: (.message | gsub("\n"; "%0A"; "m")),
level: (if .severity <= 1 then "error" else "warning" end) level: (if .severity <= 1 then "error" else "warning" end)
}) | } |
map("::\(.level) file=\(.file),line=\(.line+1),endLine=\(.line+1),col=\(.col+1),endColumn=\(.endColumn+1),title=\(.title)::\(.message) (\(.title))") | .[]' "::\(.level) file=\(.file),line=\(.line + 1),endLine=\(.endLine + 1),col=\(.col + 1),endColumn=\(.endColumn + 1),title=\(.title)::\(.message) (\(.title))"' \
check.json
if [[ $(wc -l < check.json) > 1 ]] ; then # An entry is emitted for every file checked, including clean ones, so
# the gate counts diagnostics and asserts the workspace was actually read
if [[ $(jq 'length' check.json) -lt 100 ]] ; then
echo "::error::Only $(jq 'length' check.json) files were checked, expected the whole workspace"
exit 1
elif [[ $(jq '[.[].diagnostics[]] | length' check.json) -gt 0 ]] ; then
exit 1 exit 1
else else
echo "✅ All checks succeeded!" | tee $GITHUB_STEP_SUMMARY echo "✅ All checks succeeded!" | tee "$GITHUB_STEP_SUMMARY"
fi fi
+1
View File
@@ -1,3 +1,4 @@
dist/ dist/
node_modules/ node_modules/
.vscode .vscode
.luarc.json
-103
View File
@@ -1,103 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"workspace.ignoreDir": [
".vscode", ".github", "luals", "factorio", "web"
],
"completion.requireSeparator": "/",
"runtime.pluginArgs": [
"--clusterio-modules"
],
"doc": {
"regengine": "glob",
"privateName": [ "__*" ],
"packageName": [ "_*" ]
},
"type": {
"checkTableShape": true,
"inferParamType": true
},
"$comment-name-style-check": "Disabled below until config issue fixed: https://github.com/LuaLS/lua-language-server/issues/2643",
"$comment-type-mismatch": "Disabled unless opened due to performance concerns, time reduced to 10s from 400s",
"diagnostics": {
"unusedLocalExclude": [ "_*", "i", "j", "k", "v" ],
"groupFileStatus": {
"ambiguity": "Any",
"await": "None",
"codestyle": "Opened",
"conventions": "Any",
"duplicate": "Any",
"global": "Any",
"luadoc": "Opened",
"redefined": "Opened",
"strict": "Any",
"strong": "Any",
"type-check": "Any",
"unbalanced": "Opened",
"unused": "Opened"
},
"neededFileStatus": {
"no-unknown": "None!",
"spell-check": "None!",
"name-style-check": "None!",
"assign-type-mismatch": "Opened!",
"return-type-mismatch": "Opened!",
"param-type-mismatch": "Opened!"
}
},
"nameStyle.config": {
"local_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"module_local_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "upper_snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "pascal_case"
}],
"function_param_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"function_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"local_function_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"table_field_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}],
"global_variable_name_style": [{
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "snake_case"
}, {
"type" : "pattern",
"param": "_?_?(\\S*)",
"$1": "upper_snake_case"
}],
"module_name_style": [ "pascal_case", "snake_case" ],
"require_module_name_style": [ "pascal_case", "snake_case" ],
"class_name_style": "pascal_case",
"const_variable_name_style": "upper_snake_case"
},
"format.defaultConfig": {
"continuation_indent.in_expr": "0"
}
}
File diff suppressed because it is too large Load Diff
-39
View File
@@ -1,39 +0,0 @@
---@meta
---@class script
script = {
---Raise an event. Only events generated with [LuaBootstrap::generate\_event\_name](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#generate_event_name) and the following can be raised:
---
---Events that can be raised manually:
---
---* [on\_console\_chat](https://lua-api.factorio.com/latest/events.html#on_console_chat)
---* [on\_player\_crafted\_item](https://lua-api.factorio.com/latest/events.html#on_player_crafted_item)
---* [on\_player\_fast\_transferred](https://lua-api.factorio.com/latest/events.html#on_player_fast_transferred)
---* [on\_biter\_base\_built](https://lua-api.factorio.com/latest/events.html#on_biter_base_built)
---* [on\_market\_item\_purchased](https://lua-api.factorio.com/latest/events.html#on_market_item_purchased)
---* [script\_raised\_built](https://lua-api.factorio.com/latest/events.html#script_raised_built)
---* [script\_raised\_destroy](https://lua-api.factorio.com/latest/events.html#script_raised_destroy)
---* [script\_raised\_revive](https://lua-api.factorio.com/latest/events.html#script_raised_revive)
---* [script\_raised\_teleported](https://lua-api.factorio.com/latest/events.html#script_raised_teleported)
---* [script\_raised\_set\_tiles](https://lua-api.factorio.com/latest/events.html#script_raised_set_tiles)
---
---### Example
---
---```
----- Raise the on_console_chat event with the desired message 'from' the first player
---local data = {player_index = 1, message = "Hello friends!"}
---script.raise_event(defines.events.on_console_chat, data)
---```
---
---[View Documentation](https://lua-api.factorio.com/latest/classes/LuaBootstrap.html#raise_event)
---
--- Type patched in 2.0.28: [Bug Report](https://forums.factorio.com/viewtopic.php?f=233&t=125062)
--- Changed "event" from "string | integer" to "LuaEventType"
--- Resolved in 2.0.29, this patch will be removed was version is stable
---@param event LuaEventType ID or name of the event to raise.
---@param data table Table with extra data that will be passed to the event handler. Any invalid LuaObjects will silently stop the event from being raised.
raise_event = function(event, data) end;
}
---@class LuaObject:userdata
--https://github.com/justarandomgeek/vscode-factoriomod-debug/issues/165