@tishlang/tish 1.3.7 → 1.4.2
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 +1 -1
- package/bin/tish +0 -0
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish_lint/Cargo.toml +1 -0
- package/crates/tish_lint/src/bin/tish-lint.rs +141 -23
- package/crates/tish_lint/src/lib.rs +3 -1
- package/crates/tish_lsp/README.md +1 -1
- package/package.json +1 -8
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Pay It Forward License (PIF)
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 The Tish Project Authors
|
|
3
|
+
Copyright (c) 2025-present The Tish Project Authors
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
6
|
|
package/bin/tish
CHANGED
|
Binary file
|
package/crates/tish/Cargo.toml
CHANGED
|
@@ -12,6 +12,7 @@ path = "src/bin/tish-lint.rs"
|
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
14
|
clap = { version = "4.6.0", features = ["derive"] }
|
|
15
|
+
serde_json = "1.0"
|
|
15
16
|
walkdir = "2"
|
|
16
17
|
tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
|
|
17
18
|
tishlang_parser = { path = "../tish_parser", version = ">=0.1" }
|
|
@@ -3,30 +3,54 @@
|
|
|
3
3
|
use std::fs;
|
|
4
4
|
use std::path::{Path, PathBuf};
|
|
5
5
|
|
|
6
|
-
use clap::Parser;
|
|
6
|
+
use clap::{Parser, ValueEnum};
|
|
7
|
+
use serde_json::json;
|
|
8
|
+
|
|
9
|
+
#[derive(Clone, Copy, Debug, ValueEnum)]
|
|
10
|
+
enum OutputFormat {
|
|
11
|
+
Text,
|
|
12
|
+
Sarif,
|
|
13
|
+
}
|
|
7
14
|
|
|
8
15
|
#[derive(Parser)]
|
|
9
16
|
#[command(name = "tish-lint")]
|
|
10
17
|
#[command(about = "AST-based linter for Tish")]
|
|
11
18
|
struct Cli {
|
|
19
|
+
/// Output format (SARIF 2.1.0 for code scanning integrations).
|
|
20
|
+
#[arg(long = "format", value_enum, default_value_t = OutputFormat::Text)]
|
|
21
|
+
output_format: OutputFormat,
|
|
22
|
+
|
|
12
23
|
#[arg(required = true)]
|
|
13
24
|
paths: Vec<String>,
|
|
14
25
|
}
|
|
15
26
|
|
|
27
|
+
#[derive(Debug)]
|
|
28
|
+
struct Issue {
|
|
29
|
+
path: PathBuf,
|
|
30
|
+
line: u32,
|
|
31
|
+
col: u32,
|
|
32
|
+
code: String,
|
|
33
|
+
message: String,
|
|
34
|
+
level: &'static str,
|
|
35
|
+
}
|
|
36
|
+
|
|
16
37
|
fn main() {
|
|
17
38
|
let cli = Cli::parse();
|
|
18
|
-
if let Err(e) = run(&cli.paths) {
|
|
39
|
+
if let Err(e) = run(&cli.paths, cli.output_format) {
|
|
19
40
|
eprintln!("{}", e);
|
|
20
41
|
std::process::exit(1);
|
|
21
42
|
}
|
|
22
43
|
}
|
|
23
44
|
|
|
24
|
-
fn
|
|
45
|
+
fn collect_files(paths: &[String]) -> Result<Vec<PathBuf>, String> {
|
|
25
46
|
let mut files: Vec<PathBuf> = Vec::new();
|
|
26
47
|
for p in paths {
|
|
27
48
|
let path = Path::new(p);
|
|
28
49
|
if path.is_dir() {
|
|
29
|
-
for e in walkdir::WalkDir::new(path)
|
|
50
|
+
for e in walkdir::WalkDir::new(path)
|
|
51
|
+
.into_iter()
|
|
52
|
+
.filter_map(|e| e.ok())
|
|
53
|
+
{
|
|
30
54
|
if e.path().extension().map(|x| x == "tish").unwrap_or(false) {
|
|
31
55
|
files.push(e.path().to_path_buf());
|
|
32
56
|
}
|
|
@@ -40,38 +64,132 @@ fn run(paths: &[String]) -> Result<(), String> {
|
|
|
40
64
|
if files.is_empty() {
|
|
41
65
|
return Err("No .tish files to lint".into());
|
|
42
66
|
}
|
|
43
|
-
|
|
67
|
+
Ok(files)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn run(paths: &[String], format: OutputFormat) -> Result<(), String> {
|
|
71
|
+
let files = collect_files(paths)?;
|
|
72
|
+
let mut issues: Vec<Issue> = Vec::new();
|
|
44
73
|
for f in files {
|
|
45
74
|
let src = fs::read_to_string(&f).map_err(|e| format!("{}: {}", f.display(), e))?;
|
|
46
75
|
match tishlang_lint::lint_source(&src) {
|
|
47
76
|
Ok(diags) => {
|
|
48
77
|
for d in diags {
|
|
49
|
-
let
|
|
50
|
-
tishlang_lint::Severity::Error =>
|
|
51
|
-
errors += 1;
|
|
52
|
-
"error"
|
|
53
|
-
}
|
|
78
|
+
let level = match d.severity {
|
|
79
|
+
tishlang_lint::Severity::Error => "error",
|
|
54
80
|
tishlang_lint::Severity::Warning => "warning",
|
|
55
81
|
};
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
d.
|
|
60
|
-
d.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
);
|
|
82
|
+
issues.push(Issue {
|
|
83
|
+
path: f.clone(),
|
|
84
|
+
line: d.line,
|
|
85
|
+
col: d.col,
|
|
86
|
+
code: d.code.to_string(),
|
|
87
|
+
message: d.message,
|
|
88
|
+
level,
|
|
89
|
+
});
|
|
65
90
|
}
|
|
66
91
|
}
|
|
67
92
|
Err(e) => {
|
|
68
|
-
|
|
69
|
-
|
|
93
|
+
issues.push(Issue {
|
|
94
|
+
path: f.clone(),
|
|
95
|
+
line: 1,
|
|
96
|
+
col: 1,
|
|
97
|
+
code: "tish-parse-error".into(),
|
|
98
|
+
message: e,
|
|
99
|
+
level: "error",
|
|
100
|
+
});
|
|
70
101
|
}
|
|
71
102
|
}
|
|
72
103
|
}
|
|
73
|
-
|
|
74
|
-
|
|
104
|
+
|
|
105
|
+
let error_count = issues.iter().filter(|i| i.level == "error").count();
|
|
106
|
+
|
|
107
|
+
match format {
|
|
108
|
+
OutputFormat::Text => {
|
|
109
|
+
for i in &issues {
|
|
110
|
+
println!(
|
|
111
|
+
"{}:{}:{}: {} [{}] {}",
|
|
112
|
+
i.path.display(),
|
|
113
|
+
i.line,
|
|
114
|
+
i.col,
|
|
115
|
+
i.level,
|
|
116
|
+
i.code,
|
|
117
|
+
i.message
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if error_count > 0 {
|
|
121
|
+
return Err(format!("{} issue(s)", error_count));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
OutputFormat::Sarif => {
|
|
125
|
+
print_sarif(&issues)?;
|
|
126
|
+
if error_count > 0 {
|
|
127
|
+
return Err(format!("{} issue(s)", error_count));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
75
130
|
}
|
|
131
|
+
|
|
132
|
+
Ok(())
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fn print_sarif(issues: &[Issue]) -> Result<(), String> {
|
|
136
|
+
let rules: Vec<_> = tishlang_lint::RULES
|
|
137
|
+
.iter()
|
|
138
|
+
.map(|(id, desc)| {
|
|
139
|
+
json!({
|
|
140
|
+
"id": id,
|
|
141
|
+
"name": id,
|
|
142
|
+
"shortDescription": { "text": desc },
|
|
143
|
+
"helpUri": "https://tishlang.com/docs/reference/linting/"
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
.chain(std::iter::once(json!({
|
|
147
|
+
"id": "tish-parse-error",
|
|
148
|
+
"name": "tish-parse-error",
|
|
149
|
+
"shortDescription": { "text": "Source failed to parse as Tish." },
|
|
150
|
+
"helpUri": "https://tishlang.com/docs/language/overview/"
|
|
151
|
+
})))
|
|
152
|
+
.collect();
|
|
153
|
+
|
|
154
|
+
let results: Vec<_> = issues
|
|
155
|
+
.iter()
|
|
156
|
+
.map(|i| {
|
|
157
|
+
let uri = i.path.to_str().unwrap_or("unknown").replace('\\', "/");
|
|
158
|
+
json!({
|
|
159
|
+
"ruleId": i.code,
|
|
160
|
+
"level": i.level,
|
|
161
|
+
"message": { "text": i.message },
|
|
162
|
+
"locations": [{
|
|
163
|
+
"physicalLocation": {
|
|
164
|
+
"artifactLocation": { "uri": uri },
|
|
165
|
+
"region": {
|
|
166
|
+
"startLine": i.line,
|
|
167
|
+
"startColumn": i.col
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}]
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
.collect();
|
|
174
|
+
|
|
175
|
+
let doc = json!({
|
|
176
|
+
"version": "2.1.0",
|
|
177
|
+
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
|
178
|
+
"runs": [{
|
|
179
|
+
"tool": {
|
|
180
|
+
"driver": {
|
|
181
|
+
"name": "tish-lint",
|
|
182
|
+
"informationUri": "https://tishlang.com/docs/reference/linting/",
|
|
183
|
+
"rules": rules
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"results": results
|
|
187
|
+
}]
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
println!(
|
|
191
|
+
"{}",
|
|
192
|
+
serde_json::to_string_pretty(&doc).map_err(|e| e.to_string())?
|
|
193
|
+
);
|
|
76
194
|
Ok(())
|
|
77
195
|
}
|
|
@@ -246,7 +246,9 @@ fn lint_expr(e: &Expr, out: &mut Vec<LintDiagnostic>) {
|
|
|
246
246
|
}
|
|
247
247
|
Expr::Await { operand, .. } => lint_expr(operand, out),
|
|
248
248
|
Expr::TypeOf { operand, .. } => lint_expr(operand, out),
|
|
249
|
-
Expr::JsxElement {
|
|
249
|
+
Expr::JsxElement {
|
|
250
|
+
props, children, ..
|
|
251
|
+
} => {
|
|
250
252
|
for pr in props {
|
|
251
253
|
match pr {
|
|
252
254
|
tishlang_ast::JsxProp::Attr { value, .. } => {
|
|
@@ -19,7 +19,7 @@ Binary: `target/release/tish-lsp` (stdio LSP).
|
|
|
19
19
|
|
|
20
20
|
## Client configuration
|
|
21
21
|
|
|
22
|
-
See the [Tish docs — Language server](https://tishlang.
|
|
22
|
+
See the [Tish docs — Language server](https://tishlang.com/docs/reference/language-server/) and [Editor setup](https://tishlang.com/docs/getting-started/editor/).
|
|
23
23
|
|
|
24
24
|
## Developing
|
|
25
25
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tishlang/tish",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Tish - minimal TS/JS-compatible language. Run, REPL, build to native or other targets.",
|
|
5
5
|
"license": "PIF",
|
|
6
6
|
"repository": {
|
|
@@ -29,13 +29,6 @@
|
|
|
29
29
|
"engines": {
|
|
30
30
|
"node": ">=22"
|
|
31
31
|
},
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
34
|
-
"@semantic-release/github": "^12.0.6",
|
|
35
|
-
"@semantic-release/npm": "^13.1.5",
|
|
36
|
-
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
37
|
-
"semantic-release": "^25.0.3"
|
|
38
|
-
},
|
|
39
32
|
"keywords": [
|
|
40
33
|
"tish",
|
|
41
34
|
"language",
|
|
Binary file
|
package/platform/darwin-x64/tish
CHANGED
|
Binary file
|
|
Binary file
|
package/platform/linux-x64/tish
CHANGED
|
Binary file
|
|
Binary file
|