TypeScript types and utility functions for handling Web Annotations.
Browse Source

Initial commit

tags/v1.0.0-src
Gerben 2 years ago
commit
6e3bf2d214
11 changed files with 1454 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +8
    -0
      .reuse/dep5
  3. +10
    -0
      LICENSES/Unlicense.txt
  4. +190
    -0
      Readme.md
  5. +854
    -0
      package-lock.json
  6. +34
    -0
      package.json
  7. +185
    -0
      src/WebAnnotation.ts
  8. +3
    -0
      src/index.ts
  9. +23
    -0
      src/multiplicity-utils.ts
  10. +133
    -0
      src/wa-attribute-utils.ts
  11. +12
    -0
      tsconfig.json

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
/node_modules
/lib

+ 8
- 0
.reuse/dep5 View File

@@ -0,0 +1,8 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Gerben
Upstream-Contact: <>
Source: https://code.treora.com/gerben/web-annotation-utils

Files: *
Copyright: 2022 Gerben
License: Unlicense

+ 10
- 0
LICENSES/Unlicense.txt View File

@@ -0,0 +1,10 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>

+ 190
- 0
Readme.md View File

@@ -0,0 +1,190 @@
# web-annotation-utils

TypeScript types and utility functions for handling Web Annotations.

A Web Annotation, as defined by the [Web Annotation Data Model][] is basically a JSON object with a target (what the note is ‘about’) and a body (the note ‘content’); along with optional metadata (creator, date, motivation, etc.). This module provides a TypeScript type declaration for Web Annotations.

Besides the type definition, it provides convenience functions for dealing with Web Annotations, such as getting the URL(s) of pages an annotation targets, or the plain text content the annotation body. It aims to provide some basic tools to get started writing interoperable annotation tools without having to deal with the intricacies of the data model.

[Web Annotation Data Model]: https://www.w3.org/TR/annotation-model/

## Usage

Install, using npm or equivalent:

```
npm install git+https://code.treora.com/gerben/web-annotation-utils#latest
```

Usage example:

```
import type { WebAnnotation } from 'web-annotation-utils';
import { completeAnnotationStub, getTargetUrls } from 'web-annotation-utils';

const webAnnotation: WebAnnotation = completeAnnotationStub({
"bodyValue": "interesting.",
"target": [
"http://example.org/page1",
{
"source": "http://example.org/page2",
"selector": {
"type": "TextQuoteSelector",
"exact": "bla bla bla",
}
}
]
});

const targetUrls = getTargetUrls(webAnnotation.target);
// [ 'http://example.org/page1', 'http://example.org/page2' ]
```


## Types

See [WebAnnotation.ts](./WebAnnotation.ts).

<!-- TSDOC_START -->

## :toolbox: Functions

