Skip to content

Commit 0048a12

Browse files
authored
Merge pull request #49 from getlang-dev/macros-and-modifiers
macros and modifiers
2 parents 78933c2 + 72a958a commit 0048a12

52 files changed

Lines changed: 1175 additions & 549 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 566 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bun.lockb

-88.6 KB
Binary file not shown.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "get",
33
"license": "Apache-2.0",
44
"private": true,
5-
"packageManager": "bun@1.2.20",
5+
"packageManager": "bun@1.2.21",
66
"scripts": {
77
"fmt": "biome check --write",
88
"lint": "bun lint:check && bun lint:types && bun lint:unused && bun lint:repo",
@@ -18,11 +18,11 @@
1818
"test"
1919
],
2020
"devDependencies": {
21-
"@biomejs/biome": "^2.2.0",
21+
"@biomejs/biome": "^2.2.3",
2222
"@changesets/changelog-github": "^0.5.1",
2323
"@changesets/cli": "^2.29.6",
24-
"@types/bun": "^1.2.20",
25-
"knip": "^5.62.0",
24+
"@types/bun": "^1.2.21",
25+
"knip": "^5.63.1",
2626
"sherif": "^1.6.1",
2727
"typescript": "^5.9.2"
2828
}

packages/get/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
"@getlang/ast": "workspace:^0.0.1",
2121
"@getlang/lib": "workspace:^0.1.5",
2222
"@getlang/parser": "workspace:^0.3.4",
23-
"@getlang/utils": "workspace:^0.1.6",
2423
"@getlang/walker": "workspace:^0.0.1",
24+
"acorn": "^8.15.0",
25+
"estree-toolkit": "^1.7.13",
2526
"lodash-es": "^4.17.21"
2627
},
2728
"devDependencies": {

packages/get/src/calls.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import type { TypeInfo } from '@getlang/ast'
2+
import { Type } from '@getlang/ast'
3+
import type { Hooks, Inputs } from '@getlang/lib'
4+
import { cookies, html, invariant, js, json } from '@getlang/lib'
5+
import { ImportError, ValueReferenceError } from '@getlang/lib/errors'
6+
import { partition } from 'lodash-es'
7+
import type { Entry, Registry } from './registry.js'
8+
import type { RuntimeValue } from './value.js'
9+
import { materialize } from './value.js'
10+
11+
export async function callModifier(
12+
registry: Registry,
13+
mod: string,
14+
args: Record<string, unknown>,
15+
context?: RuntimeValue,
16+
) {
17+
const entry = await registry.importMod(mod)
18+
if (entry) {
19+
return entry.mod(context?.data, args)
20+
}
21+
22+
invariant(context, 'Modifier requires context')
23+
24+
if (mod === 'link') {
25+
invariant(typeof args.base === 'string', '@link requires base url')
26+
const data = html.findLink(context.data)
27+
const link = materialize({ data, typeInfo: context.typeInfo })
28+
return new URL(link, args.base).toString()
29+
}
30+
31+
const doc = materialize(context)
32+
33+
switch (mod) {
34+
case 'html':
35+
return html.parse(doc)
36+
case 'js':
37+
return js.parse(doc)
38+
case 'json':
39+
return json.parse(doc)
40+
case 'cookies':
41+
return cookies.parse(doc)
42+
default:
43+
throw new ValueReferenceError(`Unsupported modifier: ${mod}`)
44+
}
45+
}
46+
47+
export type Execute = (entry: Entry, inputs: Inputs) => Promise<any>
48+
49+
export async function callModule(
50+
registry: Registry,
51+
execute: Execute,
52+
hooks: Required<Hooks>,
53+
module: string,
54+
args: RuntimeValue,
55+
contextType?: TypeInfo,
56+
) {
57+
let entry: Entry
58+
try {
59+
entry = await registry.import(module, [], contextType)
60+
} catch (e) {
61+
const err = `Failed to import module: ${module}`
62+
throw new ImportError(err, { cause: e })
63+
}
64+
const [inputArgs, attrArgs] = partition(Object.entries(args.data), e =>
65+
entry.inputs.has(e[0]),
66+
)
67+
const inputs = Object.fromEntries(inputArgs)
68+
let extracted = await hooks.call(module, inputs)
69+
if (typeof extracted === 'undefined') {
70+
extracted = await execute(entry, inputs)
71+
}
72+
await hooks.extract(module, inputs, extracted.data)
73+
74+
function dropWarning(reason: string) {
75+
if (attrArgs.length) {
76+
const dropped = attrArgs.map(e => e[0]).join(', ')
77+
const err = [
78+
`Module '${module}' ${reason}`,
79+
`dropping view attributes: ${dropped}`,
80+
].join(', ')
81+
console.warn(err)
82+
}
83+
}
84+
85+
if (entry.returnType.type !== Type.Value) {
86+
dropWarning('returned unmaterialized value')
87+
return extracted
88+
}
89+
90+
if (typeof extracted !== 'object') {
91+
dropWarning('returned a primitive')
92+
return extracted
93+
}
94+
95+
const data = Object.fromEntries(attrArgs)
96+
const raster = materialize({ data, typeInfo: args.typeInfo })
97+
return { ...raster, ...extracted }
98+
}

0 commit comments

Comments
 (0)