From 193a9c16404cbf8b9fc0a7d35e74a16ea0ab3113 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Mon, 6 Aug 2018 11:01:16 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Add=20HTML=20annotations=20(#66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This defines a subset of the HTML spec as annotations. In the future, we'd like these to be automatically generated from the HTML spec. --- package-lock.json | 137 ++++++++++-------- packages/@atjson/document/src/index.ts | 3 +- .../source-html/src/annotations/anchor.ts | 11 ++ .../source-html/src/annotations/blockquote.ts | 6 + .../source-html/src/annotations/bold.ts | 6 + .../source-html/src/annotations/break.ts | 6 + .../source-html/src/annotations/code.ts | 6 + .../src/annotations/deleted-text.ts | 6 + .../source-html/src/annotations/emphasis.ts | 6 + .../source-html/src/annotations/heading-1.ts | 6 + .../source-html/src/annotations/heading-2.ts | 6 + .../source-html/src/annotations/heading-3.ts | 6 + .../source-html/src/annotations/heading-4.ts | 6 + .../source-html/src/annotations/heading-5.ts | 6 + .../source-html/src/annotations/heading-6.ts | 6 + .../src/annotations/horizontal-rule.ts | 6 + .../source-html/src/annotations/image.ts | 11 ++ .../source-html/src/annotations/index.ts | 26 ++++ .../source-html/src/annotations/italic.ts | 6 + .../source-html/src/annotations/list-item.ts | 6 + .../src/annotations/ordered-list.ts | 9 ++ .../source-html/src/annotations/paragraph.ts | 10 ++ .../src/annotations/preformatted-text.ts | 6 + .../src/annotations/strikethrough.ts | 6 + .../source-html/src/annotations/strong.ts | 6 + .../source-html/src/annotations/subscript.ts | 6 + .../src/annotations/superscript.ts | 6 + .../source-html/src/annotations/underline.ts | 6 + .../src/annotations/unordered-list.ts | 6 + packages/@atjson/source-html/src/index.ts | 96 +++++++++--- packages/@atjson/source-html/src/schema.ts | 61 -------- .../@atjson/source-html/src/translator.ts | 68 ++++----- .../source-html/test/source-html-test.ts | 69 +++++---- 33 files changed, 411 insertions(+), 222 deletions(-) create mode 100644 packages/@atjson/source-html/src/annotations/anchor.ts create mode 100644 packages/@atjson/source-html/src/annotations/blockquote.ts create mode 100644 packages/@atjson/source-html/src/annotations/bold.ts create mode 100644 packages/@atjson/source-html/src/annotations/break.ts create mode 100644 packages/@atjson/source-html/src/annotations/code.ts create mode 100644 packages/@atjson/source-html/src/annotations/deleted-text.ts create mode 100644 packages/@atjson/source-html/src/annotations/emphasis.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-1.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-2.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-3.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-4.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-5.ts create mode 100644 packages/@atjson/source-html/src/annotations/heading-6.ts create mode 100644 packages/@atjson/source-html/src/annotations/horizontal-rule.ts create mode 100644 packages/@atjson/source-html/src/annotations/image.ts create mode 100644 packages/@atjson/source-html/src/annotations/index.ts create mode 100644 packages/@atjson/source-html/src/annotations/italic.ts create mode 100644 packages/@atjson/source-html/src/annotations/list-item.ts create mode 100644 packages/@atjson/source-html/src/annotations/ordered-list.ts create mode 100644 packages/@atjson/source-html/src/annotations/paragraph.ts create mode 100644 packages/@atjson/source-html/src/annotations/preformatted-text.ts create mode 100644 packages/@atjson/source-html/src/annotations/strikethrough.ts create mode 100644 packages/@atjson/source-html/src/annotations/strong.ts create mode 100644 packages/@atjson/source-html/src/annotations/subscript.ts create mode 100644 packages/@atjson/source-html/src/annotations/superscript.ts create mode 100644 packages/@atjson/source-html/src/annotations/underline.ts create mode 100644 packages/@atjson/source-html/src/annotations/unordered-list.ts delete mode 100644 packages/@atjson/source-html/src/schema.ts diff --git a/package-lock.json b/package-lock.json index 2e65afabe4..6ef4cd21e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1598,6 +1598,14 @@ "dev": true, "requires": { "lodash": "^4.17.10" + }, + "dependencies": { + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + } } }, "async-each": { @@ -2498,53 +2506,45 @@ "q": "^1.5.1" }, "dependencies": { - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "dev": true - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "dev": true, - "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" - } - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { - "repeating": "^2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" } }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - }, "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", "dev": true, "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", "minimist": "^1.1.3", + "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + }, + "dependencies": { + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + } } }, "minimist": { @@ -2553,37 +2553,46 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "get-stdin": "^4.0.1" - }, - "dependencies": { - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", - "dev": true - } + "pify": "^3.0.0" } }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } } @@ -2830,6 +2839,14 @@ "dev": true, "requires": { "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, "defaults": { diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index 68c51e3bb4..5b396c4693 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -230,7 +230,8 @@ export default class Document { private createAnnotation(json: AnnotationJSON): Annotation { let DocumentClass = this.constructor as typeof Document; - let schema = DocumentClass.schema.slice().concat([Parse]); + let schema = [...DocumentClass.schema, Parse]; + let ConcreteAnnotation = schema.find(AnnotationClass => { let fullyQualifiedType = `-${AnnotationClass.vendorPrefix}-${AnnotationClass.type}`; return json.type === fullyQualifiedType; diff --git a/packages/@atjson/source-html/src/annotations/anchor.ts b/packages/@atjson/source-html/src/annotations/anchor.ts new file mode 100644 index 0000000000..f5c4a61aec --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/anchor.ts @@ -0,0 +1,11 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Anchor extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'a'; + attributes!: { + href: string; + target: string; + rel: string; + }; +} diff --git a/packages/@atjson/source-html/src/annotations/blockquote.ts b/packages/@atjson/source-html/src/annotations/blockquote.ts new file mode 100644 index 0000000000..c6458c02c3 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/blockquote.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Blockquote extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'blockquote'; +} diff --git a/packages/@atjson/source-html/src/annotations/bold.ts b/packages/@atjson/source-html/src/annotations/bold.ts new file mode 100644 index 0000000000..df003b5e6a --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/bold.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Bold extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'b'; +} diff --git a/packages/@atjson/source-html/src/annotations/break.ts b/packages/@atjson/source-html/src/annotations/break.ts new file mode 100644 index 0000000000..d97eedd677 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/break.ts @@ -0,0 +1,6 @@ +import { ObjectAnnotation } from '@atjson/document'; + +export default class Break extends ObjectAnnotation { + static vendorPrefix = 'html'; + static type = 'br'; +} diff --git a/packages/@atjson/source-html/src/annotations/code.ts b/packages/@atjson/source-html/src/annotations/code.ts new file mode 100644 index 0000000000..d9709615d2 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/code.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Code extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'code'; +} diff --git a/packages/@atjson/source-html/src/annotations/deleted-text.ts b/packages/@atjson/source-html/src/annotations/deleted-text.ts new file mode 100644 index 0000000000..cdbfc1191b --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/deleted-text.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class DeletedText extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'del'; +} diff --git a/packages/@atjson/source-html/src/annotations/emphasis.ts b/packages/@atjson/source-html/src/annotations/emphasis.ts new file mode 100644 index 0000000000..ca627e4187 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/emphasis.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Emphasis extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'em'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-1.ts b/packages/@atjson/source-html/src/annotations/heading-1.ts new file mode 100644 index 0000000000..e76e71a045 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-1.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading1 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h1'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-2.ts b/packages/@atjson/source-html/src/annotations/heading-2.ts new file mode 100644 index 0000000000..4b32a9a175 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-2.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading2 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h2'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-3.ts b/packages/@atjson/source-html/src/annotations/heading-3.ts new file mode 100644 index 0000000000..d7a9503ce4 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-3.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading3 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h3'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-4.ts b/packages/@atjson/source-html/src/annotations/heading-4.ts new file mode 100644 index 0000000000..61ff870951 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-4.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading4 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h4'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-5.ts b/packages/@atjson/source-html/src/annotations/heading-5.ts new file mode 100644 index 0000000000..20946645a7 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-5.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading5 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h5'; +} diff --git a/packages/@atjson/source-html/src/annotations/heading-6.ts b/packages/@atjson/source-html/src/annotations/heading-6.ts new file mode 100644 index 0000000000..e93e712c96 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/heading-6.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Heading6 extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'h6'; +} diff --git a/packages/@atjson/source-html/src/annotations/horizontal-rule.ts b/packages/@atjson/source-html/src/annotations/horizontal-rule.ts new file mode 100644 index 0000000000..3765c66e8e --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/horizontal-rule.ts @@ -0,0 +1,6 @@ +import { ObjectAnnotation } from '@atjson/document'; + +export default class HorizontalRule extends ObjectAnnotation { + static vendorPrefix = 'html'; + static type = 'hr'; +} diff --git a/packages/@atjson/source-html/src/annotations/image.ts b/packages/@atjson/source-html/src/annotations/image.ts new file mode 100644 index 0000000000..67a7a51e74 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/image.ts @@ -0,0 +1,11 @@ +import { ObjectAnnotation } from '@atjson/document'; + +export default class Image extends ObjectAnnotation { + static vendorPrefix = 'html'; + static type = 'img'; + attributes!: { + alt?: string; + src: string; + title?: string; + }; +} diff --git a/packages/@atjson/source-html/src/annotations/index.ts b/packages/@atjson/source-html/src/annotations/index.ts new file mode 100644 index 0000000000..adb503f37c --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/index.ts @@ -0,0 +1,26 @@ +export { default as Anchor } from './anchor'; +export { default as Bold } from './bold'; +export { default as Blockquote } from './blockquote'; +export { default as Break } from './break'; +export { default as Code } from './code'; +export { default as DeletedText } from './deleted-text'; +export { default as Emphasis } from './emphasis'; +export { default as Heading1 } from './heading-1'; +export { default as Heading2 } from './heading-2'; +export { default as Heading3 } from './heading-3'; +export { default as Heading4 } from './heading-4'; +export { default as Heading5 } from './heading-5'; +export { default as Heading6 } from './heading-6'; +export { default as HorizontalRule } from './horizontal-rule'; +export { default as Image } from './image'; +export { default as Italic } from './italic'; +export { default as ListItem } from './list-item'; +export { default as OrderedList } from './ordered-list'; +export { default as Paragraph } from './paragraph'; +export { default as PreformattedText } from './preformatted-text'; +export { default as Strikethrough } from './strikethrough'; +export { default as Strong } from './strong'; +export { default as Subscript } from './subscript'; +export { default as Superscript } from './superscript'; +export { default as UnorderedList } from './unordered-list'; +export { default as Underline } from './underline'; diff --git a/packages/@atjson/source-html/src/annotations/italic.ts b/packages/@atjson/source-html/src/annotations/italic.ts new file mode 100644 index 0000000000..fb4e96fe36 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/italic.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Italic extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'i'; +} diff --git a/packages/@atjson/source-html/src/annotations/list-item.ts b/packages/@atjson/source-html/src/annotations/list-item.ts new file mode 100644 index 0000000000..0f8c22f8bd --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/list-item.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class ListItem extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'li'; +} diff --git a/packages/@atjson/source-html/src/annotations/ordered-list.ts b/packages/@atjson/source-html/src/annotations/ordered-list.ts new file mode 100644 index 0000000000..e07b009cbf --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/ordered-list.ts @@ -0,0 +1,9 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class OrderedList extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'ol'; + attributes!: { + starts: string; + }; +} diff --git a/packages/@atjson/source-html/src/annotations/paragraph.ts b/packages/@atjson/source-html/src/annotations/paragraph.ts new file mode 100644 index 0000000000..afbbe32f67 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/paragraph.ts @@ -0,0 +1,10 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class Paragraph extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'p'; + + get rank() { + return super.rank * 3 / 2; + } +} diff --git a/packages/@atjson/source-html/src/annotations/preformatted-text.ts b/packages/@atjson/source-html/src/annotations/preformatted-text.ts new file mode 100644 index 0000000000..6119201385 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/preformatted-text.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class PreformattedText extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'pre'; +} diff --git a/packages/@atjson/source-html/src/annotations/strikethrough.ts b/packages/@atjson/source-html/src/annotations/strikethrough.ts new file mode 100644 index 0000000000..c767f4fe5f --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/strikethrough.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Strikethrough extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 's'; +} diff --git a/packages/@atjson/source-html/src/annotations/strong.ts b/packages/@atjson/source-html/src/annotations/strong.ts new file mode 100644 index 0000000000..dbe57f2b72 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/strong.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Strong extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'strong'; +} diff --git a/packages/@atjson/source-html/src/annotations/subscript.ts b/packages/@atjson/source-html/src/annotations/subscript.ts new file mode 100644 index 0000000000..8245521b9a --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/subscript.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Subscript extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'sub'; +} diff --git a/packages/@atjson/source-html/src/annotations/superscript.ts b/packages/@atjson/source-html/src/annotations/superscript.ts new file mode 100644 index 0000000000..6eb51a7d9e --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/superscript.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Superscript extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'sup'; +} diff --git a/packages/@atjson/source-html/src/annotations/underline.ts b/packages/@atjson/source-html/src/annotations/underline.ts new file mode 100644 index 0000000000..b5c0a76e68 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/underline.ts @@ -0,0 +1,6 @@ +import { InlineAnnotation } from '@atjson/document'; + +export default class Underline extends InlineAnnotation { + static vendorPrefix = 'html'; + static type = 'u'; +} diff --git a/packages/@atjson/source-html/src/annotations/unordered-list.ts b/packages/@atjson/source-html/src/annotations/unordered-list.ts new file mode 100644 index 0000000000..d64d261149 --- /dev/null +++ b/packages/@atjson/source-html/src/annotations/unordered-list.ts @@ -0,0 +1,6 @@ +import { BlockAnnotation } from '@atjson/document'; + +export default class UnorderedList extends BlockAnnotation { + static vendorPrefix = 'html'; + static type = 'ul'; +} diff --git a/packages/@atjson/source-html/src/index.ts b/packages/@atjson/source-html/src/index.ts index a18d57bfe9..9d16e9051f 100644 --- a/packages/@atjson/source-html/src/index.ts +++ b/packages/@atjson/source-html/src/index.ts @@ -1,10 +1,35 @@ -import Document, { Annotation, Schema } from '@atjson/document'; -import * as parse5 from 'parse5'; -import schema from './schema'; +import Document, { AnnotationJSON, Attributes } from '@atjson/document'; +import * as parse5 from 'parse5/lib'; +import { + Anchor, + Blockquote, + Bold, + Break, + Code, + DeletedText, + Emphasis, + Heading1, + Heading2, + Heading3, + Heading4, + Heading5, + Heading6, + HorizontalRule, + Image, + Italic, + ListItem, + OrderedList, + Paragraph, + PreformattedText, + Strikethrough, + Strong, + Subscript, + Superscript, + Underline, + UnorderedList +} from './annotations'; import HTMLSchemaTranslator from './translator'; -export { schema }; - function isElement(node: parse5.AST.Default.Node) { return node.nodeName !== undefined && node.nodeName !== '#text' && @@ -19,18 +44,14 @@ function isText(node: parse5.AST.Default.Node) { return node.nodeName === '#text'; } -interface Attributes { - [key: string]: string; -} - function getAttributes(node: parse5.AST.Default.Element): Attributes { let attrs: Attributes = (node.attrs || []).reduce((attributes: Attributes, attr: parse5.AST.Default.Attribute) => { - attributes[attr.name] = attr.value; + attributes[`-html-${attr.name}`] = attr.value; return attributes; }, {}); - if (node.tagName === 'a' && attrs.href) { - attrs.href = decodeURI(attrs.href); + if (node.tagName === 'a' && typeof attrs['-html-href'] === 'string') { + attrs['-html-href'] = decodeURI(attrs['-html-href']); } return attrs; } @@ -39,7 +60,7 @@ class Parser { content: string; - annotations: Annotation[]; + annotations: AnnotationJSON[]; private html: string; @@ -87,9 +108,10 @@ class Parser { if (location == null) return -1; let { startOffset: start, endOffset: end } = location[which]; + let reason = which === 'startTag' ? `<${node.tagName}>` : ``; this.annotations.push({ - type: 'parse-token', - attributes: { tagName: node.tagName }, + type: '-atjson-parse-token', + attributes: { '-atjson-reason': reason }, start: start - this.offset, end: end - this.offset }); @@ -138,8 +160,8 @@ class Parser { this.content += this.html.slice(location.startOffset, location.endOffset); this.annotations.push({ - type: 'parse-token', - attributes: { tagName }, + type: '-atjson-parse-token', + attributes: { '-atjson-reason': `<${tagName}/>` }, start, end }, { @@ -155,14 +177,40 @@ class Parser { } export default class HTMLSource extends Document { - - constructor(content: string) { - let parser = new Parser(content); - super({ + static contentType = 'appplication/vnd.atjson+html'; + static schema = [ + Anchor, + Bold, + Blockquote, + Break, + Code, + DeletedText, + Emphasis, + Heading1, + Heading2, + Heading3, + Heading4, + Heading5, + Heading6, + HorizontalRule, + Italic, + Image, + ListItem, + OrderedList, + Paragraph, + PreformattedText, + Strikethrough, + Strong, + Subscript, + Superscript, + Underline, + UnorderedList + ]; + static fromSource(html: string) { + let parser = new Parser(html); + return new this({ content: parser.content, - contentType: 'text/html', - annotations: parser.annotations, - schema: schema as Schema + annotations: parser.annotations }); } diff --git a/packages/@atjson/source-html/src/schema.ts b/packages/@atjson/source-html/src/schema.ts deleted file mode 100644 index 5706b8465a..0000000000 --- a/packages/@atjson/source-html/src/schema.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Display } from '@atjson/document'; - -export default { - '-html-a': { - display: 'inline' as Display - }, - '-html-b': { - display: 'inline' as Display - }, - '-html-blockquote': { - display: 'block' as Display - }, - '-html-br': { - display: 'object' as Display - }, - '-html-em': { - display: 'inline' as Display - }, - '-html-hr': { - display: 'object' as Display - }, - '-html-h1': { - display: 'block' as Display - }, - '-html-h2': { - display: 'block' as Display - }, - '-html-h3': { - display: 'block' as Display - }, - '-html-h4': { - display: 'block' as Display - }, - '-html-h5': { - display: 'block' as Display - }, - '-html-h6': { - display: 'block' as Display - }, - '-html-i': { - display: 'inline' as Display - }, - '-html-img': { - display: 'object' as Display - }, - '-html-li': { - display: 'block' as Display - }, - '-html-ol': { - display: 'block' as Display - }, - '-html-p': { - display: 'paragraph' as Display - }, - '-html-strong': { - display: 'inline' as Display - }, - '-html-ul': { - display: 'block' as Display - } -}; diff --git a/packages/@atjson/source-html/src/translator.ts b/packages/@atjson/source-html/src/translator.ts index 2e90ee4721..fbfd5c1185 100644 --- a/packages/@atjson/source-html/src/translator.ts +++ b/packages/@atjson/source-html/src/translator.ts @@ -1,48 +1,30 @@ -import Document, { Annotation, Schema } from '@atjson/document'; -import schema from '@atjson/schema'; +import Document, { AnyAnnotation } from '@atjson/document'; -export default class HTMLSchemaTranslator { +export default class HTMLSchemaTranslator extends Document { + static schema = []; + constructor(document: Document) { + super(document.toJSON()); - document: Document; + this.where({ type: '-html-a' }).set({ type: 'link' }).rename({ attributes: { '-html-href': 'url' } }); - constructor(document: Document) { - this.document = new Document({ - content: document.content, - contentType: 'text/atjson', - annotations: [...document.annotations], - schema: schema as Schema - }); - } + this.where({ type: '-html-blockquote' }).set({ type: 'blockquote' }); + + this.where({ type: '-html-h1' }).set({ type: 'heading', attributes: { level: 1 } }); + this.where({ type: '-html-h2' }).set({ type: 'heading', attributes: { level: 2 } }); + this.where({ type: '-html-h3' }).set({ type: 'heading', attributes: { level: 3 } }); + this.where({ type: '-html-h4' }).set({ type: 'heading', attributes: { level: 4 } }); + this.where({ type: '-html-h5' }).set({ type: 'heading', attributes: { level: 5 } }); + this.where({ type: '-html-h6' }).set({ type: 'heading', attributes: { level: 6 } }); + + this.where({ type: '-html-p' }).set({ type: 'paragraph' }); + this.where({ type: '-html-br' }).set({ type: 'line-break' }); + this.where({ type: '-html-hr' }).set({ type: 'horizontal-rule' }); - translate() { - let doc = this.document; - - doc.where({ type: '-html-a' }).set({ type: 'link' }).rename({ attributes: { href: 'url' } }); - - doc.where({ type: '-html-blockquote' }).set({ type: 'blockquote' }); - - doc.where({ type: '-html-h1' }).set({ type: 'heading', attributes: { level: 1 } }); - doc.where({ type: '-html-h2' }).set({ type: 'heading', attributes: { level: 2 } }); - doc.where({ type: '-html-h3' }).set({ type: 'heading', attributes: { level: 3 } }); - doc.where({ type: '-html-h4' }).set({ type: 'heading', attributes: { level: 4 } }); - doc.where({ type: '-html-h5' }).set({ type: 'heading', attributes: { level: 5 } }); - doc.where({ type: '-html-h6' }).set({ type: 'heading', attributes: { level: 6 } }); - - doc.where({ type: '-html-p' }).set({ type: 'paragraph' }); - doc.where({ type: '-html-br' }).set({ type: 'line-break' }); - doc.where({ type: '-html-hr' }).set({ type: 'horizontal-rule' }); - - doc.where({ type: '-html-ul' }).set({ type: 'list', attributes: { type: 'bulleted' } }); - doc.where({ type: '-html-ol' }).set({ type: 'list', attributes: { type: 'numbered' } }) - .rename({ attributes: { starts: 'startsAt' } }) - .map((list: Annotation) => { - if (list.attributes !== undefined) { - if (list.attributes && list.attributes.startsAt) { - list.attributes.startsAt = parseInt(list.attributes.startsAt, 10); - } - return list; - } else { - return null; + this.where({ type: '-html-ul' }).set({ type: 'list', attributes: { type: 'bulleted' } }); + this.where({ type: '-html-ol' }).set({ type: 'list', attributes: { type: 'numbered' } }) + .rename({ attributes: { '-html-starts': 'startsAt' } }).map((list: AnyAnnotation) => { + if (list.attributes && list.attributes.startsAt) { + list.attributes.startsAt = parseInt(list.attributes.startsAt, 10); } }); doc.where({ type: '-html-li' }).set({ type: 'list-item' }); @@ -54,6 +36,10 @@ export default class HTMLSchemaTranslator { doc.where({ type: '-html-img' }).set({ type: 'image'}).rename({ attributes: { src: 'url', alt: 'description' } }); +<<<<<<< HEAD return doc; +======= + this.where({ type: '-html-img' }).set({ type: 'image'}).rename({ attributes: { '-html-src': 'url', '-html-alt': 'description' } }); +>>>>>>> 🐛 Add HTML annotations (#66) } } diff --git a/packages/@atjson/source-html/test/source-html-test.ts b/packages/@atjson/source-html/test/source-html-test.ts index e35b39b2e4..d6c1233452 100644 --- a/packages/@atjson/source-html/test/source-html-test.ts +++ b/packages/@atjson/source-html/test/source-html-test.ts @@ -1,24 +1,23 @@ -import Document from '@atjson/document'; import { HIR } from '@atjson/hir'; -import HTMLSource from '@atjson/source-html'; +import HTMLSource from '../src'; describe('@atjson/source-html', () => { test('pre-code', () => { - let doc = new HTMLSource('
this is a test
'); + let doc = HTMLSource.fromSource('
this is a test
'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-pre', + type: 'pre', attributes: {}, children: [{ - type: '-html-code', + type: 'code', attributes: {}, children: [ 'this ', { - type: '-html-b', + type: 'b', attributes: {}, children: ['is'] }, @@ -30,30 +29,30 @@ describe('@atjson/source-html', () => { }); test('

aaa
\nbbb

', () => { - let doc = new HTMLSource('

aaa
\nbbb

'); + let doc = HTMLSource.fromSource('

aaa
\nbbb

'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-p', + type: 'p', attributes: {}, children: [ - 'aaa', { type: '-html-br', attributes: {}, children: [] }, '\nbbb' + 'aaa', { type: 'br', attributes: {}, children: [] }, '\nbbb' ] }] }); }); test('example', () => { - let doc = new HTMLSource('example'); + let doc = HTMLSource.fromSource('example'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-a', + type: 'a', attributes: { href: 'https://example.com' }, @@ -63,13 +62,13 @@ describe('@atjson/source-html', () => { }); test(' ', () => { - let doc = new HTMLSource(' '); + let doc = HTMLSource.fromSource(' '); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-img', + type: 'img', attributes: { src: 'https://example.com/test.png' }, @@ -79,21 +78,21 @@ describe('@atjson/source-html', () => { }); test('

\n

\n

', () => { - let doc = new HTMLSource('

\n

\n

'); + let doc = HTMLSource.fromSource('

\n

\n

'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-h2', + type: 'h2', attributes: {}, children: [] }, '\n', { - type: '-html-h1', + type: 'h1', attributes: {}, children: [] }, '\n', { - type: '-html-h3', + type: 'h3', attributes: {}, children: [] }] @@ -101,16 +100,16 @@ describe('@atjson/source-html', () => { }); test('

Foo

', () => { - let doc = new HTMLSource('

Foo

'); + let doc = HTMLSource.fromSource('

Foo

'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-p', + type: 'p', attributes: {}, children: [{ - type: '-html-img', + type: 'img', attributes: { src: '/url', alt: 'Foo', @@ -123,16 +122,16 @@ describe('@atjson/source-html', () => { }); test('

**

', () => { - let doc = new HTMLSource('

**

'); + let doc = HTMLSource.fromSource('

**

'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-p', + type: 'p', attributes: {}, children: ['**', { - type: '-html-a', + type: 'a', attributes: { href: '**' }, children: [] @@ -142,7 +141,7 @@ describe('@atjson/source-html', () => { }); test('<>', () => { - let doc = new HTMLSource('<>'); + let doc = HTMLSource.fromSource('<>'); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', @@ -152,13 +151,13 @@ describe('@atjson/source-html', () => { }); test('', () => { - let doc = new HTMLSource(''); + let doc = HTMLSource.fromSource(''); let hir = new HIR(doc).toJSON(); expect(hir).toEqual({ type: 'root', attributes: {}, children: [{ - type: '-html-a', + type: 'a', attributes: { href: 'https://en.wiktionary.org/wiki/日本人' }, @@ -169,7 +168,7 @@ describe('@atjson/source-html', () => { describe('translator to common schema', () => { test('bold, strong', () => { - let doc = new HTMLSource('This text is bold'); + let doc = HTMLSource.fromSource('This text is bold'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -187,7 +186,7 @@ describe('@atjson/source-html', () => { }); test('i, em', () => { - let doc = new HTMLSource('This text is italic'); + let doc = HTMLSource.fromSource('This text is italic'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -205,7 +204,7 @@ describe('@atjson/source-html', () => { }); test('h1, h2, h3, h4, h5, h6', () => { - let doc = new HTMLSource('

Title

Byline

Section

Normal heading

Small heading
Tiny heading
'); + let doc = HTMLSource.fromSource('

Title

Byline

Section

Normal heading

Small heading
Tiny heading
'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -239,7 +238,7 @@ describe('@atjson/source-html', () => { }); test('p, br', () => { - let doc = new HTMLSource('

This paragraph has a
line break

'); + let doc = HTMLSource.fromSource('

This paragraph has a
line break

'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -257,7 +256,7 @@ describe('@atjson/source-html', () => { }); test('a', () => { - let doc = new HTMLSource('This is a link'); + let doc = HTMLSource.fromSource('This is a link'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -273,7 +272,7 @@ describe('@atjson/source-html', () => { }); test('hr', () => { - let doc = new HTMLSource('Horizontal
rules!'); + let doc = HTMLSource.fromSource('Horizontal
rules!'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -287,7 +286,7 @@ describe('@atjson/source-html', () => { }); test('img', () => { - let doc = new HTMLSource('Miles Davis came out, blond, in gold lamé, and he plays really terrific music. High heels. 4/6/86'); + let doc = HTMLSource.fromSource('Miles Davis came out, blond, in gold lamé, and he plays really terrific music. High heels. 4/6/86'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -305,7 +304,7 @@ describe('@atjson/source-html', () => { }); test('blockquote', () => { - let doc = new HTMLSource('
This is a quote
'); + let doc = HTMLSource.fromSource('
This is a quote
'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root', @@ -319,7 +318,7 @@ describe('@atjson/source-html', () => { }); test('ul, ol, li', () => { - let doc = new HTMLSource('
  1. Second
  2. Third
'); + let doc = HTMLSource.fromSource('
  1. Second
  2. Third
'); let hir = new HIR(doc.toCommonSchema()).toJSON(); expect(hir).toEqual({ type: 'root',