- [asArray](#gear-asarray)
- [asSingleValue](#gear-assinglevalue)
- [findTargetsInDocument](#gear-findtargetsindocument)
- [findTargetInDocument](#gear-findtargetindocument)
- [completeAnnotationStub](#gear-completeannotationstub)
- [getSingleCreatorName](#gear-getsinglecreatorname)
- [targetsUrl](#gear-targetsurl)
- [getTargetUrls](#gear-gettargeturls)
- [getTargetUrl](#gear-gettargeturl)
- [getTargetQuotes](#gear-gettargetquotes)
- [getTargetQuote](#gear-gettargetquote)

### :gear: asArray

| Function | Type |
| ---------- | ---------- |
| `asArray` | `<T>(value: ZeroOrMore<T>) => T[]` |

### :gear: asSingleValue

| Function | Type |
| ---------- | ---------- |
| `asSingleValue` | `<T>(value: ZeroOrMore<T>) => T` |

### :gear: findTargetsInDocument

Find the Elements and/or Ranges in the document the annotation targets, if
any.

This supports the following selector types:
- CssSelector
- TextQuoteSelector
- TextPositionSelector
- RangeSelector

| Function | Type |
| ---------- | ---------- |
| `findTargetsInDocument` | `(target: OneOrMore<Target>, document?: Document) => Promise<DomMatch[]>` |

### :gear: findTargetInDocument

Find the Elements and/or Ranges in the document the annotation targets, if
any, given a single target.

This supports the following selector types:
- CssSelector
- TextQuoteSelector
- TextPositionSelector
- RangeSelector

| Function | Type |
| ---------- | ---------- |
| `findTargetInDocument` | `(target: Target, document?: Document) => Promise<DomMatch[]>` |

### :gear: completeAnnotationStub

Turn a partial annotation into a ‘well-formed’ WebAnnotation.

It sets the following properties, if absent in the given stub:
- `@context` as required
- `type` as required, to `'Annotation'`
- `created` as recommended (to the current time)
- `target` to `'about:invalid'`

| Function | Type |
| ---------- | ---------- |
| `completeAnnotationStub` | `(annotationStub: Partial<WebAnnotation>) => WebAnnotation` |

### :gear: getSingleCreatorName

Get the name of the creator. If there are multiple, returns the first.
Assumes the creator is a nested Agent object: if the creator a string
(presumably the URL of an Agent node), `undefined` is returned.

| Function | Type |
| ---------- | ---------- |
| `getSingleCreatorName` | `(annotationOrBody: WebAnnotation or BodyObject) => string` |

### :gear: targetsUrl

Check whether the annotation likely targets the given URL.

The word “likely” is used because, in its comparison, this ignores the URL
scheme, fragment and query parameters.

Note that, strictly speaking, a URL should be treated as an opaque string.
In practice, it may however be useful to consider URLs as ‘likely equivalent’
in order to apply annotations targeting one URL to the document with the
very similar URL. Apply with caution: Especially a different query may,
depending on the website at hand, result in very different documents.

| Function | Type |
| ---------- | ---------- |
| `targetsUrl` | `(target: OneOrMore<Target>, url: string) => boolean` |

### :gear: getTargetUrls

Get the URLs of the resources that the annotation targets, for all its
targets.

| Function | Type |
| ---------- | ---------- |
| `getTargetUrls` | `(target: OneOrMore<Target>) => string[]` |

### :gear: getTargetUrl

Get the URL of the resource that the annotation targets, for a single
target.

| Function | Type |
| ---------- | ---------- |
| `getTargetUrl` | `(target: Target) => string` |

### :gear: getTargetQuotes

Get the exact quotes that the annotation targets using a TextQuoteSelector,
if any.

| Function | Type |
| ---------- | ---------- |
| `getTargetQuotes` | `(target: OneOrMore<Target>) => string[]` |

### :gear: getTargetQuote

Get the exact quote that a single target of an annotation targets using a
TextQuoteSelector, if any.

| Function | Type |
| ---------- | ---------- |
| `getTargetQuote` | `(target: Target) => string` |



<!-- TSDOC_END -->


## Licence

This is free and unencumbered software released into the public domain.

+ 854
- 0
package-lock.json View File

@@ -0,0 +1,854 @@
{
"name": "web-annotation-utils",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "web-annotation-utils",
"version": "1.0.0",
"license": "Unlicense",
"dependencies": {
"@apache-annotator/selector": "^0.3.0-dev.23",
"typescript": "^4.8.4"
},
"devDependencies": {
"publish-to-git": "^1.1.7",
"tsdoc-markdown": "^0.0.1"
}
},
"node_modules/@apache-annotator/selector": {
"version": "0.3.0-dev.23",
"resolved": "https://registry.npmjs.org/@apache-annotator/selector/-/selector-0.3.0-dev.23.tgz",
"integrity": "sha512-+GHbZb5zRMhKyoXLZEurKjzmk/yXFRV66f2wIKDeQcYdI3qAhcrnaqWfx6RMCSa8WFmNMWIbl6xjIvJxsbRYGQ==",
"dependencies": {
"@babel/runtime-corejs3": "^7.13.10"
},
"engines": {
"node": "^14.15 || ^15.4 || >=16"
}
},
"node_modules/@babel/runtime-corejs3": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz",
"integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==",
"dependencies": {
"core-js-pure": "^3.25.1",
"regenerator-runtime": "^0.13.4"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true
},
"node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/core-js-pure": {
"version": "3.25.3",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.3.tgz",
"integrity": "sha512-T/7qvgv70MEvRkZ8p6BasLZmOVYKzOaWNBEHAU8FmveCJkl4nko2quqPQOmy6AJIp5MBanhz9no3A94NoRb0XA==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"dev": true,
"dependencies": {
"minipass": "^2.6.0"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/minimist": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"node_modules/minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dev": true,
"dependencies": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"node_modules/minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"dev": true,
"dependencies": {
"minipass": "^2.9.0"
}
},
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dev": true,
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/publish-to-git": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/publish-to-git/-/publish-to-git-1.1.9.tgz",
"integrity": "sha512-Lk1YDPyx/yvDUP8SaT6B1EAbr/tJLuYd3aAbop3H5C0XrK5cmjhnZ42n507HLraLqiymKZof2+UNVMnw6gOCiw==",
"dev": true,
"dependencies": {
"bluebird": "^3.5.1",
"tar": "^4.4.4",
"tmp": "0.0.33",
"yargs": "^15.3.1"
},
"bin": {
"publish-to-git": "main.js"
}
},
"node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/tar": {
"version": "4.4.19",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
"integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
"dev": true,
"dependencies": {
"chownr": "^1.1.4",
"fs-minipass": "^1.2.7",
"minipass": "^2.9.0",
"minizlib": "^1.3.3",
"mkdirp": "^0.5.5",
"safe-buffer": "^5.2.1",
"yallist": "^3.1.1"
},
"engines": {
"node": ">=4.5"
}
},
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"dependencies": {
"os-tmpdir": "~1.0.2"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/tsdoc-markdown": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/tsdoc-markdown/-/tsdoc-markdown-0.0.1.tgz",
"integrity": "sha512-tQ5+KjT/9DJNXqzTYQg1NVmSPBgpC2cUxFALxRdUa/08jjhjH2LsaGio9MSlLNjjFx4D24q6JIp4uuKsvfs8AQ==",
"dev": true,
"bin": {
"tsdoc": "bin/index.js"
},
"peerDependencies": {
"typescript": "4.X"
}
},
"node_modules/typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"dev": true
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
},
"node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dev": true,
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dev": true,
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
}
},
"dependencies": {
"@apache-annotator/selector": {
"version": "0.3.0-dev.23",
"resolved": "https://registry.npmjs.org/@apache-annotator/selector/-/selector-0.3.0-dev.23.tgz",
"integrity": "sha512-+GHbZb5zRMhKyoXLZEurKjzmk/yXFRV66f2wIKDeQcYdI3qAhcrnaqWfx6RMCSa8WFmNMWIbl6xjIvJxsbRYGQ==",
"requires": {
"@babel/runtime-corejs3": "^7.13.10"
}
},
"@babel/runtime-corejs3": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz",
"integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==",
"requires": {
"core-js-pure": "^3.25.1",
"regenerator-runtime": "^0.13.4"
}
},
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"requires": {
"color-convert": "^2.0.1"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"core-js-pure": {
"version": "3.25.3",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.3.tgz",
"integrity": "sha512-T/7qvgv70MEvRkZ8p6BasLZmOVYKzOaWNBEHAU8FmveCJkl4nko2quqPQOmy6AJIp5MBanhz9no3A94NoRb0XA=="
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"dev": true
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"dev": true,
"requires": {
"minipass": "^2.6.0"
}
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
},
"minimist": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"dev": true,
"requires": {
"minipass": "^2.9.0"
}
},
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dev": true,
"requires": {
"minimist": "^1.2.6"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
"dev": true
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"publish-to-git": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/publish-to-git/-/publish-to-git-1.1.9.tgz",
"integrity": "sha512-Lk1YDPyx/yvDUP8SaT6B1EAbr/tJLuYd3aAbop3H5C0XrK5cmjhnZ42n507HLraLqiymKZof2+UNVMnw6gOCiw==",
"dev": true,
"requires": {
"bluebird": "^3.5.1",
"tar": "^4.4.4",
"tmp": "0.0.33",
"yargs": "^15.3.1"
}
},
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
}
},
"strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
},
"tar": {
"version": "4.4.19",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
"integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
"dev": true,
"requires": {
"chownr": "^1.1.4",
"fs-minipass": "^1.2.7",
"minipass": "^2.9.0",
"minizlib": "^1.3.3",
"mkdirp": "^0.5.5",
"safe-buffer": "^5.2.1",
"yallist": "^3.1.1"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"tsdoc-markdown": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/tsdoc-markdown/-/tsdoc-markdown-0.0.1.tgz",
"integrity": "sha512-tQ5+KjT/9DJNXqzTYQg1NVmSPBgpC2cUxFALxRdUa/08jjhjH2LsaGio9MSlLNjjFx4D24q6JIp4uuKsvfs8AQ==",
"dev": true,
"requires": {}
},
"typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ=="
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==",
"dev": true
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"dev": true
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
},
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
}

+ 34
- 0
package.json View File

@@ -0,0 +1,34 @@
{
"name": "web-annotation-utils",
"version": "1.0.0",
"description": "TypeScript types and utility functions for handling Web Annotations",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"type": "module",
"exports": {
".": "./lib/index.js"
},
"files": ["lib"],
"scripts": {
"prepublish": "tsc",
"publish": "publish-to-git --force && publish-to-git --force --tag latest",
"doc": "tsdoc --src=* --dest=Readme.md"
},
"repository": {
"type": "git",
"url": "https://code.treora.com/gerben/web-annotation-utils"
},
"keywords": [
"web-annotation"
],
"author": "Gerben",
"license": "Unlicense",
"dependencies": {
"@apache-annotator/selector": "^0.3.0-dev.23",
"typescript": "^4.8.4"
},
"devDependencies": {
"publish-to-git": "^1.1.7",
"tsdoc-markdown": "^0.0.1"
}
}

+ 185
- 0
src/WebAnnotation.ts View File

@@ -0,0 +1,185 @@
import type {
OneOrMore,
OneOrMoreIncluding,
ZeroOrMore,
} from './multiplicity-utils.js';

/**
* A Web Annotation object.
*
* This is an interpretation of the Web Annotation Data Model:
* <https://www.w3.org/TR/2017/REC-annotation-model-20170223/>
*
* TODO Deal more systemically with ‘relations’, i.e. values that could be
* either a nested object or a URI referring to such an object.
*/
export interface WebAnnotation {
'@context': OneOrMoreIncluding<string, 'http://www.w3.org/ns/anno.jsonld'>;
type: OneOrMoreIncluding<string, 'Annotation'>;
id: string;
target: OneOrMore<Target>;
creator?: OneOrMore<Agent>;
created?: UtcDateTime;
generator?: OneOrMore<Agent>;
generated?: UtcDateTime;
modified?: UtcDateTime;
motivation?: OneOrMore<Motivation>;
audience?: ZeroOrMore<Audience>;
rights?: ZeroOrMore<string>;
canonical?: string;
via?: ZeroOrMore<string>;
body?: BodyChoice | OneOrMore<Body>;
bodyValue?: string;
}

/**
* A slightly stricter type for WebAnnotation, not allowing both a body and bodyValue.
*/
export type WebAnnotationStrict = WebAnnotation & (WithBody | WithBodyValue | WithoutBody);

interface WithBody {
body: BodyChoice | OneOrMore<Body>;
bodyValue?: undefined;
}

interface WithBodyValue {
body?: undefined;
bodyValue: string;
}

interface WithoutBody {
body?: undefined;
bodyValue?: undefined;
}

export type Body = string | BodyObject;

export type BodyObject = {
creator?: OneOrMore<Agent>;
created?: UtcDateTime;
modified?: UtcDateTime;
purpose?: OneOrMore<Motivation>;
} & (TextualBody | SpecificResource | ExternalResource);

export type Target = string | SpecificResource | ExternalResource;

export type Agent =
| string
| {
id?: string;
type?: OneOrMore<'Person' | 'Organization' | 'Software'>;
name?: OneOrMore<string>;
nickname?: OneOrMore<string>;
email?: OneOrMore<string>;
email_sha1?: OneOrMore<string>;
homepage?: OneOrMore<string>;
};

export type Audience =
| string
| {
id?: string;
type?: string;
};

export interface BodyChoice {
type: 'Choice';
items: Body[];
}

export interface TextualBody extends Omit<ExternalResource, 'id' | 'type'> {
id?: string;
type: 'TextualBody';
value: string;
}

export interface SpecificResource {
id?: string;
type?: 'SpecificResource';
source: string;
selector?: string | OneOrMore<Selector>;
accessibility?: AccessibilityFeatures;
rights?: ZeroOrMore<string>;
canonical?: string;
via?: ZeroOrMore<string>;
}

export interface Selector {
type?: string;
refinedBy?: Selector;
}

export interface ExternalResource {
id: string;
// XXX type’s value SHOULD be one of these, “but MAY come from other vocabularies”.
type?: OneOrMore<'Dataset' | 'Image' | 'Video' | 'Sound' | 'Text'>;
format?: OneOrMore<string>;
language?: OneOrMore<string>;
processingLanguage?: string;
textDirection?: 'ltr' | 'rtl' | 'auto';
accessibility?: AccessibilityFeatures;
rights?: ZeroOrMore<string>;
canonical?: string;
via?: ZeroOrMore<string>;
}

export type Motivation =
| 'assessing'
| 'bookmarking'
| 'classifying'
| 'commenting'
| 'describing'
| 'editing'
| 'highlighting'
| 'identifying'
| 'linking'
| 'moderating'
| 'questioning'
| 'replying'
| 'tagging';

// “The datetime MUST be a xsd:dateTime with the UTC timezone expressed as "Z".”
type UtcDateTime = `${string}Z`;
declare global {
interface Date {
toISOString(): UtcDateTime;
}
}

// From <https://www.w3.org/2021/a11y-discov-vocab/latest/CG-FINAL-a11y-discov-vocab-20220610.html>
export type AccessibilityFeatures =
| ZeroOrMore<AccessibilityFeature>
| 'none'
| ['none'];
export type AccessibilityFeature =
| 'annotations'
| 'ARIA'
| 'bookmarks'
| 'index'
| 'printPageNumbers'
| 'readingOrder'
| 'structuralNavigation'
| 'tableOfContents'
| 'taggedPDF'
| 'alternativeText'
| 'audioDescription'
| 'captions'
| 'describedMath'
| 'longDescription'
| 'rubyAnnotations'
| 'signLanguage'
| 'transcript'
| 'displayTransformability'
| 'synchronizedAudioText'
| 'timingControl'
| 'unlocked'
| 'ChemML'
| 'latex'
| 'MathML'
| 'ttsMarkup'
| 'highContrastAudio'
| 'highContrastDisplay'
| 'largePrint'
| 'braille'
| 'tactileGraphic'
| 'tactileObject';

+ 3
- 0
src/index.ts View File

@@ -0,0 +1,3 @@
export * from './WebAnnotation.js'
export * from './multiplicity-utils.js'
export * from './wa-attribute-utils.js'

+ 23
- 0
src/multiplicity-utils.ts View File

@@ -0,0 +1,23 @@
export type OneOrMore<T> = T | T[];
export type ZeroOrMore<T> = undefined | null | T | T[];

export type OneOrMoreIncluding<Other extends any, RequiredValue extends any> =
| RequiredValue
| [RequiredValue, ...Other[]]
| [...Other[], RequiredValue];
// | [Other, ...OneOrMoreIncluding<Other, RequiredValue>]; // FIXME TypeScript complains about the circular reference..

// OnlyOne<T> extracts the T from a One/ZeroOrMore<T> type
export type OnlyOne<T> = T extends (infer X)[] ? X : T;

export function asArray<T>(value: ZeroOrMore<T>): T[] {
if (Array.isArray(value)) return value;
if (value === undefined || value === null) return [];
return [value];
}

export function asSingleValue<T>(value: ZeroOrMore<T>): T | undefined {
if (value instanceof Array) return value[0];
if (value === undefined || value === null) return undefined;
return value;
}

+ 133
- 0
src/wa-attribute-utils.ts View File

@@ -0,0 +1,133 @@
import type { TextQuoteSelector } from '@apache-annotator/selector';
import type { BodyObject, WebAnnotation } from './WebAnnotation.js';
import { asArray, asSingleValue, OnlyOne } from './multiplicity-utils.js';

/**
* Turn a partial annotation into a ‘well-formed’ WebAnnotation.
*
* It sets the following properties, if absent in the given stub:
* - `@context` as required
* - `type` as required, to `'Annotation'`
* - `created` as recommended (to the current time)
* - `target` to `'about:invalid'`
*
* @returns A shallow clone of the given annotation stub, with the missing
* properties added.
*/
export function completeAnnotationStub(annotationStub: Partial<WebAnnotation>) {
const webAnnotation: WebAnnotation = {
'@context': 'http://www.w3.org/ns/anno.jsonld',
type: 'Annotation',
created: new Date().toISOString(),
id: '',
target: 'about:invalid',
...annotationStub,
};

return webAnnotation;
}

/**
* Get the name of the creator. If there are multiple, returns the first.
* Assumes the creator is a nested Agent object: if the creator a string
* (presumably the URL of an Agent node), `undefined` is returned.
*/
export function getSingleCreatorName(
annotationOrBody: WebAnnotation | BodyObject,
): string | undefined {
const creator = asSingleValue(annotationOrBody.creator);
if (typeof creator === 'string') return undefined;
return asSingleValue(creator?.name ?? creator?.nickname);
}

/**
* Check whether the annotation likely targets the given URL.
*
* The word “likely” is used because, in its comparison, this ignores the URL
* scheme, fragment and query parameters.
*
* Note that, strictly speaking, a URL should be treated as an opaque string.
* In practice, it may however be useful to consider URLs as ‘likely equivalent’
* in order to apply annotations targeting one URL to the document with the
* very similar URL. Apply with caution: Especially a different query may,
* depending on the website at hand, result in very different documents.
*/
export function targetsUrl(target: WebAnnotation['target'], url: string) {
return getTargetUrls(target).some((targetUrl) => sameishUrl(targetUrl, url));
}

// Compare URLs while ignoring the scheme, fragment identifier, query parameter and trailing slash.
function sameishUrl(url1: string, url2: string) {
return normaliseUrl(url1) === normaliseUrl(url2);
}

function normaliseUrl(url: string) {
url = url
.split('#')[0]
.split('?')[0]
.replace(/^[a-zA-Z0-9.+-]+:\/\//, '');
if (url.endsWith('/')) url = url.slice(0, -1);
return url;
}

/**
* Get the URLs of the resources that the annotation targets, for all its
* targets.
*/
export function getTargetUrls(target: WebAnnotation['target']): string[] {
return unique(asArray(target).map(getTargetUrl));
}

/**
* Get the URL of the resource that the annotation targets, for a single
* target.
*/
export function getTargetUrl(target: OnlyOne<WebAnnotation['target']>): string {
if (typeof target === 'string') {
// This string *could* be referring to a non-nested SpecificResource that
// then contains the actual target URL. But we are not able to fetch that
// now, and simply assume the string refers to the target document.
return target;
}
// Specific Resource
if ('source' in target) return target.source;
// External Resource
return target.id;
}

/**
* Get the exact quotes that the annotation targets using a TextQuoteSelector,
* if any.
*/
export function getTargetQuotes(target: WebAnnotation['target']): string[] {
const quotes = unique(asArray(target).map(getTargetQuote)).filter(
(s) => s !== undefined,
) as string[];
return quotes;
}

/**
* Get the exact quote that a single target of an annotation targets using a
* TextQuoteSelector, if any.
*/
export function getTargetQuote(target: OnlyOne<WebAnnotation['target']>): string | undefined {
if (typeof target === 'string') return undefined;
if ('selector' in target) {
// Find if target.selector is/has a TextQuoteSelector.
const selectors = asArray(target.selector);
const textQuoteSelector = selectors.find(selector => {
if (typeof selector === 'string') {
// The selector is not nested in the annotation. But we are not able to
// fetch it now, and will thus have to ignore this selector.
return false;
}
return selector.type === 'TextQuoteSelector';
}) as TextQuoteSelector | undefined;
if (textQuoteSelector)
return textQuoteSelector.exact;
}
}

function unique<T>(a: T[]): T[] {
return [...new Set(a)];
}

+ 12
- 0
tsconfig.json View File

@@ -0,0 +1,12 @@
{
"compilerOptions": {
"strict": true,
"isolatedModules": true,
"lib": ["ES2018"],
"moduleResolution": "Node16",
"target": "ES6",
"declaration": true,
"outDir": "lib"
},
"files": ["src/index.ts"]
}

Loading…
Cancel
Save