Skip to content

Commit

Permalink
feat: simple key/value pairs
Browse files Browse the repository at this point in the history
  • Loading branch information
tpluscode committed Feb 22, 2024
1 parent 869296a commit 829dc79
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-pants-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"rdf-loader-code": minor
---

Add simpler syntax for creating key/value pair arguments (closes #37, closes #38)
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
root = true

[*]
indent_size = 2
indent_style = space
insert_final_newline = true
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,13 @@ loading of an argument map. Such arguments are declared as name/value pairs.

```turtle
@prefix code: <https://code.described.at/>.
@prefix arg: <https://code.described.at/argument#>.
<urn:call:string#startsWith>
code:arguments [
code:name "first"; code:value "foo"
], [
code:name "second"; code:value "bar"
] .
code:arguments ([
arg:first "foo" ;
arg:second "bar" ;
]) .
```

Executing the code below against the above triples will return an object containing the values
Expand All @@ -220,20 +220,32 @@ Executing the code below against the above triples will return an object contain
]
```

To make this method consistent with the positional flavor, the object will actually be wrapped
in an array as presented above.
#### Mixed arguments

Both methods can be sed together to represent any kind of function signature.

For example, to call a function as below

```js
import rdf from '@zazuko/env'
import loadArguments from 'rdf-loader-code/arguments.js'
import registry from './registry.js'
import dataset from './dataset.js'
myFunction('foo', 42, { bar: { baz: 'baz' } })
```

const term = rdf.namedNode('urn:call:string#startsWith')
You would declare the argument list as follows:

const argumentsObject = loadArguments(
rdf.clownface({ term, dataset }),
{
loaderRegistry: registry
})
```turtle
@prefix code: <https://code.described.at/> .
@prefix arg: <https://code.described.at/argument#> .
<urn:call:myFunction>
code:arguments
(
"foo"
42
[
arg:bar
[
arg:baz "baz"
]
]
) .
```
20 changes: 20 additions & 0 deletions arguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,31 @@ async function parseArguments(args: MultiPointer, options: ParseArgument): Promi
return [argObject]
}

const argumentPropPattern = new RegExp(`^${ns.code('argument#').value}(.+)$`)

async function parseArgument(arg: AnyPointer, { context, variables, basePath, loaderRegistry }: ParseArgument): Promise<unknown> {
if (!isGraphPointer(arg)) {
throw new Error('Cannot load argument. Expected a single node or RDF List.')
}

const keyValuePairs = await [...arg.dataset.match(arg.term)]
.reduce(async (previous: Promise<[string, unknown][]>, quad) => {
const isArgumentProp = quad.predicate.value.match(argumentPropPattern)
if (isArgumentProp) {
const entries = await previous
const key = isArgumentProp[1]
const value = await parseArgument(clownface({ dataset: arg.dataset, term: quad.object }), { context, variables, basePath, loaderRegistry })
entries.push([key, value])
return entries
}

return previous
}, Promise.resolve([]))

if (keyValuePairs.length > 0) {
return Object.fromEntries(keyValuePairs)
}

const code = await loaderRegistry.load(arg, { context, variables, basePath })

if (typeof code !== 'undefined') {
Expand Down
20 changes: 20 additions & 0 deletions test/arguments-shorthand.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@prefix arg: <https://code.described.at/argument#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix code: <https://code.described.at/> .

<http://example.com/single> code:arguments
(
[
arg:foo "foo" ;
arg:bar true ;
arg:baz 10 ;
]
) .


<http://example.com/nested> code:arguments
(
[
arg:foo [ arg:bar [ arg:baz "buzz" ] ] ;
]
) .
30 changes: 30 additions & 0 deletions test/arguments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,34 @@ describe('arguments loader', () => {
}
})
})

describe('shorthand syntax', () => {
it('load key-value pairs from a single blank node', async () => {
const term = rdf.namedNode('http://example.com/single')
const dataset = await loadDataset('./arguments-shorthand.ttl')

const result = await loader({ term, dataset }, { loaderRegistry: dummyLoaderRegistry })

deepStrictEqual(result, [{
foo: 'foo',
bar: true,
baz: 10,
}])
})

it('load deep key-value pairs', async () => {
const term = rdf.namedNode('http://example.com/nested')
const dataset = await loadDataset('./arguments-shorthand.ttl')

const result = await loader({ term, dataset }, { loaderRegistry: dummyLoaderRegistry })

deepStrictEqual(result, [{
foo: {
bar: {
baz: 'buzz',
},
},
}])
})
})
})

0 comments on commit 829dc79

Please sign in to comment.