-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(types): add type definitions #24
Changes from all commits
5a75bc2
184d4a2
2ebc320
f9f9cd0
b7403ec
6e5ae64
9b31b18
6b4ed7c
acfdaf9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// JsonML | ||
// see: http://www.jsonml.org/syntax/ | ||
// | ||
// `Node` type imported from lib.dom | ||
// | ||
/// <reference lib="dom"/> | ||
|
||
export type AttributeValue = any; | ||
|
||
export interface Attributes { | ||
[key: string]: AttributeValue; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The problem I see with using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not using it because I think it will break our applications. I'm pretty sure we are extending element attributes with objects within our applications, since we don't intend to transform the JsonML back into HTML or DOM. An example of a common use case might be an embedded content reference where later we merge in the related data structures directly with the attributes. A likely use case, in the wild: ['inline-embed', { type: 'foo', relatedData: {/* some object */}, }] Enforcing this type strictness is correct per the spec but might become a problem for us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I gave this some more thought. This fork is open-source and shouldn't care about how downstream applications. The type definitions should be strict and accurate. If we need to find some workarounds later, we can figure that out. I've updated the attribute value definition accordingly. Update: still more struggle. I'm testing this and it does indeed cause a great deal of trouble. Far more than it's worth, I'd say. Once I define strict attribute values, this is required by the Thoughts? I feel like the most strictly correct thing to do is to keep the strict definitions and then duplicate and modify the definitions file as needed by applications. However, I worry about the trade-off in value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my experience, its pretty common to have strict types imported as correctly typed by a lib and then extend, union, or partial them in my code. Here's a paired down example of how this might work in this case: Playground Link. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, agreed. The trouble is that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jeromecovington @pgoldrbx yeah, I think for now we may just want to use |
||
|
||
type TagName = string; | ||
|
||
type TextNode = string; | ||
|
||
export type JSONMLElement = [ TagName ] | ||
| [ TagName, Attributes ] | ||
| [ TagName, ...JSONMLNode[] ] | ||
| [ TagName, Attributes, ...JSONMLNode[] ] | ||
; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jeromecovington I've tried another approach! I think I have variable-length tuples working now by using spread. 🤷♂ |
||
|
||
export type JSONMLNode = JSONMLElement | TextNode | ||
|
||
|
||
// Utils | ||
export function isFragment(jml: JSONMLElement): boolean; | ||
|
||
export function isMarkup(value: any): boolean; | ||
|
||
export function getTagName(jml: JSONMLElement): TagName; | ||
|
||
export function isElement(value: any): boolean; | ||
|
||
export function isAttributes(value: any): boolean; | ||
|
||
export function hasAttributes(jml: JSONMLElement): boolean; | ||
|
||
export function getAttributes(jml: JSONMLElement, addIfMissing?: boolean): Attributes; | ||
|
||
export function addAttributes(jml: JSONMLElement, attr: Attributes): void; | ||
|
||
export function getAttribute(jml: JSONMLElement, key: string): AttributeValue | void; | ||
|
||
export function setAttribute(jml: JSONMLElement, key: string, value: AttributeValue): void; | ||
|
||
export function appendChild(jml: JSONMLElement, child: JSONMLElement): boolean; | ||
|
||
export function getChildren(jml: JSONMLElement): JSONMLNode[]; | ||
|
||
|
||
// DOM | ||
export type JSONMLElementFilter = (jml: JSONMLElement, elem: JSONMLNode) => JSONMLElement | null; | ||
|
||
export function fromHTML(elem: Node, filter?: JSONMLElementFilter): JSONMLElement | null; | ||
|
||
export function fromHTMLText(html: string, filter?: JSONMLElementFilter): JSONMLElement | null; | ||
|
||
|
||
// HTML | ||
export class Markup { | ||
value: string | ||
toString(): string | ||
} | ||
|
||
export type HTMLElementFilter = (elem: Node) => Node | ||
|
||
export type ErrorHandler = (err: Error, jml: JSONMLElement, filter?: HTMLElementFilter) => any | ||
|
||
export function raw(value: string): Markup; | ||
|
||
export function isRaw(value: any): boolean; | ||
|
||
export let onerror: null | ErrorHandler | ||
|
||
export function patch(elem: Node, jml: JSONMLElement, filter?: HTMLElementFilter): Node | ||
|
||
export function toHTML(jml: string | JSONMLElement, filter?: HTMLElementFilter): Node | ||
|
||
export function toHTMLText(jml: string | JSONMLElement, filter?: HTMLElementFilter): string |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { | ||
Attributes, | ||
AttributeValue, | ||
JSONMLNode, | ||
} from '..'; | ||
|
||
import * as jsonml from '..'; | ||
|
||
// Utils | ||
const isFragYes: boolean = jsonml.isFragment(['', 'hi']); | ||
const isFragNo: boolean = jsonml.isFragment(['div', 'hi']); | ||
|
||
const isMarkupYes: boolean = jsonml.isMarkup(jsonml.raw('hello')); | ||
const isMarkupNo: boolean = jsonml.isMarkup(['div', 'hello']); | ||
|
||
const paraTag: string = jsonml.getTagName(['p', 'some text']); | ||
const fragTag: string = jsonml.getTagName(['', 'some fragment text']); | ||
|
||
const foo = jsonml.getTagName([ | ||
'', // fragment | ||
{ foo: 'bar' }, // attributes allowed here | ||
['p', { foo: 'bar' }, 'some fragment text'], | ||
['p', { foo: 'bar' }, 'some fragment text'], | ||
['div', 'foo'], | ||
'baz' | ||
]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested and can verify that I get issues if the attributes are moved to the wrong position or if an |
||
|
||
const isElemYes: boolean = jsonml.isElement(['img', { href: 'https://example.com/foo.jpg' }]); | ||
const isElemNo: boolean = jsonml.isElement({}); | ||
|
||
const isAttrsYes: boolean = jsonml.isAttributes({ foo: 'bar' }); | ||
const isAttrsNo: boolean = jsonml.isAttributes(['foo']); | ||
|
||
const hasAttrsYes: boolean = jsonml.hasAttributes(['p', { foo: 'bar' }]); | ||
const hasAttrsNo: boolean = jsonml.hasAttributes(['p']); | ||
|
||
const gotAttrs: Attributes = jsonml.getAttributes(['p', { foo: 'bar' }]); | ||
const gotAddedAttrs: Attributes = jsonml.getAttributes(['p'], true); | ||
const gotEmptyAttrs: Attributes = jsonml.getAttributes(['p'], false); | ||
|
||
const addAttributesRetval: void = jsonml.addAttributes(['p'], { foo: 'bar', a: 1 }); | ||
|
||
type MaybeAttributeValue = AttributeValue | void; | ||
const gotAttr: MaybeAttributeValue = jsonml.getAttribute(['p', { foo: 'bar' }], 'foo'); | ||
const gotNoAttr: MaybeAttributeValue = jsonml.getAttribute(['p', { foo: 'bar' }], 'this-does-not-exist'); | ||
|
||
const setAttributeRetval: void = jsonml.setAttribute(['p'], 'foo', 'bar'); | ||
|
||
const childWasAppended: boolean = jsonml.appendChild(['p', { foo: 'bar'}], ['strong', 'Hello World', ['em', 'another'], 'bye' ]); | ||
|
||
const gotChildren: JSONMLNode[] = jsonml.getChildren(['div', ['p', 'one'], ['p', 'two'], 'foo']); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"compilerOptions": { | ||
"module": "commonjs", | ||
"noEmit": true, | ||
"strict": true, | ||
"target": "es6", | ||
"lib": [ | ||
"es2015", | ||
"dom" | ||
] | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attempting to mark that
lib.dom
is required. TheNode
type is available as a global after adding'dom'
totsconfig
. I wish I could reference it more explicitly.Overall, I'm not sure if I'm handling namespacing/scope properly.
I've also renamed types to avoid shadowing the DOM globals.
Element
->
JSONMLElement
Node
->
JSONMLNode
(based on similar from
HTMLElement
)