diff --git a/.lune/data/test.csv b/.lune/data/test.csv
new file mode 100644
index 0000000..dbc7627
--- /dev/null
+++ b/.lune/data/test.csv
@@ -0,0 +1,4 @@
+Header1,Header2,Header3
+Hello,World,!
+1,2,3
+Foo,Bar,Baz
\ No newline at end of file
diff --git a/.lune/examples/csv_printer.luau b/.lune/examples/csv_printer.luau
new file mode 100644
index 0000000..ab4f5c3
--- /dev/null
+++ b/.lune/examples/csv_printer.luau
@@ -0,0 +1,59 @@
+--> A utility script that prints out a CSV
+--> file in a prettified format to stdout
+
+local LINE_SEPARATOR = "\n"
+local COMMA_SEPARATOR = ","
+
+local path = process.args[1] or ".lune/data/test.csv"
+
+assert(path ~= nil and #path > 0, "No input file path was given")
+assert(not fs.isDir(path), "Input file path was a dir, not a file")
+assert(fs.isFile(path), "Input file path does not exist")
+
+-- Read all the lines of the wanted file
+local rawLines = string.split(fs.readFile(path), LINE_SEPARATOR)
+
+-- Split the raw lines into header and table of data
+local csvHeader = string.split(rawLines[1], COMMA_SEPARATOR)
+local csvTable = {}
+for index = 2, #rawLines, 1 do -- NOTE: We skip the first line here, that's the header
+ csvTable[index - 1] = string.split(rawLines[index], COMMA_SEPARATOR)
+end
+
+-- Gather the maximum widths of strings for alignment
+local maxWidths = {}
+
+for index, header in csvHeader do
+ maxWidths[index] = #header
+end
+
+for _, row in csvTable do
+ for index, value in row do
+ maxWidths[index] = math.max(maxWidths[index], #value)
+ end
+end
+
+local totalWidth = 0
+for _, width in maxWidths do
+ totalWidth += width
+end
+
+-- Print it all out
+
+local function printRow(row: { string })
+ local paddedValues = {}
+ for index, value in row do
+ local spacing = string.rep(" ", maxWidths[index] - #value)
+ table.insert(paddedValues, string.format(" %s%s ", value, spacing))
+ end
+ print(string.format("┃ %s ┃", table.concat(paddedValues, "┃")))
+end
+
+local thiccLine = string.rep("━", totalWidth + #csvHeader * 3 + 1)
+print(string.format("┏%s┓", thiccLine))
+printRow(csvHeader)
+print(string.format("┣%s┫", thiccLine))
+for _, row in csvTable do
+ printRow(row)
+end
+print(string.format("┗%s┛", thiccLine))
diff --git a/.lune/examples/server.luau b/.lune/examples/server.luau
new file mode 100644
index 0000000..f8fe022
--- /dev/null
+++ b/.lune/examples/server.luau
@@ -0,0 +1,41 @@
+--> A basic webserver that echoes the given request
+--> body at /ping and otherwise responds 404 "Not Found"
+
+local PORT = if process.env.PORT ~= nil and #process.env.PORT > 0
+ then assert(tonumber(process.env.PORT), "Failed to parse port from env")
+ else 8080
+
+-- Create our responder functions
+
+local function pong(request: NetRequest): NetResponse
+ return {
+ body = `Pong!\n{request.path}\n{request.body}"`,
+ }
+end
+
+local function notFound(request: NetRequest): NetResponse
+ return {
+ status = 404,
+ body = "Not Found",
+ }
+end
+
+-- Exit our example after a small delay, if you copy this
+-- example just remove this part to keep the server running
+
+task.delay(2, function()
+ print("Shutting down...")
+ task.wait(1)
+ process.exit(0)
+end)
+
+-- Run the server on port 8080
+
+print(`Listening on port {PORT} 🚀`)
+net.serve(PORT, function(request)
+ if string.sub(request.path, 1, 6) == "/ping" then
+ return pong(request)
+ else
+ return notFound(request)
+ end
+end)
diff --git a/.lune/hello_lune.luau b/.lune/hello_lune.luau
index 63707d7..4251038 100644
--- a/.lune/hello_lune.luau
+++ b/.lune/hello_lune.luau
@@ -8,7 +8,7 @@ print("Hello, lune! 🌙")
Using a function from another module
]==]
-local module = require("./module")
+local module = require("./modules/module")
module.sayHello()
--[==[
diff --git a/.lune/module.luau b/.lune/modules/module.luau
similarity index 100%
rename from .lune/module.luau
rename to .lune/modules/module.luau
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ba43e0..6fddc6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Added
+
+- Added global types for networking & child process APIs
+ - `net.request` gets `NetFetchParams` and `NetFetchResponse` for its argument and return value
+ - `net.serve` gets `NetRequest` and `NetResponse` for the handler function argument and return value
+ - `process.spawn` gets `ProcessSpawnOptions` for its third and optional parameter
+
## `0.2.1` - February 3rd, 2023
### Added
diff --git a/README.md b/README.md
index 02ecd2f..7402b55 100644
--- a/README.md
+++ b/README.md
@@ -29,8 +29,8 @@ You can also download pre-built binaries for most systems directly from the GitH
## ✏️ Writing Lune Scripts
-Check out the examples on how to write a script in the [.lune](.lune) folder !
-A great starting point and walkthrough of Lune can be found in the [Hello, Lune](.lune/hello_lune.luau) example.
+A great starting point and walkthrough of Lune can be found in [Hello, Lune](.lune/hello_lune.luau).
+More examples of how to write Lune scripts can be found in the [examples](.lune/examples/) folder.
🔎 List of APIs
diff --git a/luneTypes.d.luau b/luneTypes.d.luau
index f51e1cf..f29e083 100644
--- a/luneTypes.d.luau
+++ b/luneTypes.d.luau
@@ -210,6 +210,35 @@ declare fs: {
isDir: (path: string) -> boolean,
}
+type NetMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH"
+
+export type NetFetchParams = {
+ url: string,
+ method: NetMethod?,
+ headers: { [string]: string }?,
+ body: string?,
+}
+export type NetFetchResponse = {
+ ok: boolean,
+ statusCode: number,
+ statusMessage: string,
+ headers: { [string]: string },
+ body: string,
+}
+
+export type NetRequest = {
+ path: string,
+ query: string,
+ method: NetMethod,
+ headers: { [string]: string },
+ body: string,
+}
+export type NetResponse = {
+ status: number?,
+ headers: { [string]: string }?,
+ body: string?,
+}
+
--[=[
@class net
@@ -226,18 +255,7 @@ declare net: {
@param config The URL or request config to use
@return A dictionary representing the response for the request
]=]
- request: (config: string | {
- url: string,
- method: ("GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH")?,
- headers: { [string]: string }?,
- body: string?,
- }) -> {
- ok: boolean,
- statusCode: number,
- statusMessage: string,
- headers: { [string]: string },
- body: string,
- },
+ request: (config: string | NetFetchParams) -> NetFetchResponse,
--[=[
@within net
@@ -250,17 +268,7 @@ declare net: {
@param port The port to use for the server
@param handler The handler function to use for the server
]=]
- serve: (port: number, handler: (request: {
- path: string,
- query: string,
- method: "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH",
- headers: { [string]: string }?,
- body: string?,
- }) -> (string | {
- status: number?,
- headers: { [string]: string }?,
- body: string?,
- })) -> (),
+ serve: (port: number, handler: (request: NetRequest) -> (string | NetResponse)) -> (),
--[=[
@within net
@@ -282,6 +290,15 @@ declare net: {
jsonDecode: (encoded: string) -> any,
}
+type ProcessSpawnOptionsStdio = "inherit" | "default"
+
+export type ProcessSpawnOptions = {
+ cwd: string?,
+ env: { [string]: string }?,
+ shell: (boolean | string)?,
+ stdio: ProcessSpawnOptionsStdio?,
+}
+
--[=[
@class process
@@ -342,12 +359,7 @@ declare process: {
spawn: (
program: string,
params: { string }?,
- options: {
- cwd: string?,
- env: { [string]: string }?,
- shell: (boolean | string)?,
- stdio: ("inherit" | "default")?,
- }?
+ options: ProcessSpawnOptions?
) -> {
ok: boolean,
code: number,