ucode-lsp 0.6.16
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/LICENSE +21 -0
- package/README.md +187 -0
- package/bin/ucode-lsp.js +9 -0
- package/dist/cli.js +1 -0
- package/dist/server.js +1 -0
- package/man/ucode-lsp.1 +298 -0
- package/package.json +102 -0
- package/scripts/postinstall.sh +15 -0
package/man/ucode-lsp.1
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
.TH UCODE-LSP 1 "2026-03-18" "0.6.16" "ucode-lsp manual"
|
|
2
|
+
.SH NAME
|
|
3
|
+
ucode-lsp \- language server and static checker for ucode
|
|
4
|
+
.SH SYNOPSIS
|
|
5
|
+
.B ucode-lsp
|
|
6
|
+
[\fIoptions\fR] [\fIpaths\fR...]
|
|
7
|
+
.br
|
|
8
|
+
.B ucode-lsp \-\-stdio
|
|
9
|
+
.SH DESCRIPTION
|
|
10
|
+
.B ucode-lsp
|
|
11
|
+
is a language server and static analysis tool for the ucode scripting
|
|
12
|
+
language used in OpenWrt.
|
|
13
|
+
.PP
|
|
14
|
+
When invoked without a transport flag, it scans \fB.uc\fR files and prints
|
|
15
|
+
diagnostics (errors and warnings) to stdout, similar to \fBtsc\fR.
|
|
16
|
+
When invoked with \fB\-\-stdio\fR, it runs as an LSP server for use with
|
|
17
|
+
editors like Neovim or VS Code.
|
|
18
|
+
.SH MODES
|
|
19
|
+
.TP
|
|
20
|
+
.B (default)
|
|
21
|
+
Check mode. Scans \fB.uc\fR files in the given paths (or the current
|
|
22
|
+
directory) and prints diagnostics. Exits with code 1 if errors are found.
|
|
23
|
+
.TP
|
|
24
|
+
.B \-\-stdio
|
|
25
|
+
LSP server mode. Communicates over stdin/stdout using the Language Server
|
|
26
|
+
Protocol. Used by editors.
|
|
27
|
+
.SH OPTIONS
|
|
28
|
+
.TP
|
|
29
|
+
.B \-\-verbose
|
|
30
|
+
Show all diagnostics including info and hints. By default, only errors and
|
|
31
|
+
warnings are shown.
|
|
32
|
+
.TP
|
|
33
|
+
.B \-\-help
|
|
34
|
+
Show a brief help message and exit.
|
|
35
|
+
.TP
|
|
36
|
+
.B \-\-version
|
|
37
|
+
Show the version number and exit.
|
|
38
|
+
.SH EXIT STATUS
|
|
39
|
+
.TP
|
|
40
|
+
.B 0
|
|
41
|
+
No errors found (warnings may still be present).
|
|
42
|
+
.TP
|
|
43
|
+
.B 1
|
|
44
|
+
One or more errors found.
|
|
45
|
+
.TP
|
|
46
|
+
.B 2
|
|
47
|
+
Invalid usage (unknown option, missing file, etc.).
|
|
48
|
+
.SH OUTPUT FORMAT
|
|
49
|
+
Diagnostic lines are printed to stdout in the format:
|
|
50
|
+
.PP
|
|
51
|
+
.RS
|
|
52
|
+
\fIfile\fR(\fIline\fR,\fIcol\fR): \fIseverity\fR [\fIcode\fR]: \fImessage\fR
|
|
53
|
+
.RE
|
|
54
|
+
.PP
|
|
55
|
+
Summary and error messages are printed to stderr.
|
|
56
|
+
.SH TYPE ANNOTATIONS
|
|
57
|
+
.B ucode-lsp
|
|
58
|
+
uses JSDoc comments to provide type information for static analysis.
|
|
59
|
+
Annotations must use the \fB/** ... */\fR comment style.
|
|
60
|
+
.SS @param \- Parameter Types
|
|
61
|
+
Annotate function parameters with their expected types:
|
|
62
|
+
.PP
|
|
63
|
+
.RS
|
|
64
|
+
.nf
|
|
65
|
+
/**
|
|
66
|
+
* @param {string} name \- The user's name
|
|
67
|
+
* @param {number} age
|
|
68
|
+
*/
|
|
69
|
+
function greet(name, age) { ... }
|
|
70
|
+
.fi
|
|
71
|
+
.RE
|
|
72
|
+
.PP
|
|
73
|
+
An alternative bare syntax is also supported:
|
|
74
|
+
.PP
|
|
75
|
+
.RS
|
|
76
|
+
.nf
|
|
77
|
+
/** @param name string \- The user's name */
|
|
78
|
+
.fi
|
|
79
|
+
.RE
|
|
80
|
+
.SS @returns \- Return Types
|
|
81
|
+
Document the return type of a function:
|
|
82
|
+
.PP
|
|
83
|
+
.RS
|
|
84
|
+
.nf
|
|
85
|
+
/** @returns {string} The greeting message */
|
|
86
|
+
function greet(name) { ... }
|
|
87
|
+
.fi
|
|
88
|
+
.RE
|
|
89
|
+
.PP
|
|
90
|
+
Note: return types are currently parsed for documentation but type inference
|
|
91
|
+
uses the actual return statements.
|
|
92
|
+
.SS @typedef / @property \- Custom Types
|
|
93
|
+
Define named object types with typed properties:
|
|
94
|
+
.PP
|
|
95
|
+
.RS
|
|
96
|
+
.nf
|
|
97
|
+
/**
|
|
98
|
+
* @typedef {object} PkgInfo
|
|
99
|
+
* @property {string} name \- Package name
|
|
100
|
+
* @property {string} version \- Semantic version
|
|
101
|
+
* @property {boolean?} installed \- Whether installed
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
/** @param {PkgInfo} pkg */
|
|
105
|
+
function install(pkg) {
|
|
106
|
+
pkg.name; // autocomplete + type: string
|
|
107
|
+
pkg.installed; // type: boolean | null
|
|
108
|
+
}
|
|
109
|
+
.fi
|
|
110
|
+
.RE
|
|
111
|
+
.PP
|
|
112
|
+
Typedefs are scoped to the file they are defined in.
|
|
113
|
+
.SS Supported Types
|
|
114
|
+
.TP
|
|
115
|
+
.B Primitives
|
|
116
|
+
\fBstring\fR, \fBnumber\fR, \fBinteger\fR (\fBint\fR), \fBdouble\fR (\fBfloat\fR),
|
|
117
|
+
\fBboolean\fR (\fBbool\fR), \fBarray\fR, \fBobject\fR, \fBfunction\fR, \fBnull\fR,
|
|
118
|
+
\fBregex\fR (\fBregexp\fR)
|
|
119
|
+
.TP
|
|
120
|
+
.B Module types
|
|
121
|
+
Builtin modules can be used directly as types:
|
|
122
|
+
\fBfs\fR, \fBuci\fR, \fBubus\fR, \fBuloop\fR, \fBmath\fR, \fBio\fR, \fBlog\fR,
|
|
123
|
+
\fBdebug\fR, \fBdigest\fR, \fBnl80211\fR, \fBresolv\fR, \fBrtnl\fR, \fBsocket\fR,
|
|
124
|
+
\fBstruct\fR, \fBzlib\fR.
|
|
125
|
+
The \fBmodule:\fR prefix is also accepted: \fB{module:fs}\fR.
|
|
126
|
+
.TP
|
|
127
|
+
.B Object types
|
|
128
|
+
Module object types provide method/property completion:
|
|
129
|
+
\fBfs.file\fR, \fBfs.dir\fR, \fBfs.proc\fR, \fBfs.statvfs\fR,
|
|
130
|
+
\fBio.handle\fR, \fBuci.cursor\fR, \fBnl80211.listener\fR,
|
|
131
|
+
\fBuloop.timer\fR, \fBuloop.handle\fR, \fBuloop.process\fR, \fBuloop.task\fR,
|
|
132
|
+
\fBuloop.interval\fR, \fBuloop.signal\fR, \fBuloop.pipe\fR,
|
|
133
|
+
\fBexception\fR.
|
|
134
|
+
.TP
|
|
135
|
+
.B Union types
|
|
136
|
+
Combine types with \fB|\fR: \fB{string|number}\fR, \fB{fs.file|null}\fR.
|
|
137
|
+
.TP
|
|
138
|
+
.B Optional types
|
|
139
|
+
Append \fB?\fR to make a type nullable: \fB{string?}\fR is equivalent to
|
|
140
|
+
\fB{string|null}\fR.
|
|
141
|
+
.TP
|
|
142
|
+
.B import() expressions
|
|
143
|
+
Reference types from other modules:
|
|
144
|
+
.RS
|
|
145
|
+
.nf
|
|
146
|
+
{import('fs')} \- builtin module type
|
|
147
|
+
{import('fs').file} \- object type from module
|
|
148
|
+
{import('./config')} \- default export from local file
|
|
149
|
+
{import('./config').name} \- named export or default export property
|
|
150
|
+
.fi
|
|
151
|
+
.RE
|
|
152
|
+
.SS Cross\-File Types with import()
|
|
153
|
+
You can reference types from other \fB.uc\fR files using import().
|
|
154
|
+
.PP
|
|
155
|
+
Named exports (\fBexport const\fR, \fBexport function\fR):
|
|
156
|
+
.PP
|
|
157
|
+
.RS
|
|
158
|
+
.nf
|
|
159
|
+
// lib/types.uc
|
|
160
|
+
export const config = {
|
|
161
|
+
host: 'localhost',
|
|
162
|
+
port: 8080,
|
|
163
|
+
enabled: true,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// main.uc
|
|
167
|
+
/** @param {import('./lib/types').config} cfg */
|
|
168
|
+
function start(cfg) {
|
|
169
|
+
cfg.host; // autocomplete + type: string
|
|
170
|
+
cfg.port; // type: number
|
|
171
|
+
cfg.enabled; // type: boolean
|
|
172
|
+
}
|
|
173
|
+
.fi
|
|
174
|
+
.RE
|
|
175
|
+
.PP
|
|
176
|
+
Default exports:
|
|
177
|
+
.PP
|
|
178
|
+
.RS
|
|
179
|
+
.nf
|
|
180
|
+
// lib/types.uc
|
|
181
|
+
export default {
|
|
182
|
+
host: 'localhost',
|
|
183
|
+
port: 8080,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// main.uc
|
|
187
|
+
/** @param {import('./lib/types')} config */
|
|
188
|
+
function start(config) {
|
|
189
|
+
config.host; // type: string
|
|
190
|
+
config.port; // type: number
|
|
191
|
+
}
|
|
192
|
+
.fi
|
|
193
|
+
.RE
|
|
194
|
+
.PP
|
|
195
|
+
You can also access a property of the default export:
|
|
196
|
+
.PP
|
|
197
|
+
.RS
|
|
198
|
+
.nf
|
|
199
|
+
// lib/types.uc
|
|
200
|
+
export default {
|
|
201
|
+
db: { host: 'localhost', port: 5432 },
|
|
202
|
+
app: { name: 'myapp', debug: false },
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// main.uc
|
|
206
|
+
/** @param {import('./lib/types').db} conn */
|
|
207
|
+
function connect(conn) {
|
|
208
|
+
conn.host; // type: string
|
|
209
|
+
conn.port; // type: number
|
|
210
|
+
}
|
|
211
|
+
.fi
|
|
212
|
+
.RE
|
|
213
|
+
.PP
|
|
214
|
+
When a name matches both a named export and a default export property,
|
|
215
|
+
the named export takes priority.
|
|
216
|
+
.SS Strict Mode
|
|
217
|
+
When a file contains \fB'use strict'\fR, the analyzer emits info\-level
|
|
218
|
+
diagnostics (UC7003) for function parameters that lack \fB@param\fR
|
|
219
|
+
annotations. Use \fB\-\-verbose\fR in check mode to see these.
|
|
220
|
+
.SH DIAGNOSTIC CODES
|
|
221
|
+
.SS Parser Errors
|
|
222
|
+
Syntax errors detected during parsing.
|
|
223
|
+
.SS Semantic Diagnostics (ucode-semantic)
|
|
224
|
+
.TP
|
|
225
|
+
.B UC1005
|
|
226
|
+
Variable shadows a variable from an outer scope.
|
|
227
|
+
.TP
|
|
228
|
+
.B UC2006, UC2007
|
|
229
|
+
printf/sprintf format string errors: wrong number of arguments or
|
|
230
|
+
incompatible argument types.
|
|
231
|
+
.TP
|
|
232
|
+
.B UC4001
|
|
233
|
+
Unreachable code after return, break, continue, or die()/exit().
|
|
234
|
+
.TP
|
|
235
|
+
.B UC7001
|
|
236
|
+
Unknown type in @param annotation.
|
|
237
|
+
.TP
|
|
238
|
+
.B UC7002
|
|
239
|
+
@param name does not match any function parameter.
|
|
240
|
+
.TP
|
|
241
|
+
.B UC7003
|
|
242
|
+
Function parameters missing @param annotations (strict mode only).
|
|
243
|
+
.TP
|
|
244
|
+
.B incompatible\-function\-argument
|
|
245
|
+
Argument type does not match what the builtin function expects.
|
|
246
|
+
.TP
|
|
247
|
+
.B nullable\-argument
|
|
248
|
+
Argument may be null where a non\-null value is required.
|
|
249
|
+
.SH EDITOR SETUP
|
|
250
|
+
.SS Neovim (0.11+)
|
|
251
|
+
Add to \fB~/.config/nvim/init.lua\fR:
|
|
252
|
+
.PP
|
|
253
|
+
.RS
|
|
254
|
+
.nf
|
|
255
|
+
vim.filetype.add({ extension = { uc = 'ucode' } })
|
|
256
|
+
|
|
257
|
+
vim.lsp.config('ucode', {
|
|
258
|
+
cmd = { 'ucode-lsp', '\-\-stdio' },
|
|
259
|
+
filetypes = { 'ucode' },
|
|
260
|
+
root_markers = { '.git' },
|
|
261
|
+
})
|
|
262
|
+
vim.lsp.enable('ucode')
|
|
263
|
+
.fi
|
|
264
|
+
.RE
|
|
265
|
+
.SS VS Code
|
|
266
|
+
Install the \fBucode Language Support\fR extension from the VS Code
|
|
267
|
+
marketplace.
|
|
268
|
+
.SH EXAMPLES
|
|
269
|
+
Check all .uc files in the current directory:
|
|
270
|
+
.PP
|
|
271
|
+
.RS
|
|
272
|
+
.B ucode-lsp
|
|
273
|
+
.RE
|
|
274
|
+
.PP
|
|
275
|
+
Check a specific directory:
|
|
276
|
+
.PP
|
|
277
|
+
.RS
|
|
278
|
+
.B ucode-lsp src/
|
|
279
|
+
.RE
|
|
280
|
+
.PP
|
|
281
|
+
Check a single file with verbose output:
|
|
282
|
+
.PP
|
|
283
|
+
.RS
|
|
284
|
+
.B ucode-lsp \-\-verbose router.uc
|
|
285
|
+
.RE
|
|
286
|
+
.PP
|
|
287
|
+
Pipe diagnostics to count errors:
|
|
288
|
+
.PP
|
|
289
|
+
.RS
|
|
290
|
+
.B ucode-lsp src/ | grep \-c error
|
|
291
|
+
.RE
|
|
292
|
+
.SH AUTHORS
|
|
293
|
+
Noah B. Peterson
|
|
294
|
+
.SH SEE ALSO
|
|
295
|
+
.BR node (1),
|
|
296
|
+
.BR nvim (1)
|
|
297
|
+
.PP
|
|
298
|
+
GitHub: https://github.com/NoahBPeterson/ucode-lsp
|
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ucode-lsp",
|
|
3
|
+
"displayName": "ucode Language Support",
|
|
4
|
+
"description": "Language Server Protocol support for ucode scripting language",
|
|
5
|
+
"version": "0.6.16",
|
|
6
|
+
"publisher": "noahbpeterson",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/NoahBPeterson/ucode-lsp"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"bin": {
|
|
13
|
+
"ucode-lsp": "./bin/ucode-lsp.js"
|
|
14
|
+
},
|
|
15
|
+
"man": "./man/ucode-lsp.1",
|
|
16
|
+
"engines": {
|
|
17
|
+
"vscode": "^1.86.0"
|
|
18
|
+
},
|
|
19
|
+
"categories": [
|
|
20
|
+
"Programming Languages"
|
|
21
|
+
],
|
|
22
|
+
"main": "./dist/extension.js",
|
|
23
|
+
"contributes": {
|
|
24
|
+
"languages": [
|
|
25
|
+
{
|
|
26
|
+
"id": "ucode",
|
|
27
|
+
"aliases": [
|
|
28
|
+
"ucode",
|
|
29
|
+
"uCode"
|
|
30
|
+
],
|
|
31
|
+
"extensions": [
|
|
32
|
+
".uc"
|
|
33
|
+
],
|
|
34
|
+
"configuration": "./language-configuration.json",
|
|
35
|
+
"mimetypes": [
|
|
36
|
+
"text/x-ucode"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"grammars": [
|
|
41
|
+
{
|
|
42
|
+
"language": "ucode",
|
|
43
|
+
"scopeName": "source.ucode",
|
|
44
|
+
"path": "./syntaxes/ucode.tmLanguage.json"
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"iconThemes": [
|
|
48
|
+
{
|
|
49
|
+
"id": "ucode-icons",
|
|
50
|
+
"label": "ucode File Icons",
|
|
51
|
+
"path": "./icons/ucode-icon-theme.json"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"configuration": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"title": "ucode",
|
|
57
|
+
"properties": {
|
|
58
|
+
"ucode.maxNumberOfProblems": {
|
|
59
|
+
"scope": "resource",
|
|
60
|
+
"type": "number",
|
|
61
|
+
"default": 100,
|
|
62
|
+
"description": "Controls the maximum number of problems produced by the server."
|
|
63
|
+
},
|
|
64
|
+
"ucode.trace.server": {
|
|
65
|
+
"scope": "window",
|
|
66
|
+
"type": "string",
|
|
67
|
+
"enum": [
|
|
68
|
+
"off",
|
|
69
|
+
"messages",
|
|
70
|
+
"verbose"
|
|
71
|
+
],
|
|
72
|
+
"default": "off",
|
|
73
|
+
"description": "Traces the communication between VS Code and the language server."
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"vscode:prepublish": "bun run package",
|
|
80
|
+
"compile": "webpack",
|
|
81
|
+
"package": "webpack --mode production --devtool hidden-source-map",
|
|
82
|
+
"watch": "webpack --watch",
|
|
83
|
+
"postinstall": "./scripts/postinstall.sh"
|
|
84
|
+
},
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"effect": "^3.19.19",
|
|
87
|
+
"vscode-languageclient": "^8.1.0",
|
|
88
|
+
"vscode-languageserver": "^9.0.1",
|
|
89
|
+
"vscode-languageserver-textdocument": "^1.0.12"
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@types/bun": "latest",
|
|
93
|
+
"@types/node": "24.0.14",
|
|
94
|
+
"@types/vscode": "^1.86.0",
|
|
95
|
+
"@vscode/vsce": "^3.6.1",
|
|
96
|
+
"mocha": "^11.7.1",
|
|
97
|
+
"ts-loader": "^9.5.2",
|
|
98
|
+
"typescript": "^5.8.3",
|
|
99
|
+
"webpack": "^5.100.1",
|
|
100
|
+
"webpack-cli": "^6.0.1"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Link man page into the npm prefix's man directory on global install.
|
|
3
|
+
# Silently skip if not a global install or if permissions prevent linking.
|
|
4
|
+
|
|
5
|
+
# Only run for global installs
|
|
6
|
+
[ "$npm_config_global" = "true" ] || exit 0
|
|
7
|
+
|
|
8
|
+
prefix="$(npm config get prefix 2>/dev/null)" || exit 0
|
|
9
|
+
mandir="$prefix/share/man/man1"
|
|
10
|
+
src="$(dirname "$0")/../man/ucode-lsp.1"
|
|
11
|
+
|
|
12
|
+
[ -d "$mandir" ] || exit 0
|
|
13
|
+
[ -f "$src" ] || exit 0
|
|
14
|
+
|
|
15
|
+
ln -sf "$(cd "$(dirname "$src")" && pwd)/$(basename "$src")" "$mandir/ucode-lsp.1" 2>/dev/null || true
|