Add TypeScript

This commit is contained in:
2025-11-19 20:02:23 +01:00
parent f4b474f0b9
commit 11a59418e8
11 changed files with 202 additions and 23 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Martin Petr
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

34
README.md Normal file
View File

@@ -0,0 +1,34 @@
# Lints
## What the hell is this?
Lints is an experimental operating system kernel written almost entirely in TypeScript. This is not some in-browser system emulator or WebAssembly hack; Lints actually runs on real hardware (or a hardware emulator like QEMU) by leveraging a JavaScript engine with a small C kernel (just some basic memory management needed by the JS engine) and JS-to-C bindings for purposes like writting data to pointers, etc.
## Why?
- I can.
- I want to be able to say that I did it.
- I am not sane and don't have a life.
- TypeScript haters.
- "Anything that can be done in JavaScript will eventually be done in JavaScript." - Jeff Atwood
## How to run it?
Please don't.
If you really want to, make sure you have Docker installed, then run:
```bash
./scripts/run-kernel.sh
```
## If you are an employer looking at this...
I would appreciate if you messaged me and gave me some well-paid job. Also...
Please don't judge me based on this project. I swear I can write normal code too.
## License
MIT License. See LICENSE file for details.
TL;DR: Do whatever you want with it, but don't blame me if it blows up in your face. Also I'd appreciate that you give me credit if you use any of my code, ideas or whatever - I mean why would someone even want to be associated with this project (or steal it), right?

View File

@@ -10,8 +10,12 @@ RUN dnf install -y \
qemu-system-x86 \ qemu-system-x86 \
wget \ wget \
meson \ meson \
unzip \
&& dnf clean all && dnf clean all
RUN curl -fsSL https://bun.sh/install | bash
ENV PATH="/root/.bun/bin:${PATH}"
WORKDIR /workspace WORKDIR /workspace
CMD ["bash", "-c", "/workspace/scripts/build-picolibc.sh && /workspace/scripts/build-kernel.sh"] CMD ["bash", "-c", "/workspace/scripts/build-picolibc.sh && /workspace/scripts/build-kernel.sh"]

View File

@@ -19,8 +19,11 @@ fi
mkdir -p "$BUILD_DIR" mkdir -p "$BUILD_DIR"
mkdir -p "$OUT_DIR" mkdir -p "$OUT_DIR"
# Copy JavaScript source to build directory # Build TypeScript to JavaScript
cp src/os/index.js build/ cd src/os
echo "Compiling TypeScript to JavaScript..."
bun build --outdir ../../build --target node --bundle kernel/index.ts
cd ../../
# Generate embedded JavaScript header # Generate embedded JavaScript header
echo "Generating embedded JavaScript..." echo "Generating embedded JavaScript..."

34
src/os/.gitignore vendored Normal file
View File

@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules
# output
out
dist
*.tgz
# code coverage
coverage
*.lcov
# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# caches
.eslintcache
.cache
*.tsbuildinfo
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

29
src/os/bun.lock Normal file
View File

@@ -0,0 +1,29 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "os",
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5",
},
},
},
"packages": {
"@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="],
"@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="],
"@types/react": ["@types/react@19.2.6", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w=="],
"bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
}
}

View File

@@ -1,21 +0,0 @@
clearScreen();
print("Hello, World!");
function clearScreen() {
var i = 0;
while (i < 80 * 25 * 2) {
writeMemory(0xb8000 + i, 0x00);
i++;
}
}
function printChar(char, offset) {
writeMemory(0xb8000 + offset * 2, char.charCodeAt(0));
writeMemory(0xb8000 + offset * 2 + 1, 0x0f); // White on black
}
function print(str) {
for (var i = 0; i < str.length; i++) {
printChar(str.charAt(i), i);
}
}

33
src/os/kernel/index.ts Normal file
View File

@@ -0,0 +1,33 @@
const SCREEN_WIDTH = 80;
const SCREEN_HEIGHT = 25;
const VIDEO_MEMORY_START = 0xb8000;
clearScreen();
print("Welcome to Lints OS!", 0, 0, 0x0a); // Light green on black
function clearScreen(): void {
for (var row = 0; row < SCREEN_HEIGHT; row++) {
for (var col = 0; col < SCREEN_WIDTH; col++) {
const address = VIDEO_MEMORY_START + 2 * (row * SCREEN_WIDTH + col);
writeMemory(address, 0x20); // ASCII space
writeMemory(address + 1, 0x07); // Light grey on black
}
}
}
function writeChar(
row: number,
col: number,
char: string,
color: number
): void {
const address = VIDEO_MEMORY_START + 2 * (row * SCREEN_WIDTH + col);
writeMemory(address, char.charCodeAt(0));
writeMemory(address + 1, color);
}
function print(text: string, row: number, col: number, color: number): void {
for (var i = 0; i < text.length; i++) {
writeChar(row, col + i, text[i]!, color);
}
}

12
src/os/package.json Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "os",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5"
}
}

29
src/os/tsconfig.json Normal file
View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

1
src/os/types/kernel/functions.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare function writeMemory(address: number, value: number): void;