Skip to content

Commit f2f4937

Browse files
authored
Utility function to handle empty query results and templates (#1386)
* Add global Lua function 'some' Moved documentation for 'each' function to non-standard section. * Revert "Add optional argument to template.each for empty collection output (#1359)" This reverts commit b73dade. * Reimplement #1359 using 'some' function
1 parent 10e7cea commit f2f4937

File tree

9 files changed

+98
-33
lines changed

9 files changed

+98
-33
lines changed

Library/Std/Pages/Maintenance.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ We would like to keep our space clean. These are some tools that help you do tha
55
# Aspiring pages
66
This shows page links (max 20 to keep things sensible) that link to a page that does not (yet) exist. These could be broken links or just pages _aspiring_ to be created.
77

8-
${template.each(query[[
8+
${some(template.each(query[[
99
from index.tag "aspiring-page"
1010
limit 20
1111
]], template.new[==[
1212
* [[${ref}]]: broken link to [[${name}]]
13-
]==], "No aspiring pages, all good!")}
13+
]==])) or "No aspiring pages, all good!"}
1414

1515
# Conflicting copies
1616
These are pages that have conflicting copies (as a result of sync). Have a look at them as well as their original (non-conflicting) versions and decide which one to keep.
1717

18-
${template.each(query[[
18+
${some(template.each(query[[
1919
from index.tag "page" where name:find("%.conflicted%.")
2020
]], template.new[==[
2121
* [[${name:gsub("%.conflicted%..+$", "")}]]: conflict copy [[${name}]]
22-
]==], "No conflicting pages!")}
22+
]==]) or "No conflicting pages!"}

Library/Std/Template.md

+4-11
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,13 @@ template = template or {}
1010
templates = {}
1111
1212
-- Iterates over a table/array and applies a function to each element,
13-
-- concatenating the results. The last, optional argument is output for empty table
14-
function template.each(tbl, fn, empty)
15-
local empty = empty or ""
16-
13+
-- concatenating the results
14+
function template.each(tbl, fn)
1715
local result = {}
1816
for _, item in ipairs(tbl) do
1917
table.insert(result, fn(item))
2018
end
21-
22-
if #result == 0 then
23-
return empty
24-
else
25-
return table.concat(result)
26-
end
19+
return table.concat(result)
2720
end
2821
2922
-- Creates a new template function from a string template
@@ -60,4 +53,4 @@ function template.fromPage(name, raw)
6053
end
6154
return template.new(templateText), fm.frontmatter
6255
end
63-
```
56+
```

common/space_lua/lua.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ Deno.test("[Lua] JS tests", async () => {
3838
await runLuaTest("./stdlib/js_test.lua");
3939
});
4040

41+
Deno.test("[Lua] Global functions tests", async () => {
42+
await runLuaTest("./stdlib/global_test.lua");
43+
});
44+
4145
async function runLuaTest(luaPath: string) {
4246
const luaFile = await Deno.readTextFile(
4347
fileURLToPath(new URL(luaPath, import.meta.url)),

common/space_lua/stdlib.ts

+16
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
luaCall,
55
LuaEnv,
66
luaGet,
7+
luaKeys,
78
LuaMultiRes,
89
LuaRuntimeError,
910
type LuaTable,
@@ -203,6 +204,20 @@ const dofileFunction = new LuaBuiltinFunction(async (sf, filename: string) => {
203204
}
204205
});
205206

207+
const someFunction = new LuaBuiltinFunction(async (_sf, value: any) => {
208+
switch (await luaTypeOf(value)) {
209+
case "number":
210+
if (!isFinite(value)) return null;
211+
break;
212+
case "string":
213+
if (value.trim() === "") return null;
214+
break;
215+
case "table":
216+
if (luaKeys(value).length === 0) return null;
217+
}
218+
return value;
219+
});
220+
206221
export function luaBuildStandardEnv() {
207222
const env = new LuaEnv();
208223
// Top-level builtins
@@ -233,5 +248,6 @@ export function luaBuildStandardEnv() {
233248
// Non-standard
234249
env.set("each", eachFunction);
235250
env.set("spacelua", spaceluaApi);
251+
env.set("some", someFunction);
236252
return env;
237253
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
local function assertEqual(a, b)
2+
if a ~= b then
3+
error("Assertion failed: " .. a .. " is not equal to " .. b)
4+
end
5+
end
6+
7+
-- Logic values, shouldn't be affected
8+
assertEqual(some(nil), nil)
9+
assertEqual(some(true), true)
10+
assertEqual(some(false), false)
11+
12+
-- Numbers
13+
assertEqual(some(1), 1)
14+
assertEqual(some(0), 0) -- 0 is not falsy unlike C
15+
assertEqual(some(-1), -1)
16+
assertEqual(some(1/0), nil) -- inf
17+
assertEqual(some(0/0), nil) -- nan
18+
19+
-- Strings
20+
assertEqual(some("foo bar"), "foo bar")
21+
assertEqual(some(""), nil)
22+
assertEqual(some(" \n"), nil)
23+
24+
-- Tables
25+
assertEqual(some({}), nil)
26+
assertEqual(some({"baz"})[1], "baz") -- compare an element to ensure passthrough
27+
assertEqual(some({foo="bar"})["foo"], "bar")

website/API/global.md

+32-16
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,6 @@ end
4949
-- city New York
5050
```
5151

52-
## each
53-
Returns an iterator for array-like tables that iterates over values only (without indices).
54-
55-
Example:
56-
```lua
57-
local fruits = {"apple", "banana", "orange"}
58-
for fruit in each(fruits) do
59-
print(fruit)
60-
end
61-
-- Output:
62-
-- apple
63-
-- banana
64-
-- orange
65-
```
66-
6752
## unpack
6853
Unpacks a table into individual values.
6954

@@ -202,4 +187,35 @@ print(t.foo) -- prints: "bar"
202187
```
203188

204189
## dofile(path)
205-
Loads a Lua file from a path in your space, e.g. if you uploaded a `test.lua` file, you can load it with `dofile("test.lua")`.
190+
Loads a Lua file from a path in your space, e.g. if you uploaded a `test.lua` file, you can load it with `dofile("test.lua")`.
191+
192+
# Non-standard Extensions
193+
## each
194+
Returns an iterator for array-like tables that iterates over values only (without indices).
195+
196+
Example:
197+
```lua
198+
local fruits = {"apple", "banana", "orange"}
199+
for fruit in each(fruits) do
200+
print(fruit)
201+
end
202+
-- Output:
203+
-- apple
204+
-- banana
205+
-- orange
206+
```
207+
208+
## some
209+
Returns nil if the value is empty, otherwise returns the value unchanged. Empty tables, strings containing only whitespace, `inf` and `nan` numeric value are considered empty.
210+
211+
Example:
212+
```lua
213+
print(some("hello")) -- hello
214+
print(some("")) -- nil
215+
print(some(" ")) -- nil
216+
print(some({})) -- nil
217+
print(some(0)) -- 0
218+
print(some(1/0)) -- nil
219+
220+
print(some({}) or "empty") -- empty
221+
```

website/API/template.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ examples.sayHello = template.new[==[Hello ${name}!]==]
1313

1414
And its use: ${examples.sayHello {name="Pete"}}
1515

16-
## template.each(collection, template, empty="")
17-
Iterates over a collection and renders a template for each item. Optionally specify output for an empty collection.
16+
## template.each(collection, template)
17+
Iterates over a collection and renders a template for each item.
1818

1919
Example:
2020

website/Space Lua.md

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ A new syntax introduced with Space Lua is the `${lua expression}` syntax that yo
5757

5858
For example: 10 + 2 = ${adder(10, 2)} (Alt-click, or select to see the expression) is using the just defined `adder` function to this rather impressive calculation.
5959

60+
Note that you can have the text {lua expression} in your page and it won't be evaluated. So writing `${"$"}{lua expression}` can be used to “delay” evaluation by one pass, for example to escape expressions in templated content.
61+
6062
## Queries
6163
Space Lua has a feature called [[Space Lua/Lua Integrated Query]], which integrate SQL-like queries into Lua. Here’s a small example querying the last 3 modifies pages:
6264

website/Space Lua/Lua Integrated Query.md

+7
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ ${query[[
2828
limit 3
2929
]]}
3030

31+
Note that the query returns a regular Lua table, so it can be part of a bigger expression:
32+
33+
${some(query[[
34+
from p = index.tag "page"
35+
limit 0
36+
]]) or "Matched no pages"}
37+
3138
# Clauses
3239
Here are the clauses that are currently supported:
3340

0 commit comments

Comments
 (0)