-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(parse-data-protocol): add utility that implements NAS-115 groupi…
…ng convention #1059
- Loading branch information
1 parent
a83cc87
commit a95e2c7
Showing
7 changed files
with
1,355 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
# parse-data-protocol | ||
|
||
A set of utilities for extracting and parsing tags associated with ANS-115 | ||
`Data-Protocol`s | ||
|
||
<!-- toc --> | ||
|
||
- [Why](#why) | ||
- [Usage](#usage) | ||
- [`findAll`](#findall) | ||
- [`findAllByName`](#findallbyname) | ||
- [`findByName`](#findbyname) | ||
- [`parseAll`](#parseall) | ||
- [`parse`](#parse) | ||
- [`create`](#create) | ||
- [`assoc`](#assoc) | ||
- [`proto`](#proto) | ||
|
||
<!-- tocstop --> | ||
|
||
## Why | ||
|
||
**It is fundamental to note that, in ANS-104, tags are ordered.** | ||
|
||
ANS-115 specifies how to utilize `Data-Protocol`s to compose application level | ||
specification using ANS-104 tags. | ||
|
||
However, ambiguity arises when a piece of data implements many `Data-Protocol` | ||
which specify the same tag name: | ||
|
||
```js | ||
const tags = [ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// ... | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// Which tags goes with which Data-Protocol? | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
{ name: "Variant", value: "0.0.2" }, | ||
]; | ||
``` | ||
|
||
This ambuguity can lead to unexpected behavior in workarounds in subsequent | ||
implementations. | ||
|
||
By enforcing one additional simple convention, this ambiguity is massively | ||
curtailed: | ||
|
||
> tags are associated with the most recent `Data-Protocol` tag. **A corollary is** | ||
> **that tags not belonging to a `Data-Protocol` would appear first, before any** | ||
> **`Data-Protocol` tags.** | ||
```js | ||
const tags = [ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// these are associated with ao Data-Protocol | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
// end ao tags | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// these are asscociated with zone Data-Protocol | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "0.0.2" }, | ||
]; | ||
``` | ||
|
||
This module provides utilties for interacting with Data-Protocol tags, using | ||
that convention. In this module, this convention is referred to as | ||
"`association`" ie. tags are associated with the most recent `Data-Protocol` | ||
|
||
## Usage | ||
|
||
```js | ||
import { | ||
concat, | ||
create, | ||
findAll, | ||
findAllByName, | ||
findByName, | ||
parse, | ||
parseAll, | ||
proto, | ||
} from "@permaweb/parse-data-protocol"; | ||
|
||
const tags = [ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// these are associated with ao Data-Protocol | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
// end ao tags | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// these are asscociated with zone Data-Protocol | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "0.0.2" }, | ||
// end zone tags | ||
]; | ||
|
||
// use a top-level export, passing protocol first | ||
const aoType = findByName("ao", "Type", tags); | ||
|
||
// OR use the proto helper to get an API per Data-Protocol | ||
const ao = proto("ao"); | ||
const zone = proto("zone"); | ||
|
||
// No longer need to pass protocol first | ||
const aoType = ao.value("Type", tags); | ||
const zoneTypes = zone.values("Type", tags); | ||
``` | ||
|
||
> Passing `protocol` first, over and over, might get verbose. Alternatively, you | ||
> can use the [`proto`](#proto) helper. | ||
### `findAll` | ||
|
||
Extract the tags associated with the provided `Data-Protocol`. | ||
|
||
If the `Data-Protocol` tag is NOT found, then ALL tags are considered associated | ||
with the `Data-Protocol`. | ||
|
||
```js | ||
import { findAll } from "@permaweb/parse-data-protocol"; | ||
|
||
const tags = [/*...*/]; | ||
|
||
// [{ name, value }, ...] | ||
const aoTags = findAll("ao", tags); | ||
``` | ||
|
||
### `findAllByName` | ||
|
||
Extract the tags, with the name, associated with the provided `Data-Protocol`. | ||
|
||
```js | ||
import { findAllByName } from '@permaweb/parse-data-protocol' | ||
|
||
const tags = [/*...*/] | ||
|
||
// [{ name, value }, ...] | ||
const zoneTypes = findAllByName('zone', 'Type' tags) | ||
``` | ||
|
||
### `findByName` | ||
|
||
Extract the FIRST tag, with the name, associated with the provided | ||
`Data-Protocol`. | ||
|
||
```js | ||
import { findByName } from '@permaweb/parse-data-protocol' | ||
|
||
const tags = [/*...*/] | ||
|
||
// { name, value } | ||
const aoType = findAllByName('ao', 'Type' tags) | ||
``` | ||
|
||
### `parseAll` | ||
|
||
Parse tags associated with the `Data-Protocol` into an object with key-value | ||
pairs of name -> an array of values. | ||
|
||
At each key, the values in each array will be in order of appearance | ||
|
||
```js | ||
import { parseAll } from "@permaweb/parse-data-protocol"; | ||
|
||
const tags = [/*...*/]; | ||
|
||
// { Type: ['Process', ...], Module: ['...'] } | ||
const aoParsed = parseAll("ao", tags); | ||
``` | ||
|
||
### `parse` | ||
|
||
Parse tags associated with the `Data-Protocol` into an object with key-value | ||
pairs of name -> value. | ||
|
||
If multiple tags are found, then the FIRST tag value is used, and subsequent | ||
values are discarded. If you'd like to preserve all values, then use | ||
[`parseAll`](#parseall) | ||
|
||
```js | ||
import { parse } from "@permaweb/parse-data-protocol"; | ||
|
||
const tags = [/*...*/]; | ||
|
||
// { Type: 'Process', Module: '...' } | ||
const aoParsed = parse("ao", tags); | ||
``` | ||
|
||
### `create` | ||
|
||
Associate an array of tags associated with the Data-Protocol. The | ||
`Data-Protocol` tag will be prepended to the front of the array. | ||
|
||
```js | ||
import { create } from "@permaweb/parse-data-protocol"; | ||
|
||
const pTags = [{ name: "Foo", value: "Bar" }]; | ||
|
||
/** | ||
[ | ||
{ name: 'Data-Protocol', value: 'ao' }, | ||
{ name: 'Foo', value: 'Bar' } | ||
] | ||
*/ | ||
const aoTags = create("ao", pTags); | ||
``` | ||
|
||
### `assoc` | ||
|
||
Produce a new array of tags by associating the provided tags with the | ||
`Data-Protocol`. The new associations are appended to end of an existing | ||
_subsection_. | ||
|
||
If there is no existing _subsection_ of tags for the `Data-Protocol`, then the | ||
new section is appended to the end | ||
|
||
NO deduplication is performed on the associated tags. | ||
|
||
```js | ||
import { assoc } from "@permaweb/parse-data-protocol"; | ||
|
||
const tags = [ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// these are associated with ao Data-Protocol | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
// end ao tags | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// these are asscociated with zone Data-Protocol | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "0.0.2" }, | ||
// end zone tags | ||
]; | ||
|
||
const pTags = [{ name: "Foo", value: "Bar" }, { name: "Cool", value: "Beans" }]; | ||
|
||
// ao subsection is appended to | ||
const newTags = assoc("ao", pTags, tags)[ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// these are associated with ao Data-Protocol | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
{ name: "Foo", value: "Bar" }, | ||
{ name: "Cool", value: "Beans" }, | ||
// end ao tags | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// these are asscociated with zone Data-Protocol | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "0.0.2" } | ||
// end zone tags | ||
]; | ||
``` | ||
|
||
### `proto` | ||
|
||
Instead of constantly passing `protocol` as the first argument every time, you | ||
can use this api. | ||
|
||
Build a `@permaweb/parse-data-protocol` API for a single `Data-Protocol` | ||
|
||
```js | ||
import { proto } from "@permaweb/parse-data-protocol"; | ||
|
||
const ao = proto("ao"); | ||
const zone = proto("zone"); | ||
|
||
const tags = [ | ||
{ name: "Data-Protocol", value: "ao" }, | ||
// these are associated with ao Data-Protocol | ||
{ name: "Type", value: "Process" }, | ||
{ name: "Variant", value: "ao.TN.1" }, | ||
// end ao tags | ||
{ name: "Data-Protocol", value: "zone" }, | ||
// these are asscociated with zone Data-Protocol | ||
{ name: "Type", value: "Profile" }, | ||
{ name: "Variant", value: "0.0.2" }, | ||
]; | ||
|
||
// 'Process' | ||
const aoType = ao.value("Type", tags); | ||
// ['Profile'] | ||
const zoneTypes = zone.values("Type", tags); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { readFileSync } from 'node:fs' | ||
import * as esbuild from 'esbuild' | ||
|
||
/** | ||
* By importing from manifest, build will always be in sync with the manifest | ||
*/ | ||
const manifest = JSON.parse(readFileSync('./package.json')) | ||
|
||
// CJS | ||
await esbuild.build({ | ||
entryPoints: ['index.js'], | ||
platform: 'node', | ||
format: 'cjs', | ||
bundle: true, | ||
outfile: manifest.main | ||
}) | ||
|
||
// ESM | ||
await esbuild.build({ | ||
entryPoints: ['index.js'], | ||
platform: 'node', | ||
format: 'esm', | ||
bundle: true, | ||
outfile: manifest.module | ||
}) |
Oops, something went wrong.