Skip to content

Commit

Permalink
🐛 Add HTML annotations (#66)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
tim-evans committed Oct 11, 2018
1 parent 32972dc commit b3cf26d
Show file tree
Hide file tree
Showing 32 changed files with 344 additions and 166 deletions.
3 changes: 2 additions & 1 deletion packages/@atjson/document/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,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;
Expand Down
11 changes: 11 additions & 0 deletions packages/@atjson/source-html/src/annotations/anchor.ts
Original file line number Diff line number Diff line change
@@ -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;
};
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/blockquote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Blockquote extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'blockquote';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/bold.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Bold extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'b';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/break.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ObjectAnnotation } from '@atjson/document';

export default class Break extends ObjectAnnotation {
static vendorPrefix = 'html';
static type = 'br';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Code extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'code';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/deleted-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class DeletedText extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'del';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/emphasis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Emphasis extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'em';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading1 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h1';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading2 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h2';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading3 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h3';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-4.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading4 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h4';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading5 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h5';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/heading-6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class Heading6 extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'h6';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ObjectAnnotation } from '@atjson/document';

export default class HorizontalRule extends ObjectAnnotation {
static vendorPrefix = 'html';
static type = 'hr';
}
11 changes: 11 additions & 0 deletions packages/@atjson/source-html/src/annotations/image.ts
Original file line number Diff line number Diff line change
@@ -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;
};
}
26 changes: 26 additions & 0 deletions packages/@atjson/source-html/src/annotations/index.ts
Original file line number Diff line number Diff line change
@@ -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';
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/italic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Italic extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'i';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/list-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class ListItem extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'li';
}
9 changes: 9 additions & 0 deletions packages/@atjson/source-html/src/annotations/ordered-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BlockAnnotation } from '@atjson/document';

export default class OrderedList extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'ol';
attributes!: {
starts: string;
};
}
10 changes: 10 additions & 0 deletions packages/@atjson/source-html/src/annotations/paragraph.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class PreformattedText extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'pre';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/strikethrough.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Strikethrough extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 's';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/strong.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Strong extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'strong';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/subscript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Subscript extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'sub';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/superscript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Superscript extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'sup';
}
6 changes: 6 additions & 0 deletions packages/@atjson/source-html/src/annotations/underline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { InlineAnnotation } from '@atjson/document';

export default class Underline extends InlineAnnotation {
static vendorPrefix = 'html';
static type = 'u';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { BlockAnnotation } from '@atjson/document';

export default class UnorderedList extends BlockAnnotation {
static vendorPrefix = 'html';
static type = 'ul';
}
96 changes: 72 additions & 24 deletions packages/@atjson/source-html/src/index.ts
Original file line number Diff line number Diff line change
@@ -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' &&
Expand All @@ -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;
}
Expand All @@ -39,7 +60,7 @@ class Parser {

content: string;

annotations: Annotation[];
annotations: AnnotationJSON[];

private html: string;

Expand Down Expand Up @@ -87,9 +108,10 @@ class Parser {
if (location == null) return -1;

let { startOffset: start, endOffset: end } = location[which];
let reason = which === 'startTag' ? `<${node.tagName}>` : `</${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
});
Expand Down Expand Up @@ -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
}, {
Expand All @@ -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
});
}

Expand Down
Loading

0 comments on commit b3cf26d

Please sign in to comment.