feat: add extended language validators and fix tokenizer crash bugs
Expand nimcheck with validators and tokenizers for C, C++, C#, Go, Rust, Ruby, CSS, SQL, Markdown, Dockerfile, Makefile, Kotlin, Lua, Swift, TypeScript, and XML. Register all flavors in the validator factory and improve auto-detection scoring for the new languages. Fix infinite tokenizer loops that caused OOM kills: closeBracket now advances position, finishTokenizeStep guards stalled tokenization, and Jinja/JS tokenizers no longer double-advance on brackets. Fix block-balance false positives in Lua (for/do) and Ruby (postfix unless), SQL trailing-comma detection across whitespace, and Makefile tab literals in test fixtures.
This commit is contained in:
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <locale.h>
|
||||
|
||||
/* Unicode in comments: Привет, 世界, 🌍 */
|
||||
|
||||
int main(void) {
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
/* Unicode string literals */
|
||||
wchar_t *greeting = L"こんにちは";
|
||||
wprintf(L"%ls\n", greeting);
|
||||
|
||||
/* Null byte embedded */
|
||||
char buf[] = "Hello\x00World";
|
||||
printf("Length: %zu\n", strlen(buf)); /* stops at null byte */
|
||||
|
||||
/* Deeply nested structs */
|
||||
struct a { int x; };
|
||||
struct b { struct a a; };
|
||||
struct c { struct b b; };
|
||||
struct d { struct c c; };
|
||||
struct e { struct d d; };
|
||||
struct f { struct e e; };
|
||||
struct f val = {{{{{{42}}}}}};
|
||||
printf("%d\n", val.e.d.c.b.a.x);
|
||||
|
||||
/* Very long function name */
|
||||
void this_is_an_extremely_long_function_name_that_goes_on_and_on_and_on(void) {
|
||||
printf("deep\n");
|
||||
}
|
||||
this_is_an_extremely_long_function_name_that_goes_on_and_on_and_on();
|
||||
|
||||
/* Encoding: BOM-like byte sequences */
|
||||
unsigned char raw[] = {0xEF, 0xBB, 0xBF, 'A', 'B', 'C', 0};
|
||||
printf("%s\n", raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX 10
|
||||
|
||||
int main(void) {
|
||||
int x = 5
|
||||
printf("x is %d\n", x)
|
||||
|
||||
char *s = "unclosed string;
|
||||
printf("%s\n", s);
|
||||
|
||||
int arr[3] = {1, 2, 3;
|
||||
printf("%d\n", arr[1]);
|
||||
|
||||
if (x > 0 {
|
||||
printf("positive\n");
|
||||
}
|
||||
|
||||
char *p = malloc(10;
|
||||
free(p);
|
||||
|
||||
struct { int a; int b; } s = {1, 2};
|
||||
s.a = ;
|
||||
|
||||
return 0;
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_NAME 64
|
||||
#define GREETING "Hello, World!"
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
char name[MAX_NAME];
|
||||
double score;
|
||||
} Player;
|
||||
|
||||
int add(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
void greet(const char *name) {
|
||||
printf("%s, %s!\n", GREETING, name);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
Player p = {1, "Alice", 95.5};
|
||||
greet(p.name);
|
||||
|
||||
int result = add(3, 4);
|
||||
printf("3 + 4 = %d\n", result);
|
||||
|
||||
FILE *fp = fopen("test.txt", "w");
|
||||
if (fp) {
|
||||
fprintf(fp, "id=%d,name=%s,score=%.1f\n", p.id, p.name, p.score);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
/* Unicode comment: 你好, 世界, 🌍🚀 */
|
||||
|
||||
int main() {
|
||||
// Unicode string literals
|
||||
std::string utf8 = "こんにちは世界";
|
||||
std::cout << utf8 << std::endl;
|
||||
|
||||
// Null byte in string
|
||||
std::string null_str = std::string("hello\x00world", 11);
|
||||
std::cout << "Null-str size: " << null_str.size() << std::endl;
|
||||
|
||||
// Deeply nested templates
|
||||
template <typename T>
|
||||
struct Wrap { T value; };
|
||||
|
||||
Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<Wrap<int>>>>>>>> deep = {{{{{{{{42}}}}}}}};
|
||||
std::cout << deep.value.value.value.value.value.value.value.value << std::endl;
|
||||
|
||||
// Extremely long string
|
||||
std::string long_str(10000, 'x');
|
||||
std::cout << "Long string length: " << long_str.length() << std::endl;
|
||||
|
||||
// BOM-like bytes
|
||||
const unsigned char bom[] = {0xEF, 0xBB, 0xBF, 'H', 'i', 0};
|
||||
std::cout << reinterpret_cast<const char*>(bom) << std::endl;
|
||||
|
||||
// Deep lambda nesting
|
||||
auto f1 = [](int x) {
|
||||
return [x](int y) {
|
||||
return [x, y](int z) {
|
||||
return [x, y, z](int w) {
|
||||
return x + y + z + w;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
std::cout << "Nested lambdas: " << f1(1)(2)(3)(4) << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
class Broken {
|
||||
public:
|
||||
Broken(int x) : x_(x) {}
|
||||
|
||||
void show() {
|
||||
std::cout << x_ << std::endl;
|
||||
|
||||
int missing_semicolon()
|
||||
return x_;
|
||||
}
|
||||
|
||||
private:
|
||||
int x_
|
||||
};
|
||||
|
||||
int main() {
|
||||
Broken b(42);
|
||||
b.show()
|
||||
|
||||
char *s = "unclosed string;
|
||||
std::cout << s << std::endl;
|
||||
|
||||
if (b.x_ > 0 {
|
||||
std::cout << "positive" << std::endl;
|
||||
}
|
||||
|
||||
std::vector<int> v = {1, 2, 3};
|
||||
std::cout << v[5] << std::endl;
|
||||
|
||||
return 0;
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
class Person {
|
||||
public:
|
||||
Person(int id, std::string name)
|
||||
: id_(id), name_(std::move(name)) {}
|
||||
|
||||
int id() const { return id_; }
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
virtual void greet() const {
|
||||
std::cout << "Hello, I'm " << name_ << std::endl;
|
||||
}
|
||||
|
||||
virtual ~Person() = default;
|
||||
|
||||
private:
|
||||
int id_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
class Student : public Person {
|
||||
public:
|
||||
Student(int id, std::string name, double gpa)
|
||||
: Person(id, std::move(name)), gpa_(gpa) {}
|
||||
|
||||
void greet() const override {
|
||||
std::cout << "Hi, I'm " << name() << " (GPA: " << gpa_ << ")" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
double gpa_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T max_value(T a, T b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto p = std::make_unique<Student>(1, "Alice", 3.9);
|
||||
p->greet();
|
||||
|
||||
std::vector<int> nums = {3, 1, 4, 1, 5, 9};
|
||||
std::sort(nums.begin(), nums.end());
|
||||
|
||||
for (int n : nums) {
|
||||
std::cout << n << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Max of 10 and 20: " << max_value(10, 20) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Vendored
+70
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// Unicode comment: 你好世界 🌍🚀
|
||||
|
||||
public class EdgeCases
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
// Unicode string literals
|
||||
string unicode = "こんにちは世界";
|
||||
Console.WriteLine(unicode);
|
||||
|
||||
// Null byte embedded
|
||||
string nullStr = "hello\x00world";
|
||||
Console.WriteLine($"Null-str length: {nullStr.Length}");
|
||||
|
||||
// Deeply nested generics
|
||||
var deep = new Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, string>>>>>
|
||||
{
|
||||
{ 1, new Dictionary<int, Dictionary<int, Dictionary<int, Dictionary<int, string>>>>
|
||||
{
|
||||
{ 2, new Dictionary<int, Dictionary<int, Dictionary<int, string>>>
|
||||
{
|
||||
{ 3, new Dictionary<int, Dictionary<int, string>>
|
||||
{
|
||||
{ 4, new Dictionary<int, string> { { 5, "deep" } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Console.WriteLine(deep[1][2][3][4][5]);
|
||||
|
||||
// Very long string
|
||||
string longStr = new string('x', 10000);
|
||||
Console.WriteLine($"Long string length: {longStr.Length}");
|
||||
|
||||
// BOM prefix
|
||||
byte[] bom = { 0xEF, 0xBB, 0xBF, (byte)'H', (byte)'i' };
|
||||
Console.WriteLine(Encoding.UTF8.GetString(bom));
|
||||
|
||||
// Deep exception nesting
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
throw new InvalidOperationException("inner");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ApplicationException("middle", ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("outer", ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Nested exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+53
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Broken
|
||||
{
|
||||
public class BrokenClass
|
||||
{
|
||||
public int X { get; set; }
|
||||
public string Name;
|
||||
|
||||
public BrokenClass(int x, string name)
|
||||
{
|
||||
X = x;
|
||||
Name = name
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
Console.WriteLine($"{Name}: {X}")
|
||||
}
|
||||
|
||||
public int MissingBody()
|
||||
}
|
||||
|
||||
public class Derived : BrokenClass
|
||||
{
|
||||
public Derived() : base(42, "test")
|
||||
{
|
||||
}
|
||||
|
||||
public void BrokenMethod()
|
||||
{
|
||||
string s = "unclosed string;
|
||||
Console.WriteLine(s);
|
||||
|
||||
if (X > 0
|
||||
Console.WriteLine("positive");
|
||||
}
|
||||
|
||||
int[] arr = {1, 2, 3;
|
||||
Console.WriteLine(arr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
var obj = new Derived();
|
||||
obj.Show()
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Fixtures
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
|
||||
public Person(int id, string name, string email)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Email = email;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name} <{Email}>";
|
||||
}
|
||||
}
|
||||
|
||||
public class Repository<T>
|
||||
{
|
||||
private readonly Dictionary<int, T> _items = new();
|
||||
|
||||
public void Add(int key, T item)
|
||||
{
|
||||
_items[key] = item;
|
||||
}
|
||||
|
||||
public T? Find(int key)
|
||||
{
|
||||
return _items.TryGetValue(key, out var item) ? item : default;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetAll()
|
||||
{
|
||||
return _items.Values.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Helpers
|
||||
{
|
||||
public static int Add(int a, int b) => a + b;
|
||||
|
||||
public static IEnumerable<T> Filter<T>(IEnumerable<T> items, Func<T, bool> predicate)
|
||||
{
|
||||
return items.Where(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var repo = new Repository<Person>();
|
||||
repo.Add(1, new Person(1, "Alice", "alice@example.com"));
|
||||
repo.Add(2, new Person(2, "Bob", "bob@example.com"));
|
||||
|
||||
var active = repo.GetAll();
|
||||
foreach (var p in active)
|
||||
{
|
||||
Console.WriteLine(p);
|
||||
}
|
||||
|
||||
Console.WriteLine($"3 + 4 = {Helpers.Add(3, 4)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
:root {
|
||||
--color-primary: #2563eb;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Inter", sans-serif;
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
background: linear-gradient(135deg, var(--color-primary), #7c3aed);
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.625rem 1.25rem;
|
||||
border: none;
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from { opacity: 0; transform: translateX(-20px); }
|
||||
to { opacity: 1; transform: translateX(0); }
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.navbar {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
:root {
|
||||
--color-primary: #2563eb;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
background: linear-gradient(135deg, var(--color-primary), #7c3aed);
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.625rem 1.25rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.navbar
|
||||
flex-direction: column;
|
||||
}
|
||||
Vendored
+159
@@ -0,0 +1,159 @@
|
||||
:root {
|
||||
--color-primary: #2563eb;
|
||||
--color-primary-hover: #1d4ed8;
|
||||
--color-bg: #f8fafc;
|
||||
--color-text: #1e293b;
|
||||
--color-border: #e2e8f0;
|
||||
--radius-md: 0.5rem;
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--font-sans: "Inter", system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1rem 2rem;
|
||||
background: linear-gradient(135deg, var(--color-primary), #7c3aed);
|
||||
}
|
||||
|
||||
.navbar .logo {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: rgb(255 255 255 / 0.85);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.card__title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.card__body {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
border: none;
|
||||
border-radius: var(--radius-md);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, transform 0.1s ease;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn--primary:hover {
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.btn--outline {
|
||||
background: transparent;
|
||||
border: 2px solid var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.animate-in {
|
||||
animation: fadeIn 0.4s ease-out both;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.navbar {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-bg: #0f172a;
|
||||
--color-text: #e2e8f0;
|
||||
--color-border: #334155;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #1e293b;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM alpine:3.20 as builder
|
||||
RUN apk add --no-cache gcc musl-dev make
|
||||
WORKDIR /build
|
||||
COPY . .
|
||||
RUN make release
|
||||
FROM alpine:3.20
|
||||
RUN apk add --no-cache pcre openssl
|
||||
COPY --from=builder /build/bin/app /usr/local/bin/app
|
||||
ENTRYPOINT ["app"]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
FROM alpine:3.20 AS builder
|
||||
RUN apk add --no-cache \
|
||||
gcc \
|
||||
musl-dev \
|
||||
make \
|
||||
|
||||
FROM alpine:3.20
|
||||
|
||||
COPY --from=builder /build/bin/app /usr/local/bin/app
|
||||
|
||||
ENTRYPOINT ["app"
|
||||
CMD ["--help"]
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
FROM alpine:3.20 AS builder
|
||||
|
||||
RUN apk add --no-cache \
|
||||
gcc \
|
||||
musl-dev \
|
||||
pcre-dev \
|
||||
openssl-dev \
|
||||
make \
|
||||
git
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN make release \
|
||||
&& strip bin/nimcheck
|
||||
|
||||
FROM alpine:3.20 AS runtime
|
||||
|
||||
RUN apk add --no-cache \
|
||||
pcre \
|
||||
openssl \
|
||||
ca-certificates \
|
||||
tzdata
|
||||
|
||||
ENV TZ=UTC
|
||||
ENV NIMCHECK_LOG_LEVEL=info
|
||||
ENV NIMCHECK_THREADS=4
|
||||
|
||||
RUN addgroup -g 1000 nimcheck \
|
||||
&& adduser -D -u 1000 -G nimcheck nimcheck
|
||||
|
||||
COPY --from=builder /build/bin/nimcheck /usr/local/bin/nimcheck
|
||||
|
||||
RUN chmod 755 /usr/local/bin/nimcheck
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
USER nimcheck
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
||||
CMD nimcheck --version || exit 1
|
||||
|
||||
ENTRYPOINT ["nimcheck"]
|
||||
CMD ["--help"]
|
||||
Vendored
+181
@@ -0,0 +1,181 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxRetries = 3
|
||||
BaseDelay = 100 * time.Millisecond
|
||||
MaxDelay = 5 * time.Second
|
||||
)
|
||||
|
||||
type Executor[T any] struct {
|
||||
workers int
|
||||
tasks chan func() T
|
||||
results chan T
|
||||
}
|
||||
|
||||
func NewExecutor[T any](workers int) *Executor[T] {
|
||||
return &Executor[T]{
|
||||
workers: workers,
|
||||
tasks: make(chan func() T, workers*2),
|
||||
results: make(chan T, workers*2),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor[T]) Submit(task func() T) {
|
||||
e.tasks <- task
|
||||
}
|
||||
|
||||
func (e *Executor[T]) Run(ctx context.Context) []T {
|
||||
for i := 0; i < e.workers; i++ {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case task := <-e.tasks:
|
||||
e.results <- task()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var results []T
|
||||
for i := 0; i < cap(e.tasks); i++ {
|
||||
select {
|
||||
case r := <-e.results:
|
||||
results = append(results, r)
|
||||
case <-ctx.Done():
|
||||
return results
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func retryWithBackoff(operation func() error) error {
|
||||
var err error
|
||||
delay := BaseDelay
|
||||
|
||||
for i := 0; i < MaxRetries; i++ {
|
||||
if err = operation(); err == nil {
|
||||
return nil
|
||||
}
|
||||
if i < MaxRetries-1 {
|
||||
jitter := time.Duration(rand.Int63n(int64(delay / 2)))
|
||||
time.Sleep(delay + jitter)
|
||||
delay = time.Duration(math.Min(float64(delay*2), float64(MaxDelay)))
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("operation failed after %d retries: %w", MaxRetries, err)
|
||||
}
|
||||
|
||||
func HashContent(r io.Reader) (string, error) {
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, r); err != nil {
|
||||
return "", fmt.Errorf("hashing failed: %w", err)
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func SliceToMap[K comparable, V any](items []V, keyFn func(V) K) map[K]V {
|
||||
result := make(map[K]V, len(items))
|
||||
for _, item := range items {
|
||||
result[keyFn(item)] = item
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func InverseMap[K, V comparable](m map[K]V) map[V]K {
|
||||
result := make(map[V]K, len(m))
|
||||
for k, v := range m {
|
||||
result[v] = k
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var counter atomic.Int64
|
||||
|
||||
func nextID() int64 {
|
||||
return counter.Add(1)
|
||||
}
|
||||
|
||||
type Enum interface {
|
||||
~int
|
||||
String() string
|
||||
}
|
||||
|
||||
type Color int
|
||||
|
||||
const (
|
||||
Red Color = iota
|
||||
Green
|
||||
Blue
|
||||
)
|
||||
|
||||
func (c Color) String() string {
|
||||
return [...]string{"red", "green", "blue"}[c]
|
||||
}
|
||||
|
||||
func Must[T any](val T, err error) T {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
type TransformFunc[T, U any] func(T) U
|
||||
|
||||
func Chain[T, U, V any](f TransformFunc[T, U], g TransformFunc[U, V]) TransformFunc[T, V] {
|
||||
return func(t T) V {
|
||||
return g(f(t))
|
||||
}
|
||||
}
|
||||
|
||||
func zero[T any]() T {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
|
||||
func Map[T, U any](items []T, fn func(T) U) []U {
|
||||
result := make([]U, len(items))
|
||||
for i, item := range items {
|
||||
result[i] = fn(item)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Filter[T any](items []T, fn func(T) bool) []T {
|
||||
var result []T
|
||||
for _, item := range items {
|
||||
if fn(item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Reduce[T, U any](items []T, init U, fn func(U, T) U) U {
|
||||
acc := init
|
||||
for _, item := range items {
|
||||
acc = fn(acc, item)
|
||||
}
|
||||
return acc
|
||||
}
|
||||
|
||||
func init() {
|
||||
fmt.Println("initializing package main")
|
||||
}
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
x := 42
|
||||
fmt.Println(x
|
||||
|
||||
func brokenFunc(x int) string {
|
||||
return x
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func (u User) Greet() string {
|
||||
return "Hello, " + .Name
|
||||
|
||||
switch x {
|
||||
case 1:
|
||||
fmt.Println("one")
|
||||
case 2:
|
||||
fmt.Println("two")
|
||||
}
|
||||
Vendored
+149
@@ -0,0 +1,149 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Active bool `json:"active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type UserService struct {
|
||||
mu sync.RWMutex
|
||||
users map[int]*User
|
||||
}
|
||||
|
||||
func NewUserService() *UserService {
|
||||
return &UserService{
|
||||
users: make(map[int]*User),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *UserService) Add(user *User) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if user.Name == "" {
|
||||
return errors.New("name is required")
|
||||
}
|
||||
if !strings.Contains(user.Email, "@") {
|
||||
return errors.New("invalid email")
|
||||
}
|
||||
if _, exists := s.users[user.ID]; exists {
|
||||
return errors.New("user already exists")
|
||||
}
|
||||
s.users[user.ID] = user
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UserService) FindByID(id int) (*User, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
user, ok := s.users[id]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("user %d not found", id)
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *UserService) FindByEmail(email string) *User {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
for _, u := range s.users {
|
||||
if u.Email == email {
|
||||
return u
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UserService) All() []*User {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
result := make([]*User, 0, len(s.users))
|
||||
for _, u := range s.users {
|
||||
result = append(result, u)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func loggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
log.Printf("%s %s %s", r.Method, r.URL.Path, r.RemoteAddr)
|
||||
next.ServeHTTP(w, r)
|
||||
log.Printf("%s completed in %v", r.URL.Path, time.Since(start))
|
||||
})
|
||||
}
|
||||
|
||||
func handleUsers(svc *UserService) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
users := svc.All()
|
||||
json.NewEncoder(w).Encode(users)
|
||||
|
||||
case http.MethodPost:
|
||||
var user User
|
||||
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if err := svc.Add(&user); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(user)
|
||||
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
svc := NewUserService()
|
||||
svc.Add(&User{
|
||||
ID: 1,
|
||||
Name: "Alice",
|
||||
Email: "alice@example.com",
|
||||
Active: true,
|
||||
})
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/users", handleUsers(svc))
|
||||
|
||||
port := os.Getenv("PORT")
|
||||
if port == "" {
|
||||
port = "8080"
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: ":" + port,
|
||||
Handler: loggingMiddleware(mux),
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
log.Printf("Server starting on :%s", port)
|
||||
log.Fatal(server.ListenAndServe())
|
||||
}
|
||||
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
package fixtures;
|
||||
|
||||
import java.util.*;
|
||||
import java.nio.charset.*;
|
||||
|
||||
// Unicode comment: 你好世界 🌍🚀
|
||||
|
||||
public class EdgeCases {
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Unicode string literals
|
||||
String unicode = "こんにちは世界";
|
||||
System.out.println(unicode);
|
||||
|
||||
// Null byte in string
|
||||
String nullStr = "hello\u0000world";
|
||||
System.out.println("Null-str length: " + nullStr.length());
|
||||
|
||||
// Deeply nested classes
|
||||
Map<Integer, Map<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>>> deep =
|
||||
new HashMap<>();
|
||||
Map<Integer, Map<Integer, Map<Integer, Map<Integer, String>>>> l4 = new HashMap<>();
|
||||
Map<Integer, Map<Integer, Map<Integer, String>>> l3 = new HashMap<>();
|
||||
Map<Integer, Map<Integer, String>> l2 = new HashMap<>();
|
||||
Map<Integer, String> l1 = new HashMap<>();
|
||||
l1.put(5, "deep");
|
||||
l2.put(4, l1);
|
||||
l3.put(3, l2);
|
||||
l4.put(2, l3);
|
||||
deep.put(1, l4);
|
||||
System.out.println(deep.get(1).get(2).get(3).get(4).get(5));
|
||||
|
||||
// Very long string
|
||||
StringBuilder sb = new StringBuilder(10000);
|
||||
for (int i = 0; i < 10000; i++) sb.append('x');
|
||||
System.out.println("Long string length: " + sb.length());
|
||||
|
||||
// BOM prefix
|
||||
byte[] bom = {(byte)0xEF, (byte)0xBB, (byte)0xBF, (byte)'H', (byte)'i'};
|
||||
System.out.println(new String(bom, StandardCharsets.UTF_8));
|
||||
|
||||
// Deep exception chaining
|
||||
try {
|
||||
try {
|
||||
try {
|
||||
throw new RuntimeException("inner");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("middle", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("outer", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Chained: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Deep array nesting
|
||||
int[][][][][][] deepArray = new int[2][2][2][2][2][2];
|
||||
deepArray[0][0][0][0][0][0] = 42;
|
||||
System.out.println("Deep array: " + deepArray[0][0][0][0][0][0]);
|
||||
}
|
||||
}
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
package fixtures;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Invalid {
|
||||
private int x;
|
||||
|
||||
public Invalid(int x) {
|
||||
this.x = x
|
||||
}
|
||||
|
||||
public void show() {
|
||||
System.out.println(x)
|
||||
}
|
||||
|
||||
public String broken() {
|
||||
String s = "unclosed string;
|
||||
return s;
|
||||
|
||||
public int missingBody()
|
||||
|
||||
public void badIf() {
|
||||
if (x > 0 {
|
||||
System.out.println("positive");
|
||||
}
|
||||
}
|
||||
|
||||
public void badArray() {
|
||||
int[] arr = {1, 2, 3;
|
||||
System.out.println(arr[0]);
|
||||
}
|
||||
|
||||
public void missingSemicolon() {
|
||||
int a = 5
|
||||
int b = 10;
|
||||
int c = a + b
|
||||
System.out.println(c);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Invalid obj = new Invalid(42);
|
||||
obj.show()
|
||||
}
|
||||
}
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
package fixtures;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
public class Valid {
|
||||
public static class Person {
|
||||
private final int id;
|
||||
private final String name;
|
||||
private final String email;
|
||||
|
||||
public Person(int id, String name, String email) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public int getId() { return id; }
|
||||
public String getName() { return name; }
|
||||
public String getEmail() { return email; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " <" + email + ">";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Repository<T> {
|
||||
private final Map<Integer, T> items = new HashMap<>();
|
||||
|
||||
public void add(int key, T item) {
|
||||
items.put(key, item);
|
||||
}
|
||||
|
||||
public Optional<T> find(int key) {
|
||||
return Optional.ofNullable(items.get(key));
|
||||
}
|
||||
|
||||
public List<T> getAll() {
|
||||
return new ArrayList<>(items.values());
|
||||
}
|
||||
}
|
||||
|
||||
public static int add(int a, int b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Repository<Person> repo = new Repository<>();
|
||||
repo.add(1, new Person(1, "Alice", "alice@example.com"));
|
||||
repo.add(2, new Person(2, "Bob", "bob@example.com"));
|
||||
|
||||
repo.getAll().stream()
|
||||
.map(Person::getName)
|
||||
.forEach(System.out::println);
|
||||
|
||||
System.out.println("3 + 4 = " + add(3, 4));
|
||||
}
|
||||
}
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
package fixtures
|
||||
|
||||
// Unicode comment: 你好世界 🌍🚀
|
||||
|
||||
fun main() {
|
||||
// Unicode string literals
|
||||
val unicode = "こんにちは世界"
|
||||
println(unicode)
|
||||
|
||||
// Null byte in string
|
||||
val nullStr = "hello\u0000world"
|
||||
println("Null-str length: ${nullStr.length}")
|
||||
|
||||
// Deeply nested generics
|
||||
val deep = mapOf(
|
||||
1 to mapOf(
|
||||
2 to mapOf(
|
||||
3 to mapOf(
|
||||
4 to mapOf(
|
||||
5 to "deep"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
println(deep[1]?.get(2)?.get(3)?.get(4)?.get(5))
|
||||
|
||||
// Very long string
|
||||
val longStr = "x".repeat(10000)
|
||||
println("Long string length: ${longStr.length}")
|
||||
|
||||
// BOM bytes
|
||||
val bom = byteArrayOf(0xEF.toByte(), 0xBB.toByte(), 0xBF.toByte(), 'H'.code.toByte(), 'i'.code.toByte())
|
||||
println(String(bom))
|
||||
|
||||
// Deep lambda nesting
|
||||
val f1: (Int) -> (Int) -> (Int) -> (Int) -> Int = { x ->
|
||||
{ y ->
|
||||
{ z ->
|
||||
{ w -> x + y + z + w }
|
||||
}
|
||||
}
|
||||
}
|
||||
println("Nested lambdas: ${f1(1)(2)(3)(4)}")
|
||||
|
||||
// Infinite sequence (lazy)
|
||||
val naturals = generateSequence(0) { it + 1 }
|
||||
println("First 5 naturals: ${naturals.take(5).toList()}")
|
||||
|
||||
// Deep data class nesting
|
||||
data class A(val x: Int)
|
||||
data class B(val a: A)
|
||||
data class C(val b: B)
|
||||
data class D(val c: C)
|
||||
data class E(val d: D)
|
||||
data class F(val e: E)
|
||||
val deepData = F(E(D(C(B(A(42))))))
|
||||
println("Deep data: ${deepData.e.d.c.b.a.x}")
|
||||
}
|
||||
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
package fixtures
|
||||
|
||||
data class Broken(
|
||||
val x: Int,
|
||||
val name: String
|
||||
)
|
||||
|
||||
fun show() {
|
||||
println("hello")
|
||||
val x = 5
|
||||
println(x)
|
||||
}
|
||||
|
||||
class BadRepo<T> {
|
||||
private val items = mutableMapOf<Int, T>()
|
||||
|
||||
fun add(key: Int, item: T) {
|
||||
items[key] = item
|
||||
}
|
||||
|
||||
fun find(key: Int): T? = items[key]
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val repo = BadRepo<String>()
|
||||
repo.add(1, "test")
|
||||
|
||||
val s = "unclosed string;
|
||||
println(s)
|
||||
|
||||
val x = 5
|
||||
if (x > 0 {
|
||||
println("positive")
|
||||
}
|
||||
|
||||
val list = listOf(1, 2, 3
|
||||
println(list)
|
||||
|
||||
fun missingReturn(): Int {
|
||||
val a = 5
|
||||
}
|
||||
|
||||
println("done")
|
||||
}
|
||||
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
package fixtures
|
||||
|
||||
data class Person(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val email: String
|
||||
)
|
||||
|
||||
class Repository<T> {
|
||||
private val items = mutableMapOf<Int, T>()
|
||||
|
||||
fun add(key: Int, item: T) {
|
||||
items[key] = item
|
||||
}
|
||||
|
||||
fun find(key: Int): T? = items[key]
|
||||
|
||||
fun getAll(): List<T> = items.values.toList()
|
||||
}
|
||||
|
||||
fun add(a: Int, b: Int): Int = a + b
|
||||
|
||||
fun <T> filter(items: List<T>, predicate: (T) -> Boolean): List<T> {
|
||||
return items.filter(predicate)
|
||||
}
|
||||
|
||||
fun main() {
|
||||
val repo = Repository<Person>()
|
||||
repo.add(1, Person(1, "Alice", "alice@example.com"))
|
||||
repo.add(2, Person(2, "Bob", "bob@example.com"))
|
||||
|
||||
repo.getAll().forEach { println(it) }
|
||||
println("3 + 4 = ${add(3, 4)}")
|
||||
|
||||
val numbers = listOf(1, 2, 3, 4, 5)
|
||||
val evens = filter(numbers) { it % 2 == 0 }
|
||||
println("Evens: $evens")
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
-- Unicode comment: 你好世界 🌍🚀
|
||||
|
||||
-- Unicode string literals
|
||||
local unicode = "こんにちは世界"
|
||||
print(unicode)
|
||||
|
||||
-- Null byte in string
|
||||
local null_str = "hello\0world"
|
||||
print("Null-str length: " .. #null_str)
|
||||
|
||||
-- Deeply nested tables
|
||||
local deep = {
|
||||
a = {
|
||||
b = {
|
||||
c = {
|
||||
d = {
|
||||
e = "deep"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
print(deep.a.b.c.d.e)
|
||||
|
||||
-- Very long string
|
||||
local long_str = string.rep("x", 10000)
|
||||
print("Long string length: " .. #long_str)
|
||||
|
||||
-- Metatable chains
|
||||
local a = {}
|
||||
local b = {}
|
||||
local c = {}
|
||||
setmetatable(a, {__index = b})
|
||||
setmetatable(b, {__index = c})
|
||||
c.value = 42
|
||||
print("Metatable chain: " .. a.value)
|
||||
|
||||
-- Deep function nesting
|
||||
local function level1()
|
||||
return function()
|
||||
return function()
|
||||
return function()
|
||||
return function()
|
||||
return 42
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
print("Deep functions: " .. level1()()()()())
|
||||
|
||||
-- Coroutine with deep stack
|
||||
local co = coroutine.create(function()
|
||||
local function recurse(n)
|
||||
if n == 0 then
|
||||
coroutine.yield("done")
|
||||
else
|
||||
return recurse(n - 1)
|
||||
end
|
||||
end
|
||||
recurse(100)
|
||||
end)
|
||||
local _, msg = coroutine.resume(co)
|
||||
print("Coroutine: " .. msg)
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
local function broken()
|
||||
local x = 5
|
||||
print(x)
|
||||
end
|
||||
|
||||
local s = "unclosed string
|
||||
print(s)
|
||||
|
||||
local function bad_if(x)
|
||||
if x > 0
|
||||
print("positive")
|
||||
end
|
||||
end
|
||||
|
||||
local function missing_end(x)
|
||||
if x > 0 then
|
||||
print("positive")
|
||||
end
|
||||
|
||||
local t = {1, 2, 3
|
||||
print(t[1])
|
||||
|
||||
local function nested()
|
||||
local function inner()
|
||||
local function deeper()
|
||||
return 42
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print("done"
|
||||
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
local function add(a, b)
|
||||
return a + b
|
||||
end
|
||||
|
||||
local function greet(name)
|
||||
print("Hello, " .. name .. "!")
|
||||
end
|
||||
|
||||
local Person = {}
|
||||
Person.__index = Person
|
||||
|
||||
function Person:new(id, name, email)
|
||||
local obj = {
|
||||
id = id,
|
||||
name = name,
|
||||
email = email
|
||||
}
|
||||
setmetatable(obj, self)
|
||||
return obj
|
||||
end
|
||||
|
||||
function Person:__tostring()
|
||||
return self.name .. " <" .. self.email .. ">"
|
||||
end
|
||||
|
||||
local Repository = {}
|
||||
Repository.__index = Repository
|
||||
|
||||
function Repository:new()
|
||||
return setmetatable({items = {}}, self)
|
||||
end
|
||||
|
||||
function Repository:add(key, item)
|
||||
self.items[key] = item
|
||||
end
|
||||
|
||||
function Repository:find(key)
|
||||
return self.items[key]
|
||||
end
|
||||
|
||||
function Repository:getAll()
|
||||
local result = {}
|
||||
for _, v in pairs(self.items) do
|
||||
table.insert(result, v)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local repo = Repository:new()
|
||||
repo:add(1, Person:new(1, "Alice", "alice@example.com"))
|
||||
repo:add(2, Person:new(2, "Bob", "bob@example.com"))
|
||||
|
||||
for _, p in ipairs(repo:getAll()) do
|
||||
print(p)
|
||||
end
|
||||
|
||||
print("3 + 4 = " .. add(3, 4))
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
.PHONY: all clean
|
||||
|
||||
CC := gcc
|
||||
CFLAGS := -O2 -Wall
|
||||
|
||||
all: program
|
||||
|
||||
program: main.o util.o
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f program *.o
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
.PHONY: all clean
|
||||
|
||||
CC := gcc
|
||||
CFLAGS := -O2 -Wall
|
||||
|
||||
all: program
|
||||
|
||||
program: main.o util.o
|
||||
$(CC) $(CFLAGS) -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $<
|
||||
echo "unclosed
|
||||
|
||||
clean:
|
||||
rm -f program *.o
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
.PHONY: all build release debug clean test coverage lint install uninstall
|
||||
|
||||
NIM := nim
|
||||
NIM_FLAGS := --hints:off --warnings:off
|
||||
SRC_DIR := src
|
||||
BIN_DIR := bin
|
||||
TEST_DIR := tests
|
||||
BUILD_DIR := build
|
||||
|
||||
SOURCES := $(shell find $(SRC_DIR) -name '*.nim')
|
||||
TESTS := $(shell find $(TEST_DIR) -name '*.nim')
|
||||
OBJECTS := $(patsubst $(SRC_DIR)/%.nim,$(BUILD_DIR)/%.o,$(SOURCES))
|
||||
|
||||
BINARY := $(BIN_DIR)/nimcheck
|
||||
|
||||
all: build
|
||||
|
||||
$(BIN_DIR):
|
||||
mkdir -p $(BIN_DIR)
|
||||
|
||||
$(BUILD_DIR):
|
||||
mkdir -p $(BUILD_DIR)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.nim | $(BUILD_DIR)
|
||||
$(NIM) compile --compileOnly -d:release -o:$@ $<
|
||||
|
||||
$(BINARY): $(OBJECTS) | $(BIN_DIR)
|
||||
$(NIM) compile -d:release --out:$(BINARY) $(SRC_DIR)/nimcheck.nim
|
||||
|
||||
build: $(BINARY)
|
||||
|
||||
release:
|
||||
$(NIM) compile -d:release --opt:speed --passC:-flto --passL:-flto \
|
||||
--out:$(BINARY) $(SRC_DIR)/nimcheck.nim
|
||||
|
||||
debug:
|
||||
$(NIM) compile -d:debug --lineDir:on --stacktrace:on \
|
||||
--out:$(BINARY) $(SRC_DIR)/nimcheck.nim
|
||||
|
||||
test: build
|
||||
$(NIM) compile --run $(TEST_DIR)/test_all.nim
|
||||
|
||||
coverage:
|
||||
$(NIM) compile --run -d:coverage $(TEST_DIR)/test_all.nim
|
||||
|
||||
lint:
|
||||
$(NIM) check $(SRC_DIR)/nimcheck.nim
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN_DIR) $(BUILD_DIR)
|
||||
find . -name 'nimcache' -type d -exec rm -rf {} + 2>/dev/null || true
|
||||
|
||||
install: release
|
||||
install -m 755 $(BINARY) /usr/local/bin/nimcheck
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/nimcheck
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# Nimcheck
|
||||
|
||||
---
|
||||
|
||||
> A fast syntax validator.
|
||||
|
||||
## Code Block
|
||||
|
||||
```nim
|
||||
proc hello(): string =
|
||||
result = "Hello"
|
||||
```
|
||||
|
||||
```python
|
||||
def hello() -> str:
|
||||
return "Hello"
|
||||
```
|
||||
|
||||
| A | B | C |
|
||||
|---|---|---|
|
||||
| 1 | 2 | 3 |
|
||||
|
||||
- [x] Done
|
||||
- [ ] Pending
|
||||
|
||||
~~strikethrough~~
|
||||
|
||||
Footnotes[^1]
|
||||
|
||||
[^1]: A footnote.
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
# Nimcheck
|
||||
|
||||
> A fast syntax validator
|
||||
|
||||
## Features
|
||||
|
||||
- Fast
|
||||
- Accurate
|
||||
- 27+ languages
|
||||
|
||||
## Unclosed Code Block
|
||||
|
||||
```nim
|
||||
proc hello(): string =
|
||||
result = "Hello"
|
||||
|
||||
Still in code block without closing fence.
|
||||
|
||||
## Broken Link
|
||||
|
||||
[Broken](
|
||||
|
||||
## Broken Table
|
||||
|
||||
| A | B | C
|
||||
| 1 | 2 | 3 |
|
||||
Vendored
+131
@@ -0,0 +1,131 @@
|
||||
# Nimcheck: Universal Syntax Validator
|
||||
|
||||
[](https://nim-lang.org)
|
||||
[](LICENSE)
|
||||
|
||||
> **Fast, accurate syntax validation for 27+ languages.**
|
||||
> Built in Nim. Zero dependencies beyond the standard library.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Features](#features)
|
||||
2. [Installation](#installation)
|
||||
3. [Quick Start](#quick-start)
|
||||
4. [Usage](#usage)
|
||||
5. [Supported Languages](#supported-languages)
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-language** — validates Nim, Python, JavaScript, TypeScript, PHP, Ruby, Rust, Go, Lua, C, C++, C#, Java, Swift, Kotlin, Bash, HTML, XML, Jinja, JSON, YAML, TOML, CSS, SQL, Markdown, Dockerfile, Makefile
|
||||
- **Blazing fast** — compiles to native code via Nim
|
||||
- **Auto-detection** — identifies language from extension, shebang, or content analysis
|
||||
- **CI-friendly** — exit codes and structured output
|
||||
|
||||
### Detection Methods
|
||||
|
||||
| Priority | Method | Confidence |
|
||||
|----------|-------------|------------|
|
||||
| 1 | Explicit | 100% |
|
||||
| 2 | Extension | 90% |
|
||||
| 3 | Shebang | 95% |
|
||||
| 4 | Content | 70-95% |
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/retoor/nimcheck
|
||||
cd nimcheck
|
||||
make release
|
||||
```
|
||||
|
||||
### Via Nimble
|
||||
|
||||
```bash
|
||||
nimble install nimcheck
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
nimcheck src/ # validate all files in src/
|
||||
nimcheck --flavor nim # validate as Nim
|
||||
nimcheck --json # JSON output
|
||||
nimcheck --watch # watch mode
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Validate a single file
|
||||
|
||||
```bash
|
||||
nimcheck src/main.nim
|
||||
```
|
||||
|
||||
### Validate with explicit language
|
||||
|
||||
```bash
|
||||
nimcheck --flavor python script.py
|
||||
```
|
||||
|
||||
### Recursive directory scan
|
||||
|
||||
```bash
|
||||
nimcheck --recursive project/
|
||||
```
|
||||
|
||||
### JSON output for CI
|
||||
|
||||
```bash
|
||||
nimcheck --json --recursive src/ > report.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Language | Extensions |
|
||||
|-------------|-------------------------------------|
|
||||
| Nim | `.nim`, `.nims`, `.nimble` |
|
||||
| Python | `.py`, `.pyw`, `.pyx`, `.pxd` |
|
||||
| JavaScript | `.js`, `.mjs`, `.cjs` |
|
||||
| TypeScript | `.ts`, `.tsx` |
|
||||
| PHP | `.php`, `.phtml` |
|
||||
| HTML | `.html`, `.htm`, `.xhtml` |
|
||||
| XML | `.xml`, `.svg` |
|
||||
| JSON | `.json`, `.jsonc` |
|
||||
| YAML | `.yaml`, `.yml` |
|
||||
| TOML | `.toml` |
|
||||
| CSS | `.css` |
|
||||
| SQL | `.sql` |
|
||||
| Markdown | `.md`, `.markdown` |
|
||||
| Ruby | `.rb` |
|
||||
| Rust | `.rs` |
|
||||
| Go | `.go` |
|
||||
| Lua | `.lua` |
|
||||
| C | `.c`, `.h` |
|
||||
| C++ | `.cpp`, `.cxx`, `.hpp` |
|
||||
| C# | `.cs` |
|
||||
| Java | `.java` |
|
||||
| Swift | `.swift` |
|
||||
| Kotlin | `.kt`, `.kts` |
|
||||
| Bash | `.sh`, `.bash` |
|
||||
| Dockerfile | `Dockerfile` |
|
||||
| Makefile | `Makefile` |
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Retoor](https://github.com/retoor)
|
||||
Vendored
+66
@@ -0,0 +1,66 @@
|
||||
module EnumerableExtensions
|
||||
refine Array do
|
||||
def second
|
||||
self[1]
|
||||
end
|
||||
|
||||
def middle
|
||||
self[size / 2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
using EnumerableExtensions
|
||||
|
||||
class Singleton
|
||||
private_class_method :new
|
||||
|
||||
@instance = nil
|
||||
|
||||
def self.instance
|
||||
@instance ||= new
|
||||
end
|
||||
end
|
||||
|
||||
module_function
|
||||
|
||||
def log(level, message)
|
||||
warn "[#{level.upcase}] #{message}"
|
||||
end
|
||||
|
||||
require "ostruct"
|
||||
require "set"
|
||||
require "delegate"
|
||||
|
||||
Point = Struct.new(:x, :y, keyword_init: true)
|
||||
p = Point.new(x: 10, y: 20)
|
||||
|
||||
class Stack
|
||||
include Enumerable
|
||||
|
||||
def initialize
|
||||
@items = []
|
||||
end
|
||||
|
||||
def push(item)
|
||||
@items.push(item)
|
||||
end
|
||||
|
||||
def pop
|
||||
@items.pop
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@items.each(&block)
|
||||
end
|
||||
end
|
||||
|
||||
s = Stack.new
|
||||
s.push(1)
|
||||
s.push(2)
|
||||
s.each { |i| puts i }
|
||||
|
||||
$global_count = 0
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
puts "Global: #{$global_count}, Timeout: #{DEFAULT_TIMEOUT}"
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
class Broken
|
||||
attr_accessor :x
|
||||
|
||||
def missing_end
|
||||
if x > 0
|
||||
puts "positive"
|
||||
|
||||
def wrong_syntax
|
||||
x = 42
|
||||
{x + 1
|
||||
|
||||
end
|
||||
Vendored
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env ruby
|
||||
require "json"
|
||||
require "net/http"
|
||||
require "uri"
|
||||
|
||||
class User
|
||||
attr_accessor :id, :name, :email, :active
|
||||
|
||||
def initialize(id:, name:, email:, active: true)
|
||||
@id = id
|
||||
@name = name
|
||||
@email = email
|
||||
@active = active
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{@name} <#{@email}>"
|
||||
end
|
||||
|
||||
def active?
|
||||
@active
|
||||
end
|
||||
|
||||
def deactivate!
|
||||
@active = false
|
||||
end
|
||||
end
|
||||
|
||||
class UserRepository
|
||||
def initialize
|
||||
@users = {}
|
||||
end
|
||||
|
||||
def add(user)
|
||||
@users[user.id] = user
|
||||
end
|
||||
|
||||
def find(id)
|
||||
@users[id]
|
||||
end
|
||||
|
||||
def find_by_email(email)
|
||||
@users.values.find { |u| u.email == email }
|
||||
end
|
||||
|
||||
def active_users
|
||||
@users.values.select(&:active?)
|
||||
end
|
||||
|
||||
def each(&block)
|
||||
@users.values.each(&block)
|
||||
end
|
||||
|
||||
def to_json(*args)
|
||||
@users.values.map(&:to_h).to_json(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_users(url)
|
||||
uri = URI.parse(url)
|
||||
response = Net::HTTP.get_response(uri)
|
||||
raise "HTTP error: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
||||
JSON.parse(response.body)
|
||||
rescue StandardError => e
|
||||
warn "Failed to fetch users: #{e.message}"
|
||||
[]
|
||||
end
|
||||
|
||||
def process_items(items)
|
||||
items.map { |item| yield item }
|
||||
end
|
||||
|
||||
repo = UserRepository.new
|
||||
repo.add(User.new(id: 1, name: "Alice", email: "alice@example.com"))
|
||||
|
||||
repo.each do |user|
|
||||
puts user.to_s
|
||||
end
|
||||
|
||||
puts "Active: #{repo.active_users.size}"
|
||||
Vendored
+147
@@ -0,0 +1,147 @@
|
||||
use std::collections::{HashMap, HashSet, BTreeMap};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum Status {
|
||||
Active,
|
||||
Inactive,
|
||||
Pending,
|
||||
Banned,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TreeNode<T> {
|
||||
pub value: T,
|
||||
pub left: Option<Box<TreeNode<T>>>,
|
||||
pub right: Option<Box<TreeNode<T>>>,
|
||||
}
|
||||
|
||||
impl<T: Ord> TreeNode<T> {
|
||||
pub fn insert(&mut self, value: T) {
|
||||
let target = if value <= self.value {
|
||||
&mut self.left
|
||||
} else {
|
||||
&mut self.right
|
||||
};
|
||||
match target {
|
||||
Some(node) => node.insert(value),
|
||||
None => *target = Some(Box::new(TreeNode {
|
||||
value,
|
||||
left: None,
|
||||
right: None,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, value: &T) -> bool {
|
||||
&self.value == value
|
||||
|| self.left.as_ref().map_or(false, |n| n.contains(value))
|
||||
|| self.right.as_ref().map_or(false, |n| n.contains(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Monoid {
|
||||
fn empty() -> Self;
|
||||
fn combine(&self, other: &Self) -> Self;
|
||||
}
|
||||
|
||||
impl Monoid for i32 {
|
||||
fn empty() -> Self { 0 }
|
||||
fn combine(&self, other: &Self) -> Self { self + other }
|
||||
}
|
||||
|
||||
impl Monoid for String {
|
||||
fn empty() -> Self { String::new() }
|
||||
fn combine(&self, other: &Self) -> Self { format!("{}{}", self, other) }
|
||||
}
|
||||
|
||||
pub fn reduce<T: Monoid>(items: &[T]) -> T {
|
||||
items.iter().fold(T::empty(), |acc, x| acc.combine(x))
|
||||
}
|
||||
|
||||
macro_rules! vec_of_strings {
|
||||
($($x:expr),*) => (vec![$($x.to_string()),*]);
|
||||
}
|
||||
|
||||
pub struct Lazy<T, F = fn() -> T>
|
||||
where
|
||||
F: Fn() -> T,
|
||||
{
|
||||
value: Option<T>,
|
||||
factory: F,
|
||||
}
|
||||
|
||||
impl<T, F: Fn() -> T> Lazy<T, F> {
|
||||
pub fn new(factory: F) -> Self {
|
||||
Self {
|
||||
value: None,
|
||||
factory,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&mut self) -> &T {
|
||||
self.value.get_or_insert_with(&self.factory)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn parallel_map<T, U, F>(items: Vec<T>, f: F) -> Vec<U>
|
||||
where
|
||||
T: Send + 'static,
|
||||
U: Send + 'static,
|
||||
F: Fn(T) -> U + Send + Sync + 'static,
|
||||
{
|
||||
use tokio::task;
|
||||
let mut handles = Vec::new();
|
||||
for item in items {
|
||||
handles.push(task::spawn(async move { f(item) }));
|
||||
}
|
||||
let mut results = Vec::new();
|
||||
for handle in handles {
|
||||
results.push(handle.await.unwrap());
|
||||
}
|
||||
results
|
||||
}
|
||||
|
||||
pub struct CustomIterator<T> {
|
||||
items: Vec<T>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<T: Clone> Iterator for CustomIterator<T> {
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index < self.items.len() {
|
||||
let item = self.items[self.index].clone();
|
||||
self.index += 1;
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_PORT: u16 = 8080;
|
||||
static APP_NAME: &str = "nimcheck-rs";
|
||||
thread_local! {
|
||||
static CACHE: RefCell<HashMap<String, String>> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
||||
unsafe impl Send for User {}
|
||||
unsafe impl Sync for User {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_insert() {
|
||||
let mut root = TreeNode { value: 5, left: None, right: None };
|
||||
root.insert(3);
|
||||
root.insert(7);
|
||||
assert!(root.contains(&3));
|
||||
assert!(root.contains(&7));
|
||||
}
|
||||
}
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
fn main() {
|
||||
let x = 42
|
||||
let y = vec![1, 2,
|
||||
println!("{}", x
|
||||
|
||||
fn missing_type(x) -> i32 {
|
||||
x
|
||||
}
|
||||
|
||||
match x {
|
||||
1 => println!("one"),
|
||||
2 => println!("two"),
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
fn new(x: i32, y: i32 -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
Vendored
+112
@@ -0,0 +1,112 @@
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct User {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub active: bool,
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn new(id: u64, name: &str, email: &str) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
email: email.to_string(),
|
||||
active: true,
|
||||
tags: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deactivate(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
|
||||
pub fn add_tag(&mut self, tag: &str) {
|
||||
self.tags.push(tag.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for User {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} <{}> [{}]", self.name, self.email, self.id)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ApiError {
|
||||
NotFound(String),
|
||||
Unauthorized,
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
impl Debug for ApiError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ApiError::NotFound(msg) => write!(f, "NotFound({})", msg),
|
||||
ApiError::Unauthorized => write!(f, "Unauthorized"),
|
||||
ApiError::Internal(msg) => write!(f, "Internal({})", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, ApiError>;
|
||||
|
||||
pub trait Repository<T> {
|
||||
fn find_by_id(&self, id: u64) -> Result<T>;
|
||||
fn save(&mut self, item: T) -> Result<()>;
|
||||
fn delete(&mut self, id: u64) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct UserRepository {
|
||||
users: HashMap<u64, User>,
|
||||
}
|
||||
|
||||
impl UserRepository {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
users: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Repository<User> for UserRepository {
|
||||
fn find_by_id(&self, id: u64) -> Result<User> {
|
||||
self.users
|
||||
.get(&id)
|
||||
.cloned()
|
||||
.ok_or_else(|| ApiError::NotFound(format!("User {}", id)))
|
||||
}
|
||||
|
||||
fn save(&mut self, user: User) -> Result<()> {
|
||||
let id = user.id;
|
||||
self.users.insert(id, user);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete(&mut self, id: u64) -> Result<()> {
|
||||
self.users.remove(&id);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn process_users(repo: &UserRepository) -> Result<Vec<String>> {
|
||||
let names: Vec<String> = repo
|
||||
.users
|
||||
.values()
|
||||
.filter(|u| u.active)
|
||||
.map(|u| u.name.clone())
|
||||
.collect();
|
||||
Ok(names)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let mut repo = UserRepository::new();
|
||||
repo.save(User::new(1, "Alice", "alice@example.com"))?;
|
||||
let names = process_users(&repo)?;
|
||||
println!("{:?}", names);
|
||||
Ok(())
|
||||
}
|
||||
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username VARCHAR(64) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password CHAR(64) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'user',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE posts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
slug VARCHAR(200) NOT NULL UNIQUE,
|
||||
body TEXT NOT NULL,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'draft'
|
||||
CHECK (status IN ('draft', 'published', 'archived')),
|
||||
view_count INTEGER NOT NULL DEFAULT 0,
|
||||
published_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
SELECT
|
||||
u.username,
|
||||
u.email,
|
||||
p.title,
|
||||
p.status,
|
||||
p.view_count
|
||||
FROM users u
|
||||
JOIN posts p ON p.author_id = u.id
|
||||
WHERE u.is_active = TRUE
|
||||
AND p.status != 'archived'
|
||||
ORDER BY p.created_at DESC
|
||||
LIMIT 20;
|
||||
|
||||
WITH cte AS (
|
||||
SELECT author_id, COUNT(*) AS cnt
|
||||
FROM posts
|
||||
GROUP BY author_id
|
||||
)
|
||||
SELECT u.username, cte.cnt
|
||||
FROM users u
|
||||
JOIN cte ON cte.author_id = u.id;
|
||||
|
||||
UPDATE posts
|
||||
SET status = 'archived',
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE published_at < datetime('now', '-1 year')
|
||||
AND status = 'published';
|
||||
|
||||
SELECT
|
||||
NULL AS maybe_value,
|
||||
COALESCE(u.email, 'no-email') AS safe_email,
|
||||
CASE
|
||||
WHEN p.view_count > 1000 THEN 'popular'
|
||||
WHEN p.view_count > 100 THEN 'moderate'
|
||||
ELSE 'quiet'
|
||||
END AS popularity
|
||||
FROM users u
|
||||
LEFT JOIN posts p ON p.author_id = u.id;
|
||||
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username VARCHAR(64) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password CHAR(64) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'user',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
);
|
||||
|
||||
SELECT
|
||||
u.username,
|
||||
u.email,
|
||||
p.title
|
||||
FROM users u
|
||||
JOIN posts p ON p.author_id = u.id
|
||||
WHERE u.is_active = TRUE
|
||||
ORDER BY p.created_at DESC
|
||||
LIMIT 20
|
||||
|
||||
SELECT * FROM;
|
||||
|
||||
CREATE INDEX ON posts(status);
|
||||
|
||||
INSERT INTO users (username, email, password)
|
||||
VALUES ('alice', 'alice@example.com');
|
||||
|
||||
UPDATE posts
|
||||
SET status = 'archived',
|
||||
WHERE published_at < datetime('now', '-1 year');
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username VARCHAR(64) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password CHAR(64) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
role VARCHAR(32) NOT NULL DEFAULT 'user',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE posts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
author_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
title VARCHAR(200) NOT NULL,
|
||||
slug VARCHAR(200) NOT NULL UNIQUE,
|
||||
body TEXT NOT NULL,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'draft'
|
||||
CHECK (status IN ('draft', 'published', 'archived')),
|
||||
view_count INTEGER NOT NULL DEFAULT 0,
|
||||
published_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(50) NOT NULL UNIQUE
|
||||
);
|
||||
|
||||
CREATE TABLE post_tags (
|
||||
post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
|
||||
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (post_id, tag_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_posts_author ON posts(author_id);
|
||||
CREATE INDEX idx_posts_status ON posts(status);
|
||||
CREATE INDEX idx_posts_slug ON posts(slug);
|
||||
CREATE INDEX idx_users_email ON users(email);
|
||||
|
||||
INSERT INTO users (username, email, password, role)
|
||||
VALUES ('alice', 'alice@example.com', 'hashed_placeholder', 'admin');
|
||||
|
||||
INSERT INTO tags (name) VALUES ('nim'), ('parsing'), ('devtools');
|
||||
|
||||
INSERT INTO posts (author_id, title, slug, body, status)
|
||||
VALUES (1, 'Introducing Nimcheck', 'introducing-nimcheck',
|
||||
'Nimcheck is a universal syntax validator.', 'published');
|
||||
|
||||
INSERT INTO post_tags (post_id, tag_id)
|
||||
SELECT p.id, t.id
|
||||
FROM posts p, tags t
|
||||
WHERE p.slug = 'introducing-nimcheck'
|
||||
AND t.name IN ('nim', 'parsing', 'devtools');
|
||||
|
||||
SELECT
|
||||
u.username,
|
||||
u.email,
|
||||
p.title,
|
||||
p.status,
|
||||
p.view_count,
|
||||
GROUP_CONCAT(t.name, ', ') AS tag_list
|
||||
FROM users u
|
||||
JOIN posts p ON p.author_id = u.id
|
||||
LEFT JOIN post_tags pt ON pt.post_id = p.id
|
||||
LEFT JOIN tags t ON t.id = pt.tag_id
|
||||
WHERE u.is_active = TRUE
|
||||
AND p.status != 'archived'
|
||||
GROUP BY p.id
|
||||
ORDER BY p.created_at DESC
|
||||
LIMIT 20;
|
||||
|
||||
UPDATE posts
|
||||
SET status = 'archived',
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE published_at < datetime('now', '-1 year')
|
||||
AND status = 'published';
|
||||
|
||||
WITH post_stats AS (
|
||||
SELECT
|
||||
author_id,
|
||||
COUNT(*) AS total_posts,
|
||||
SUM(view_count) AS total_views,
|
||||
AVG(view_count) AS avg_views
|
||||
FROM posts
|
||||
GROUP BY author_id
|
||||
)
|
||||
SELECT u.username, ps.total_posts, ps.total_views, ps.avg_views
|
||||
FROM users u
|
||||
JOIN post_stats ps ON ps.author_id = u.id
|
||||
ORDER BY ps.total_views DESC;
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
import Foundation
|
||||
|
||||
// Unicode comment: 你好世界 🌍🚀
|
||||
|
||||
// Unicode string literals
|
||||
let unicode = "こんにちは世界"
|
||||
print(unicode)
|
||||
|
||||
// Null byte in string
|
||||
let nullStr = "hello\0world"
|
||||
print("Null-str length: \(nullStr.count)")
|
||||
|
||||
// Deeply nested optionals
|
||||
let deep: Int????? = 42
|
||||
if let l1 = deep,
|
||||
let l2 = l1,
|
||||
let l3 = l2,
|
||||
let l4 = l3 {
|
||||
print("Deep optional: \(l4)")
|
||||
}
|
||||
|
||||
// Very long string
|
||||
let longStr = String(repeating: "x", count: 10000)
|
||||
print("Long string length: \(longStr.count)")
|
||||
|
||||
// BOM bytes
|
||||
let bom = Data([0xEF, 0xBB, 0xBF, 0x48, 0x69])
|
||||
print(String(data: bom, encoding: .utf8) ?? "")
|
||||
|
||||
// Deep closure nesting
|
||||
let f1: (Int) -> (Int) -> (Int) -> (Int) -> Int = { x in
|
||||
{ y in
|
||||
{ z in
|
||||
{ w in x + y + z + w }
|
||||
}
|
||||
}
|
||||
}
|
||||
print("Nested closures: \(f1(1)(2)(3)(4))")
|
||||
|
||||
// Deep dictionary nesting
|
||||
let deepDict: [String: Any] = [
|
||||
"a": [
|
||||
"b": [
|
||||
"c": [
|
||||
"d": [
|
||||
"e": "deep"
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
if let a = deepDict["a"] as? [String: Any],
|
||||
let b = a["b"] as? [String: Any],
|
||||
let c = b["c"] as? [String: Any],
|
||||
let d = c["d"] as? [String: Any],
|
||||
let e = d["e"] as? String {
|
||||
print("Deep dict: \(e)")
|
||||
}
|
||||
|
||||
// Deep error nesting
|
||||
enum AppError: Error {
|
||||
case inner(String)
|
||||
case middle(String, Error)
|
||||
case outer(String, Error)
|
||||
}
|
||||
|
||||
do {
|
||||
do {
|
||||
do {
|
||||
throw AppError.inner("oops")
|
||||
} catch {
|
||||
throw AppError.middle("wrapped", error)
|
||||
}
|
||||
} catch {
|
||||
throw AppError.outer("re-wrapped", error)
|
||||
}
|
||||
} catch {
|
||||
print("Nested error: \(error)")
|
||||
}
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
import Foundation
|
||||
|
||||
struct Broken {
|
||||
let x: Int
|
||||
let name: String
|
||||
}
|
||||
|
||||
class BadRepo {
|
||||
private var items: [Int: String] = [:]
|
||||
|
||||
func add(key: Int, item: String) {
|
||||
items[key] = item
|
||||
}
|
||||
|
||||
func show() {
|
||||
print("hello")
|
||||
let x = 5
|
||||
print(x)
|
||||
}
|
||||
}
|
||||
|
||||
let s = "unclosed string
|
||||
print(s)
|
||||
|
||||
let x = 5
|
||||
if x > 0 {
|
||||
print("positive")
|
||||
|
||||
func missingReturn() -> Int {
|
||||
let a = 5
|
||||
}
|
||||
|
||||
let list = [1, 2, 3
|
||||
print(list)
|
||||
|
||||
func badFunction() {
|
||||
let y = 5
|
||||
print(y)
|
||||
}
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
import Foundation
|
||||
|
||||
struct Person: Codable {
|
||||
let id: Int
|
||||
let name: String
|
||||
let email: String
|
||||
let active: Bool
|
||||
|
||||
init(id: Int, name: String, email: String, active: Bool = true) {
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.email = email
|
||||
self.active = active
|
||||
}
|
||||
}
|
||||
|
||||
class Repository<T> {
|
||||
private var items: [Int: T] = [:]
|
||||
|
||||
func add(key: Int, item: T) {
|
||||
items[key] = item
|
||||
}
|
||||
|
||||
func find(key: Int) -> T? {
|
||||
return items[key]
|
||||
}
|
||||
|
||||
func getAll() -> [T] {
|
||||
return Array(items.values)
|
||||
}
|
||||
}
|
||||
|
||||
func add(_ a: Int, _ b: Int) -> Int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
enum Result<T> {
|
||||
case success(T)
|
||||
case failure(Error)
|
||||
}
|
||||
|
||||
let repo = Repository<Person>()
|
||||
repo.add(key: 1, item: Person(id: 1, name: "Alice", email: "alice@example.com"))
|
||||
repo.add(key: 2, item: Person(id: 2, name: "Bob", email: "bob@example.com"))
|
||||
|
||||
for person in repo.getAll() {
|
||||
print("\(person.name) <\(person.email)>")
|
||||
}
|
||||
|
||||
print("3 + 4 = \(add(3, 4))")
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
active: boolean;
|
||||
metadata: Record<string, unknown>;
|
||||
tags: string[];
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
type Result<T> = {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
error?: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
type DeepPartial<T> = {
|
||||
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
|
||||
};
|
||||
|
||||
type Nullable<T> = T | null | undefined;
|
||||
|
||||
type UnionToIntersection<U> =
|
||||
(U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
||||
|
||||
class Container<T> {
|
||||
constructor(private value: T) {}
|
||||
|
||||
map<U>(fn: (val: T) => U): Container<U> {
|
||||
return new Container(fn(this.value));
|
||||
}
|
||||
|
||||
flatMap<U>(fn: (val: T) => Container<U>): Container<U> {
|
||||
return fn(this.value);
|
||||
}
|
||||
|
||||
unwrap(): T {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
function pipe<T>(...fns: Array<(arg: T) => T>): (arg: T) => T {
|
||||
return (arg: T) => fns.reduce((acc, fn) => fn(acc), arg);
|
||||
}
|
||||
|
||||
function memoize<T extends (...args: unknown[]) => unknown>(fn: T): T {
|
||||
const cache = new Map<string, unknown>();
|
||||
return ((...args: unknown[]) => {
|
||||
const key = JSON.stringify(args);
|
||||
if (cache.has(key)) return cache.get(key);
|
||||
const result = fn(...args);
|
||||
cache.set(key, result);
|
||||
return result;
|
||||
}) as unknown as T;
|
||||
}
|
||||
|
||||
function withDefault<T>(value: T | undefined | null, fallback: T): T {
|
||||
return value ?? fallback;
|
||||
}
|
||||
|
||||
async function* paginate<T>(url: string, pageSize: number): AsyncGenerator<T[], void, unknown> {
|
||||
let page = 0;
|
||||
while (true) {
|
||||
const response = await fetch(`${url}?page=${page}&size=${pageSize}`);
|
||||
const items: T[] = await response.json();
|
||||
if (items.length === 0) return;
|
||||
yield items;
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
export { User, Result, Container, pipe, memoize, withDefault, paginate };
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
interface Broken {
|
||||
id number;
|
||||
name: ;
|
||||
email string;
|
||||
}
|
||||
|
||||
type Result<T> = {
|
||||
success: boolean
|
||||
data?: T
|
||||
error: string
|
||||
};
|
||||
|
||||
abstract class BadRepo<T extends id: number>> {
|
||||
protected items: Map<number, T> = new Map();
|
||||
|
||||
findById(id: number): T | undefined {
|
||||
return this.items.get(id);
|
||||
|
||||
validate(entity: T): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchBad(url: string): Promise<Result<User[]>> {
|
||||
const response = await fetch(url);
|
||||
const data: User[[]] = await response.json();
|
||||
return { success: true, data };
|
||||
}
|
||||
|
||||
const x: = 42;
|
||||
const y = x as;
|
||||
|
||||
function missingReturn(x: number): string {
|
||||
if (x > 0)
|
||||
return "positive"
|
||||
}
|
||||
Vendored
+86
@@ -0,0 +1,86 @@
|
||||
interface User {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
active: boolean;
|
||||
metadata: Record<string, unknown>;
|
||||
tags: string[];
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
type Result<T> = {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
error?: string;
|
||||
timestamp: number;
|
||||
};
|
||||
|
||||
enum LogLevel {
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Warn = 2,
|
||||
Error = 3,
|
||||
}
|
||||
|
||||
abstract class BaseRepository<T extends { id: number }> {
|
||||
protected items: Map<number, T> = new Map();
|
||||
|
||||
findById(id: number): T | undefined {
|
||||
return this.items.get(id);
|
||||
}
|
||||
|
||||
abstract validate(entity: T): boolean;
|
||||
|
||||
save(entity: T): Result<T> {
|
||||
if (!this.validate(entity)) {
|
||||
return { success: false, error: "Validation failed", timestamp: Date.now() };
|
||||
}
|
||||
this.items.set(entity.id, entity);
|
||||
return { success: true, data: entity, timestamp: Date.now() };
|
||||
}
|
||||
}
|
||||
|
||||
class UserRepository extends BaseRepository<User> {
|
||||
validate(user: User): boolean {
|
||||
return user.name.length > 0 && user.email.includes("@");
|
||||
}
|
||||
|
||||
findByEmail(email: string): User | undefined {
|
||||
for (const user of this.items.values()) {
|
||||
if (user.email === email) return user;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchUsers(url: string): Promise<Result<User[]>> {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data: User[] = await response.json();
|
||||
return { success: true, data, timestamp: Date.now() };
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Unknown error";
|
||||
return { success: false, error: message, timestamp: Date.now() };
|
||||
}
|
||||
}
|
||||
|
||||
function processItems<T, U>(items: T[], transform: (item: T) => U): U[] {
|
||||
return items.map(transform);
|
||||
}
|
||||
|
||||
const repo = new UserRepository();
|
||||
const user: User = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
email: "alice@example.com",
|
||||
active: true,
|
||||
metadata: { role: "admin", level: 42 },
|
||||
tags: ["typescript", "backend"],
|
||||
createdAt: new Date(),
|
||||
};
|
||||
|
||||
repo.save(user);
|
||||
|
||||
const names = processItems(repo.items.size > 0 ? Array.from(repo.items.values()) : [], (u) => u.name.toUpperCase());
|
||||
|
||||
export { User, UserRepository, fetchUsers, processItems, LogLevel };
|
||||
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Unicode comment: 你好世界 🌍🚀 -->
|
||||
<edge-cases>
|
||||
<!-- Unicode content -->
|
||||
<unicode>こんにちは世界🌍🚀</unicode>
|
||||
|
||||
<!-- Null byte in content (will be truncated by XML parser) -->
|
||||
<null-bytes>hello�world</null-bytes>
|
||||
|
||||
<!-- Deeply nested elements -->
|
||||
<level1>
|
||||
<level2>
|
||||
<level3>
|
||||
<level4>
|
||||
<level5>
|
||||
<level6>
|
||||
<level7>
|
||||
<level8>
|
||||
<value>deep</value>
|
||||
</level8>
|
||||
</level7>
|
||||
</level6>
|
||||
</level5>
|
||||
</level4>
|
||||
</level3>
|
||||
</level2>
|
||||
</level1>
|
||||
|
||||
<!-- Very long string content -->
|
||||
<long-string>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</long-string>
|
||||
|
||||
<!-- BOM prefix (encoded) -->
|
||||
<bom>Hi</bom>
|
||||
|
||||
<!-- Special characters -->
|
||||
<special-chars>&<>"'</special-chars>
|
||||
|
||||
<!-- CDATA with special content -->
|
||||
<cdata-example><![CDATA[<script>alert("xss")</script>]]></cdata-example>
|
||||
|
||||
<!-- Deep attribute nesting (flat but many attributes) -->
|
||||
<multi-attrs a="1" b="2" c="3" d="4" e="5" f="6" g="7" h="8" i="9" j="10" k="11" l="12" m="13" n="14" o="15" p="16" q="17" r="18" s="19" t="20">many-attrs</multi-attrs>
|
||||
|
||||
<!-- Mixed content -->
|
||||
<mixed>Some text <child>with child</child> and more text <another/> trailing.</mixed>
|
||||
</edge-cases>
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<fixtures>
|
||||
<person id=1>
|
||||
<name>Alice</name>
|
||||
<email>alice@example.com
|
||||
</person>
|
||||
<person id="2">
|
||||
<name>Bob</name>
|
||||
<email>bob@example.com</email>
|
||||
<active>true</active>
|
||||
</persn>
|
||||
<unclosed>
|
||||
<inner>value
|
||||
<bad>&unknown;</bad>
|
||||
<nested>
|
||||
<unclosedTag>
|
||||
</metadata>
|
||||
</fixtures>
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<fixtures>
|
||||
<person id="1">
|
||||
<name>Alice</name>
|
||||
<email>alice@example.com</email>
|
||||
<active>true</active>
|
||||
<tags>
|
||||
<tag>admin</tag>
|
||||
<tag>backend</tag>
|
||||
</tags>
|
||||
</person>
|
||||
<person id="2">
|
||||
<name>Bob</name>
|
||||
<email>bob@example.com</email>
|
||||
<active>false</active>
|
||||
<tags>
|
||||
<tag>user</tag>
|
||||
</tags>
|
||||
</person>
|
||||
<metadata>
|
||||
<source>test-fixture</source>
|
||||
<version>1.0</version>
|
||||
<generated>2026-07-13</generated>
|
||||
</metadata>
|
||||
</fixtures>
|
||||
Reference in New Issue
Block a user