From 8cd5b0218fb68832a09029597da04932d43f12cb Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sat, 3 Mar 2018 00:33:04 +0000 Subject: [PATCH 001/104] fix more edge cases when selecting text --- packages/editor/src/text-selection.ts | 159 ++++++++++++++------------ 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index fb562a945..d1ff90072 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -1,13 +1,33 @@ import events from './mixins/events'; +import { debug } from 'util'; const TEXT_NODE_TYPE = 3; const DOCUMENT_POSITION_PRECEDING = 2; const DOCUMENT_POSITION_FOLLOWING = 4; -function sum(a, b) { +function sum(a: number, b: number) { return a + b; } +interface RangeEdge { + node: Node | null; + offset: number; +} + +function getTextNode(node: Node, trailing?: boolean): Text | null { + while (node.nodeType !== TEXT_NODE_TYPE && node != null) { + if (trailing) { + node = node.childNodes[node.childNodes.length - 1]; + } else { + node = node.childNodes[0]; + } + } + if (node) { + return node as Text; + } + return null; +} + /** Events available for listening for : @@ -17,12 +37,16 @@ function sum(a, b) { class TextSelection extends events(HTMLElement) { static observedAttributes = ['start', 'end']; static events = { - 'selectionchange document': 'selectedTextDidChange', - 'mousedown': 'willSelectText', - 'mouseup': 'didSelectText' + 'selectionchange document': 'selectedTextDidChange' }; - private textNodes: Text[] | null; + private textNodes: Text[]; + private observer?: MutationObserver | null; + + constructor() { + super(); + this.textNodes = []; + } connectedCallback() { super.connectedCallback(); @@ -39,21 +63,23 @@ class TextSelection extends events(HTMLElement) { disconnectedCallback() { super.disconnectedCallback(); - this.observer.disconnect(); - this.observer = null; - this.textNodes = null; + if (this.observer) { + this.observer.disconnect(); + this.observer = null; + } + this.textNodes = []; } - getTextNodes(element?: Element): Text[] { - let nodes = []; - element = element || this; + getTextNodes(node?: Node): Text[] { + let nodes: Text[] = []; + node = node || this; - if (element.hasChildNodes()) { - element.childNodes.forEach((node) => { - nodes = nodes.concat(this.getTextNodes(node)); + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(this.getTextNodes(child)); }); - } else if (element.nodeType === TEXT_NODE_TYPE) { - nodes.push(element); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); } return nodes; @@ -64,7 +90,7 @@ class TextSelection extends events(HTMLElement) { let start = 0; let node = nodes.find(function (node) { - let end = start + node.nodeValue.length; + let end = start + (node.nodeValue || '').length; if (position >= start && position < end) { return true; } @@ -78,25 +104,19 @@ class TextSelection extends events(HTMLElement) { }; } - willSelectText() { - this.isSelecting = true; - } - - didSelectText() { - this.isSelecting = false; - } - - getNodeAndOffset(node: Element | null, offset: number): { node: Element | null, offset: number } | never { + getNodeAndOffset({ node, offset }: RangeEdge): { node: Text | null, offset: number } | never { if (node == null) { return { node: null, offset }; } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node, offset }; + return { node: node as Text, offset }; } else if (node.childNodes.length > 0) { + let textNode; // Firefox can return an offset that is the length // of the node list, which signifies that the node // and offset is the last node at the last character :/ if (offset === node.childNodes.length) { - return { node: node.childNodes[offset - 1], offset: node.childNodes[offset - 1].length }; + textNode = getTextNode(node, true); + return { node: textNode, offset: (textNode ? textNode.length : 0) }; } let offsetNode = node.childNodes[offset]; @@ -109,35 +129,39 @@ class TextSelection extends events(HTMLElement) { // The offset node is a text node; quickly return if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode, offset: 0 }; + return { node: offsetNode as Text, offset: 0 }; + + // If the selected node is wholly outside of the + // component, it's a nil selection + } else if (!this.contains(offsetNode)) { + return { node: null, offset: 0 }; // Find the closest text node and return that } else if (!offsetNode.hasChildNodes()) { let adjustedOffset = offset - 1; // Look for the nearest preceding text node - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset > 0) { - offsetNode = node.childNodes[adjustedOffset--]; - } - - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - offset = offsetNode.length; + do { + textNode = getTextNode(node.childNodes[adjustedOffset--], true); + } while (textNode && this.contains(textNode) && adjustedOffset > 0); // Look for the next text node following the offset + if (textNode) { + offset = textNode.length; } else { adjustedOffset = offset; offset = 0; - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset < node.childNodes.length) { - offsetNode = node.childNodes[adjustedOffset++]; - } + + do { + textNode = getTextNode(node.childNodes[adjustedOffset++]); + } while (textNode && this.contains(textNode) && adjustedOffset < node.childNodes.length); } - if (offsetNode.nodeType !== TEXT_NODE_TYPE) { - throw new Error("A node / offset pair couldn't be found for the selection."); + if (textNode) { + return { node: textNode, offset }; + } else { - return { node: offsetNode, offset }; + throw new Error("A node / offset pair couldn't be found for the selection."); } } else { throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); @@ -147,15 +171,7 @@ class TextSelection extends events(HTMLElement) { } } - clearSelection(): number { - return setTimeout(() => { - this.removeAttribute('start'); - this.removeAttribute('end'); - this.dispatchEvent(new CustomEvent('clear')); - }, 10); - } - - clampRangePoint(edge: { node: Element, offset: number }): { node: Element, offset: number } { + clampRangePoint(edge: { node: Text, offset: number }): { node: Text, offset: number } { let firstNode = this.textNodes[0]; let lastNode = this.textNodes[this.textNodes.length - 1]; @@ -173,25 +189,26 @@ class TextSelection extends events(HTMLElement) { return edge; } - selectedTextDidChange() { - if (this.didSetSelection) { - this.didSetSelection = false; - return true; - } + clearSelection() { + this.removeAttribute('start'); + this.removeAttribute('end'); + this.dispatchEvent(new CustomEvent('clear')); + } + selectedTextDidChange() { let range = document.getSelection(); let nodes = this.textNodes; - let basePrefix = 'base'; - let extentPrefix = 'extent'; - if (range.anchorNode != null) { - basePrefix = 'anchor'; - extentPrefix = 'focus'; + let startOfSelection = { node: range.baseNode, offset: range.baseOffset }; + let endOfSelection = { node: range.extentNode, offset: range.extentOffset }; + if (range.anchorNode) { + startOfSelection = { node: range.anchorNode, offset: range.anchorOffset }; + endOfSelection = { node: range.focusNode, offset: range.focusOffset }; } let [base, extent] = [ - this.getNodeAndOffset(range[`${basePrefix}Node`], range[`${basePrefix}Offset`]), - this.getNodeAndOffset(range[`${extentPrefix}Node`], range[`${extentPrefix}Offset`]) + this.getNodeAndOffset(startOfSelection), + this.getNodeAndOffset(endOfSelection) ].sort((a, b) => { if (!a.node || !b.node) return 0; @@ -211,7 +228,7 @@ class TextSelection extends events(HTMLElement) { // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable if (base.node == null || extent.node == null) { - this._clearTimer = this.clearSelection(); + this.clearSelection(); return true; } @@ -222,7 +239,7 @@ class TextSelection extends events(HTMLElement) { let commonAncestor = domRange.commonAncestorContainer; if (!this.contains(commonAncestor) && !commonAncestor.contains(this)) { - this._clearTimer = this.clearSelection(); + this.clearSelection(); return true; } @@ -232,19 +249,17 @@ class TextSelection extends events(HTMLElement) { extent = this.clampRangePoint(extent); } - let lengths = nodes.map((node) => node.nodeValue.length); + let lengths = nodes.map((node) => (node.nodeValue || '').length); let start = lengths.slice(0, nodes.indexOf(base.node)).reduce(sum, base.offset); let end = lengths.slice(0, nodes.indexOf(extent.node)).reduce(sum, extent.offset); if (start === end && isNonZeroRange) { - this._clearTimer = this.clearSelection(); return true; } - clearTimeout(this._clearTimer); - this.setAttribute('start', start); - this.setAttribute('end', end); - this.dispatchEvent(new CustomEvent('change', { detail: { start, end } })); + this.setAttribute('start', start.toString()); + this.setAttribute('end', end.toString()); + this.dispatchEvent(new CustomEvent('change', { detail: { start, end, collapsed: start === end } })); return true; } } From baf98c81d8137db37d74ee675a93e5175c60a2e1 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:12:29 -0500 Subject: [PATCH 002/104] allow closures to be called directly from events --- packages/editor/src/mixins/events.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/editor/src/mixins/events.ts b/packages/editor/src/mixins/events.ts index df7c902af..d10ff8e80 100644 --- a/packages/editor/src/mixins/events.ts +++ b/packages/editor/src/mixins/events.ts @@ -5,7 +5,7 @@ interface EventCallback { } interface EventHandlerDefinitions { - [key: string]: string; + [key: string]: string | EventCallback; } interface EventHandlerReferences { @@ -68,13 +68,19 @@ export default function(Base: HTMLElement) { Object.keys(events).forEach((definition: string) => { let { eventName, element } = getEventNameAndElement(this, definition); let method = events[definition]; - this.eventHandlers[definition] = (evt): EventCallback | never => { - if (this[method]) { - return this[method](evt); - } else { - throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); - } - }; + if (typeof method === 'string') { + this.eventHandlers[definition] = (evt): EventCallback | never => { + if (this[method]) { + return this[method](evt); + } else { + throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); + } + }; + } else { + this.eventHandlers[definition] = (evt): EventCallback => { + return method.call(this, evt); + }; + } element.addEventListener(eventName, this.eventHandlers[definition]); }); } @@ -88,4 +94,3 @@ export default function(Base: HTMLElement) { } } }; - From b12393d6428231308d25f8b5ad76973acee7b1aa Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:13:00 -0500 Subject: [PATCH 003/104] simplify text selection code and make it work with more edge cases Specifically, we have cases where selecting nodes with no children results in an ambiguous offset. Technically, these represent annotation boundaries, but since we don't actually want to disambiguate these, we're instead looking at pure textual offsets. The major change here was simplifying the code that handles selection on nodes with no children (cf,
, ) and nodes that are outside the text selection component. --- packages/editor/src/text-selection.ts | 276 +++++++++++++------------- 1 file changed, 141 insertions(+), 135 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index d1ff90072..9fa086436 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -1,21 +1,20 @@ import events from './mixins/events'; -import { debug } from 'util'; const TEXT_NODE_TYPE = 3; const DOCUMENT_POSITION_PRECEDING = 2; const DOCUMENT_POSITION_FOLLOWING = 4; -function sum(a: number, b: number) { +function sum(a: number, b: number): number { return a + b; } -interface RangeEdge { - node: Node | null; - offset: number; -} +type MaybeNode = Node | null; +type NodeRangePoint = [MaybeNode, number]; +type NodeRange = [NodeRangePoint, NodeRangePoint]; +type TextRangePoint = [Text | null, number]; -function getTextNode(node: Node, trailing?: boolean): Text | null { - while (node.nodeType !== TEXT_NODE_TYPE && node != null) { +function getTextNode(node: MaybeNode, trailing?: boolean): Text | null { + while (node && node.nodeType !== TEXT_NODE_TYPE && node != null) { if (trailing) { node = node.childNodes[node.childNodes.length - 1]; } else { @@ -28,6 +27,51 @@ function getTextNode(node: Node, trailing?: boolean): Text | null { return null; } +function getTextNodes(node: Node): Text[] { + let nodes: Text[] = []; + + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(getTextNodes(child)); + }); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); + } + + return nodes; +} + +function nextTextNode(node: Node): TextRangePoint { + let nextNode: MaybeNode = node; + while (nextNode) { + let textNodes = getTextNodes(nextNode); + if (textNodes.length) { + return [textNodes[0], 0]; + } + nextNode = nextNode.nextSibling; + } + if (node.parentNode) { + return nextTextNode(node.parentNode); + } + return [null, 0]; +} + +function previousTextNode(node: Node): TextRangePoint { + let previousNode: MaybeNode = node; + while (previousNode) { + let textNodes = getTextNodes(previousNode); + if (textNodes.length) { + let textNode = textNodes[textNodes.length - 1]; + return [textNode, textNode.length]; + } + previousNode = previousNode.previousSibling; + } + if (node.parentNode) { + return previousTextNode(node.parentNode); + } + return [null, 0]; +} + /** Events available for listening for : @@ -54,10 +98,10 @@ class TextSelection extends events(HTMLElement) { // Setup observers so when the underlying text changes, // we update the text nodes that we want to map our selection from this.observer = new MutationObserver(() => { - this.textNodes = this.getTextNodes(); + this.textNodes = getTextNodes(this); }); this.observer.observe(this, { childList: true, characterData: true, subtree: true }); - this.textNodes = this.getTextNodes(); + this.textNodes = getTextNodes(this); } disconnectedCallback() { @@ -70,171 +114,125 @@ class TextSelection extends events(HTMLElement) { this.textNodes = []; } - getTextNodes(node?: Node): Text[] { - let nodes: Text[] = []; - node = node || this; + private getNodeAndOffset([node, offset]: NodeRangePoint, leading: boolean): TextRangePoint | never { + // No node to get an offset for; bail + if (node == null) { + return [null, offset]; - if (node.hasChildNodes()) { - node.childNodes.forEach((child: Node) => { - nodes = nodes.concat(this.getTextNodes(child)); - }); + // The offset is a text offset } else if (node.nodeType === TEXT_NODE_TYPE) { - nodes.push(node as Text); - } - - return nodes; - } - - nodeAndOffsetForPosition(position: number) { - let nodes = this.textNodes; - let start = 0; - - let node = nodes.find(function (node) { - let end = start + (node.nodeValue || '').length; - if (position >= start && position < end) { - return true; - } - start = end; - return false; - }); - - return { - node, - offset: position - start - }; - } + return [node as Text, offset]; + + // If the node is outside the + } else if (!this.contains(node) && this !== node) { + switch (this.compareDocumentPosition(node)) { + case DOCUMENT_POSITION_PRECEDING: + return previousTextNode(node); + case DOCUMENT_POSITION_FOLLOWING: + return nextTextNode(node); + default: + return [null, 0]; + } - getNodeAndOffset({ node, offset }: RangeEdge): { node: Text | null, offset: number } | never { - if (node == null) { - return { node: null, offset }; - } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node: node as Text, offset }; - } else if (node.childNodes.length > 0) { - let textNode; - // Firefox can return an offset that is the length - // of the node list, which signifies that the node - // and offset is the last node at the last character :/ - if (offset === node.childNodes.length) { - textNode = getTextNode(node, true); - return { node: textNode, offset: (textNode ? textNode.length : 0) }; - } + // If the node isn't a text node, the offset refers to a + // node offset. We will disambiguate this to a text offset + } else if (node.childNodes.length > offset) { let offsetNode = node.childNodes[offset]; + let textNodes = getTextNodes(offsetNode); // If the offset node has a single child node, // use that node instead of the parent - if (offsetNode.nodeType !== TEXT_NODE_TYPE && - offsetNode.childNodes.length === 1) { - offsetNode = offsetNode.childNodes[0]; + if (textNodes.length === 1) { + return [textNodes[0], 0]; } - - // The offset node is a text node; quickly return - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode as Text, offset: 0 }; - - // If the selected node is wholly outside of the - // component, it's a nil selection - } else if (!this.contains(offsetNode)) { - return { node: null, offset: 0 }; - + // Find the closest text node and return that - } else if (!offsetNode.hasChildNodes()) { - let adjustedOffset = offset - 1; - - // Look for the nearest preceding text node - do { - textNode = getTextNode(node.childNodes[adjustedOffset--], true); - } while (textNode && this.contains(textNode) && adjustedOffset > 0); - - // Look for the next text node following the offset - if (textNode) { - offset = textNode.length; - } else { - adjustedOffset = offset; - offset = 0; - - do { - textNode = getTextNode(node.childNodes[adjustedOffset++]); - } while (textNode && this.contains(textNode) && adjustedOffset < node.childNodes.length); + if (textNodes.length === 0) { + if (leading) { + return previousTextNode(node); } + return nextTextNode(node); + } - if (textNode) { - return { node: textNode, offset }; + throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); + + // Firefox can return an offset that is the length + // of the node list, which signifies that the node + // and offset is the last node at the last character :/ + } else if (node.childNodes.length === offset) { + let textNodes = getTextNodes(node); + let textNode = textNodes[textNodes.length - 1]; + return [textNode, textNode ? textNode.length : 0]; - } else { - throw new Error("A node / offset pair couldn't be found for the selection."); - } - } else { - throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); - } } else { - return { node: null, offset }; + return [null, offset]; } } - clampRangePoint(edge: { node: Text, offset: number }): { node: Text, offset: number } { + private clampRangePoint([text, offset]: TextRangePoint): TextRangePoint { + if (text == null) { + return [text, offset]; + } let firstNode = this.textNodes[0]; let lastNode = this.textNodes[this.textNodes.length - 1]; - if (firstNode.compareDocumentPosition(edge.node) == DOCUMENT_POSITION_PRECEDING) { - return { - node: firstNode, - offset: 0 - }; - } else if (lastNode.compareDocumentPosition(edge.node) == DOCUMENT_POSITION_FOLLOWING) { - return { - node: lastNode, - offset: lastNode.length - }; + if (firstNode.compareDocumentPosition(text) == DOCUMENT_POSITION_PRECEDING) { + return [firstNode, 0]; + + } else if (lastNode.compareDocumentPosition(text) == DOCUMENT_POSITION_FOLLOWING) { + return [lastNode, lastNode.length]; + } - return edge; + return [text, offset]; } - clearSelection() { + private clearSelection() { this.removeAttribute('start'); this.removeAttribute('end'); this.dispatchEvent(new CustomEvent('clear')); } - selectedTextDidChange() { - let range = document.getSelection(); + private selectedTextDidChange() { + let selectionRange = document.getSelection(); let nodes = this.textNodes; - let startOfSelection = { node: range.baseNode, offset: range.baseOffset }; - let endOfSelection = { node: range.extentNode, offset: range.extentOffset }; - if (range.anchorNode) { - startOfSelection = { node: range.anchorNode, offset: range.anchorOffset }; - endOfSelection = { node: range.focusNode, offset: range.focusOffset }; + let nodeRange: NodeRange = [[selectionRange.baseNode, selectionRange.baseOffset], + [selectionRange.extentNode, selectionRange.extentOffset]]; + if (selectionRange.anchorNode) { + nodeRange = [[selectionRange.anchorNode, selectionRange.anchorOffset], + [selectionRange.focusNode, selectionRange.focusOffset]]; } - - let [base, extent] = [ - this.getNodeAndOffset(startOfSelection), - this.getNodeAndOffset(endOfSelection) - ].sort((a, b) => { - if (!a.node || !b.node) return 0; + nodeRange = nodeRange.sort(([aNode, aOffset], [bNode, bOffset]) => { + if (!aNode || !bNode) return 0; // Sort by node position then offset - switch (a.node.compareDocumentPosition(b.node)) { + switch (aNode.compareDocumentPosition(bNode)) { case DOCUMENT_POSITION_PRECEDING: return 1; case DOCUMENT_POSITION_FOLLOWING: return -1; default: - return a.offset - b.offset; + return aOffset - bOffset; } }); - let isNonZeroRange = base.node !== extent.node || base.offset !== extent.offset; + let [start, end] = [ + this.getNodeAndOffset(nodeRange[0], true), + this.getNodeAndOffset(nodeRange[1], false) + ]; + + let isNonZeroRange = start[0] !== end[0] || start[1] !== end[1]; // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable - if (base.node == null || extent.node == null) { + if (start[0] == null || end[0] == null) { this.clearSelection(); return true; } let domRange = document.createRange(); - domRange.setStart(base.node, base.offset); - domRange.setEnd(extent.node, extent.offset); + domRange.setStart(start[0], start[1]); + domRange.setEnd(end[0], end[1]); let commonAncestor = domRange.commonAncestorContainer; @@ -245,21 +243,29 @@ class TextSelection extends events(HTMLElement) { // Fix the base and offset nodes if (!this.contains(commonAncestor) && this !== commonAncestor) { - base = this.clampRangePoint(base); - extent = this.clampRangePoint(extent); + start = this.clampRangePoint(start); + end = this.clampRangePoint(end); } let lengths = nodes.map((node) => (node.nodeValue || '').length); - let start = lengths.slice(0, nodes.indexOf(base.node)).reduce(sum, base.offset); - let end = lengths.slice(0, nodes.indexOf(extent.node)).reduce(sum, extent.offset); + let range = [ + lengths.slice(0, nodes.indexOf(start[0])).reduce(sum, start[1]), + lengths.slice(0, nodes.indexOf(end[0])).reduce(sum, end[1]) + ]; - if (start === end && isNonZeroRange) { + if (range[0] === range[1] && isNonZeroRange) { return true; } - this.setAttribute('start', start.toString()); - this.setAttribute('end', end.toString()); - this.dispatchEvent(new CustomEvent('change', { detail: { start, end, collapsed: start === end } })); + this.setAttribute('start', range[0].toString()); + this.setAttribute('end', range[1].toString()); + this.dispatchEvent(new CustomEvent('change', { + detail: { + start: range[0], + end: range[1], + collapsed: range[0] === range[1] + } + })); return true; } } From b0eac848cb69d767a44d05ea2888514893bcffd2 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:15:31 -0500 Subject: [PATCH 004/104] add a more complicated document to test text selection better --- packages/editor/demo.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/editor/demo.ts diff --git a/packages/editor/demo.ts b/packages/editor/demo.ts new file mode 100644 index 000000000..4f87f5640 --- /dev/null +++ b/packages/editor/demo.ts @@ -0,0 +1,26 @@ +import Document from '@atjson/document'; +import Editor from './src/index'; + +if (!window.customElements.get('text-editor')) { + window.customElements.define('text-editor', Editor); +} + +// Web components in the registry can't be redefined, +// so reload the page on every change +if (module.hot) { + module.hot.dispose(function () { + window.location.reload(); + }); +} + +let doc = new Document({ + content: 'Some text that is both bold and italic plus something after.', + annotations: [ + { type: 'bold', start: 23, end: 31 }, + { type: 'italic', start: 28, end: 38 } + ] +}); + +let editor = document.createElement('text-editor'); +editor.document = doc; +document.body.appendChild(editor); From a1346d82b770eba47e4cd705824ad510cb657738 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:15:49 -0500 Subject: [PATCH 005/104] move text input management into its own component --- packages/editor/src/index.ts | 129 ++---------------------------- packages/editor/src/text-input.ts | 93 +++++++++++++++++++++ 2 files changed, 98 insertions(+), 124 deletions(-) create mode 100644 packages/editor/src/text-input.ts diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 8a762655a..9fb84c66d 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -2,66 +2,12 @@ import { HIR } from '@atjson/hir'; import Document from '@atjson/document'; import events from './mixins/events'; import './text-selection'; +import './text-input'; const TEXT_NODE_TYPE = 3; type Element = TextNode | HTMLElement; -function getNodeAndOffset(node: Element | null, offset: number): { node: Element | null, offset: number } | never { - if (node == null) { - return { node: null, offset }; - } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node, offset }; - } else if (node.childNodes.length > 0) { - let offsetNode = node.childNodes[offset]; - - // If the offset node has a single child node, - // use that node instead of the parent - if (offsetNode.nodeType !== TEXT_NODE_TYPE && - offsetNode.childNodes.length === 1) { - offsetNode = offsetNode.childNodes[0]; - } - - // The offset node is a text node; quickly return - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode, offset: 0 }; - - // Find the closest text node and return that - } else if (!offsetNode.hasChildNodes()) { - let adjustedOffset = offset - 1; - - // Look for the nearest preceding text node - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset > 0) { - offsetNode = node.childNodes[adjustedOffset--]; - } - - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - offset = offsetNode.length; - - // Look for the next text node following the offset - } else { - adjustedOffset = offset; - offset = 0; - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset < node.childNodes.length) { - offsetNode = node.childNodes[adjustedOffset++]; - } - } - - if (offsetNode.nodeType !== TEXT_NODE_TYPE) { - throw new Error("A node / offset pair couldn't be found for the selection."); - } else { - return { node: offsetNode, offset }; - } - } else { - throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); - } - } else { - return { node: null, offset }; - } -} - function compile(editor: Editor, hir: Map, nodes: HIRNode[]): Element[] { return nodes.map((node: HIRNode) => { let children = node.children(); @@ -80,10 +26,11 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '

'; static events = { - 'beforeinput': 'beforeinput', - 'change text-selection': 'updateSelection' + 'change text-selection'(evt) { + this.selection = evt.detail; + } }; text({ text }) { @@ -106,50 +53,6 @@ export default class Editor extends events(HTMLElement) { return document.createElement('br'); } - beforeinput(evt) { - let ranges = evt.getTargetRanges(); - let editor = this.querySelector('.editor'); - - let base = getNodeAndOffset(ranges[0].startContainer, ranges[0].startOffset); - let extent = getNodeAndOffset(ranges[0].endContainer, ranges[0].endOffset); - let start = editor.hir.get(base.node).start + base.offset; - let end = editor.hir.get(extent.node).end + extent.offset; - - switch (evt.inputType) { - case 'insertText': - this.document.insertText(start, evt.data); - break; - case 'insertLineBreak': - this.document.insertText(start, '\u2028', true); - this.document.addAnnotations({ - type: 'line-break', - start: start, - end: end + 1 - }); - break; - case 'formatBold': - this.document.addAnnotations({ - type: 'bold', - start, - end - }); - case 'insertParagraph': - this.document.insertText(start, '\n', true); - this.document.addAnnotations({ - type: 'paragraph', - start: end + 1, - end: end + 1 - }); - break; - case 'deleteContentBackward': - case 'deleteContentForward': - this.document.deleteText({ start, end }); - break; - } - - this.render(this.querySelector('.output')); - } - render(editor) { editor.innerHTML = ''; editor.hir = new Map(); @@ -159,26 +62,4 @@ export default class Editor extends events(HTMLElement) { editor.appendChild(element); }); } - - updateSelection(evt) { - console.log(evt.detail); - this.cursor = evt.detail; - } - - setDocument(value: Document) { - this.document = value; - if (this.isConnected) { - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); - } - } - - connectedCallback() { - this.innerHTML = this.constructor.template; - super.connectedCallback(); - if (this.document) { - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); - } - } } diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts new file mode 100644 index 000000000..24fb0abd6 --- /dev/null +++ b/packages/editor/src/text-input.ts @@ -0,0 +1,93 @@ +import events from './mixins/events'; + +type Constructor = new (...args: any[]) => T; + +const supports = { + beforeinput: InputEvent.prototype.hasOwnProperty('inputType') +}; + +function getRangeFrom() { + +} + +/** + * The keyboard mixin normalizes keyboard input across browsers. + * This is due to varying levels of support by browser vendors + * of different Web APIs. The Input Events API provides a fairly + * robust set of events that we can use to correctly detect input + * from people fluent in CJK languages (Chinese, Japanese, and Korean). + * These languages share a feature that _most_ input methods are + * done through a series of characters. + * + * For example, in Japanese, the following sequence of roman + * characters will result in the following set of text: + * + * | w | wa | wat | wata | watas | watash | watashi | + * | w | わ | わt | わた | わたs | わたsh | 私 | + * + * This results in text that does not map 1:1 to the keys that + * the person typed on their keyboard. + * + * This is the same series of events that we receive from + * autocorrect and predictive text keyboards. + * + * Our approach here is to do the best we can to get the most + * accurate set of events from the user's keyboard. We can only + * promise accuracy to the level of what is provided by the + * fidelity of the web API that's available for use in the browser. + */ +class TextInput extends events(HTMLElement) { + static events = { + 'beforeinput': 'beforeinput', + 'change text-selection'(evt) { + this.selection = evt.detail; + } + 'clear text-selection'() { + this.selection = null; + } + }; + private selection?: { start: number, end: number, collapsed: boolean } | null; + + beforeinput(evt: InputEvent) { + let ranges = evt.getTargetRanges(); + let { start, end } = this.selection; + console.log(this.selection); + debugger; + switch (evt.inputType) { + case 'insertText': + this.dispatchEvent(new CustomEvent('insertText', [start, evt.data])); + break; + case 'insertLineBreak': + this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); + new CustomEvent('addAnnotation', { + type: 'line-break', + start, + end: end + 1 + }); + break; + case 'deleteContentBackward': + if (this.selection.collapsed) { + start--; + } + this.dispatchEvent(new CustomEvent('deleteText', { + start, + end + })); + break; + case 'deleteContentForward': + + if (this.selection.collapsed) { + end++; + } + this.dispatchEvent(new CustomEvent('deleteText', { + start, + end + })); + break; + } + } +}; + +customElements.define('text-input', TextInput); + +export default TextInput; \ No newline at end of file From 3bd81bbb156f9874bbfd1b2a5136f6dbfcfab7b4 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:25:38 +0100 Subject: [PATCH 006/104] Handle composition events. --- packages/editor/src/text-input.ts | 6 ++++++ packages/editor/src/text-selection.ts | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 24fb0abd6..ffab169da 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -39,6 +39,11 @@ function getRangeFrom() { class TextInput extends events(HTMLElement) { static events = { 'beforeinput': 'beforeinput', + 'compositionend'(evt) { + let { start } = this.selection; + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + this.composing = false; + }, 'change text-selection'(evt) { this.selection = evt.detail; } @@ -49,6 +54,7 @@ class TextInput extends events(HTMLElement) { private selection?: { start: number, end: number, collapsed: boolean } | null; beforeinput(evt: InputEvent) { + if (evt.isComposing) return; let ranges = evt.getTargetRanges(); let { start, end } = this.selection; console.log(this.selection); diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index 9fa086436..c61846dc7 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -81,7 +81,13 @@ function previousTextNode(node: Node): TextRangePoint { class TextSelection extends events(HTMLElement) { static observedAttributes = ['start', 'end']; static events = { - 'selectionchange document': 'selectedTextDidChange' + 'selectionchange document': 'selectedTextDidChange', + 'compositionstart'(evt) { + this.composing = true; + }, + 'compositionend'(evt) { + this.composing = false; + } }; private textNodes: Text[]; @@ -193,6 +199,9 @@ class TextSelection extends events(HTMLElement) { } private selectedTextDidChange() { + + if (this.composing) return; + let selectionRange = document.getSelection(); let nodes = this.textNodes; From 468755458e323e91e226568f017ce682a3b08ec7 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:28:39 +0100 Subject: [PATCH 007/104] Assign detail correctly when dispatching custom events --- packages/editor/src/text-input.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index ffab169da..3b98bc332 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -57,37 +57,33 @@ class TextInput extends events(HTMLElement) { if (evt.isComposing) return; let ranges = evt.getTargetRanges(); let { start, end } = this.selection; - console.log(this.selection); - debugger; switch (evt.inputType) { case 'insertText': - this.dispatchEvent(new CustomEvent('insertText', [start, evt.data])); + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); break; + case 'insertLineBreak': this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); new CustomEvent('addAnnotation', { - type: 'line-break', - start, - end: end + 1 + detail: { type: 'line-break', start, end: end + 1 } }); break; + case 'deleteContentBackward': if (this.selection.collapsed) { start--; } this.dispatchEvent(new CustomEvent('deleteText', { - start, - end + detail: { start, end } })); break; - case 'deleteContentForward': + case 'deleteContentForward': if (this.selection.collapsed) { end++; } this.dispatchEvent(new CustomEvent('deleteText', { - start, - end + detail: { start, end } })); break; } From c3db5152d6cf525d458719c5afba90e7cb6c34ae Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:30:57 +0100 Subject: [PATCH 008/104] Handle bold/italic format input events. --- packages/editor/src/text-input.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 3b98bc332..1d81c0949 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -86,10 +86,22 @@ class TextInput extends events(HTMLElement) { detail: { start, end } })); break; + + case 'formatBold': + this.dispatchEvent(new CustomEvent('addAnnotation', { + detail: { start, end, type: 'bold' } + })); + break; + + case 'formatItalic': + this.dispatchEvent(new CustomEvent('addAnnotation', { + detail: { start, end, type: 'italic' } + })); + break; } } }; customElements.define('text-input', TextInput); -export default TextInput; \ No newline at end of file +export default TextInput; From 5206af5bf9c506c301b2a0ca3270a0b3c14b700a Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:32:35 +0100 Subject: [PATCH 009/104] factor out reset-text-nodes for reuse --- packages/editor/src/text-selection.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index c61846dc7..836c6d305 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -103,10 +103,13 @@ class TextSelection extends events(HTMLElement) { // Setup observers so when the underlying text changes, // we update the text nodes that we want to map our selection from - this.observer = new MutationObserver(() => { - this.textNodes = getTextNodes(this); - }); + this.observer = new MutationObserver(() => this.reset()); this.observer.observe(this, { childList: true, characterData: true, subtree: true }); + + this.reset(); + } + + reset() { this.textNodes = getTextNodes(this); } From 9cd9b7bf8784c981158f77519f4e5b3bd9d75637 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:33:49 +0100 Subject: [PATCH 010/104] add setSelection method to enable resetting of the selection when we have lost the original DOM tree / selection --- packages/editor/src/text-selection.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index 836c6d305..ba4df02cc 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -98,6 +98,26 @@ class TextSelection extends events(HTMLElement) { this.textNodes = []; } + setSelection(range) { + let l = this.textNodes.length; + let offset = 0; + + for (let i = 0; i < l; i++) { + let node = this.textNodes[i]; + + if (offset + (node.nodeValue || '').length >= range.start) { + let selection = document.getSelection(); + let r = document.createRange(); + r.setStart(node, range.start - offset); + selection.removeAllRanges(); + selection.addRange(r); + break; + } + + offset += (node.nodeValue || '').length; + } + } + connectedCallback() { super.connectedCallback(); From 245e17e0266632ec7ad7df9ab8d0fec078c1d6c7 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:35:18 +0100 Subject: [PATCH 011/104] handle the insertion / deletion of text and insertion of annotations (deletion/update of annotations TK) --- packages/editor/src/index.ts | 63 ++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 9fb84c66d..760cea473 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -30,9 +30,45 @@ export default class Editor extends events(HTMLElement) { static events = { 'change text-selection'(evt) { this.selection = evt.detail; + }, + + 'insertText text-input'(evt) { + this.document.insertText(evt.detail.position, evt.detail.text); + this.selection.start += evt.detail.text.length; + this.selection.end += evt.detail.text.length; + this.scheduleRender(); + }, + + 'deleteText text-input'(evt) { + let deletion = evt.detail; + this.document.deleteText(deletion); + // FIXME the selection should just be an annotation that we transform. We shouldn't handle logic here. + if (this.selection.start < deletion.start) { + // do nothing. + } else if (this.selection.start < deletion.end) { + this.selection.start = this.selection.end = deletion.start; + } else { + let l = deletion.end - deletion.start; + this.selection.start -= l; + this.selection.end -= l; + } + this.scheduleRender(); + }, + + 'addAnnotation text-input'(evt) { + this.document.addAnnotations(evt.detail); + this.scheduleRender(); } + }; + scheduleRender() { + window.requestAnimationFrame(() => { + this.render(this.querySelector('.editor')); + this.render(this.querySelector('.output')); + }); + } + text({ text }) { return document.createTextNode(text); } @@ -54,12 +90,35 @@ export default class Editor extends events(HTMLElement) { } render(editor) { - editor.innerHTML = ''; editor.hir = new Map(); let annotationGraph = new HIR(this.document); + + let placeholder = document.createElement('div'); let children = compile(this, editor.hir, annotationGraph.rootNode.children()); children.forEach((element: Element) => { - editor.appendChild(element); + placeholder.appendChild(element); }); + + // This can be improved by doing the comparison on an element-by-element + // basis (or by rendering incrementally via the HIR), but for now this will + // prevent flickering of OS UI elements (e.g., spell check) while typing + // characters that don't result in changes outside of text elements. + if (placeholder.innerHTML != editor.innerHTML) { + console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML); + editor.innerHTML = placeholder.innerHTML; + + // We need to do a force-reset here in order to avoid waiting for a full + // cycle of the browser event loop. The DOM has changed, but if we wait + // for the TextSelection MutationObserver to fire, the TextSelection + // model will have an old set of nodes (since we've just replaced them + // with new ones). + // + // PERF In the event of performance issues, this is a good candidate for + // optimization. + if (this.selection) { + this.querySelector('text-selection').reset(); + this.querySelector('text-selection').setSelection(this.selection); + } + } } } From d80e79371cbf06f989fa6cf149e910c8191c283f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:36:36 +0100 Subject: [PATCH 012/104] Add pre-wrap styling to editor to preserve whitespace. --- packages/editor/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 760cea473..7a7a85a8c 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -26,7 +26,7 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '

'; static events = { 'change text-selection'(evt) { this.selection = evt.detail; From 9d1b9ce453069cbb552cdb850ef3d158bf85f4a6 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 17 Apr 2018 19:40:41 +0100 Subject: [PATCH 013/104] Add some debugging and start on WIP for paragraph handling. --- packages/document/src/index.ts | 31 +++++++-- packages/editor/demo.ts | 9 ++- packages/editor/package.json | 2 +- packages/editor/src/index.ts | 107 +++++++++++++++++++++++++++++- packages/editor/src/text-input.ts | 91 ++++++++++++++++++++++++- 5 files changed, 228 insertions(+), 12 deletions(-) diff --git a/packages/document/src/index.ts b/packages/document/src/index.ts index a68e7d66f..8a3ffbbeb 100644 --- a/packages/document/src/index.ts +++ b/packages/document/src/index.ts @@ -89,8 +89,8 @@ export default class AtJSON { const after = this.content.slice(position); this.content = before + text + after; - for (let i = this.annotations.length - 1; i >= 0; i--) { - let a = this.annotations[i]; + for (var i = this.annotations.length - 1; i >= 0; i--) { + var a = this.annotations[i]; // annotation types that implement the Annotation transform interface can // override the default behaviour. This is desirable for e.g., links or @@ -119,10 +119,12 @@ export default class AtJSON { // Default edge behaviour. } else if (!preserveAdjacentBoundaries) { - if (position === a.start) { + if (position === a.start && a.type !== 'paragraph') { a.start += length; a.end += length; - } else if (position === a.end) { + } else if (position === a.start && a.type === 'paragraph') { + a.end += length; + } else if (position === a.end && a.type !== 'paragraph') { a.end += length; } @@ -137,6 +139,27 @@ export default class AtJSON { } else if (position === a.end) { a.end += 0; } + + if (text.indexOf("\n") > -1) { + console.log('new line fun!!'); + for (var i = this.annotations.length - 1; i >= 0; i--) { + var a = this.annotations[i]; + if (a.type === 'paragraph') { + // This doesn't affect us. + if (a.end < position) continue; + if (position < a.start) continue; + + console.log('going to add a new annotation'); + var prevEnd = a.end; + a.end = position + 1; + this.addAnnotations({ + type: 'paragraph', + start: position + 1, + end: prevEnd + 1 + }); + } + } + } } } diff --git a/packages/editor/demo.ts b/packages/editor/demo.ts index 4f87f5640..45c796d21 100644 --- a/packages/editor/demo.ts +++ b/packages/editor/demo.ts @@ -14,10 +14,13 @@ if (module.hot) { } let doc = new Document({ - content: 'Some text that is both bold and italic plus something after.', + content: 'Some text that is both bold and italic plus something after.\nA second paragraph.', annotations: [ - { type: 'bold', start: 23, end: 31 }, - { type: 'italic', start: 28, end: 38 } + { type: 'bold', display: 'inline', start: 23, end: 31 }, + { type: 'italic', display: 'inline', start: 28, end: 38 }, + { type: 'underline', display: 'inline', start: 28, end: 38 }, + { type: 'paragraph', display: 'block', start: 0, end: 61 }, + { type: 'paragraph', display: 'block', start: 61, end: 80 } ] }); diff --git a/packages/editor/package.json b/packages/editor/package.json index 2adaa5a78..ee7f25ec6 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -24,7 +24,7 @@ "@atjson/hir": "^0.7.14" }, "devDependencies": { - "parcel-bundler": "^1.6.2", + "parcel-bundler": "^1.7.0", "ts-loader": "^4.0.0", "tslint": "^5.9.1", "typescript": "^2.6.2" diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 7a7a85a8c..423ddb2d9 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -26,10 +26,13 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '
' + + '
' + + '
'; static events = { 'change text-selection'(evt) { this.selection = evt.detail; + this.scheduleRender(); }, 'insertText text-input'(evt) { @@ -55,6 +58,16 @@ export default class Editor extends events(HTMLElement) { this.scheduleRender(); }, + 'replaceText text-input'(evt) { + let replacement = evt.detail; + + this.document.deleteText(replacement); + this.document.insertText(replacement.start, replacement.text); + this.selection.start = replacement.start + replacement.text.length; + + this.scheduleRender(); + }, + 'addAnnotation text-input'(evt) { this.document.addAnnotations(evt.detail); this.scheduleRender(); @@ -66,10 +79,36 @@ export default class Editor extends events(HTMLElement) { window.requestAnimationFrame(() => { this.render(this.querySelector('.editor')); this.render(this.querySelector('.output')); + this.renderJson(this.querySelector('.json')); }); } text({ text }) { + if (text[text.length - 1] == "\n") { + var nonBreakStrings = text.split("\n"); + console.log('+++--->' + text + '<---+++', '->',nonBreakStrings); + if (nonBreakStrings[nonBreakStrings.length - 1] == '') { + nonBreakStrings.pop(); + } + var children = nonBreakStrings.map((str) => { + var span = document.createElement('span'); + span.style.whiteSpace = 'normal'; + span.style.display = 'none'; + span.contentEditable = false; + span.appendChild(document.createTextNode("\n")); + console.log(span); + return [document.createTextNode(str), span] + }).reduce((a, b) => a.concat(b)); + + console.log(children); + + var textParentNode = document.createElement('span'); + children.forEach((child) => { + textParentNode.appendChild(child); + }) + + return textParentNode; + } return document.createTextNode(text); } @@ -85,6 +124,16 @@ export default class Editor extends events(HTMLElement) { return document.createElement('em'); } + underline() { + return document.createElement('u'); + } + + link(attributes) { + let link = document.createElement('a'); + link.setAttribute('href', attributes.uri); + return link; + } + 'line-break'() { return document.createElement('br'); } @@ -104,7 +153,7 @@ export default class Editor extends events(HTMLElement) { // prevent flickering of OS UI elements (e.g., spell check) while typing // characters that don't result in changes outside of text elements. if (placeholder.innerHTML != editor.innerHTML) { - console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML); + console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML, this.document); editor.innerHTML = placeholder.innerHTML; // We need to do a force-reset here in order to avoid waiting for a full @@ -121,4 +170,58 @@ export default class Editor extends events(HTMLElement) { } } } + + renderJson(container) { + window.requestAnimationFrame(() => { + container.innerHTML = ''; + var counter = document.createElement('pre'); + var top = ''; + var bottom = ''; + for (var x = 0; x < 100; x++) { + if (this.selection.start == x) { + bottom += '' + } + bottom += x % 10; + if (this.selection.end == x) { + bottom += ''; + } + + if (x % 10 == 0) { + top += x / 10; + } else { + top += ' '; + } + } + top += '\n'; + counter.innerHTML = top + bottom; + container.appendChild(counter); + var rawText = document.createElement('pre'); + rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶")); + container.appendChild(rawText); + let table = ''; + this.document.annotations.forEach((a) => { + table += ''; + ['type', 'start', 'end', 'display'].forEach(attr => { + table += ''; + }); + if (a.attributes) { + table += ''; + } else { + table += ''; + } + table += ''; + }); + table += '
typestartenddisplayattributes
' + a[attr] + '' + a.attributes.toJSON() + '
'; + let tableContainer = document.createElement('div'); + tableContainer.innerHTML = table; + container.appendChild(tableContainer); + }); + } + + connectedCallback() { + this.innerHTML = this.constructor.template; + super.connectedCallback(); + this.render(this.querySelector('.editor')); + this.render(this.querySelector('.output')); + } } diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 1d81c0949..14b44c2d4 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -10,6 +10,25 @@ function getRangeFrom() { } +// n.b. this is duplicated from text-selection and should be refactored to be +// included from a shared base. +const TEXT_NODE_TYPE = 3; + +function getTextNodes(node: Node): Text[] { + let nodes: Text[] = []; + + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(getTextNodes(child)); + }); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); + } + + return nodes; +} + + /** * The keyboard mixin normalizes keyboard input across browsers. * This is due to varying levels of support by browser vendors @@ -54,19 +73,28 @@ class TextInput extends events(HTMLElement) { private selection?: { start: number, end: number, collapsed: boolean } | null; beforeinput(evt: InputEvent) { + if (evt.isComposing) return; + let ranges = evt.getTargetRanges(); let { start, end } = this.selection; + + console.log('here is a thing', evt); + switch (evt.inputType) { case 'insertText': this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); break; + case 'insertParagraph': + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: "\n" } })); + break; + case 'insertLineBreak': this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); - new CustomEvent('addAnnotation', { + this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { type: 'line-break', start, end: end + 1 } - }); + })); break; case 'deleteContentBackward': @@ -78,6 +106,20 @@ class TextInput extends events(HTMLElement) { })); break; + case 'deleteWordBackward': + if (this.selection.collapsed) { + end++; + } + + var target = evt.getTargetRanges()[0]; + let deletionStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); + let deletionEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); + + this.dispatchEvent(new CustomEvent('deleteText', { + detail: { start: deletionStart, end: deletionEnd } + })); + break; + case 'deleteContentForward': if (this.selection.collapsed) { end++; @@ -87,6 +129,27 @@ class TextInput extends events(HTMLElement) { })); break; + case 'insertReplacementText': + console.log('in here with evt', evt); + // n.b. this assumes that there is only one target range. + if (evt.getTargetRanges().length !== 1) { + throw new Error('Unhandled scenario. Breaking in an unelegant way. Expected exactly one target range in insertReplacementText handler, got', evt.getTargetRanges().length); + } + + var target = evt.getTargetRanges()[0]; + let replaceStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); + let replaceEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); + + console.log('found', {start: replaceStart, end: replaceEnd}, 'for target', target); + + evt.dataTransfer.items[0].getAsString(replString => { + this.dispatchEvent(new CustomEvent('replaceText', { + detail: { start: replaceStart, end: replaceEnd, text: replString } + })); + }); + + break; + case 'formatBold': this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { start, end, type: 'bold' } @@ -100,6 +163,30 @@ class TextInput extends events(HTMLElement) { break; } } + + // This could be better implemented by tagging each parent node (i.e., + // not-text node) with its start offset, so that we could go from text node + + // offset to document offset directly. Not going to do it now to minimize + // impact across the codebase, but flagging here as a potential and desirable + // separate refactor. + nodeAndOffsetToDocumentOffset(node, offset): number { + let textNodes = getTextNodes(this); + + let l = textNodes.length; + let currOffset = 0; + + for (let i = 0; i < l; i++) { + let currNode = textNodes[i]; + + if (currNode === node) { + return currOffset + offset; + } else { + currOffset += (currNode.nodeValue || '').length + } + } + + throw new Error('Did not find a matching node. Was matching against', node, textNodes); + } }; customElements.define('text-input', TextInput); From 01623d9e6488e87232fc2c8f6d29cb4ac0e330c4 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sat, 3 Mar 2018 00:33:04 +0000 Subject: [PATCH 014/104] fix more edge cases when selecting text --- packages/editor/src/text-selection.ts | 159 ++++++++++++++------------ 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index fb562a945..d1ff90072 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -1,13 +1,33 @@ import events from './mixins/events'; +import { debug } from 'util'; const TEXT_NODE_TYPE = 3; const DOCUMENT_POSITION_PRECEDING = 2; const DOCUMENT_POSITION_FOLLOWING = 4; -function sum(a, b) { +function sum(a: number, b: number) { return a + b; } +interface RangeEdge { + node: Node | null; + offset: number; +} + +function getTextNode(node: Node, trailing?: boolean): Text | null { + while (node.nodeType !== TEXT_NODE_TYPE && node != null) { + if (trailing) { + node = node.childNodes[node.childNodes.length - 1]; + } else { + node = node.childNodes[0]; + } + } + if (node) { + return node as Text; + } + return null; +} + /** Events available for listening for : @@ -17,12 +37,16 @@ function sum(a, b) { class TextSelection extends events(HTMLElement) { static observedAttributes = ['start', 'end']; static events = { - 'selectionchange document': 'selectedTextDidChange', - 'mousedown': 'willSelectText', - 'mouseup': 'didSelectText' + 'selectionchange document': 'selectedTextDidChange' }; - private textNodes: Text[] | null; + private textNodes: Text[]; + private observer?: MutationObserver | null; + + constructor() { + super(); + this.textNodes = []; + } connectedCallback() { super.connectedCallback(); @@ -39,21 +63,23 @@ class TextSelection extends events(HTMLElement) { disconnectedCallback() { super.disconnectedCallback(); - this.observer.disconnect(); - this.observer = null; - this.textNodes = null; + if (this.observer) { + this.observer.disconnect(); + this.observer = null; + } + this.textNodes = []; } - getTextNodes(element?: Element): Text[] { - let nodes = []; - element = element || this; + getTextNodes(node?: Node): Text[] { + let nodes: Text[] = []; + node = node || this; - if (element.hasChildNodes()) { - element.childNodes.forEach((node) => { - nodes = nodes.concat(this.getTextNodes(node)); + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(this.getTextNodes(child)); }); - } else if (element.nodeType === TEXT_NODE_TYPE) { - nodes.push(element); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); } return nodes; @@ -64,7 +90,7 @@ class TextSelection extends events(HTMLElement) { let start = 0; let node = nodes.find(function (node) { - let end = start + node.nodeValue.length; + let end = start + (node.nodeValue || '').length; if (position >= start && position < end) { return true; } @@ -78,25 +104,19 @@ class TextSelection extends events(HTMLElement) { }; } - willSelectText() { - this.isSelecting = true; - } - - didSelectText() { - this.isSelecting = false; - } - - getNodeAndOffset(node: Element | null, offset: number): { node: Element | null, offset: number } | never { + getNodeAndOffset({ node, offset }: RangeEdge): { node: Text | null, offset: number } | never { if (node == null) { return { node: null, offset }; } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node, offset }; + return { node: node as Text, offset }; } else if (node.childNodes.length > 0) { + let textNode; // Firefox can return an offset that is the length // of the node list, which signifies that the node // and offset is the last node at the last character :/ if (offset === node.childNodes.length) { - return { node: node.childNodes[offset - 1], offset: node.childNodes[offset - 1].length }; + textNode = getTextNode(node, true); + return { node: textNode, offset: (textNode ? textNode.length : 0) }; } let offsetNode = node.childNodes[offset]; @@ -109,35 +129,39 @@ class TextSelection extends events(HTMLElement) { // The offset node is a text node; quickly return if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode, offset: 0 }; + return { node: offsetNode as Text, offset: 0 }; + + // If the selected node is wholly outside of the + // component, it's a nil selection + } else if (!this.contains(offsetNode)) { + return { node: null, offset: 0 }; // Find the closest text node and return that } else if (!offsetNode.hasChildNodes()) { let adjustedOffset = offset - 1; // Look for the nearest preceding text node - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset > 0) { - offsetNode = node.childNodes[adjustedOffset--]; - } - - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - offset = offsetNode.length; + do { + textNode = getTextNode(node.childNodes[adjustedOffset--], true); + } while (textNode && this.contains(textNode) && adjustedOffset > 0); // Look for the next text node following the offset + if (textNode) { + offset = textNode.length; } else { adjustedOffset = offset; offset = 0; - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset < node.childNodes.length) { - offsetNode = node.childNodes[adjustedOffset++]; - } + + do { + textNode = getTextNode(node.childNodes[adjustedOffset++]); + } while (textNode && this.contains(textNode) && adjustedOffset < node.childNodes.length); } - if (offsetNode.nodeType !== TEXT_NODE_TYPE) { - throw new Error("A node / offset pair couldn't be found for the selection."); + if (textNode) { + return { node: textNode, offset }; + } else { - return { node: offsetNode, offset }; + throw new Error("A node / offset pair couldn't be found for the selection."); } } else { throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); @@ -147,15 +171,7 @@ class TextSelection extends events(HTMLElement) { } } - clearSelection(): number { - return setTimeout(() => { - this.removeAttribute('start'); - this.removeAttribute('end'); - this.dispatchEvent(new CustomEvent('clear')); - }, 10); - } - - clampRangePoint(edge: { node: Element, offset: number }): { node: Element, offset: number } { + clampRangePoint(edge: { node: Text, offset: number }): { node: Text, offset: number } { let firstNode = this.textNodes[0]; let lastNode = this.textNodes[this.textNodes.length - 1]; @@ -173,25 +189,26 @@ class TextSelection extends events(HTMLElement) { return edge; } - selectedTextDidChange() { - if (this.didSetSelection) { - this.didSetSelection = false; - return true; - } + clearSelection() { + this.removeAttribute('start'); + this.removeAttribute('end'); + this.dispatchEvent(new CustomEvent('clear')); + } + selectedTextDidChange() { let range = document.getSelection(); let nodes = this.textNodes; - let basePrefix = 'base'; - let extentPrefix = 'extent'; - if (range.anchorNode != null) { - basePrefix = 'anchor'; - extentPrefix = 'focus'; + let startOfSelection = { node: range.baseNode, offset: range.baseOffset }; + let endOfSelection = { node: range.extentNode, offset: range.extentOffset }; + if (range.anchorNode) { + startOfSelection = { node: range.anchorNode, offset: range.anchorOffset }; + endOfSelection = { node: range.focusNode, offset: range.focusOffset }; } let [base, extent] = [ - this.getNodeAndOffset(range[`${basePrefix}Node`], range[`${basePrefix}Offset`]), - this.getNodeAndOffset(range[`${extentPrefix}Node`], range[`${extentPrefix}Offset`]) + this.getNodeAndOffset(startOfSelection), + this.getNodeAndOffset(endOfSelection) ].sort((a, b) => { if (!a.node || !b.node) return 0; @@ -211,7 +228,7 @@ class TextSelection extends events(HTMLElement) { // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable if (base.node == null || extent.node == null) { - this._clearTimer = this.clearSelection(); + this.clearSelection(); return true; } @@ -222,7 +239,7 @@ class TextSelection extends events(HTMLElement) { let commonAncestor = domRange.commonAncestorContainer; if (!this.contains(commonAncestor) && !commonAncestor.contains(this)) { - this._clearTimer = this.clearSelection(); + this.clearSelection(); return true; } @@ -232,19 +249,17 @@ class TextSelection extends events(HTMLElement) { extent = this.clampRangePoint(extent); } - let lengths = nodes.map((node) => node.nodeValue.length); + let lengths = nodes.map((node) => (node.nodeValue || '').length); let start = lengths.slice(0, nodes.indexOf(base.node)).reduce(sum, base.offset); let end = lengths.slice(0, nodes.indexOf(extent.node)).reduce(sum, extent.offset); if (start === end && isNonZeroRange) { - this._clearTimer = this.clearSelection(); return true; } - clearTimeout(this._clearTimer); - this.setAttribute('start', start); - this.setAttribute('end', end); - this.dispatchEvent(new CustomEvent('change', { detail: { start, end } })); + this.setAttribute('start', start.toString()); + this.setAttribute('end', end.toString()); + this.dispatchEvent(new CustomEvent('change', { detail: { start, end, collapsed: start === end } })); return true; } } From 2b9cb88a0c28fa0e9407c8e68510d9168580c607 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:12:29 -0500 Subject: [PATCH 015/104] allow closures to be called directly from events --- packages/editor/src/mixins/events.ts | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/editor/src/mixins/events.ts b/packages/editor/src/mixins/events.ts index df7c902af..d10ff8e80 100644 --- a/packages/editor/src/mixins/events.ts +++ b/packages/editor/src/mixins/events.ts @@ -5,7 +5,7 @@ interface EventCallback { } interface EventHandlerDefinitions { - [key: string]: string; + [key: string]: string | EventCallback; } interface EventHandlerReferences { @@ -68,13 +68,19 @@ export default function(Base: HTMLElement) { Object.keys(events).forEach((definition: string) => { let { eventName, element } = getEventNameAndElement(this, definition); let method = events[definition]; - this.eventHandlers[definition] = (evt): EventCallback | never => { - if (this[method]) { - return this[method](evt); - } else { - throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); - } - }; + if (typeof method === 'string') { + this.eventHandlers[definition] = (evt): EventCallback | never => { + if (this[method]) { + return this[method](evt); + } else { + throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); + } + }; + } else { + this.eventHandlers[definition] = (evt): EventCallback => { + return method.call(this, evt); + }; + } element.addEventListener(eventName, this.eventHandlers[definition]); }); } @@ -88,4 +94,3 @@ export default function(Base: HTMLElement) { } } }; - From 499124bf24a77fde190a2ddde370b5a0eab91395 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:13:00 -0500 Subject: [PATCH 016/104] simplify text selection code and make it work with more edge cases Specifically, we have cases where selecting nodes with no children results in an ambiguous offset. Technically, these represent annotation boundaries, but since we don't actually want to disambiguate these, we're instead looking at pure textual offsets. The major change here was simplifying the code that handles selection on nodes with no children (cf,
, ) and nodes that are outside the text selection component. --- packages/editor/src/text-selection.ts | 276 +++++++++++++------------- 1 file changed, 141 insertions(+), 135 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index d1ff90072..9fa086436 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -1,21 +1,20 @@ import events from './mixins/events'; -import { debug } from 'util'; const TEXT_NODE_TYPE = 3; const DOCUMENT_POSITION_PRECEDING = 2; const DOCUMENT_POSITION_FOLLOWING = 4; -function sum(a: number, b: number) { +function sum(a: number, b: number): number { return a + b; } -interface RangeEdge { - node: Node | null; - offset: number; -} +type MaybeNode = Node | null; +type NodeRangePoint = [MaybeNode, number]; +type NodeRange = [NodeRangePoint, NodeRangePoint]; +type TextRangePoint = [Text | null, number]; -function getTextNode(node: Node, trailing?: boolean): Text | null { - while (node.nodeType !== TEXT_NODE_TYPE && node != null) { +function getTextNode(node: MaybeNode, trailing?: boolean): Text | null { + while (node && node.nodeType !== TEXT_NODE_TYPE && node != null) { if (trailing) { node = node.childNodes[node.childNodes.length - 1]; } else { @@ -28,6 +27,51 @@ function getTextNode(node: Node, trailing?: boolean): Text | null { return null; } +function getTextNodes(node: Node): Text[] { + let nodes: Text[] = []; + + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(getTextNodes(child)); + }); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); + } + + return nodes; +} + +function nextTextNode(node: Node): TextRangePoint { + let nextNode: MaybeNode = node; + while (nextNode) { + let textNodes = getTextNodes(nextNode); + if (textNodes.length) { + return [textNodes[0], 0]; + } + nextNode = nextNode.nextSibling; + } + if (node.parentNode) { + return nextTextNode(node.parentNode); + } + return [null, 0]; +} + +function previousTextNode(node: Node): TextRangePoint { + let previousNode: MaybeNode = node; + while (previousNode) { + let textNodes = getTextNodes(previousNode); + if (textNodes.length) { + let textNode = textNodes[textNodes.length - 1]; + return [textNode, textNode.length]; + } + previousNode = previousNode.previousSibling; + } + if (node.parentNode) { + return previousTextNode(node.parentNode); + } + return [null, 0]; +} + /** Events available for listening for : @@ -54,10 +98,10 @@ class TextSelection extends events(HTMLElement) { // Setup observers so when the underlying text changes, // we update the text nodes that we want to map our selection from this.observer = new MutationObserver(() => { - this.textNodes = this.getTextNodes(); + this.textNodes = getTextNodes(this); }); this.observer.observe(this, { childList: true, characterData: true, subtree: true }); - this.textNodes = this.getTextNodes(); + this.textNodes = getTextNodes(this); } disconnectedCallback() { @@ -70,171 +114,125 @@ class TextSelection extends events(HTMLElement) { this.textNodes = []; } - getTextNodes(node?: Node): Text[] { - let nodes: Text[] = []; - node = node || this; + private getNodeAndOffset([node, offset]: NodeRangePoint, leading: boolean): TextRangePoint | never { + // No node to get an offset for; bail + if (node == null) { + return [null, offset]; - if (node.hasChildNodes()) { - node.childNodes.forEach((child: Node) => { - nodes = nodes.concat(this.getTextNodes(child)); - }); + // The offset is a text offset } else if (node.nodeType === TEXT_NODE_TYPE) { - nodes.push(node as Text); - } - - return nodes; - } - - nodeAndOffsetForPosition(position: number) { - let nodes = this.textNodes; - let start = 0; - - let node = nodes.find(function (node) { - let end = start + (node.nodeValue || '').length; - if (position >= start && position < end) { - return true; - } - start = end; - return false; - }); - - return { - node, - offset: position - start - }; - } + return [node as Text, offset]; + + // If the node is outside the + } else if (!this.contains(node) && this !== node) { + switch (this.compareDocumentPosition(node)) { + case DOCUMENT_POSITION_PRECEDING: + return previousTextNode(node); + case DOCUMENT_POSITION_FOLLOWING: + return nextTextNode(node); + default: + return [null, 0]; + } - getNodeAndOffset({ node, offset }: RangeEdge): { node: Text | null, offset: number } | never { - if (node == null) { - return { node: null, offset }; - } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node: node as Text, offset }; - } else if (node.childNodes.length > 0) { - let textNode; - // Firefox can return an offset that is the length - // of the node list, which signifies that the node - // and offset is the last node at the last character :/ - if (offset === node.childNodes.length) { - textNode = getTextNode(node, true); - return { node: textNode, offset: (textNode ? textNode.length : 0) }; - } + // If the node isn't a text node, the offset refers to a + // node offset. We will disambiguate this to a text offset + } else if (node.childNodes.length > offset) { let offsetNode = node.childNodes[offset]; + let textNodes = getTextNodes(offsetNode); // If the offset node has a single child node, // use that node instead of the parent - if (offsetNode.nodeType !== TEXT_NODE_TYPE && - offsetNode.childNodes.length === 1) { - offsetNode = offsetNode.childNodes[0]; + if (textNodes.length === 1) { + return [textNodes[0], 0]; } - - // The offset node is a text node; quickly return - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode as Text, offset: 0 }; - - // If the selected node is wholly outside of the - // component, it's a nil selection - } else if (!this.contains(offsetNode)) { - return { node: null, offset: 0 }; - + // Find the closest text node and return that - } else if (!offsetNode.hasChildNodes()) { - let adjustedOffset = offset - 1; - - // Look for the nearest preceding text node - do { - textNode = getTextNode(node.childNodes[adjustedOffset--], true); - } while (textNode && this.contains(textNode) && adjustedOffset > 0); - - // Look for the next text node following the offset - if (textNode) { - offset = textNode.length; - } else { - adjustedOffset = offset; - offset = 0; - - do { - textNode = getTextNode(node.childNodes[adjustedOffset++]); - } while (textNode && this.contains(textNode) && adjustedOffset < node.childNodes.length); + if (textNodes.length === 0) { + if (leading) { + return previousTextNode(node); } + return nextTextNode(node); + } - if (textNode) { - return { node: textNode, offset }; + throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); + + // Firefox can return an offset that is the length + // of the node list, which signifies that the node + // and offset is the last node at the last character :/ + } else if (node.childNodes.length === offset) { + let textNodes = getTextNodes(node); + let textNode = textNodes[textNodes.length - 1]; + return [textNode, textNode ? textNode.length : 0]; - } else { - throw new Error("A node / offset pair couldn't be found for the selection."); - } - } else { - throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); - } } else { - return { node: null, offset }; + return [null, offset]; } } - clampRangePoint(edge: { node: Text, offset: number }): { node: Text, offset: number } { + private clampRangePoint([text, offset]: TextRangePoint): TextRangePoint { + if (text == null) { + return [text, offset]; + } let firstNode = this.textNodes[0]; let lastNode = this.textNodes[this.textNodes.length - 1]; - if (firstNode.compareDocumentPosition(edge.node) == DOCUMENT_POSITION_PRECEDING) { - return { - node: firstNode, - offset: 0 - }; - } else if (lastNode.compareDocumentPosition(edge.node) == DOCUMENT_POSITION_FOLLOWING) { - return { - node: lastNode, - offset: lastNode.length - }; + if (firstNode.compareDocumentPosition(text) == DOCUMENT_POSITION_PRECEDING) { + return [firstNode, 0]; + + } else if (lastNode.compareDocumentPosition(text) == DOCUMENT_POSITION_FOLLOWING) { + return [lastNode, lastNode.length]; + } - return edge; + return [text, offset]; } - clearSelection() { + private clearSelection() { this.removeAttribute('start'); this.removeAttribute('end'); this.dispatchEvent(new CustomEvent('clear')); } - selectedTextDidChange() { - let range = document.getSelection(); + private selectedTextDidChange() { + let selectionRange = document.getSelection(); let nodes = this.textNodes; - let startOfSelection = { node: range.baseNode, offset: range.baseOffset }; - let endOfSelection = { node: range.extentNode, offset: range.extentOffset }; - if (range.anchorNode) { - startOfSelection = { node: range.anchorNode, offset: range.anchorOffset }; - endOfSelection = { node: range.focusNode, offset: range.focusOffset }; + let nodeRange: NodeRange = [[selectionRange.baseNode, selectionRange.baseOffset], + [selectionRange.extentNode, selectionRange.extentOffset]]; + if (selectionRange.anchorNode) { + nodeRange = [[selectionRange.anchorNode, selectionRange.anchorOffset], + [selectionRange.focusNode, selectionRange.focusOffset]]; } - - let [base, extent] = [ - this.getNodeAndOffset(startOfSelection), - this.getNodeAndOffset(endOfSelection) - ].sort((a, b) => { - if (!a.node || !b.node) return 0; + nodeRange = nodeRange.sort(([aNode, aOffset], [bNode, bOffset]) => { + if (!aNode || !bNode) return 0; // Sort by node position then offset - switch (a.node.compareDocumentPosition(b.node)) { + switch (aNode.compareDocumentPosition(bNode)) { case DOCUMENT_POSITION_PRECEDING: return 1; case DOCUMENT_POSITION_FOLLOWING: return -1; default: - return a.offset - b.offset; + return aOffset - bOffset; } }); - let isNonZeroRange = base.node !== extent.node || base.offset !== extent.offset; + let [start, end] = [ + this.getNodeAndOffset(nodeRange[0], true), + this.getNodeAndOffset(nodeRange[1], false) + ]; + + let isNonZeroRange = start[0] !== end[0] || start[1] !== end[1]; // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable - if (base.node == null || extent.node == null) { + if (start[0] == null || end[0] == null) { this.clearSelection(); return true; } let domRange = document.createRange(); - domRange.setStart(base.node, base.offset); - domRange.setEnd(extent.node, extent.offset); + domRange.setStart(start[0], start[1]); + domRange.setEnd(end[0], end[1]); let commonAncestor = domRange.commonAncestorContainer; @@ -245,21 +243,29 @@ class TextSelection extends events(HTMLElement) { // Fix the base and offset nodes if (!this.contains(commonAncestor) && this !== commonAncestor) { - base = this.clampRangePoint(base); - extent = this.clampRangePoint(extent); + start = this.clampRangePoint(start); + end = this.clampRangePoint(end); } let lengths = nodes.map((node) => (node.nodeValue || '').length); - let start = lengths.slice(0, nodes.indexOf(base.node)).reduce(sum, base.offset); - let end = lengths.slice(0, nodes.indexOf(extent.node)).reduce(sum, extent.offset); + let range = [ + lengths.slice(0, nodes.indexOf(start[0])).reduce(sum, start[1]), + lengths.slice(0, nodes.indexOf(end[0])).reduce(sum, end[1]) + ]; - if (start === end && isNonZeroRange) { + if (range[0] === range[1] && isNonZeroRange) { return true; } - this.setAttribute('start', start.toString()); - this.setAttribute('end', end.toString()); - this.dispatchEvent(new CustomEvent('change', { detail: { start, end, collapsed: start === end } })); + this.setAttribute('start', range[0].toString()); + this.setAttribute('end', range[1].toString()); + this.dispatchEvent(new CustomEvent('change', { + detail: { + start: range[0], + end: range[1], + collapsed: range[0] === range[1] + } + })); return true; } } From 7d38eaa0a4fde74262db67f84e38da8627d9ec96 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:15:31 -0500 Subject: [PATCH 017/104] add a more complicated document to test text selection better --- packages/editor/demo.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/editor/demo.ts diff --git a/packages/editor/demo.ts b/packages/editor/demo.ts new file mode 100644 index 000000000..4f87f5640 --- /dev/null +++ b/packages/editor/demo.ts @@ -0,0 +1,26 @@ +import Document from '@atjson/document'; +import Editor from './src/index'; + +if (!window.customElements.get('text-editor')) { + window.customElements.define('text-editor', Editor); +} + +// Web components in the registry can't be redefined, +// so reload the page on every change +if (module.hot) { + module.hot.dispose(function () { + window.location.reload(); + }); +} + +let doc = new Document({ + content: 'Some text that is both bold and italic plus something after.', + annotations: [ + { type: 'bold', start: 23, end: 31 }, + { type: 'italic', start: 28, end: 38 } + ] +}); + +let editor = document.createElement('text-editor'); +editor.document = doc; +document.body.appendChild(editor); From fc64db42cc9918bdc3a6c8ceaabd44b00947fb5d Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 4 Mar 2018 13:15:49 -0500 Subject: [PATCH 018/104] move text input management into its own component --- packages/editor/src/index.ts | 129 ++---------------------------- packages/editor/src/text-input.ts | 93 +++++++++++++++++++++ 2 files changed, 98 insertions(+), 124 deletions(-) create mode 100644 packages/editor/src/text-input.ts diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 8a762655a..9fb84c66d 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -2,66 +2,12 @@ import { HIR } from '@atjson/hir'; import Document from '@atjson/document'; import events from './mixins/events'; import './text-selection'; +import './text-input'; const TEXT_NODE_TYPE = 3; type Element = TextNode | HTMLElement; -function getNodeAndOffset(node: Element | null, offset: number): { node: Element | null, offset: number } | never { - if (node == null) { - return { node: null, offset }; - } else if (node.nodeType === TEXT_NODE_TYPE) { - return { node, offset }; - } else if (node.childNodes.length > 0) { - let offsetNode = node.childNodes[offset]; - - // If the offset node has a single child node, - // use that node instead of the parent - if (offsetNode.nodeType !== TEXT_NODE_TYPE && - offsetNode.childNodes.length === 1) { - offsetNode = offsetNode.childNodes[0]; - } - - // The offset node is a text node; quickly return - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - return { node: offsetNode, offset: 0 }; - - // Find the closest text node and return that - } else if (!offsetNode.hasChildNodes()) { - let adjustedOffset = offset - 1; - - // Look for the nearest preceding text node - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset > 0) { - offsetNode = node.childNodes[adjustedOffset--]; - } - - if (offsetNode.nodeType === TEXT_NODE_TYPE) { - offset = offsetNode.length; - - // Look for the next text node following the offset - } else { - adjustedOffset = offset; - offset = 0; - while (offsetNode.nodeType !== TEXT_NODE_TYPE && - adjustedOffset < node.childNodes.length) { - offsetNode = node.childNodes[adjustedOffset++]; - } - } - - if (offsetNode.nodeType !== TEXT_NODE_TYPE) { - throw new Error("A node / offset pair couldn't be found for the selection."); - } else { - return { node: offsetNode, offset }; - } - } else { - throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); - } - } else { - return { node: null, offset }; - } -} - function compile(editor: Editor, hir: Map, nodes: HIRNode[]): Element[] { return nodes.map((node: HIRNode) => { let children = node.children(); @@ -80,10 +26,11 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '

'; static events = { - 'beforeinput': 'beforeinput', - 'change text-selection': 'updateSelection' + 'change text-selection'(evt) { + this.selection = evt.detail; + } }; text({ text }) { @@ -106,50 +53,6 @@ export default class Editor extends events(HTMLElement) { return document.createElement('br'); } - beforeinput(evt) { - let ranges = evt.getTargetRanges(); - let editor = this.querySelector('.editor'); - - let base = getNodeAndOffset(ranges[0].startContainer, ranges[0].startOffset); - let extent = getNodeAndOffset(ranges[0].endContainer, ranges[0].endOffset); - let start = editor.hir.get(base.node).start + base.offset; - let end = editor.hir.get(extent.node).end + extent.offset; - - switch (evt.inputType) { - case 'insertText': - this.document.insertText(start, evt.data); - break; - case 'insertLineBreak': - this.document.insertText(start, '\u2028', true); - this.document.addAnnotations({ - type: 'line-break', - start: start, - end: end + 1 - }); - break; - case 'formatBold': - this.document.addAnnotations({ - type: 'bold', - start, - end - }); - case 'insertParagraph': - this.document.insertText(start, '\n', true); - this.document.addAnnotations({ - type: 'paragraph', - start: end + 1, - end: end + 1 - }); - break; - case 'deleteContentBackward': - case 'deleteContentForward': - this.document.deleteText({ start, end }); - break; - } - - this.render(this.querySelector('.output')); - } - render(editor) { editor.innerHTML = ''; editor.hir = new Map(); @@ -159,26 +62,4 @@ export default class Editor extends events(HTMLElement) { editor.appendChild(element); }); } - - updateSelection(evt) { - console.log(evt.detail); - this.cursor = evt.detail; - } - - setDocument(value: Document) { - this.document = value; - if (this.isConnected) { - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); - } - } - - connectedCallback() { - this.innerHTML = this.constructor.template; - super.connectedCallback(); - if (this.document) { - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); - } - } } diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts new file mode 100644 index 000000000..24fb0abd6 --- /dev/null +++ b/packages/editor/src/text-input.ts @@ -0,0 +1,93 @@ +import events from './mixins/events'; + +type Constructor = new (...args: any[]) => T; + +const supports = { + beforeinput: InputEvent.prototype.hasOwnProperty('inputType') +}; + +function getRangeFrom() { + +} + +/** + * The keyboard mixin normalizes keyboard input across browsers. + * This is due to varying levels of support by browser vendors + * of different Web APIs. The Input Events API provides a fairly + * robust set of events that we can use to correctly detect input + * from people fluent in CJK languages (Chinese, Japanese, and Korean). + * These languages share a feature that _most_ input methods are + * done through a series of characters. + * + * For example, in Japanese, the following sequence of roman + * characters will result in the following set of text: + * + * | w | wa | wat | wata | watas | watash | watashi | + * | w | わ | わt | わた | わたs | わたsh | 私 | + * + * This results in text that does not map 1:1 to the keys that + * the person typed on their keyboard. + * + * This is the same series of events that we receive from + * autocorrect and predictive text keyboards. + * + * Our approach here is to do the best we can to get the most + * accurate set of events from the user's keyboard. We can only + * promise accuracy to the level of what is provided by the + * fidelity of the web API that's available for use in the browser. + */ +class TextInput extends events(HTMLElement) { + static events = { + 'beforeinput': 'beforeinput', + 'change text-selection'(evt) { + this.selection = evt.detail; + } + 'clear text-selection'() { + this.selection = null; + } + }; + private selection?: { start: number, end: number, collapsed: boolean } | null; + + beforeinput(evt: InputEvent) { + let ranges = evt.getTargetRanges(); + let { start, end } = this.selection; + console.log(this.selection); + debugger; + switch (evt.inputType) { + case 'insertText': + this.dispatchEvent(new CustomEvent('insertText', [start, evt.data])); + break; + case 'insertLineBreak': + this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); + new CustomEvent('addAnnotation', { + type: 'line-break', + start, + end: end + 1 + }); + break; + case 'deleteContentBackward': + if (this.selection.collapsed) { + start--; + } + this.dispatchEvent(new CustomEvent('deleteText', { + start, + end + })); + break; + case 'deleteContentForward': + + if (this.selection.collapsed) { + end++; + } + this.dispatchEvent(new CustomEvent('deleteText', { + start, + end + })); + break; + } + } +}; + +customElements.define('text-input', TextInput); + +export default TextInput; \ No newline at end of file From ded75d0198615a3536920431bcae4e1e6491a9f3 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:25:38 +0100 Subject: [PATCH 019/104] Handle composition events. --- packages/editor/src/text-input.ts | 6 ++++++ packages/editor/src/text-selection.ts | 11 ++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 24fb0abd6..ffab169da 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -39,6 +39,11 @@ function getRangeFrom() { class TextInput extends events(HTMLElement) { static events = { 'beforeinput': 'beforeinput', + 'compositionend'(evt) { + let { start } = this.selection; + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + this.composing = false; + }, 'change text-selection'(evt) { this.selection = evt.detail; } @@ -49,6 +54,7 @@ class TextInput extends events(HTMLElement) { private selection?: { start: number, end: number, collapsed: boolean } | null; beforeinput(evt: InputEvent) { + if (evt.isComposing) return; let ranges = evt.getTargetRanges(); let { start, end } = this.selection; console.log(this.selection); diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index 9fa086436..c61846dc7 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -81,7 +81,13 @@ function previousTextNode(node: Node): TextRangePoint { class TextSelection extends events(HTMLElement) { static observedAttributes = ['start', 'end']; static events = { - 'selectionchange document': 'selectedTextDidChange' + 'selectionchange document': 'selectedTextDidChange', + 'compositionstart'(evt) { + this.composing = true; + }, + 'compositionend'(evt) { + this.composing = false; + } }; private textNodes: Text[]; @@ -193,6 +199,9 @@ class TextSelection extends events(HTMLElement) { } private selectedTextDidChange() { + + if (this.composing) return; + let selectionRange = document.getSelection(); let nodes = this.textNodes; From 0257ad10656ebd0bd319c189e41ab2a84a507e04 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:28:39 +0100 Subject: [PATCH 020/104] Assign detail correctly when dispatching custom events --- packages/editor/src/text-input.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index ffab169da..3b98bc332 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -57,37 +57,33 @@ class TextInput extends events(HTMLElement) { if (evt.isComposing) return; let ranges = evt.getTargetRanges(); let { start, end } = this.selection; - console.log(this.selection); - debugger; switch (evt.inputType) { case 'insertText': - this.dispatchEvent(new CustomEvent('insertText', [start, evt.data])); + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); break; + case 'insertLineBreak': this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); new CustomEvent('addAnnotation', { - type: 'line-break', - start, - end: end + 1 + detail: { type: 'line-break', start, end: end + 1 } }); break; + case 'deleteContentBackward': if (this.selection.collapsed) { start--; } this.dispatchEvent(new CustomEvent('deleteText', { - start, - end + detail: { start, end } })); break; - case 'deleteContentForward': + case 'deleteContentForward': if (this.selection.collapsed) { end++; } this.dispatchEvent(new CustomEvent('deleteText', { - start, - end + detail: { start, end } })); break; } From 8f371288c40206ad113345ef3f4be0da0adff207 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:30:57 +0100 Subject: [PATCH 021/104] Handle bold/italic format input events. --- packages/editor/src/text-input.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 3b98bc332..1d81c0949 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -86,10 +86,22 @@ class TextInput extends events(HTMLElement) { detail: { start, end } })); break; + + case 'formatBold': + this.dispatchEvent(new CustomEvent('addAnnotation', { + detail: { start, end, type: 'bold' } + })); + break; + + case 'formatItalic': + this.dispatchEvent(new CustomEvent('addAnnotation', { + detail: { start, end, type: 'italic' } + })); + break; } } }; customElements.define('text-input', TextInput); -export default TextInput; \ No newline at end of file +export default TextInput; From ff60b6997b6a5d3ed4c1574c38fbdec1f5a5b0b8 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:32:35 +0100 Subject: [PATCH 022/104] factor out reset-text-nodes for reuse --- packages/editor/src/text-selection.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index c61846dc7..836c6d305 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -103,10 +103,13 @@ class TextSelection extends events(HTMLElement) { // Setup observers so when the underlying text changes, // we update the text nodes that we want to map our selection from - this.observer = new MutationObserver(() => { - this.textNodes = getTextNodes(this); - }); + this.observer = new MutationObserver(() => this.reset()); this.observer.observe(this, { childList: true, characterData: true, subtree: true }); + + this.reset(); + } + + reset() { this.textNodes = getTextNodes(this); } From b19e1123c4f071949779ad80fa5c9df9889f6f0f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:33:49 +0100 Subject: [PATCH 023/104] add setSelection method to enable resetting of the selection when we have lost the original DOM tree / selection --- packages/editor/src/text-selection.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/editor/src/text-selection.ts b/packages/editor/src/text-selection.ts index 836c6d305..ba4df02cc 100644 --- a/packages/editor/src/text-selection.ts +++ b/packages/editor/src/text-selection.ts @@ -98,6 +98,26 @@ class TextSelection extends events(HTMLElement) { this.textNodes = []; } + setSelection(range) { + let l = this.textNodes.length; + let offset = 0; + + for (let i = 0; i < l; i++) { + let node = this.textNodes[i]; + + if (offset + (node.nodeValue || '').length >= range.start) { + let selection = document.getSelection(); + let r = document.createRange(); + r.setStart(node, range.start - offset); + selection.removeAllRanges(); + selection.addRange(r); + break; + } + + offset += (node.nodeValue || '').length; + } + } + connectedCallback() { super.connectedCallback(); From 098129c8c350b6545b34f76ad78b1271dac33603 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:35:18 +0100 Subject: [PATCH 024/104] handle the insertion / deletion of text and insertion of annotations (deletion/update of annotations TK) --- packages/editor/src/index.ts | 63 ++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 9fb84c66d..760cea473 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -30,9 +30,45 @@ export default class Editor extends events(HTMLElement) { static events = { 'change text-selection'(evt) { this.selection = evt.detail; + }, + + 'insertText text-input'(evt) { + this.document.insertText(evt.detail.position, evt.detail.text); + this.selection.start += evt.detail.text.length; + this.selection.end += evt.detail.text.length; + this.scheduleRender(); + }, + + 'deleteText text-input'(evt) { + let deletion = evt.detail; + this.document.deleteText(deletion); + // FIXME the selection should just be an annotation that we transform. We shouldn't handle logic here. + if (this.selection.start < deletion.start) { + // do nothing. + } else if (this.selection.start < deletion.end) { + this.selection.start = this.selection.end = deletion.start; + } else { + let l = deletion.end - deletion.start; + this.selection.start -= l; + this.selection.end -= l; + } + this.scheduleRender(); + }, + + 'addAnnotation text-input'(evt) { + this.document.addAnnotations(evt.detail); + this.scheduleRender(); } + }; + scheduleRender() { + window.requestAnimationFrame(() => { + this.render(this.querySelector('.editor')); + this.render(this.querySelector('.output')); + }); + } + text({ text }) { return document.createTextNode(text); } @@ -54,12 +90,35 @@ export default class Editor extends events(HTMLElement) { } render(editor) { - editor.innerHTML = ''; editor.hir = new Map(); let annotationGraph = new HIR(this.document); + + let placeholder = document.createElement('div'); let children = compile(this, editor.hir, annotationGraph.rootNode.children()); children.forEach((element: Element) => { - editor.appendChild(element); + placeholder.appendChild(element); }); + + // This can be improved by doing the comparison on an element-by-element + // basis (or by rendering incrementally via the HIR), but for now this will + // prevent flickering of OS UI elements (e.g., spell check) while typing + // characters that don't result in changes outside of text elements. + if (placeholder.innerHTML != editor.innerHTML) { + console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML); + editor.innerHTML = placeholder.innerHTML; + + // We need to do a force-reset here in order to avoid waiting for a full + // cycle of the browser event loop. The DOM has changed, but if we wait + // for the TextSelection MutationObserver to fire, the TextSelection + // model will have an old set of nodes (since we've just replaced them + // with new ones). + // + // PERF In the event of performance issues, this is a good candidate for + // optimization. + if (this.selection) { + this.querySelector('text-selection').reset(); + this.querySelector('text-selection').setSelection(this.selection); + } + } } } From 9730aafd2238b0bdc2255ce109ce4b38dff60acc Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 4 Apr 2018 15:36:36 +0100 Subject: [PATCH 025/104] Add pre-wrap styling to editor to preserve whitespace. --- packages/editor/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 760cea473..7a7a85a8c 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -26,7 +26,7 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '

'; static events = { 'change text-selection'(evt) { this.selection = evt.detail; From 1c2c6911d719691e48a269e12e61d3fc24b03b97 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 17 Apr 2018 19:40:41 +0100 Subject: [PATCH 026/104] Add some debugging and start on WIP for paragraph handling. --- packages/document/src/index.ts | 31 +++++++-- packages/editor/demo.ts | 9 ++- packages/editor/package.json | 2 +- packages/editor/src/index.ts | 107 +++++++++++++++++++++++++++++- packages/editor/src/text-input.ts | 91 ++++++++++++++++++++++++- 5 files changed, 228 insertions(+), 12 deletions(-) diff --git a/packages/document/src/index.ts b/packages/document/src/index.ts index a68e7d66f..8a3ffbbeb 100644 --- a/packages/document/src/index.ts +++ b/packages/document/src/index.ts @@ -89,8 +89,8 @@ export default class AtJSON { const after = this.content.slice(position); this.content = before + text + after; - for (let i = this.annotations.length - 1; i >= 0; i--) { - let a = this.annotations[i]; + for (var i = this.annotations.length - 1; i >= 0; i--) { + var a = this.annotations[i]; // annotation types that implement the Annotation transform interface can // override the default behaviour. This is desirable for e.g., links or @@ -119,10 +119,12 @@ export default class AtJSON { // Default edge behaviour. } else if (!preserveAdjacentBoundaries) { - if (position === a.start) { + if (position === a.start && a.type !== 'paragraph') { a.start += length; a.end += length; - } else if (position === a.end) { + } else if (position === a.start && a.type === 'paragraph') { + a.end += length; + } else if (position === a.end && a.type !== 'paragraph') { a.end += length; } @@ -137,6 +139,27 @@ export default class AtJSON { } else if (position === a.end) { a.end += 0; } + + if (text.indexOf("\n") > -1) { + console.log('new line fun!!'); + for (var i = this.annotations.length - 1; i >= 0; i--) { + var a = this.annotations[i]; + if (a.type === 'paragraph') { + // This doesn't affect us. + if (a.end < position) continue; + if (position < a.start) continue; + + console.log('going to add a new annotation'); + var prevEnd = a.end; + a.end = position + 1; + this.addAnnotations({ + type: 'paragraph', + start: position + 1, + end: prevEnd + 1 + }); + } + } + } } } diff --git a/packages/editor/demo.ts b/packages/editor/demo.ts index 4f87f5640..45c796d21 100644 --- a/packages/editor/demo.ts +++ b/packages/editor/demo.ts @@ -14,10 +14,13 @@ if (module.hot) { } let doc = new Document({ - content: 'Some text that is both bold and italic plus something after.', + content: 'Some text that is both bold and italic plus something after.\nA second paragraph.', annotations: [ - { type: 'bold', start: 23, end: 31 }, - { type: 'italic', start: 28, end: 38 } + { type: 'bold', display: 'inline', start: 23, end: 31 }, + { type: 'italic', display: 'inline', start: 28, end: 38 }, + { type: 'underline', display: 'inline', start: 28, end: 38 }, + { type: 'paragraph', display: 'block', start: 0, end: 61 }, + { type: 'paragraph', display: 'block', start: 61, end: 80 } ] }); diff --git a/packages/editor/package.json b/packages/editor/package.json index addb7d4fe..1bd87244a 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -23,7 +23,7 @@ "@atjson/hir": "^0.7.15" }, "devDependencies": { - "parcel-bundler": "^1.6.2", + "parcel-bundler": "^1.7.0", "ts-loader": "^4.0.0", "tslint": "^5.9.1", "typescript": "^2.6.2" diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 7a7a85a8c..423ddb2d9 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -26,10 +26,13 @@ function compile(editor: Editor, hir: Map, nodes: HIRNode[]): } export default class Editor extends events(HTMLElement) { - static template = '

'; + static template = '
' + + '
' + + '
'; static events = { 'change text-selection'(evt) { this.selection = evt.detail; + this.scheduleRender(); }, 'insertText text-input'(evt) { @@ -55,6 +58,16 @@ export default class Editor extends events(HTMLElement) { this.scheduleRender(); }, + 'replaceText text-input'(evt) { + let replacement = evt.detail; + + this.document.deleteText(replacement); + this.document.insertText(replacement.start, replacement.text); + this.selection.start = replacement.start + replacement.text.length; + + this.scheduleRender(); + }, + 'addAnnotation text-input'(evt) { this.document.addAnnotations(evt.detail); this.scheduleRender(); @@ -66,10 +79,36 @@ export default class Editor extends events(HTMLElement) { window.requestAnimationFrame(() => { this.render(this.querySelector('.editor')); this.render(this.querySelector('.output')); + this.renderJson(this.querySelector('.json')); }); } text({ text }) { + if (text[text.length - 1] == "\n") { + var nonBreakStrings = text.split("\n"); + console.log('+++--->' + text + '<---+++', '->',nonBreakStrings); + if (nonBreakStrings[nonBreakStrings.length - 1] == '') { + nonBreakStrings.pop(); + } + var children = nonBreakStrings.map((str) => { + var span = document.createElement('span'); + span.style.whiteSpace = 'normal'; + span.style.display = 'none'; + span.contentEditable = false; + span.appendChild(document.createTextNode("\n")); + console.log(span); + return [document.createTextNode(str), span] + }).reduce((a, b) => a.concat(b)); + + console.log(children); + + var textParentNode = document.createElement('span'); + children.forEach((child) => { + textParentNode.appendChild(child); + }) + + return textParentNode; + } return document.createTextNode(text); } @@ -85,6 +124,16 @@ export default class Editor extends events(HTMLElement) { return document.createElement('em'); } + underline() { + return document.createElement('u'); + } + + link(attributes) { + let link = document.createElement('a'); + link.setAttribute('href', attributes.uri); + return link; + } + 'line-break'() { return document.createElement('br'); } @@ -104,7 +153,7 @@ export default class Editor extends events(HTMLElement) { // prevent flickering of OS UI elements (e.g., spell check) while typing // characters that don't result in changes outside of text elements. if (placeholder.innerHTML != editor.innerHTML) { - console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML); + console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML, this.document); editor.innerHTML = placeholder.innerHTML; // We need to do a force-reset here in order to avoid waiting for a full @@ -121,4 +170,58 @@ export default class Editor extends events(HTMLElement) { } } } + + renderJson(container) { + window.requestAnimationFrame(() => { + container.innerHTML = ''; + var counter = document.createElement('pre'); + var top = ''; + var bottom = ''; + for (var x = 0; x < 100; x++) { + if (this.selection.start == x) { + bottom += '' + } + bottom += x % 10; + if (this.selection.end == x) { + bottom += ''; + } + + if (x % 10 == 0) { + top += x / 10; + } else { + top += ' '; + } + } + top += '\n'; + counter.innerHTML = top + bottom; + container.appendChild(counter); + var rawText = document.createElement('pre'); + rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶")); + container.appendChild(rawText); + let table = ''; + this.document.annotations.forEach((a) => { + table += ''; + ['type', 'start', 'end', 'display'].forEach(attr => { + table += ''; + }); + if (a.attributes) { + table += ''; + } else { + table += ''; + } + table += ''; + }); + table += '
typestartenddisplayattributes
' + a[attr] + '' + a.attributes.toJSON() + '
'; + let tableContainer = document.createElement('div'); + tableContainer.innerHTML = table; + container.appendChild(tableContainer); + }); + } + + connectedCallback() { + this.innerHTML = this.constructor.template; + super.connectedCallback(); + this.render(this.querySelector('.editor')); + this.render(this.querySelector('.output')); + } } diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 1d81c0949..14b44c2d4 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -10,6 +10,25 @@ function getRangeFrom() { } +// n.b. this is duplicated from text-selection and should be refactored to be +// included from a shared base. +const TEXT_NODE_TYPE = 3; + +function getTextNodes(node: Node): Text[] { + let nodes: Text[] = []; + + if (node.hasChildNodes()) { + node.childNodes.forEach((child: Node) => { + nodes = nodes.concat(getTextNodes(child)); + }); + } else if (node.nodeType === TEXT_NODE_TYPE) { + nodes.push(node as Text); + } + + return nodes; +} + + /** * The keyboard mixin normalizes keyboard input across browsers. * This is due to varying levels of support by browser vendors @@ -54,19 +73,28 @@ class TextInput extends events(HTMLElement) { private selection?: { start: number, end: number, collapsed: boolean } | null; beforeinput(evt: InputEvent) { + if (evt.isComposing) return; + let ranges = evt.getTargetRanges(); let { start, end } = this.selection; + + console.log('here is a thing', evt); + switch (evt.inputType) { case 'insertText': this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); break; + case 'insertParagraph': + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: "\n" } })); + break; + case 'insertLineBreak': this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); - new CustomEvent('addAnnotation', { + this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { type: 'line-break', start, end: end + 1 } - }); + })); break; case 'deleteContentBackward': @@ -78,6 +106,20 @@ class TextInput extends events(HTMLElement) { })); break; + case 'deleteWordBackward': + if (this.selection.collapsed) { + end++; + } + + var target = evt.getTargetRanges()[0]; + let deletionStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); + let deletionEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); + + this.dispatchEvent(new CustomEvent('deleteText', { + detail: { start: deletionStart, end: deletionEnd } + })); + break; + case 'deleteContentForward': if (this.selection.collapsed) { end++; @@ -87,6 +129,27 @@ class TextInput extends events(HTMLElement) { })); break; + case 'insertReplacementText': + console.log('in here with evt', evt); + // n.b. this assumes that there is only one target range. + if (evt.getTargetRanges().length !== 1) { + throw new Error('Unhandled scenario. Breaking in an unelegant way. Expected exactly one target range in insertReplacementText handler, got', evt.getTargetRanges().length); + } + + var target = evt.getTargetRanges()[0]; + let replaceStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); + let replaceEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); + + console.log('found', {start: replaceStart, end: replaceEnd}, 'for target', target); + + evt.dataTransfer.items[0].getAsString(replString => { + this.dispatchEvent(new CustomEvent('replaceText', { + detail: { start: replaceStart, end: replaceEnd, text: replString } + })); + }); + + break; + case 'formatBold': this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { start, end, type: 'bold' } @@ -100,6 +163,30 @@ class TextInput extends events(HTMLElement) { break; } } + + // This could be better implemented by tagging each parent node (i.e., + // not-text node) with its start offset, so that we could go from text node + + // offset to document offset directly. Not going to do it now to minimize + // impact across the codebase, but flagging here as a potential and desirable + // separate refactor. + nodeAndOffsetToDocumentOffset(node, offset): number { + let textNodes = getTextNodes(this); + + let l = textNodes.length; + let currOffset = 0; + + for (let i = 0; i < l; i++) { + let currNode = textNodes[i]; + + if (currNode === node) { + return currOffset + offset; + } else { + currOffset += (currNode.nodeValue || '').length + } + } + + throw new Error('Did not find a matching node. Was matching against', node, textNodes); + } }; customElements.define('text-input', TextInput); From 4060fb77c50e53a868aa0a5c34b63359b756c2d2 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Apr 2018 16:24:39 +0100 Subject: [PATCH 027/104] Fixes for basic demo --- packages/editor/demo.ts | 29 ----------------------------- packages/editor/public/app.ts | 17 +++++++++++++---- packages/editor/src/index.ts | 10 ++++++++-- 3 files changed, 21 insertions(+), 35 deletions(-) delete mode 100644 packages/editor/demo.ts diff --git a/packages/editor/demo.ts b/packages/editor/demo.ts deleted file mode 100644 index 45c796d21..000000000 --- a/packages/editor/demo.ts +++ /dev/null @@ -1,29 +0,0 @@ -import Document from '@atjson/document'; -import Editor from './src/index'; - -if (!window.customElements.get('text-editor')) { - window.customElements.define('text-editor', Editor); -} - -// Web components in the registry can't be redefined, -// so reload the page on every change -if (module.hot) { - module.hot.dispose(function () { - window.location.reload(); - }); -} - -let doc = new Document({ - content: 'Some text that is both bold and italic plus something after.\nA second paragraph.', - annotations: [ - { type: 'bold', display: 'inline', start: 23, end: 31 }, - { type: 'italic', display: 'inline', start: 28, end: 38 }, - { type: 'underline', display: 'inline', start: 28, end: 38 }, - { type: 'paragraph', display: 'block', start: 0, end: 61 }, - { type: 'paragraph', display: 'block', start: 61, end: 80 } - ] -}); - -let editor = document.createElement('text-editor'); -editor.document = doc; -document.body.appendChild(editor); diff --git a/packages/editor/public/app.ts b/packages/editor/public/app.ts index 2c3ea1778..c6feb3ca6 100644 --- a/packages/editor/public/app.ts +++ b/packages/editor/public/app.ts @@ -19,8 +19,17 @@ document.addEventListener('DOMContentLoaded', function () { if (doc) { editor.setDocument(new Document(JSON.parse(doc))); } else { - editor.setDocument(new Document({ - content: 'Hello, world' - })); + let doc = new Document({ + content: 'Some text that is both bold and italic plus something after.\nA second paragraph.', + annotations: [ + { type: 'bold', display: 'inline', start: 23, end: 31 }, + { type: 'italic', display: 'inline', start: 28, end: 38 }, + { type: 'underline', display: 'inline', start: 28, end: 38 }, + { type: 'paragraph', display: 'block', start: 0, end: 61 }, + { type: 'paragraph', display: 'block', start: 61, end: 80 } + ] + }); + + editor.setDocument(doc); } -}); \ No newline at end of file +}); diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 423ddb2d9..b90c228de 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -218,10 +218,16 @@ export default class Editor extends events(HTMLElement) { }); } + setDocument(value: Document) { + this.document = value; + if (this.isConnected) { + this.scheduleRender(); + } + } + connectedCallback() { this.innerHTML = this.constructor.template; super.connectedCallback(); - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); + this.scheduleRender(); } } From 4703529967c78ca4f352538e2fed208f0a2596e0 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Sat, 5 May 2018 21:02:32 +0100 Subject: [PATCH 028/104] wip rebase --- packages/editor/src/index.ts | 5 +++- packages/editor/src/text-input.ts | 3 ++- packages/renderer-webcomponent/.npmignore | 11 ++++++++ packages/renderer-webcomponent/LICENSE | 1 + packages/renderer-webcomponent/README.md | 3 +++ packages/renderer-webcomponent/package.json | 26 +++++++++++++++++++ packages/renderer-webcomponent/src/index.ts | 20 ++++++++++++++ .../test/webcomponent-renderer-test.ts | 6 +++++ packages/renderer-webcomponent/tsconfig.json | 9 +++++++ packages/renderer-webcomponent/tslint.json | 1 + 10 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 packages/renderer-webcomponent/.npmignore create mode 120000 packages/renderer-webcomponent/LICENSE create mode 100644 packages/renderer-webcomponent/README.md create mode 100644 packages/renderer-webcomponent/package.json create mode 100644 packages/renderer-webcomponent/src/index.ts create mode 100644 packages/renderer-webcomponent/test/webcomponent-renderer-test.ts create mode 100644 packages/renderer-webcomponent/tsconfig.json create mode 120000 packages/renderer-webcomponent/tslint.json diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index b90c228de..5b50ae858 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -135,7 +135,10 @@ export default class Editor extends events(HTMLElement) { } 'line-break'() { - return document.createElement('br'); + var parentElement = document.createElement('span'); + parentElement.appendChild(document.createElement('br')); + + return parentElement; } render(editor) { diff --git a/packages/editor/src/text-input.ts b/packages/editor/src/text-input.ts index 14b44c2d4..69d359c78 100644 --- a/packages/editor/src/text-input.ts +++ b/packages/editor/src/text-input.ts @@ -91,7 +91,8 @@ class TextInput extends events(HTMLElement) { break; case 'insertLineBreak': - this.dispatchEvent(new CustomEvent('insertText', [start, '\u2028', true])); + console.log('start is', start, end); + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: '\u2028' } })); this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { type: 'line-break', start, end: end + 1 } })); diff --git a/packages/renderer-webcomponent/.npmignore b/packages/renderer-webcomponent/.npmignore new file mode 100644 index 000000000..36040d0e2 --- /dev/null +++ b/packages/renderer-webcomponent/.npmignore @@ -0,0 +1,11 @@ +.vscode +.travis.yml +dist/**/test +dist/**/node_modules +ember-cli-build.js +scripts +test +testem.js +tmp +tsconfig.json +tsling.json diff --git a/packages/renderer-webcomponent/LICENSE b/packages/renderer-webcomponent/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/renderer-webcomponent/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/renderer-webcomponent/README.md b/packages/renderer-webcomponent/README.md new file mode 100644 index 000000000..ae889f5d5 --- /dev/null +++ b/packages/renderer-webcomponent/README.md @@ -0,0 +1,3 @@ +# @atjson/renderer-plain-text + +A brand new TypeScript library. diff --git a/packages/renderer-webcomponent/package.json b/packages/renderer-webcomponent/package.json new file mode 100644 index 000000000..3f52dfdba --- /dev/null +++ b/packages/renderer-webcomponent/package.json @@ -0,0 +1,26 @@ +{ + "name": "@atjson/renderer-webcomponent", + "version": "0.7.15", + "description": "A brand new TypeScript library.", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "scripts": { + "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "lint": "../../node_modules/.bin/tslint -c ../../tslint.json 'src/**/*.ts'", + "prepublishOnly": "npm run build", + "test": "../../node_modules/jest/bin/jest.js packages/$(basename $PWD) --config=../../package.json" + }, + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@atjson/document": "^0.7.15", + "@atjson/hir": "^0.7.15", + "@atjson/source-html": "^0.7.15" + }, + "dependencies": { + "@atjson/renderer-hir": "^0.7.15" + } +} diff --git a/packages/renderer-webcomponent/src/index.ts b/packages/renderer-webcomponent/src/index.ts new file mode 100644 index 000000000..259079652 --- /dev/null +++ b/packages/renderer-webcomponent/src/index.ts @@ -0,0 +1,20 @@ +import Renderer, { escapeHTML } from '@atjson/renderer-hir'; + +export default class WebComponentRenderer extends Renderer { + + renderText(text: string) { + return escapeHTML(text); + } + + *renderAnnotation(node): IterableIterator { + let text = yield; + let attributes = node.attributes; + let attrs = ''; + if (attributes) { + // FIXME this is both buggy and incorrect, since many annotation + // attributes are not necessarily appropriate for inclusion in HTML. + attrs = Object.keys(attributes).map(key => `${key}='${attributes[key]}'`).join(' '); + } + return `<${node.type} ${attrs}>${text.join('')}`; + } +} diff --git a/packages/renderer-webcomponent/test/webcomponent-renderer-test.ts b/packages/renderer-webcomponent/test/webcomponent-renderer-test.ts new file mode 100644 index 000000000..8dc291160 --- /dev/null +++ b/packages/renderer-webcomponent/test/webcomponent-renderer-test.ts @@ -0,0 +1,6 @@ +import Document, { Annotation } from '@atjson/document'; +import WebComponentRenderer from '@atjson/renderer-webcomponent'; + +describe('PlainTextRenderer', function () { + it('renders the atjson document'); +}); diff --git a/packages/renderer-webcomponent/tsconfig.json b/packages/renderer-webcomponent/tsconfig.json new file mode 100644 index 000000000..18dd94908 --- /dev/null +++ b/packages/renderer-webcomponent/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist/commonjs" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/renderer-webcomponent/tslint.json b/packages/renderer-webcomponent/tslint.json new file mode 120000 index 000000000..6fd001f22 --- /dev/null +++ b/packages/renderer-webcomponent/tslint.json @@ -0,0 +1 @@ +tslint.json \ No newline at end of file From 96f222a3ef6a88b1f37ce9d9358b9f5ae6ffe49f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Thu, 7 Jun 2018 12:17:57 -0500 Subject: [PATCH 029/104] broken wip --- packages/@atjson/editor/src/index.ts | 2 +- packages/@atjson/editor/src/mixins/events.ts | 6 +++--- packages/@atjson/editor/src/text-input.ts | 2 +- packages/@atjson/editor/src/text-selection.ts | 8 ++++++-- packages/@atjson/renderer-webcomponent/package.json | 12 ++++++------ packages/@atjson/renderer-webcomponent/src/index.ts | 3 ++- packages/@atjson/renderer-webcomponent/tsconfig.json | 2 +- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 5b50ae858..2949e48d0 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -199,7 +199,7 @@ export default class Editor extends events(HTMLElement) { counter.innerHTML = top + bottom; container.appendChild(counter); var rawText = document.createElement('pre'); - rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶")); + rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶"))); container.appendChild(rawText); let table = ''; this.document.annotations.forEach((a) => { diff --git a/packages/@atjson/editor/src/mixins/events.ts b/packages/@atjson/editor/src/mixins/events.ts index d10ff8e80..84e2142d3 100644 --- a/packages/@atjson/editor/src/mixins/events.ts +++ b/packages/@atjson/editor/src/mixins/events.ts @@ -1,14 +1,14 @@ type Constructor = new (...args: any[]) => T; -interface EventCallback { +export interface EventCallback { (evt: Event): boolean; } -interface EventHandlerDefinitions { +export interface EventHandlerDefinitions { [key: string]: string | EventCallback; } -interface EventHandlerReferences { +export interface EventHandlerReferences { [key: string]: EventCallback; } diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 69d359c78..15afa67e3 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -65,7 +65,7 @@ class TextInput extends events(HTMLElement) { }, 'change text-selection'(evt) { this.selection = evt.detail; - } + }, 'clear text-selection'() { this.selection = null; } diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index ba4df02cc..dc49e178d 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -79,13 +79,16 @@ function previousTextNode(node: Node): TextRangePoint { - `clear`- called when the text selecton is cleared */ class TextSelection extends events(HTMLElement) { + + composing: boolean; + static observedAttributes = ['start', 'end']; static events = { 'selectionchange document': 'selectedTextDidChange', - 'compositionstart'(evt) { + 'compositionstart'() { this.composing = true; }, - 'compositionend'(evt) { + 'compositionend'() { this.composing = false; } }; @@ -96,6 +99,7 @@ class TextSelection extends events(HTMLElement) { constructor() { super(); this.textNodes = []; + this.composing = false; } setSelection(range) { diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index 3f52dfdba..4217ce92f 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -7,20 +7,20 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", - "lint": "../../node_modules/.bin/tslint -c ../../tslint.json 'src/**/*.ts'", + "lint": "../../../node_modules/.bin/tslint -c ../../../tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", - "test": "../../node_modules/jest/bin/jest.js packages/$(basename $PWD) --config=../../package.json" + "test": "../../../node_modules/jest/bin/jest.js packages/$(basename $PWD) --config=../../../package.json" }, "license": "Apache-2.0", "publishConfig": { "access": "public" }, "devDependencies": { - "@atjson/document": "^0.7.15", - "@atjson/hir": "^0.7.15", - "@atjson/source-html": "^0.7.15" + "@atjson/document": "^0.7.16", + "@atjson/hir": "^0.8.0", + "@atjson/source-html": "^0.8.0" }, "dependencies": { - "@atjson/renderer-hir": "^0.7.15" + "@atjson/renderer-hir": "^0.8.0" } } diff --git a/packages/@atjson/renderer-webcomponent/src/index.ts b/packages/@atjson/renderer-webcomponent/src/index.ts index 259079652..e8f8c92e1 100644 --- a/packages/@atjson/renderer-webcomponent/src/index.ts +++ b/packages/@atjson/renderer-webcomponent/src/index.ts @@ -1,4 +1,5 @@ import Renderer, { escapeHTML } from '@atjson/renderer-hir'; +import { HIRNode } from '@atjson/hir'; export default class WebComponentRenderer extends Renderer { @@ -6,7 +7,7 @@ export default class WebComponentRenderer extends Renderer { return escapeHTML(text); } - *renderAnnotation(node): IterableIterator { + *renderAnnotation(node: HIRNode): IterableIterator { let text = yield; let attributes = node.attributes; let attrs = ''; diff --git a/packages/@atjson/renderer-webcomponent/tsconfig.json b/packages/@atjson/renderer-webcomponent/tsconfig.json index 18dd94908..58e586825 100644 --- a/packages/@atjson/renderer-webcomponent/tsconfig.json +++ b/packages/@atjson/renderer-webcomponent/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.json", + "extends": "../../../tsconfig.json", "compilerOptions": { "outDir": "./dist/commonjs" }, From b17cce82b958aa54b5d76ceec175927c6709cc58 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Sat, 9 Jun 2018 12:14:51 -0400 Subject: [PATCH 030/104] add very primitive change event to document --- packages/@atjson/document/src/index.ts | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index 8a3ffbbeb..f546f73ce 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -12,6 +12,8 @@ export default class AtJSON { contentType?: string; annotations: Annotation[]; schema?: Schema; + changeListeners: Function[]; + private pendingChangeEvent: any; protected queries: Query[]; @@ -24,6 +26,40 @@ export default class AtJSON { this.contentType = options.contentType || 'text/plain'; this.queries = []; this.schema = options.schema || {}; + + this.changeListeners = []; + } + + /** + * I'm on a plane; I'm not sure the best approach to cross-platform event + * listeners and don't have internet access at the moment, so I'm just going + * to quickly roll my own here. To be updated. + */ + addEventListener(eventName: string, func: Function): void { + if (eventName !== 'change') throw new Error('Unsupported event. `change` is the only constant.'); + this.changeListeners.push(func); + } + + /* + removeEventListener(eventName: string, func: Function): void { + throw new Error('Unimplemented.'); + } + */ + + /** + * This is really coarse, just enough to allow different code in the editor to detect + * changes in the document without handling that change management separately. + * + * Eventually it should be possible to handle this transactionally, but for + * now we batch all changes enacted within one cycle of the event loop and + * fire the change event only once. n.b that we don't send any information + * about the changes here yet, but that's not to say we couldn't, but rather + * it's not clear right now what the best approach would be so it's left + * undefined. + */ + private triggerChange() { + if (this.pendingChangeEvent) return; + this.pendingChangeEvent = setTimeout(_ => this.changeListeners.forEach(l => l()), 0) } /** @@ -41,6 +77,7 @@ export default class AtJSON { this.annotations.push(...finalizedAnnotations); } }); + this.triggerChange(); } /** @@ -71,6 +108,7 @@ export default class AtJSON { if (index > -1) { return this.annotations.splice(index, 1)[0]; } + this.triggerChange(); } replaceAnnotation(annotation: Annotation, ...newAnnotations: Annotation[]): void { @@ -78,6 +116,7 @@ export default class AtJSON { if (index > -1) { this.annotations.splice(index, 1, ...newAnnotations); } + this.triggerChange(); } insertText(position: number, text: string, preserveAdjacentBoundaries: boolean = false) { @@ -161,6 +200,8 @@ export default class AtJSON { } } } + + this.triggerChange(); } deleteText(annotation: Annotation) { @@ -237,6 +278,8 @@ export default class AtJSON { } } } + + this.triggerChange(); } /** @@ -288,5 +331,7 @@ export default class AtJSON { } } } + + this.triggerChange(); } } From f33a066f698316150bd90b8a7e73b3399dd1a280 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Sat, 9 Jun 2018 12:19:21 -0400 Subject: [PATCH 031/104] Refactor so that standalone editor is a standalone component and demo/dingus is separate and uses the base editor separately. --- packages/@atjson/editor/public/app.ts | 8 +- packages/@atjson/editor/public/index.html | 2 +- packages/@atjson/editor/src/editor-demo.ts | 51 +++++ packages/@atjson/editor/src/index.ts | 179 ++++-------------- .../@atjson/editor/src/inspector-gadget.ts | 72 +++++++ packages/@atjson/editor/src/text-input.ts | 2 +- .../editor/src/webcomponent-renderer.ts | 97 ++++++++++ 7 files changed, 258 insertions(+), 153 deletions(-) create mode 100644 packages/@atjson/editor/src/editor-demo.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget.ts create mode 100644 packages/@atjson/editor/src/webcomponent-renderer.ts diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index c6feb3ca6..c67c482f3 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -1,8 +1,8 @@ import Document from '@atjson/document'; -import Editor from '../src/index'; +import EditorDemo from '../src/editor-demo'; -if (!window.customElements.get('text-editor')) { - window.customElements.define('text-editor', Editor); +if (!window.customElements.get('text-editor-demo')) { + window.customElements.define('text-editor-demo', EditorDemo); } // Web components in the registry can't be redefined, @@ -14,7 +14,7 @@ if (module.hot) { } document.addEventListener('DOMContentLoaded', function () { - let editor: Editor = document.querySelector('text-editor'); + let editor: EditorDemo = document.querySelector('text-editor-demo'); let doc = new URL(location.toString()).searchParams.get('document'); if (doc) { editor.setDocument(new Document(JSON.parse(doc))); diff --git a/packages/@atjson/editor/public/index.html b/packages/@atjson/editor/public/index.html index 36957a5f5..18c592d71 100644 --- a/packages/@atjson/editor/public/index.html +++ b/packages/@atjson/editor/public/index.html @@ -3,6 +3,6 @@ - + diff --git a/packages/@atjson/editor/src/editor-demo.ts b/packages/@atjson/editor/src/editor-demo.ts new file mode 100644 index 000000000..ecdddedaa --- /dev/null +++ b/packages/@atjson/editor/src/editor-demo.ts @@ -0,0 +1,51 @@ +import Document from '@atjson/document'; +import Editor from './index'; +import WebComponentRenderer from './webcomponent-renderer'; +import InspectorGadget from './inspector-gadget'; +import events from './mixins/events'; + +if (!window.customElements.get('text-editor')) { + window.customElements.define('text-editor', Editor); +} + +if (!window.customElements.get('inspector-gadget')) { + window.customElements.define('inspector-gadget', InspectorGadget); +} + +export default class EditorDemo extends events(HTMLElement) { + static template = '' + + '
' + + ''; + + static events = { + 'change text-editor'(evt) { + console.log('got change event'); + this.renderOutput(evt.detail.document); + } + } + + renderOutput(doc) { + let outputElement = this.querySelector('.output'); + let rendered = new WebComponentRenderer(doc).render(); + this.querySelector('.output').innerHTML = rendered.innerHTML; + } + + setDocument(doc: Document) { + let editor = this.querySelector('text-editor'); + editor.setDocument(doc); + let inspectorGadget = this.querySelector('inspector-gadget'); + inspectorGadget.setDocument(doc); + inspectorGadget.setSelection(editor.getSelection()); + } + + connectedCallback() { + this.innerHTML = this.constructor.template; + super.connectedCallback(); + } +} + +console.log('loaded yo'); +if (!window.customElements.get('text-editor-demo')) { + console.log('defineingadfj'); + window.customElements.define('text-editor-demo', EditorDemo); +} diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 2949e48d0..393535340 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -1,34 +1,20 @@ -import { HIR } from '@atjson/hir'; import Document from '@atjson/document'; +import WebComponentRenderer from './webcomponent-renderer'; import events from './mixins/events'; import './text-selection'; import './text-input'; const TEXT_NODE_TYPE = 3; +type Range = { start: number, end: number }; type Element = TextNode | HTMLElement; -function compile(editor: Editor, hir: Map, nodes: HIRNode[]): Element[] { - return nodes.map((node: HIRNode) => { - let children = node.children(); - if (children.length > 0) { - let element = editor[node.type](node); - hir.set(element, node); - compile(editor, hir, children).forEach((child: Element) => { - element.appendChild(child); - }); - return element; - } - let text = editor[node.type](node); - hir.set(text, node); - return text; - }); -} - export default class Editor extends events(HTMLElement) { - static template = '
' + - '
' + - '
'; + + selection: Range; + + static template = '
'; + static events = { 'change text-selection'(evt) { this.selection = evt.detail; @@ -39,7 +25,6 @@ export default class Editor extends events(HTMLElement) { this.document.insertText(evt.detail.position, evt.detail.text); this.selection.start += evt.detail.text.length; this.selection.end += evt.detail.text.length; - this.scheduleRender(); }, 'deleteText text-input'(evt) { @@ -55,7 +40,6 @@ export default class Editor extends events(HTMLElement) { this.selection.start -= l; this.selection.end -= l; } - this.scheduleRender(); }, 'replaceText text-input'(evt) { @@ -64,100 +48,42 @@ export default class Editor extends events(HTMLElement) { this.document.deleteText(replacement); this.document.insertText(replacement.start, replacement.text); this.selection.start = replacement.start + replacement.text.length; - - this.scheduleRender(); }, 'addAnnotation text-input'(evt) { - this.document.addAnnotations(evt.detail); - this.scheduleRender(); - } - }; - scheduleRender() { - window.requestAnimationFrame(() => { - this.render(this.querySelector('.editor')); - this.render(this.querySelector('.output')); - this.renderJson(this.querySelector('.json')); - }); - } - text({ text }) { - if (text[text.length - 1] == "\n") { - var nonBreakStrings = text.split("\n"); - console.log('+++--->' + text + '<---+++', '->',nonBreakStrings); - if (nonBreakStrings[nonBreakStrings.length - 1] == '') { - nonBreakStrings.pop(); - } - var children = nonBreakStrings.map((str) => { - var span = document.createElement('span'); - span.style.whiteSpace = 'normal'; - span.style.display = 'none'; - span.contentEditable = false; - span.appendChild(document.createTextNode("\n")); - console.log(span); - return [document.createTextNode(str), span] - }).reduce((a, b) => a.concat(b)); - - console.log(children); - - var textParentNode = document.createElement('span'); - children.forEach((child) => { - textParentNode.appendChild(child); - }) - - return textParentNode; - } - return document.createTextNode(text); - } - - paragraph() { - return document.createElement('p'); - } - bold() { - return document.createElement('strong'); - } - italic() { - return document.createElement('em'); - } - underline() { - return document.createElement('u'); - } - link(attributes) { - let link = document.createElement('a'); - link.setAttribute('href', attributes.uri); - return link; - } - 'line-break'() { - var parentElement = document.createElement('span'); - parentElement.appendChild(document.createElement('br')); - return parentElement; + scheduleRender() { + console.log('schedule render called.'); + window.requestAnimationFrame(() => { + this.render(this.querySelector('.editor')); + let evt = new CustomEvent('change', { bubbles: true, detail: { document: this.document } }); + console.log('dispatching event', evt); + this.dispatchEvent(evt); + }); } render(editor) { - editor.hir = new Map(); - let annotationGraph = new HIR(this.document); - - let placeholder = document.createElement('div'); - let children = compile(this, editor.hir, annotationGraph.rootNode.children()); - children.forEach((element: Element) => { - placeholder.appendChild(element); - }); + let rendered = new WebComponentRenderer(this.document).render(); // This can be improved by doing the comparison on an element-by-element // basis (or by rendering incrementally via the HIR), but for now this will // prevent flickering of OS UI elements (e.g., spell check) while typing // characters that don't result in changes outside of text elements. - if (placeholder.innerHTML != editor.innerHTML) { - console.log('not match', placeholder.innerHTML, '\n---\n', editor.innerHTML, this.document); - editor.innerHTML = placeholder.innerHTML; + if (rendered.innerHTML != editor.innerHTML) { + console.table({ + current: rendered.innerHTML, + updated: editor.innerHTML + }); + console.info('Rendering', this.document); + editor.innerHTML = rendered.innerHTML; // We need to do a force-reset here in order to avoid waiting for a full // cycle of the browser event loop. The DOM has changed, but if we wait @@ -174,58 +100,13 @@ export default class Editor extends events(HTMLElement) { } } - renderJson(container) { - window.requestAnimationFrame(() => { - container.innerHTML = ''; - var counter = document.createElement('pre'); - var top = ''; - var bottom = ''; - for (var x = 0; x < 100; x++) { - if (this.selection.start == x) { - bottom += '' - } - bottom += x % 10; - if (this.selection.end == x) { - bottom += ''; - } - - if (x % 10 == 0) { - top += x / 10; - } else { - top += ' '; - } - } - top += '\n'; - counter.innerHTML = top + bottom; - container.appendChild(counter); - var rawText = document.createElement('pre'); - rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶"))); - container.appendChild(rawText); - let table = '
typestartenddisplayattributes
'; - this.document.annotations.forEach((a) => { - table += ''; - ['type', 'start', 'end', 'display'].forEach(attr => { - table += ''; - }); - if (a.attributes) { - table += ''; - } else { - table += ''; - } - table += ''; - }); - table += '
typestartenddisplayattributes
' + a[attr] + '' + a.attributes.toJSON() + '
'; - let tableContainer = document.createElement('div'); - tableContainer.innerHTML = table; - container.appendChild(tableContainer); - }); - } - setDocument(value: Document) { this.document = value; - if (this.isConnected) { - this.scheduleRender(); - } + this.document.addEventListener('change', (_ => this.scheduleRender() )); + } + + getSelection() { + return this.querySelector('text-selection'); } connectedCallback() { @@ -234,3 +115,7 @@ export default class Editor extends events(HTMLElement) { this.scheduleRender(); } } + +if (!window.customElements.get('text-editor')) { + window.customElements.define('text-editor', Editor); +} diff --git a/packages/@atjson/editor/src/inspector-gadget.ts b/packages/@atjson/editor/src/inspector-gadget.ts new file mode 100644 index 000000000..3397d6a5e --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget.ts @@ -0,0 +1,72 @@ +import Document from '@atjson/document'; +import events from './mixins/events'; + +export default class InspectorGadget extends events(HTMLElement) { + + document: Document; + + render() { + this.innerHTML = ''; + var counter = document.createElement('pre'); + var top = ''; + var bottom = ''; + console.table({start: this.selection.start, end: this.selection.end}); + for (var x = 0; x < 100; x++) { + if (this.selection.start == x) { + bottom += '' + } + bottom += x % 10; + if (this.selection.end == x) { + bottom += ''; + } + + if (x % 10 == 0) { + top += x / 10; + } else { + top += ' '; + } + } + top += '\n'; + counter.innerHTML = top + bottom; + this.appendChild(counter); + var rawText = document.createElement('pre'); + rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶"))); + this.appendChild(rawText); + let table = ''; + this.document.annotations.forEach((a) => { + table += ''; + ['type', 'start', 'end', 'display'].forEach(attr => { + table += ''; + }); + if (a.attributes) { + table += ''; + } else { + table += ''; + } + table += ''; + }); + table += '
typestartenddisplayattributes
' + a[attr] + '' + a.attributes.toJSON() + '
'; + let tableContainer = document.createElement('div'); + tableContainer.innerHTML = table; + this.appendChild(tableContainer); + } + + setDocument(doc) { + this.document = doc; + this.document.addEventListener('change', (_ => { + window.requestAnimationFrame(_ => this.render()); + })); + } + + setSelection(el) { + el.addEventListener('change', evt => { + this.selection = evt.detail; + window.requestAnimationFrame(_ => this.render()); + }); + } + + connectedCallback() { + this.innerHTML = this.constructor.template; + super.connectedCallback(); + } +} diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 15afa67e3..6362d5dab 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -58,7 +58,7 @@ function getTextNodes(node: Node): Text[] { class TextInput extends events(HTMLElement) { static events = { 'beforeinput': 'beforeinput', - 'compositionend'(evt) { + 'compositionend'() { let { start } = this.selection; this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); this.composing = false; diff --git a/packages/@atjson/editor/src/webcomponent-renderer.ts b/packages/@atjson/editor/src/webcomponent-renderer.ts new file mode 100644 index 000000000..3e88d3745 --- /dev/null +++ b/packages/@atjson/editor/src/webcomponent-renderer.ts @@ -0,0 +1,97 @@ +import { HIR } from '@atjson/hir'; + +export default class WebComponentRenderer { + + constructor(document) { + this.document = document; + } + + text({ text }) { + if (text[text.length - 1] == "\n") { + var nonBreakStrings = text.split("\n"); + console.log('+++--->' + text + '<---+++', '->',nonBreakStrings); + if (nonBreakStrings[nonBreakStrings.length - 1] == '') { + nonBreakStrings.pop(); + } + var children = nonBreakStrings.map((str: string) => { + var span = document.createElement('span'); + span.style.whiteSpace = 'normal'; + span.style.display = 'none'; + span.contentEditable = false; + span.appendChild(document.createTextNode("\n")); + console.log(span); + return [document.createTextNode(str), span] + }).reduce((a, b) => a.concat(b)); + + console.log(children); + + var textParentNode = document.createElement('span'); + children.forEach((child) => { + textParentNode.appendChild(child); + }) + + return textParentNode; + } + return document.createTextNode(text); + } + + paragraph() { + return document.createElement('p'); + } + + bold() { + return document.createElement('strong'); + } + + italic() { + return document.createElement('em'); + } + + underline() { + return document.createElement('u'); + } + + link(attributes) { + let link = document.createElement('a'); + link.setAttribute('href', attributes.uri); + return link; + } + + 'line-break'() { + var parentElement = document.createElement('span'); + parentElement.appendChild(document.createElement('br')); + + return parentElement; + } + + render() { + let hir = new Map(); + let annotationGraph = new HIR(this.document); + + let placeholder = document.createElement('div'); + let children = this.compile(hir, annotationGraph.rootNode.children()); + children.forEach((element: Element) => { + placeholder.appendChild(element); + }); + return placeholder; + } + + compile(hir: Map, nodes: HIRNode[]): Element[] { + return nodes.map((node: HIRNode) => { + let children = node.children(); + if (children.length > 0) { + let element = this[node.type](node); + hir.set(element, node); + this.compile(hir, children).forEach((child: Element) => { + element.appendChild(child); + }); + return element; + } + let text = this[node.type](node); + hir.set(text, node); + return text; + }); + } + + +} From 99e62329b4728cec56267d81a167eefdea1db3c3 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Sat, 9 Jun 2018 12:20:07 -0400 Subject: [PATCH 032/104] handle inversion / overlaps of inline singleton annotations --- packages/@atjson/editor/src/index.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 393535340..ec247e8ff 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -51,14 +51,39 @@ export default class Editor extends events(HTMLElement) { }, 'addAnnotation text-input'(evt) { + if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { + const contained = (a, b) => a.start >= b.start && a.end <= b.end + const offset = (a, b) => a.start <= b.end && a.end >= b.start + let overlapping = this.document.annotations.filter(a => a.type === evt.detail.type) + .filter(a => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); + let min = overlapping.reduce((a, b) => { return Math.min(a, b.start) }, this.document.content.length) + let max = overlapping.reduce((a, b) => { return Math.max(a, b.end) }, 0) + if (overlapping.length === 0) { + this.document.addAnnotations(evt.detail); + } else if (min <= evt.detail.start && evt.detail.end <= max && overlapping.length === 1) { + // invert the state. + let prev = overlapping[0]; + let newFirst = Object.assign({}, prev, evt.detail, { start: prev.start, end: evt.detail.start }); + let newLast = Object.assign({}, prev, evt.detail, { start: evt.detail.end, end: prev.end }); + if (min !== evt.detail.start) this.document.addAnnotations(newFirst) + if (max !== evt.detail.end) this.document.addAnnotations(newLast); + } else { + this.document.addAnnotations(Object.assign({}, overlapping[0], evt.detail, { start: Math.min(min, evt.detail.start), end: Math.max(max, evt.detail.end) })); + } + overlapping.forEach(o => this.document.removeAnnotation(o)); + } else { + this.document.addAnnotations(evt.detail); + } + } + }; scheduleRender() { console.log('schedule render called.'); From 66500a2305a94a507e45baee966649a4e7a98023 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Thu, 21 Jun 2018 23:59:57 +0100 Subject: [PATCH 033/104] Move Webcomponent Renderer to separate directory --- .../components/editable-link.ts | 135 ++++++++++++++++++ .../index.ts} | 30 ++-- 2 files changed, 155 insertions(+), 10 deletions(-) create mode 100644 packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts rename packages/@atjson/editor/src/{webcomponent-renderer.ts => webcomponent-renderer/index.ts} (77%) diff --git a/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts b/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts new file mode 100644 index 000000000..567a515e3 --- /dev/null +++ b/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts @@ -0,0 +1,135 @@ +import WebComponent from '../../mixins/component'; + +export default class EditableLink extends WebComponent { + static template = `
🔗 
+    
`; + + static observedAttributes = ['url', 'nofollow']; + + static events = { + 'beforeinput': 'beforeInput', + 'cursorfocus': 'cursorFocus', + 'cursorblur': 'cursorBlur', + 'click .text-link': 'cancelLinkClick', + 'click .cancel': 'cursorBlur', + 'click .save': 'onSave', + 'click .config': 'onConfig', + 'keypress .urlinput': 'handleKeypress' + } + + static style = ` + :host { + position: relative; + outline: none; + } + + .controls { + display: none; + position: absolute; + top: -2.5em; + right: -10em; + height: 1.5em; + vertical-align: baseline; + background-color: white; + padding: 3px; + border: 1px solid black; + border-radius: 5px; + white-space: normal; + } + + a { + text-decoration: underline; + } + + .controls .extended { + display: none; + width: max-content; + } + + :host(.cursorfocus) .controls { + display: flex; + } + + :host(.config) .controls .default { + display: none; + } + + :host(.config) .controls .extended { + display: block; + } + + :host(.config) button.config { + background: darkgrey; + } + `; + + url: string; + nofollow: boolean; + + cursorFocus() { + this.classList.add('cursorfocus'); + } + + cursorBlur() { + console.trace('got cursor blur??'); + this.classList.remove('cursorfocus'); + this.classList.remove('config'); + } + + cancelLinkClick(evt) { + evt.preventDefault(); + } + + handleKeypress(evt) { + if (evt.keyCode === 13) { + this.onSave(evt); + } + } + + beforeInput(evt) { + evt.stopPropagation(); + } + + onConfig() { + this.classList.toggle('config'); + } + + onSave(evt) { + let link = this.shadowRoot.querySelector('.urlinput'); + this.setAttribute('url', link.value); + + let nofollow = this.shadowRoot.querySelector('.nofollow'); + if (nofollow.checked) { + this.setAttribute('nofollow', ''); + } else { + this.removeAttribute('nofollow'); + } + + console.log(nofollow); + + this.dispatchEvent(new CustomEvent('attributechange', { bubbles: true, detail: { + attributes: { + url: link.value, + nofollow: nofollow.checked + } + }})); + + this.cursorBlur(); + evt.stopPropagation(); + } + + attributeChangedCallback(attribute) { + let link = this.shadowRoot.querySelector('a'); + let input = this.shadowRoot.querySelector('.urlinput'); + let nofollow = this.shadowRoot.querySelector('.nofollow'); + switch (attribute) { + case 'url': + link.setAttribute('href', this.getAttribute('url')); + input.setAttribute('value', this.getAttribute('url')); + break; + case 'nofollow': + nofollow.checked = this.hasAttribute('nofollow'); + break; + } + } +} diff --git a/packages/@atjson/editor/src/webcomponent-renderer.ts b/packages/@atjson/editor/src/webcomponent-renderer/index.ts similarity index 77% rename from packages/@atjson/editor/src/webcomponent-renderer.ts rename to packages/@atjson/editor/src/webcomponent-renderer/index.ts index 3e88d3745..e649076e6 100644 --- a/packages/@atjson/editor/src/webcomponent-renderer.ts +++ b/packages/@atjson/editor/src/webcomponent-renderer/index.ts @@ -1,4 +1,9 @@ import { HIR } from '@atjson/hir'; +import EditableLink from './components/editable-link'; + +if (!window.customElements.get('editable-link')) { + window.customElements.define('editable-link', EditableLink); +} export default class WebComponentRenderer { @@ -9,7 +14,6 @@ export default class WebComponentRenderer { text({ text }) { if (text[text.length - 1] == "\n") { var nonBreakStrings = text.split("\n"); - console.log('+++--->' + text + '<---+++', '->',nonBreakStrings); if (nonBreakStrings[nonBreakStrings.length - 1] == '') { nonBreakStrings.pop(); } @@ -19,12 +23,9 @@ export default class WebComponentRenderer { span.style.display = 'none'; span.contentEditable = false; span.appendChild(document.createTextNode("\n")); - console.log(span); return [document.createTextNode(str), span] }).reduce((a, b) => a.concat(b)); - console.log(children); - var textParentNode = document.createElement('span'); children.forEach((child) => { textParentNode.appendChild(child); @@ -43,6 +44,10 @@ export default class WebComponentRenderer { return document.createElement('strong'); } + strikethrough() { + return document.createElement('del'); + } + italic() { return document.createElement('em'); } @@ -51,9 +56,12 @@ export default class WebComponentRenderer { return document.createElement('u'); } - link(attributes) { - let link = document.createElement('a'); - link.setAttribute('href', attributes.uri); + link(node) { + let link = document.createElement('editable-link'); + link.setAttribute('url', node.attributes.url); + if (node.attributes.nofollow) { + link.setAttribute('nofollow', ''); + } return link; } @@ -80,7 +88,11 @@ export default class WebComponentRenderer { return nodes.map((node: HIRNode) => { let children = node.children(); if (children.length > 0) { - let element = this[node.type](node); + let element = document.createElement('span'); + if (this[node.type]) { + element = this[node.type](node); + element.setAttribute('data-annotation-id', node.id); + } hir.set(element, node); this.compile(hir, children).forEach((child: Element) => { element.appendChild(child); @@ -92,6 +104,4 @@ export default class WebComponentRenderer { return text; }); } - - } From 1e37da4787667158adaa906c43bf0449917375d3 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:00:40 +0100 Subject: [PATCH 034/104] Move demo and inspector to separate directory --- .../{editor-demo.ts => editor-demo/index.ts} | 36 ++++++-- .../@atjson/editor/src/editor-demo/logo.ts | 71 +++++++++++++++ .../@atjson/editor/src/inspector-gadget.ts | 72 --------------- .../inspector-gadget/annotation-attribute.ts | 19 ++++ .../inspector-gadget/annotation-inspector.ts | 48 ++++++++++ .../inspector-gadget/annotations-inspector.ts | 91 +++++++++++++++++++ .../src/inspector-gadget/character-counter.ts | 79 ++++++++++++++++ .../editor/src/inspector-gadget/index.ts | 67 ++++++++++++++ 8 files changed, 401 insertions(+), 82 deletions(-) rename packages/@atjson/editor/src/{editor-demo.ts => editor-demo/index.ts} (51%) create mode 100644 packages/@atjson/editor/src/editor-demo/logo.ts delete mode 100644 packages/@atjson/editor/src/inspector-gadget.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget/character-counter.ts create mode 100644 packages/@atjson/editor/src/inspector-gadget/index.ts diff --git a/packages/@atjson/editor/src/editor-demo.ts b/packages/@atjson/editor/src/editor-demo/index.ts similarity index 51% rename from packages/@atjson/editor/src/editor-demo.ts rename to packages/@atjson/editor/src/editor-demo/index.ts index ecdddedaa..259855ba0 100644 --- a/packages/@atjson/editor/src/editor-demo.ts +++ b/packages/@atjson/editor/src/editor-demo/index.ts @@ -1,8 +1,10 @@ import Document from '@atjson/document'; -import Editor from './index'; -import WebComponentRenderer from './webcomponent-renderer'; -import InspectorGadget from './inspector-gadget'; -import events from './mixins/events'; +import Editor from '../index'; +import WebComponentRenderer from '../webcomponent-renderer'; +import CommonmarkRenderer from '@atjson/renderer-commonmark'; +import InspectorGadget from '../inspector-gadget'; +import OffsetLogo from './logo'; +import events from '../mixins/events'; if (!window.customElements.get('text-editor')) { window.customElements.define('text-editor', Editor); @@ -12,22 +14,33 @@ if (!window.customElements.get('inspector-gadget')) { window.customElements.define('inspector-gadget', InspectorGadget); } +if (!window.customElements.get('offset-logo')) { + window.customElements.define('offset-logo', OffsetLogo); +} + export default class EditorDemo extends events(HTMLElement) { - static template = '' + - '
' + + static template = '

' + + '

HTML Output

' + + '

Commonmark Output

' + ''; static events = { 'change text-editor'(evt) { - console.log('got change event'); this.renderOutput(evt.detail.document); + this.renderMarkdown(evt.detail.document); } } renderOutput(doc) { let outputElement = this.querySelector('.output'); let rendered = new WebComponentRenderer(doc).render(); - this.querySelector('.output').innerHTML = rendered.innerHTML; + outputElement.innerHTML = rendered.innerHTML; + } + + renderMarkdown(doc) { + let outputElement = this.querySelector('.markdown'); + let rendered = new CommonmarkRenderer().render(doc); + outputElement.innerHTML = rendered; } setDocument(doc: Document) { @@ -36,6 +49,11 @@ export default class EditorDemo extends events(HTMLElement) { let inspectorGadget = this.querySelector('inspector-gadget'); inspectorGadget.setDocument(doc); inspectorGadget.setSelection(editor.getSelection()); + + doc.addEventListener('change', _ => { + let logo = this.querySelector('offset-logo'); + logo.setAttribute('offset', doc.content.length) + }); } connectedCallback() { @@ -44,8 +62,6 @@ export default class EditorDemo extends events(HTMLElement) { } } -console.log('loaded yo'); if (!window.customElements.get('text-editor-demo')) { - console.log('defineingadfj'); window.customElements.define('text-editor-demo', EditorDemo); } diff --git a/packages/@atjson/editor/src/editor-demo/logo.ts b/packages/@atjson/editor/src/editor-demo/logo.ts new file mode 100644 index 000000000..77fe1a0da --- /dev/null +++ b/packages/@atjson/editor/src/editor-demo/logo.ts @@ -0,0 +1,71 @@ +import WebComponent from '../mixins/component'; + +export default class OffsetLogo extends WebComponent { + static template = ''; + + static style = 'canvas { width: 300px; height: 150px; }'; + + static observedAttributes = ['offset']; + + render() { + let x = parseInt(this.getAttribute('offset')); + + var canvas = this.shadowRoot.querySelector('canvas'); + canvas.width = 300; + canvas.height = 150; + canvas.style.width = 150; + canvas.style.height = 75; + + var ctx = canvas.getContext('2d'); + ctx.scale(2, 2); + + ctx.globalCompositeOperation = 'darken'; + let fontSize = canvas.width / 7 + 'px'; + ctx.font = `${fontSize} Helvetica`; + + var origin = { x: 2, y: canvas.height / 4.0 }; + + let rotatePoint = (angle, point) => { + var radians = angle * Math.PI / 180.0; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var dX = point.x - origin.x; + var dY = point.y - origin.y; + var x = cos * dX - sin * dY + origin.x; + var y = sin * dX + cos * dY + origin.y; + return { x, y }; + } + + if (!this.cyanPoint) { + this.cyanPoint = { x: 0, y: canvas.height / 4.0 - 1 }; + this.magentaPoint = rotatePoint(120, { x: 0, y: canvas.height / 4.0 - 1 }); + this.yellowPoint = rotatePoint(240, { x: 0, y: canvas.height / 4.0 - 1 }); + } + var rotationAngle = 2 * (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1); + + let drawOffset = (point, color) => { + var newPoint = rotatePoint(rotationAngle, point); + ctx.fillStyle = color; + ctx.fillText('Offset', newPoint.x, newPoint.y); + return newPoint; + } + + let drawOffsets = (angle) => { + ctx.clearRect(0, 0, 1000, 300); + console.log(angle, this.cyanPoint); + this.cyanPoint = drawOffset(this.cyanPoint, 'cyan'); + this.magentaPoint = drawOffset(this.magentaPoint, 'magenta'); + this.yellowPoint = drawOffset(this.yellowPoint, 'yellow'); + } + + drawOffsets(x); + } + + attributeChangedCallback(attribute) { + this.render(); + } + + connectedCallback() { + this.render(); + } +} diff --git a/packages/@atjson/editor/src/inspector-gadget.ts b/packages/@atjson/editor/src/inspector-gadget.ts deleted file mode 100644 index 3397d6a5e..000000000 --- a/packages/@atjson/editor/src/inspector-gadget.ts +++ /dev/null @@ -1,72 +0,0 @@ -import Document from '@atjson/document'; -import events from './mixins/events'; - -export default class InspectorGadget extends events(HTMLElement) { - - document: Document; - - render() { - this.innerHTML = ''; - var counter = document.createElement('pre'); - var top = ''; - var bottom = ''; - console.table({start: this.selection.start, end: this.selection.end}); - for (var x = 0; x < 100; x++) { - if (this.selection.start == x) { - bottom += '' - } - bottom += x % 10; - if (this.selection.end == x) { - bottom += ''; - } - - if (x % 10 == 0) { - top += x / 10; - } else { - top += ' '; - } - } - top += '\n'; - counter.innerHTML = top + bottom; - this.appendChild(counter); - var rawText = document.createElement('pre'); - rawText.appendChild(document.createTextNode(this.document.content.replace(/\n/g, "¶"))); - this.appendChild(rawText); - let table = ''; - this.document.annotations.forEach((a) => { - table += ''; - ['type', 'start', 'end', 'display'].forEach(attr => { - table += ''; - }); - if (a.attributes) { - table += ''; - } else { - table += ''; - } - table += ''; - }); - table += '
typestartenddisplayattributes
' + a[attr] + '' + a.attributes.toJSON() + '
'; - let tableContainer = document.createElement('div'); - tableContainer.innerHTML = table; - this.appendChild(tableContainer); - } - - setDocument(doc) { - this.document = doc; - this.document.addEventListener('change', (_ => { - window.requestAnimationFrame(_ => this.render()); - })); - } - - setSelection(el) { - el.addEventListener('change', evt => { - this.selection = evt.detail; - window.requestAnimationFrame(_ => this.render()); - }); - } - - connectedCallback() { - this.innerHTML = this.constructor.template; - super.connectedCallback(); - } -} diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts b/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts new file mode 100644 index 000000000..d03ea7e9f --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts @@ -0,0 +1,19 @@ +import WebComponent from '../mixins/component'; + +export default class AnnotationAttribute extends WebComponent { + static template = ' = ' + + static observedAttributes = ['name', 'value']; + + attributeChangedCallback(attribute) { + console.log('got this here', attribute, this.getAttribute(attribute)) + switch (attribute) { + case 'name': + this.shadowRoot.querySelector('.name').innerHTML = this.getAttribute('name'); + break; + case 'value': + this.shadowRoot.querySelector('.value').innerHTML = this.getAttribute('value'); + break; + } + } +} diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts b/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts new file mode 100644 index 000000000..1a4daba4b --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts @@ -0,0 +1,48 @@ +import WebComponent from '../mixins/component'; +import AnnotationAttribute from './annotation-attribute'; + +export default class AnnotationInspector extends WebComponent { + + static template = ` + + + + + + + `; + + static observedAttributes = ['type', 'start', 'end', 'attributes']; + + attributeChangedCallback(attribute) { + console.log('i am in here...'); + switch (attribute) { + case 'type': + this.shadowRoot.querySelector('.type').innerHTML = this.getAttribute('type'); + break; + case 'start': + this.shadowRoot.querySelector('.start').innerHTML = this.getAttribute('start'); + break; + case 'end': + this.shadowRoot.querySelector('.end').innerHTML = this.getAttribute('end'); + break; + case 'attributes': + try { + attributes = JSON.parse(this.getAttribute('attributes')); + } catch { + this.shadowRoot.querySelector('.attributes').innerHTML = ''; + return; + } + + let inner = []; + console.log('i am here???'); + this.shadowRoot.querySelector('.attributes').innerHTML = attributes.keys.map(key => { + console.log('adding thing ... ', key, attributes[key]); + return `
`; + this.shadowRoot.querySelector('.attributes'); + }).join(''); + + break; + } + } +} diff --git a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts new file mode 100644 index 000000000..e13f78d1e --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts @@ -0,0 +1,91 @@ +import AnnotationInspector from './annotation-attribute'; +import WebComponent from '../mixins/component'; + +if (!window.customElements.get('annotation-attribute')) { + window.customElements.define('annotation-attribute', AnnotationInspector); +} + +export default class AnnotationsInspector extends WebComponent { + static template = ` +
+ + + + + + + + + + + + + + + + +
TypeStartEndAttributes
+
+ `; + static style = ` + .container { + overflow-y: scroll; + position: relative; + padding-bottom: 2em; + } + + table { + border-collapse: collapse; + width: 100vw; + } + + th { + font-size: 0.75em; + font-family: sans-serif; + border-bottom: 1px solid black; + border-top: 1px solid black; + text-align: left; + } + + td { + font-family: monospace; + vertical-align: top; + border-bottom: 0.5px solid grey; + } + + th, td { + padding: 1ex 0; + } + + td:first-child, th:first-child { + padding-left: 1ex; + } + + .annotation-type { + width: 10vw; + } + + .annotation-start, .annotation-end { + width: 4em; + } + `; + + updateTBody() { + let tbody = ''; + this.document.annotations.forEach((a) => { + tbody += `${a.type}${a.start}${a.end}`; + if (a.attributes) { + Object.keys(a.attributes).forEach(key => { + tbody += `
` + }); + } else { + tbody += `` + }); + this.shadowRoot.querySelector('tbody').innerHTML = tbody; + } + + setDocument(doc) { + this.document = doc; + this.document.addEventListener('change', _ => window.requestAnimationFrame(_ => this.updateTBody())); + } +} diff --git a/packages/@atjson/editor/src/inspector-gadget/character-counter.ts b/packages/@atjson/editor/src/inspector-gadget/character-counter.ts new file mode 100644 index 000000000..4bcc8d314 --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget/character-counter.ts @@ -0,0 +1,79 @@ +import WebComponent from '../mixins/component'; + +export default class CharacterCounter extends WebComponent { + static template = "
\n
"; + + static style = ` + .caret-wrapper { + display: inline; + position: relative; + width: 0; + } + + .caret { + background-color: rgb(96, 200, 240); + display: inline-block; + width: 2px; + border: 0; + padding: 0; + position: absolute; + left: -1px; + z-index: -1; + } + + .highlight { + background-color: rgb(96, 200, 240); + } + `; + + static observedAttributes = ['start', 'end', 'length']; + + renderCounter() { + let start = this.getAttribute('start'); + let end = this.getAttribute('end'); + + let topEl = this.shadowRoot.querySelector('.top'); + let topVal = ''; + + let bottomEl = this.shadowRoot.querySelector('.bottom'); + let bottomVal = ''; + + let length = Math.max(parseInt(this.getAttribute('length')), 1); + + for (var x = 0; x <= length; x++) { + if (start == x && end == x) { + bottomVal += ''; + } else { + if (start == x) { + bottomVal += ''; + } + + if (end == x) { + bottomVal += ''; + } + } + + bottomVal += x % 10; + + if (x % 10 == 0) { + topVal += x / 10; + } else { + topVal += ' '; + } + } + + topEl.innerHTML = topVal; + bottomEl.innerHTML = bottomVal; + + } + + attributeChangedCallback(attribute) { + switch (attribute) { + case 'start': + case 'end': + case 'length': + window.requestAnimationFrame(_ => this.renderCounter()); + break; + } + } +} diff --git a/packages/@atjson/editor/src/inspector-gadget/index.ts b/packages/@atjson/editor/src/inspector-gadget/index.ts new file mode 100644 index 000000000..7233120fc --- /dev/null +++ b/packages/@atjson/editor/src/inspector-gadget/index.ts @@ -0,0 +1,67 @@ +import AnnotationsInspector from './annotations-inspector'; +import CharacterCounter from './character-counter'; +import Document from '@atjson/document'; +import WebComponent from '../mixins/component'; + +if (!window.customElements.get('annotations-inspector')) { + window.customElements.define('annotations-inspector', AnnotationsInspector); +} + +if (!window.customElements.get('character-counter')) { + window.customElements.define('character-counter', CharacterCounter); +} + +export default class InspectorGadget extends WebComponent { + + static template = ` +

Character Counter

+
+ +
+ +

Annotations

+ `; + + static style = ` + :host { + position: fixed; + bottom: 0; + left: 0; + max-height: 50vh; + overflow: scroll-y; + } + + h1 { + font-size: 1em; + font-family: helvetica; + width: 100vw; + background-color: #cccccc; + padding: 4px; + } + + .cc-container { + max-width: 100vw; + overflow-x: auto; + } + `; + + document: Document; + + setDocument(doc) { + this.document = doc; + this.shadowRoot.querySelector('annotations-inspector').setDocument(doc); + this.document.addEventListener('change', (_ => { + let charCounter = this.shadowRoot.querySelector('character-counter'); + charCounter.setAttribute('length', this.document.content.length); + charCounter.innerHTML = "" + this.document.content.replace(/\n/g, "¶") + ""; + })); + } + + setSelection(el) { + el.addEventListener('change', evt => { + let charCounter = this.shadowRoot.querySelector('character-counter'); + charCounter.setAttribute('start', evt.detail.start); + charCounter.setAttribute('end', evt.detail.end); + }); + } +} From 2ed71a5c9db326acb7a5f9172ff5ffc046031500 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:02:03 +0100 Subject: [PATCH 035/104] Remove (currently unsupported) second paragraph from demo --- packages/@atjson/editor/public/app.ts | 3 +-- packages/@atjson/editor/public/index.html | 1 + packages/@atjson/editor/public/style.scss | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index c67c482f3..41fc17418 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -20,13 +20,12 @@ document.addEventListener('DOMContentLoaded', function () { editor.setDocument(new Document(JSON.parse(doc))); } else { let doc = new Document({ - content: 'Some text that is both bold and italic plus something after.\nA second paragraph.', + content: 'Some text that is both bold and italic plus something after.', annotations: [ { type: 'bold', display: 'inline', start: 23, end: 31 }, { type: 'italic', display: 'inline', start: 28, end: 38 }, { type: 'underline', display: 'inline', start: 28, end: 38 }, { type: 'paragraph', display: 'block', start: 0, end: 61 }, - { type: 'paragraph', display: 'block', start: 61, end: 80 } ] }); diff --git a/packages/@atjson/editor/public/index.html b/packages/@atjson/editor/public/index.html index 18c592d71..de886d004 100644 --- a/packages/@atjson/editor/public/index.html +++ b/packages/@atjson/editor/public/index.html @@ -1,6 +1,7 @@ + diff --git a/packages/@atjson/editor/public/style.scss b/packages/@atjson/editor/public/style.scss index 7fc28f96c..85fbea005 100644 --- a/packages/@atjson/editor/public/style.scss +++ b/packages/@atjson/editor/public/style.scss @@ -1,3 +1,3 @@ body { - -} \ No newline at end of file + margin: 2em; +} From 1b7a936041eaa82f074230f5f0fd0c554ed03894 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:03:34 +0100 Subject: [PATCH 036/104] Automatically descend to shadowRoot. Not sure if this is a good idea. --- packages/@atjson/editor/src/mixins/events.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/@atjson/editor/src/mixins/events.ts b/packages/@atjson/editor/src/mixins/events.ts index 84e2142d3..aca7a654c 100644 --- a/packages/@atjson/editor/src/mixins/events.ts +++ b/packages/@atjson/editor/src/mixins/events.ts @@ -22,7 +22,13 @@ function getEventNameAndElement(element: HTMLElement, definition: string) { } else if (selector === '') { return { eventName, element }; } else { - return { eventName, element: element.querySelector(selector) }; + let querySelector; + if (element.shadowRoot) { + querySelector = element.shadowRoot.querySelector(selector) || element.querySelector(selector); + } else { + querySelector = element.querySelector(selector); + } + return { eventName, element: querySelector }; } } From 5728e948fa57edb54c6521d7852a780b2088729c Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:04:11 +0100 Subject: [PATCH 037/104] update and pin parcel-bundler; 1.9.x seems broken --- packages/@atjson/editor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 814eb7fcf..764d23fd9 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -24,7 +24,7 @@ "@atjson/hir": "^0.8.0" }, "devDependencies": { - "parcel-bundler": "^1.7.0", + "parcel-bundler": "1.8.1", "ts-loader": "^4.0.0", "tslint": "^5.9.1", "typescript": "^2.6.2" From efe16bd6a1f31904989f4b982abaf803be7375cf Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:04:43 +0100 Subject: [PATCH 038/104] include web component base as a mixin --- .../@atjson/editor/src/mixins/component.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/@atjson/editor/src/mixins/component.ts b/packages/@atjson/editor/src/mixins/component.ts index e69de29bb..00bebd0dd 100644 --- a/packages/@atjson/editor/src/mixins/component.ts +++ b/packages/@atjson/editor/src/mixins/component.ts @@ -0,0 +1,34 @@ +import events from './events'; + +export default class WebComponent extends events(HTMLElement) { + static template: string; + static style: string | null; + private static compiledElement: Element; + + private static get compiledTemplate(): Element { + if (!this.compiledElement) { + this.compiledElement = document.createElement('template'); + let scopedStyles = this.style; + let html = this.template; + if (scopedStyles) { + html = `${html}`; + } + this.compiledElement.innerHTML = html; + } + return this.compiledElement; + } + + constructor() { + super(); + let shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); + } + + dispatchAttributeChangeEvent(attributes) { + let event = new CustomEvent('attributechange', { + detail: attributes, + bubbles: true + }); + this.dispatchEvent(event); + } +} From dc03b11d3b2b5516249ef06fb20398a63b7fd2e7 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:05:26 +0100 Subject: [PATCH 039/104] add support (and make explicit non-support) for various other input events --- packages/@atjson/editor/src/text-input.ts | 102 +++++++++++++++++++--- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 6362d5dab..bf5f9ed40 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -58,9 +58,16 @@ function getTextNodes(node: Node): Text[] { class TextInput extends events(HTMLElement) { static events = { 'beforeinput': 'beforeinput', - 'compositionend'() { - let { start } = this.selection; - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + 'drag'(evt) { + this.lastDragEvent = evt; + }, + 'compositionend'(evt) { + let { start, end } = this.selection; + if (start === end) { + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + } else { + this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); + } this.composing = false; }, 'change text-selection'(evt) { @@ -83,21 +90,41 @@ class TextInput extends events(HTMLElement) { switch (evt.inputType) { case 'insertText': - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); - break; - - case 'insertParagraph': - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: "\n" } })); + if (start === end) { + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + } else { + this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); + } break; case 'insertLineBreak': - console.log('start is', start, end); this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: '\u2028' } })); this.dispatchEvent(new CustomEvent('addAnnotation', { detail: { type: 'line-break', start, end: end + 1 } })); break; + case 'insertFromPaste': + var text = evt.dataTransfer.getData('text/plain'); + + if (start === end) { + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: text } })); + } else { + this.dispatchEvent(new CustomEvent('replaceText', { detail: { start: start, end: end, text: text } })); + } + break; + + case 'insertFromDrop': + var text = evt.dataTransfer.getData('text/plain'); + + var target = evt.getTargetRanges()[0]; + start = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); + + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: text } })); + + break; + + case 'deleteContentBackward': if (this.selection.collapsed) { start--; @@ -108,7 +135,8 @@ class TextInput extends events(HTMLElement) { break; case 'deleteWordBackward': - if (this.selection.collapsed) { + case 'deleteWordForward': + if (evt.inputType === 'deleteWordBackward' && this.selection.collapsed) { end++; } @@ -130,6 +158,14 @@ class TextInput extends events(HTMLElement) { })); break; + case 'deleteByCut': + case 'deleteContent': + case 'deleteByDrag': + this.dispatchEvent(new CustomEvent('deleteText', { + detail: { start, end } + })); + break; + case 'insertReplacementText': console.log('in here with evt', evt); // n.b. this assumes that there is only one target range. @@ -162,6 +198,52 @@ class TextInput extends events(HTMLElement) { detail: { start, end, type: 'italic' } })); break; + + case 'formatUnderline': + evt.preventDefault(); + break; + + case 'insertParagraph': + case 'insertOrderedList': + case 'insertUnorderedList': + case 'insertHorizontalRule': + case 'insertFromYank': + case 'insertTranspose': + case 'insertCompositionText': + case 'insertFromComposition': + case 'insertLink': + case 'deleteByComposition': + case 'deleteCompositionText': + case 'deleteSoftLineBackward': + case 'deleteSoftLineForward': + case 'deleteEntireSoftLine': + case 'deleteHardLineBackward': + case 'deleteHardLineForward': + case 'deleteContentBackward': + case 'deleteContentForward': + case 'historyUndo': + case 'historyRedo': + case 'formatStrikeThrough': + case 'formatSuperscript': + case 'formatSubscript': + case 'formatJustifyFull': + case 'formatJustifyCenter': + case 'formatJustifyRight': + case 'formatJustifyLeft': + case 'formatIndent': + case 'formatOutdent': + case 'formatRemove': + case 'formatSetBlockTextDirection': + case 'formatSetInlineTextDirection': + case 'formatBackColor': + case 'formatFontColor': + case 'formatFontName': + console.log('Unsupported Input Event: ', evt); + break; + + default + console.log('Unknown Input Event: ', evt); + break; } } From 3e1182e00200f9df8ec7922b0b71aafeb3002a8b Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:07:24 +0100 Subject: [PATCH 040/104] add toolbar that maps to selections --- packages/@atjson/editor/src/index.ts | 10 +++-- .../@atjson/editor/src/selection-toolbar.ts | 44 +++++++++++++++++++ packages/@atjson/editor/src/text-selection.ts | 4 ++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 packages/@atjson/editor/src/selection-toolbar.ts diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index ec247e8ff..e5e8af974 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -3,6 +3,7 @@ import WebComponentRenderer from './webcomponent-renderer'; import events from './mixins/events'; import './text-selection'; import './text-input'; +import './selection-toolbar'; const TEXT_NODE_TYPE = 3; type Range = { start: number, end: number }; @@ -13,12 +14,14 @@ export default class Editor extends events(HTMLElement) { selection: Range; - static template = '
'; + static template = '
'; static events = { 'change text-selection'(evt) { this.selection = evt.detail; - this.scheduleRender(); + let toolbar = this.querySelector('selection-toolbar'); + toolbar.setAttribute('start', evt.detail.start); + toolbar.setAttribute('end', evt.detail.end); }, 'insertText text-input'(evt) { @@ -50,7 +53,8 @@ export default class Editor extends events(HTMLElement) { this.selection.start = replacement.start + replacement.text.length; }, - 'addAnnotation text-input'(evt) { + 'addAnnotation'(evt) { + console.log('got annotation', evt); if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { const contained = (a, b) => a.start >= b.start && a.end <= b.end diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts new file mode 100644 index 000000000..f81675f33 --- /dev/null +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -0,0 +1,44 @@ +import WebComponent from './mixins/component'; + +export default class SelectionToolbar extends WebComponent { + static template = ''; + + static style = ` + :host { + border-radius: 4px; + } + `; + + static events = { + 'click': 'onClick' + } + + onClick(evt) { + let target = null; + for (var i = 0; i < evt.path.length; i++) { + console.log('got target', target); + if (evt.path[i].nodeName === 'BUTTON') { + target = evt.path[i]; + break; + } + } + + let type = target.getAttribute('data-type'); + console.log('got a click', evt, this.getAttribute('start'), this.getAttribute('end'), type); + let detail = { + type, + start: parseInt(this.getAttribute('start')), + end: parseInt(this.getAttribute('end')) + }; + + if (type === 'link') { + detail.attributes = { url: '' } + } + + this.dispatchEvent(new CustomEvent('addAnnotation', { bubbles: true, detail })); + } +} + +if (!window.customElements.get('selection-toolbar')) { + window.customElements.define('selection-toolbar', SelectionToolbar); +} diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index dc49e178d..4b51a827d 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -124,6 +124,10 @@ class TextSelection extends events(HTMLElement) { connectedCallback() { super.connectedCallback(); + let shadowRoot = this.attachShadow({mode: 'open'}); + let template = document.createElement('template'); + template.innerHTML = '
'; + shadowRoot.appendChild(template.content.cloneNode(true)); // Setup observers so when the underlying text changes, // we update the text nodes that we want to map our selection from From f51169fb778ac7f8e33ff31c0f3c75c65e4c01c8 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:08:03 +0100 Subject: [PATCH 041/104] handle the dom being a bit pants --- packages/@atjson/editor/src/text-selection.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 4b51a827d..12973d124 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -261,7 +261,14 @@ class TextSelection extends events(HTMLElement) { this.getNodeAndOffset(nodeRange[1], false) ]; - let isNonZeroRange = start[0] !== end[0] || start[1] !== end[1]; + // getNodeAndOffset throws in case the node doesn't exist in the + // document. Often, this happens if we've entered a context inside of a + // web component whose text nodes are not exposed via slots, so just do + // nothing. We don't want to clear the selection here because that may + // trigger unexpected problems in the state of editable components. + if (start === null || end === null) { + return; + } // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable @@ -270,6 +277,9 @@ class TextSelection extends events(HTMLElement) { return true; } + let isNonZeroRange = start[0] !== end[0] || start[1] !== end[1]; + + let domRange = document.createRange(); domRange.setStart(start[0], start[1]); domRange.setEnd(end[0], end[1]); From 54fb7a4df35cbf8249970e4429491e25d1989dbd Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:08:23 +0100 Subject: [PATCH 042/104] bugfixes; need more investigation --- packages/@atjson/editor/src/text-selection.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 12973d124..ea54758da 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -113,6 +113,13 @@ class TextSelection extends events(HTMLElement) { let selection = document.getSelection(); let r = document.createRange(); r.setStart(node, range.start - offset); + if (node.nodeType === 1) { + console.log('attempting to focus', node) + node.focus(); + } else if (node.nodeType === 3) { + console.log('attempting to focus', node.parentNode) + node.parentNode.focus(); + } selection.removeAllRanges(); selection.addRange(r); break; @@ -191,7 +198,8 @@ class TextSelection extends events(HTMLElement) { return nextTextNode(node); } - throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); + //throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); + return null // Firefox can return an offset that is the length // of the node list, which signifies that the node From 76946792940d3e4e49be72e6b1cf18fea5164c58 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:09:26 +0100 Subject: [PATCH 043/104] add caret focus events in order to activate web components that exist at the caret --- packages/@atjson/editor/src/text-selection.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index ea54758da..2bd06cead 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -315,6 +315,43 @@ class TextSelection extends events(HTMLElement) { return true; } + // Handle cursor focus/blur events for elements at a cursor position. + // + // If we're focused on a text node, that means we have a cursor. + if (selectionRange.focusNode.nodeType === 3) { + + // First, clear any existing focus. We do this first because in the next step, we reset it. + if (this._focusNode && (this._focusNode !== selectionRange.focusNode || range[0] !== range[1])) { + this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + delete this._focusNode; + } + + // If we have a collapsed range. + if (range[0] === range[1]) { + + // And the focused node is *not* the same as the previously focused node. + if (this._focusNode !== selectionRange.focusNode) { + + // then fire a focus event for parents of this text node to pick up. + this._focusNode = selectionRange.focusNode; + this._focusNode.dispatchEvent(new CustomEvent('cursorfocus', { bubbles: true })); + } + } + + } + + let toolbarStyle = this.shadowRoot.querySelector('.toolbar').style; + if (range[0] === range[1]) { + toolbarStyle.display = 'none'; + } else { + window.requestAnimationFrame(_ => { + let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); + toolbarStyle.display = 'block'; + toolbarStyle.top = selectionBoundingRect.y - selectionBoundingRect.height * 1.5; + toolbarStyle.left = selectionBoundingRect.x; + }); + } + this.setAttribute('start', range[0].toString()); this.setAttribute('end', range[1].toString()); this.dispatchEvent(new CustomEvent('change', { From 7873681496569e91a51799f161045ce0ea5a3f77 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:10:07 +0100 Subject: [PATCH 044/104] add event to track annotation changes --- packages/@atjson/editor/src/index.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index e5e8af974..387fd8072 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -87,14 +87,22 @@ export default class Editor extends events(HTMLElement) { } } + 'attributechange text-input'(evt) { + let annotationId = evt.target.getAttribute('data-annotation-id'); + let annotation = this.document.annotations.find(a => a.id.toString(10) === annotationId); + this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); + } + }; + get value() { + return this.document; + } + scheduleRender() { - console.log('schedule render called.'); window.requestAnimationFrame(() => { this.render(this.querySelector('.editor')); let evt = new CustomEvent('change', { bubbles: true, detail: { document: this.document } }); - console.log('dispatching event', evt); this.dispatchEvent(evt); }); } @@ -111,7 +119,6 @@ export default class Editor extends events(HTMLElement) { current: rendered.innerHTML, updated: editor.innerHTML }); - console.info('Rendering', this.document); editor.innerHTML = rendered.innerHTML; // We need to do a force-reset here in order to avoid waiting for a full @@ -131,6 +138,16 @@ export default class Editor extends events(HTMLElement) { setDocument(value: Document) { this.document = value; + + // n.b., would be good to have a way to query for existence of id on + // annotation (or to make ids required globally) + this.document.where({}).map(a => { + if (a.id !== undefined) return a; + + // this is not safe. + let id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); + return Object.assign(a, {id}); + }); this.document.addEventListener('change', (_ => this.scheduleRender() )); } From 6a7c8a44d321b1a072182c6351b768393486b931 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:10:25 +0100 Subject: [PATCH 045/104] add link annotation to default demo doc --- packages/@atjson/editor/public/app.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index 41fc17418..503cd731d 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -23,6 +23,7 @@ document.addEventListener('DOMContentLoaded', function () { content: 'Some text that is both bold and italic plus something after.', annotations: [ { type: 'bold', display: 'inline', start: 23, end: 31 }, + { type: 'link', display: 'inline', start: 20, end: 24, attributes: { url: 'https://google.com' } }, { type: 'italic', display: 'inline', start: 28, end: 38 }, { type: 'underline', display: 'inline', start: 28, end: 38 }, { type: 'paragraph', display: 'block', start: 0, end: 61 }, From a6ce2bea6977a134a1c795ae47de56f1ce1adcf4 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:10:40 +0100 Subject: [PATCH 046/104] add commonmark renderer dep --- packages/@atjson/editor/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 764d23fd9..aa0d54e8b 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -21,7 +21,9 @@ ], "dependencies": { "@atjson/document": "^0.7.16", - "@atjson/hir": "^0.8.0" + "@atjson/renderer-commonmark": "", + "@atjson/hir": "^0.8.0", + "node-sass": "^4.9.0" }, "devDependencies": { "parcel-bundler": "1.8.1", From 0014b05628abd3aa7fdf68b5674b772428e1dc70 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:11:24 +0100 Subject: [PATCH 047/104] Fix change tracking for documents --- packages/@atjson/document/src/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index f546f73ce..c95b4d318 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -59,7 +59,10 @@ export default class AtJSON { */ private triggerChange() { if (this.pendingChangeEvent) return; - this.pendingChangeEvent = setTimeout(_ => this.changeListeners.forEach(l => l()), 0) + this.pendingChangeEvent = setTimeout(_ => { + this.changeListeners.forEach(l => l()); + delete this.pendingChangeEvent; + }, 0) } /** @@ -106,9 +109,9 @@ export default class AtJSON { removeAnnotation(annotation: Annotation): Annotation | void { let index = this.annotations.indexOf(annotation); if (index > -1) { + this.triggerChange(); return this.annotations.splice(index, 1)[0]; } - this.triggerChange(); } replaceAnnotation(annotation: Annotation, ...newAnnotations: Annotation[]): void { From 3a6c6ebd61513480b5c1ba2a622604e39ab4955d Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 22 Jun 2018 00:12:05 +0100 Subject: [PATCH 048/104] add support for passing ids into hir/json nodes in order to have annotation id pass through to rendered doc. --- packages/@atjson/hir/src/hir-node.ts | 6 +++++- packages/@atjson/hir/src/json-node.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/@atjson/hir/src/hir-node.ts b/packages/@atjson/hir/src/hir-node.ts index edd878348..11a8a8202 100644 --- a/packages/@atjson/hir/src/hir-node.ts +++ b/packages/@atjson/hir/src/hir-node.ts @@ -20,6 +20,8 @@ export default class HIRNode { start: number; end: number; + id?: number|string; + text?: string; rank: number; @@ -28,10 +30,11 @@ export default class HIRNode { private sibling: HIRNode | undefined; private schema: Schema; - constructor(node: {type: string, start: number, end: number, display?: Display, attributes?: object, text?: string}, schema?: Schema) { + constructor(node: {type: string, start: number, end: number, display?: Display, id?: number|string, attributes?: object, text?: string}, schema?: Schema) { this.type = node.type; this.start = node.start; this.end = node.end; + this.id = node.id; this.attributes = Object.keys(node.attributes || {}).reduce((attrs: any, key: string) => { let value = (node.attributes as any)[key]; if (value instanceof Document) { @@ -78,6 +81,7 @@ export default class HIRNode { return { type: this.type, + id: this.id, attributes, children: this.children().map(child => { return child.toJSON(); diff --git a/packages/@atjson/hir/src/json-node.ts b/packages/@atjson/hir/src/json-node.ts index 45c846dd0..14d0c1e1c 100644 --- a/packages/@atjson/hir/src/json-node.ts +++ b/packages/@atjson/hir/src/json-node.ts @@ -2,6 +2,7 @@ export type Node = JSONNode | string; export default interface JSONNode { type: string; + id?: number|string; attributes?: { [key: string]: any }; children: Node[]; } From 1d66e2c5e18893d7a844210c5de2b8784071724f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 27 Jun 2018 14:32:10 -0400 Subject: [PATCH 049/104] set commonmark renderer version --- packages/@atjson/editor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index aa0d54e8b..23d182d7d 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -21,7 +21,7 @@ ], "dependencies": { "@atjson/document": "^0.7.16", - "@atjson/renderer-commonmark": "", + "@atjson/renderer-commonmark": "0.8.2", "@atjson/hir": "^0.8.0", "node-sass": "^4.9.0" }, From 533f6843ce886fd6b9fb6fc3145a5acfcf7e8115 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 27 Jun 2018 14:36:55 -0400 Subject: [PATCH 050/104] Refactor editable components for less boilerplate. --- packages/@atjson/editor/public/app.ts | 12 +- .../@atjson/editor/public/index-simple.html | 9 ++ .../editor/src/components/editable-link.ts | 62 ++++++++ .../editor/src/components/link-editor.ts | 98 +++++++++++++ .../@atjson/editor/src/editor-demo/index.ts | 8 ++ packages/@atjson/editor/src/index.ts | 31 ++-- .../editor/src/mixins/editable-component.ts | 60 ++++++++ .../@atjson/editor/src/selection-toolbar.ts | 2 +- packages/@atjson/editor/src/text-selection.ts | 78 ++++++---- .../components/editable-link.ts | 135 ------------------ .../editor/src/webcomponent-renderer/index.ts | 14 -- 11 files changed, 318 insertions(+), 191 deletions(-) create mode 100644 packages/@atjson/editor/public/index-simple.html create mode 100644 packages/@atjson/editor/src/components/editable-link.ts create mode 100644 packages/@atjson/editor/src/components/link-editor.ts create mode 100644 packages/@atjson/editor/src/mixins/editable-component.ts delete mode 100644 packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index 503cd731d..ce0ce36f8 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -1,10 +1,15 @@ import Document from '@atjson/document'; import EditorDemo from '../src/editor-demo'; +import Editor from '../src'; if (!window.customElements.get('text-editor-demo')) { window.customElements.define('text-editor-demo', EditorDemo); } +if (!window.customElements.get('text-editor')) { + window.customElements.define('text-editor', Editor); +} + // Web components in the registry can't be redefined, // so reload the page on every change if (module.hot) { @@ -14,7 +19,10 @@ if (module.hot) { } document.addEventListener('DOMContentLoaded', function () { - let editor: EditorDemo = document.querySelector('text-editor-demo'); + let editor = document.querySelector('text-editor-demo'); + if (editor === null) { + editor = document.querySelector('text-editor'); + } let doc = new URL(location.toString()).searchParams.get('document'); if (doc) { editor.setDocument(new Document(JSON.parse(doc))); @@ -26,7 +34,7 @@ document.addEventListener('DOMContentLoaded', function () { { type: 'link', display: 'inline', start: 20, end: 24, attributes: { url: 'https://google.com' } }, { type: 'italic', display: 'inline', start: 28, end: 38 }, { type: 'underline', display: 'inline', start: 28, end: 38 }, - { type: 'paragraph', display: 'block', start: 0, end: 61 }, + { type: 'paragraph', display: 'block', start: 0, end: 61 } ] }); diff --git a/packages/@atjson/editor/public/index-simple.html b/packages/@atjson/editor/public/index-simple.html new file mode 100644 index 000000000..d05d04fe1 --- /dev/null +++ b/packages/@atjson/editor/public/index-simple.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/@atjson/editor/src/components/editable-link.ts b/packages/@atjson/editor/src/components/editable-link.ts new file mode 100644 index 000000000..74ccd43a2 --- /dev/null +++ b/packages/@atjson/editor/src/components/editable-link.ts @@ -0,0 +1,62 @@ +import EditableComponent from '../mixins/editable-component'; +import LinkEditor from './link-editor'; + +if (!window.customElements.get('link-editor')) { + window.customElements.define('link-editor', LinkEditor); +} + +export default class EditableLink extends EditableComponent { + + static template = `
`; + + static observedAttributes = ['url', 'nofollow']; + + static style = EditableComponent.style + ` + a { + text-decoration: underline; + color: blue; + cursor: text; + } + `; + + static events = Object.assign({ + 'click .text-link': 'cancelLinkClick', + }, EditableComponent.events); + + static annotationName = 'link'; + + static elementRenderer = (node) => { + let link = document.createElement('editable-link'); + link.setAttribute('url', node.attributes.url); + if (node.attributes.nofollow) { + link.setAttribute('nofollow', ''); + } + return link; + } + + cancelLinkClick(evt) { + evt.preventDefault(); + } + + attributeChangedCallback(attribute) { + let link = this.shadowRoot.querySelector('a'); + let linkEditor = this.shadowRoot.querySelector('link-editor'); + switch (attribute) { + case 'url': + link.setAttribute('href', this.getAttribute('url')); + linkEditor.setAttribute('url', this.getAttribute('url')); + break; + case 'nofollow': + if (this.hasAttribute('nofollow')) { + linkEditor.setAttribute('nofollow', ''); + } else { + linkEditor.removeAttribute('nofollow'); + } + break; + } + } +} + +if (!window.customElements.get('editable-link')) { + window.customElements.define('editable-link', EditableLink); +} diff --git a/packages/@atjson/editor/src/components/link-editor.ts b/packages/@atjson/editor/src/components/link-editor.ts new file mode 100644 index 000000000..9cec07e5a --- /dev/null +++ b/packages/@atjson/editor/src/components/link-editor.ts @@ -0,0 +1,98 @@ +import WebComponent from '../mixins/component'; + +export default class LinkEditor extends WebComponent { + + static template = `🔗 
   `; + + static events = { + 'beforeinput': 'beforeInput', + 'click .cancel': 'cursorBlur', + 'click .save': 'onSave', + 'click .config': 'onConfig', + 'keypress .urlinput': 'handleKeypress' + }; + + static observedAttributes = ['url', 'nofollow']; + + static style = ` + :host { + display: flex; + } + + .extended { + display: none; + width: max-content; + } + + :host(.config) .default { + display: none; + } + + :host(.config) .extended { + display: block; + } + + :host(.config) button.config { + background: darkgrey; + } + `; + + onConfig() { + this.classList.toggle('config'); + } + + beforeInput(evt) { + evt.stopPropagation(); + } + + handleKeypress(evt) { + if (evt.keyCode === 13) { + this.onSave(evt); + } + } + + onSave(evt) { + let link = this.shadowRoot.querySelector('.urlinput'); + this.setAttribute('url', link.value); + + let nofollow = this.shadowRoot.querySelector('.nofollow'); + if (nofollow.checked) { + this.setAttribute('nofollow', ''); + } else { + this.removeAttribute('nofollow'); + } + + console.log('dispatching attributechange event'); + this.dispatchEvent(new CustomEvent('attributechange', { + bubbles: true, + composed: true, + detail: { + attributes: { + url: link.value, + nofollow: nofollow.checked + } + } + })); + + this.dispatchEvent(new CustomEvent('resumeinput', { bubbles: true, composed: true })); + + evt.stopPropagation(); + } + + attributeChangedCallback(attribute) { + let input = this.shadowRoot.querySelector('.urlinput'); + let nofollow = this.shadowRoot.querySelector('.nofollow'); + switch (attribute) { + case 'url': + input.setAttribute('value', this.getAttribute('url')); + break; + case 'nofollow': + nofollow.checked = this.hasAttribute('nofollow'); + break; + } + } +} + +if (!window.customElements.get('link-editor')) { + window.customElements.define('link-editor', LinkEditor); +} diff --git a/packages/@atjson/editor/src/editor-demo/index.ts b/packages/@atjson/editor/src/editor-demo/index.ts index 259855ba0..896545002 100644 --- a/packages/@atjson/editor/src/editor-demo/index.ts +++ b/packages/@atjson/editor/src/editor-demo/index.ts @@ -6,6 +6,8 @@ import InspectorGadget from '../inspector-gadget'; import OffsetLogo from './logo'; import events from '../mixins/events'; +import EditableLink from '../components/editable-link'; + if (!window.customElements.get('text-editor')) { window.customElements.define('text-editor', Editor); } @@ -45,7 +47,9 @@ export default class EditorDemo extends events(HTMLElement) { setDocument(doc: Document) { let editor = this.querySelector('text-editor'); + editor.setDocument(doc); + let inspectorGadget = this.querySelector('inspector-gadget'); inspectorGadget.setDocument(doc); inspectorGadget.setSelection(editor.getSelection()); @@ -58,6 +62,10 @@ export default class EditorDemo extends events(HTMLElement) { connectedCallback() { this.innerHTML = this.constructor.template; + + let editor = this.querySelector('text-editor'); + editor.addContentFeature(EditableLink); + super.connectedCallback(); } } diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 387fd8072..fad1c7fa6 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -54,7 +54,6 @@ export default class Editor extends events(HTMLElement) { }, 'addAnnotation'(evt) { - console.log('got annotation', evt); if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { const contained = (a, b) => a.start >= b.start && a.end <= b.end @@ -115,23 +114,10 @@ export default class Editor extends events(HTMLElement) { // prevent flickering of OS UI elements (e.g., spell check) while typing // characters that don't result in changes outside of text elements. if (rendered.innerHTML != editor.innerHTML) { - console.table({ - current: rendered.innerHTML, - updated: editor.innerHTML - }); editor.innerHTML = rendered.innerHTML; - // We need to do a force-reset here in order to avoid waiting for a full - // cycle of the browser event loop. The DOM has changed, but if we wait - // for the TextSelection MutationObserver to fire, the TextSelection - // model will have an old set of nodes (since we've just replaced them - // with new ones). - // - // PERF In the event of performance issues, this is a good candidate for - // optimization. if (this.selection) { - this.querySelector('text-selection').reset(); - this.querySelector('text-selection').setSelection(this.selection); + this.querySelector('text-selection').setSelection(this.selection, { suppressEvents: true }); } } } @@ -151,6 +137,16 @@ export default class Editor extends events(HTMLElement) { this.document.addEventListener('change', (_ => this.scheduleRender() )); } + addContentFeature(component) { + if (component.selectionButton) { + this.querySelector('selection-toolbar').shadowRoot.appendChild(component.selectionButton); + } + + if (component.annotationName) { + WebComponentRenderer.prototype[component.annotationName] = component.elementRenderer; + } + } + getSelection() { return this.querySelector('text-selection'); } @@ -160,6 +156,11 @@ export default class Editor extends events(HTMLElement) { super.connectedCallback(); this.scheduleRender(); } + + constructor() { + super(); + this.contentFeatures = []; + } } if (!window.customElements.get('text-editor')) { diff --git a/packages/@atjson/editor/src/mixins/editable-component.ts b/packages/@atjson/editor/src/mixins/editable-component.ts new file mode 100644 index 000000000..b3bf3a49e --- /dev/null +++ b/packages/@atjson/editor/src/mixins/editable-component.ts @@ -0,0 +1,60 @@ +import WebComponent from './component'; + +export default class EditableComponent extends WebComponent { + + static style = ` + :host { + position: relative; + outline: none; + } + + @keyframes showControls { + from { opacity: 0; } + to { opacity: 1; } + } + + .controls { + position: absolute; + top: -2.5em; + left: 0; + height: 1.5em; + vertical-align: baseline; + background-color: white; + padding: 3px; + border: 1px solid black; + white-space: normal; + } + + :host(:not(.cursorfocus)) .controls { + display: none; + } + + :host(.cursorfocus) .controls { + animation: showControls 200ms ease-in-out both; + display: flex; + }`; + + static events = { + 'cursorfocus': 'cursorFocus', + 'cursorblur': 'cursorBlur', + }; + + static get selectionButton() { + var el = document.createElement('button'); + el.setAttribute('data-type', this.annotationName); + el.innerHTML = this.annotationName; + return el; + } + + static elementRenderer = (node) => { + throw new Error('Element Renderer must be overriden'); + } + + cursorFocus() { + this.classList.add('cursorfocus'); + } + + cursorBlur() { + this.classList.remove('cursorfocus'); + } +} diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts index f81675f33..7480d91df 100644 --- a/packages/@atjson/editor/src/selection-toolbar.ts +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -1,7 +1,7 @@ import WebComponent from './mixins/component'; export default class SelectionToolbar extends WebComponent { - static template = ''; + static template = ``; static style = ` :host { diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 2bd06cead..30505db16 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -90,7 +90,8 @@ class TextSelection extends events(HTMLElement) { }, 'compositionend'() { this.composing = false; - } + }, + 'resumeinput': 'resumeInput' }; private textNodes: Text[]; @@ -103,6 +104,16 @@ class TextSelection extends events(HTMLElement) { } setSelection(range) { + // We need to do a force-reset here in order to avoid waiting for a full + // cycle of the browser event loop. The DOM has changed, but if we wait + // for the TextSelection MutationObserver to fire, the TextSelection + // model will have an old set of nodes (since we've just replaced them + // with new ones). + // + // PERF In the event of performance issues, this is a good candidate for + // optimization. + this.reset(); + let l = this.textNodes.length; let offset = 0; @@ -114,10 +125,8 @@ class TextSelection extends events(HTMLElement) { let r = document.createRange(); r.setStart(node, range.start - offset); if (node.nodeType === 1) { - console.log('attempting to focus', node) node.focus(); } else if (node.nodeType === 3) { - console.log('attempting to focus', node.parentNode) node.parentNode.focus(); } selection.removeAllRanges(); @@ -287,7 +296,6 @@ class TextSelection extends events(HTMLElement) { let isNonZeroRange = start[0] !== end[0] || start[1] !== end[1]; - let domRange = document.createRange(); domRange.setStart(start[0], start[1]); domRange.setEnd(end[0], end[1]); @@ -315,8 +323,24 @@ class TextSelection extends events(HTMLElement) { return true; } - // Handle cursor focus/blur events for elements at a cursor position. - // + this.handleCursorFocus(range, selectionRange); + this.updateToolbar(range, selectionRange); + + this.setAttribute('start', range[0].toString()); + this.setAttribute('end', range[1].toString()); + this.dispatchEvent(new CustomEvent('change', { + detail: { + start: range[0], + end: range[1], + collapsed: range[0] === range[1] + } + })); + return true; + } + + // Handle cursor focus/blur events for elements at a cursor position. + handleCursorFocus(range, selectionRange) { + // If we're focused on a text node, that means we have a cursor. if (selectionRange.focusNode.nodeType === 3) { @@ -328,18 +352,28 @@ class TextSelection extends events(HTMLElement) { // If we have a collapsed range. if (range[0] === range[1]) { - - // And the focused node is *not* the same as the previously focused node. - if (this._focusNode !== selectionRange.focusNode) { - - // then fire a focus event for parents of this text node to pick up. - this._focusNode = selectionRange.focusNode; - this._focusNode.dispatchEvent(new CustomEvent('cursorfocus', { bubbles: true })); + + if (!this._previousRange || range[0] !== this._previousRange[0]) { + // And the focused node is *not* the same as the previously focused node. + if (this._focusNode !== selectionRange.focusNode) { + + // then fire a focus event for parents of this text node to pick up. + this._focusNode = selectionRange.focusNode; + this._previousRange = range; + this._focusNode.dispatchEvent(new CustomEvent('cursorfocus', { bubbles: true })); + } + } else { + + // We don't want to re-fire (this case is likely encountered in a + // re-render), but since we don't have a _focusNode we just reset it + // here to prevent re-firing on the next selection change. + if (!this._focusNode) this._focusNode = selectionRange.focusNode; } } - } + } + updateToolbar(range, selectionRange) { let toolbarStyle = this.shadowRoot.querySelector('.toolbar').style; if (range[0] === range[1]) { toolbarStyle.display = 'none'; @@ -351,17 +385,13 @@ class TextSelection extends events(HTMLElement) { toolbarStyle.left = selectionBoundingRect.x; }); } + } - this.setAttribute('start', range[0].toString()); - this.setAttribute('end', range[1].toString()); - this.dispatchEvent(new CustomEvent('change', { - detail: { - start: range[0], - end: range[1], - collapsed: range[0] === range[1] - } - })); - return true; + resumeInput() { + if (this._previousRange) { + this.setSelection(this._previousRange); + this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + } } } diff --git a/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts b/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts deleted file mode 100644 index 567a515e3..000000000 --- a/packages/@atjson/editor/src/webcomponent-renderer/components/editable-link.ts +++ /dev/null @@ -1,135 +0,0 @@ -import WebComponent from '../../mixins/component'; - -export default class EditableLink extends WebComponent { - static template = `
🔗 
-    
`; - - static observedAttributes = ['url', 'nofollow']; - - static events = { - 'beforeinput': 'beforeInput', - 'cursorfocus': 'cursorFocus', - 'cursorblur': 'cursorBlur', - 'click .text-link': 'cancelLinkClick', - 'click .cancel': 'cursorBlur', - 'click .save': 'onSave', - 'click .config': 'onConfig', - 'keypress .urlinput': 'handleKeypress' - } - - static style = ` - :host { - position: relative; - outline: none; - } - - .controls { - display: none; - position: absolute; - top: -2.5em; - right: -10em; - height: 1.5em; - vertical-align: baseline; - background-color: white; - padding: 3px; - border: 1px solid black; - border-radius: 5px; - white-space: normal; - } - - a { - text-decoration: underline; - } - - .controls .extended { - display: none; - width: max-content; - } - - :host(.cursorfocus) .controls { - display: flex; - } - - :host(.config) .controls .default { - display: none; - } - - :host(.config) .controls .extended { - display: block; - } - - :host(.config) button.config { - background: darkgrey; - } - `; - - url: string; - nofollow: boolean; - - cursorFocus() { - this.classList.add('cursorfocus'); - } - - cursorBlur() { - console.trace('got cursor blur??'); - this.classList.remove('cursorfocus'); - this.classList.remove('config'); - } - - cancelLinkClick(evt) { - evt.preventDefault(); - } - - handleKeypress(evt) { - if (evt.keyCode === 13) { - this.onSave(evt); - } - } - - beforeInput(evt) { - evt.stopPropagation(); - } - - onConfig() { - this.classList.toggle('config'); - } - - onSave(evt) { - let link = this.shadowRoot.querySelector('.urlinput'); - this.setAttribute('url', link.value); - - let nofollow = this.shadowRoot.querySelector('.nofollow'); - if (nofollow.checked) { - this.setAttribute('nofollow', ''); - } else { - this.removeAttribute('nofollow'); - } - - console.log(nofollow); - - this.dispatchEvent(new CustomEvent('attributechange', { bubbles: true, detail: { - attributes: { - url: link.value, - nofollow: nofollow.checked - } - }})); - - this.cursorBlur(); - evt.stopPropagation(); - } - - attributeChangedCallback(attribute) { - let link = this.shadowRoot.querySelector('a'); - let input = this.shadowRoot.querySelector('.urlinput'); - let nofollow = this.shadowRoot.querySelector('.nofollow'); - switch (attribute) { - case 'url': - link.setAttribute('href', this.getAttribute('url')); - input.setAttribute('value', this.getAttribute('url')); - break; - case 'nofollow': - nofollow.checked = this.hasAttribute('nofollow'); - break; - } - } -} diff --git a/packages/@atjson/editor/src/webcomponent-renderer/index.ts b/packages/@atjson/editor/src/webcomponent-renderer/index.ts index e649076e6..310163ae8 100644 --- a/packages/@atjson/editor/src/webcomponent-renderer/index.ts +++ b/packages/@atjson/editor/src/webcomponent-renderer/index.ts @@ -1,9 +1,4 @@ import { HIR } from '@atjson/hir'; -import EditableLink from './components/editable-link'; - -if (!window.customElements.get('editable-link')) { - window.customElements.define('editable-link', EditableLink); -} export default class WebComponentRenderer { @@ -56,15 +51,6 @@ export default class WebComponentRenderer { return document.createElement('u'); } - link(node) { - let link = document.createElement('editable-link'); - link.setAttribute('url', node.attributes.url); - if (node.attributes.nofollow) { - link.setAttribute('nofollow', ''); - } - return link; - } - 'line-break'() { var parentElement = document.createElement('span'); parentElement.appendChild(document.createElement('br')); From 1226b64e1c7b986fe83f8f93852e251eb01c20fa Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 27 Jun 2018 16:10:15 -0400 Subject: [PATCH 051/104] tweak logo --- .../@atjson/editor/src/editor-demo/logo.ts | 137 +++++++++++++----- 1 file changed, 97 insertions(+), 40 deletions(-) diff --git a/packages/@atjson/editor/src/editor-demo/logo.ts b/packages/@atjson/editor/src/editor-demo/logo.ts index 77fe1a0da..2d8257998 100644 --- a/packages/@atjson/editor/src/editor-demo/logo.ts +++ b/packages/@atjson/editor/src/editor-demo/logo.ts @@ -5,11 +5,21 @@ export default class OffsetLogo extends WebComponent { static style = 'canvas { width: 300px; height: 150px; }'; - static observedAttributes = ['offset']; + static observedAttributes = ['offset', 'continuous']; - render() { - let x = parseInt(this.getAttribute('offset')); + initChannel(color, initialRotation, initialOffset, rotationAngleMultiplier, magicNumber) { + let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; + return { + color, + point: this.rotatePoint(initialRotation, { x: this.origin.x + initialOffset.x, y: this.origin.y + initialOffset.x }), + angle: rotationAngle * rotationAngleMultiplier, + dx: 0, + dtheta: 0, + magicNumber + } + } + initCanvas() { var canvas = this.shadowRoot.querySelector('canvas'); canvas.width = 300; canvas.height = 150; @@ -21,51 +31,98 @@ export default class OffsetLogo extends WebComponent { ctx.globalCompositeOperation = 'darken'; let fontSize = canvas.width / 7 + 'px'; - ctx.font = `${fontSize} Helvetica`; - - var origin = { x: 2, y: canvas.height / 4.0 }; - - let rotatePoint = (angle, point) => { - var radians = angle * Math.PI / 180.0; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var dX = point.x - origin.x; - var dY = point.y - origin.y; - var x = cos * dX - sin * dY + origin.x; - var y = sin * dX + cos * dY + origin.y; - return { x, y }; - } - - if (!this.cyanPoint) { - this.cyanPoint = { x: 0, y: canvas.height / 4.0 - 1 }; - this.magentaPoint = rotatePoint(120, { x: 0, y: canvas.height / 4.0 - 1 }); - this.yellowPoint = rotatePoint(240, { x: 0, y: canvas.height / 4.0 - 1 }); + ctx.font = `italic ${fontSize} Georgia`; + + this.origin = { x: 5, y: canvas.height / 4.0 }; + this.ctx = ctx; + + this.channels = [ + this.initChannel('cyan', 0, { x: -2, y: -2 }, 1, 5), + this.initChannel('magenta', 120, { x: -2, y: -2 }, -1, 95), + this.initChannel('yellow', 240, { x: -2, y: -2 }, 1, 50) + ]; + } + + rotatePoint(angle, point) { + var radians = angle * Math.PI / 180.0; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var dX = point.x - this.origin.x; + var dY = point.y - this.origin.y; + var x = cos * dX - sin * dY + this.origin.x; + var y = sin * dX + cos * dY + this.origin.y; + return { x, y }; + } + + drawOffset(point, color) { + this.ctx.fillStyle = color; + this.ctx.fillText('offset', point.x, point.y); + } + + mutateChannel(channel) { + var thetaSign = 1; + if (Math.random() < 0.25) thetaSign = -1; + + if (channel.dtheta < 1 && channel.dtheta > -1) { + channel.dtheta += thetaSign * Math.random() } - var rotationAngle = 2 * (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1); - - let drawOffset = (point, color) => { - var newPoint = rotatePoint(rotationAngle, point); - ctx.fillStyle = color; - ctx.fillText('Offset', newPoint.x, newPoint.y); - return newPoint; - } - - let drawOffsets = (angle) => { - ctx.clearRect(0, 0, 1000, 300); - console.log(angle, this.cyanPoint); - this.cyanPoint = drawOffset(this.cyanPoint, 'cyan'); - this.magentaPoint = drawOffset(this.magentaPoint, 'magenta'); - this.yellowPoint = drawOffset(this.yellowPoint, 'yellow'); - } - - drawOffsets(x); + + if (channel.angle < 0.05 && channel.angle > 0 ) { + channel.angle = -0.05; + } else if (channel.angle < 0 && channel.angle > -0.05) { + channel.angle = 0.05; + } + + var newAngle = channel.dtheta * channel.angle; + if (newAngle < 5 && newAngle > -5) { + channel.angle = newAngle; + } + + if (Math.random() < 0.5 && channel.dx < 2.5) { + channel.point.x += 0.5 / 3; + channel.dx += 0.5 / 3; + } else if (channel.dx > -2.5) { + channel.point.x -= 0.5 / 3; + channel.dx -= 0.5 / 3; + } + + return channel; + } + + drawChannel(channel) { + let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; + channel.point = this.rotatePoint(rotationAngle, channel.point); + this.drawOffset(channel.point, channel.color); + + if (Math.floor(Math.random()*100) !== channel.magicNumber) { + return channel; + } else { + return this.mutateChannel(channel); + } + } + + render() { + this.ctx.clearRect(0, 0, 1000, 300); + this.channels.map(c => this.drawChannel(c)); } attributeChangedCallback(attribute) { + if (!this.ctx) return; + this.render(); + + if (this.hasAttribute('continuous') && !this.loop) { + let loop = () => { + this.render(); + window.requestAnimationFrame(loop); + } + loop(); + this.loop = true; + } } connectedCallback() { + this.initCanvas(); this.render(); } } From 4b56a7f60a7edb065702ba1369c329c5024ff4bd Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 27 Jun 2018 16:33:18 -0400 Subject: [PATCH 052/104] move logo to components --- packages/@atjson/editor/src/{editor-demo => components}/logo.ts | 0 packages/@atjson/editor/src/editor-demo/index.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/@atjson/editor/src/{editor-demo => components}/logo.ts (100%) diff --git a/packages/@atjson/editor/src/editor-demo/logo.ts b/packages/@atjson/editor/src/components/logo.ts similarity index 100% rename from packages/@atjson/editor/src/editor-demo/logo.ts rename to packages/@atjson/editor/src/components/logo.ts diff --git a/packages/@atjson/editor/src/editor-demo/index.ts b/packages/@atjson/editor/src/editor-demo/index.ts index 896545002..d8542756b 100644 --- a/packages/@atjson/editor/src/editor-demo/index.ts +++ b/packages/@atjson/editor/src/editor-demo/index.ts @@ -3,7 +3,7 @@ import Editor from '../index'; import WebComponentRenderer from '../webcomponent-renderer'; import CommonmarkRenderer from '@atjson/renderer-commonmark'; import InspectorGadget from '../inspector-gadget'; -import OffsetLogo from './logo'; +import OffsetLogo from '../components/logo'; import events from '../mixins/events'; import EditableLink from '../components/editable-link'; From 36eab12345a1dc4f69a11d0291d49ea667e0d03a Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 11 Jul 2018 23:57:18 +0100 Subject: [PATCH 053/104] a few visual tweaks --- .../inspector-gadget/annotations-inspector.ts | 1 + .../editor/src/inspector-gadget/index.ts | 26 +++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts index e13f78d1e..758ce52ea 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts +++ b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts @@ -45,6 +45,7 @@ export default class AnnotationsInspector extends WebComponent { border-bottom: 1px solid black; border-top: 1px solid black; text-align: left; + background-color: #f3f3f3; } td { diff --git a/packages/@atjson/editor/src/inspector-gadget/index.ts b/packages/@atjson/editor/src/inspector-gadget/index.ts index 7233120fc..792dc35c6 100644 --- a/packages/@atjson/editor/src/inspector-gadget/index.ts +++ b/packages/@atjson/editor/src/inspector-gadget/index.ts @@ -14,12 +14,13 @@ if (!window.customElements.get('character-counter')) { export default class InspectorGadget extends WebComponent { static template = ` -

Character Counter

+

AtJSON Document Inspector

+

Content

-

Annotations

+

Annotations

`; static style = ` @@ -27,21 +28,36 @@ export default class InspectorGadget extends WebComponent { position: fixed; bottom: 0; left: 0; + right: 0; max-height: 50vh; - overflow: scroll-y; + margin: 1em; + overflow: hidden; + border: 1px solid #555555; + padding: 0; } h1 { font-size: 1em; font-family: helvetica; - width: 100vw; - background-color: #cccccc; + width: calc(100vw-2em); + background-color: #bbbbbb; + padding: 4px; + margin: 0; + } + + h2 { + margin: 0; + font-size: 0.75em; + font-family: helvetica; + width: calc(100vw-2em); + background-color: #dddddd; padding: 4px; } .cc-container { max-width: 100vw; overflow-x: auto; + margin: 0 6px 5px 6px; } `; From fcbdd6bdaa4462b86db5e060e0f626a68b351c9d Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 12:25:59 +0100 Subject: [PATCH 054/104] Don't redeclare loop variable. Oops. --- packages/@atjson/document/src/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index c95b4d318..a8b8fecce 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -131,7 +131,7 @@ export default class AtJSON { const after = this.content.slice(position); this.content = before + text + after; - for (var i = this.annotations.length - 1; i >= 0; i--) { + for (let i = this.annotations.length - 1; i >= 0; i--) { var a = this.annotations[i]; // annotation types that implement the Annotation transform interface can @@ -183,15 +183,13 @@ export default class AtJSON { } if (text.indexOf("\n") > -1) { - console.log('new line fun!!'); - for (var i = this.annotations.length - 1; i >= 0; i--) { - var a = this.annotations[i]; + for (let j = this.annotations.length - 1; j >= 0; j--) { + var a = this.annotations[j]; if (a.type === 'paragraph') { // This doesn't affect us. if (a.end < position) continue; if (position < a.start) continue; - console.log('going to add a new annotation'); var prevEnd = a.end; a.end = position + 1; this.addAnnotations({ From 9c3186e8d406e1002b48dfce9ae7b9b056f40f6c Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 12:30:01 +0100 Subject: [PATCH 055/104] Add a touch of documentation --- packages/@atjson/document/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index a8b8fecce..24eb30b8e 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -190,8 +190,11 @@ export default class AtJSON { if (a.end < position) continue; if (position < a.start) continue; + // First adjust the end of the current paragraph. var prevEnd = a.end; a.end = position + 1; + + // And now add a new paragraph. this.addAnnotations({ type: 'paragraph', start: position + 1, From 00186cd67f2d9efbca399a83b1ded99e48420457 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 14:24:16 +0100 Subject: [PATCH 056/104] Miscellaneous cleanup (debugging, indentation, etc) --- packages/@atjson/editor/src/components/logo.ts | 2 +- .../editor/src/inspector-gadget/annotation-attribute.ts | 1 - .../editor/src/inspector-gadget/annotation-inspector.ts | 3 --- .../editor/src/inspector-gadget/annotations-inspector.ts | 3 ++- packages/@atjson/editor/src/selection-toolbar.ts | 4 +--- packages/@atjson/editor/src/text-input.ts | 5 ----- 6 files changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/@atjson/editor/src/components/logo.ts b/packages/@atjson/editor/src/components/logo.ts index 2d8257998..5eed43b1a 100644 --- a/packages/@atjson/editor/src/components/logo.ts +++ b/packages/@atjson/editor/src/components/logo.ts @@ -90,7 +90,7 @@ export default class OffsetLogo extends WebComponent { } drawChannel(channel) { - let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; + let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; channel.point = this.rotatePoint(rotationAngle, channel.point); this.drawOffset(channel.point, channel.color); diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts b/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts index d03ea7e9f..c3743eb01 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts +++ b/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts @@ -6,7 +6,6 @@ export default class AnnotationAttribute extends WebComponent { static observedAttributes = ['name', 'value']; attributeChangedCallback(attribute) { - console.log('got this here', attribute, this.getAttribute(attribute)) switch (attribute) { case 'name': this.shadowRoot.querySelector('.name').innerHTML = this.getAttribute('name'); diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts b/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts index 1a4daba4b..c947d6d9e 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts +++ b/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts @@ -15,7 +15,6 @@ export default class AnnotationInspector extends WebComponent { static observedAttributes = ['type', 'start', 'end', 'attributes']; attributeChangedCallback(attribute) { - console.log('i am in here...'); switch (attribute) { case 'type': this.shadowRoot.querySelector('.type').innerHTML = this.getAttribute('type'); @@ -35,9 +34,7 @@ export default class AnnotationInspector extends WebComponent { } let inner = []; - console.log('i am here???'); this.shadowRoot.querySelector('.attributes').innerHTML = attributes.keys.map(key => { - console.log('adding thing ... ', key, attributes[key]); return `
`; this.shadowRoot.querySelector('.attributes'); }).join(''); diff --git a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts index 758ce52ea..108207f82 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts +++ b/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts @@ -80,7 +80,8 @@ export default class AnnotationsInspector extends WebComponent { tbody += `
` }); } else { - tbody += `` + tbody += `` + } }); this.shadowRoot.querySelector('tbody').innerHTML = tbody; } diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts index 7480d91df..80c13a8f7 100644 --- a/packages/@atjson/editor/src/selection-toolbar.ts +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -11,12 +11,11 @@ export default class SelectionToolbar extends WebComponent { static events = { 'click': 'onClick' - } + }; onClick(evt) { let target = null; for (var i = 0; i < evt.path.length; i++) { - console.log('got target', target); if (evt.path[i].nodeName === 'BUTTON') { target = evt.path[i]; break; @@ -24,7 +23,6 @@ export default class SelectionToolbar extends WebComponent { } let type = target.getAttribute('data-type'); - console.log('got a click', evt, this.getAttribute('start'), this.getAttribute('end'), type); let detail = { type, start: parseInt(this.getAttribute('start')), diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index bf5f9ed40..9a5e50daf 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -86,8 +86,6 @@ class TextInput extends events(HTMLElement) { let ranges = evt.getTargetRanges(); let { start, end } = this.selection; - console.log('here is a thing', evt); - switch (evt.inputType) { case 'insertText': if (start === end) { @@ -167,7 +165,6 @@ class TextInput extends events(HTMLElement) { break; case 'insertReplacementText': - console.log('in here with evt', evt); // n.b. this assumes that there is only one target range. if (evt.getTargetRanges().length !== 1) { throw new Error('Unhandled scenario. Breaking in an unelegant way. Expected exactly one target range in insertReplacementText handler, got', evt.getTargetRanges().length); @@ -177,8 +174,6 @@ class TextInput extends events(HTMLElement) { let replaceStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); let replaceEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); - console.log('found', {start: replaceStart, end: replaceEnd}, 'for target', target); - evt.dataTransfer.items[0].getAsString(replString => { this.dispatchEvent(new CustomEvent('replaceText', { detail: { start: replaceStart, end: replaceEnd, text: replString } From 069d576fd5c2077fde0c5e42c5d3e4a2edbb3e6e Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 14:34:12 +0100 Subject: [PATCH 057/104] Delete unused webcomponent renderer, pending proper extraction from editor. --- .../@atjson/renderer-webcomponent/.npmignore | 11 -------- .../@atjson/renderer-webcomponent/LICENSE | 1 - .../@atjson/renderer-webcomponent/README.md | 3 --- .../renderer-webcomponent/package.json | 26 ------------------- .../renderer-webcomponent/src/index.ts | 21 --------------- .../test/webcomponent-renderer-test.ts | 6 ----- .../renderer-webcomponent/tsconfig.json | 9 ------- .../@atjson/renderer-webcomponent/tslint.json | 1 - 8 files changed, 78 deletions(-) delete mode 100644 packages/@atjson/renderer-webcomponent/.npmignore delete mode 120000 packages/@atjson/renderer-webcomponent/LICENSE delete mode 100644 packages/@atjson/renderer-webcomponent/README.md delete mode 100644 packages/@atjson/renderer-webcomponent/package.json delete mode 100644 packages/@atjson/renderer-webcomponent/src/index.ts delete mode 100644 packages/@atjson/renderer-webcomponent/test/webcomponent-renderer-test.ts delete mode 100644 packages/@atjson/renderer-webcomponent/tsconfig.json delete mode 120000 packages/@atjson/renderer-webcomponent/tslint.json diff --git a/packages/@atjson/renderer-webcomponent/.npmignore b/packages/@atjson/renderer-webcomponent/.npmignore deleted file mode 100644 index 36040d0e2..000000000 --- a/packages/@atjson/renderer-webcomponent/.npmignore +++ /dev/null @@ -1,11 +0,0 @@ -.vscode -.travis.yml -dist/**/test -dist/**/node_modules -ember-cli-build.js -scripts -test -testem.js -tmp -tsconfig.json -tsling.json diff --git a/packages/@atjson/renderer-webcomponent/LICENSE b/packages/@atjson/renderer-webcomponent/LICENSE deleted file mode 120000 index 30cff7403..000000000 --- a/packages/@atjson/renderer-webcomponent/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE \ No newline at end of file diff --git a/packages/@atjson/renderer-webcomponent/README.md b/packages/@atjson/renderer-webcomponent/README.md deleted file mode 100644 index ae889f5d5..000000000 --- a/packages/@atjson/renderer-webcomponent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# @atjson/renderer-plain-text - -A brand new TypeScript library. diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json deleted file mode 100644 index 4217ce92f..000000000 --- a/packages/@atjson/renderer-webcomponent/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@atjson/renderer-webcomponent", - "version": "0.7.15", - "description": "A brand new TypeScript library.", - "main": "dist/commonjs/index.js", - "module": "dist/modules/index.js", - "types": "dist/commonjs/index.d.ts", - "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", - "lint": "../../../node_modules/.bin/tslint -c ../../../tslint.json 'src/**/*.ts'", - "prepublishOnly": "npm run build", - "test": "../../../node_modules/jest/bin/jest.js packages/$(basename $PWD) --config=../../../package.json" - }, - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "devDependencies": { - "@atjson/document": "^0.7.16", - "@atjson/hir": "^0.8.0", - "@atjson/source-html": "^0.8.0" - }, - "dependencies": { - "@atjson/renderer-hir": "^0.8.0" - } -} diff --git a/packages/@atjson/renderer-webcomponent/src/index.ts b/packages/@atjson/renderer-webcomponent/src/index.ts deleted file mode 100644 index e8f8c92e1..000000000 --- a/packages/@atjson/renderer-webcomponent/src/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Renderer, { escapeHTML } from '@atjson/renderer-hir'; -import { HIRNode } from '@atjson/hir'; - -export default class WebComponentRenderer extends Renderer { - - renderText(text: string) { - return escapeHTML(text); - } - - *renderAnnotation(node: HIRNode): IterableIterator { - let text = yield; - let attributes = node.attributes; - let attrs = ''; - if (attributes) { - // FIXME this is both buggy and incorrect, since many annotation - // attributes are not necessarily appropriate for inclusion in HTML. - attrs = Object.keys(attributes).map(key => `${key}='${attributes[key]}'`).join(' '); - } - return `<${node.type} ${attrs}>${text.join('')}`; - } -} diff --git a/packages/@atjson/renderer-webcomponent/test/webcomponent-renderer-test.ts b/packages/@atjson/renderer-webcomponent/test/webcomponent-renderer-test.ts deleted file mode 100644 index 8dc291160..000000000 --- a/packages/@atjson/renderer-webcomponent/test/webcomponent-renderer-test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import Document, { Annotation } from '@atjson/document'; -import WebComponentRenderer from '@atjson/renderer-webcomponent'; - -describe('PlainTextRenderer', function () { - it('renders the atjson document'); -}); diff --git a/packages/@atjson/renderer-webcomponent/tsconfig.json b/packages/@atjson/renderer-webcomponent/tsconfig.json deleted file mode 100644 index 58e586825..000000000 --- a/packages/@atjson/renderer-webcomponent/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist/commonjs" - }, - "include": [ - "src/**/*" - ] -} diff --git a/packages/@atjson/renderer-webcomponent/tslint.json b/packages/@atjson/renderer-webcomponent/tslint.json deleted file mode 120000 index 6fd001f22..000000000 --- a/packages/@atjson/renderer-webcomponent/tslint.json +++ /dev/null @@ -1 +0,0 @@ -tslint.json \ No newline at end of file From 9f1c406f745de1fc07a6663fa90266875b531c09 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 22:19:49 +0100 Subject: [PATCH 058/104] Remove unused code --- packages/@atjson/editor/src/index.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index fad1c7fa6..b56ed9b19 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -156,11 +156,6 @@ export default class Editor extends events(HTMLElement) { super.connectedCallback(); this.scheduleRender(); } - - constructor() { - super(); - this.contentFeatures = []; - } } if (!window.customElements.get('text-editor')) { From 2512639505931a80f484bb31aa7483e7b0a0a185 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 13 Jul 2018 22:20:59 +0100 Subject: [PATCH 059/104] Fix paragraph insertion. --- packages/@atjson/document/src/index.ts | 41 ++++++++++++----------- packages/@atjson/editor/src/text-input.ts | 6 ++++ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index 24eb30b8e..5bc82ec98 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -181,27 +181,28 @@ export default class AtJSON { } else if (position === a.end) { a.end += 0; } + } - if (text.indexOf("\n") > -1) { - for (let j = this.annotations.length - 1; j >= 0; j--) { - var a = this.annotations[j]; - if (a.type === 'paragraph') { - // This doesn't affect us. - if (a.end < position) continue; - if (position < a.start) continue; - - // First adjust the end of the current paragraph. - var prevEnd = a.end; - a.end = position + 1; - - // And now add a new paragraph. - this.addAnnotations({ - type: 'paragraph', - start: position + 1, - end: prevEnd + 1 - }); - } - } + if (text.indexOf("\n") > -1) { + for (let j = this.annotations.length - 1; j >= 0; j--) { + var a = this.annotations[j]; + + // This doesn't affect us. + if (a.type !== 'paragraph') continue; + if (a.end < position) continue; + if (position < a.start) continue; + + // First adjust the end of the current paragraph. + var prevEnd = a.end; + a.end = position + 1; + + // And now add a new paragraph. + this.addAnnotations({ + type: 'paragraph', + display: 'paragraph', + start: position + 1, + end: prevEnd + }); } } diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 9a5e50daf..2889cc695 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -199,6 +199,12 @@ class TextInput extends events(HTMLElement) { break; case 'insertParagraph': + evt.preventDefault(); + this.dispatchEvent(new CustomEvent('insertText', { + detail: { position: start, text: "\n" } + })); + break; + case 'insertOrderedList': case 'insertUnorderedList': case 'insertHorizontalRule': From 1ed8c1ea9d2fa0ea3e7aefe8afffcc770f29b159 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 16 Jul 2018 16:22:59 +0100 Subject: [PATCH 060/104] Cleanup --- packages/@atjson/document/src/index.ts | 53 ++++++++++++++------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index 5bc82ec98..5f6035bb8 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -13,10 +13,11 @@ export default class AtJSON { annotations: Annotation[]; schema?: Schema; changeListeners: Function[]; - private pendingChangeEvent: any; protected queries: Query[]; + private pendingChangeEvent: any; + constructor(options: { content: string, annotations?: Annotation[], contentType?: string, schema?: Schema } | string) { if (typeof options === 'string') { options = { content: options }; @@ -35,7 +36,7 @@ export default class AtJSON { * listeners and don't have internet access at the moment, so I'm just going * to quickly roll my own here. To be updated. */ - addEventListener(eventName: string, func: Function): void { + addEventListener(eventName: string, func: () => void): void { if (eventName !== 'change') throw new Error('Unsupported event. `change` is the only constant.'); this.changeListeners.push(func); } @@ -46,25 +47,6 @@ export default class AtJSON { } */ - /** - * This is really coarse, just enough to allow different code in the editor to detect - * changes in the document without handling that change management separately. - * - * Eventually it should be possible to handle this transactionally, but for - * now we batch all changes enacted within one cycle of the event loop and - * fire the change event only once. n.b that we don't send any information - * about the changes here yet, but that's not to say we couldn't, but rather - * it's not clear right now what the best approach would be so it's left - * undefined. - */ - private triggerChange() { - if (this.pendingChangeEvent) return; - this.pendingChangeEvent = setTimeout(_ => { - this.changeListeners.forEach(l => l()); - delete this.pendingChangeEvent; - }, 0) - } - /** * Annotations must be explicitly allowed unless they * are added to the annotations array directly- this is @@ -125,6 +107,7 @@ export default class AtJSON { insertText(position: number, text: string, preserveAdjacentBoundaries: boolean = false) { if (position < 0 || position > this.content.length) throw new Error('Invalid position.'); + let a: Annotation; const length = text.length; const before = this.content.slice(0, position); @@ -132,7 +115,7 @@ export default class AtJSON { this.content = before + text + after; for (let i = this.annotations.length - 1; i >= 0; i--) { - var a = this.annotations[i]; + a = this.annotations[i]; // annotation types that implement the Annotation transform interface can // override the default behaviour. This is desirable for e.g., links or @@ -183,9 +166,10 @@ export default class AtJSON { } } - if (text.indexOf("\n") > -1) { + if (text.indexOf('\n') > -1) { + let prevEnd: number; for (let j = this.annotations.length - 1; j >= 0; j--) { - var a = this.annotations[j]; + a = this.annotations[j]; // This doesn't affect us. if (a.type !== 'paragraph') continue; @@ -193,7 +177,7 @@ export default class AtJSON { if (position < a.start) continue; // First adjust the end of the current paragraph. - var prevEnd = a.end; + prevEnd = a.end; a.end = position + 1; // And now add a new paragraph. @@ -339,4 +323,23 @@ export default class AtJSON { this.triggerChange(); } + + /** + * This is really coarse, just enough to allow different code in the editor to detect + * changes in the document without handling that change management separately. + * + * Eventually it should be possible to handle this transactionally, but for + * now we batch all changes enacted within one cycle of the event loop and + * fire the change event only once. n.b that we don't send any information + * about the changes here yet, but that's not to say we couldn't, but rather + * it's not clear right now what the best approach would be so it's left + * undefined. + */ + private triggerChange() { + if (this.pendingChangeEvent) return; + this.pendingChangeEvent = setTimeout(_ => { + this.changeListeners.forEach(l => l()); + delete this.pendingChangeEvent; + }, 0); + } } From 451e5b9f0efa55cd761efe4b102eab74a9bce427 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 17 Jul 2018 01:04:25 +0100 Subject: [PATCH 061/104] tslint cleanups --- .../editor/src/components/link-editor.ts | 9 +- .../@atjson/editor/src/components/logo.ts | 58 +++--- .../@atjson/editor/src/editor-demo/index.ts | 46 +++-- packages/@atjson/editor/src/index.ts | 77 ++++---- .../@atjson/editor/src/mixins/component.ts | 2 +- .../editor/src/mixins/editable-component.ts | 10 +- .../@atjson/editor/src/selection-toolbar.ts | 18 +- packages/@atjson/editor/src/text-input.ts | 106 ++++++----- packages/@atjson/editor/src/text-selection.ts | 176 +++++++++--------- .../editor/src/webcomponent-renderer/index.ts | 37 ++-- 10 files changed, 293 insertions(+), 246 deletions(-) diff --git a/packages/@atjson/editor/src/components/link-editor.ts b/packages/@atjson/editor/src/components/link-editor.ts index 9cec07e5a..a754a989c 100644 --- a/packages/@atjson/editor/src/components/link-editor.ts +++ b/packages/@atjson/editor/src/components/link-editor.ts @@ -41,17 +41,17 @@ export default class LinkEditor extends WebComponent { this.classList.toggle('config'); } - beforeInput(evt) { + beforeInput(evt: Event) { evt.stopPropagation(); } - handleKeypress(evt) { + handleKeypress(evt: KeyboardEvent) { if (evt.keyCode === 13) { this.onSave(evt); } } - onSave(evt) { + onSave(evt: Event) { let link = this.shadowRoot.querySelector('.urlinput'); this.setAttribute('url', link.value); @@ -62,7 +62,6 @@ export default class LinkEditor extends WebComponent { this.removeAttribute('nofollow'); } - console.log('dispatching attributechange event'); this.dispatchEvent(new CustomEvent('attributechange', { bubbles: true, composed: true, @@ -79,7 +78,7 @@ export default class LinkEditor extends WebComponent { evt.stopPropagation(); } - attributeChangedCallback(attribute) { + attributeChangedCallback(attribute: string) { let input = this.shadowRoot.querySelector('.urlinput'); let nofollow = this.shadowRoot.querySelector('.nofollow'); switch (attribute) { diff --git a/packages/@atjson/editor/src/components/logo.ts b/packages/@atjson/editor/src/components/logo.ts index 5eed43b1a..47dfd5843 100644 --- a/packages/@atjson/editor/src/components/logo.ts +++ b/packages/@atjson/editor/src/components/logo.ts @@ -1,14 +1,18 @@ import WebComponent from '../mixins/component'; export default class OffsetLogo extends WebComponent { - static template = ''; + static template = ''; static style = 'canvas { width: 300px; height: 150px; }'; - static observedAttributes = ['offset', 'continuous']; + ctx: CanvasRenderingContext2D; + origin: { x: number, y: number }; + loop?: boolean; + channels?: any[]; + initChannel(color, initialRotation, initialOffset, rotationAngleMultiplier, magicNumber) { - let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; + let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2 / 3; return { color, point: this.rotatePoint(initialRotation, { x: this.origin.x + initialOffset.x, y: this.origin.y + initialOffset.x }), @@ -16,24 +20,26 @@ export default class OffsetLogo extends WebComponent { dx: 0, dtheta: 0, magicNumber - } + }; } initCanvas() { - var canvas = this.shadowRoot.querySelector('canvas'); + let canvas = this.shadowRoot.querySelector('canvas'); + if (canvas === null) return; canvas.width = 300; canvas.height = 150; - canvas.style.width = 150; - canvas.style.height = 75; + canvas.style.width = '150'; + canvas.style.height = '75'; - var ctx = canvas.getContext('2d'); + let ctx = canvas.getContext('2d'); + if (ctx === null) throw new Error('Unable to initialize Canvas'); ctx.scale(2, 2); ctx.globalCompositeOperation = 'darken'; let fontSize = canvas.width / 7 + 'px'; ctx.font = `italic ${fontSize} Georgia`; - this.origin = { x: 5, y: canvas.height / 4.0 }; + this.origin = { x: 5, y: canvas.height / 4.0 }; this.ctx = ctx; this.channels = [ @@ -43,28 +49,28 @@ export default class OffsetLogo extends WebComponent { ]; } - rotatePoint(angle, point) { - var radians = angle * Math.PI / 180.0; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var dX = point.x - this.origin.x; - var dY = point.y - this.origin.y; - var x = cos * dX - sin * dY + this.origin.x; - var y = sin * dX + cos * dY + this.origin.y; + rotatePoint(angle: number, point) { + let radians = angle * Math.PI / 180.0; + let cos = Math.cos(radians); + let sin = Math.sin(radians); + let dX = point.x - this.origin.x; + let dY = point.y - this.origin.y; + let x = cos * dX - sin * dY + this.origin.x; + let y = sin * dX + cos * dY + this.origin.y; return { x, y }; } - drawOffset(point, color) { + drawOffset(point, color) { this.ctx.fillStyle = color; this.ctx.fillText('offset', point.x, point.y); } mutateChannel(channel) { - var thetaSign = 1; + let thetaSign = 1; if (Math.random() < 0.25) thetaSign = -1; if (channel.dtheta < 1 && channel.dtheta > -1) { - channel.dtheta += thetaSign * Math.random() + channel.dtheta += thetaSign * Math.random(); } if (channel.angle < 0.05 && channel.angle > 0 ) { @@ -73,7 +79,7 @@ export default class OffsetLogo extends WebComponent { channel.angle = 0.05; } - var newAngle = channel.dtheta * channel.angle; + let newAngle = channel.dtheta * channel.angle; if (newAngle < 5 && newAngle > -5) { channel.angle = newAngle; } @@ -89,12 +95,12 @@ export default class OffsetLogo extends WebComponent { return channel; } - drawChannel(channel) { - let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2/3; + drawChannel(channel: any) { + let rotationAngle = (Math.abs(Math.cos(1 * Math.PI / 180.0)) + 1) * 2 / 3; channel.point = this.rotatePoint(rotationAngle, channel.point); this.drawOffset(channel.point, channel.color); - if (Math.floor(Math.random()*100) !== channel.magicNumber) { + if (Math.floor(Math.random() * 100) !== channel.magicNumber) { return channel; } else { return this.mutateChannel(channel); @@ -106,7 +112,7 @@ export default class OffsetLogo extends WebComponent { this.channels.map(c => this.drawChannel(c)); } - attributeChangedCallback(attribute) { + attributeChangedCallback() { if (!this.ctx) return; this.render(); @@ -115,7 +121,7 @@ export default class OffsetLogo extends WebComponent { let loop = () => { this.render(); window.requestAnimationFrame(loop); - } + }; loop(); this.loop = true; } diff --git a/packages/@atjson/editor/src/editor-demo/index.ts b/packages/@atjson/editor/src/editor-demo/index.ts index d8542756b..80ebace59 100644 --- a/packages/@atjson/editor/src/editor-demo/index.ts +++ b/packages/@atjson/editor/src/editor-demo/index.ts @@ -1,10 +1,10 @@ import Document from '@atjson/document'; -import Editor from '../index'; -import WebComponentRenderer from '../webcomponent-renderer'; import CommonmarkRenderer from '@atjson/renderer-commonmark'; -import InspectorGadget from '../inspector-gadget'; import OffsetLogo from '../components/logo'; +import Editor from '../index'; +import InspectorGadget from '../inspector-gadget'; import events from '../mixins/events'; +import WebComponentRenderer from '../webcomponent-renderer'; import EditableLink from '../components/editable-link'; @@ -22,41 +22,52 @@ if (!window.customElements.get('offset-logo')) { export default class EditorDemo extends events(HTMLElement) { static template = '

' + - '

HTML Output

' + + '

HTML Output

' + '

Commonmark Output

' + ''; static events = { - 'change text-editor'(evt) { + 'change text-editor'(evt: CustomEvent) { this.renderOutput(evt.detail.document); this.renderMarkdown(evt.detail.document); } - } + }; - renderOutput(doc) { + renderOutput(doc: Document) { let outputElement = this.querySelector('.output'); let rendered = new WebComponentRenderer(doc).render(); - outputElement.innerHTML = rendered.innerHTML; + if (outputElement) { + outputElement.innerHTML = rendered.innerHTML; + } } - renderMarkdown(doc) { + renderMarkdown(doc: Document) { let outputElement = this.querySelector('.markdown'); let rendered = new CommonmarkRenderer().render(doc); - outputElement.innerHTML = rendered; + if (outputElement) { + outputElement.innerHTML = rendered; + } } setDocument(doc: Document) { let editor = this.querySelector('text-editor'); + if (editor === null) return; + editor.setDocument(doc); let inspectorGadget = this.querySelector('inspector-gadget'); - inspectorGadget.setDocument(doc); - inspectorGadget.setSelection(editor.getSelection()); - doc.addEventListener('change', _ => { - let logo = this.querySelector('offset-logo'); - logo.setAttribute('offset', doc.content.length) + if (inspectorGadget) { + inspectorGadget.setDocument(doc); + inspectorGadget.setSelection(editor.getSelection()); + } + + doc.addEventListener('change', () => { + let logo = this.querySelector('offset-logo'); + if (logo) { + logo.setAttribute('offset', doc.content.length); + } }); } @@ -64,7 +75,10 @@ export default class EditorDemo extends events(HTMLElement) { this.innerHTML = this.constructor.template; let editor = this.querySelector('text-editor'); - editor.addContentFeature(EditableLink); + + if (editor) { + editor.addContentFeature(EditableLink); + } super.connectedCallback(); } diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index b56ed9b19..fe310a50c 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -1,36 +1,31 @@ -import Document from '@atjson/document'; -import WebComponentRenderer from './webcomponent-renderer'; +import Document, { Annotation } from '@atjson/document'; import events from './mixins/events'; -import './text-selection'; -import './text-input'; import './selection-toolbar'; +import './text-input'; +import './text-selection'; +import WebComponentRenderer from './webcomponent-renderer'; -const TEXT_NODE_TYPE = 3; type Range = { start: number, end: number }; -type Element = TextNode | HTMLElement; - export default class Editor extends events(HTMLElement) { - selection: Range; - static template = '
'; static events = { - 'change text-selection'(evt) { + 'change text-selection'(evt: CustomEvent) { this.selection = evt.detail; let toolbar = this.querySelector('selection-toolbar'); toolbar.setAttribute('start', evt.detail.start); toolbar.setAttribute('end', evt.detail.end); }, - 'insertText text-input'(evt) { + 'insertText text-input'(evt: CustomEvent) { this.document.insertText(evt.detail.position, evt.detail.text); this.selection.start += evt.detail.text.length; this.selection.end += evt.detail.text.length; }, - 'deleteText text-input'(evt) { + 'deleteText text-input'(evt: CustomEvent) { let deletion = evt.detail; this.document.deleteText(deletion); // FIXME the selection should just be an annotation that we transform. We shouldn't handle logic here. @@ -45,7 +40,7 @@ export default class Editor extends events(HTMLElement) { } }, - 'replaceText text-input'(evt) { + 'replaceText text-input'(evt: CustomEvent) { let replacement = evt.detail; this.document.deleteText(replacement); @@ -53,16 +48,16 @@ export default class Editor extends events(HTMLElement) { this.selection.start = replacement.start + replacement.text.length; }, - 'addAnnotation'(evt) { + 'addAnnotation'(evt: CustomEvent) { if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { - const contained = (a, b) => a.start >= b.start && a.end <= b.end - const offset = (a, b) => a.start <= b.end && a.end >= b.start - let overlapping = this.document.annotations.filter(a => a.type === evt.detail.type) - .filter(a => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); + const contained = (a: Annotation, b: Annotation) => a.start >= b.start && a.end <= b.end; + const offset = (a: Annotation, b: Annotation) => a.start <= b.end && a.end >= b.start; + let overlapping = this.document.annotations.filter((a: Annotation) => a.type === evt.detail.type) + .filter((a: Annotation) => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); - let min = overlapping.reduce((a, b) => { return Math.min(a, b.start) }, this.document.content.length) - let max = overlapping.reduce((a, b) => { return Math.max(a, b.end) }, 0) + let min = overlapping.reduce((a, b) => { return Math.min(a, b.start); }, this.document.content.length); + let max = overlapping.reduce((a, b) => { return Math.max(a, b.end); }, 0); if (overlapping.length === 0) { this.document.addAnnotations(evt.detail); @@ -72,7 +67,7 @@ export default class Editor extends events(HTMLElement) { let prev = overlapping[0]; let newFirst = Object.assign({}, prev, evt.detail, { start: prev.start, end: evt.detail.start }); let newLast = Object.assign({}, prev, evt.detail, { start: evt.detail.end, end: prev.end }); - if (min !== evt.detail.start) this.document.addAnnotations(newFirst) + if (min !== evt.detail.start) this.document.addAnnotations(newFirst); if (max !== evt.detail.end) this.document.addAnnotations(newLast); } else { @@ -84,40 +79,52 @@ export default class Editor extends events(HTMLElement) { } else { this.document.addAnnotations(evt.detail); } - } + }, - 'attributechange text-input'(evt) { - let annotationId = evt.target.getAttribute('data-annotation-id'); - let annotation = this.document.annotations.find(a => a.id.toString(10) === annotationId); - this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); + 'attributechange text-input'(evt: CustomEvent) { + if (evt.target !== null) { + let annotationId = evt.target.getAttribute('data-annotation-id'); + let annotation = this.document.annotations.find((a: Annotation) => a.id.toString(10) === annotationId); + this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); + } } }; + selection: Range | undefined; + document: Document | undefined; + get value() { return this.document; } scheduleRender() { window.requestAnimationFrame(() => { - this.render(this.querySelector('.editor')); - let evt = new CustomEvent('change', { bubbles: true, detail: { document: this.document } }); - this.dispatchEvent(evt); + let editor = this.querySelector('.editor'); + + if (editor !== null) { + this.render(editor); + let evt = new CustomEvent('change', { bubbles: true, detail: { document: this.document } }); + this.dispatchEvent(evt); + } }); } - render(editor) { + render(editor: Element) { let rendered = new WebComponentRenderer(this.document).render(); // This can be improved by doing the comparison on an element-by-element // basis (or by rendering incrementally via the HIR), but for now this will // prevent flickering of OS UI elements (e.g., spell check) while typing // characters that don't result in changes outside of text elements. - if (rendered.innerHTML != editor.innerHTML) { + if (rendered.innerHTML !== editor.innerHTML) { editor.innerHTML = rendered.innerHTML; if (this.selection) { - this.querySelector('text-selection').setSelection(this.selection, { suppressEvents: true }); + let textSelection = this.querySelector('text-selection'); + if (textSelection) { + textSelection.setSelection(this.selection, { suppressEvents: true }); + } } } } @@ -127,17 +134,17 @@ export default class Editor extends events(HTMLElement) { // n.b., would be good to have a way to query for existence of id on // annotation (or to make ids required globally) - this.document.where({}).map(a => { + this.document.where({}).map((a: Annotation) => { if (a.id !== undefined) return a; // this is not safe. let id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); return Object.assign(a, {id}); }); - this.document.addEventListener('change', (_ => this.scheduleRender() )); + this.document.addEventListener('change', (() => this.scheduleRender() )); } - addContentFeature(component) { + addContentFeature(component: any) { if (component.selectionButton) { this.querySelector('selection-toolbar').shadowRoot.appendChild(component.selectionButton); } diff --git a/packages/@atjson/editor/src/mixins/component.ts b/packages/@atjson/editor/src/mixins/component.ts index 00bebd0dd..ed9e74d42 100644 --- a/packages/@atjson/editor/src/mixins/component.ts +++ b/packages/@atjson/editor/src/mixins/component.ts @@ -24,7 +24,7 @@ export default class WebComponent extends events(HTMLElement) { shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); } - dispatchAttributeChangeEvent(attributes) { + dispatchAttributeChangeEvent(attributes: {}) { let event = new CustomEvent('attributechange', { detail: attributes, bubbles: true diff --git a/packages/@atjson/editor/src/mixins/editable-component.ts b/packages/@atjson/editor/src/mixins/editable-component.ts index b3bf3a49e..17f6fa248 100644 --- a/packages/@atjson/editor/src/mixins/editable-component.ts +++ b/packages/@atjson/editor/src/mixins/editable-component.ts @@ -35,18 +35,20 @@ export default class EditableComponent extends WebComponent { }`; static events = { - 'cursorfocus': 'cursorFocus', - 'cursorblur': 'cursorBlur', + cursorfocus: 'cursorFocus', + cursorblur: 'cursorBlur' }; + static annotationName: string; + static get selectionButton() { - var el = document.createElement('button'); + let el = document.createElement('button'); el.setAttribute('data-type', this.annotationName); el.innerHTML = this.annotationName; return el; } - static elementRenderer = (node) => { + static elementRenderer = () => { throw new Error('Element Renderer must be overriden'); } diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts index 80c13a8f7..2e0f14059 100644 --- a/packages/@atjson/editor/src/selection-toolbar.ts +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -10,12 +10,12 @@ export default class SelectionToolbar extends WebComponent { `; static events = { - 'click': 'onClick' + click: 'onClick' }; - onClick(evt) { + onClick(evt: MouseEvent) { let target = null; - for (var i = 0; i < evt.path.length; i++) { + for (let i of evt.path.length) { if (evt.path[i].nodeName === 'BUTTON') { target = evt.path[i]; break; @@ -23,14 +23,20 @@ export default class SelectionToolbar extends WebComponent { } let type = target.getAttribute('data-type'); + let start = this.getAttribute('start'); + let end = this.getAttribute('end'); + + if (start === null || end === null) return; + let detail = { type, - start: parseInt(this.getAttribute('start')), - end: parseInt(this.getAttribute('end')) + start: parseInt(start, 10), + end: parseInt(end, 10), + attributes: {} }; if (type === 'link') { - detail.attributes = { url: '' } + detail.attributes = { url: '' }; } this.dispatchEvent(new CustomEvent('addAnnotation', { bubbles: true, detail })); diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 2889cc695..4d39c1a26 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -2,13 +2,10 @@ import events from './mixins/events'; type Constructor = new (...args: any[]) => T; -const supports = { +/* const supports = { beforeinput: InputEvent.prototype.hasOwnProperty('inputType') }; - -function getRangeFrom() { - -} +*/ // n.b. this is duplicated from text-selection and should be refactored to be // included from a shared base. @@ -28,7 +25,6 @@ function getTextNodes(node: Node): Text[] { return nodes; } - /** * The keyboard mixin normalizes keyboard input across browsers. * This is due to varying levels of support by browser vendors @@ -58,33 +54,53 @@ function getTextNodes(node: Node): Text[] { class TextInput extends events(HTMLElement) { static events = { 'beforeinput': 'beforeinput', - 'drag'(evt) { - this.lastDragEvent = evt; - }, - 'compositionend'(evt) { - let { start, end } = this.selection; - if (start === end) { - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); - } else { - this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); - } - this.composing = false; - }, - 'change text-selection'(evt) { - this.selection = evt.detail; - }, - 'clear text-selection'() { - this.selection = null; - } + 'drag': 'drag', + 'compositionend': 'compositionend', + 'change text-selection': 'setSelection', + 'clear text-selection': 'clearSelection' }; + + private composing?: boolean; private selection?: { start: number, end: number, collapsed: boolean } | null; + private lastDragEvent?: Event; + + clearSelection() { + this.selection = null; + } + + setSelection(evt: CustomEvent) { + this.selection = evt.detail; + } + + drag(evt: Event) { + this.lastDragEvent = evt; + } + + compositionend(evt: CustomEvent) { + let { start, end } = this.selection; + if (start === end) { + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + } else { + this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); + } + this.composing = false; + } beforeinput(evt: InputEvent) { if (evt.isComposing) return; - let ranges = evt.getTargetRanges(); - let { start, end } = this.selection; + let start: number; + let end: number; + let text: string; + let target; + + if (this.selection) { + start = this.selection.start; + end = this.selection.end; + } else { + return; + } switch (evt.inputType) { case 'insertText': @@ -103,26 +119,25 @@ class TextInput extends events(HTMLElement) { break; case 'insertFromPaste': - var text = evt.dataTransfer.getData('text/plain'); + text = evt.dataTransfer.getData('text/plain'); if (start === end) { - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: text } })); + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text } })); } else { - this.dispatchEvent(new CustomEvent('replaceText', { detail: { start: start, end: end, text: text } })); + this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text } })); } break; case 'insertFromDrop': - var text = evt.dataTransfer.getData('text/plain'); + text = evt.dataTransfer.getData('text/plain'); - var target = evt.getTargetRanges()[0]; + target = evt.getTargetRanges()[0]; start = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: text } })); + this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text } })); break; - case 'deleteContentBackward': if (this.selection.collapsed) { start--; @@ -138,7 +153,7 @@ class TextInput extends events(HTMLElement) { end++; } - var target = evt.getTargetRanges()[0]; + target = evt.getTargetRanges()[0]; let deletionStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); let deletionEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); @@ -167,14 +182,14 @@ class TextInput extends events(HTMLElement) { case 'insertReplacementText': // n.b. this assumes that there is only one target range. if (evt.getTargetRanges().length !== 1) { - throw new Error('Unhandled scenario. Breaking in an unelegant way. Expected exactly one target range in insertReplacementText handler, got', evt.getTargetRanges().length); + throw new Error('Unhandled scenario. Breaking in an unelegant way. Expected exactly one target range in insertReplacementText handler, got ' + evt.getTargetRanges().length); } - var target = evt.getTargetRanges()[0]; + target = evt.getTargetRanges()[0]; let replaceStart = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); let replaceEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); - evt.dataTransfer.items[0].getAsString(replString => { + evt.dataTransfer.items[0].getAsString((replString: string) => { this.dispatchEvent(new CustomEvent('replaceText', { detail: { start: replaceStart, end: replaceEnd, text: replString } })); @@ -201,7 +216,7 @@ class TextInput extends events(HTMLElement) { case 'insertParagraph': evt.preventDefault(); this.dispatchEvent(new CustomEvent('insertText', { - detail: { position: start, text: "\n" } + detail: { position: start, text: '\n' } })); break; @@ -239,11 +254,11 @@ class TextInput extends events(HTMLElement) { case 'formatBackColor': case 'formatFontColor': case 'formatFontName': - console.log('Unsupported Input Event: ', evt); + // console.debug('Unsupported Input Event: ', evt); break; - default - console.log('Unknown Input Event: ', evt); + default: + // console.debug('Unknown Input Event: ', evt); break; } } @@ -253,7 +268,7 @@ class TextInput extends events(HTMLElement) { // offset to document offset directly. Not going to do it now to minimize // impact across the codebase, but flagging here as a potential and desirable // separate refactor. - nodeAndOffsetToDocumentOffset(node, offset): number { + nodeAndOffsetToDocumentOffset(node: Node, offset: number): number { let textNodes = getTextNodes(this); let l = textNodes.length; @@ -265,13 +280,14 @@ class TextInput extends events(HTMLElement) { if (currNode === node) { return currOffset + offset; } else { - currOffset += (currNode.nodeValue || '').length + currOffset += (currNode.nodeValue || '').length; } } - throw new Error('Did not find a matching node. Was matching against', node, textNodes); + // console.debug('No matching node', { node: node, textNodes: textNodes }); + throw new Error('Did not find a matching node. Was matching against'); } -}; +} customElements.define('text-input', TextInput); diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 30505db16..56cc6acc8 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -13,20 +13,6 @@ type NodeRangePoint = [MaybeNode, number]; type NodeRange = [NodeRangePoint, NodeRangePoint]; type TextRangePoint = [Text | null, number]; -function getTextNode(node: MaybeNode, trailing?: boolean): Text | null { - while (node && node.nodeType !== TEXT_NODE_TYPE && node != null) { - if (trailing) { - node = node.childNodes[node.childNodes.length - 1]; - } else { - node = node.childNodes[0]; - } - } - if (node) { - return node as Text; - } - return null; -} - function getTextNodes(node: Node): Text[] { let nodes: Text[] = []; @@ -73,29 +59,27 @@ function previousTextNode(node: Node): TextRangePoint { } /** - Events available for listening for : - - - `change`- called when the text selection changes - - `clear`- called when the text selecton is cleared + * Events available for listening for : + * + * @emits CustomEvent#change - called when the text selection changes + * @emits CustomEvent#clear - called when the text selecton is cleared */ class TextSelection extends events(HTMLElement) { - composing: boolean; - static observedAttributes = ['start', 'end']; static events = { 'selectionchange document': 'selectedTextDidChange', - 'compositionstart'() { - this.composing = true; - }, - 'compositionend'() { - this.composing = false; - }, + 'compositionstart': 'startComposition', + 'compositionend': 'endComposition', 'resumeinput': 'resumeInput' }; + composing: boolean; + private textNodes: Text[]; private observer?: MutationObserver | null; + private _focusNode?: Node | Text | null; + private _previousRange?: any; constructor() { super(); @@ -103,7 +87,15 @@ class TextSelection extends events(HTMLElement) { this.composing = false; } - setSelection(range) { + startComposition() { + this.composing = true; + } + + endComposition() { + this.composing = false; + } + + setSelection(range: {start: number, end: number}) { // We need to do a force-reset here in order to avoid waiting for a full // cycle of the browser event loop. The DOM has changed, but if we wait // for the TextSelection MutationObserver to fire, the TextSelection @@ -167,7 +159,63 @@ class TextSelection extends events(HTMLElement) { this.textNodes = []; } - private getNodeAndOffset([node, offset]: NodeRangePoint, leading: boolean): TextRangePoint | never { + // Handle cursor focus/blur events for elements at a cursor position. + handleCursorFocus(range, selectionRange) { + + // If we're focused on a text node, that means we have a cursor. + if (selectionRange.focusNode.nodeType === 3) { + + // First, clear any existing focus. We do this first because in the next step, we reset it. + if (this._focusNode && (this._focusNode !== selectionRange.focusNode || range[0] !== range[1])) { + this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + delete this._focusNode; + } + + // If we have a collapsed range. + if (range[0] === range[1]) { + + if (!this._previousRange || range[0] !== this._previousRange[0]) { + // And the focused node is *not* the same as the previously focused node. + if (this._focusNode !== selectionRange.focusNode) { + + // then fire a focus event for parents of this text node to pick up. + this._focusNode = selectionRange.focusNode; + this._previousRange = range; + this._focusNode.dispatchEvent(new CustomEvent('cursorfocus', { bubbles: true })); + } + } else { + + // We don't want to re-fire (this case is likely encountered in a + // re-render), but since we don't have a _focusNode we just reset it + // here to prevent re-firing on the next selection change. + if (!this._focusNode) this._focusNode = selectionRange.focusNode; + } + } + } + } + + updateToolbar(range, selectionRange) { + let toolbarStyle = this.shadowRoot.querySelector('.toolbar').style; + if (range[0] === range[1]) { + toolbarStyle.display = 'none'; + } else { + window.requestAnimationFrame(_ => { + let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); + toolbarStyle.display = 'block'; + toolbarStyle.top = selectionBoundingRect.y - selectionBoundingRect.height * 1.5; + toolbarStyle.left = selectionBoundingRect.x; + }); + } + } + + resumeInput() { + if (this._previousRange) { + this.setSelection(this._previousRange); + this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + } + } + + private getNodeAndOffset([node, offset]: NodeRangePoint, leading: boolean): TextRangePoint | never | null { // No node to get an offset for; bail if (node == null) { return [null, offset]; @@ -176,7 +224,7 @@ class TextSelection extends events(HTMLElement) { } else if (node.nodeType === TEXT_NODE_TYPE) { return [node as Text, offset]; - // If the node is outside the + // If the node is outside the } else if (!this.contains(node) && this !== node) { switch (this.compareDocumentPosition(node)) { case DOCUMENT_POSITION_PRECEDING: @@ -198,7 +246,7 @@ class TextSelection extends events(HTMLElement) { if (textNodes.length === 1) { return [textNodes[0], 0]; } - + // Find the closest text node and return that if (textNodes.length === 0) { if (leading) { @@ -207,8 +255,8 @@ class TextSelection extends events(HTMLElement) { return nextTextNode(node); } - //throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); - return null + // throw new Error("The selection for this node is ambiguous- we received a node with child nodes, but expected to get a leaf node"); + return null; // Firefox can return an offset that is the length // of the node list, which signifies that the node @@ -230,10 +278,10 @@ class TextSelection extends events(HTMLElement) { let firstNode = this.textNodes[0]; let lastNode = this.textNodes[this.textNodes.length - 1]; - if (firstNode.compareDocumentPosition(text) == DOCUMENT_POSITION_PRECEDING) { + if (firstNode.compareDocumentPosition(text) === DOCUMENT_POSITION_PRECEDING) { return [firstNode, 0]; - } else if (lastNode.compareDocumentPosition(text) == DOCUMENT_POSITION_FOLLOWING) { + } else if (lastNode.compareDocumentPosition(text) === DOCUMENT_POSITION_FOLLOWING) { return [lastNode, lastNode.length]; } @@ -289,7 +337,7 @@ class TextSelection extends events(HTMLElement) { // The selection range returned a selection with no base or extent; // This means that a node was selected that is not selectable - if (start[0] == null || end[0] == null) { + if (start[0] === null || end[0] === null) { this.clearSelection(); return true; } @@ -313,7 +361,7 @@ class TextSelection extends events(HTMLElement) { end = this.clampRangePoint(end); } - let lengths = nodes.map((node) => (node.nodeValue || '').length); + let lengths = nodes.map(node => (node.nodeValue || '').length); let range = [ lengths.slice(0, nodes.indexOf(start[0])).reduce(sum, start[1]), lengths.slice(0, nodes.indexOf(end[0])).reduce(sum, end[1]) @@ -337,62 +385,6 @@ class TextSelection extends events(HTMLElement) { })); return true; } - - // Handle cursor focus/blur events for elements at a cursor position. - handleCursorFocus(range, selectionRange) { - - // If we're focused on a text node, that means we have a cursor. - if (selectionRange.focusNode.nodeType === 3) { - - // First, clear any existing focus. We do this first because in the next step, we reset it. - if (this._focusNode && (this._focusNode !== selectionRange.focusNode || range[0] !== range[1])) { - this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); - delete this._focusNode; - } - - // If we have a collapsed range. - if (range[0] === range[1]) { - - if (!this._previousRange || range[0] !== this._previousRange[0]) { - // And the focused node is *not* the same as the previously focused node. - if (this._focusNode !== selectionRange.focusNode) { - - // then fire a focus event for parents of this text node to pick up. - this._focusNode = selectionRange.focusNode; - this._previousRange = range; - this._focusNode.dispatchEvent(new CustomEvent('cursorfocus', { bubbles: true })); - } - } else { - - // We don't want to re-fire (this case is likely encountered in a - // re-render), but since we don't have a _focusNode we just reset it - // here to prevent re-firing on the next selection change. - if (!this._focusNode) this._focusNode = selectionRange.focusNode; - } - } - } - } - - updateToolbar(range, selectionRange) { - let toolbarStyle = this.shadowRoot.querySelector('.toolbar').style; - if (range[0] === range[1]) { - toolbarStyle.display = 'none'; - } else { - window.requestAnimationFrame(_ => { - let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); - toolbarStyle.display = 'block'; - toolbarStyle.top = selectionBoundingRect.y - selectionBoundingRect.height * 1.5; - toolbarStyle.left = selectionBoundingRect.x; - }); - } - } - - resumeInput() { - if (this._previousRange) { - this.setSelection(this._previousRange); - this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); - } - } } customElements.define('text-selection', TextSelection); diff --git a/packages/@atjson/editor/src/webcomponent-renderer/index.ts b/packages/@atjson/editor/src/webcomponent-renderer/index.ts index 310163ae8..3ebec88f4 100644 --- a/packages/@atjson/editor/src/webcomponent-renderer/index.ts +++ b/packages/@atjson/editor/src/webcomponent-renderer/index.ts @@ -1,30 +1,33 @@ -import { HIR } from '@atjson/hir'; +import Document from '@atjson/document'; +import { HIR, HIRNode } from '@atjson/hir'; export default class WebComponentRenderer { - constructor(document) { + document: Document; + + constructor(document: Document) { this.document = document; } text({ text }) { - if (text[text.length - 1] == "\n") { - var nonBreakStrings = text.split("\n"); - if (nonBreakStrings[nonBreakStrings.length - 1] == '') { + if (text[text.length - 1] === '\n') { + let nonBreakStrings = text.split('\n'); + if (nonBreakStrings[nonBreakStrings.length - 1] === '') { nonBreakStrings.pop(); } - var children = nonBreakStrings.map((str: string) => { - var span = document.createElement('span'); + let children = nonBreakStrings.map((str: string) => { + let span = document.createElement('span'); span.style.whiteSpace = 'normal'; span.style.display = 'none'; - span.contentEditable = false; - span.appendChild(document.createTextNode("\n")); - return [document.createTextNode(str), span] - }).reduce((a, b) => a.concat(b)); + span.contentEditable = 'false'; + span.appendChild(document.createTextNode('\n')); + return [document.createTextNode(str), span]; + }).reduce((a: string, b: string) => a.concat(b)); - var textParentNode = document.createElement('span'); - children.forEach((child) => { + let textParentNode = document.createElement('span'); + children.forEach((child: Node) => { textParentNode.appendChild(child); - }) + }); return textParentNode; } @@ -52,7 +55,7 @@ export default class WebComponentRenderer { } 'line-break'() { - var parentElement = document.createElement('span'); + let parentElement = document.createElement('span'); parentElement.appendChild(document.createElement('br')); return parentElement; @@ -74,10 +77,12 @@ export default class WebComponentRenderer { return nodes.map((node: HIRNode) => { let children = node.children(); if (children.length > 0) { - let element = document.createElement('span'); + let element: Element; if (this[node.type]) { element = this[node.type](node); element.setAttribute('data-annotation-id', node.id); + } else { + element = document.createElement('span'); } hir.set(element, node); this.compile(hir, children).forEach((child: Element) => { From ee6529d1288eb7d3f92d61151dcb441a30b6f940 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 18 Jul 2018 00:48:55 +0100 Subject: [PATCH 062/104] Big reorg; move everything out of src except core bits, move webcomponent renderer to separate lib. --- packages/@atjson/editor/demo/app.ts | 40 +++++++++++++++++++ .../index.ts => demo/editor-demo.ts} | 28 +++++-------- .../index-simple.html => demo/index.html} | 2 +- packages/@atjson/editor/demo/style.scss | 3 ++ packages/@atjson/editor/package.json | 3 +- packages/@atjson/editor/public/app.ts | 13 +++--- packages/@atjson/editor/public/index.html | 2 +- .../editor/{src/components => public}/logo.ts | 0 .../editor/src/components/editable-link.ts | 8 ++-- packages/@atjson/editor/src/index.ts | 2 +- .../inspector-gadget/annotation-attribute.ts | 2 +- .../inspector-gadget/annotation-inspector.ts | 3 +- .../inspector-gadget/annotations-inspector.ts | 5 ++- .../inspector-gadget/character-counter.ts | 23 +++++------ .../{src => utils}/inspector-gadget/index.ts | 12 ++++-- .../@atjson/renderer-webcomponent/.npmignore | 11 +++++ .../@atjson/renderer-webcomponent/README.md | 3 ++ .../renderer-webcomponent/package.json | 26 ++++++++++++ .../src}/index.ts | 20 +++++++--- .../renderer-webcomponent/tsconfig.json | 9 +++++ .../@atjson/renderer-webcomponent/tslint.json | 30 ++++++++++++++ 21 files changed, 186 insertions(+), 59 deletions(-) create mode 100644 packages/@atjson/editor/demo/app.ts rename packages/@atjson/editor/{src/editor-demo/index.ts => demo/editor-demo.ts} (82%) rename packages/@atjson/editor/{public/index-simple.html => demo/index.html} (78%) create mode 100644 packages/@atjson/editor/demo/style.scss rename packages/@atjson/editor/{src/components => public}/logo.ts (100%) rename packages/@atjson/editor/{src => utils}/inspector-gadget/annotation-attribute.ts (90%) rename packages/@atjson/editor/{src => utils}/inspector-gadget/annotation-inspector.ts (94%) rename packages/@atjson/editor/{src => utils}/inspector-gadget/annotations-inspector.ts (94%) rename packages/@atjson/editor/{src => utils}/inspector-gadget/character-counter.ts (78%) rename packages/@atjson/editor/{src => utils}/inspector-gadget/index.ts (88%) create mode 100644 packages/@atjson/renderer-webcomponent/.npmignore create mode 100644 packages/@atjson/renderer-webcomponent/README.md create mode 100644 packages/@atjson/renderer-webcomponent/package.json rename packages/@atjson/{editor/src/webcomponent-renderer => renderer-webcomponent/src}/index.ts (84%) create mode 100644 packages/@atjson/renderer-webcomponent/tsconfig.json create mode 100644 packages/@atjson/renderer-webcomponent/tslint.json diff --git a/packages/@atjson/editor/demo/app.ts b/packages/@atjson/editor/demo/app.ts new file mode 100644 index 000000000..a86460560 --- /dev/null +++ b/packages/@atjson/editor/demo/app.ts @@ -0,0 +1,40 @@ +import Document from '@atjson/document'; +import EditorDemo from './editor-demo'; + +import EditableLink from '../src/components/editable-link'; + +if (!window.customElements.get('text-editor-demo')) { + window.customElements.define('text-editor-demo', EditorDemo); +} + +// Web components in the registry can't be redefined, +// so reload the page on every change +if (module.hot) { + module.hot.dispose(() => { + window.location.reload(); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + + let editor = document.querySelector('text-editor-demo'); + editor.addContentFeature(EditableLink); + + let doc = new URL(location.toString()).searchParams.get('document'); + if (doc) { + editor.setDocument(new Document(JSON.parse(doc))); + } else { + let doc = new Document({ + content: 'Some text that is both bold and italic plus something after.', + annotations: [ + { type: 'bold', display: 'inline', start: 23, end: 31 }, + { type: 'link', display: 'inline', start: 20, end: 24, attributes: { url: 'https://google.com' } }, + { type: 'italic', display: 'inline', start: 28, end: 38 }, + { type: 'underline', display: 'inline', start: 28, end: 38 }, + { type: 'paragraph', display: 'block', start: 0, end: 61 } + ] + }); + + editor.setDocument(doc); + } +}); diff --git a/packages/@atjson/editor/src/editor-demo/index.ts b/packages/@atjson/editor/demo/editor-demo.ts similarity index 82% rename from packages/@atjson/editor/src/editor-demo/index.ts rename to packages/@atjson/editor/demo/editor-demo.ts index 80ebace59..f80937fc7 100644 --- a/packages/@atjson/editor/src/editor-demo/index.ts +++ b/packages/@atjson/editor/demo/editor-demo.ts @@ -1,12 +1,10 @@ import Document from '@atjson/document'; import CommonmarkRenderer from '@atjson/renderer-commonmark'; -import OffsetLogo from '../components/logo'; -import Editor from '../index'; -import InspectorGadget from '../inspector-gadget'; -import events from '../mixins/events'; -import WebComponentRenderer from '../webcomponent-renderer'; - -import EditableLink from '../components/editable-link'; +import WebComponentRenderer from '@atjson/renderer-webcomponent'; +import OffsetLogo from '../public/logo'; +import Editor from '../src/index'; +import events from '../src/mixins/events'; +import InspectorGadget from '../utils/inspector-gadget'; if (!window.customElements.get('text-editor')) { window.customElements.define('text-editor', Editor); @@ -16,10 +14,6 @@ if (!window.customElements.get('inspector-gadget')) { window.customElements.define('inspector-gadget', InspectorGadget); } -if (!window.customElements.get('offset-logo')) { - window.customElements.define('offset-logo', OffsetLogo); -} - export default class EditorDemo extends events(HTMLElement) { static template = '

' + '

HTML Output

' + @@ -49,6 +43,11 @@ export default class EditorDemo extends events(HTMLElement) { } } + addContentFeature(component) { + let editor = this.querySelector('text-editor'); + editor.addContentFeature(component); + } + setDocument(doc: Document) { let editor = this.querySelector('text-editor'); @@ -73,13 +72,6 @@ export default class EditorDemo extends events(HTMLElement) { connectedCallback() { this.innerHTML = this.constructor.template; - - let editor = this.querySelector('text-editor'); - - if (editor) { - editor.addContentFeature(EditableLink); - } - super.connectedCallback(); } } diff --git a/packages/@atjson/editor/public/index-simple.html b/packages/@atjson/editor/demo/index.html similarity index 78% rename from packages/@atjson/editor/public/index-simple.html rename to packages/@atjson/editor/demo/index.html index d05d04fe1..de886d004 100644 --- a/packages/@atjson/editor/public/index-simple.html +++ b/packages/@atjson/editor/demo/index.html @@ -4,6 +4,6 @@ - + diff --git a/packages/@atjson/editor/demo/style.scss b/packages/@atjson/editor/demo/style.scss new file mode 100644 index 000000000..85fbea005 --- /dev/null +++ b/packages/@atjson/editor/demo/style.scss @@ -0,0 +1,3 @@ +body { + margin: 2em; +} diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 23d182d7d..3e6933223 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -21,6 +21,7 @@ ], "dependencies": { "@atjson/document": "^0.7.16", + "@atjson/renderer-webcomponent": "0.8.0", "@atjson/renderer-commonmark": "0.8.2", "@atjson/hir": "^0.8.0", "node-sass": "^4.9.0" @@ -29,6 +30,6 @@ "parcel-bundler": "1.8.1", "ts-loader": "^4.0.0", "tslint": "^5.9.1", - "typescript": "^2.6.2" + "typescript": "^2.8.1" } } diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index ce0ce36f8..cfa1c4f4e 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -1,10 +1,7 @@ import Document from '@atjson/document'; -import EditorDemo from '../src/editor-demo'; import Editor from '../src'; -if (!window.customElements.get('text-editor-demo')) { - window.customElements.define('text-editor-demo', EditorDemo); -} +import EditableLink from '../src/components/editable-link'; if (!window.customElements.get('text-editor')) { window.customElements.define('text-editor', Editor); @@ -19,10 +16,10 @@ if (module.hot) { } document.addEventListener('DOMContentLoaded', function () { - let editor = document.querySelector('text-editor-demo'); - if (editor === null) { - editor = document.querySelector('text-editor'); - } + + let editor = document.querySelector('text-editor'); + editor.addContentFeature(EditableLink); + let doc = new URL(location.toString()).searchParams.get('document'); if (doc) { editor.setDocument(new Document(JSON.parse(doc))); diff --git a/packages/@atjson/editor/public/index.html b/packages/@atjson/editor/public/index.html index de886d004..d05d04fe1 100644 --- a/packages/@atjson/editor/public/index.html +++ b/packages/@atjson/editor/public/index.html @@ -4,6 +4,6 @@ - + diff --git a/packages/@atjson/editor/src/components/logo.ts b/packages/@atjson/editor/public/logo.ts similarity index 100% rename from packages/@atjson/editor/src/components/logo.ts rename to packages/@atjson/editor/public/logo.ts diff --git a/packages/@atjson/editor/src/components/editable-link.ts b/packages/@atjson/editor/src/components/editable-link.ts index 74ccd43a2..65cfc6080 100644 --- a/packages/@atjson/editor/src/components/editable-link.ts +++ b/packages/@atjson/editor/src/components/editable-link.ts @@ -20,12 +20,12 @@ export default class EditableLink extends EditableComponent { `; static events = Object.assign({ - 'click .text-link': 'cancelLinkClick', + 'click .text-link': 'cancelLinkClick' }, EditableComponent.events); static annotationName = 'link'; - static elementRenderer = (node) => { + static elementRenderer(node: any): Element { let link = document.createElement('editable-link'); link.setAttribute('url', node.attributes.url); if (node.attributes.nofollow) { @@ -34,11 +34,11 @@ export default class EditableLink extends EditableComponent { return link; } - cancelLinkClick(evt) { + cancelLinkClick(evt: MouseEvent) { evt.preventDefault(); } - attributeChangedCallback(attribute) { + attributeChangedCallback(attribute: string) { let link = this.shadowRoot.querySelector('a'); let linkEditor = this.shadowRoot.querySelector('link-editor'); switch (attribute) { diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index fe310a50c..eabfa5bd2 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -1,9 +1,9 @@ import Document, { Annotation } from '@atjson/document'; +import WebComponentRenderer from '@atjson/renderer-webcomponent'; import events from './mixins/events'; import './selection-toolbar'; import './text-input'; import './text-selection'; -import WebComponentRenderer from './webcomponent-renderer'; type Range = { start: number, end: number }; diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts b/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts similarity index 90% rename from packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts rename to packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts index c3743eb01..edb01fe22 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotation-attribute.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts @@ -1,4 +1,4 @@ -import WebComponent from '../mixins/component'; +import WebComponent from '../../src/mixins/component'; export default class AnnotationAttribute extends WebComponent { static template = ' = ' diff --git a/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts b/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts similarity index 94% rename from packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts rename to packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts index c947d6d9e..d70f9a0e2 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotation-inspector.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts @@ -1,4 +1,4 @@ -import WebComponent from '../mixins/component'; +import WebComponent from '../../src/mixins/component'; import AnnotationAttribute from './annotation-attribute'; export default class AnnotationInspector extends WebComponent { @@ -26,6 +26,7 @@ export default class AnnotationInspector extends WebComponent { this.shadowRoot.querySelector('.end').innerHTML = this.getAttribute('end'); break; case 'attributes': + let attributes; try { attributes = JSON.parse(this.getAttribute('attributes')); } catch { diff --git a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts similarity index 94% rename from packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts rename to packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts index 108207f82..4fcdeb2b3 100644 --- a/packages/@atjson/editor/src/inspector-gadget/annotations-inspector.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts @@ -1,5 +1,6 @@ +import Document from '@atjson/document'; +import WebComponent from '../../src/mixins/component'; import AnnotationInspector from './annotation-attribute'; -import WebComponent from '../mixins/component'; if (!window.customElements.get('annotation-attribute')) { window.customElements.define('annotation-attribute', AnnotationInspector); @@ -71,6 +72,8 @@ export default class AnnotationsInspector extends WebComponent { } `; + document: Document; + updateTBody() { let tbody = ''; this.document.annotations.forEach((a) => { diff --git a/packages/@atjson/editor/src/inspector-gadget/character-counter.ts b/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts similarity index 78% rename from packages/@atjson/editor/src/inspector-gadget/character-counter.ts rename to packages/@atjson/editor/utils/inspector-gadget/character-counter.ts index 4bcc8d314..7079a5fb7 100644 --- a/packages/@atjson/editor/src/inspector-gadget/character-counter.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts @@ -1,4 +1,4 @@ -import WebComponent from '../mixins/component'; +import WebComponent from '../../src/mixins/component'; export default class CharacterCounter extends WebComponent { static template = "
\n
"; @@ -9,7 +9,7 @@ export default class CharacterCounter extends WebComponent { position: relative; width: 0; } - + .caret { background-color: rgb(96, 200, 240); display: inline-block; @@ -29,8 +29,8 @@ export default class CharacterCounter extends WebComponent { static observedAttributes = ['start', 'end', 'length']; renderCounter() { - let start = this.getAttribute('start'); - let end = this.getAttribute('end'); + let start = parseInt(this.getAttribute('start'), 10); + let end = parseInt(this.getAttribute('end'), 10); let topEl = this.shadowRoot.querySelector('.top'); let topVal = ''; @@ -38,24 +38,24 @@ export default class CharacterCounter extends WebComponent { let bottomEl = this.shadowRoot.querySelector('.bottom'); let bottomVal = ''; - let length = Math.max(parseInt(this.getAttribute('length')), 1); + let length = Math.max(parseInt(this.getAttribute('length'), 10), 1); - for (var x = 0; x <= length; x++) { - if (start == x && end == x) { + for (let x = 0; x <= length; x++) { + if (start === x && end === x) { bottomVal += ''; } else { - if (start == x) { + if (start === x) { bottomVal += ''; } - - if (end == x) { + + if (end === x) { bottomVal += ''; } } bottomVal += x % 10; - if (x % 10 == 0) { + if (x % 10 === 0) { topVal += x / 10; } else { topVal += ' '; @@ -64,7 +64,6 @@ export default class CharacterCounter extends WebComponent { topEl.innerHTML = topVal; bottomEl.innerHTML = bottomVal; - } attributeChangedCallback(attribute) { diff --git a/packages/@atjson/editor/src/inspector-gadget/index.ts b/packages/@atjson/editor/utils/inspector-gadget/index.ts similarity index 88% rename from packages/@atjson/editor/src/inspector-gadget/index.ts rename to packages/@atjson/editor/utils/inspector-gadget/index.ts index 792dc35c6..1be89594a 100644 --- a/packages/@atjson/editor/src/inspector-gadget/index.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/index.ts @@ -1,7 +1,7 @@ +import Document from '@atjson/document'; +import WebComponent from '../../src/mixins/component'; import AnnotationsInspector from './annotations-inspector'; import CharacterCounter from './character-counter'; -import Document from '@atjson/document'; -import WebComponent from '../mixins/component'; if (!window.customElements.get('annotations-inspector')) { window.customElements.define('annotations-inspector', AnnotationsInspector); @@ -19,7 +19,7 @@ export default class InspectorGadget extends WebComponent {
- +

Annotations

`; @@ -69,7 +69,7 @@ export default class InspectorGadget extends WebComponent { this.document.addEventListener('change', (_ => { let charCounter = this.shadowRoot.querySelector('character-counter'); charCounter.setAttribute('length', this.document.content.length); - charCounter.innerHTML = "" + this.document.content.replace(/\n/g, "¶") + ""; + charCounter.innerHTML = '' + this.document.content.replace(/\n/g, '¶') + ''; })); } @@ -81,3 +81,7 @@ export default class InspectorGadget extends WebComponent { }); } } + +if (!window.customElements.get('inspector-gadget')) { + window.customElements.define('inspector-gadget', InspectorGadget); +} diff --git a/packages/@atjson/renderer-webcomponent/.npmignore b/packages/@atjson/renderer-webcomponent/.npmignore new file mode 100644 index 000000000..36040d0e2 --- /dev/null +++ b/packages/@atjson/renderer-webcomponent/.npmignore @@ -0,0 +1,11 @@ +.vscode +.travis.yml +dist/**/test +dist/**/node_modules +ember-cli-build.js +scripts +test +testem.js +tmp +tsconfig.json +tsling.json diff --git a/packages/@atjson/renderer-webcomponent/README.md b/packages/@atjson/renderer-webcomponent/README.md new file mode 100644 index 000000000..04d22040d --- /dev/null +++ b/packages/@atjson/renderer-webcomponent/README.md @@ -0,0 +1,3 @@ +# @atjson/renderer-webcomponent + +A brand new TypeScript library. diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json new file mode 100644 index 000000000..1cbf83a7f --- /dev/null +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -0,0 +1,26 @@ +{ + "name": "@atjson/renderer-webcomponent", + "version": "0.8.0", + "description": "A brand new TypeScript library.", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "scripts": { + "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "prepublishOnly": "npm run build", + "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" + }, + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@atjson/document": "^0.7.16", + "@atjson/hir": "^0.8.0" + }, + "dependencies": { + "@atjson/hir": "^0.8.0", + "@atjson/renderer-hir": "^0.8.0" + } +} diff --git a/packages/@atjson/editor/src/webcomponent-renderer/index.ts b/packages/@atjson/renderer-webcomponent/src/index.ts similarity index 84% rename from packages/@atjson/editor/src/webcomponent-renderer/index.ts rename to packages/@atjson/renderer-webcomponent/src/index.ts index 3ebec88f4..d7aa252fc 100644 --- a/packages/@atjson/editor/src/webcomponent-renderer/index.ts +++ b/packages/@atjson/renderer-webcomponent/src/index.ts @@ -22,7 +22,7 @@ export default class WebComponentRenderer { span.contentEditable = 'false'; span.appendChild(document.createTextNode('\n')); return [document.createTextNode(str), span]; - }).reduce((a: string, b: string) => a.concat(b)); + }).reduce((a, b) => a.concat(b)); let textParentNode = document.createElement('span'); children.forEach((child: Node) => { @@ -78,9 +78,11 @@ export default class WebComponentRenderer { let children = node.children(); if (children.length > 0) { let element: Element; - if (this[node.type]) { + if (typeof (this as any)[node.type] === 'function') { element = this[node.type](node); - element.setAttribute('data-annotation-id', node.id); + if (node.id) { + element.setAttribute('data-annotation-id', node.id.toString()); + } } else { element = document.createElement('span'); } @@ -89,10 +91,16 @@ export default class WebComponentRenderer { element.appendChild(child); }); return element; + } else { + let text; + if (typeof (this as any)[node.type] === 'function') { + text = this[node.type](node); + } else { + text = ''; + } + hir.set(text, node); + return text; } - let text = this[node.type](node); - hir.set(text, node); - return text; }); } } diff --git a/packages/@atjson/renderer-webcomponent/tsconfig.json b/packages/@atjson/renderer-webcomponent/tsconfig.json new file mode 100644 index 000000000..58e586825 --- /dev/null +++ b/packages/@atjson/renderer-webcomponent/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist/commonjs" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/@atjson/renderer-webcomponent/tslint.json b/packages/@atjson/renderer-webcomponent/tslint.json new file mode 100644 index 000000000..30612ee31 --- /dev/null +++ b/packages/@atjson/renderer-webcomponent/tslint.json @@ -0,0 +1,30 @@ +{ + "extends": "tslint:recommended", + "defaultSeverity": "warning", + "rules": { + "arrow-parens": [true, "ban-single-arg-parens"], + "curly": [true, "ignore-same-line"], + "forin": false, + "interface-name": [true, "never-prefix"], + "max-classes-per-file": [false], + "max-line-length": [false], + "member-access": [true, "no-public"], + "no-empty-interface": false, + "object-literal-sort-keys": false, + "ordered-imports": [ + true, + { + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-last" + } + ], + "prefer-const": false, + "quotemark": [true, "single"], + "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], + "whitespace": [true, + "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", + "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" + ] + } +} From c6980d361295854d6e21d149aababe3bc8a2a27e Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 18 Jul 2018 13:15:22 +0100 Subject: [PATCH 063/104] Incr parcel version --- packages/@atjson/editor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 3e6933223..3d3f1f8bb 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -27,7 +27,7 @@ "node-sass": "^4.9.0" }, "devDependencies": { - "parcel-bundler": "1.8.1", + "parcel-bundler": "1.9.7", "ts-loader": "^4.0.0", "tslint": "^5.9.1", "typescript": "^2.8.1" From 10459fa9e2e0f58ebec0795b831430880078d593 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 18 Jul 2018 13:18:37 +0100 Subject: [PATCH 064/104] Update method for importing web components, s/text-editor/offset-editor/ --- packages/@atjson/editor/demo/app.ts | 9 +-- packages/@atjson/editor/demo/editor-demo.ts | 62 ++++++------------- packages/@atjson/editor/demo/index.html | 2 +- packages/@atjson/editor/public/app.ts | 14 ++--- packages/@atjson/editor/public/index.html | 3 +- packages/@atjson/editor/public/logo.ts | 8 ++- .../editor/src/components/editable-link.ts | 6 +- packages/@atjson/editor/src/index.ts | 9 +-- .../editor/src/mixins/editable-component.ts | 2 +- packages/@atjson/editor/src/mixins/events.ts | 4 +- .../inspector-gadget/annotation-attribute.ts | 4 ++ .../inspector-gadget/annotation-inspector.ts | 6 +- .../inspector-gadget/annotations-inspector.ts | 10 +-- .../inspector-gadget/character-counter.ts | 4 ++ .../editor/utils/inspector-gadget/index.ts | 12 +--- 15 files changed, 66 insertions(+), 89 deletions(-) diff --git a/packages/@atjson/editor/demo/app.ts b/packages/@atjson/editor/demo/app.ts index a86460560..9d36684dd 100644 --- a/packages/@atjson/editor/demo/app.ts +++ b/packages/@atjson/editor/demo/app.ts @@ -1,12 +1,9 @@ import Document from '@atjson/document'; -import EditorDemo from './editor-demo'; +import './editor-demo'; +import OffsetEditor from '../src'; import EditableLink from '../src/components/editable-link'; -if (!window.customElements.get('text-editor-demo')) { - window.customElements.define('text-editor-demo', EditorDemo); -} - // Web components in the registry can't be redefined, // so reload the page on every change if (module.hot) { @@ -17,7 +14,7 @@ if (module.hot) { document.addEventListener('DOMContentLoaded', () => { - let editor = document.querySelector('text-editor-demo'); + let editor: OffsetEditor = document.querySelector('offset-editor'); editor.addContentFeature(EditableLink); let doc = new URL(location.toString()).searchParams.get('document'); diff --git a/packages/@atjson/editor/demo/editor-demo.ts b/packages/@atjson/editor/demo/editor-demo.ts index f80937fc7..abb0080b8 100644 --- a/packages/@atjson/editor/demo/editor-demo.ts +++ b/packages/@atjson/editor/demo/editor-demo.ts @@ -1,34 +1,29 @@ import Document from '@atjson/document'; import CommonmarkRenderer from '@atjson/renderer-commonmark'; import WebComponentRenderer from '@atjson/renderer-webcomponent'; -import OffsetLogo from '../public/logo'; -import Editor from '../src/index'; -import events from '../src/mixins/events'; +import '../public/logo'; +import '../src/index'; +import WebComponent from '../src/mixins/component'; +import '../utils/inspector-gadget'; import InspectorGadget from '../utils/inspector-gadget'; -if (!window.customElements.get('text-editor')) { - window.customElements.define('text-editor', Editor); -} - -if (!window.customElements.get('inspector-gadget')) { - window.customElements.define('inspector-gadget', InspectorGadget); -} - -export default class EditorDemo extends events(HTMLElement) { - static template = '

' + +export default class OffsetEditorDemo extends WebComponent { + static template = '

' + '

HTML Output

' + '

Commonmark Output

' + ''; static events = { - 'change text-editor'(evt: CustomEvent) { + 'change'(evt: CustomEvent) { + console.log('GOT CHANGE!', evt); this.renderOutput(evt.detail.document); this.renderMarkdown(evt.detail.document); + this.renderInspector(evt.detail.document); } }; renderOutput(doc: Document) { - let outputElement = this.querySelector('.output'); + let outputElement = this.shadowRoot.querySelector('.output'); let rendered = new WebComponentRenderer(doc).render(); if (outputElement) { outputElement.innerHTML = rendered.innerHTML; @@ -36,46 +31,27 @@ export default class EditorDemo extends events(HTMLElement) { } renderMarkdown(doc: Document) { - let outputElement = this.querySelector('.markdown'); + let outputElement = this.shadowRoot.querySelector('.markdown'); let rendered = new CommonmarkRenderer().render(doc); if (outputElement) { outputElement.innerHTML = rendered; } } - addContentFeature(component) { - let editor = this.querySelector('text-editor'); - editor.addContentFeature(component); - } - - setDocument(doc: Document) { - let editor = this.querySelector('text-editor'); - - if (editor === null) return; - - editor.setDocument(doc); - - let inspectorGadget = this.querySelector('inspector-gadget'); + renderInspector(doc: Document) { + // This is really ineffecient, because we're calling it every document + // change at the moment. To fix this, we need a new "changedocument" or + // similar event on the editor. + let inspectorGadget: InspectorGadget = this.shadowRoot.querySelector('inspector-gadget'); + let editor = this.querySelector('offset-editor'); if (inspectorGadget) { inspectorGadget.setDocument(doc); inspectorGadget.setSelection(editor.getSelection()); } - - doc.addEventListener('change', () => { - let logo = this.querySelector('offset-logo'); - if (logo) { - logo.setAttribute('offset', doc.content.length); - } - }); - } - - connectedCallback() { - this.innerHTML = this.constructor.template; - super.connectedCallback(); } } -if (!window.customElements.get('text-editor-demo')) { - window.customElements.define('text-editor-demo', EditorDemo); +if (!window.customElements.get('offset-editor-demo')) { + window.customElements.define('offset-editor-demo', OffsetEditorDemo); } diff --git a/packages/@atjson/editor/demo/index.html b/packages/@atjson/editor/demo/index.html index de886d004..85f017712 100644 --- a/packages/@atjson/editor/demo/index.html +++ b/packages/@atjson/editor/demo/index.html @@ -4,6 +4,6 @@ - + diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index cfa1c4f4e..526d24a10 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -1,23 +1,21 @@ import Document from '@atjson/document'; -import Editor from '../src'; +import '../src'; +import OffsetEditor from '../src'; +import './logo'; import EditableLink from '../src/components/editable-link'; -if (!window.customElements.get('text-editor')) { - window.customElements.define('text-editor', Editor); -} - // Web components in the registry can't be redefined, // so reload the page on every change if (module.hot) { - module.hot.dispose(function () { + module.hot.dispose(() => { window.location.reload(); }); } -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener('DOMContentLoaded', () => { - let editor = document.querySelector('text-editor'); + let editor: OffsetEditor = document.querySelector('offset-editor'); editor.addContentFeature(EditableLink); let doc = new URL(location.toString()).searchParams.get('document'); diff --git a/packages/@atjson/editor/public/index.html b/packages/@atjson/editor/public/index.html index d05d04fe1..b81b8893e 100644 --- a/packages/@atjson/editor/public/index.html +++ b/packages/@atjson/editor/public/index.html @@ -4,6 +4,7 @@ - + + diff --git a/packages/@atjson/editor/public/logo.ts b/packages/@atjson/editor/public/logo.ts index 47dfd5843..cc5c47a63 100644 --- a/packages/@atjson/editor/public/logo.ts +++ b/packages/@atjson/editor/public/logo.ts @@ -1,10 +1,9 @@ -import WebComponent from '../mixins/component'; +import WebComponent from '../src/mixins/component'; export default class OffsetLogo extends WebComponent { static template = ''; static style = 'canvas { width: 300px; height: 150px; }'; - static observedAttributes = ['offset', 'continuous']; ctx: CanvasRenderingContext2D; origin: { x: number, y: number }; @@ -128,7 +127,12 @@ export default class OffsetLogo extends WebComponent { } connectedCallback() { + super.connectedCallback(); this.initCanvas(); this.render(); } } + +if (!window.customElements.get('offset-logo')) { + window.customElements.define('offset-logo', OffsetLogo); +} diff --git a/packages/@atjson/editor/src/components/editable-link.ts b/packages/@atjson/editor/src/components/editable-link.ts index 65cfc6080..5da7072d5 100644 --- a/packages/@atjson/editor/src/components/editable-link.ts +++ b/packages/@atjson/editor/src/components/editable-link.ts @@ -1,9 +1,5 @@ import EditableComponent from '../mixins/editable-component'; -import LinkEditor from './link-editor'; - -if (!window.customElements.get('link-editor')) { - window.customElements.define('link-editor', LinkEditor); -} +import './link-editor'; export default class EditableLink extends EditableComponent { diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index eabfa5bd2..771892e55 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -7,7 +7,7 @@ import './text-selection'; type Range = { start: number, end: number }; -export default class Editor extends events(HTMLElement) { +export default class OffsetEditor extends events(HTMLElement) { static template = '
'; @@ -104,7 +104,7 @@ export default class Editor extends events(HTMLElement) { if (editor !== null) { this.render(editor); - let evt = new CustomEvent('change', { bubbles: true, detail: { document: this.document } }); + let evt = new CustomEvent('change', { bubbles: true, composed: true, detail: { document: this.document } }); this.dispatchEvent(evt); } }); @@ -141,6 +141,7 @@ export default class Editor extends events(HTMLElement) { let id = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); return Object.assign(a, {id}); }); + this.document.addEventListener('change', (() => this.scheduleRender() )); } @@ -165,6 +166,6 @@ export default class Editor extends events(HTMLElement) { } } -if (!window.customElements.get('text-editor')) { - window.customElements.define('text-editor', Editor); +if (!window.customElements.get('offset-editor')) { + window.customElements.define('offset-editor', OffsetEditor); } diff --git a/packages/@atjson/editor/src/mixins/editable-component.ts b/packages/@atjson/editor/src/mixins/editable-component.ts index 17f6fa248..a4284822a 100644 --- a/packages/@atjson/editor/src/mixins/editable-component.ts +++ b/packages/@atjson/editor/src/mixins/editable-component.ts @@ -48,7 +48,7 @@ export default class EditableComponent extends WebComponent { return el; } - static elementRenderer = () => { + static elementRenderer = (node: any): Element => { throw new Error('Element Renderer must be overriden'); } diff --git a/packages/@atjson/editor/src/mixins/events.ts b/packages/@atjson/editor/src/mixins/events.ts index aca7a654c..a97da3a5a 100644 --- a/packages/@atjson/editor/src/mixins/events.ts +++ b/packages/@atjson/editor/src/mixins/events.ts @@ -98,5 +98,5 @@ export default function(Base: HTMLElement) { }); this.eventHandlers = {}; } - } -}; + }; +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts b/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts index edb01fe22..40d190d4f 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts @@ -16,3 +16,7 @@ export default class AnnotationAttribute extends WebComponent { } } } + +if (!window.customElements.get('annotation-attribute')) { + window.customElements.define('annotation-attribute', AnnotationAttribute); +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts b/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts index d70f9a0e2..8372473d3 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts @@ -1,5 +1,5 @@ import WebComponent from '../../src/mixins/component'; -import AnnotationAttribute from './annotation-attribute'; +import './annotation-attribute'; export default class AnnotationInspector extends WebComponent { @@ -44,3 +44,7 @@ export default class AnnotationInspector extends WebComponent { } } } + +if (!window.customElements.get('annotation-inspector')) { + window.customElements.define('annotation-inspector', AnnotationInspector); +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts index 4fcdeb2b3..e584f033b 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts @@ -1,10 +1,6 @@ import Document from '@atjson/document'; import WebComponent from '../../src/mixins/component'; -import AnnotationInspector from './annotation-attribute'; - -if (!window.customElements.get('annotation-attribute')) { - window.customElements.define('annotation-attribute', AnnotationInspector); -} +import './annotation-attribute'; export default class AnnotationsInspector extends WebComponent { static template = ` @@ -94,3 +90,7 @@ export default class AnnotationsInspector extends WebComponent { this.document.addEventListener('change', _ => window.requestAnimationFrame(_ => this.updateTBody())); } } + +if (!window.customElements.get('annotations-inspector')) { + window.customElements.define('annotations-inspector', AnnotationsInspector); +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts b/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts index 7079a5fb7..f7af54afe 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts @@ -76,3 +76,7 @@ export default class CharacterCounter extends WebComponent { } } } + +if (!window.customElements.get('character-counter')) { + window.customElements.define('character-counter', CharacterCounter); +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/index.ts b/packages/@atjson/editor/utils/inspector-gadget/index.ts index 1be89594a..6a7b1b9c8 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/index.ts +++ b/packages/@atjson/editor/utils/inspector-gadget/index.ts @@ -1,15 +1,7 @@ import Document from '@atjson/document'; import WebComponent from '../../src/mixins/component'; -import AnnotationsInspector from './annotations-inspector'; -import CharacterCounter from './character-counter'; - -if (!window.customElements.get('annotations-inspector')) { - window.customElements.define('annotations-inspector', AnnotationsInspector); -} - -if (!window.customElements.get('character-counter')) { - window.customElements.define('character-counter', CharacterCounter); -} +import './annotations-inspector'; +import './character-counter'; export default class InspectorGadget extends WebComponent { From 2ff7de7689794d67f169bf2b0c4770ad53816d69 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Wed, 18 Jul 2018 14:03:39 -0400 Subject: [PATCH 065/104] renderer-webcomponent: Address TypeScript compiler warnings. --- packages/@atjson/renderer-webcomponent/src/index.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/@atjson/renderer-webcomponent/src/index.ts b/packages/@atjson/renderer-webcomponent/src/index.ts index d7aa252fc..c8ed1af3f 100644 --- a/packages/@atjson/renderer-webcomponent/src/index.ts +++ b/packages/@atjson/renderer-webcomponent/src/index.ts @@ -1,7 +1,11 @@ import Document from '@atjson/document'; import { HIR, HIRNode } from '@atjson/hir'; -export default class WebComponentRenderer { +interface WebComponentRenderer { + [key: string]: any; +} + +class WebComponentRenderer { document: Document; @@ -9,7 +13,7 @@ export default class WebComponentRenderer { this.document = document; } - text({ text }) { + text({ text }: { text: string }) { if (text[text.length - 1] === '\n') { let nonBreakStrings = text.split('\n'); if (nonBreakStrings[nonBreakStrings.length - 1] === '') { @@ -22,7 +26,7 @@ export default class WebComponentRenderer { span.contentEditable = 'false'; span.appendChild(document.createTextNode('\n')); return [document.createTextNode(str), span]; - }).reduce((a, b) => a.concat(b)); + }).reduce((a: Array, b: Array): Array => a.concat(b)); let textParentNode = document.createElement('span'); children.forEach((child: Node) => { @@ -104,3 +108,5 @@ export default class WebComponentRenderer { }); } } + +export default WebComponentRenderer; From be85c785ea069d715f8f2b506be9ccd8225d2151 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Wed, 18 Jul 2018 22:11:48 +0100 Subject: [PATCH 066/104] Components!!! --- packages/@atjson/editor/demo/app.ts | 37 +++++++--- .../editor/src/components/blockquote.ts | 8 +++ .../@atjson/editor/src/components/bold.ts | 8 +++ .../@atjson/editor/src/components/code.ts | 0 .../editor/src/components/color-editor.ts | 71 ++++++++++++++++++ .../@atjson/editor/src/components/color.ts | 56 +++++++++++++++ .../editor/src/components/font-editor.ts | 72 +++++++++++++++++++ .../@atjson/editor/src/components/font.ts | 56 +++++++++++++++ .../src/components/heading-action-button.ts | 53 ++++++++++++++ .../@atjson/editor/src/components/heading.ts | 14 ++++ .../@atjson/editor/src/components/italic.ts | 8 +++ .../editor/src/components/line-break.ts | 11 +++ .../components/{editable-link.ts => link.ts} | 12 ++-- .../editor/src/components/paragraph.ts | 8 +++ .../editor/src/components/strikethrough.ts | 8 +++ .../editor/src/components/underline.ts | 8 +++ packages/@atjson/editor/src/index.ts | 17 ++++- .../@atjson/editor/src/selection-toolbar.ts | 41 ++++------- .../renderer-webcomponent/src/index.ts | 36 ++-------- 19 files changed, 449 insertions(+), 75 deletions(-) create mode 100644 packages/@atjson/editor/src/components/blockquote.ts create mode 100644 packages/@atjson/editor/src/components/bold.ts create mode 100644 packages/@atjson/editor/src/components/code.ts create mode 100644 packages/@atjson/editor/src/components/color-editor.ts create mode 100644 packages/@atjson/editor/src/components/color.ts create mode 100644 packages/@atjson/editor/src/components/font-editor.ts create mode 100644 packages/@atjson/editor/src/components/font.ts create mode 100644 packages/@atjson/editor/src/components/heading-action-button.ts create mode 100644 packages/@atjson/editor/src/components/heading.ts create mode 100644 packages/@atjson/editor/src/components/italic.ts create mode 100644 packages/@atjson/editor/src/components/line-break.ts rename packages/@atjson/editor/src/components/{editable-link.ts => link.ts} (78%) create mode 100644 packages/@atjson/editor/src/components/paragraph.ts create mode 100644 packages/@atjson/editor/src/components/strikethrough.ts create mode 100644 packages/@atjson/editor/src/components/underline.ts diff --git a/packages/@atjson/editor/demo/app.ts b/packages/@atjson/editor/demo/app.ts index 9d36684dd..47a5f6c3e 100644 --- a/packages/@atjson/editor/demo/app.ts +++ b/packages/@atjson/editor/demo/app.ts @@ -2,7 +2,16 @@ import Document from '@atjson/document'; import './editor-demo'; import OffsetEditor from '../src'; -import EditableLink from '../src/components/editable-link'; +import OffsetBlockquote from '../src/components/blockquote'; +import OffsetBold from '../src/components/bold'; +import OffsetColor from '../src/components/color'; +import OffsetFont from '../src/components/font'; +import OffsetHeading from '../src/components/heading'; +import OffsetItalic from '../src/components/italic'; +import OffsetLink from '../src/components/link'; +import OffsetParagraphElement from '../src/components/paragraph'; +import OffsetStrikethrough from '../src/components/strikethrough'; +import OffsetUnderline from '../src/components/underline'; // Web components in the registry can't be redefined, // so reload the page on every change @@ -15,20 +24,32 @@ if (module.hot) { document.addEventListener('DOMContentLoaded', () => { let editor: OffsetEditor = document.querySelector('offset-editor'); - editor.addContentFeature(EditableLink); + editor.addContentFeature(OffsetParagraphElement); + editor.addContentFeature(OffsetLink); + editor.addContentFeature(OffsetBold); + editor.addContentFeature(OffsetItalic); + editor.addContentFeature(OffsetUnderline); + editor.addContentFeature(OffsetStrikethrough); + editor.addContentFeature(OffsetFont); + editor.addContentFeature(OffsetColor); + editor.addContentFeature(OffsetHeading); let doc = new URL(location.toString()).searchParams.get('document'); if (doc) { editor.setDocument(new Document(JSON.parse(doc))); } else { let doc = new Document({ - content: 'Some text that is both bold and italic plus something after.', + content: 'Heading 1\nSome text that is both bold and italic plus something after.', annotations: [ - { type: 'bold', display: 'inline', start: 23, end: 31 }, - { type: 'link', display: 'inline', start: 20, end: 24, attributes: { url: 'https://google.com' } }, - { type: 'italic', display: 'inline', start: 28, end: 38 }, - { type: 'underline', display: 'inline', start: 28, end: 38 }, - { type: 'paragraph', display: 'block', start: 0, end: 61 } + { type: 'bold', display: 'inline', start: 33, end: 41 }, + { type: 'link', display: 'inline', start: 30, end: 34, attributes: { url: 'https://google.com' } }, + { type: 'italic', display: 'inline', start: 38, end: 48 }, + { type: 'underline', display: 'inline', start: 38, end: 48 }, + { type: 'strikethrough', display: 'inline', start: 40, end: 50 }, + { type: 'font', display: 'inline', start: 15, end: 25, attributes: { 'font-family': 'Sans-serif', 'font-size': '200%' } }, + { type: 'color', display: 'inline', start: 20, end: 30, attributes: { } }, + { type: 'heading', display: 'block', start: 0, end: 10, attributes: { level: '1' } } + { type: 'paragraph', display: 'block', start: 10, end: 71 } ] }); diff --git a/packages/@atjson/editor/src/components/blockquote.ts b/packages/@atjson/editor/src/components/blockquote.ts new file mode 100644 index 000000000..04c377e4c --- /dev/null +++ b/packages/@atjson/editor/src/components/blockquote.ts @@ -0,0 +1,8 @@ +export default class OffsetBlockquoteElement { + + static annotationName = 'blockquote'; + + static elementRenderer = (node: any): Element => { + return document.createElement('blockquote'); + } +} diff --git a/packages/@atjson/editor/src/components/bold.ts b/packages/@atjson/editor/src/components/bold.ts new file mode 100644 index 000000000..ab4995df8 --- /dev/null +++ b/packages/@atjson/editor/src/components/bold.ts @@ -0,0 +1,8 @@ +export default class OffsetBoldElement { + + static annotationName = 'bold'; + + static elementRenderer = (node: any): Element => { + return document.createElement('strong'); + } +} diff --git a/packages/@atjson/editor/src/components/code.ts b/packages/@atjson/editor/src/components/code.ts new file mode 100644 index 000000000..e69de29bb diff --git a/packages/@atjson/editor/src/components/color-editor.ts b/packages/@atjson/editor/src/components/color-editor.ts new file mode 100644 index 000000000..35653a46b --- /dev/null +++ b/packages/@atjson/editor/src/components/color-editor.ts @@ -0,0 +1,71 @@ +import WebComponent from '../mixins/component'; + +export default class ColorEditor extends WebComponent { + + static template = `    `; + + static events = { + 'beforeinput': 'beforeInput', + 'click .cancel': 'cursorBlur', + 'click .save': 'onSave', + 'keypress .text-color': 'handleKeypress' + 'keypress .background-color': 'handleKeypress' + }; + + static observedAttributes = ['text-color', 'background-color']; + + static style = ` + :host { + display: flex; + } + `; + + beforeInput(evt: Event) { + evt.stopPropagation(); + } + + handleKeypress(evt: KeyboardEvent) { + if (evt.keyCode === 13) { + this.onSave(evt); + } + } + + onSave(evt: Event) { + let textColor = this.shadowRoot.querySelector('.text-color'); + this.setAttribute('text-color', textColor.value); + let backgroundColor = this.shadowRoot.querySelector('.background-color'); + this.setAttribute('background-color', backgroundColor.value); + + this.dispatchEvent(new CustomEvent('attributechange', { + bubbles: true, + composed: true, + detail: { + attributes: { + 'text-color': textColor.value, + 'background-color': backgroundColor.value + } + } + })); + + this.dispatchEvent(new CustomEvent('resumeinput', { bubbles: true, composed: true })); + + evt.stopPropagation(); + } + + attributeChangedCallback(attribute: string) { + switch (attribute) { + case 'text-color': + let textColor = this.shadowRoot.querySelector('.text-color'); + textColor.setAttribute('value', this.getAttribute('text-color')); + break; + case 'background-color': + let backgroundColor = this.shadowRoot.querySelector('.background-color'); + backgroundColor.setAttribute('value', this.getAttribute('background-color')); + break; + } + } +} + +if (!window.customElements.get('color-editor')) { + window.customElements.define('color-editor', ColorEditor); +} diff --git a/packages/@atjson/editor/src/components/color.ts b/packages/@atjson/editor/src/components/color.ts new file mode 100644 index 000000000..e66c0a5f2 --- /dev/null +++ b/packages/@atjson/editor/src/components/color.ts @@ -0,0 +1,56 @@ +import EditableComponent from '../mixins/editable-component'; +import './color-editor'; + +export default class OffsetColor extends EditableComponent { + + static template = `
`; + + static observedAttributes = ['text-color', 'background-color']; + + static annotationName = 'color'; + + static elementRenderer(node: any): Element { + let el = document.createElement('offset-color'); + if (node.attributes['text-color']) { + el.setAttribute('text-color', node.attributes['text-color']); + } + + if (node.attributes['background-color']) { + el.setAttribute('background-color', node.attributes['background-color']); + } + + return el; + } + + attributeChangedCallback(attribute: string) { + let el: HTMLSpanElement = this.shadowRoot.querySelector('.color'); + let editor = this.shadowRoot.querySelector('color-editor'); + switch (attribute) { + case 'text-color': + let color = this.getAttribute('text-color'); + if (color) { + el.style.color = color; + editor.setAttribute('text-color', color); + } else { + el.style.color = ''; + editor.removeAttribute('text-color'); + } + break; + + case 'background-color': + let backgroundColor = this.getAttribute('background-color'); + if (backgroundColor) { + el.style.backgroundColor = backgroundColor; + editor.setAttribute('background-color', backgroundColor); + } else { + el.style.backgroundColor = ''; + editor.removeAttribute('background-color'); + } + break; + } + } +} + +if (!window.customElements.get('offset-color')) { + window.customElements.define('offset-color', OffsetColor); +} diff --git a/packages/@atjson/editor/src/components/font-editor.ts b/packages/@atjson/editor/src/components/font-editor.ts new file mode 100644 index 000000000..6315c3e1d --- /dev/null +++ b/packages/@atjson/editor/src/components/font-editor.ts @@ -0,0 +1,72 @@ +import WebComponent from '../mixins/component'; + +export default class FontEditor extends WebComponent { + + static template = `    `; + + static events = { + 'beforeinput': 'beforeInput', + 'click .cancel': 'cursorBlur', + 'click .save': 'onSave', + 'keypress .font-family': 'handleKeypress' + 'keypress .font-size': 'handleKeypress' + }; + + static observedAttributes = ['font-family', 'font-size']; + + static style = ` + :host { + display: flex; + } + `; + + beforeInput(evt: Event) { + evt.stopPropagation(); + } + + handleKeypress(evt: KeyboardEvent) { + if (evt.keyCode === 13) { + this.onSave(evt); + } + } + + onSave(evt: Event) { + let fontFamily = this.shadowRoot.querySelector('.font-family'); + this.setAttribute('font-family', fontFamily.value); + + let fontSize = this.shadowRoot.querySelector('.font-size'); + this.setAttribute('font-size', fontSize.value); + + this.dispatchEvent(new CustomEvent('attributechange', { + bubbles: true, + composed: true, + detail: { + attributes: { + 'font-family': fontFamily.value, + 'font-size': fontSize.value + } + } + })); + + this.dispatchEvent(new CustomEvent('resumeinput', { bubbles: true, composed: true })); + + evt.stopPropagation(); + } + + attributeChangedCallback(attribute: string) { + switch (attribute) { + case 'font-family': + let fontFamily = this.shadowRoot.querySelector('.font-family'); + fontFamily.setAttribute('value', this.getAttribute('font-family')); + break; + case 'font-size': + let fontSize = this.shadowRoot.querySelector('.font-size'); + fontSize.setAttribute('value', this.getAttribute('font-size')); + break; + } + } +} + +if (!window.customElements.get('font-editor')) { + window.customElements.define('font-editor', FontEditor); +} diff --git a/packages/@atjson/editor/src/components/font.ts b/packages/@atjson/editor/src/components/font.ts new file mode 100644 index 000000000..97b05e613 --- /dev/null +++ b/packages/@atjson/editor/src/components/font.ts @@ -0,0 +1,56 @@ +import EditableComponent from '../mixins/editable-component'; +import './font-editor'; + +export default class OffsetFont extends EditableComponent { + + static template = `
`; + + static observedAttributes = ['font-family', 'font-size']; + + static annotationName = 'font'; + + static elementRenderer(node: any): Element { + let el = document.createElement('offset-font'); + if (node.attributes['font-family']) { + el.setAttribute('font-family', node.attributes['font-family']); + } + + if (node.attributes['font-size']) { + el.setAttribute('font-size', node.attributes['font-size']); + } + + return el; + } + + attributeChangedCallback(attribute: string) { + let el: HTMLSpanElement = this.shadowRoot.querySelector('.font'); + let editor = this.shadowRoot.querySelector('font-editor'); + switch (attribute) { + case 'font-family': + let family = this.getAttribute('font-family'); + if (family) { + el.style.fontFamily = family; + editor.setAttribute('font-family', family); + } else { + el.style.fontFamily = ''; + editor.removeAttribute('font-family'); + } + break; + + case 'font-size': + let size = this.getAttribute('font-size'); + if (size) { + el.style.fontSize = size; + editor.setAttribute('font-size', size); + } else { + el.style.fontSize = ''; + editor.removeAttribute('font-size'); + } + break; + } + } +} + +if (!window.customElements.get('offset-font')) { + window.customElements.define('offset-font', OffsetFont); +} diff --git a/packages/@atjson/editor/src/components/heading-action-button.ts b/packages/@atjson/editor/src/components/heading-action-button.ts new file mode 100644 index 000000000..6b3f2c2cb --- /dev/null +++ b/packages/@atjson/editor/src/components/heading-action-button.ts @@ -0,0 +1,53 @@ +import WebComponent from '../mixins/component'; + +export default class OffsetHeadingActionButton extends WebComponent { + + static template = ''; + + static style = ` + :host(.active) button { + border-color: red; + } + `; + + static events = { + selectionchange: 'onSelectionChange', + click: 'onClick' + }; + + onSelectionChange(evt: CustomEvent) { + console.log('selectionchange'); + if (evt.detail.start !== evt.detail.end) { + if (evt.detail.selectedAnnotations.find(a => a.type === 'heading')) { + this.classList.add('active'); + } else { + this.classList.remove('active'); + } + this.style.display = 'initial'; + this.selection = evt.detail; + } else { + evt.preventDefault(); + this.style.display = 'none'; + } + } + + onClick(evt: MouseEvent) { + console.log('click') + let detail = { + type: 'heading', + start: parseInt(this.selection.start, 10), + end: parseInt(this.selection.end, 10), + attributes: { level: 1 } + }; + + this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, + composed: true, + detail + })); + } +} + +if (!window.customElements.get('offset-heading-action-button')) { + window.customElements.define('offset-heading-action-button', OffsetHeadingActionButton); +} diff --git a/packages/@atjson/editor/src/components/heading.ts b/packages/@atjson/editor/src/components/heading.ts new file mode 100644 index 000000000..4e961632f --- /dev/null +++ b/packages/@atjson/editor/src/components/heading.ts @@ -0,0 +1,14 @@ +import './heading-action-button'; + +export default class OffsetHeadingElement { + + static annotationName = 'heading'; + + static elementRenderer(node: any): Element { + return document.createElement('h' + node.attributes.level); + } + + static get selectionButton() { + return document.createElement('offset-heading-action-button'); + } +} diff --git a/packages/@atjson/editor/src/components/italic.ts b/packages/@atjson/editor/src/components/italic.ts new file mode 100644 index 000000000..15d2017f9 --- /dev/null +++ b/packages/@atjson/editor/src/components/italic.ts @@ -0,0 +1,8 @@ +export default class OffsetItalicElement { + + static annotationName = 'italic'; + + static elementRenderer = (node: any): Element => { + return document.createElement('em'); + } +} diff --git a/packages/@atjson/editor/src/components/line-break.ts b/packages/@atjson/editor/src/components/line-break.ts new file mode 100644 index 000000000..d8694506e --- /dev/null +++ b/packages/@atjson/editor/src/components/line-break.ts @@ -0,0 +1,11 @@ +export default class OffsetLineBreakElement { + + static annotationName = 'line-break'; + + static elementRenderer = (node: any): Element => { + let parentElement = document.createElement('span'); + parentElement.appendChild(document.createElement('br')); + + return parentElement; + } +} diff --git a/packages/@atjson/editor/src/components/editable-link.ts b/packages/@atjson/editor/src/components/link.ts similarity index 78% rename from packages/@atjson/editor/src/components/editable-link.ts rename to packages/@atjson/editor/src/components/link.ts index 5da7072d5..45b8605bd 100644 --- a/packages/@atjson/editor/src/components/editable-link.ts +++ b/packages/@atjson/editor/src/components/link.ts @@ -1,9 +1,9 @@ import EditableComponent from '../mixins/editable-component'; import './link-editor'; -export default class EditableLink extends EditableComponent { +export default class OffsetLink extends EditableComponent { - static template = `
`; + static template = `
`; static observedAttributes = ['url', 'nofollow']; @@ -16,13 +16,13 @@ export default class EditableLink extends EditableComponent { `; static events = Object.assign({ - 'click .text-link': 'cancelLinkClick' + 'click .link': 'cancelLinkClick' }, EditableComponent.events); static annotationName = 'link'; static elementRenderer(node: any): Element { - let link = document.createElement('editable-link'); + let link = document.createElement('offset-link'); link.setAttribute('url', node.attributes.url); if (node.attributes.nofollow) { link.setAttribute('nofollow', ''); @@ -53,6 +53,6 @@ export default class EditableLink extends EditableComponent { } } -if (!window.customElements.get('editable-link')) { - window.customElements.define('editable-link', EditableLink); +if (!window.customElements.get('offset-link')) { + window.customElements.define('offset-link', OffsetLink); } diff --git a/packages/@atjson/editor/src/components/paragraph.ts b/packages/@atjson/editor/src/components/paragraph.ts new file mode 100644 index 000000000..b4f82e25a --- /dev/null +++ b/packages/@atjson/editor/src/components/paragraph.ts @@ -0,0 +1,8 @@ +export default class OffsetParagraphElement { + + static annotationName = 'paragraph'; + + static elementRenderer(): Element { + return document.createElement('p'); + } +} diff --git a/packages/@atjson/editor/src/components/strikethrough.ts b/packages/@atjson/editor/src/components/strikethrough.ts new file mode 100644 index 000000000..d52724473 --- /dev/null +++ b/packages/@atjson/editor/src/components/strikethrough.ts @@ -0,0 +1,8 @@ +export default class OffsetStrikethroughElement { + + static annotationName = 'strikethrough'; + + static elementRenderer(): Element { + return document.createElement('del'); + } +} diff --git a/packages/@atjson/editor/src/components/underline.ts b/packages/@atjson/editor/src/components/underline.ts new file mode 100644 index 000000000..bc9d204eb --- /dev/null +++ b/packages/@atjson/editor/src/components/underline.ts @@ -0,0 +1,8 @@ +export default class OffsetUnderlineElement { + + static annotationName = 'underline'; + + static elementRenderer = (node: any): Element => { + return document.createElement('u'); + } +} diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 771892e55..786f63688 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -15,8 +15,20 @@ export default class OffsetEditor extends events(HTMLElement) { 'change text-selection'(evt: CustomEvent) { this.selection = evt.detail; let toolbar = this.querySelector('selection-toolbar'); - toolbar.setAttribute('start', evt.detail.start); - toolbar.setAttribute('end', evt.detail.end); + + let selectedAnnotations = this.document.annotations.filter(a => { + return (a.start <= evt.detail.start && a.end >= evt.detail.start) || + (a.start <= evt.detail.end && a.end >= evt.detail.end) + }); + + let selectionChangeEvent = new CustomEvent('selectionchange', { + detail: Object.assign({ + selectedAnnotations, + document: this.document + }, evt.detail), + bubbles: false + }); + toolbar.dispatchEvent(selectionChangeEvent); }, 'insertText text-input'(evt: CustomEvent) { @@ -49,6 +61,7 @@ export default class OffsetEditor extends events(HTMLElement) { }, 'addAnnotation'(evt: CustomEvent) { + console.log('is this the real life?', evt); if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { const contained = (a: Annotation, b: Annotation) => a.start >= b.start && a.end <= b.end; diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts index 2e0f14059..4a0e0aad8 100644 --- a/packages/@atjson/editor/src/selection-toolbar.ts +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -1,7 +1,7 @@ import WebComponent from './mixins/component'; export default class SelectionToolbar extends WebComponent { - static template = ``; + static template = ``; static style = ` :host { @@ -10,36 +10,19 @@ export default class SelectionToolbar extends WebComponent { `; static events = { - click: 'onClick' + selectionchange: 'onSelectionChange' }; - onClick(evt: MouseEvent) { - let target = null; - for (let i of evt.path.length) { - if (evt.path[i].nodeName === 'BUTTON') { - target = evt.path[i]; - break; - } - } - - let type = target.getAttribute('data-type'); - let start = this.getAttribute('start'); - let end = this.getAttribute('end'); - - if (start === null || end === null) return; - - let detail = { - type, - start: parseInt(start, 10), - end: parseInt(end, 10), - attributes: {} - }; - - if (type === 'link') { - detail.attributes = { url: '' }; - } - - this.dispatchEvent(new CustomEvent('addAnnotation', { bubbles: true, detail })); + // Bubble down the selection change event so that the button can decide if it + // should be visible or not. + onSelectionChange(evt: CustomEvent) { + let visibleElements = false; + this.shadowRoot.childNodes.forEach(element => { + let event = new CustomEvent(evt.type, { bubbles: false, cancelable: true, detail: evt.detail }); + element.dispatchEvent(event); + if (!event.defaultPrevented) visibleElements = true; + }); + console.log('visible elements?', visibleElements); } } diff --git a/packages/@atjson/renderer-webcomponent/src/index.ts b/packages/@atjson/renderer-webcomponent/src/index.ts index c8ed1af3f..268097283 100644 --- a/packages/@atjson/renderer-webcomponent/src/index.ts +++ b/packages/@atjson/renderer-webcomponent/src/index.ts @@ -38,33 +38,6 @@ class WebComponentRenderer { return document.createTextNode(text); } - paragraph() { - return document.createElement('p'); - } - - bold() { - return document.createElement('strong'); - } - - strikethrough() { - return document.createElement('del'); - } - - italic() { - return document.createElement('em'); - } - - underline() { - return document.createElement('u'); - } - - 'line-break'() { - let parentElement = document.createElement('span'); - parentElement.appendChild(document.createElement('br')); - - return parentElement; - } - render() { let hir = new Map(); let annotationGraph = new HIR(this.document); @@ -84,12 +57,15 @@ class WebComponentRenderer { let element: Element; if (typeof (this as any)[node.type] === 'function') { element = this[node.type](node); - if (node.id) { - element.setAttribute('data-annotation-id', node.id.toString()); - } } else { element = document.createElement('span'); + element.classList.add('unknown-annotation'); + } + + if (node.id) { + element.setAttribute('data-annotation-id', node.id.toString()); } + hir.set(element, node); this.compile(hir, children).forEach((child: Element) => { element.appendChild(child); From 14a3f66f9adec99a3fed64772c746534117f0b69 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Thu, 19 Jul 2018 18:56:18 +0100 Subject: [PATCH 067/104] Contextual Heading Button (prototype for button interactions) --- .../src/components/heading-action-button.ts | 112 +++++++++++++++--- packages/@atjson/editor/src/index.ts | 14 ++- 2 files changed, 107 insertions(+), 19 deletions(-) diff --git a/packages/@atjson/editor/src/components/heading-action-button.ts b/packages/@atjson/editor/src/components/heading-action-button.ts index 6b3f2c2cb..b7bee54f0 100644 --- a/packages/@atjson/editor/src/components/heading-action-button.ts +++ b/packages/@atjson/editor/src/components/heading-action-button.ts @@ -2,48 +2,126 @@ import WebComponent from '../mixins/component'; export default class OffsetHeadingActionButton extends WebComponent { - static template = ''; + static template = ''; static style = ` - :host(.active) button { + :host(.active) .toggle { border-color: red; + font-weight: bold; + } + + .level { + display: none; + } + + :host(.active) .level { + display: initial; + } + + :host(.active) .level.hidden { + display: none; } `; static events = { selectionchange: 'onSelectionChange', - click: 'onClick' + 'click .toggle': 'onToggleClick', + 'click .level': 'onLevelClick' }; + selection: any; + + getOverlappingHeading() { + return this.selection.selectedAnnotations.find(a => a.type === 'heading'); + } + onSelectionChange(evt: CustomEvent) { - console.log('selectionchange'); - if (evt.detail.start !== evt.detail.end) { - if (evt.detail.selectedAnnotations.find(a => a.type === 'heading')) { + let { start, end, document } = evt.detail; + let newlineFree: boolean = false; + + if (start !== end) { + let coveredContent = document.content.slice(start, end); + let nlIdx = coveredContent.lastIndexOf('\n'); + newlineFree = nlIdx === -1 || nlIdx === end - 1; + } + + // Only display if the selection *does not* span multiple paragraphs. + if (newlineFree) { + + this.selection = evt.detail; + + let overlappingHeading = this.getOverlappingHeading(); + let levelButton = this.shadowRoot.querySelector('.level'); + + if (overlappingHeading) { + this.shadowRoot.querySelector('.toggle').innerText = 'H' + overlappingHeading.attributes.level; this.classList.add('active'); + let nextLevel = parseInt(overlappingHeading.attributes.level, 10) + 1; + if (nextLevel < 4) { + levelButton.innerText = 'H' + nextLevel; + levelButton.classList.remove('hidden'); + } else { + levelButton.classList.add('hidden'); + } } else { + this.shadowRoot.querySelector('.toggle').innerText = 'H1'; + levelButton.classList.add('hidden'); this.classList.remove('active'); } + this.style.display = 'initial'; - this.selection = evt.detail; + } else { + delete this.selection; evt.preventDefault(); this.style.display = 'none'; } } - onClick(evt: MouseEvent) { - console.log('click') - let detail = { - type: 'heading', - start: parseInt(this.selection.start, 10), - end: parseInt(this.selection.end, 10), - attributes: { level: 1 } - }; + onToggleClick(evt: MouseEvent) { + let overlappingHeading = this.getOverlappingHeading(); + + if (overlappingHeading) { + // Delete (toggle) the Heading + this.dispatchEvent(new CustomEvent('deleteAnnotation', { + bubbles: true, + composed: true, + detail: { + annotationId: overlappingHeading.id + } + })); + } else { + // Create a new Heading at level 1 + let content = this.selection.document.content; + let start = Math.max(0, content.lastIndexOf('\n', parseInt(this.selection.start, 10))); + let end = content.indexOf('\n', parseInt(this.selection.end, 10)); + if (end === -1) end = content.length; - this.dispatchEvent(new CustomEvent('addAnnotation', { + this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, + composed: true, + detail: { + type: 'heading', + start, end, + attributes: { level: 1 } + } + })); + } + } + + onLevelClick(evt: MouseEvent) { + let overlappingHeading = this.getOverlappingHeading(); + + let level = parseInt(overlappingHeading.attributes.level, 10) + 1; + + // Update the existing heading's level. + this.dispatchEvent(new CustomEvent('attributechange', { bubbles: true, composed: true, - detail + detail: { + annotationId: overlappingHeading.id, + attributes: Object.assign(overlappingHeading.attributes, { level }) + } })); } } diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 786f63688..a1ba7b649 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -94,8 +94,18 @@ export default class OffsetEditor extends events(HTMLElement) { } }, - 'attributechange text-input'(evt: CustomEvent) { - if (evt.target !== null) { + 'deleteAnnotation'(evt: CustomEvent) { + let annotation = this.document.annotations.find(a => a.id === evt.detail.annotationId); + this.document.removeAnnotation(annotation); + } + + 'attributechange'(evt: CustomEvent) { + console.log('got event', evt); + if (evt.detail.annotationId) { + let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); + console.log('in here?', annotation); + this.document.replaceAnnotation(annotation, Object.assign(annotation, {attributes: evt.detail.attributes})); + } else if (evt.target !== null) { let annotationId = evt.target.getAttribute('data-annotation-id'); let annotation = this.document.annotations.find((a: Annotation) => a.id.toString(10) === annotationId); this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); From 52ba1dcc37c9a0bffde8835c31fec955fe19f089 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Jul 2018 22:34:38 +0100 Subject: [PATCH 068/104] Fix positioning of toolbar --- packages/@atjson/editor/src/text-selection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 56cc6acc8..347d0eb59 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -202,7 +202,7 @@ class TextSelection extends events(HTMLElement) { window.requestAnimationFrame(_ => { let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); toolbarStyle.display = 'block'; - toolbarStyle.top = selectionBoundingRect.y - selectionBoundingRect.height * 1.5; + toolbarStyle.bottom = selectionBoundingRect.y - 3; toolbarStyle.left = selectionBoundingRect.x; }); } From 0b183489924c94f5c48d29f726bd90cacab307f5 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Jul 2018 22:36:23 +0100 Subject: [PATCH 069/104] Reduce agressiveness / debounce toolbar and cursor focus events --- packages/@atjson/editor/src/text-selection.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 347d0eb59..3dd5b7eb7 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -75,6 +75,7 @@ class TextSelection extends events(HTMLElement) { }; composing: boolean; + private _cursorToolbarResetTimeout: any; private textNodes: Text[]; private observer?: MutationObserver | null; @@ -121,6 +122,7 @@ class TextSelection extends events(HTMLElement) { } else if (node.nodeType === 3) { node.parentNode.focus(); } + selection.removeAllRanges(); selection.addRange(r); break; @@ -371,8 +373,13 @@ class TextSelection extends events(HTMLElement) { return true; } - this.handleCursorFocus(range, selectionRange); - this.updateToolbar(range, selectionRange); + clearTimeout(this._cursorToolbarResetTimeout); + + this._cursorToolbarResetTimeout = setTimeout(_ => { + delete this._cursorToolbarResetTimeout; + this.handleCursorFocus(range, selectionRange); + this.updateToolbar(range, selectionRange); + }, 500); this.setAttribute('start', range[0].toString()); this.setAttribute('end', range[1].toString()); From 871f070248050bb28b3fd80db7284e1c65bb5019 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Jul 2018 22:38:09 +0100 Subject: [PATCH 070/104] Remove debug logging --- packages/@atjson/editor/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index a1ba7b649..ff3b3f893 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -61,7 +61,6 @@ export default class OffsetEditor extends events(HTMLElement) { }, 'addAnnotation'(evt: CustomEvent) { - console.log('is this the real life?', evt); if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { const contained = (a: Annotation, b: Annotation) => a.start >= b.start && a.end <= b.end; @@ -100,10 +99,8 @@ export default class OffsetEditor extends events(HTMLElement) { } 'attributechange'(evt: CustomEvent) { - console.log('got event', evt); if (evt.detail.annotationId) { let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); - console.log('in here?', annotation); this.document.replaceAnnotation(annotation, Object.assign(annotation, {attributes: evt.detail.attributes})); } else if (evt.target !== null) { let annotationId = evt.target.getAttribute('data-annotation-id'); From b138162c0a8cde029b814fece8cde678cbc2db7c Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Jul 2018 23:51:22 +0100 Subject: [PATCH 071/104] Actually fix toolbar positioning --- packages/@atjson/editor/src/text-selection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index 3dd5b7eb7..a6b07b919 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -204,7 +204,7 @@ class TextSelection extends events(HTMLElement) { window.requestAnimationFrame(_ => { let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); toolbarStyle.display = 'block'; - toolbarStyle.bottom = selectionBoundingRect.y - 3; + toolbarStyle.top = selectionBoundingRect.y - this.shadowRoot.querySelector('.toolbar').offsetHeight - 3; toolbarStyle.left = selectionBoundingRect.x; }); } From 0b1cc4ec5d56bc75e4c91bf1e56c7b93bab2643e Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 20 Jul 2018 23:51:37 +0100 Subject: [PATCH 072/104] Convert removed headings to paragraphs. --- .../editor/src/components/heading-action-button.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/@atjson/editor/src/components/heading-action-button.ts b/packages/@atjson/editor/src/components/heading-action-button.ts index b7bee54f0..9809d8b9d 100644 --- a/packages/@atjson/editor/src/components/heading-action-button.ts +++ b/packages/@atjson/editor/src/components/heading-action-button.ts @@ -90,6 +90,15 @@ export default class OffsetHeadingActionButton extends WebComponent { annotationId: overlappingHeading.id } })); + this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, + composed: true, + detail: { + type: 'paragraph', + start: overlappingHeading.start, + end: overlappingHeading.end + } + })); } else { // Create a new Heading at level 1 let content = this.selection.document.content; From 5693613245f79cbcce0fbf801dd1b9ddb8b8822f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 23 Jul 2018 15:12:25 +0100 Subject: [PATCH 073/104] =?UTF-8?q?=F0=9F=91=A9=E2=80=8D=E2=9A=95=EF=B8=8F?= =?UTF-8?q?=F0=9F=90=9B=20Switch=20to=20bubbling,=20don't=20observe=20even?= =?UTF-8?q?t=20directly=20(allows=20for=20events=20from=20e.g.,=20toolbar)?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/@atjson/editor/src/text-input.ts | 25 +++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/@atjson/editor/src/text-input.ts b/packages/@atjson/editor/src/text-input.ts index 4d39c1a26..dd6c33b41 100644 --- a/packages/@atjson/editor/src/text-input.ts +++ b/packages/@atjson/editor/src/text-input.ts @@ -79,9 +79,9 @@ class TextInput extends events(HTMLElement) { compositionend(evt: CustomEvent) { let { start, end } = this.selection; if (start === end) { - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + this.dispatchEvent(new CustomEvent('insertText', { bubbles: true, detail: { position: start, text: evt.data } })); } else { - this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); + this.dispatchEvent(new CustomEvent('replaceText', { bubbles: true, detail: { start, end, text: evt.data } })); } this.composing = false; } @@ -105,15 +105,16 @@ class TextInput extends events(HTMLElement) { switch (evt.inputType) { case 'insertText': if (start === end) { - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: evt.data } })); + this.dispatchEvent(new CustomEvent('insertText', { bubbles: true, detail: { position: start, text: evt.data } })); } else { - this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text: evt.data } })); + this.dispatchEvent(new CustomEvent('replaceText', { bubbles: true, detail: { start, end, text: evt.data } })); } break; case 'insertLineBreak': - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text: '\u2028' } })); + this.dispatchEvent(new CustomEvent('insertText', { bubbles: true, detail: { position: start, text: '\u2028' } })); this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, detail: { type: 'line-break', start, end: end + 1 } })); break; @@ -122,9 +123,9 @@ class TextInput extends events(HTMLElement) { text = evt.dataTransfer.getData('text/plain'); if (start === end) { - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text } })); + this.dispatchEvent(new CustomEvent('insertText', { bubbles: true, detail: { position: start, text } })); } else { - this.dispatchEvent(new CustomEvent('replaceText', { detail: { start, end, text } })); + this.dispatchEvent(new CustomEvent('replaceText', { bubbles: true, detail: { start, end, text } })); } break; @@ -134,7 +135,7 @@ class TextInput extends events(HTMLElement) { target = evt.getTargetRanges()[0]; start = this.nodeAndOffsetToDocumentOffset(target.startContainer, target.startOffset); - this.dispatchEvent(new CustomEvent('insertText', { detail: { position: start, text } })); + this.dispatchEvent(new CustomEvent('insertText', { bubbles: true, detail: { position: start, text } })); break; @@ -143,6 +144,7 @@ class TextInput extends events(HTMLElement) { start--; } this.dispatchEvent(new CustomEvent('deleteText', { + bubbles: true, detail: { start, end } })); break; @@ -158,6 +160,7 @@ class TextInput extends events(HTMLElement) { let deletionEnd = this.nodeAndOffsetToDocumentOffset(target.endContainer, target.endOffset); this.dispatchEvent(new CustomEvent('deleteText', { + bubbles: true, detail: { start: deletionStart, end: deletionEnd } })); break; @@ -167,6 +170,7 @@ class TextInput extends events(HTMLElement) { end++; } this.dispatchEvent(new CustomEvent('deleteText', { + bubbles: true, detail: { start, end } })); break; @@ -175,6 +179,7 @@ class TextInput extends events(HTMLElement) { case 'deleteContent': case 'deleteByDrag': this.dispatchEvent(new CustomEvent('deleteText', { + bubbles: true, detail: { start, end } })); break; @@ -191,6 +196,7 @@ class TextInput extends events(HTMLElement) { evt.dataTransfer.items[0].getAsString((replString: string) => { this.dispatchEvent(new CustomEvent('replaceText', { + bubbles: true, detail: { start: replaceStart, end: replaceEnd, text: replString } })); }); @@ -199,12 +205,14 @@ class TextInput extends events(HTMLElement) { case 'formatBold': this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, detail: { start, end, type: 'bold' } })); break; case 'formatItalic': this.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, detail: { start, end, type: 'italic' } })); break; @@ -216,6 +224,7 @@ class TextInput extends events(HTMLElement) { case 'insertParagraph': evt.preventDefault(); this.dispatchEvent(new CustomEvent('insertText', { + bubbles: true, detail: { position: start, text: '\n' } })); break; From e61ac0c24f4131655f76d3d813b8e380808f0476 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 30 Jul 2018 15:12:48 +0100 Subject: [PATCH 074/104] refactor: move inspector to separate package --- packages/@atjson/editor/demo/app.ts | 58 ----- packages/@atjson/editor/demo/editor-demo.ts | 57 ----- packages/@atjson/editor/demo/style.scss | 3 - .../inspector-gadget/annotations-inspector.ts | 96 -------- .../inspector-gadget/character-counter.ts | 82 ------- .../editor/utils/inspector-gadget/index.ts | 79 ------ packages/@atjson/offset-inspector/README.md | 3 + .../offset-inspector/package-lock.json | 32 +++ .../@atjson/offset-inspector/package.json | 37 +++ .../@atjson/offset-inspector/public/app.ts | 48 ++++ .../public}/index.html | 0 .../offset-inspector/public/style.scss | 3 + .../offset-inspector/public/superscript.ts | 35 +++ .../annotation-attribute.ts | 18 +- .../annotation-inspector.ts | 54 +++-- .../annotations-inspector.ts | 42 ++++ .../document-inspector/character-counter.ts | 88 +++++++ .../src/document-inspector/index.ts | 129 ++++++++++ .../src/html-tree-inspector.ts | 225 ++++++++++++++++++ .../@atjson/offset-inspector/src/index.ts | 164 +++++++++++++ .../offset-inspector/src/mixins/component.ts | 34 +++ .../offset-inspector/src/mixins/events.ts | 102 ++++++++ .../@atjson/offset-inspector/tsconfig.json | 10 + packages/@atjson/offset-inspector/tslint.json | 30 +++ 24 files changed, 1031 insertions(+), 398 deletions(-) delete mode 100644 packages/@atjson/editor/demo/app.ts delete mode 100644 packages/@atjson/editor/demo/editor-demo.ts delete mode 100644 packages/@atjson/editor/demo/style.scss delete mode 100644 packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts delete mode 100644 packages/@atjson/editor/utils/inspector-gadget/character-counter.ts delete mode 100644 packages/@atjson/editor/utils/inspector-gadget/index.ts create mode 100644 packages/@atjson/offset-inspector/README.md create mode 100644 packages/@atjson/offset-inspector/package-lock.json create mode 100644 packages/@atjson/offset-inspector/package.json create mode 100644 packages/@atjson/offset-inspector/public/app.ts rename packages/@atjson/{editor/demo => offset-inspector/public}/index.html (100%) create mode 100644 packages/@atjson/offset-inspector/public/style.scss create mode 100644 packages/@atjson/offset-inspector/public/superscript.ts rename packages/@atjson/{editor/utils/inspector-gadget => offset-inspector/src/document-inspector}/annotation-attribute.ts (66%) rename packages/@atjson/{editor/utils/inspector-gadget => offset-inspector/src/document-inspector}/annotation-inspector.ts (53%) create mode 100644 packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts create mode 100644 packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts create mode 100644 packages/@atjson/offset-inspector/src/document-inspector/index.ts create mode 100644 packages/@atjson/offset-inspector/src/html-tree-inspector.ts create mode 100644 packages/@atjson/offset-inspector/src/index.ts create mode 100644 packages/@atjson/offset-inspector/src/mixins/component.ts create mode 100644 packages/@atjson/offset-inspector/src/mixins/events.ts create mode 100644 packages/@atjson/offset-inspector/tsconfig.json create mode 100644 packages/@atjson/offset-inspector/tslint.json diff --git a/packages/@atjson/editor/demo/app.ts b/packages/@atjson/editor/demo/app.ts deleted file mode 100644 index 47a5f6c3e..000000000 --- a/packages/@atjson/editor/demo/app.ts +++ /dev/null @@ -1,58 +0,0 @@ -import Document from '@atjson/document'; -import './editor-demo'; -import OffsetEditor from '../src'; - -import OffsetBlockquote from '../src/components/blockquote'; -import OffsetBold from '../src/components/bold'; -import OffsetColor from '../src/components/color'; -import OffsetFont from '../src/components/font'; -import OffsetHeading from '../src/components/heading'; -import OffsetItalic from '../src/components/italic'; -import OffsetLink from '../src/components/link'; -import OffsetParagraphElement from '../src/components/paragraph'; -import OffsetStrikethrough from '../src/components/strikethrough'; -import OffsetUnderline from '../src/components/underline'; - -// Web components in the registry can't be redefined, -// so reload the page on every change -if (module.hot) { - module.hot.dispose(() => { - window.location.reload(); - }); -} - -document.addEventListener('DOMContentLoaded', () => { - - let editor: OffsetEditor = document.querySelector('offset-editor'); - editor.addContentFeature(OffsetParagraphElement); - editor.addContentFeature(OffsetLink); - editor.addContentFeature(OffsetBold); - editor.addContentFeature(OffsetItalic); - editor.addContentFeature(OffsetUnderline); - editor.addContentFeature(OffsetStrikethrough); - editor.addContentFeature(OffsetFont); - editor.addContentFeature(OffsetColor); - editor.addContentFeature(OffsetHeading); - - let doc = new URL(location.toString()).searchParams.get('document'); - if (doc) { - editor.setDocument(new Document(JSON.parse(doc))); - } else { - let doc = new Document({ - content: 'Heading 1\nSome text that is both bold and italic plus something after.', - annotations: [ - { type: 'bold', display: 'inline', start: 33, end: 41 }, - { type: 'link', display: 'inline', start: 30, end: 34, attributes: { url: 'https://google.com' } }, - { type: 'italic', display: 'inline', start: 38, end: 48 }, - { type: 'underline', display: 'inline', start: 38, end: 48 }, - { type: 'strikethrough', display: 'inline', start: 40, end: 50 }, - { type: 'font', display: 'inline', start: 15, end: 25, attributes: { 'font-family': 'Sans-serif', 'font-size': '200%' } }, - { type: 'color', display: 'inline', start: 20, end: 30, attributes: { } }, - { type: 'heading', display: 'block', start: 0, end: 10, attributes: { level: '1' } } - { type: 'paragraph', display: 'block', start: 10, end: 71 } - ] - }); - - editor.setDocument(doc); - } -}); diff --git a/packages/@atjson/editor/demo/editor-demo.ts b/packages/@atjson/editor/demo/editor-demo.ts deleted file mode 100644 index abb0080b8..000000000 --- a/packages/@atjson/editor/demo/editor-demo.ts +++ /dev/null @@ -1,57 +0,0 @@ -import Document from '@atjson/document'; -import CommonmarkRenderer from '@atjson/renderer-commonmark'; -import WebComponentRenderer from '@atjson/renderer-webcomponent'; -import '../public/logo'; -import '../src/index'; -import WebComponent from '../src/mixins/component'; -import '../utils/inspector-gadget'; -import InspectorGadget from '../utils/inspector-gadget'; - -export default class OffsetEditorDemo extends WebComponent { - static template = '

' + - '

HTML Output

' + - '

Commonmark Output

' + - ''; - - static events = { - 'change'(evt: CustomEvent) { - console.log('GOT CHANGE!', evt); - this.renderOutput(evt.detail.document); - this.renderMarkdown(evt.detail.document); - this.renderInspector(evt.detail.document); - } - }; - - renderOutput(doc: Document) { - let outputElement = this.shadowRoot.querySelector('.output'); - let rendered = new WebComponentRenderer(doc).render(); - if (outputElement) { - outputElement.innerHTML = rendered.innerHTML; - } - } - - renderMarkdown(doc: Document) { - let outputElement = this.shadowRoot.querySelector('.markdown'); - let rendered = new CommonmarkRenderer().render(doc); - if (outputElement) { - outputElement.innerHTML = rendered; - } - } - - renderInspector(doc: Document) { - // This is really ineffecient, because we're calling it every document - // change at the moment. To fix this, we need a new "changedocument" or - // similar event on the editor. - let inspectorGadget: InspectorGadget = this.shadowRoot.querySelector('inspector-gadget'); - let editor = this.querySelector('offset-editor'); - - if (inspectorGadget) { - inspectorGadget.setDocument(doc); - inspectorGadget.setSelection(editor.getSelection()); - } - } -} - -if (!window.customElements.get('offset-editor-demo')) { - window.customElements.define('offset-editor-demo', OffsetEditorDemo); -} diff --git a/packages/@atjson/editor/demo/style.scss b/packages/@atjson/editor/demo/style.scss deleted file mode 100644 index 85fbea005..000000000 --- a/packages/@atjson/editor/demo/style.scss +++ /dev/null @@ -1,3 +0,0 @@ -body { - margin: 2em; -} diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts b/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts deleted file mode 100644 index e584f033b..000000000 --- a/packages/@atjson/editor/utils/inspector-gadget/annotations-inspector.ts +++ /dev/null @@ -1,96 +0,0 @@ -import Document from '@atjson/document'; -import WebComponent from '../../src/mixins/component'; -import './annotation-attribute'; - -export default class AnnotationsInspector extends WebComponent { - static template = ` -
- - - - - - - - - - - - - - - - -
TypeStartEndAttributes
-
- `; - static style = ` - .container { - overflow-y: scroll; - position: relative; - padding-bottom: 2em; - } - - table { - border-collapse: collapse; - width: 100vw; - } - - th { - font-size: 0.75em; - font-family: sans-serif; - border-bottom: 1px solid black; - border-top: 1px solid black; - text-align: left; - background-color: #f3f3f3; - } - - td { - font-family: monospace; - vertical-align: top; - border-bottom: 0.5px solid grey; - } - - th, td { - padding: 1ex 0; - } - - td:first-child, th:first-child { - padding-left: 1ex; - } - - .annotation-type { - width: 10vw; - } - - .annotation-start, .annotation-end { - width: 4em; - } - `; - - document: Document; - - updateTBody() { - let tbody = ''; - this.document.annotations.forEach((a) => { - tbody += `${a.type}${a.start}${a.end}`; - if (a.attributes) { - Object.keys(a.attributes).forEach(key => { - tbody += `
` - }); - } else { - tbody += `` - } - }); - this.shadowRoot.querySelector('tbody').innerHTML = tbody; - } - - setDocument(doc) { - this.document = doc; - this.document.addEventListener('change', _ => window.requestAnimationFrame(_ => this.updateTBody())); - } -} - -if (!window.customElements.get('annotations-inspector')) { - window.customElements.define('annotations-inspector', AnnotationsInspector); -} diff --git a/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts b/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts deleted file mode 100644 index f7af54afe..000000000 --- a/packages/@atjson/editor/utils/inspector-gadget/character-counter.ts +++ /dev/null @@ -1,82 +0,0 @@ -import WebComponent from '../../src/mixins/component'; - -export default class CharacterCounter extends WebComponent { - static template = "
\n
"; - - static style = ` - .caret-wrapper { - display: inline; - position: relative; - width: 0; - } - - .caret { - background-color: rgb(96, 200, 240); - display: inline-block; - width: 2px; - border: 0; - padding: 0; - position: absolute; - left: -1px; - z-index: -1; - } - - .highlight { - background-color: rgb(96, 200, 240); - } - `; - - static observedAttributes = ['start', 'end', 'length']; - - renderCounter() { - let start = parseInt(this.getAttribute('start'), 10); - let end = parseInt(this.getAttribute('end'), 10); - - let topEl = this.shadowRoot.querySelector('.top'); - let topVal = ''; - - let bottomEl = this.shadowRoot.querySelector('.bottom'); - let bottomVal = ''; - - let length = Math.max(parseInt(this.getAttribute('length'), 10), 1); - - for (let x = 0; x <= length; x++) { - if (start === x && end === x) { - bottomVal += ''; - } else { - if (start === x) { - bottomVal += ''; - } - - if (end === x) { - bottomVal += ''; - } - } - - bottomVal += x % 10; - - if (x % 10 === 0) { - topVal += x / 10; - } else { - topVal += ' '; - } - } - - topEl.innerHTML = topVal; - bottomEl.innerHTML = bottomVal; - } - - attributeChangedCallback(attribute) { - switch (attribute) { - case 'start': - case 'end': - case 'length': - window.requestAnimationFrame(_ => this.renderCounter()); - break; - } - } -} - -if (!window.customElements.get('character-counter')) { - window.customElements.define('character-counter', CharacterCounter); -} diff --git a/packages/@atjson/editor/utils/inspector-gadget/index.ts b/packages/@atjson/editor/utils/inspector-gadget/index.ts deleted file mode 100644 index 6a7b1b9c8..000000000 --- a/packages/@atjson/editor/utils/inspector-gadget/index.ts +++ /dev/null @@ -1,79 +0,0 @@ -import Document from '@atjson/document'; -import WebComponent from '../../src/mixins/component'; -import './annotations-inspector'; -import './character-counter'; - -export default class InspectorGadget extends WebComponent { - - static template = ` -

AtJSON Document Inspector

-

Content

-
- -
- -

Annotations

- `; - - static style = ` - :host { - position: fixed; - bottom: 0; - left: 0; - right: 0; - max-height: 50vh; - margin: 1em; - overflow: hidden; - border: 1px solid #555555; - padding: 0; - } - - h1 { - font-size: 1em; - font-family: helvetica; - width: calc(100vw-2em); - background-color: #bbbbbb; - padding: 4px; - margin: 0; - } - - h2 { - margin: 0; - font-size: 0.75em; - font-family: helvetica; - width: calc(100vw-2em); - background-color: #dddddd; - padding: 4px; - } - - .cc-container { - max-width: 100vw; - overflow-x: auto; - margin: 0 6px 5px 6px; - } - `; - - document: Document; - - setDocument(doc) { - this.document = doc; - this.shadowRoot.querySelector('annotations-inspector').setDocument(doc); - this.document.addEventListener('change', (_ => { - let charCounter = this.shadowRoot.querySelector('character-counter'); - charCounter.setAttribute('length', this.document.content.length); - charCounter.innerHTML = '' + this.document.content.replace(/\n/g, '¶') + ''; - })); - } - - setSelection(el) { - el.addEventListener('change', evt => { - let charCounter = this.shadowRoot.querySelector('character-counter'); - charCounter.setAttribute('start', evt.detail.start); - charCounter.setAttribute('end', evt.detail.end); - }); - } -} - -if (!window.customElements.get('inspector-gadget')) { - window.customElements.define('inspector-gadget', InspectorGadget); -} diff --git a/packages/@atjson/offset-inspector/README.md b/packages/@atjson/offset-inspector/README.md new file mode 100644 index 000000000..69ad31811 --- /dev/null +++ b/packages/@atjson/offset-inspector/README.md @@ -0,0 +1,3 @@ +# @atjson/offset-inspector + +Inspector for AtJSON documents, with integration to offset editor. diff --git a/packages/@atjson/offset-inspector/package-lock.json b/packages/@atjson/offset-inspector/package-lock.json new file mode 100644 index 000000000..921ecddb6 --- /dev/null +++ b/packages/@atjson/offset-inspector/package-lock.json @@ -0,0 +1,32 @@ +{ + "name": "@atjson/offset-editor", + "version": "0.8.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@atjson/document": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@atjson/document/-/document-0.8.4.tgz", + "integrity": "sha512-uOvHrGHfm1n0Ni4PYN/GwvcCYVeJDbVG0Tstw+mfoE0Hipw9x0dEq1dxmIyh95w5lOW4YDXNmhpA86UcMpOijA==" + }, + "@atjson/renderer-commonmark": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@atjson/renderer-commonmark/-/renderer-commonmark-0.8.4.tgz", + "integrity": "sha512-mQQnuqAt3Q3jBRlSx0VBDUX5OaqDJTS0UtNw6/GpVuBGFzzbjlbiizQVcCwvq69txtBHshlDxmugHoAM/+41BA==", + "requires": { + "@atjson/document": "0.8.4", + "@atjson/hir": "0.8.4" + }, + "dependencies": { + "@atjson/hir": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@atjson/hir/-/hir-0.8.4.tgz", + "integrity": "sha512-DG7UVtEpiVjLcCNPGMIW0biGLgEBNQyB+fP4YPmouarCdqeAsLZpnwFYBTzy54SjEz5mikSkG9CXcnNx9J/HjQ==", + "requires": { + "@atjson/document": "0.8.4" + } + } + } + } + } +} diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json new file mode 100644 index 000000000..95b1304d3 --- /dev/null +++ b/packages/@atjson/offset-inspector/package.json @@ -0,0 +1,37 @@ +{ + "name": "@atjson/offset-inspector", + "version": "0.8.0", + "description": "Offset AtJSON Inspector", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "scripts": { + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", + "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "prepublishOnly": "npm run build", + "start": "parcel public/index.html", + "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" + }, + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "browserslist": [ + "last 2 Chrome versions" + ], + "dependencies": { + "@atjson/document": "^0.7.16", + "@atjson/editor": "^0.8.0", + "@atjson/hir": "^0.8.0", + "@atjson/renderer-commonmark": "^0.8.4", + "@atjson/renderer-webcomponent": "0.8.0", + "@atjson/offset-core-components": "0.8.0", + "node-sass": "^4.9.0" + }, + "devDependencies": { + "parcel-bundler": "1.9.7", + "ts-loader": "^4.0.0", + "tslint": "^5.9.1", + "typescript": "^2.8.1" + } +} diff --git a/packages/@atjson/offset-inspector/public/app.ts b/packages/@atjson/offset-inspector/public/app.ts new file mode 100644 index 000000000..df780add8 --- /dev/null +++ b/packages/@atjson/offset-inspector/public/app.ts @@ -0,0 +1,48 @@ +import Document from '@atjson/document'; +import '@atjson/editor'; +import OffsetCoreComponents from '@atjson/offset-core-components'; +import '../src'; +import Superscript from './superscript'; + +// Web components in the registry can't be redefined, +// so reload the page on every change +if (module.hot) { + module.hot.dispose(() => { + window.location.reload(); + }); +} + +document.addEventListener('DOMContentLoaded', () => { + + let editor: OffsetEditor = document.querySelector('offset-editor'); + + for (let component of OffsetCoreComponents) { + editor.addContentFeature(component); + } + editor.addContentFeature(Superscript); + + let doc = new URL(location.toString()).searchParams.get('document'); + if (doc) { + editor.setDocument(new Document(JSON.parse(doc))); + } else { + let doc = new Document({ + content: 'Heading 1\nSome text that is both bold and italic plus something after.', + annotations: [ + { type: 'bold', display: 'inline', start: 33, end: 41 }, + { type: 'link', display: 'inline', start: 30, end: 34, attributes: { url: 'https://google.com' } }, + { type: 'italic', display: 'inline', start: 38, end: 48 }, + { type: 'underline', display: 'inline', start: 38, end: 48 }, + { type: 'heading', display: 'block', start: 0, end: 10, attributes: { level: '1' } }, + { type: 'paragraph', display: 'block', start: 10, end: 71 }, + { type: 'superscript', display: 'inline', start: 41, end: 48 } +// +// { type: 'strikethrough', display: 'inline', start: 40, end: 50 }, +// { type: 'font', display: 'inline', start: 15, end: 25, attributes: { 'font-family': 'Sans-serif', 'font-size': '200%' } }, +// { type: 'color', display: 'inline', start: 20, end: 30, attributes: { } }, +// { type: 'superscript', display: 'inline', start: 41, end: 48 }, + ] + }); + + editor.setDocument(doc); + } +}); diff --git a/packages/@atjson/editor/demo/index.html b/packages/@atjson/offset-inspector/public/index.html similarity index 100% rename from packages/@atjson/editor/demo/index.html rename to packages/@atjson/offset-inspector/public/index.html diff --git a/packages/@atjson/offset-inspector/public/style.scss b/packages/@atjson/offset-inspector/public/style.scss new file mode 100644 index 000000000..e0218f9d8 --- /dev/null +++ b/packages/@atjson/offset-inspector/public/style.scss @@ -0,0 +1,3 @@ +body { + margin: 0em; +} diff --git a/packages/@atjson/offset-inspector/public/superscript.ts b/packages/@atjson/offset-inspector/public/superscript.ts new file mode 100644 index 000000000..82f990fbf --- /dev/null +++ b/packages/@atjson/offset-inspector/public/superscript.ts @@ -0,0 +1,35 @@ + +export default class Superscript { + static annotationName = 'superscript'; + + static elementRenderer = (node: any): Element => { + return document.createElement('sup'); + } + + static get selectionButton() { + let el = document.createElement('button'); + el.setAttribute('data-type', this.annotationName); + el.innerHTML = this.annotationName; + let start + let end; + + el.addEventListener('selectionchange', (evt: CustomEvent) => { + start = evt.detail.start; + end = evt.detail.end; + console.log('set start and end to', { start, end }) + }); + + el.addEventListener('click', _ => { + el.dispatchEvent(new CustomEvent('addAnnotation', { + bubbles: true, + composed: true, + detail: { + type: 'superscript', + start, + end + } + })); + }); + return el; + } +} diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotation-attribute.ts similarity index 66% rename from packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts rename to packages/@atjson/offset-inspector/src/document-inspector/annotation-attribute.ts index 40d190d4f..af56c5862 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/annotation-attribute.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotation-attribute.ts @@ -1,7 +1,23 @@ import WebComponent from '../../src/mixins/component'; export default class AnnotationAttribute extends WebComponent { - static template = ' = ' + static template = '
: ""
'; + + static style = ` + .attribute { + padding: 0; + margin: 0; + } + + .name { + padding-left: 1em; + color: rgb(153, 69, 0); + } + + .value { + color: rgb(26, 26, 166); + } + `; static observedAttributes = ['name', 'value']; diff --git a/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts similarity index 53% rename from packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts rename to packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts index 8372473d3..70b04b227 100644 --- a/packages/@atjson/editor/utils/inspector-gadget/annotation-inspector.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts @@ -4,12 +4,38 @@ import './annotation-attribute'; export default class AnnotationInspector extends WebComponent { static template = ` - - - - - - +
+ + {} +
+ [
] +
+
+ `; + + static style = ` + :host { + font-family: Consolas, Lucida Console, Courier New, monospace; + width: 100%; + } + + .annotation { + padding: 1ex; + border-bottom: 1px solid #ccc; + position: relative; + } + + .type { + color: rgb(136, 18, 128); + } + + .position { + position: absolute; + top: 1ex; + right: 1ex; + display: flex; + flex-direction: row; + } `; static observedAttributes = ['type', 'start', 'end', 'attributes']; @@ -24,22 +50,6 @@ export default class AnnotationInspector extends WebComponent { break; case 'end': this.shadowRoot.querySelector('.end').innerHTML = this.getAttribute('end'); - break; - case 'attributes': - let attributes; - try { - attributes = JSON.parse(this.getAttribute('attributes')); - } catch { - this.shadowRoot.querySelector('.attributes').innerHTML = ''; - return; - } - - let inner = []; - this.shadowRoot.querySelector('.attributes').innerHTML = attributes.keys.map(key => { - return `
`; - this.shadowRoot.querySelector('.attributes'); - }).join(''); - break; } } diff --git a/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts new file mode 100644 index 000000000..2b9e39d01 --- /dev/null +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts @@ -0,0 +1,42 @@ +import Document from '@atjson/document'; +import WebComponent from '../../src/mixins/component'; +import './annotation-attribute'; +import './annotation-inspector'; + +export default class AnnotationsInspector extends WebComponent { + + static template = ``; + + static style = ` + .container { + overflow-y: scroll; + position: relative; + max-height: 100%; + } + `; + + document: Document; + + updateBody() { + let body = ''; + this.document.annotations.sort((a, b) => a.start - b.start).forEach(a => { + body += ``; + if (a.attributes) { + Object.keys(a.attributes).forEach(key => { + body += ``; + }); + } + body += ''; + }); + this.shadowRoot.innerHTML = body; + } + + setDocument(doc) { + this.document = doc; + this.document.addEventListener('change', _ => window.requestAnimationFrame(_ => this.updateBody())); + } +} + +if (!window.customElements.get('annotations-inspector')) { + window.customElements.define('annotations-inspector', AnnotationsInspector); +} diff --git a/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts new file mode 100644 index 000000000..2b5410cb0 --- /dev/null +++ b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts @@ -0,0 +1,88 @@ +import WebComponent from '../../src/mixins/component'; + +export default class CharacterCounter extends WebComponent { + static template = ` +

+  `;
+
+  static style = `
+    :host {
+      position: relative;
+    }
+
+    .content {
+      white-space: pre-wrap;
+    }
+
+    .caret-wrapper {
+      display: inline;
+      position: relative;
+      width: 0;
+    }
+
+    .caret {
+      background-color: rgb(96, 200, 240);
+      display: inline-block;
+      width: 2px;
+      border: 0;
+      padding: 0;
+      position: absolute;
+      left: -1px;
+      z-index: -1;
+    }
+
+    .highlight {
+      background-color: rgb(96, 200, 240);
+    }
+
+
+  `;
+
+  static observedAttributes = ['start', 'end', 'content'];
+
+  updateContent() {
+    const start = parseInt(this.getAttribute('start'), 10);
+    const end = parseInt(this.getAttribute('end'), 10);
+    let contentSpan = this.shadowRoot.querySelector('.content');
+    let rawContent = this.getAttribute('content').replace(/\n/g, '¶');
+    let content = document.createElement('span');
+
+    let contentStart = document.createTextNode(rawContent.substr(0, start));
+    let contentEnd = document.createTextNode(rawContent.substr(end));
+    let highlight = document.createElement('span');
+
+    if (start === end) {
+      highlight.classList.add('caret-wrapper');
+      let caret = document.createElement('span');
+      caret.classList.add('caret');
+      caret.textContent = '\u200B';
+      highlight.appendChild(caret);
+    }  else {
+      let contentHighlight = document.createTextNode(rawContent.substr(start, end - start));
+      highlight.classList.add('highlight');
+      highlight.appendChild(contentHighlight);
+    }
+
+    content.appendChild(contentStart);
+    content.appendChild(highlight);
+    content.appendChild(contentEnd);
+
+    contentSpan.innerHTML = '';
+    contentSpan.appendChild(content);
+  }
+
+
+  attributeChangedCallback(attribute) {
+    switch (attribute) {
+      case 'start':
+      case 'end':
+      case 'content':
+        this.updateContent();
+        break;
+    }
+  }
+}
+
+if (!window.customElements.get('character-counter')) {
+  window.customElements.define('character-counter', CharacterCounter);
+}
diff --git a/packages/@atjson/offset-inspector/src/document-inspector/index.ts b/packages/@atjson/offset-inspector/src/document-inspector/index.ts
new file mode 100644
index 000000000..c19cefc3a
--- /dev/null
+++ b/packages/@atjson/offset-inspector/src/document-inspector/index.ts
@@ -0,0 +1,129 @@
+import Document from '@atjson/document';
+import WebComponent from '../mixins/component';
+import './annotations-inspector';
+import './character-counter';
+
+export default class InspectorGadget extends WebComponent {
+
+  static template = `
+    
AtJSON
+
+
Content
+
+ + +
+
+ +
+
+ +
+
Annotations
+ +
`; + + static style = ` + .heading { + font-size: 12px; + line-height: 15px; + height: 26px; + font-family: helvetica; + background-color: #f3f3f3; + color: #333; + padding: 0; + margin: 0; + font-weight: normal; + font-family: 'Segoe UI', Tahoma, sans-serif; + border-bottom: 1px solid #ccc; + display: flex; + flex-direction: row; + } + + .heading > div { + padding: 4px 1em; + border-bottom: 2px solid #03a9f4; + } + + .content { + margin-top: 1em; + } + + section > .heading { + border-top: 1px solid #ccc; + background-color: #f6f6f6; + } + + section > .heading > div { + border-bottom: none; + } + + .content { + font-family: Consolas, Lucida Console, Courier New, monospace; + position: relative; + box-sizing: border; + } + + .content .open, .content .close { + color: #333; + font-weight: bold + } + + .cc-container { + max-width: 100%; + overflow-x: auto; + margin: 0 6px 5px 6px; + } + + .position { + position: absolute; + top: 1ex; + right: 1ex; + } + + .position.is-caret .end { + display: none; + } + `; + + document: Document; + + updatePosition({start, end}) { + this.shadowRoot.querySelector('.start').textContent = start; + this.shadowRoot.querySelector('.end').textContent = end; + + if (start === end) { + this.shadowRoot.querySelector('.position').classList.add('is-caret'); + } else { + this.shadowRoot.querySelector('.position').classList.remove('is-caret'); + } + } + + setDocument(doc) { + this.document = doc; + this.shadowRoot.querySelector('annotations-inspector').setDocument(doc); + this.document.addEventListener('change', (_ => { + if (this.deferred) clearTimeout(this.deferred); + this.deferred = setTimeout(_ => { + let charCounter = this.shadowRoot.querySelector('character-counter'); + charCounter.setAttribute('content', this.document.content); + }, 500); + })); + } + + setSelection(el) { + el.addEventListener('change', evt => { + if (this.selDeferred) clearTimeout(this.selDeferred); + this.selDeferred = setTimeout(_ => { + let charCounter = this.shadowRoot.querySelector('character-counter'); + charCounter.setAttribute('start', evt.detail.start); + charCounter.setAttribute('end', evt.detail.end); + this.updatePosition(evt.detail); + }, 500); + }); + } +} + +if (!window.customElements.get('inspector-gadget')) { + window.customElements.define('inspector-gadget', InspectorGadget); +} diff --git a/packages/@atjson/offset-inspector/src/html-tree-inspector.ts b/packages/@atjson/offset-inspector/src/html-tree-inspector.ts new file mode 100644 index 000000000..8de290493 --- /dev/null +++ b/packages/@atjson/offset-inspector/src/html-tree-inspector.ts @@ -0,0 +1,225 @@ +import Document from '@atjson/document'; +import WebComponentRenderer from '@atjson/renderer-webcomponent'; +import WebComponent from './mixins/component'; + +export default class HTMLTreeInspector extends WebComponent { + + static template = '
'; + + static events = { + click: 'handleClick', + change: 'render' + }; + + static style = ` + ol { + list-style-type: none; + font-family: Consolas, Lucida Console, Courier New, monospace; + border-left: 1px solid #ccc; + -webkit-padding-start: 0; + margin: 0 0 0 6px; + } + + .wrapper > ol { + border-left: none; + padding-left: 0; + } + + li { + padding-left: 18px; + } + + li.collapsible { + padding-left: 0; + } + + li.collapsible > ol { + padding-left: 8px; + } + + li > .arrow::before { + content: "\u2BC6"; + } + + li.collapsed > .arrow::before { + content: "\u2BC8"; + } + + li .arrow { + color: #727272; + padding-right: 4px; + } + + li.collapsed ol { + display: none; + } + + li > .ellip { + display: none; + } + + li.collapsed > .ellip { + display: inline; + } + + .html-tag { + color: rgb(168, 148, 166); + } + + li.collapsible > .html-tag.closing { + padding-left: 11px; + margin-left: 6px; + border-left: 1px solid #ccc; + } + + li.collapsed > .html-tag.closing { + padding-left: 0; + margin-left: 0; + border-left: none; + } + + .html-tag-name { + color: rgb(136, 18, 128); + } + + .html-attribute-name { + padding-left: 1ex; + color: rgb(153, 69, 0); + } + + .html-attribute-value { + color: rgb(26, 26, 166); + } + `; + + document: Document; + + render(event: CustomEvent) { + if (this.deferred) clearTimeout(this.deferred); + + this.deferred = setTimeout(_ => { + let doc = event.detail.document; + let outputElement = this.shadowRoot.querySelector('.wrapper'); + let rendered = new WebComponentRenderer(doc).render(); + + let children = this.renderChildren(rendered.childNodes); + outputElement.innerHTML = ''; + outputElement.appendChild(children); + }, 100); + + } + + handleClick(event: MouseEvent) { + if (event.path[0].classList.contains('arrow')) { + event.path[1].classList.toggle('collapsed'); + } + } + + addComponent(component) { + WebComponentRenderer.prototype[component.annotationName] = component.elementRenderer; + } + + private renderChildren(children) { + let ol = document.createElement('ol'); + for (let child of children) { + let li = document.createElement('li'); + + if (child.nodeType === 3) { + let text = document.createTextNode('"' + child.textContent.replace('\n', '\\n') + '"'); + li.appendChild(text); + ol.appendChild(li); + continue; + } + + let openTag = this.genTag(child); + let closeTag = this.genTag(child, true); + + if (child.childNodes.length === 1 && child.childNodes[0].nodeType === 3) { + let innerText = document.createTextNode(child.childNodes[0].textContent.replace('\n', '\\n')); + li.appendChild(openTag); + li.appendChild(innerText); + li.appendChild(closeTag); + } else { + if (child.childNodes.length > 0) this.renderArrow(li); + li.appendChild(openTag); + this.renderEllip(li); + li.appendChild(this.renderChildren(child.childNodes)); + li.appendChild(closeTag); + } + ol.appendChild(li); + } + return ol; + } + + private genAttrs(node: HTMLElement) { + let attrs = document.createElement('span'); + attrs.classList.add('html-attributes'); + + for (let attr of node.attributes) { + if (attr.name === 'data-annotation-id') continue; + + let attrElement = document.createElement('span'); + attrElement.classList.add('html-attribute'); + + let attrName = document.createElement('span'); + attrName.classList.add('html-attribute-name'); + attrName.textContent = attr.name; + + let attrValue = document.createElement('span'); + attrValue.classList.add('html-attribute-value'); + attrValue.textContent = attr.value; + + attrElement.appendChild(attrName); + attrElement.appendChild(document.createTextNode('="')); + attrElement.appendChild(attrValue); + attrElement.appendChild(document.createTextNode('"')); + + attrs.appendChild(attrElement); + } + return attrs; + } + + private genTag(node: HTMLElement, closing: boolean = false) { + let tag = document.createElement('span'); + + let openStr = '<'; + if (closing) openStr += '/'; + + let open = document.createTextNode(openStr); + let close = document.createTextNode('>'); + + tag.classList.add('html-tag'); + if (closing) tag.classList.add('closing'); + + let tagName = document.createElement('span'); + tagName.classList.add('html-tag-name'); + tagName.textContent = node.tagName.toLowerCase(); + + tag.appendChild(open); + tag.appendChild(tagName); + if (!closing) tag.appendChild(this.genAttrs(node)); + + tag.appendChild(close); + + return tag; + } + + private renderArrow(li: HTMLLIElement) { + li.classList.add('collapsed'); + li.classList.add('collapsible'); + let arrow = document.createElement('span'); + arrow.classList.add('arrow'); + li.appendChild(arrow); + } + + private renderEllip(li: HTMLLIElement) { + let ellip = document.createElement('span'); + ellip.textContent = '\u2026'; + ellip.classList.add('ellip'); + li.appendChild(ellip); + } +} + +if (!window.customElements.get('html-tree-inspector')) { + window.customElements.define('html-tree-inspector', HTMLTreeInspector); +} diff --git a/packages/@atjson/offset-inspector/src/index.ts b/packages/@atjson/offset-inspector/src/index.ts new file mode 100644 index 000000000..adf0d8df5 --- /dev/null +++ b/packages/@atjson/offset-inspector/src/index.ts @@ -0,0 +1,164 @@ +import Document from '@atjson/document'; +import CommonmarkRenderer from '@atjson/renderer-commonmark'; +import InspectorGadget from './document-inspector'; +import './document-inspector'; +import './html-tree-inspector'; +//import '../public/logo'; +import WebComponent from './mixins/component'; + +export default class OffsetEditorDemo extends WebComponent { + static template = '

' + + '
' + + '
' + + '
' + + '
Editor
' + + '
HTML
' + + '
Commonmark
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
'; + + static events = { + 'change'(evt: CustomEvent) { + this.shadowRoot.querySelector('html-tree-inspector').dispatchEvent(new CustomEvent('change', {detail: {document: evt.detail.document}})); + this.renderMarkdown(evt.detail.document); + this.renderInspector(evt.detail.document); + }, + + 'click .tabs'(event) { + let targetTabClass = event.path[0].getAttribute('data-target'); + let active = this.shadowRoot.querySelector('.editor > .active'); + if (active) { + active.classList.remove('active'); + } + this.shadowRoot.querySelector('.editor > .' + targetTabClass).classList.add('active'); + this.shadowRoot.querySelector('.editor > .tabs > .active').classList.remove('active'); + event.path[0].classList.add('active'); + }, + + 'addComponent'(event) { + console.log('saw event!', event); + this.shadowRoot.querySelector('html-tree-inspector').addComponent(event.detail.component); + } + }; + + static style = ` + :host { + max-height: 100vh; + max-width: 100vw; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + } + + :host > h1 { + padding: 1ex; + margin: 0; + border-bottom: 1px solid #bbb; + background-color: #f3f3f3 + } + + .demo { + display: flex; + flex-direction: row; + margin: 0; + padding: 0; + height: 100vh; + width: 100vw; + overflow: hidden; + } + + .demo > section { + position: relative; + flex-grow: 1; + max-height: 100%; + width: 50%; + } + + .editor { + padding-right: 1px; + padding-bottom: 2em; + border-right: 1px solid #ccc; + } + + .tabs { + display: flex; + flex-direction: row; + justify-content: flex-start; + background-color: #f3f3f3; + color: #333; + font-family: 'Segoe UI', Tahoma, sans-serif; + height: 26px; + line-height: 15px; + font-size: 12px; + border-bottom: 1px solid #ccc; + position: sticky; + top: 0; + } + + .tabs > div { + padding: 4px 1em; + border-bottom: 1px solid #ccc; + } + + .tabs > div:hover { + background-color: #eaeaea; + cursor: pointer; + } + + .tabs > .active { + border-bottom: 2px solid #03a9f4; + } + + .editor > section { + display: none; + overflow-y: auto; + position: relative; + max-height: calc(100% - 24px); + box-sizing: border-box; + padding: 1em; + } + + .editor > section.active { + display: inherit; + } + + .markdown { + white-space: pre-wrap; + font-family: Consolas, Lucida Console, Courier New, monospace; + } + `; + + renderMarkdown(doc: Document) { + let outputElement = this.shadowRoot.querySelector('.markdown'); + let rendered = new CommonmarkRenderer().render(doc); + if (outputElement) { + outputElement.textContent = rendered; + } + } + + renderInspector(doc: Document) { + // This is really ineffecient, because we're calling it every document + // change at the moment. To fix this, we need a new "changedocument" or + // similar event on the editor. + let inspectorGadget: InspectorGadget = this.shadowRoot.querySelector('inspector-gadget'); + let editor = this.querySelector('offset-editor'); + + console.log('in here?', doc) + if (inspectorGadget) { + inspectorGadget.setDocument(doc); + inspectorGadget.setSelection(editor.getSelection()); + } + } +} + +if (!window.customElements.get('offset-editor-demo')) { + window.customElements.define('offset-editor-demo', OffsetEditorDemo); +} diff --git a/packages/@atjson/offset-inspector/src/mixins/component.ts b/packages/@atjson/offset-inspector/src/mixins/component.ts new file mode 100644 index 000000000..ed9e74d42 --- /dev/null +++ b/packages/@atjson/offset-inspector/src/mixins/component.ts @@ -0,0 +1,34 @@ +import events from './events'; + +export default class WebComponent extends events(HTMLElement) { + static template: string; + static style: string | null; + private static compiledElement: Element; + + private static get compiledTemplate(): Element { + if (!this.compiledElement) { + this.compiledElement = document.createElement('template'); + let scopedStyles = this.style; + let html = this.template; + if (scopedStyles) { + html = `${html}`; + } + this.compiledElement.innerHTML = html; + } + return this.compiledElement; + } + + constructor() { + super(); + let shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); + } + + dispatchAttributeChangeEvent(attributes: {}) { + let event = new CustomEvent('attributechange', { + detail: attributes, + bubbles: true + }); + this.dispatchEvent(event); + } +} diff --git a/packages/@atjson/offset-inspector/src/mixins/events.ts b/packages/@atjson/offset-inspector/src/mixins/events.ts new file mode 100644 index 000000000..a97da3a5a --- /dev/null +++ b/packages/@atjson/offset-inspector/src/mixins/events.ts @@ -0,0 +1,102 @@ +type Constructor = new (...args: any[]) => T; + +export interface EventCallback { + (evt: Event): boolean; +} + +export interface EventHandlerDefinitions { + [key: string]: string | EventCallback; +} + +export interface EventHandlerReferences { + [key: string]: EventCallback; +} + +function getEventNameAndElement(element: HTMLElement, definition: string) { + let [eventName, ...selectors] = definition.split(' '); + let selector = selectors.join(' '); + if (selector === 'document') { + return { eventName, element: document }; + } else if (selector === 'window') { + return { eventName, element: window }; + } else if (selector === '') { + return { eventName, element }; + } else { + let querySelector; + if (element.shadowRoot) { + querySelector = element.shadowRoot.querySelector(selector) || element.querySelector(selector); + } else { + querySelector = element.querySelector(selector); + } + return { eventName, element: querySelector }; + } +} + +/** + * The events mixin is a Backbone-flavored event management system + * that automatically sets up and tears down events on web components + * when they are connected and disconnected from a document. + * + * To use this, include the events mixin on your web component, + * and add a static property called `events` that provides a lookup + * table to the events that you'd like to attach to your component. + * + * ```js + * import events from './mixins/events'; + * + * export default TextSelection extends events(HTMLElement) { + * static events = { + * 'selectionchange document': 'selectedTextDidChange', + * 'mousedown': 'willSelectText', + * 'mouseup': 'didSelectText' + * }; + * } + * ``` + * + * The selectors for `window` and `document` will select only those + * elements; all other selectors will lookup in the scope of the web + * component. This allows components to look at events like scrolling, + * resizing, and selection events without using `addEventListener` / + * `removeEventListener`. + */ +export default function(Base: HTMLElement) { + return class extends Base { + static events: EventHandlerDefinitions | null; + private eventHandlers: EventHandlerReferences; + + constructor(...args: any[]) { + super(...args); + this.eventHandlers = {}; + } + + connectedCallback() { + let events: EventHandlerDefinitions = this.constructor.events || {}; + Object.keys(events).forEach((definition: string) => { + let { eventName, element } = getEventNameAndElement(this, definition); + let method = events[definition]; + if (typeof method === 'string') { + this.eventHandlers[definition] = (evt): EventCallback | never => { + if (this[method]) { + return this[method](evt); + } else { + throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); + } + }; + } else { + this.eventHandlers[definition] = (evt): EventCallback => { + return method.call(this, evt); + }; + } + element.addEventListener(eventName, this.eventHandlers[definition]); + }); + } + + disconnectedCallback() { + Object.keys(this.eventHandlers).forEach((definition) => { + let { eventName, element } = getEventNameAndElement(this, definition); + element.removeEventListener(eventName, this.eventHandlers[definition]); + }); + this.eventHandlers = {}; + } + }; +} diff --git a/packages/@atjson/offset-inspector/tsconfig.json b/packages/@atjson/offset-inspector/tsconfig.json new file mode 100644 index 000000000..8e0557d00 --- /dev/null +++ b/packages/@atjson/offset-inspector/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "target": "es2017", + "outDir": "./dist/commonjs" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/@atjson/offset-inspector/tslint.json b/packages/@atjson/offset-inspector/tslint.json new file mode 100644 index 000000000..30612ee31 --- /dev/null +++ b/packages/@atjson/offset-inspector/tslint.json @@ -0,0 +1,30 @@ +{ + "extends": "tslint:recommended", + "defaultSeverity": "warning", + "rules": { + "arrow-parens": [true, "ban-single-arg-parens"], + "curly": [true, "ignore-same-line"], + "forin": false, + "interface-name": [true, "never-prefix"], + "max-classes-per-file": [false], + "max-line-length": [false], + "member-access": [true, "no-public"], + "no-empty-interface": false, + "object-literal-sort-keys": false, + "ordered-imports": [ + true, + { + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-last" + } + ], + "prefer-const": false, + "quotemark": [true, "single"], + "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], + "whitespace": [true, + "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", + "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" + ] + } +} From abf0376057efc59f97c1221c809b3df2da3d3e4a Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 30 Jul 2018 15:22:26 +0100 Subject: [PATCH 075/104] move core web components to separate package --- .../@atjson/offset-core-components/README.md | 3 + .../offset-core-components/package.json | 35 ++++++ .../src/components/blockquote.ts | 0 .../src/components/bold.ts | 0 .../src/components/code.ts | 0 .../src/components/color-editor.ts | 0 .../src/components/color.ts | 0 .../src/components/font-editor.ts | 0 .../src/components/font.ts | 0 .../src/components/heading-action-button.ts | 0 .../src/components/heading.ts | 0 .../src/components/italic.ts | 0 .../src/components/line-break.ts | 0 .../src/components/link-editor.ts | 0 .../src/components/link.ts | 0 .../src/components/paragraph.ts | 0 .../src/components/strikethrough.ts | 0 .../src/components/superscript.ts | 10 ++ .../src/components/underline.ts | 0 .../offset-core-components/src/index.ts | 21 ++++ .../src/mixins/component.ts | 34 ++++++ .../src/mixins/editable-component.ts | 0 .../src/mixins/events.ts | 102 ++++++++++++++++++ .../offset-core-components/tsconfig.json | 10 ++ .../offset-core-components/tslint.json | 30 ++++++ 25 files changed, 245 insertions(+) create mode 100644 packages/@atjson/offset-core-components/README.md create mode 100644 packages/@atjson/offset-core-components/package.json rename packages/@atjson/{editor => offset-core-components}/src/components/blockquote.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/bold.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/code.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/color-editor.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/color.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/font-editor.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/font.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/heading-action-button.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/heading.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/italic.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/line-break.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/link-editor.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/link.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/paragraph.ts (100%) rename packages/@atjson/{editor => offset-core-components}/src/components/strikethrough.ts (100%) create mode 100644 packages/@atjson/offset-core-components/src/components/superscript.ts rename packages/@atjson/{editor => offset-core-components}/src/components/underline.ts (100%) create mode 100644 packages/@atjson/offset-core-components/src/index.ts create mode 100644 packages/@atjson/offset-core-components/src/mixins/component.ts rename packages/@atjson/{editor => offset-core-components}/src/mixins/editable-component.ts (100%) create mode 100644 packages/@atjson/offset-core-components/src/mixins/events.ts create mode 100644 packages/@atjson/offset-core-components/tsconfig.json create mode 100644 packages/@atjson/offset-core-components/tslint.json diff --git a/packages/@atjson/offset-core-components/README.md b/packages/@atjson/offset-core-components/README.md new file mode 100644 index 000000000..3190a5181 --- /dev/null +++ b/packages/@atjson/offset-core-components/README.md @@ -0,0 +1,3 @@ +# @atjson/offset-core-components + +Core Components for Offset & Poetica diff --git a/packages/@atjson/offset-core-components/package.json b/packages/@atjson/offset-core-components/package.json new file mode 100644 index 000000000..11f42bcb8 --- /dev/null +++ b/packages/@atjson/offset-core-components/package.json @@ -0,0 +1,35 @@ +{ + "name": "@atjson/offset-core-components", + "version": "0.8.0", + "description": "Offset Core Components", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "scripts": { + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", + "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "prepublishOnly": "npm run build", + "start": "parcel public/index.html", + "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" + }, + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "browserslist": [ + "last 2 Chrome versions" + ], + "dependencies": { + "@atjson/document": "^0.7.16", + "@atjson/renderer-webcomponent": "0.8.0", + "@atjson/renderer-commonmark": "0.8.2", + "@atjson/hir": "^0.8.0", + "node-sass": "^4.9.0" + }, + "devDependencies": { + "parcel-bundler": "1.9.7", + "ts-loader": "^4.0.0", + "tslint": "^5.9.1", + "typescript": "^2.8.1" + } +} diff --git a/packages/@atjson/editor/src/components/blockquote.ts b/packages/@atjson/offset-core-components/src/components/blockquote.ts similarity index 100% rename from packages/@atjson/editor/src/components/blockquote.ts rename to packages/@atjson/offset-core-components/src/components/blockquote.ts diff --git a/packages/@atjson/editor/src/components/bold.ts b/packages/@atjson/offset-core-components/src/components/bold.ts similarity index 100% rename from packages/@atjson/editor/src/components/bold.ts rename to packages/@atjson/offset-core-components/src/components/bold.ts diff --git a/packages/@atjson/editor/src/components/code.ts b/packages/@atjson/offset-core-components/src/components/code.ts similarity index 100% rename from packages/@atjson/editor/src/components/code.ts rename to packages/@atjson/offset-core-components/src/components/code.ts diff --git a/packages/@atjson/editor/src/components/color-editor.ts b/packages/@atjson/offset-core-components/src/components/color-editor.ts similarity index 100% rename from packages/@atjson/editor/src/components/color-editor.ts rename to packages/@atjson/offset-core-components/src/components/color-editor.ts diff --git a/packages/@atjson/editor/src/components/color.ts b/packages/@atjson/offset-core-components/src/components/color.ts similarity index 100% rename from packages/@atjson/editor/src/components/color.ts rename to packages/@atjson/offset-core-components/src/components/color.ts diff --git a/packages/@atjson/editor/src/components/font-editor.ts b/packages/@atjson/offset-core-components/src/components/font-editor.ts similarity index 100% rename from packages/@atjson/editor/src/components/font-editor.ts rename to packages/@atjson/offset-core-components/src/components/font-editor.ts diff --git a/packages/@atjson/editor/src/components/font.ts b/packages/@atjson/offset-core-components/src/components/font.ts similarity index 100% rename from packages/@atjson/editor/src/components/font.ts rename to packages/@atjson/offset-core-components/src/components/font.ts diff --git a/packages/@atjson/editor/src/components/heading-action-button.ts b/packages/@atjson/offset-core-components/src/components/heading-action-button.ts similarity index 100% rename from packages/@atjson/editor/src/components/heading-action-button.ts rename to packages/@atjson/offset-core-components/src/components/heading-action-button.ts diff --git a/packages/@atjson/editor/src/components/heading.ts b/packages/@atjson/offset-core-components/src/components/heading.ts similarity index 100% rename from packages/@atjson/editor/src/components/heading.ts rename to packages/@atjson/offset-core-components/src/components/heading.ts diff --git a/packages/@atjson/editor/src/components/italic.ts b/packages/@atjson/offset-core-components/src/components/italic.ts similarity index 100% rename from packages/@atjson/editor/src/components/italic.ts rename to packages/@atjson/offset-core-components/src/components/italic.ts diff --git a/packages/@atjson/editor/src/components/line-break.ts b/packages/@atjson/offset-core-components/src/components/line-break.ts similarity index 100% rename from packages/@atjson/editor/src/components/line-break.ts rename to packages/@atjson/offset-core-components/src/components/line-break.ts diff --git a/packages/@atjson/editor/src/components/link-editor.ts b/packages/@atjson/offset-core-components/src/components/link-editor.ts similarity index 100% rename from packages/@atjson/editor/src/components/link-editor.ts rename to packages/@atjson/offset-core-components/src/components/link-editor.ts diff --git a/packages/@atjson/editor/src/components/link.ts b/packages/@atjson/offset-core-components/src/components/link.ts similarity index 100% rename from packages/@atjson/editor/src/components/link.ts rename to packages/@atjson/offset-core-components/src/components/link.ts diff --git a/packages/@atjson/editor/src/components/paragraph.ts b/packages/@atjson/offset-core-components/src/components/paragraph.ts similarity index 100% rename from packages/@atjson/editor/src/components/paragraph.ts rename to packages/@atjson/offset-core-components/src/components/paragraph.ts diff --git a/packages/@atjson/editor/src/components/strikethrough.ts b/packages/@atjson/offset-core-components/src/components/strikethrough.ts similarity index 100% rename from packages/@atjson/editor/src/components/strikethrough.ts rename to packages/@atjson/offset-core-components/src/components/strikethrough.ts diff --git a/packages/@atjson/offset-core-components/src/components/superscript.ts b/packages/@atjson/offset-core-components/src/components/superscript.ts new file mode 100644 index 000000000..4d2e6f1aa --- /dev/null +++ b/packages/@atjson/offset-core-components/src/components/superscript.ts @@ -0,0 +1,10 @@ +import EditableComponent from "../mixins/editable-component"; + +export default class OffsetSuperscriptElement extends EditableComponent { + + static annotationName = 'superscript'; + + static elementRenderer = (node: any): Element => { + return document.createElement('sup'); + } +} diff --git a/packages/@atjson/editor/src/components/underline.ts b/packages/@atjson/offset-core-components/src/components/underline.ts similarity index 100% rename from packages/@atjson/editor/src/components/underline.ts rename to packages/@atjson/offset-core-components/src/components/underline.ts diff --git a/packages/@atjson/offset-core-components/src/index.ts b/packages/@atjson/offset-core-components/src/index.ts new file mode 100644 index 000000000..08f6db18c --- /dev/null +++ b/packages/@atjson/offset-core-components/src/index.ts @@ -0,0 +1,21 @@ +import OffsetBlockquote from './components/blockquote'; +import OffsetBold from './components/bold'; +import OffsetColor from './components/color'; +import OffsetFont from './components/font'; +import OffsetHeading from './components/heading'; +import OffsetItalic from './components/italic'; +import OffsetLink from './components/link'; +import OffsetParagraph from './components/paragraph'; +import OffsetStrikethrough from './components/strikethrough'; +import OffsetSuperscript from './components/superscript'; +import OffsetUnderline from './components/underline'; +import EditableComponent from './mixins/editable-component'; + +let OffsetCoreComponents = [ + OffsetBlockquote, OffsetBold, OffsetColor, OffsetFont, OffsetHeading, + OffsetItalic, OffsetLink, OffsetParagraph, OffsetStrikethrough, OffsetSuperscript, + OffsetUnderline +]; + +export default OffsetCoreComponents; +export * from './mixins/editable-component'; \ No newline at end of file diff --git a/packages/@atjson/offset-core-components/src/mixins/component.ts b/packages/@atjson/offset-core-components/src/mixins/component.ts new file mode 100644 index 000000000..ed9e74d42 --- /dev/null +++ b/packages/@atjson/offset-core-components/src/mixins/component.ts @@ -0,0 +1,34 @@ +import events from './events'; + +export default class WebComponent extends events(HTMLElement) { + static template: string; + static style: string | null; + private static compiledElement: Element; + + private static get compiledTemplate(): Element { + if (!this.compiledElement) { + this.compiledElement = document.createElement('template'); + let scopedStyles = this.style; + let html = this.template; + if (scopedStyles) { + html = `${html}`; + } + this.compiledElement.innerHTML = html; + } + return this.compiledElement; + } + + constructor() { + super(); + let shadowRoot = this.attachShadow({ mode: 'open' }); + shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); + } + + dispatchAttributeChangeEvent(attributes: {}) { + let event = new CustomEvent('attributechange', { + detail: attributes, + bubbles: true + }); + this.dispatchEvent(event); + } +} diff --git a/packages/@atjson/editor/src/mixins/editable-component.ts b/packages/@atjson/offset-core-components/src/mixins/editable-component.ts similarity index 100% rename from packages/@atjson/editor/src/mixins/editable-component.ts rename to packages/@atjson/offset-core-components/src/mixins/editable-component.ts diff --git a/packages/@atjson/offset-core-components/src/mixins/events.ts b/packages/@atjson/offset-core-components/src/mixins/events.ts new file mode 100644 index 000000000..a97da3a5a --- /dev/null +++ b/packages/@atjson/offset-core-components/src/mixins/events.ts @@ -0,0 +1,102 @@ +type Constructor = new (...args: any[]) => T; + +export interface EventCallback { + (evt: Event): boolean; +} + +export interface EventHandlerDefinitions { + [key: string]: string | EventCallback; +} + +export interface EventHandlerReferences { + [key: string]: EventCallback; +} + +function getEventNameAndElement(element: HTMLElement, definition: string) { + let [eventName, ...selectors] = definition.split(' '); + let selector = selectors.join(' '); + if (selector === 'document') { + return { eventName, element: document }; + } else if (selector === 'window') { + return { eventName, element: window }; + } else if (selector === '') { + return { eventName, element }; + } else { + let querySelector; + if (element.shadowRoot) { + querySelector = element.shadowRoot.querySelector(selector) || element.querySelector(selector); + } else { + querySelector = element.querySelector(selector); + } + return { eventName, element: querySelector }; + } +} + +/** + * The events mixin is a Backbone-flavored event management system + * that automatically sets up and tears down events on web components + * when they are connected and disconnected from a document. + * + * To use this, include the events mixin on your web component, + * and add a static property called `events` that provides a lookup + * table to the events that you'd like to attach to your component. + * + * ```js + * import events from './mixins/events'; + * + * export default TextSelection extends events(HTMLElement) { + * static events = { + * 'selectionchange document': 'selectedTextDidChange', + * 'mousedown': 'willSelectText', + * 'mouseup': 'didSelectText' + * }; + * } + * ``` + * + * The selectors for `window` and `document` will select only those + * elements; all other selectors will lookup in the scope of the web + * component. This allows components to look at events like scrolling, + * resizing, and selection events without using `addEventListener` / + * `removeEventListener`. + */ +export default function(Base: HTMLElement) { + return class extends Base { + static events: EventHandlerDefinitions | null; + private eventHandlers: EventHandlerReferences; + + constructor(...args: any[]) { + super(...args); + this.eventHandlers = {}; + } + + connectedCallback() { + let events: EventHandlerDefinitions = this.constructor.events || {}; + Object.keys(events).forEach((definition: string) => { + let { eventName, element } = getEventNameAndElement(this, definition); + let method = events[definition]; + if (typeof method === 'string') { + this.eventHandlers[definition] = (evt): EventCallback | never => { + if (this[method]) { + return this[method](evt); + } else { + throw new Error(`😭 \`${method}\` was not defined on ${this.tagName}- did you misspell or forget to add it?`); + } + }; + } else { + this.eventHandlers[definition] = (evt): EventCallback => { + return method.call(this, evt); + }; + } + element.addEventListener(eventName, this.eventHandlers[definition]); + }); + } + + disconnectedCallback() { + Object.keys(this.eventHandlers).forEach((definition) => { + let { eventName, element } = getEventNameAndElement(this, definition); + element.removeEventListener(eventName, this.eventHandlers[definition]); + }); + this.eventHandlers = {}; + } + }; +} diff --git a/packages/@atjson/offset-core-components/tsconfig.json b/packages/@atjson/offset-core-components/tsconfig.json new file mode 100644 index 000000000..8e0557d00 --- /dev/null +++ b/packages/@atjson/offset-core-components/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "target": "es2017", + "outDir": "./dist/commonjs" + }, + "include": [ + "src/**/*" + ] +} diff --git a/packages/@atjson/offset-core-components/tslint.json b/packages/@atjson/offset-core-components/tslint.json new file mode 100644 index 000000000..30612ee31 --- /dev/null +++ b/packages/@atjson/offset-core-components/tslint.json @@ -0,0 +1,30 @@ +{ + "extends": "tslint:recommended", + "defaultSeverity": "warning", + "rules": { + "arrow-parens": [true, "ban-single-arg-parens"], + "curly": [true, "ignore-same-line"], + "forin": false, + "interface-name": [true, "never-prefix"], + "max-classes-per-file": [false], + "max-line-length": [false], + "member-access": [true, "no-public"], + "no-empty-interface": false, + "object-literal-sort-keys": false, + "ordered-imports": [ + true, + { + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-last" + } + ], + "prefer-const": false, + "quotemark": [true, "single"], + "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], + "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], + "whitespace": [true, + "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", + "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" + ] + } +} From 0f02fee4401468c2f33a5cc5f89d004ba772c9b1 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 30 Jul 2018 15:23:05 +0100 Subject: [PATCH 076/104] always build tsc package --- packages/@atjson/editor/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 3d3f1f8bb..81554b390 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . & tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "start": "parcel public/index.html", From 2f44f4dd51088fc81e1d09b028f3ec1cfe5ee7ca Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 12:56:04 +0100 Subject: [PATCH 077/104] Add jenkinsfile --- Jenkinsfile | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..31c3f20ea --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,7 @@ +CnNodeBuild(project: "atjson", + nodeVersion: "nsolid-2.3.4-boron", + npmVersion: "3") { + sh "npm install" + sh "./node_modules/.bin/lerna bootstrap --hoist" + sh "./node_modules/.bin/lerna run build --parallel" +} From 399206731fa3cee0215ed91b0664e01f7a2cd156 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 13:02:47 +0100 Subject: [PATCH 078/104] Always build --- packages/@atjson/document/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/document/package.json b/packages/@atjson/document/package.json index 919b02153..59fc73a33 100644 --- a/packages/@atjson/document/package.json +++ b/packages/@atjson/document/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" From 9d0ebdc7448dc369eecd57003e7ac7b597f4d6a0 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 13:23:15 +0100 Subject: [PATCH 079/104] block transform tweaks --- packages/@atjson/document/src/index.ts | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index 5f6035bb8..744c5cae2 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -172,7 +172,7 @@ export default class AtJSON { a = this.annotations[j]; // This doesn't affect us. - if (a.type !== 'paragraph') continue; + if (a.type !== 'block') continue; if (a.end < position) continue; if (position < a.start) continue; @@ -183,7 +183,7 @@ export default class AtJSON { // And now add a new paragraph. this.addAnnotations({ type: 'paragraph', - display: 'paragraph', + display: 'block', start: position + 1, end: prevEnd }); @@ -211,6 +211,8 @@ export default class AtJSON { this.content = before + after; + let potentialMergeAnnotations = {}; + for (let i = this.annotations.length - 1; i >= 0; i--) { let a = this.annotations[i]; @@ -229,6 +231,17 @@ export default class AtJSON { } else { + let mergeType: string; + if (a.display === 'block') { + mergeType = 'block'; + } else { + mergeType = a.type; + } + if (!potentialMergeAnnotations[mergeType]) { + potentialMergeAnnotations[mergeType] = []; + } + potentialMergeAnnotations[mergeType].push(a); + if (end < a.end) { // Annotation spans the whole deleted text, so just truncate the end of @@ -266,6 +279,17 @@ export default class AtJSON { } } + + for (const type in potentialMergeAnnotations) { + let annotations = potentialMergeAnnotations[type]; + annotations = annotations.sort((a, b) => a.start - b.start); + for (let i = annotations.length - 1; i > 0; i--) { + if (annotations[i-1].end === annotations[i].start) { // && annotations[i-1].attributes.toJSON() === annotations[i].attributes.toJSON()) { + annotations[i-1].end = annotations[i].end; + this.removeAnnotation(annotations[i]); + } + } + } } this.triggerChange(); From 903f2a38516f40a54d9075c77404be2c85c6247a Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 15:06:25 +0100 Subject: [PATCH 080/104] Fix package.json merge typo --- packages/@atjson/editor/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 70de5eb57..e386a47ae 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -24,8 +24,8 @@ "@atjson/renderer-webcomponent": "0.8.0", "@atjson/renderer-commonmark": "0.8.2", "@atjson/hir": "^0.8.7", - "node-sass": "^4.9.0" - "@atjson/document": "0.8.4", + "node-sass": "^4.9.0", + "@atjson/document": "0.8.4" }, "devDependencies": { "parcel-bundler": "1.9.7", From e118172e8c5e0571fa138af2bed71ce9c2d493f9 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 15:08:59 +0100 Subject: [PATCH 081/104] always build --- packages/@atjson/renderer-webcomponent/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index 1cbf83a7f..c201c6244 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" From 4092c959446b34a16f012b3dfb123b7553c3d226 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 16:17:23 +0100 Subject: [PATCH 082/104] ugh, fix package.json hell --- package-lock.json | 10087 ---------------- packages/@atjson/document/package.json | 2 +- packages/@atjson/editor/package.json | 8 +- packages/@atjson/hir/package.json | 2 +- .../offset-core-components/package.json | 6 - .../offset-inspector/package-lock.json | 32 - .../@atjson/offset-inspector/package.json | 55 +- .../@atjson/renderer-graphviz/package.json | 2 +- .../@atjson/renderer-plain-text/package.json | 2 +- packages/@atjson/renderer-react/package.json | 2 +- .../renderer-webcomponent/package.json | 8 +- packages/@atjson/schema/package.json | 2 +- .../@atjson/source-commonmark/package.json | 2 +- .../@atjson/source-gdocs-paste/package.json | 2 +- packages/@atjson/source-html/package.json | 2 +- 15 files changed, 37 insertions(+), 10177 deletions(-) delete mode 100644 package-lock.json delete mode 100644 packages/@atjson/offset-inspector/package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e4cc2619b..000000000 --- a/package-lock.json +++ /dev/null @@ -1,10087 +0,0 @@ -{ - "name": "atjson", - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz", - "integrity": "sha512-cuAuTTIQ9RqcFRJ/Y8PvTh+paepNcaGxwQwjIDRWPXmzzyAeCO4KqS9ikMvq0MCbRk6GlYKwfzStrcP3/jSL8g==", - "dev": true, - "requires": { - "@babel/highlight": "7.0.0-beta.44" - } - }, - "@babel/highlight": { - "version": "7.0.0-beta.44", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz", - "integrity": "sha512-Il19yJvy7vMFm8AVAh6OZzaFoAd0hbkeMZiX3P5HGD+z7dyI7RzndHB0dg6Urh/VAFfHtpOIzDUSxmY6coyZWQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^3.0.0" - } - }, - "@lerna/add": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.0.0-rc.0.tgz", - "integrity": "sha512-PZ/dn4UlA/7sd848LHE2TLXIkOzLDk8Uw/Gz6OwXfxXpng/w6mXcyjaScniT3HzLbzw5fP150+im5mL6BQv9JQ==", - "dev": true, - "requires": { - "@lerna/bootstrap": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "dedent": "^0.7.0", - "npm-package-arg": "^6.0.0", - "p-map": "^1.2.0", - "package-json": "^4.0.1", - "semver": "^5.5.0" - } - }, - "@lerna/batch-packages": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/batch-packages/-/batch-packages-3.0.0-rc.0.tgz", - "integrity": "sha512-2FZs545THLHSWZ96xKT5wWFOdIt1UIKnc+Z2IIXCgmhT//fcqEcHFSgq42VxgoELgE4rM7jE2s6wgMatiJwRGg==", - "dev": true, - "requires": { - "@lerna/package-graph": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/bootstrap": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.0.0-rc.0.tgz", - "integrity": "sha512-69mXMWjXA8R6ldDmSntFIIZTNAgEu1lOUP7DilL4OY55z01ln5fOtG/c65PQBm4mjm5ejh1kJVWiDT8MbCRslQ==", - "dev": true, - "requires": { - "@lerna/batch-packages": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/npm-conf": "^3.0.0-rc.0", - "@lerna/npm-install": "^3.0.0-rc.0", - "@lerna/rimraf-dir": "^3.0.0-rc.0", - "@lerna/run-lifecycle": "^3.0.0-rc.0", - "@lerna/run-parallel-batches": "^3.0.0-rc.0", - "@lerna/symlink-binary": "^3.0.0-rc.0", - "@lerna/symlink-dependencies": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "dedent": "^0.7.0", - "get-port": "^3.2.0", - "multimatch": "^2.1.0", - "npm-package-arg": "^6.0.0", - "npmlog": "^4.1.2", - "p-finally": "^1.0.0", - "p-map": "^1.2.0", - "p-map-series": "^1.0.0", - "p-waterfall": "^1.0.0", - "read-package-tree": "^5.1.6", - "semver": "^5.5.0" - } - }, - "@lerna/changed": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.0.0-rc.0.tgz", - "integrity": "sha512-DY2Id3Y1jifIdZ8uNymUijUgkVRFg64IUHMTb1sm0g/Nd+n++kLo9oqxRTUfuBkW3e1HTUuMkd3ZygU5UBtz6g==", - "dev": true, - "requires": { - "@lerna/collect-updates": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/output": "^3.0.0-rc.0", - "@lerna/publish": "^3.0.0-rc.0", - "chalk": "^2.3.1" - } - }, - "@lerna/child-process": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-3.0.0-rc.0.tgz", - "integrity": "sha512-5LhCU8isfJFj+5V5cJ+wcRR+VkNIbb3rSjm4VVclnD05ZfaY1HmfhBu3VjYt0SulhZKWJEnNBvjG88wgTay1vQ==", - "dev": true, - "requires": { - "chalk": "^2.3.1", - "execa": "^0.10.0", - "strong-log-transformer": "^1.0.6" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "@lerna/clean": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.0.0-rc.0.tgz", - "integrity": "sha512-rVlvO+bhfU/Q9D6bfg5GaLprKMD5rTRjJEqLONpESx/5Ed+NKgbYRiWafpQrB85m2r3c5dSGEPEc2q2rNG3EPg==", - "dev": true, - "requires": { - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/prompt": "^3.0.0-rc.0", - "@lerna/rimraf-dir": "^3.0.0-rc.0", - "p-map": "^1.2.0", - "p-map-series": "^1.0.0", - "p-waterfall": "^1.0.0" - } - }, - "@lerna/cli": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-3.0.0-rc.0.tgz", - "integrity": "sha512-MUOrP8BiwjayPZAS3Nww1nlB6j02N4FmJK/f2PhJPMDsXMqm3mn5jBTBvlKbLQZJ/VDro8JbRGUUxCuCQEE+cQ==", - "dev": true, - "requires": { - "@lerna/add": "^3.0.0-rc.0", - "@lerna/bootstrap": "^3.0.0-rc.0", - "@lerna/changed": "^3.0.0-rc.0", - "@lerna/clean": "^3.0.0-rc.0", - "@lerna/create": "^3.0.0-rc.0", - "@lerna/diff": "^3.0.0-rc.0", - "@lerna/exec": "^3.0.0-rc.0", - "@lerna/global-options": "^3.0.0-rc.0", - "@lerna/import": "^3.0.0-rc.0", - "@lerna/init": "^3.0.0-rc.0", - "@lerna/link": "^3.0.0-rc.0", - "@lerna/list": "^3.0.0-rc.0", - "@lerna/publish": "^3.0.0-rc.0", - "@lerna/run": "^3.0.0-rc.0", - "dedent": "^0.7.0", - "is-ci": "^1.0.10", - "npmlog": "^4.1.2", - "yargs": "^12.0.1" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "decamelize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", - "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", - "dev": true, - "requires": { - "xregexp": "4.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - }, - "yargs": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.1.tgz", - "integrity": "sha512-B0vRAp1hRX4jgIOWFtjfNjd9OA9RWYZ6tqGA9/I/IrTMsxmKvtWy+ersM+jzpQqbC3YfLzeABPdeTgcJ9eu1qQ==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" - } - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "@lerna/collect-updates": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-3.0.0-rc.0.tgz", - "integrity": "sha512-G1BgTIWc6rSsuMLsgpT+xvrQrSN/a0kC+KqMZ9CbCoImtj0AKvrAm3TeFOsYU9JHBUYfe1HWMIIhUSD4VhXmeg==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "minimatch": "^3.0.4", - "npmlog": "^4.1.2", - "semver": "^5.5.0", - "slash": "^1.0.0" - } - }, - "@lerna/command": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.0.0-rc.0.tgz", - "integrity": "sha512-YzQKhQGSaqhnj/UbygmIneQDuhsTGu9rBqbX84Qs8RhKMMAPWurg+k6sCIihHgBz17tknxEvch/SefMNQxqzAA==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/collect-updates": "^3.0.0-rc.0", - "@lerna/filter-packages": "^3.0.0-rc.0", - "@lerna/package-graph": "^3.0.0-rc.0", - "@lerna/project": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "@lerna/write-log-file": "^3.0.0-rc.0", - "dedent": "^0.7.0", - "execa": "^0.10.0", - "lodash": "^4.17.5", - "npmlog": "^4.1.2" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, - "@lerna/conventional-commits": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-3.0.0-rc.0.tgz", - "integrity": "sha512-J5RC+pd7kHP8EfqzvZqaXW253IoShdlzl1Jrw17KqPDAfL5CoZoUwxgZv4ur3kSSv+jHZGQeuAcg93OsBgkzPw==", - "dev": true, - "requires": { - "@lerna/validation-error": "^3.0.0-rc.0", - "conventional-changelog-angular": "^1.6.6", - "conventional-changelog-core": "^2.0.5", - "conventional-recommended-bump": "^2.0.6", - "dedent": "^0.7.0", - "fs-extra": "^6.0.1", - "get-stream": "^3.0.0", - "npm-package-arg": "^6.0.0", - "npmlog": "^4.1.2", - "semver": "^5.5.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/create": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.0.0-rc.0.tgz", - "integrity": "sha512-6GLI+MEKANCAVnuA9pYQX1k+XyyPEBdoPAiSK4lnW2w4E2KSQZxdkI1+9QLv6S2oTrnlrFSxGmqgmmijaZfCGg==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/npm-conf": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "camelcase": "^4.1.0", - "dedent": "^0.7.0", - "fs-extra": "^6.0.1", - "globby": "^8.0.1", - "init-package-json": "^1.10.3", - "npm-package-arg": "^6.0.0", - "pify": "^3.0.0", - "semver": "^5.5.0", - "slash": "^1.0.0", - "validate-npm-package-license": "^3.0.3", - "validate-npm-package-name": "^3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "@lerna/create-symlink": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-3.0.0-rc.0.tgz", - "integrity": "sha512-wz/C7DB5chTidAOc9+edeg65nJLG1PNO9J/jlAUZOY4G3EPGihLroabIlvbjB5SJ8QKS88ftX+f1pzFZ+nYOdQ==", - "dev": true, - "requires": { - "cmd-shim": "^2.0.2", - "fs-extra": "^6.0.1", - "npmlog": "^4.1.2" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/diff": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.0.0-rc.0.tgz", - "integrity": "sha512-fXeB10qaFeBMucorkV6Q/bJiWayZgGizVsPkuGN1izENd4DBsTxUyh2a6Y3lY5GzCZ33wmuVDe2HdRVHtfrzaQ==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/exec": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.0.0-rc.0.tgz", - "integrity": "sha512-DYU00HAAoreqNQmLV0+gfH4mXIJKbd1rbrMvQbnfCTZ3nWYiORXQwvwCYbGgmsMarSaJ/T3eTPP6LvsVt7y1aw==", - "dev": true, - "requires": { - "@lerna/batch-packages": "^3.0.0-rc.0", - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/run-parallel-batches": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0" - } - }, - "@lerna/filter-options": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.0.0-rc.0.tgz", - "integrity": "sha512-aqyb0GWEnQgu7eXHpVSpZLedVd3PrI5WK/CfzDlHGqUT8PCJTo9q2562gmEdeCWWfeSvXbezGm0djTC6RwHV1A==", - "dev": true, - "requires": { - "dedent": "^0.7.0" - } - }, - "@lerna/filter-packages": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-3.0.0-rc.0.tgz", - "integrity": "sha512-ZVObVh8Nk5d6XS/RAJEdu56KbpqvwJrKruoYnDPFeno/Q6/G1Oi8S/W2NmfEXMBSPaVpYecbGfM4Xu5dLzipNA==", - "dev": true, - "requires": { - "@lerna/validation-error": "^3.0.0-rc.0", - "multimatch": "^2.1.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/get-npm-exec-opts": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.0.0-rc.0.tgz", - "integrity": "sha512-n5Oe1LPzyMKGAdYVVDimpuVsWexTCaLlJq9RqXphoijRh5DAB/Mhaw9//5vGrv770m/QNMSceF99SZLI9gyh4g==", - "dev": true, - "requires": { - "npmlog": "^4.1.2" - } - }, - "@lerna/global-options": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-3.0.0-rc.0.tgz", - "integrity": "sha512-Sy8KE1cAcGwjxOxiJOHjTxJecLcJhAeQym4Ge3WP1Jnz5mq03o9mb37X0Hmjpv1W9OblbXVxHdmbyC3hxMEHIA==", - "dev": true - }, - "@lerna/import": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.0.0-rc.0.tgz", - "integrity": "sha512-ZRrusuAScKg29jRrurEi/qJbpol5RWY98nBhOmq08pibVz8cwS1QzyTwQhxaZECHYrKpL/qdLNigKsNi4+jyYw==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/prompt": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "dedent": "^0.7.0", - "fs-extra": "^6.0.1", - "p-map-series": "^1.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/init": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.0.0-rc.0.tgz", - "integrity": "sha512-/G4gy5QDNsxVXTEo59YRilcW7hnob31GVPc3omy9AZq8HZYCpj/tAw39mEds7S1wPCx0aotRj+NDf178zj11Mw==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "fs-extra": "^6.0.1", - "p-map": "^1.2.0", - "write-json-file": "^2.3.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/link": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.0.0-rc.0.tgz", - "integrity": "sha512-Al57Ib56/ojGQ3hcln+DhS5IGWqLv8EElrAmSp0c3t/Ie48VOv9AusQR9nDRIGEn73APu/EG0ILdbylfQBzaKg==", - "dev": true, - "requires": { - "@lerna/command": "^3.0.0-rc.0", - "@lerna/package-graph": "^3.0.0-rc.0", - "@lerna/symlink-dependencies": "^3.0.0-rc.0", - "p-map": "^1.2.0", - "slash": "^1.0.0" - } - }, - "@lerna/list": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.0.0-rc.0.tgz", - "integrity": "sha512-uQuFeRHhF6ALohRkVY6VxpCyeCHHTEqzt0SNvacTAA+gJX/hadtEYS883KOzmmcFibL4UtljQbdfj+DjrLKfUQ==", - "dev": true, - "requires": { - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/output": "^3.0.0-rc.0", - "chalk": "^2.3.1", - "columnify": "^1.5.4" - } - }, - "@lerna/npm-conf": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.0.0-rc.0.tgz", - "integrity": "sha512-zdd/c83UTDGHci1MrW61olXh04cqRvwkA1SZgXYiLo7A87yHlBYwVOu1d7Rl0J6lHG7++8X2odWqzYZkFfeVFA==", - "dev": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "@lerna/npm-dist-tag": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.0.0-rc.0.tgz", - "integrity": "sha512-Xa5mPmSIsi0N4pNNSBpKeghQ7XskKCVK+pawEvgKAYHph/J9PIfrddVJUU8o3nk2qkqeqikypoS++bwMdVr8Ew==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/get-npm-exec-opts": "^3.0.0-rc.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/npm-install": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-3.0.0-rc.0.tgz", - "integrity": "sha512-QWvgQ0osTf7e87hc1kKXDcbWPXVCqGUiVnTpjX22+CEiJjUMStWEp4MjLieObgFVLyTtanOZp8VpRqBsPE0HRQ==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/get-npm-exec-opts": "^3.0.0-rc.0", - "fs-extra": "^6.0.1", - "npm-package-arg": "^6.0.0", - "npmlog": "^4.1.2", - "signal-exit": "^3.0.2", - "write-pkg": "^3.1.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/npm-publish": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.0.0-rc.0.tgz", - "integrity": "sha512-rP8epG0SsHzqYw9xvwVX6YyAAwPYJAYZvMNxJvyi8fp5KdnD2sTeV/JOrWbQD/RxBxR2WGJxelVRL617KWZMOA==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/get-npm-exec-opts": "^3.0.0-rc.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/npm-run-script": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-3.0.0-rc.0.tgz", - "integrity": "sha512-Hm6KLPpeIyRIdc9MntmaAhuboUyw75DJLJ1MTaLwq/RwZ2kKHYk1Hi/R7yjj8LOyD7A25BTYX0Pd1gHd1lsFVw==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/get-npm-exec-opts": "^3.0.0-rc.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/output": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/output/-/output-3.0.0-rc.0.tgz", - "integrity": "sha512-zZmQ94nVUfe1CvexarDnrb/Mqt81OcZNuOCvcKFHJiNkr5VSIn2GJuUwtTaVUtoh5uXdJCJvm696Ptsep10BWw==", - "dev": true, - "requires": { - "npmlog": "^4.1.2" - } - }, - "@lerna/package": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.0.0-rc.0.tgz", - "integrity": "sha512-4EUnBc04IxganMamjnEfagajLya3nPKfqlorGc5VLoGh5akOZmrCF9qiqB90nYzrJoMt+5QB1lxYD8bxikX0qg==", - "dev": true, - "requires": { - "npm-package-arg": "^6.0.0", - "write-pkg": "^3.1.0" - } - }, - "@lerna/package-graph": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-3.0.0-rc.0.tgz", - "integrity": "sha512-E2MlL0CwDzcDTLPpMhg9+TESRAD/wYLtEu+Mj1R4OZbF2jlSXSZok1g3LW/gzulVd5oq9q+qBdY3SX5b9PCsGQ==", - "dev": true, - "requires": { - "npm-package-arg": "^6.0.0", - "semver": "^5.5.0" - } - }, - "@lerna/project": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.0.0-rc.0.tgz", - "integrity": "sha512-lNego7jYd24jIDGLTcy1mrESEopCblVaZztKhJJntSZdqWZ/tnExjIITfS55CnZyKAXwPVIus6YRfOc24tvuaA==", - "dev": true, - "requires": { - "@lerna/package": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "cosmiconfig": "^5.0.2", - "dedent": "^0.7.0", - "dot-prop": "^4.2.0", - "glob-parent": "^3.1.0", - "globby": "^8.0.1", - "load-json-file": "^4.0.0", - "npmlog": "^4.1.2", - "p-map": "^1.2.0", - "resolve-from": "^4.0.0", - "write-json-file": "^2.3.0" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "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": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "@lerna/prompt": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-3.0.0-rc.0.tgz", - "integrity": "sha512-4ABsGTq7/IMh3nX7LfRirJnXt50Yp/Lg837hb/Hp1OXFz1FoXLcbzoIx0QQYyk3q+Gnv2TwSK2M86xoUFIUXnw==", - "dev": true, - "requires": { - "inquirer": "^5.1.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/publish": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.0.0-rc.0.tgz", - "integrity": "sha512-bfjRtCzHAGSS5z8QOUw3UeLn4u5CpJTGUkk9y1PPbzdbMWmJhJnEjSw+TN2LaZFVGzQbE8dsLqR5TL149Y7P/Q==", - "dev": true, - "requires": { - "@lerna/batch-packages": "^3.0.0-rc.0", - "@lerna/child-process": "^3.0.0-rc.0", - "@lerna/collect-updates": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/conventional-commits": "^3.0.0-rc.0", - "@lerna/npm-dist-tag": "^3.0.0-rc.0", - "@lerna/npm-publish": "^3.0.0-rc.0", - "@lerna/output": "^3.0.0-rc.0", - "@lerna/prompt": "^3.0.0-rc.0", - "@lerna/run-lifecycle": "^3.0.0-rc.0", - "@lerna/run-parallel-batches": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "chalk": "^2.3.1", - "dedent": "^0.7.0", - "fs-extra": "^6.0.1", - "minimatch": "^3.0.4", - "npmlog": "^4.1.2", - "p-finally": "^1.0.0", - "p-map": "^1.2.0", - "p-reduce": "^1.0.0", - "p-waterfall": "^1.0.0", - "semver": "^5.5.0", - "slash": "^1.0.0", - "temp-write": "^3.4.0", - "write-json-file": "^2.3.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/resolve-symlink": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-3.0.0-rc.0.tgz", - "integrity": "sha512-EBRD/65aTCyZMqWzAM7Ac1zqtZBkTE5AHzzIViQaB5el3j7ThBzzWwYuiBNWibNGTMObLQMrp+65yCbew5H+aA==", - "dev": true, - "requires": { - "fs-extra": "^6.0.1", - "npmlog": "^4.1.2", - "read-cmd-shim": "^1.0.1" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/rimraf-dir": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-3.0.0-rc.0.tgz", - "integrity": "sha512-aFPX1hMOBL+5AU5xI9SZ2xKTAlnk93+tIw1ZJGWMMc4dzxNs/sT3WeUUH4v1TOYzMqWM3AnLQza3O4OY/xb2hg==", - "dev": true, - "requires": { - "@lerna/child-process": "^3.0.0-rc.0", - "npmlog": "^4.1.2", - "path-exists": "^3.0.0", - "rimraf": "^2.6.2" - } - }, - "@lerna/run": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.0.0-rc.0.tgz", - "integrity": "sha512-biLKshDBwQ7n3XLihV5QvrlOBJ1isnRJC8xC8FeUbH3x1FRX15Ogg+8/GiGG7vaM6kdE4j0ebrW8HPUEh5L4cw==", - "dev": true, - "requires": { - "@lerna/batch-packages": "^3.0.0-rc.0", - "@lerna/command": "^3.0.0-rc.0", - "@lerna/filter-options": "^3.0.0-rc.0", - "@lerna/npm-run-script": "^3.0.0-rc.0", - "@lerna/output": "^3.0.0-rc.0", - "@lerna/run-parallel-batches": "^3.0.0-rc.0", - "@lerna/validation-error": "^3.0.0-rc.0", - "p-map": "^1.2.0" - } - }, - "@lerna/run-lifecycle": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.0.0-rc.0.tgz", - "integrity": "sha512-/cofDJ5qzAgC99+VYxO602k1wBetv79NYOXUoju3R8xPrCXGJYoBN+/NhrPdj/CciZd9lSsx016M6FcScsaO1Q==", - "dev": true, - "requires": { - "@lerna/npm-conf": "^3.0.0-rc.0", - "npm-lifecycle": "^2.0.0", - "npmlog": "^4.1.2" - } - }, - "@lerna/run-parallel-batches": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/run-parallel-batches/-/run-parallel-batches-3.0.0-rc.0.tgz", - "integrity": "sha512-MpXiDRo02ZHazis3sDqzhmFuMxEEPKv+mmPpzLElkCDO4LHVZYvwa3ib3ezhWwt+FUFPP4u/8w2A4cFO2PbmVQ==", - "dev": true, - "requires": { - "p-map": "^1.2.0", - "p-map-series": "^1.0.0" - } - }, - "@lerna/symlink-binary": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.0.0-rc.0.tgz", - "integrity": "sha512-aFmZmvjNApa7i4SCrq//j7kg7E6mO3U7dzE4J28biFen2Ey1fmxObf1jiv6b24T92D/WztiBGSSTXbFR41yAsw==", - "dev": true, - "requires": { - "@lerna/create-symlink": "^3.0.0-rc.0", - "@lerna/package": "^3.0.0-rc.0", - "fs-extra": "^6.0.1", - "p-map": "^1.2.0", - "read-pkg": "^3.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "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": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "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": { - "pify": "^3.0.0" - } - }, - "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 - } - } - }, - "@lerna/symlink-dependencies": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.0.0-rc.0.tgz", - "integrity": "sha512-dk7V95ToYw1nfn7ydkGQAn0RWyye9n05vPSCQzME+OP0nL7PcsSY+0umatsRP104VMX0yTmML129Zg5xpYDSAw==", - "dev": true, - "requires": { - "@lerna/create-symlink": "^3.0.0-rc.0", - "@lerna/resolve-symlink": "^3.0.0-rc.0", - "@lerna/symlink-binary": "^3.0.0-rc.0", - "fs-extra": "^6.0.1", - "p-finally": "^1.0.0", - "p-map": "^1.2.0", - "p-map-series": "^1.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", - "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "@lerna/validation-error": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-3.0.0-rc.0.tgz", - "integrity": "sha512-VuYvUC2DUjVq/DG7r52wWKmq1G0doGPB5eq7Uozi4QIIRWj2op1l6yCSogb3H2UKPn/5NrMOV4jztwQBnSJu0w==", - "dev": true, - "requires": { - "npmlog": "^4.1.2" - } - }, - "@lerna/write-log-file": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-3.0.0-rc.0.tgz", - "integrity": "sha512-LHQPRY/1eWyq7ly+4A412FT9uzGKHDSGHkLYVro8r6mToPB/6eHdntJFRGOYNzKM5eax6RgrzBImEhs3F9FWSQ==", - "dev": true, - "requires": { - "npmlog": "^4.1.2", - "write-file-atomic": "^2.3.0" - } - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz", - "integrity": "sha512-LAQ1d4OPfSJ/BMbI2DuizmYrrkD9JMaTdi2hQTlI53lQ4kRQPyZQRS4CYQ7O66bnBBnP/oYdRxbk++X0xuFU6A==", - "dev": true - }, - "@types/events": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", - "dev": true - }, - "@types/fs-extra": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.1.tgz", - "integrity": "sha512-h3wnflb+jMTipvbbZnClgA2BexrT4w0GcfoCz5qyxd0IRsbqhLSyesM6mqZTAnhbVmhyTm5tuxfRu9R+8l+lGw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "5.0.35", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", - "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/handlebars": { - "version": "4.0.36", - "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.36.tgz", - "integrity": "sha512-LjNiTX7TY7wtuC6y3QwC93hKMuqYhgV9A1uXBKNvZtVC8ZvyWAjZkJ5BvT0K7RKqORRYRLMrqCxpw5RgS+MdrQ==", - "dev": true - }, - "@types/highlight.js": { - "version": "9.12.2", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.2.tgz", - "integrity": "sha512-y5x0XD/WXDaGSyiTaTcKS4FurULJtSiYbGTeQd0m2LYZGBcZZ/7fM6t5H/DzeUF+kv8y6UfmF6yJABQsHcp9VQ==", - "dev": true - }, - "@types/jest": { - "version": "22.2.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-22.2.3.tgz", - "integrity": "sha512-e74sM9W/4qqWB6D4TWV9FQk0WoHtX1X4FJpbjxucMSVJHtFjbQOH3H6yp+xno4br0AKG0wz/kPtaN599GUOvAg==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.104", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.104.tgz", - "integrity": "sha512-ufQcVg4daO8xQ5kopxRHanqFdL4AI7ondQkV+2f+7mz3gvp0LkBx2zBRC6hfs3T87mzQFmf5Fck7Fi145Ul6NQ==", - "dev": true - }, - "@types/marked": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz", - "integrity": "sha512-CSf9YWJdX1DkTNu9zcNtdCcn6hkRtB5ILjbhRId4ZOQqx30fXmdecuaXhugQL6eyrhuXtaHJ7PHI+Vm7k9ZJjg==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/node": { - "version": "9.6.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.6.tgz", - "integrity": "sha512-SJe0g5cZeGNDP5sD8mIX3scb+eq8LQQZ60FXiKZHipYSeEFZ5EKml+NNMiO76F74TY4PoMWlNxF/YRY40FOvZQ==", - "dev": true - }, - "@types/shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha512-M2giRw93PxKS7YjU6GZjtdV9HASdB7TWqizBXe4Ju7AqbKlWvTr0gNO92XH56D/gMxqD/jNHLNfC5hA34yGqrQ==", - "dev": true, - "requires": { - "@types/glob": "*", - "@types/node": "*" - } - }, - "JSONStream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz", - "integrity": "sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg==", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true - }, - "acorn-globals": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", - "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", - "dev": true, - "requires": { - "acorn": "^5.0.0" - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "dev": true - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.0.tgz", - "integrity": "sha512-SuiKH8vbsOyCALjA/+EINmt/Kdl+TQPrtFgW7XZZcwtryFu9e5kQoX3bjCW6mIvGH1fbeAZZuvwGR5IlBRznGw==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "babel-core": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", - "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.0", - "debug": "^2.6.8", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.7", - "slash": "^1.0.0", - "source-map": "^0.5.6" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-22.4.3.tgz", - "integrity": "sha512-BgSjmtl3mW3i+VeVHEr9d2zFSAT66G++pJcHQiUjd00pkW+voYXFctIm/indcqOWWXw5a1nUpR1XWszD9fJ1qg==", - "dev": true, - "requires": { - "babel-plugin-istanbul": "^4.1.5", - "babel-preset-jest": "^22.4.3" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-istanbul": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", - "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", - "dev": true, - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" - } - }, - "babel-plugin-jest-hoist": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.3.tgz", - "integrity": "sha512-zhvv4f6OTWy2bYevcJftwGCWXMFe7pqoz41IhMi4xna7xNsX5NygdagsrE0y6kkfuXq8UalwvPwKTyAxME2E/g==", - "dev": true - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", - "dev": true - }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", - "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } - }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-22.4.3.tgz", - "integrity": "sha512-a+M3LTEXTq3gxv0uBN9Qm6ahUl7a8pj923nFbCUdqFUSsf3YrX8Uc+C3MEwji5Af3LiQjSC7w4ooYewlz8HRTA==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^22.4.3", - "babel-plugin-syntax-object-rest-spread": "^6.13.0" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true - }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dev": true, - "requires": { - "hoek": "4.x.x" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "browser-process-hrtime": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz", - "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=", - "dev": true - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "dev": true, - "requires": { - "resolve": "1.1.7" - } - }, - "bser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", - "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", - "dev": true - }, - "byline": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", - "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "camelcase-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", - "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", - "dev": true, - "requires": { - "camelcase": "^4.1.0", - "map-obj": "^2.0.0", - "quick-lru": "^1.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } - } - }, - "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chalk": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", - "dev": true - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" - }, - "dependencies": { - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - } - } - }, - "ci-info": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", - "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "optional": true - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "cmd-shim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-2.0.2.tgz", - "integrity": "sha1-b8vamUg6j9FdfTChlspp1oii79s=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "mkdirp": "~0.5.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "columnify": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", - "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", - "dev": true, - "requires": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, - "compare-func": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", - "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", - "dev": true, - "requires": { - "array-ify": "^1.0.0", - "dot-prop": "^3.0.0" - }, - "dependencies": { - "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - } - } - }, - "compare-versions": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.1.0.tgz", - "integrity": "sha512-4hAxDSBypT/yp2ySFD346So6Ragw5xmBn/e/agIGl3bZr6DLUqnoRZPusxKrXdYRZpgexO9daejmIenlq/wrIQ==", - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "config-chain": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", - "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "conventional-changelog-angular": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-1.6.6.tgz", - "integrity": "sha512-suQnFSqCxRwyBxY68pYTsFkG0taIdinHLNEAX5ivtw8bCRnIgnpvcHmlR/yjUyZIrNPYAoXlY1WiEKWgSE4BNg==", - "dev": true, - "requires": { - "compare-func": "^1.3.1", - "q": "^1.5.1" - } - }, - "conventional-changelog-core": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-2.0.11.tgz", - "integrity": "sha512-HvTE6RlqeEZ/NFPtQeFLsIDOLrGP3bXYr7lFLMhCVsbduF1MXIe8OODkwMFyo1i9ku9NWBwVnVn0jDmIFXjDRg==", - "dev": true, - "requires": { - "conventional-changelog-writer": "^3.0.9", - "conventional-commits-parser": "^2.1.7", - "dateformat": "^3.0.0", - "get-pkg-repo": "^1.0.0", - "git-raw-commits": "^1.3.6", - "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^1.3.6", - "lodash": "^4.2.1", - "normalize-package-data": "^2.3.5", - "q": "^1.5.1", - "read-pkg": "^1.1.0", - "read-pkg-up": "^1.0.1", - "through2": "^2.0.0" - } - }, - "conventional-changelog-preset-loader": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-1.1.8.tgz", - "integrity": "sha512-MkksM4G4YdrMlT2MbTsV2F6LXu/hZR0Tc/yenRrDIKRwBl/SP7ER4ZDlglqJsCzLJi4UonBc52Bkm5hzrOVCcw==", - "dev": true - }, - "conventional-changelog-writer": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-3.0.9.tgz", - "integrity": "sha512-n9KbsxlJxRQsUnK6wIBRnARacvNnN4C/nxnxCkH+B/R1JS2Fa+DiP1dU4I59mEDEjgnFaN2+9wr1P1s7GYB5/Q==", - "dev": true, - "requires": { - "compare-func": "^1.3.1", - "conventional-commits-filter": "^1.1.6", - "dateformat": "^3.0.0", - "handlebars": "^4.0.2", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.2.1", - "meow": "^4.0.0", - "semver": "^5.5.0", - "split": "^1.0.0", - "through2": "^2.0.0" - } - }, - "conventional-commits-filter": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-1.1.6.tgz", - "integrity": "sha512-KcDgtCRKJCQhyk6VLT7zR+ZOyCnerfemE/CsR3iQpzRRFbLEs0Y6rwk3mpDvtOh04X223z+1xyJ582Stfct/0Q==", - "dev": true, - "requires": { - "is-subset": "^0.1.1", - "modify-values": "^1.0.0" - } - }, - "conventional-commits-parser": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-2.1.7.tgz", - "integrity": "sha512-BoMaddIEJ6B4QVMSDu9IkVImlGOSGA1I2BQyOZHeLQ6qVOJLcLKn97+fL6dGbzWEiqDzfH4OkcveULmeq2MHFQ==", - "dev": true, - "requires": { - "JSONStream": "^1.0.4", - "is-text-path": "^1.0.0", - "lodash": "^4.2.1", - "meow": "^4.0.0", - "split2": "^2.0.0", - "through2": "^2.0.0", - "trim-off-newlines": "^1.0.0" - } - }, - "conventional-recommended-bump": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-2.0.9.tgz", - "integrity": "sha512-YE6/o+648qkX3fTNvfBsvPW3tSnbZ6ec3gF0aBahCPgyoVHU2Mw0nUAZ1h1UN65GazpORngrgRC8QCltNYHPpQ==", - "dev": true, - "requires": { - "concat-stream": "^1.6.0", - "conventional-changelog-preset-loader": "^1.1.8", - "conventional-commits-filter": "^1.1.6", - "conventional-commits-parser": "^2.1.7", - "git-raw-commits": "^1.3.6", - "git-semver-tags": "^1.3.6", - "meow": "^4.0.0", - "q": "^1.5.1" - } - }, - "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz", - "integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.5.tgz", - "integrity": "sha512-94j37OtvxS5w7qr7Ta6dt67tWdnOxigBVN4VnSxNXFez9o18PGQ0D33SchKP17r9LAcWVTYV72G6vDayAUBFIg==", - "dev": true, - "requires": { - "is-directory": "^0.3.1", - "js-yaml": "^3.9.0", - "parse-json": "^4.0.0" - }, - "dependencies": { - "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - } - } - }, - "cpx": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz", - "integrity": "sha1-GFvgGFEdhycN7czCkxceN2VauI8=", - "dev": true, - "requires": { - "babel-runtime": "^6.9.2", - "chokidar": "^1.6.0", - "duplexer": "^0.1.1", - "glob": "^7.0.5", - "glob2base": "^0.0.12", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "resolve": "^1.1.7", - "safe-buffer": "^5.0.1", - "shell-quote": "^1.6.1", - "subarg": "^1.0.0" - } - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dev": true, - "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "dev": true, - "requires": { - "hoek": "4.x.x" - } - } - } - }, - "cssom": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", - "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", - "dev": true - }, - "cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, - "dargs": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", - "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.0.tgz", - "integrity": "sha512-ai40PPQR0Fn1lD2PPie79CibnlMN2AYiDhwFX/rZHVsxbs5kNJSjegqXIprhouGXlRdEnfybva7kqRGnB6mypA==", - "dev": true, - "requires": { - "abab": "^1.0.4", - "whatwg-mimetype": "^2.0.0", - "whatwg-url": "^6.4.0" - } - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decamelize-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", - "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", - "dev": true, - "requires": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "dependencies": { - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", - "dev": true - } - } - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "dev": true, - "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - }, - "dependencies": { - "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": { - "pify": "^3.0.0" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", - "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", - "dev": true, - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "dev": true, - "requires": { - "is-callable": "^1.1.1", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", - "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "exec-sh": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz", - "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==", - "dev": true, - "requires": { - "merge": "^1.1.3" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - } - }, - "expect": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.3.tgz", - "integrity": "sha512-XcNXEPehqn8b/jm8FYotdX0YrXn36qp4HWlrVT4ktwQas1l1LPxiVWncYnnL2eyMtKAmVIaG0XAp0QlrqJaxaA==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "jest-diff": "^22.4.3", - "jest-get-type": "^22.4.3", - "jest-matcher-utils": "^22.4.3", - "jest-message-util": "^22.4.3", - "jest-regex-util": "^22.4.3" - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "requires": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "fast-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz", - "integrity": "sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==", - "dev": true, - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.0.1", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.1", - "micromatch": "^3.1.10" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", - "dev": true, - "requires": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" - } - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.3.0", - "node-pre-gyp": "^0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^0.4.1", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "^1.0.0", - "inherits": "2", - "minimatch": "^3.0.0" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "~1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "hawk": "3.1.3", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "request": "2.81.0", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^2.2.1", - "tar-pack": "^3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "~0.4.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "~1.0.0", - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~1.0.0", - "util-deprecate": "~1.0.1" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jodid25519": "^1.0.0", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^2.2.0", - "fstream": "^1.0.10", - "fstream-ignore": "^1.0.5", - "once": "^1.3.3", - "readable-stream": "^2.1.4", - "rimraf": "^2.5.1", - "tar": "^2.2.1", - "uid-number": "^0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true - }, - "get-pkg-repo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz", - "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "meow": "^3.3.0", - "normalize-package-data": "^2.3.0", - "parse-github-repo-url": "^1.3.0", - "through2": "^2.0.0" - }, - "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=", - "dev": true, - "requires": { - "repeating": "^2.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=", - "dev": true, - "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "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" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^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=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - } - } - }, - "get-port": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", - "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", - "dev": true - }, - "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 - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "git-raw-commits": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-1.3.6.tgz", - "integrity": "sha512-svsK26tQ8vEKnMshTDatSIQSMDdz8CxIIqKsvPqbtV23Etmw6VNaFAitu8zwZ0VrOne7FztwPyRLxK7/DIUTQg==", - "dev": true, - "requires": { - "dargs": "^4.0.1", - "lodash.template": "^4.0.2", - "meow": "^4.0.0", - "split2": "^2.0.0", - "through2": "^2.0.0" - } - }, - "git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", - "dev": true, - "requires": { - "gitconfiglocal": "^1.0.0", - "pify": "^2.3.0" - } - }, - "git-semver-tags": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-1.3.6.tgz", - "integrity": "sha512-2jHlJnln4D/ECk9FxGEBh3k44wgYdWjWDtMmJPaecjoRmxKo3Y1Lh8GMYuOPu04CHw86NTAODchYjC5pnpMQig==", - "dev": true, - "requires": { - "meow": "^4.0.0", - "semver": "^5.5.0" - } - }, - "gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", - "dev": true, - "requires": { - "ini": "^1.3.2" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true - }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", - "dev": true, - "requires": { - "find-index": "^0.1.1" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dev": true, - "requires": { - "ajv": "^5.1.0", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "^1.0.2" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "dev": true, - "requires": { - "boom": "4.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "sntp": "2.x.x" - } - }, - "highlight.js": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", - "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=", - "dev": true - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "dev": true - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "1.0.0-rc.13", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.0.0-rc.13.tgz", - "integrity": "sha512-ZNNoaBgfOHRA05UHS/etBoWFDu65mjPoohPYQwOqb5155KOovBp8LMkMoNK0kn3VYdsm+HWdtuHbD4XjfzlfpQ==", - "dev": true, - "requires": { - "cosmiconfig": "^5.0.2", - "execa": "^0.9.0", - "find-up": "^3.0.0", - "get-stdin": "^6.0.0", - "is-ci": "^1.1.0", - "pkg-dir": "^3.0.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^4.0.1", - "run-node": "^1.0.0", - "slash": "^2.0.0" - }, - "dependencies": { - "execa": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz", - "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", - "dev": true - }, - "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "read-pkg": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", - "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", - "dev": true, - "requires": { - "normalize-package-data": "^2.3.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0" - } - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - } - } - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "dev": true - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "import-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", - "dev": true, - "requires": { - "pkg-dir": "^2.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "init-package-json": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", - "dev": true, - "requires": { - "glob": "^7.1.1", - "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "1 || 2", - "semver": "2.x || 3.x || 4 || 5", - "validate-npm-package-license": "^3.0.1", - "validate-npm-package-name": "^3.0.0" - } - }, - "inquirer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", - "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.1.0", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^5.5.2", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", - "dev": true - }, - "is-ci": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", - "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", - "dev": true, - "requires": { - "ci-info": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", - "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-retry-allowed": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", - "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true - }, - "is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, - "requires": { - "text-extensions": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-api": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz", - "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", - "dev": true, - "requires": { - "async": "^2.1.4", - "compare-versions": "^3.1.0", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-hook": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-report": "^1.1.4", - "istanbul-lib-source-maps": "^1.2.4", - "istanbul-reports": "^1.3.0", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.4.tgz", - "integrity": "sha512-UzuK0g1wyQijiaYQxj/CdNycFhAd2TLtO2obKQMTZrZ1jzEMRY3rvpASEKkaxbRR6brvdovfA03znPa/pXcejg==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.0", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - } - } - } - }, - "istanbul-lib-coverage": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", - "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.0.tgz", - "integrity": "sha512-p3En6/oGkFQV55Up8ZPC2oLxvgSxD8CzA0yBrhRZSh3pfv3OFj9aSGVC0yoerAi/O4u7jUVnOGVX1eVFM+0tmQ==", - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", - "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz", - "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^1.2.0", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "dev": true - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", - "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "istanbul-reports": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz", - "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", - "dev": true, - "requires": { - "handlebars": "^4.0.3" - } - }, - "jest": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-22.4.3.tgz", - "integrity": "sha512-FFCdU/pXOEASfHxFDOWUysI/+FFoqiXJADEIXgDKuZyqSmBD3tZ4BEGH7+M79v7czj7bbkhwtd2LaEDcJiM/GQ==", - "dev": true, - "requires": { - "import-local": "^1.0.0", - "jest-cli": "^22.4.3" - }, - "dependencies": { - "jest-cli": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-22.4.3.tgz", - "integrity": "sha512-IiHybF0DJNqZPsbjn4Cy4vcqcmImpoFwNFnkehzVw8lTUSl4axZh5DHewu5bdpZF2Y5gUqFKYzH0FH4Qx2k+UA==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "import-local": "^1.0.0", - "is-ci": "^1.0.10", - "istanbul-api": "^1.1.14", - "istanbul-lib-coverage": "^1.1.1", - "istanbul-lib-instrument": "^1.8.0", - "istanbul-lib-source-maps": "^1.2.1", - "jest-changed-files": "^22.4.3", - "jest-config": "^22.4.3", - "jest-environment-jsdom": "^22.4.3", - "jest-get-type": "^22.4.3", - "jest-haste-map": "^22.4.3", - "jest-message-util": "^22.4.3", - "jest-regex-util": "^22.4.3", - "jest-resolve-dependencies": "^22.4.3", - "jest-runner": "^22.4.3", - "jest-runtime": "^22.4.3", - "jest-snapshot": "^22.4.3", - "jest-util": "^22.4.3", - "jest-validate": "^22.4.3", - "jest-worker": "^22.4.3", - "micromatch": "^2.3.11", - "node-notifier": "^5.2.1", - "realpath-native": "^1.0.0", - "rimraf": "^2.5.4", - "slash": "^1.0.0", - "string-length": "^2.0.0", - "strip-ansi": "^4.0.0", - "which": "^1.2.12", - "yargs": "^10.0.3" - } - } - } - }, - "jest-changed-files": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-22.4.3.tgz", - "integrity": "sha512-83Dh0w1aSkUNFhy5d2dvqWxi/y6weDwVVLU6vmK0cV9VpRxPzhTeGimbsbRDSnEoszhF937M4sDLLeS7Cu/Tmw==", - "dev": true, - "requires": { - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-22.4.3.tgz", - "integrity": "sha512-KSg3EOToCgkX+lIvenKY7J8s426h6ahXxaUFJxvGoEk0562Z6inWj1TnKoGycTASwiLD+6kSYFALcjdosq9KIQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^22.4.3", - "jest-environment-node": "^22.4.3", - "jest-get-type": "^22.4.3", - "jest-jasmine2": "^22.4.3", - "jest-regex-util": "^22.4.3", - "jest-resolve": "^22.4.3", - "jest-util": "^22.4.3", - "jest-validate": "^22.4.3", - "pretty-format": "^22.4.3" - } - }, - "jest-diff": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.3.tgz", - "integrity": "sha512-/QqGvCDP5oZOF6PebDuLwrB2BMD8ffJv6TAGAdEVuDx1+uEgrHpSFrfrOiMRx2eJ1hgNjlQrOQEHetVwij90KA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.4.3", - "pretty-format": "^22.4.3" - } - }, - "jest-docblock": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-22.4.3.tgz", - "integrity": "sha512-uPKBEAw7YrEMcXueMKZXn/rbMxBiSv48fSqy3uEnmgOlQhSX+lthBqHb1fKWNVmFqAp9E/RsSdBfiV31LbzaOg==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-environment-jsdom": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-22.4.3.tgz", - "integrity": "sha512-FviwfR+VyT3Datf13+ULjIMO5CSeajlayhhYQwpzgunswoaLIPutdbrnfUHEMyJCwvqQFaVtTmn9+Y8WCt6n1w==", - "dev": true, - "requires": { - "jest-mock": "^22.4.3", - "jest-util": "^22.4.3", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-22.4.3.tgz", - "integrity": "sha512-reZl8XF6t/lMEuPWwo9OLfttyC26A5AMgDyEQ6DBgZuyfyeNUzYT8BFo6uxCCP/Av/b7eb9fTi3sIHFPBzmlRA==", - "dev": true, - "requires": { - "jest-mock": "^22.4.3", - "jest-util": "^22.4.3" - } - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==", - "dev": true - }, - "jest-haste-map": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-22.4.3.tgz", - "integrity": "sha512-4Q9fjzuPVwnaqGKDpIsCSoTSnG3cteyk2oNVjBX12HHOaF1oxql+uUiqZb5Ndu7g/vTZfdNwwy4WwYogLh29DQ==", - "dev": true, - "requires": { - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.1.11", - "jest-docblock": "^22.4.3", - "jest-serializer": "^22.4.3", - "jest-worker": "^22.4.3", - "micromatch": "^2.3.11", - "sane": "^2.0.0" - } - }, - "jest-jasmine2": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-22.4.3.tgz", - "integrity": "sha512-yZCPCJUcEY6R5KJB/VReo1AYI2b+5Ky+C+JA1v34jndJsRcLpU4IZX4rFJn7yDTtdNbO/nNqg+3SDIPNH2ecnw==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^22.4.3", - "graceful-fs": "^4.1.11", - "is-generator-fn": "^1.0.0", - "jest-diff": "^22.4.3", - "jest-matcher-utils": "^22.4.3", - "jest-message-util": "^22.4.3", - "jest-snapshot": "^22.4.3", - "jest-util": "^22.4.3", - "source-map-support": "^0.5.0" - } - }, - "jest-leak-detector": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-22.4.3.tgz", - "integrity": "sha512-NZpR/Ls7+ndO57LuXROdgCGz2RmUdC541tTImL9bdUtU3WadgFGm0yV+Ok4Fuia/1rLAn5KaJ+i76L6e3zGJYQ==", - "dev": true, - "requires": { - "pretty-format": "^22.4.3" - } - }, - "jest-matcher-utils": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.3.tgz", - "integrity": "sha512-lsEHVaTnKzdAPR5t4B6OcxXo9Vy4K+kRRbG5gtddY8lBEC+Mlpvm1CJcsMESRjzUhzkz568exMV1hTB76nAKbA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.4.3", - "pretty-format": "^22.4.3" - } - }, - "jest-message-util": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.3.tgz", - "integrity": "sha512-iAMeKxhB3Se5xkSjU0NndLLCHtP4n+GtCqV0bISKA5dmOXQfEbdEmYiu2qpnWBDCQdEafNDDU6Q+l6oBMd/+BA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0-beta.35", - "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-22.4.3.tgz", - "integrity": "sha512-+4R6mH5M1G4NK16CKg9N1DtCaFmuxhcIqF4lQK/Q1CIotqMs/XBemfpDPeVZBFow6iyUNu6EBT9ugdNOTT5o5Q==", - "dev": true - }, - "jest-regex-util": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.4.3.tgz", - "integrity": "sha512-LFg1gWr3QinIjb8j833bq7jtQopiwdAs67OGfkPrvy7uNUbVMfTXXcOKXJaeY5GgjobELkKvKENqq1xrUectWg==", - "dev": true - }, - "jest-resolve": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-22.4.3.tgz", - "integrity": "sha512-u3BkD/MQBmwrOJDzDIaxpyqTxYH+XqAXzVJP51gt29H8jpj3QgKof5GGO2uPGKGeA1yTMlpbMs1gIQ6U4vcRhw==", - "dev": true, - "requires": { - "browser-resolve": "^1.11.2", - "chalk": "^2.0.1" - } - }, - "jest-resolve-dependencies": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-22.4.3.tgz", - "integrity": "sha512-06czCMVToSN8F2U4EvgSB1Bv/56gc7MpCftZ9z9fBgUQM7dzHGCMBsyfVA6dZTx8v0FDcnALf7hupeQxaBCvpA==", - "dev": true, - "requires": { - "jest-regex-util": "^22.4.3" - } - }, - "jest-runner": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-22.4.3.tgz", - "integrity": "sha512-U7PLlQPRlWNbvOHWOrrVay9sqhBJmiKeAdKIkvX4n1G2tsvzLlf77nBD28GL1N6tGv4RmuTfI8R8JrkvCa+IBg==", - "dev": true, - "requires": { - "exit": "^0.1.2", - "jest-config": "^22.4.3", - "jest-docblock": "^22.4.3", - "jest-haste-map": "^22.4.3", - "jest-jasmine2": "^22.4.3", - "jest-leak-detector": "^22.4.3", - "jest-message-util": "^22.4.3", - "jest-runtime": "^22.4.3", - "jest-util": "^22.4.3", - "jest-worker": "^22.4.3", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-22.4.3.tgz", - "integrity": "sha512-Eat/esQjevhx9BgJEC8udye+FfoJ2qvxAZfOAWshYGS22HydHn5BgsvPdTtt9cp0fSl5LxYOFA1Pja9Iz2Zt8g==", - "dev": true, - "requires": { - "babel-core": "^6.0.0", - "babel-jest": "^22.4.3", - "babel-plugin-istanbul": "^4.1.5", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "exit": "^0.1.2", - "graceful-fs": "^4.1.11", - "jest-config": "^22.4.3", - "jest-haste-map": "^22.4.3", - "jest-regex-util": "^22.4.3", - "jest-resolve": "^22.4.3", - "jest-util": "^22.4.3", - "jest-validate": "^22.4.3", - "json-stable-stringify": "^1.0.1", - "micromatch": "^2.3.11", - "realpath-native": "^1.0.0", - "slash": "^1.0.0", - "strip-bom": "3.0.0", - "write-file-atomic": "^2.1.0", - "yargs": "^10.0.3" - }, - "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 - } - } - }, - "jest-serializer": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-22.4.3.tgz", - "integrity": "sha512-uPaUAppx4VUfJ0QDerpNdF43F68eqKWCzzhUlKNDsUPhjOon7ZehR4C809GCqh765FoMRtTVUVnGvIoskkYHiw==", - "dev": true - }, - "jest-snapshot": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-22.4.3.tgz", - "integrity": "sha512-JXA0gVs5YL0HtLDCGa9YxcmmV2LZbwJ+0MfyXBBc5qpgkEYITQFJP7XNhcHFbUvRiniRpRbGVfJrOoYhhGE0RQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^22.4.3", - "jest-matcher-utils": "^22.4.3", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^22.4.3" - } - }, - "jest-util": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-22.4.3.tgz", - "integrity": "sha512-rfDfG8wyC5pDPNdcnAlZgwKnzHvZDu8Td2NJI/jAGKEGxJPYiE4F0ss/gSAkG4778Y23Hvbz+0GMrDJTeo7RjQ==", - "dev": true, - "requires": { - "callsites": "^2.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.11", - "is-ci": "^1.0.10", - "jest-message-util": "^22.4.3", - "mkdirp": "^0.5.1", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "jest-validate": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-22.4.3.tgz", - "integrity": "sha512-CfFM18W3GSP/xgmA4UouIx0ljdtfD2mjeBC6c89Gg17E44D4tQhAcTrZmf9djvipwU30kSTnk6CzcxdCCeSXfA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-config": "^22.4.3", - "jest-get-type": "^22.4.3", - "leven": "^2.1.0", - "pretty-format": "^22.4.3" - } - }, - "jest-worker": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-22.4.3.tgz", - "integrity": "sha512-B1ucW4fI8qVAuZmicFxI1R3kr2fNeYJyvIQ1rKcuLYnenFV5K5aMbxFj6J0i00Ju83S8jP2d7Dz14+AvbIHRYQ==", - "dev": true, - "requires": { - "merge-stream": "^1.0.1" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", - "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "jsdom": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.8.0.tgz", - "integrity": "sha512-fZZSH6P8tVqYIQl0WKpZuQljPu2cW41Uj/c9omtyGwjwZCB8c82UAi7BSQs/F1FgWovmZsoU02z3k28eHp0Cdw==", - "dev": true, - "requires": { - "abab": "^1.0.4", - "acorn": "^5.3.0", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": ">= 0.2.37 < 0.3.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.0", - "escodegen": "^1.9.0", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.2.0", - "nwmatcher": "^1.4.3", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.83.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.3", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.0", - "ws": "^4.0.0", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true, - "optional": true - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "lerna": { - "version": "3.0.0-rc.0", - "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.0.0-rc.0.tgz", - "integrity": "sha512-fj5Ku6vGgJAzdnpXWE3Stlgnex9ZfaHBQvMQzts13qZ57cJNCzEq5AQPVOOFWE6qqqiABLQfE5T2+Yg/IEqWNQ==", - "dev": true, - "requires": { - "@lerna/cli": "^3.0.0-rc.0", - "import-local": "^1.0.0", - "npmlog": "^4.1.2" - } - }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.template": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", - "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", - "dev": true, - "requires": { - "lodash._reinterpolate": "~3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", - "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", - "dev": true, - "requires": { - "lodash._reinterpolate": "~3.0.0" - } - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "^3.0.0" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", - "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", - "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "marked": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", - "dev": true - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "meow": { - "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": "^4.0.0", - "decamelize-keys": "^1.0.0", - "loud-rejection": "^1.0.0", - "minimist": "^1.1.3", - "minimist-options": "^3.0.1", - "normalize-package-data": "^2.3.4", - "read-pkg-up": "^3.0.0", - "redent": "^2.0.0", - "trim-newlines": "^2.0.0" - }, - "dependencies": { - "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": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "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": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "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": { - "pify": "^3.0.0" - } - }, - "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" - } - }, - "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" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "merge": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", - "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", - "dev": true - }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, - "merge2": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.2.tgz", - "integrity": "sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg==", - "dev": true - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", - "dev": true - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "dev": true, - "requires": { - "mime-db": "~1.33.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "minimist-options": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0" - } - }, - "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "modify-values": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", - "dev": true - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" - } - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", - "dev": true - }, - "node-gyp": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.7.0.tgz", - "integrity": "sha512-qDQE/Ft9xXP6zphwx4sD0t+VhwV7yFaloMpfbL2QnnDZcyaiakWlLdtFGGQfTAwpFHdpbRhRxVhIHN1OKAjgbg==", - "dev": true, - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": ">=2.9.0 <2.82.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - } - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-notifier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", - "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "semver": "^5.4.1", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-lifecycle": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz", - "integrity": "sha512-0U4Iim5ix2NHUT672G7FBpldJX0N2xKBjJqRTAzioEJjb6I6KpQXq+y1sB5EDSjKaAX8VCC9qPK31Jy+p3ix5A==", - "dev": true, - "requires": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.11", - "node-gyp": "^3.6.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "npm-package-arg": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", - "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.6.0", - "osenv": "^0.1.5", - "semver": "^5.5.0", - "validate-npm-package-name": "^3.0.0" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "dev": true - }, - "p-map-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz", - "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "p-waterfall": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-waterfall/-/p-waterfall-1.0.0.tgz", - "integrity": "sha1-ftlLPOszMngjU69qrhGqn8I1uwA=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "parse-github-repo-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", - "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", - "dev": true - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "please-upgrade-node": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", - "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, - "pretty-format": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.3.tgz", - "integrity": "sha512-S4oT9/sT6MN7/3COoOy+ZJeA92VmOnveLHgrwBE3Z1W5N9S2A1QGNYiE1z75DAENbJrXXUb+OWXhpJcg05QKQQ==", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - } - } - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, - "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", - "dev": true - }, - "promzard": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", - "dev": true, - "requires": { - "read": "1" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "punycode": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - }, - "quick-lru": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", - "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz", - "integrity": "sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "read-package-json": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.13.tgz", - "integrity": "sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg==", - "dev": true, - "requires": { - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "json-parse-better-errors": "^1.0.1", - "normalize-package-data": "^2.0.0", - "slash": "^1.0.0" - } - }, - "read-package-tree": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.1.tgz", - "integrity": "sha512-2CNoRoh95LxY47LvqrehIAfUVda2JbuFE/HaGYs42bNrGG+ojbw1h3zOcPcQ+1GQ3+rkzNndZn85u1XyZ3UsIA==", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "once": "^1.3.0", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz", - "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - } - }, - "realpath-native": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.0.tgz", - "integrity": "sha512-XJtlRJ9jf0E1H1SLeJyQ9PGzQD7S65h1pRXEcAeK48doKOnKxcgPeNohJvD5u/2sI9J1oke6E8bZHS/fmW1UiQ==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "redent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", - "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", - "dev": true, - "requires": { - "indent-string": "^3.0.0", - "strip-indent": "^2.0.0" - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "registry-auth-token": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", - "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", - "dev": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, - "requires": { - "rc": "^1.0.1" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", - "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", - "hawk": "~6.0.2", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", - "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "stringstream": "~0.0.5", - "tough-cookie": "~2.3.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" - } - }, - "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "dev": true, - "requires": { - "lodash": "^4.13.1" - } - }, - "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", - "dev": true, - "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true, - "requires": { - "is-promise": "^2.1.0" - } - }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "rxjs": { - "version": "5.5.11", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.11.tgz", - "integrity": "sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA==", - "dev": true, - "requires": { - "symbol-observable": "1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "sane": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.0.tgz", - "integrity": "sha512-glfKd7YH4UCrh/7dD+UESsr8ylKWRE7UQPoXuz28FgmcF0ViJQhCTCCZHICRKxf8G8O1KdLEn20dcICK54c7ew==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "exec-sh": "^0.2.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.1.1", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5", - "watch": "~0.18.0" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true - }, - "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "shelljs": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.1.tgz", - "integrity": "sha512-YA/iYtZpzFe5HyWVGrb02FjPxc4EMCfpoU/Phg9fQoyMC72u9598OUBrsU8IrtwAKG0tO8IYaqbaLIw+k3IRGA==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "dev": true, - "requires": { - "hoek": "4.x.x" - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "dev": true, - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", - "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", - "dev": true, - "requires": { - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "split2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", - "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", - "dev": true, - "requires": { - "through2": "^2.0.2" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - } - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-indent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", - "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "strong-log-transformer": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-1.0.6.tgz", - "integrity": "sha1-9/uTdYpppXEUAYEnfuoMLrEwH6M=", - "dev": true, - "requires": { - "byline": "^5.0.0", - "duplexer": "^0.1.1", - "minimist": "^0.1.0", - "moment": "^2.6.0", - "through": "^2.3.4" - }, - "dependencies": { - "minimist": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", - "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=", - "dev": true - } - } - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "^1.1.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "supports-color": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", - "dev": true - }, - "symbol-tree": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", - "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", - "dev": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, - "temp-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", - "dev": true - }, - "temp-write": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-3.4.0.tgz", - "integrity": "sha1-jP9jD7fp2gXwR8dM5M5NaFRX1JI=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "is-stream": "^1.1.0", - "make-dir": "^1.0.0", - "pify": "^3.0.0", - "temp-dir": "^1.0.0", - "uuid": "^3.0.1" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "test-exclude": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", - "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "text-extensions": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.7.0.tgz", - "integrity": "sha512-AKXZeDq230UaSzaO5s3qQUZOaC7iKbzq0jOFL614R7d9R593HLqAOL0cYoqLdkNrjBSOdmoQI06yigq1TSBXAg==", - "dev": true - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true - }, - "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" - } - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } - } - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "dev": true, - "requires": { - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "trim-newlines": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", - "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", - "dev": true - }, - "trim-off-newlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "ts-jest": { - "version": "22.4.4", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-22.4.4.tgz", - "integrity": "sha512-v9pO7u4HNMDSBCN9IEvlR6taDAGm2mo7nHEDLWyoFDgYeZ4aHm8JHEPrthd8Pmcl4eCM8J4Ata4ROR/cwFRV2A==", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-plugin-istanbul": "^4.1.4", - "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", - "babel-preset-jest": "^22.4.0", - "cpx": "^1.5.0", - "fs-extra": "4.0.3", - "jest-config": "^22.4.2", - "pkg-dir": "^2.0.0", - "yargs": "^11.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "yargs": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", - "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "tslib": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", - "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", - "dev": true - }, - "tslint": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", - "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.12.1" - }, - "dependencies": { - "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - } - } - }, - "tsutils": { - "version": "2.26.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.26.1.tgz", - "integrity": "sha512-bnm9bcjOqOr1UljleL94wVCDlpa6KjfGaTkefeLch4GRafgDkROxPizbB/FxTEdI++5JqhxczRy/Qub0syNqZA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typedoc": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.11.1.tgz", - "integrity": "sha512-jdNIoHm5wkZqxQTe/g9AQ3LKnZyrzHXqu6A/c9GUOeJyBWLxNr7/Dm3rwFvLksuxRNwTvY/0HRDU9sJTa9WQSg==", - "dev": true, - "requires": { - "@types/fs-extra": "5.0.1", - "@types/handlebars": "4.0.36", - "@types/highlight.js": "9.12.2", - "@types/lodash": "4.14.104", - "@types/marked": "0.3.0", - "@types/minimatch": "3.0.3", - "@types/shelljs": "0.7.8", - "fs-extra": "^5.0.0", - "handlebars": "^4.0.6", - "highlight.js": "^9.0.0", - "lodash": "^4.17.5", - "marked": "^0.3.17", - "minimatch": "^3.0.0", - "progress": "^2.0.0", - "shelljs": "^0.8.1", - "typedoc-default-themes": "^0.5.0", - "typescript": "2.7.2" - }, - "dependencies": { - "fs-extra": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "typescript": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", - "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", - "dev": true - } - } - }, - "typedoc-default-themes": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz", - "integrity": "sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=", - "dev": true - }, - "typedoc-plugin-monorepo": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-monorepo/-/typedoc-plugin-monorepo-0.1.0.tgz", - "integrity": "sha512-hx42ck+9dJCoZO0jLCmEE3R6lydYaaYIKL+g6LT5Ev+B8CdAESsML2jiGR+TFu1rUuEujjArtCHjNLj2YqnKnQ==", - "dev": true, - "requires": { - "highlight.js": "^9.12.0", - "marked": "^0.3.19" - } - }, - "typescript": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz", - "integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg==", - "dev": true - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", - "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", - "dev": true - }, - "umask": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", - "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=", - "dev": true - }, - "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", - "dev": true, - "requires": { - "builtins": "^1.0.3" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "watch": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", - "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", - "dev": true, - "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", - "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.19" - } - }, - "whatwg-mimetype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz", - "integrity": "sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew==", - "dev": true - }, - "whatwg-url": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", - "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.0", - "webidl-conversions": "^4.0.1" - } - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", - "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "write-json-file": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-2.3.0.tgz", - "integrity": "sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8=", - "dev": true, - "requires": { - "detect-indent": "^5.0.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "pify": "^3.0.0", - "sort-keys": "^2.0.0", - "write-file-atomic": "^2.0.0" - }, - "dependencies": { - "detect-indent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", - "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "write-pkg": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", - "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", - "dev": true, - "requires": { - "sort-keys": "^2.0.0", - "write-json-file": "^2.2.0" - } - }, - "ws": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", - "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true - }, - "yargs": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", - "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^8.1.0" - }, - "dependencies": { - "cliui": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", - "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - } - } - }, - "yargs-parser": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", - "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } - } - } - } -} diff --git a/packages/@atjson/document/package.json b/packages/@atjson/document/package.json index 5d6ae1b33..d184bac2d 100644 --- a/packages/@atjson/document/package.json +++ b/packages/@atjson/document/package.json @@ -1,6 +1,6 @@ { "name": "@atjson/document", - "version": "0.8.4", + "version": "0.8.5", "description": "Document definition for AtJSON", "main": "dist/commonjs/index.js", "module": "dist/modules/index.js", diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index e386a47ae..d9625cb54 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -20,12 +20,12 @@ "last 2 Chrome versions" ], "dependencies": { - "@atjson/document": "^0.8.4", + "@atjson/document": "0.8.5", "@atjson/renderer-webcomponent": "0.8.0", "@atjson/renderer-commonmark": "0.8.2", - "@atjson/hir": "^0.8.7", - "node-sass": "^4.9.0", - "@atjson/document": "0.8.4" + "@atjson/hir": "0.8.7", + "@atjson/offset-core-components": "0.8.0", + "node-sass": "^4.9.0" }, "devDependencies": { "parcel-bundler": "1.9.7", diff --git a/packages/@atjson/hir/package.json b/packages/@atjson/hir/package.json index 3ce360d2f..ffa64f54e 100644 --- a/packages/@atjson/hir/package.json +++ b/packages/@atjson/hir/package.json @@ -21,6 +21,6 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.4" + "@atjson/document": "0.8.5" } } diff --git a/packages/@atjson/offset-core-components/package.json b/packages/@atjson/offset-core-components/package.json index 11f42bcb8..f38f7393c 100644 --- a/packages/@atjson/offset-core-components/package.json +++ b/packages/@atjson/offset-core-components/package.json @@ -9,7 +9,6 @@ "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", - "start": "parcel public/index.html", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, "license": "Apache-2.0", @@ -20,14 +19,9 @@ "last 2 Chrome versions" ], "dependencies": { - "@atjson/document": "^0.7.16", - "@atjson/renderer-webcomponent": "0.8.0", - "@atjson/renderer-commonmark": "0.8.2", - "@atjson/hir": "^0.8.0", "node-sass": "^4.9.0" }, "devDependencies": { - "parcel-bundler": "1.9.7", "ts-loader": "^4.0.0", "tslint": "^5.9.1", "typescript": "^2.8.1" diff --git a/packages/@atjson/offset-inspector/package-lock.json b/packages/@atjson/offset-inspector/package-lock.json deleted file mode 100644 index 921ecddb6..000000000 --- a/packages/@atjson/offset-inspector/package-lock.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@atjson/offset-editor", - "version": "0.8.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@atjson/document": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/@atjson/document/-/document-0.8.4.tgz", - "integrity": "sha512-uOvHrGHfm1n0Ni4PYN/GwvcCYVeJDbVG0Tstw+mfoE0Hipw9x0dEq1dxmIyh95w5lOW4YDXNmhpA86UcMpOijA==" - }, - "@atjson/renderer-commonmark": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/@atjson/renderer-commonmark/-/renderer-commonmark-0.8.4.tgz", - "integrity": "sha512-mQQnuqAt3Q3jBRlSx0VBDUX5OaqDJTS0UtNw6/GpVuBGFzzbjlbiizQVcCwvq69txtBHshlDxmugHoAM/+41BA==", - "requires": { - "@atjson/document": "0.8.4", - "@atjson/hir": "0.8.4" - }, - "dependencies": { - "@atjson/hir": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/@atjson/hir/-/hir-0.8.4.tgz", - "integrity": "sha512-DG7UVtEpiVjLcCNPGMIW0biGLgEBNQyB+fP4YPmouarCdqeAsLZpnwFYBTzy54SjEz5mikSkG9CXcnNx9J/HjQ==", - "requires": { - "@atjson/document": "0.8.4" - } - } - } - } - } -} diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index 95b1304d3..8de8d15bc 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -1,37 +1,22 @@ { - "name": "@atjson/offset-inspector", - "version": "0.8.0", - "description": "Offset AtJSON Inspector", - "main": "dist/commonjs/index.js", - "module": "dist/modules/index.js", - "types": "dist/commonjs/index.d.ts", - "scripts": { - "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", - "prepublishOnly": "npm run build", - "start": "parcel public/index.html", - "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" - }, - "license": "Apache-2.0", - "publishConfig": { - "access": "public" - }, - "browserslist": [ - "last 2 Chrome versions" - ], - "dependencies": { - "@atjson/document": "^0.7.16", - "@atjson/editor": "^0.8.0", - "@atjson/hir": "^0.8.0", - "@atjson/renderer-commonmark": "^0.8.4", - "@atjson/renderer-webcomponent": "0.8.0", - "@atjson/offset-core-components": "0.8.0", - "node-sass": "^4.9.0" - }, - "devDependencies": { - "parcel-bundler": "1.9.7", - "ts-loader": "^4.0.0", - "tslint": "^5.9.1", - "typescript": "^2.8.1" - } + "name": "@atjson/offset-inspector", + "version": "0.8.0", + "description": "Offset AtJSON Inspector", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "browserslist": [ + "last 2 Chrome versions" + ], + "dependencies": { + "@atjson/editor": "0.8.8", + "@atjson/document": "0.8.5", + "@atjson/offset-core-components": "0.8.0", + "@atjson/renderer-commonmark": "0.8.2", + "@atjson/renderer-webcomponent": "0.8.0" + } } diff --git a/packages/@atjson/renderer-graphviz/package.json b/packages/@atjson/renderer-graphviz/package.json index 656a3e9eb..015199183 100644 --- a/packages/@atjson/renderer-graphviz/package.json +++ b/packages/@atjson/renderer-graphviz/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/hir": "0.8.7" } } diff --git a/packages/@atjson/renderer-plain-text/package.json b/packages/@atjson/renderer-plain-text/package.json index b8d957c27..000e0ec5f 100644 --- a/packages/@atjson/renderer-plain-text/package.json +++ b/packages/@atjson/renderer-plain-text/package.json @@ -16,7 +16,7 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/hir": "0.8.7", "@atjson/source-html": "0.8.8" }, diff --git a/packages/@atjson/renderer-react/package.json b/packages/@atjson/renderer-react/package.json index 5d0657a6a..1f7783959 100644 --- a/packages/@atjson/renderer-react/package.json +++ b/packages/@atjson/renderer-react/package.json @@ -16,7 +16,7 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/hir": "0.8.7", "@types/react": "^16.0.36", "@types/react-dom": "^16.0.3", diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index c201c6244..47f49637d 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -16,11 +16,11 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "^0.7.16", - "@atjson/hir": "^0.8.0" + "@atjson/document": "0.8.5", + "@atjson/hir": "0.8.7" }, "dependencies": { - "@atjson/hir": "^0.8.0", - "@atjson/renderer-hir": "^0.8.0" + "@atjson/hir": "0.8.7", + "@atjson/renderer-hir": "0.8.0" } } diff --git a/packages/@atjson/schema/package.json b/packages/@atjson/schema/package.json index 04e0c0ba6..b2cb859f5 100644 --- a/packages/@atjson/schema/package.json +++ b/packages/@atjson/schema/package.json @@ -16,6 +16,6 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.4" + "@atjson/document": "0.8.5" } } diff --git a/packages/@atjson/source-commonmark/package.json b/packages/@atjson/source-commonmark/package.json index a57452f80..ff916890c 100644 --- a/packages/@atjson/source-commonmark/package.json +++ b/packages/@atjson/source-commonmark/package.json @@ -22,7 +22,7 @@ "commonmark-spec": "^0.28.0" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/schema": "0.8.7", "@atjson/source-html": "0.8.8", "@types/entities": "^1.1.0", diff --git a/packages/@atjson/source-gdocs-paste/package.json b/packages/@atjson/source-gdocs-paste/package.json index c019aa122..41792ae30 100644 --- a/packages/@atjson/source-gdocs-paste/package.json +++ b/packages/@atjson/source-gdocs-paste/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/schema": "0.8.7" } } diff --git a/packages/@atjson/source-html/package.json b/packages/@atjson/source-html/package.json index cf5216216..bca3916ae 100644 --- a/packages/@atjson/source-html/package.json +++ b/packages/@atjson/source-html/package.json @@ -21,7 +21,7 @@ "@types/node": "^9.6.5" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/schema": "0.8.7", "parse5": "^4.0.0" } From cb6c29b29df2374399b8263c6364bbbf7988cc1c Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 16:31:29 +0100 Subject: [PATCH 083/104] Add index.js for Departures (run offset inspector) --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 index.js diff --git a/index.js b/index.js new file mode 100644 index 000000000..05bb630f9 --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); + +//process.chdir("./packages/@atjson/offset-inspector/"); +execSync("./node_modules/.bin/parcel public/index.html", { + cwd: './packages/@atjson/offset-inspector/' +}); From 61151a9a12cdebcee53a052785652263a9e1a8e3 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 3 Aug 2018 16:32:06 +0100 Subject: [PATCH 084/104] re-add parcel-bundler to offset-inspector --- packages/@atjson/offset-inspector/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index 8de8d15bc..c953f95af 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -12,6 +12,9 @@ "browserslist": [ "last 2 Chrome versions" ], + "devDependencies": { + "parcel-bundler": "1.9.7" + }, "dependencies": { "@atjson/editor": "0.8.8", "@atjson/document": "0.8.5", From d4e5b37f78ff83bcf309c4c071d8dcd59fc49cb9 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 17:47:56 +0100 Subject: [PATCH 085/104] Adjust build scripts so that lerna build will always succeed, even with local failures --- packages/@atjson/document/package.json | 2 +- packages/@atjson/hir/package.json | 2 +- packages/@atjson/renderer-commonmark/package.json | 2 +- packages/@atjson/renderer-graphviz/package.json | 2 +- packages/@atjson/renderer-hir/package.json | 2 +- packages/@atjson/renderer-plain-text/package.json | 2 +- packages/@atjson/renderer-react/package.json | 2 +- packages/@atjson/renderer-webcomponent/package.json | 2 +- packages/@atjson/schema/package.json | 2 +- packages/@atjson/source-commonmark/package.json | 2 +- packages/@atjson/source-gdocs-paste/package.json | 2 +- packages/@atjson/source-html/package.json | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/@atjson/document/package.json b/packages/@atjson/document/package.json index d184bac2d..ee95672d4 100644 --- a/packages/@atjson/document/package.json +++ b/packages/@atjson/document/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/hir/package.json b/packages/@atjson/hir/package.json index ffa64f54e..fefc94756 100644 --- a/packages/@atjson/hir/package.json +++ b/packages/@atjson/hir/package.json @@ -11,7 +11,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-commonmark/package.json b/packages/@atjson/renderer-commonmark/package.json index a07c13e81..b6bcebbcb 100644 --- a/packages/@atjson/renderer-commonmark/package.json +++ b/packages/@atjson/renderer-commonmark/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-graphviz/package.json b/packages/@atjson/renderer-graphviz/package.json index 015199183..d137f67d9 100644 --- a/packages/@atjson/renderer-graphviz/package.json +++ b/packages/@atjson/renderer-graphviz/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-hir/package.json b/packages/@atjson/renderer-hir/package.json index 76a961e65..7c1bca7c7 100644 --- a/packages/@atjson/renderer-hir/package.json +++ b/packages/@atjson/renderer-hir/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-plain-text/package.json b/packages/@atjson/renderer-plain-text/package.json index 000e0ec5f..576324580 100644 --- a/packages/@atjson/renderer-plain-text/package.json +++ b/packages/@atjson/renderer-plain-text/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-react/package.json b/packages/@atjson/renderer-react/package.json index 1f7783959..7e7c4c5e8 100644 --- a/packages/@atjson/renderer-react/package.json +++ b/packages/@atjson/renderer-react/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index 47f49637d..e2ae05910 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/schema/package.json b/packages/@atjson/schema/package.json index b2cb859f5..199ffdbae 100644 --- a/packages/@atjson/schema/package.json +++ b/packages/@atjson/schema/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/source-commonmark/package.json b/packages/@atjson/source-commonmark/package.json index ff916890c..4c8c11aed 100644 --- a/packages/@atjson/source-commonmark/package.json +++ b/packages/@atjson/source-commonmark/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/source-gdocs-paste/package.json b/packages/@atjson/source-gdocs-paste/package.json index 41792ae30..b2aa5435a 100644 --- a/packages/@atjson/source-gdocs-paste/package.json +++ b/packages/@atjson/source-gdocs-paste/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/source-html/package.json b/packages/@atjson/source-html/package.json index bca3916ae..f3c56e8b3 100644 --- a/packages/@atjson/source-html/package.json +++ b/packages/@atjson/source-html/package.json @@ -6,7 +6,7 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "scripts": { - "build": "rm -rf dist; tsc -p . && tsc -p . --module ESNext --outDir dist/modules/ --target ES2017", + "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", "lint": "tslint -c ./tslint.json 'src/**/*.ts'", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" From 498f61dec311c081b9b4fe51ebba6cc1cd3ef113 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 18:24:47 +0100 Subject: [PATCH 086/104] make build work for departures, hopefully --- Jenkinsfile | 2 +- index.js | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 31c3f20ea..4593366b4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -3,5 +3,5 @@ CnNodeBuild(project: "atjson", npmVersion: "3") { sh "npm install" sh "./node_modules/.bin/lerna bootstrap --hoist" - sh "./node_modules/.bin/lerna run build --parallel" + sh "./node_modules/.bin/lerna run build" } diff --git a/index.js b/index.js index 05bb630f9..6de65b4b1 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,9 @@ const { execSync } = require('child_process'); -//process.chdir("./packages/@atjson/offset-inspector/"); -execSync("./node_modules/.bin/parcel public/index.html", { - cwd: './packages/@atjson/offset-inspector/' -}); +const port = process.env.NODE_PORT || '8081'; + +console.log('Listening on ', port); + +process.chdir("./packages/@atjson/offset-inspector/"); +execSync(`./node_modules/.bin/parcel serve --port ${port} public/index.html`); From 3e2b562a7d0905adb21efa8de48b341836f40318 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 18:50:41 +0100 Subject: [PATCH 087/104] move parcel to full dep because departures strips dev deps --- packages/@atjson/offset-inspector/package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index c953f95af..bdf6e60a6 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -12,14 +12,12 @@ "browserslist": [ "last 2 Chrome versions" ], - "devDependencies": { - "parcel-bundler": "1.9.7" - }, "dependencies": { "@atjson/editor": "0.8.8", "@atjson/document": "0.8.5", "@atjson/offset-core-components": "0.8.0", "@atjson/renderer-commonmark": "0.8.2", - "@atjson/renderer-webcomponent": "0.8.0" + "@atjson/renderer-webcomponent": "0.8.0", + "parcel-bundler": "1.9.7" } } From 2f657bbda9a0681caed0020bfa5d4222ef11cf4d Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 19:08:36 +0100 Subject: [PATCH 088/104] Ugh, do not want to add this here, but might be necessary for departures. --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index a2d634cfd..faa985706 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,9 @@ "typedoc-plugin-monorepo": "^0.1.0", "typescript": "^2.8.1" }, + "dependencies": { + "parcel-bundler": "1.9.7" + }, "scripts": { "build": "lerna run build", "docs": "typedoc", From 9235cc9f641b6cc4d112cc4fa40f4ceb466fbec7 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 19:41:21 +0100 Subject: [PATCH 089/104] Try without hoisting? --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4593366b4..64f468298 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,6 +2,6 @@ CnNodeBuild(project: "atjson", nodeVersion: "nsolid-2.3.4-boron", npmVersion: "3") { sh "npm install" - sh "./node_modules/.bin/lerna bootstrap --hoist" + sh "./node_modules/.bin/lerna bootstrap" sh "./node_modules/.bin/lerna run build" } From 44b0de7ff865e4ad8494547c871330917c0cefaf Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 20:05:39 +0100 Subject: [PATCH 090/104] debugging --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 6de65b4b1..85a063fb7 100644 --- a/index.js +++ b/index.js @@ -7,4 +7,5 @@ const port = process.env.NODE_PORT || '8081'; console.log('Listening on ', port); process.chdir("./packages/@atjson/offset-inspector/"); +console.log('current directory ', process.cwd()); execSync(`./node_modules/.bin/parcel serve --port ${port} public/index.html`); From c07ae746aa4ac0e3bb57830430d2b96b41b23e10 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 22:38:56 +0100 Subject: [PATCH 091/104] giving up. switching to a local server. shrug. --- index.js | 43 ++++++++++++++++--- package.json | 1 + .../@atjson/offset-inspector/package.json | 12 ++++-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 85a063fb7..55ea320ae 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,40 @@ -#!/usr/bin/env node +const appName = require('./package').name; +const express = require('express'); +const app = express(); -const { execSync } = require('child_process'); +const basePath = '/packages/@atjson/offset-inspector/dist'; -const port = process.env.NODE_PORT || '8081'; +app.use(express.static(__dirname + basePath, { + index: false +})); -console.log('Listening on ', port); +// /ping for a healthy app! +app.get('/ping', (req, res) => res.send(200)); -process.chdir("./packages/@atjson/offset-inspector/"); -console.log('current directory ', process.cwd()); -execSync(`./node_modules/.bin/parcel serve --port ${port} public/index.html`); +let index = require('fs').readFileSync(__dirname + basePath + '/index.html').toString(); +//let environment = require('./config/environment')(process.env['NODE_ENV'] || 'development'); + +// Dynamic configuration is stored in a meta tag named "${package.name}/config" +/*let metaTag = new RegExp(`name="${appName}/config/environment" content="(.*)"`); +if (index.match(metaTag) == null) { + console.warn(''); +} + +index = index.replace(metaTag, function (match) { + return `name="${appName}/config/environment" content="${encodeURIComponent(JSON.stringify(environment))}"`; +}); +*/ + +// Return the index.html with appropriate configuration variables +app.get('*', function (req, res) { + res.send(index); +}); + +if (process.env['NODE_PORT']) { + let port = process.env['NODE_PORT']; + app.listen(port, function () { + console.log(`${appName} listening on port ${port}`); + }); +} + +module.exports = app; diff --git a/package.json b/package.json index faa985706..21eecd89e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "typescript": "^2.8.1" }, "dependencies": { + "express": "^4.16.3", "parcel-bundler": "1.9.7" }, "scripts": { diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index bdf6e60a6..157be4dbc 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -6,18 +6,24 @@ "module": "dist/modules/index.js", "types": "dist/commonjs/index.d.ts", "license": "Apache-2.0", + "scripts": { + "build": "parcel build public/index.html", + "lint": "tslint -c ./tslint.json 'src/**/*.ts'" + }, "publishConfig": { "access": "public" }, "browserslist": [ "last 2 Chrome versions" ], - "dependencies": { + "devDependencies": { + "parcel-bundler": "1.9.7" + }, + "dependencies": { "@atjson/editor": "0.8.8", "@atjson/document": "0.8.5", "@atjson/offset-core-components": "0.8.0", "@atjson/renderer-commonmark": "0.8.2", - "@atjson/renderer-webcomponent": "0.8.0", - "parcel-bundler": "1.9.7" + "@atjson/renderer-webcomponent": "0.8.0" } } From c10ef64279e21733b921f21726ffa2d6908d560f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 23:24:48 +0100 Subject: [PATCH 092/104] Fix ts issues --- packages/@atjson/document/src/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/@atjson/document/src/index.ts b/packages/@atjson/document/src/index.ts index c40f85cb9..7cb29d1c0 100644 --- a/packages/@atjson/document/src/index.ts +++ b/packages/@atjson/document/src/index.ts @@ -12,7 +12,7 @@ export default class Document { contentType?: string; annotations: Annotation[]; schema?: Schema; - changeListeners: Function[]; + changeListeners: Array<() => void>; protected queries: Query[]; @@ -211,7 +211,7 @@ export default class Document { this.content = before + after; - let potentialMergeAnnotations = {}; + let potentialMergeAnnotations: {[key: string]: Annotation[]} = {}; for (let i = this.annotations.length - 1; i >= 0; i--) { let a = this.annotations[i]; @@ -282,11 +282,11 @@ export default class Document { for (const type in potentialMergeAnnotations) { let annotations = potentialMergeAnnotations[type]; - annotations = annotations.sort((a, b) => a.start - b.start); - for (let i = annotations.length - 1; i > 0; i--) { - if (annotations[i-1].end === annotations[i].start) { // && annotations[i-1].attributes.toJSON() === annotations[i].attributes.toJSON()) { - annotations[i-1].end = annotations[i].end; - this.removeAnnotation(annotations[i]); + annotations = annotations.sort((j, k) => j.start - k.start); + for (let l = annotations.length - 1; l > 0; l--) { + if (annotations[l - 1].end === annotations[l].start) { // && annotations[i-1].attributes.toJSON() === annotations[i].attributes.toJSON()) { + annotations[l - 1].end = annotations[l].end; + this.removeAnnotation(annotations[l]); } } } From 543a0f4b9de1ff46d5928e6635829696ed287117 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Mon, 6 Aug 2018 23:29:12 +0100 Subject: [PATCH 093/104] cleanup tsc errors --- packages/@atjson/renderer-commonmark/src/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/renderer-commonmark/src/index.ts b/packages/@atjson/renderer-commonmark/src/index.ts index ed0f893dc..5ebce08ee 100644 --- a/packages/@atjson/renderer-commonmark/src/index.ts +++ b/packages/@atjson/renderer-commonmark/src/index.ts @@ -7,10 +7,14 @@ export function* split(): Iterable { let end = text.length; let match; - while ((match = text.slice(start).match(/^(\s| ){1}/)) && start < end) { + while (start < end) { + match = text.slice(start).match(/^(\s| ){1}/); + if (!match) break; start += match[1].length; } - while ((match = text.slice(0, end).match(/(\s| ){1}$/)) && end > start) { + while (end > start) { + match = text.slice(0, end).match(/(\s| ){1}$/); + if (!match) break; end -= match[1].length; } From 82e470c48040a5164c2d1c59d2a4f23745bc70ef Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 7 Aug 2018 00:12:50 +0100 Subject: [PATCH 094/104] more tsc cleanup --- packages/@atjson/editor/src/index.ts | 17 ++++---- packages/@atjson/editor/src/mixins/events.ts | 6 +-- .../@atjson/editor/src/selection-toolbar.ts | 3 +- packages/@atjson/editor/src/text-selection.ts | 11 +++-- packages/@atjson/hir/src/hir-node.ts | 14 +++---- packages/@atjson/hir/src/json-node.ts | 2 +- .../src/components/heading-action-button.ts | 11 +++-- .../src/components/superscript.ts | 4 +- .../offset-core-components/src/index.ts | 41 +++++++++---------- .../src/mixins/events.ts | 6 +-- .../annotations-inspector.ts | 2 +- .../document-inspector/character-counter.ts | 3 -- .../src/document-inspector/index.ts | 4 +- .../@atjson/offset-inspector/src/index.ts | 3 -- .../offset-inspector/src/mixins/events.ts | 6 +-- 15 files changed, 66 insertions(+), 67 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index ff3b3f893..812711c41 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -5,7 +5,10 @@ import './selection-toolbar'; import './text-input'; import './text-selection'; -type Range = { start: number, end: number }; +interface Range { + start: number; + end: number; +} export default class OffsetEditor extends events(HTMLElement) { @@ -16,9 +19,9 @@ export default class OffsetEditor extends events(HTMLElement) { this.selection = evt.detail; let toolbar = this.querySelector('selection-toolbar'); - let selectedAnnotations = this.document.annotations.filter(a => { + let selectedAnnotations = this.document.annotations.filter((a: Annotation) => { return (a.start <= evt.detail.start && a.end >= evt.detail.start) || - (a.start <= evt.detail.end && a.end >= evt.detail.end) + (a.start <= evt.detail.end && a.end >= evt.detail.end); }); let selectionChangeEvent = new CustomEvent('selectionchange', { @@ -68,8 +71,8 @@ export default class OffsetEditor extends events(HTMLElement) { let overlapping = this.document.annotations.filter((a: Annotation) => a.type === evt.detail.type) .filter((a: Annotation) => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); - let min = overlapping.reduce((a, b) => { return Math.min(a, b.start); }, this.document.content.length); - let max = overlapping.reduce((a, b) => { return Math.max(a, b.end); }, 0); + let min = overlapping.reduce((a: number, b: Annotation) => Math.min(a, b.start), this.document.content.length); + let max = overlapping.reduce((a: number, b: Annotation) => Math.max(a, b.end), 0); if (overlapping.length === 0) { this.document.addAnnotations(evt.detail); @@ -86,7 +89,7 @@ export default class OffsetEditor extends events(HTMLElement) { this.document.addAnnotations(Object.assign({}, overlapping[0], evt.detail, { start: Math.min(min, evt.detail.start), end: Math.max(max, evt.detail.end) })); } - overlapping.forEach(o => this.document.removeAnnotation(o)); + overlapping.forEach((o: Annotation) => this.document.removeAnnotation(o)); } else { this.document.addAnnotations(evt.detail); @@ -94,7 +97,7 @@ export default class OffsetEditor extends events(HTMLElement) { }, 'deleteAnnotation'(evt: CustomEvent) { - let annotation = this.document.annotations.find(a => a.id === evt.detail.annotationId); + let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); this.document.removeAnnotation(annotation); } diff --git a/packages/@atjson/editor/src/mixins/events.ts b/packages/@atjson/editor/src/mixins/events.ts index a97da3a5a..1a3dfe511 100644 --- a/packages/@atjson/editor/src/mixins/events.ts +++ b/packages/@atjson/editor/src/mixins/events.ts @@ -1,8 +1,6 @@ type Constructor = new (...args: any[]) => T; -export interface EventCallback { - (evt: Event): boolean; -} +export type EventCallback = (evt: Event) => boolean; export interface EventHandlerDefinitions { [key: string]: string | EventCallback; @@ -92,7 +90,7 @@ export default function(Base: HTMLElement) { } disconnectedCallback() { - Object.keys(this.eventHandlers).forEach((definition) => { + Object.keys(this.eventHandlers).forEach(definition => { let { eventName, element } = getEventNameAndElement(this, definition); element.removeEventListener(eventName, this.eventHandlers[definition]); }); diff --git a/packages/@atjson/editor/src/selection-toolbar.ts b/packages/@atjson/editor/src/selection-toolbar.ts index 4a0e0aad8..751ecb0ca 100644 --- a/packages/@atjson/editor/src/selection-toolbar.ts +++ b/packages/@atjson/editor/src/selection-toolbar.ts @@ -16,13 +16,14 @@ export default class SelectionToolbar extends WebComponent { // Bubble down the selection change event so that the button can decide if it // should be visible or not. onSelectionChange(evt: CustomEvent) { + if (!this.shadowRoot) return; + let visibleElements = false; this.shadowRoot.childNodes.forEach(element => { let event = new CustomEvent(evt.type, { bubbles: false, cancelable: true, detail: evt.detail }); element.dispatchEvent(event); if (!event.defaultPrevented) visibleElements = true; }); - console.log('visible elements?', visibleElements); } } diff --git a/packages/@atjson/editor/src/text-selection.ts b/packages/@atjson/editor/src/text-selection.ts index a6b07b919..2b43a48c9 100644 --- a/packages/@atjson/editor/src/text-selection.ts +++ b/packages/@atjson/editor/src/text-selection.ts @@ -197,14 +197,17 @@ class TextSelection extends events(HTMLElement) { } updateToolbar(range, selectionRange) { - let toolbarStyle = this.shadowRoot.querySelector('.toolbar').style; + if (!this.shadowRoot) return; + let toolbar = this.shadowRoot.querySelector('.toolbar'); + if (!toolbar) return; + let toolbarStyle = toolbar.style; if (range[0] === range[1]) { toolbarStyle.display = 'none'; } else { window.requestAnimationFrame(_ => { let selectionBoundingRect = selectionRange.getRangeAt(0).getBoundingClientRect(); toolbarStyle.display = 'block'; - toolbarStyle.top = selectionBoundingRect.y - this.shadowRoot.querySelector('.toolbar').offsetHeight - 3; + toolbarStyle.top = selectionBoundingRect.y - toolbar.offsetHeight - 3; toolbarStyle.left = selectionBoundingRect.x; }); } @@ -213,7 +216,9 @@ class TextSelection extends events(HTMLElement) { resumeInput() { if (this._previousRange) { this.setSelection(this._previousRange); - this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + if (this._focusNode) { + this._focusNode.dispatchEvent(new CustomEvent('cursorblur', { bubbles: true })); + } } } diff --git a/packages/@atjson/hir/src/hir-node.ts b/packages/@atjson/hir/src/hir-node.ts index 11a8a8202..fe7917bb2 100644 --- a/packages/@atjson/hir/src/hir-node.ts +++ b/packages/@atjson/hir/src/hir-node.ts @@ -1,6 +1,6 @@ import Document, { Annotation, Display, Schema } from '@atjson/document'; -import JSONNode from './json-node'; import { HIR } from '.'; +import JSONNode from './json-node'; const RANK = { root: 0, @@ -20,7 +20,7 @@ export default class HIRNode { start: number; end: number; - id?: number|string; + id?: number | string; text?: string; @@ -30,7 +30,7 @@ export default class HIRNode { private sibling: HIRNode | undefined; private schema: Schema; - constructor(node: {type: string, start: number, end: number, display?: Display, id?: number|string, attributes?: object, text?: string}, schema?: Schema) { + constructor(node: {type: string, start: number, end: number, display?: Display, id?: number | string, attributes?: object, text?: string}, schema?: Schema) { this.type = node.type; this.start = node.start; this.end = node.end; @@ -69,14 +69,14 @@ export default class HIRNode { return this.text; } - let attributes = Object.keys(this.attributes || {}).reduce((attributes: any, key: string) => { + let attributes = Object.keys(this.attributes || {}).reduce((attrs: any, key: string) => { let value = (this.attributes as any)[key]; if (value instanceof HIR) { - attributes[key] = value.toJSON(); + attrs[key] = value.toJSON(); } else { - attributes[key] = value; + attrs[key] = value; } - return attributes; + return attrs; }, {}); return { diff --git a/packages/@atjson/hir/src/json-node.ts b/packages/@atjson/hir/src/json-node.ts index 14d0c1e1c..9898f69b0 100644 --- a/packages/@atjson/hir/src/json-node.ts +++ b/packages/@atjson/hir/src/json-node.ts @@ -2,7 +2,7 @@ export type Node = JSONNode | string; export default interface JSONNode { type: string; - id?: number|string; + id?: number | string; attributes?: { [key: string]: any }; children: Node[]; } diff --git a/packages/@atjson/offset-core-components/src/components/heading-action-button.ts b/packages/@atjson/offset-core-components/src/components/heading-action-button.ts index 9809d8b9d..acf907302 100644 --- a/packages/@atjson/offset-core-components/src/components/heading-action-button.ts +++ b/packages/@atjson/offset-core-components/src/components/heading-action-button.ts @@ -1,3 +1,4 @@ +import { Annotation } from '@atjson/document'; import WebComponent from '../mixins/component'; export default class OffsetHeadingActionButton extends WebComponent { @@ -24,7 +25,7 @@ export default class OffsetHeadingActionButton extends WebComponent { `; static events = { - selectionchange: 'onSelectionChange', + 'selectionchange': 'onSelectionChange', 'click .toggle': 'onToggleClick', 'click .level': 'onLevelClick' }; @@ -32,7 +33,7 @@ export default class OffsetHeadingActionButton extends WebComponent { selection: any; getOverlappingHeading() { - return this.selection.selectedAnnotations.find(a => a.type === 'heading'); + return this.selection.selectedAnnotations.find((a: Annotation) => a.type === 'heading'); } onSelectionChange(evt: CustomEvent) { @@ -45,6 +46,8 @@ export default class OffsetHeadingActionButton extends WebComponent { newlineFree = nlIdx === -1 || nlIdx === end - 1; } + if (!this.shadowRoot) return; + // Only display if the selection *does not* span multiple paragraphs. if (newlineFree) { @@ -78,7 +81,7 @@ export default class OffsetHeadingActionButton extends WebComponent { } } - onToggleClick(evt: MouseEvent) { + onToggleClick() { let overlappingHeading = this.getOverlappingHeading(); if (overlappingHeading) { @@ -118,7 +121,7 @@ export default class OffsetHeadingActionButton extends WebComponent { } } - onLevelClick(evt: MouseEvent) { + onLevelClick() { let overlappingHeading = this.getOverlappingHeading(); let level = parseInt(overlappingHeading.attributes.level, 10) + 1; diff --git a/packages/@atjson/offset-core-components/src/components/superscript.ts b/packages/@atjson/offset-core-components/src/components/superscript.ts index 4d2e6f1aa..9a7c24b1b 100644 --- a/packages/@atjson/offset-core-components/src/components/superscript.ts +++ b/packages/@atjson/offset-core-components/src/components/superscript.ts @@ -1,10 +1,10 @@ -import EditableComponent from "../mixins/editable-component"; +import EditableComponent from '../mixins/editable-component'; export default class OffsetSuperscriptElement extends EditableComponent { static annotationName = 'superscript'; - static elementRenderer = (node: any): Element => { + static elementRenderer = (): Element => { return document.createElement('sup'); } } diff --git a/packages/@atjson/offset-core-components/src/index.ts b/packages/@atjson/offset-core-components/src/index.ts index 08f6db18c..6f693be29 100644 --- a/packages/@atjson/offset-core-components/src/index.ts +++ b/packages/@atjson/offset-core-components/src/index.ts @@ -1,21 +1,20 @@ -import OffsetBlockquote from './components/blockquote'; -import OffsetBold from './components/bold'; -import OffsetColor from './components/color'; -import OffsetFont from './components/font'; -import OffsetHeading from './components/heading'; -import OffsetItalic from './components/italic'; -import OffsetLink from './components/link'; -import OffsetParagraph from './components/paragraph'; -import OffsetStrikethrough from './components/strikethrough'; -import OffsetSuperscript from './components/superscript'; -import OffsetUnderline from './components/underline'; -import EditableComponent from './mixins/editable-component'; - -let OffsetCoreComponents = [ - OffsetBlockquote, OffsetBold, OffsetColor, OffsetFont, OffsetHeading, - OffsetItalic, OffsetLink, OffsetParagraph, OffsetStrikethrough, OffsetSuperscript, - OffsetUnderline -]; - -export default OffsetCoreComponents; -export * from './mixins/editable-component'; \ No newline at end of file +import OffsetBlockquote from './components/blockquote'; +import OffsetBold from './components/bold'; +import OffsetColor from './components/color'; +import OffsetFont from './components/font'; +import OffsetHeading from './components/heading'; +import OffsetItalic from './components/italic'; +import OffsetLink from './components/link'; +import OffsetParagraph from './components/paragraph'; +import OffsetStrikethrough from './components/strikethrough'; +import OffsetSuperscript from './components/superscript'; +import OffsetUnderline from './components/underline'; + +let OffsetCoreComponents = [ + OffsetBlockquote, OffsetBold, OffsetColor, OffsetFont, OffsetHeading, + OffsetItalic, OffsetLink, OffsetParagraph, OffsetStrikethrough, OffsetSuperscript, + OffsetUnderline +]; + +export default OffsetCoreComponents; +export * from './mixins/editable-component'; diff --git a/packages/@atjson/offset-core-components/src/mixins/events.ts b/packages/@atjson/offset-core-components/src/mixins/events.ts index a97da3a5a..1a3dfe511 100644 --- a/packages/@atjson/offset-core-components/src/mixins/events.ts +++ b/packages/@atjson/offset-core-components/src/mixins/events.ts @@ -1,8 +1,6 @@ type Constructor = new (...args: any[]) => T; -export interface EventCallback { - (evt: Event): boolean; -} +export type EventCallback = (evt: Event) => boolean; export interface EventHandlerDefinitions { [key: string]: string | EventCallback; @@ -92,7 +90,7 @@ export default function(Base: HTMLElement) { } disconnectedCallback() { - Object.keys(this.eventHandlers).forEach((definition) => { + Object.keys(this.eventHandlers).forEach(definition => { let { eventName, element } = getEventNameAndElement(this, definition); element.removeEventListener(eventName, this.eventHandlers[definition]); }); diff --git a/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts index 2b9e39d01..9912a3e4d 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts @@ -33,7 +33,7 @@ export default class AnnotationsInspector extends WebComponent { setDocument(doc) { this.document = doc; - this.document.addEventListener('change', _ => window.requestAnimationFrame(_ => this.updateBody())); + this.document.addEventListener('change', () => window.requestAnimationFrame(() => this.updateBody())); } } diff --git a/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts index 2b5410cb0..751b1686c 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts @@ -34,8 +34,6 @@ export default class CharacterCounter extends WebComponent { .highlight { background-color: rgb(96, 200, 240); } - - `; static observedAttributes = ['start', 'end', 'content']; @@ -71,7 +69,6 @@ export default class CharacterCounter extends WebComponent { contentSpan.appendChild(content); } - attributeChangedCallback(attribute) { switch (attribute) { case 'start': diff --git a/packages/@atjson/offset-inspector/src/document-inspector/index.ts b/packages/@atjson/offset-inspector/src/document-inspector/index.ts index c19cefc3a..77766ac5a 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/index.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/index.ts @@ -102,9 +102,9 @@ export default class InspectorGadget extends WebComponent { setDocument(doc) { this.document = doc; this.shadowRoot.querySelector('annotations-inspector').setDocument(doc); - this.document.addEventListener('change', (_ => { + this.document.addEventListener('change', (() => { if (this.deferred) clearTimeout(this.deferred); - this.deferred = setTimeout(_ => { + this.deferred = setTimeout(() => { let charCounter = this.shadowRoot.querySelector('character-counter'); charCounter.setAttribute('content', this.document.content); }, 500); diff --git a/packages/@atjson/offset-inspector/src/index.ts b/packages/@atjson/offset-inspector/src/index.ts index adf0d8df5..ae1750d32 100644 --- a/packages/@atjson/offset-inspector/src/index.ts +++ b/packages/@atjson/offset-inspector/src/index.ts @@ -3,7 +3,6 @@ import CommonmarkRenderer from '@atjson/renderer-commonmark'; import InspectorGadget from './document-inspector'; import './document-inspector'; import './html-tree-inspector'; -//import '../public/logo'; import WebComponent from './mixins/component'; export default class OffsetEditorDemo extends WebComponent { @@ -43,7 +42,6 @@ export default class OffsetEditorDemo extends WebComponent { }, 'addComponent'(event) { - console.log('saw event!', event); this.shadowRoot.querySelector('html-tree-inspector').addComponent(event.detail.component); } }; @@ -151,7 +149,6 @@ export default class OffsetEditorDemo extends WebComponent { let inspectorGadget: InspectorGadget = this.shadowRoot.querySelector('inspector-gadget'); let editor = this.querySelector('offset-editor'); - console.log('in here?', doc) if (inspectorGadget) { inspectorGadget.setDocument(doc); inspectorGadget.setSelection(editor.getSelection()); diff --git a/packages/@atjson/offset-inspector/src/mixins/events.ts b/packages/@atjson/offset-inspector/src/mixins/events.ts index a97da3a5a..1a3dfe511 100644 --- a/packages/@atjson/offset-inspector/src/mixins/events.ts +++ b/packages/@atjson/offset-inspector/src/mixins/events.ts @@ -1,8 +1,6 @@ type Constructor = new (...args: any[]) => T; -export interface EventCallback { - (evt: Event): boolean; -} +export type EventCallback = (evt: Event) => boolean; export interface EventHandlerDefinitions { [key: string]: string | EventCallback; @@ -92,7 +90,7 @@ export default function(Base: HTMLElement) { } disconnectedCallback() { - Object.keys(this.eventHandlers).forEach((definition) => { + Object.keys(this.eventHandlers).forEach(definition => { let { eventName, element } = getEventNameAndElement(this, definition); element.removeEventListener(eventName, this.eventHandlers[definition]); }); From fc7689dd780a2b904e1a8ae2e58212d04f540f06 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Tue, 7 Aug 2018 08:05:16 -0400 Subject: [PATCH 095/104] Update to latest @atjson/document in renderer-commonmark and renderer-hir. --- packages/@atjson/renderer-commonmark/package.json | 2 +- packages/@atjson/renderer-hir/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@atjson/renderer-commonmark/package.json b/packages/@atjson/renderer-commonmark/package.json index b6bcebbcb..5375adcdd 100644 --- a/packages/@atjson/renderer-commonmark/package.json +++ b/packages/@atjson/renderer-commonmark/package.json @@ -22,7 +22,7 @@ "markdown-it": "^8.4.1" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/hir": "0.8.7" } } diff --git a/packages/@atjson/renderer-hir/package.json b/packages/@atjson/renderer-hir/package.json index 7c1bca7c7..9039dbd26 100644 --- a/packages/@atjson/renderer-hir/package.json +++ b/packages/@atjson/renderer-hir/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.4", + "@atjson/document": "0.8.5", "@atjson/hir": "0.8.7" } } From d60ccf256637f50d334a9562dc579621a77f2280 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Tue, 7 Aug 2018 08:17:38 -0400 Subject: [PATCH 096/104] offset-core-components: Override shadowRoot to not allow null. --- packages/@atjson/editor/src/index.ts | 2 +- .../offset-core-components/src/components/color-editor.ts | 2 +- .../offset-core-components/src/components/font-editor.ts | 2 +- .../@atjson/offset-core-components/src/mixins/component.ts | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 812711c41..980b496f9 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -99,7 +99,7 @@ export default class OffsetEditor extends events(HTMLElement) { 'deleteAnnotation'(evt: CustomEvent) { let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); this.document.removeAnnotation(annotation); - } + }, 'attributechange'(evt: CustomEvent) { if (evt.detail.annotationId) { diff --git a/packages/@atjson/offset-core-components/src/components/color-editor.ts b/packages/@atjson/offset-core-components/src/components/color-editor.ts index 35653a46b..93e4fcce6 100644 --- a/packages/@atjson/offset-core-components/src/components/color-editor.ts +++ b/packages/@atjson/offset-core-components/src/components/color-editor.ts @@ -8,7 +8,7 @@ export default class ColorEditor extends WebComponent { 'beforeinput': 'beforeInput', 'click .cancel': 'cursorBlur', 'click .save': 'onSave', - 'keypress .text-color': 'handleKeypress' + 'keypress .text-color': 'handleKeypress', 'keypress .background-color': 'handleKeypress' }; diff --git a/packages/@atjson/offset-core-components/src/components/font-editor.ts b/packages/@atjson/offset-core-components/src/components/font-editor.ts index 6315c3e1d..8d6e4f5b8 100644 --- a/packages/@atjson/offset-core-components/src/components/font-editor.ts +++ b/packages/@atjson/offset-core-components/src/components/font-editor.ts @@ -8,7 +8,7 @@ export default class FontEditor extends WebComponent { 'beforeinput': 'beforeInput', 'click .cancel': 'cursorBlur', 'click .save': 'onSave', - 'keypress .font-family': 'handleKeypress' + 'keypress .font-family': 'handleKeypress', 'keypress .font-size': 'handleKeypress' }; diff --git a/packages/@atjson/offset-core-components/src/mixins/component.ts b/packages/@atjson/offset-core-components/src/mixins/component.ts index ed9e74d42..fdd666096 100644 --- a/packages/@atjson/offset-core-components/src/mixins/component.ts +++ b/packages/@atjson/offset-core-components/src/mixins/component.ts @@ -18,10 +18,12 @@ export default class WebComponent extends events(HTMLElement) { return this.compiledElement; } + shadowRoot: ShadowRoot; + constructor() { super(); - let shadowRoot = this.attachShadow({ mode: 'open' }); - shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); + this.shadowRoot = this.attachShadow({ mode: 'open' }); + this.shadowRoot.appendChild(WebComponent.compiledTemplate.cloneNode(true)); } dispatchAttributeChangeEvent(attributes: {}) { From 9ca5c5ddf39b448bf60ae682e2c4bab68639db58 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Tue, 7 Aug 2018 12:21:01 -0400 Subject: [PATCH 097/104] Don't bump @atjson/document version (Lerna will handle it). --- packages/@atjson/document/package.json | 2 +- packages/@atjson/editor/package.json | 4 +- packages/@atjson/hir/package.json | 2 +- .../@atjson/offset-inspector/package.json | 38 +++++++++---------- .../@atjson/renderer-commonmark/package.json | 2 +- .../@atjson/renderer-graphviz/package.json | 2 +- packages/@atjson/renderer-hir/package.json | 2 +- .../@atjson/renderer-plain-text/package.json | 2 +- packages/@atjson/renderer-react/package.json | 2 +- .../renderer-webcomponent/package.json | 2 +- packages/@atjson/schema/package.json | 2 +- .../@atjson/source-commonmark/package.json | 2 +- .../@atjson/source-gdocs-paste/package.json | 2 +- packages/@atjson/source-html/package.json | 2 +- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/@atjson/document/package.json b/packages/@atjson/document/package.json index ee95672d4..704caeb13 100644 --- a/packages/@atjson/document/package.json +++ b/packages/@atjson/document/package.json @@ -1,6 +1,6 @@ { "name": "@atjson/document", - "version": "0.8.5", + "version": "0.8.4", "description": "Document definition for AtJSON", "main": "dist/commonjs/index.js", "module": "dist/modules/index.js", diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index d9625cb54..6877ab805 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -20,9 +20,9 @@ "last 2 Chrome versions" ], "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/renderer-webcomponent": "0.8.0", - "@atjson/renderer-commonmark": "0.8.2", + "@atjson/renderer-commonmark": "0.9.0", "@atjson/hir": "0.8.7", "@atjson/offset-core-components": "0.8.0", "node-sass": "^4.9.0" diff --git a/packages/@atjson/hir/package.json b/packages/@atjson/hir/package.json index fefc94756..a2a43e6ee 100644 --- a/packages/@atjson/hir/package.json +++ b/packages/@atjson/hir/package.json @@ -21,6 +21,6 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.5" + "@atjson/document": "0.8.4" } } diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index 157be4dbc..8b2498911 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -1,29 +1,29 @@ { - "name": "@atjson/offset-inspector", - "version": "0.8.0", - "description": "Offset AtJSON Inspector", - "main": "dist/commonjs/index.js", - "module": "dist/modules/index.js", - "types": "dist/commonjs/index.d.ts", - "license": "Apache-2.0", + "name": "@atjson/offset-inspector", + "version": "0.8.0", + "description": "Offset AtJSON Inspector", + "main": "dist/commonjs/index.js", + "module": "dist/modules/index.js", + "types": "dist/commonjs/index.d.ts", + "license": "Apache-2.0", "scripts": { "build": "parcel build public/index.html", "lint": "tslint -c ./tslint.json 'src/**/*.ts'" }, - "publishConfig": { - "access": "public" - }, - "browserslist": [ - "last 2 Chrome versions" - ], + "publishConfig": { + "access": "public" + }, + "browserslist": [ + "last 2 Chrome versions" + ], "devDependencies": { "parcel-bundler": "1.9.7" }, "dependencies": { - "@atjson/editor": "0.8.8", - "@atjson/document": "0.8.5", - "@atjson/offset-core-components": "0.8.0", - "@atjson/renderer-commonmark": "0.8.2", - "@atjson/renderer-webcomponent": "0.8.0" - } + "@atjson/editor": "0.8.8", + "@atjson/document": "0.8.4", + "@atjson/offset-core-components": "0.8.0", + "@atjson/renderer-commonmark": "0.9.0", + "@atjson/renderer-webcomponent": "0.8.0" + } } diff --git a/packages/@atjson/renderer-commonmark/package.json b/packages/@atjson/renderer-commonmark/package.json index 5375adcdd..b6bcebbcb 100644 --- a/packages/@atjson/renderer-commonmark/package.json +++ b/packages/@atjson/renderer-commonmark/package.json @@ -22,7 +22,7 @@ "markdown-it": "^8.4.1" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7" } } diff --git a/packages/@atjson/renderer-graphviz/package.json b/packages/@atjson/renderer-graphviz/package.json index d137f67d9..e811270ad 100644 --- a/packages/@atjson/renderer-graphviz/package.json +++ b/packages/@atjson/renderer-graphviz/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7" } } diff --git a/packages/@atjson/renderer-hir/package.json b/packages/@atjson/renderer-hir/package.json index 9039dbd26..7c1bca7c7 100644 --- a/packages/@atjson/renderer-hir/package.json +++ b/packages/@atjson/renderer-hir/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7" } } diff --git a/packages/@atjson/renderer-plain-text/package.json b/packages/@atjson/renderer-plain-text/package.json index 576324580..e89a366c1 100644 --- a/packages/@atjson/renderer-plain-text/package.json +++ b/packages/@atjson/renderer-plain-text/package.json @@ -16,7 +16,7 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7", "@atjson/source-html": "0.8.8" }, diff --git a/packages/@atjson/renderer-react/package.json b/packages/@atjson/renderer-react/package.json index 7e7c4c5e8..094542077 100644 --- a/packages/@atjson/renderer-react/package.json +++ b/packages/@atjson/renderer-react/package.json @@ -16,7 +16,7 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7", "@types/react": "^16.0.36", "@types/react-dom": "^16.0.3", diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index e2ae05910..5c8a86565 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -16,7 +16,7 @@ "access": "public" }, "devDependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/hir": "0.8.7" }, "dependencies": { diff --git a/packages/@atjson/schema/package.json b/packages/@atjson/schema/package.json index 199ffdbae..0ae606f04 100644 --- a/packages/@atjson/schema/package.json +++ b/packages/@atjson/schema/package.json @@ -16,6 +16,6 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.5" + "@atjson/document": "0.8.4" } } diff --git a/packages/@atjson/source-commonmark/package.json b/packages/@atjson/source-commonmark/package.json index 4c8c11aed..98d1ea9fb 100644 --- a/packages/@atjson/source-commonmark/package.json +++ b/packages/@atjson/source-commonmark/package.json @@ -22,7 +22,7 @@ "commonmark-spec": "^0.28.0" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/schema": "0.8.7", "@atjson/source-html": "0.8.8", "@types/entities": "^1.1.0", diff --git a/packages/@atjson/source-gdocs-paste/package.json b/packages/@atjson/source-gdocs-paste/package.json index b2aa5435a..b71dfc439 100644 --- a/packages/@atjson/source-gdocs-paste/package.json +++ b/packages/@atjson/source-gdocs-paste/package.json @@ -16,7 +16,7 @@ "access": "public" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/schema": "0.8.7" } } diff --git a/packages/@atjson/source-html/package.json b/packages/@atjson/source-html/package.json index f3c56e8b3..8116f7610 100644 --- a/packages/@atjson/source-html/package.json +++ b/packages/@atjson/source-html/package.json @@ -21,7 +21,7 @@ "@types/node": "^9.6.5" }, "dependencies": { - "@atjson/document": "0.8.5", + "@atjson/document": "0.8.4", "@atjson/schema": "0.8.7", "parse5": "^4.0.0" } From 31ab1642826cad8fd56ce87424a7945b7941b5b2 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Tue, 7 Aug 2018 12:36:06 -0400 Subject: [PATCH 098/104] Extend root tsconfig.json and use tsconfig when invoking tslint. --- packages/@atjson/document/package.json | 2 +- packages/@atjson/document/tslint.json | 31 ++----------------- packages/@atjson/editor/package.json | 2 +- packages/@atjson/editor/tslint.json | 31 ++----------------- packages/@atjson/hir/package.json | 2 +- packages/@atjson/hir/tslint.json | 31 ++----------------- .../offset-core-components/package.json | 2 +- .../offset-core-components/tslint.json | 31 ++----------------- .../@atjson/offset-inspector/package.json | 2 +- packages/@atjson/offset-inspector/tslint.json | 31 ++----------------- .../@atjson/renderer-commonmark/package.json | 2 +- .../@atjson/renderer-commonmark/tslint.json | 31 ++----------------- .../@atjson/renderer-graphviz/package.json | 2 +- .../@atjson/renderer-graphviz/tslint.json | 31 ++----------------- packages/@atjson/renderer-hir/package.json | 2 +- packages/@atjson/renderer-hir/tslint.json | 31 ++----------------- .../@atjson/renderer-plain-text/package.json | 2 +- .../@atjson/renderer-plain-text/tslint.json | 31 ++----------------- packages/@atjson/renderer-react/package.json | 2 +- .../renderer-webcomponent/package.json | 2 +- .../@atjson/renderer-webcomponent/tslint.json | 31 ++----------------- packages/@atjson/schema/package.json | 2 +- packages/@atjson/schema/tslint.json | 31 ++----------------- .../@atjson/source-commonmark/package.json | 2 +- .../@atjson/source-commonmark/tslint.json | 31 ++----------------- .../@atjson/source-gdocs-paste/package.json | 2 +- .../@atjson/source-gdocs-paste/tslint.json | 31 ++----------------- packages/@atjson/source-html/package.json | 2 +- packages/@atjson/source-html/tslint.json | 31 ++----------------- tslint.json | 1 + 30 files changed, 44 insertions(+), 421 deletions(-) diff --git a/packages/@atjson/document/package.json b/packages/@atjson/document/package.json index 704caeb13..195e2e608 100644 --- a/packages/@atjson/document/package.json +++ b/packages/@atjson/document/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/document/tslint.json b/packages/@atjson/document/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/document/tslint.json +++ b/packages/@atjson/document/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/editor/package.json b/packages/@atjson/editor/package.json index 6877ab805..ae9f9c1aa 100644 --- a/packages/@atjson/editor/package.json +++ b/packages/@atjson/editor/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "start": "parcel public/index.html", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" diff --git a/packages/@atjson/editor/tslint.json b/packages/@atjson/editor/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/editor/tslint.json +++ b/packages/@atjson/editor/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/hir/package.json b/packages/@atjson/hir/package.json index a2a43e6ee..a9f8588cb 100644 --- a/packages/@atjson/hir/package.json +++ b/packages/@atjson/hir/package.json @@ -12,7 +12,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/hir/tslint.json b/packages/@atjson/hir/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/hir/tslint.json +++ b/packages/@atjson/hir/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/offset-core-components/package.json b/packages/@atjson/offset-core-components/package.json index f38f7393c..e89a637ab 100644 --- a/packages/@atjson/offset-core-components/package.json +++ b/packages/@atjson/offset-core-components/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/offset-core-components/tslint.json b/packages/@atjson/offset-core-components/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/offset-core-components/tslint.json +++ b/packages/@atjson/offset-core-components/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/offset-inspector/package.json b/packages/@atjson/offset-inspector/package.json index 8b2498911..5d0fb9c1f 100644 --- a/packages/@atjson/offset-inspector/package.json +++ b/packages/@atjson/offset-inspector/package.json @@ -8,7 +8,7 @@ "license": "Apache-2.0", "scripts": { "build": "parcel build public/index.html", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'" + "lint": "tslint -p ." }, "publishConfig": { "access": "public" diff --git a/packages/@atjson/offset-inspector/tslint.json b/packages/@atjson/offset-inspector/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/offset-inspector/tslint.json +++ b/packages/@atjson/offset-inspector/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/renderer-commonmark/package.json b/packages/@atjson/renderer-commonmark/package.json index b6bcebbcb..e35278202 100644 --- a/packages/@atjson/renderer-commonmark/package.json +++ b/packages/@atjson/renderer-commonmark/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-commonmark/tslint.json b/packages/@atjson/renderer-commonmark/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/renderer-commonmark/tslint.json +++ b/packages/@atjson/renderer-commonmark/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/renderer-graphviz/package.json b/packages/@atjson/renderer-graphviz/package.json index e811270ad..038be7bdc 100644 --- a/packages/@atjson/renderer-graphviz/package.json +++ b/packages/@atjson/renderer-graphviz/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-graphviz/tslint.json b/packages/@atjson/renderer-graphviz/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/renderer-graphviz/tslint.json +++ b/packages/@atjson/renderer-graphviz/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/renderer-hir/package.json b/packages/@atjson/renderer-hir/package.json index 7c1bca7c7..731231cb4 100644 --- a/packages/@atjson/renderer-hir/package.json +++ b/packages/@atjson/renderer-hir/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-hir/tslint.json b/packages/@atjson/renderer-hir/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/renderer-hir/tslint.json +++ b/packages/@atjson/renderer-hir/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/renderer-plain-text/package.json b/packages/@atjson/renderer-plain-text/package.json index e89a366c1..a3cc08e0c 100644 --- a/packages/@atjson/renderer-plain-text/package.json +++ b/packages/@atjson/renderer-plain-text/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-plain-text/tslint.json b/packages/@atjson/renderer-plain-text/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/renderer-plain-text/tslint.json +++ b/packages/@atjson/renderer-plain-text/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/renderer-react/package.json b/packages/@atjson/renderer-react/package.json index 094542077..b9f421bbc 100644 --- a/packages/@atjson/renderer-react/package.json +++ b/packages/@atjson/renderer-react/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-webcomponent/package.json b/packages/@atjson/renderer-webcomponent/package.json index 5c8a86565..8db053222 100644 --- a/packages/@atjson/renderer-webcomponent/package.json +++ b/packages/@atjson/renderer-webcomponent/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/renderer-webcomponent/tslint.json b/packages/@atjson/renderer-webcomponent/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/renderer-webcomponent/tslint.json +++ b/packages/@atjson/renderer-webcomponent/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/schema/package.json b/packages/@atjson/schema/package.json index 0ae606f04..ef7c6f289 100644 --- a/packages/@atjson/schema/package.json +++ b/packages/@atjson/schema/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/schema/tslint.json b/packages/@atjson/schema/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/schema/tslint.json +++ b/packages/@atjson/schema/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/source-commonmark/package.json b/packages/@atjson/source-commonmark/package.json index 98d1ea9fb..c0f461198 100644 --- a/packages/@atjson/source-commonmark/package.json +++ b/packages/@atjson/source-commonmark/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/source-commonmark/tslint.json b/packages/@atjson/source-commonmark/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/source-commonmark/tslint.json +++ b/packages/@atjson/source-commonmark/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/source-gdocs-paste/package.json b/packages/@atjson/source-gdocs-paste/package.json index b71dfc439..80acefd8a 100644 --- a/packages/@atjson/source-gdocs-paste/package.json +++ b/packages/@atjson/source-gdocs-paste/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/source-gdocs-paste/tslint.json b/packages/@atjson/source-gdocs-paste/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/source-gdocs-paste/tslint.json +++ b/packages/@atjson/source-gdocs-paste/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/packages/@atjson/source-html/package.json b/packages/@atjson/source-html/package.json index 8116f7610..ff8db5ad0 100644 --- a/packages/@atjson/source-html/package.json +++ b/packages/@atjson/source-html/package.json @@ -7,7 +7,7 @@ "types": "dist/commonjs/index.d.ts", "scripts": { "build": "rm -rf dist; tsc -p . ; tsc -p . --module ESNext --outDir dist/modules/ --target ES2017; exit 0", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "lint": "tslint -p .", "prepublishOnly": "npm run build", "test": "../../../node_modules/.bin/jest packages/@atjson/$(basename $PWD) --config=../../../package.json" }, diff --git a/packages/@atjson/source-html/tslint.json b/packages/@atjson/source-html/tslint.json index 30612ee31..fdb2e2d8f 100644 --- a/packages/@atjson/source-html/tslint.json +++ b/packages/@atjson/source-html/tslint.json @@ -1,30 +1,3 @@ { - "extends": "tslint:recommended", - "defaultSeverity": "warning", - "rules": { - "arrow-parens": [true, "ban-single-arg-parens"], - "curly": [true, "ignore-same-line"], - "forin": false, - "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], - "max-line-length": [false], - "member-access": [true, "no-public"], - "no-empty-interface": false, - "object-literal-sort-keys": false, - "ordered-imports": [ - true, - { - "import-sources-order": "lowercase-last", - "named-imports-order": "lowercase-last" - } - ], - "prefer-const": false, - "quotemark": [true, "single"], - "trailing-comma": [true, { "multiline": "never", "singleline": "never" }], - "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore", "allow-pascal-case"], - "whitespace": [true, - "check-branch", "check-decl", "check-module", "check-operator", "check-preblock", - "check-rest-spread", "check-separator", "check-type", "check-type-operator", "check-typecast" - ] - } -} + "extends": "../../../tslint.json" +} \ No newline at end of file diff --git a/tslint.json b/tslint.json index 30612ee31..25df00caa 100644 --- a/tslint.json +++ b/tslint.json @@ -10,6 +10,7 @@ "max-line-length": [false], "member-access": [true, "no-public"], "no-empty-interface": false, + "no-implicit-dependencies": [true, "dev"], "object-literal-sort-keys": false, "ordered-imports": [ true, From 189d37dc92c274e12998b30ef1295bb8aeb59f77 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Tue, 7 Aug 2018 13:52:11 -0400 Subject: [PATCH 099/104] Alphabetize tsconfig.json entries. --- tsconfig.json | 24 ++++++++++++------------ tslint.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 0c33085b5..35032f567 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,23 @@ { "compilerOptions": { - "target": "ES6", + "alwaysStrict": true, + "baseUrl": "./", "declaration": true, - "module": "commonjs", - "removeComments": true, "downlevelIteration": true, - "skipDefaultLibCheck": true, - "strict": true, - "alwaysStrict": true, + "experimentalDecorators": true, + "inlineSourceMap": true, + "module": "commonjs", + "moduleResolution": "node", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "moduleResolution": "node", "paths": { "parse5": ["./node_modules/parse5/lib/index.d.ts"] }, - "baseUrl": "./", - "inlineSourceMap": true, - "experimentalDecorators": true + "removeComments": true, + "skipDefaultLibCheck": true, + "strict": true, + "target": "ES6" } } diff --git a/tslint.json b/tslint.json index 25df00caa..f441ce8b9 100644 --- a/tslint.json +++ b/tslint.json @@ -6,7 +6,7 @@ "curly": [true, "ignore-same-line"], "forin": false, "interface-name": [true, "never-prefix"], - "max-classes-per-file": [false], + "max-classes-per-file": [false, 1], "max-line-length": [false], "member-access": [true, "no-public"], "no-empty-interface": false, From deb5a8817ce62be372886e57746ef4704a24f5da Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Wed, 8 Aug 2018 16:30:10 -0400 Subject: [PATCH 100/104] offset-core-components: Revert acccessing of compiledTemplate. --- packages/@atjson/offset-core-components/src/mixins/component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@atjson/offset-core-components/src/mixins/component.ts b/packages/@atjson/offset-core-components/src/mixins/component.ts index fdd666096..2aedb4943 100644 --- a/packages/@atjson/offset-core-components/src/mixins/component.ts +++ b/packages/@atjson/offset-core-components/src/mixins/component.ts @@ -23,7 +23,7 @@ export default class WebComponent extends events(HTMLElement) { constructor() { super(); this.shadowRoot = this.attachShadow({ mode: 'open' }); - this.shadowRoot.appendChild(WebComponent.compiledTemplate.cloneNode(true)); + this.shadowRoot.appendChild(this.constructor.compiledTemplate.content.cloneNode(true)); } dispatchAttributeChangeEvent(attributes: {}) { From dece44d5d88bb76369884f33259a14839759de9c Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Fri, 31 Aug 2018 22:16:02 +0200 Subject: [PATCH 101/104] Move events to named functions --- packages/@atjson/editor/src/index.ts | 215 ++++++++++++++------------- 1 file changed, 114 insertions(+), 101 deletions(-) diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 980b496f9..9610d7227 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -5,113 +5,28 @@ import './selection-toolbar'; import './text-input'; import './text-selection'; -interface Range { +export interface Range { start: number; end: number; } export default class OffsetEditor extends events(HTMLElement) { - static template = '
'; + static template = '' + + '' + + '' + + '
' + + '
' + + '
'; static events = { - 'change text-selection'(evt: CustomEvent) { - this.selection = evt.detail; - let toolbar = this.querySelector('selection-toolbar'); - - let selectedAnnotations = this.document.annotations.filter((a: Annotation) => { - return (a.start <= evt.detail.start && a.end >= evt.detail.start) || - (a.start <= evt.detail.end && a.end >= evt.detail.end); - }); - - let selectionChangeEvent = new CustomEvent('selectionchange', { - detail: Object.assign({ - selectedAnnotations, - document: this.document - }, evt.detail), - bubbles: false - }); - toolbar.dispatchEvent(selectionChangeEvent); - }, - - 'insertText text-input'(evt: CustomEvent) { - this.document.insertText(evt.detail.position, evt.detail.text); - this.selection.start += evt.detail.text.length; - this.selection.end += evt.detail.text.length; - }, - - 'deleteText text-input'(evt: CustomEvent) { - let deletion = evt.detail; - this.document.deleteText(deletion); - // FIXME the selection should just be an annotation that we transform. We shouldn't handle logic here. - if (this.selection.start < deletion.start) { - // do nothing. - } else if (this.selection.start < deletion.end) { - this.selection.start = this.selection.end = deletion.start; - } else { - let l = deletion.end - deletion.start; - this.selection.start -= l; - this.selection.end -= l; - } - }, - - 'replaceText text-input'(evt: CustomEvent) { - let replacement = evt.detail; - - this.document.deleteText(replacement); - this.document.insertText(replacement.start, replacement.text); - this.selection.start = replacement.start + replacement.text.length; - }, - - 'addAnnotation'(evt: CustomEvent) { - if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { - - const contained = (a: Annotation, b: Annotation) => a.start >= b.start && a.end <= b.end; - const offset = (a: Annotation, b: Annotation) => a.start <= b.end && a.end >= b.start; - let overlapping = this.document.annotations.filter((a: Annotation) => a.type === evt.detail.type) - .filter((a: Annotation) => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); - - let min = overlapping.reduce((a: number, b: Annotation) => Math.min(a, b.start), this.document.content.length); - let max = overlapping.reduce((a: number, b: Annotation) => Math.max(a, b.end), 0); - - if (overlapping.length === 0) { - this.document.addAnnotations(evt.detail); - - } else if (min <= evt.detail.start && evt.detail.end <= max && overlapping.length === 1) { - // invert the state. - let prev = overlapping[0]; - let newFirst = Object.assign({}, prev, evt.detail, { start: prev.start, end: evt.detail.start }); - let newLast = Object.assign({}, prev, evt.detail, { start: evt.detail.end, end: prev.end }); - if (min !== evt.detail.start) this.document.addAnnotations(newFirst); - if (max !== evt.detail.end) this.document.addAnnotations(newLast); - - } else { - this.document.addAnnotations(Object.assign({}, overlapping[0], evt.detail, { start: Math.min(min, evt.detail.start), end: Math.max(max, evt.detail.end) })); - } - - overlapping.forEach((o: Annotation) => this.document.removeAnnotation(o)); - - } else { - this.document.addAnnotations(evt.detail); - } - }, - - 'deleteAnnotation'(evt: CustomEvent) { - let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); - this.document.removeAnnotation(annotation); - }, - - 'attributechange'(evt: CustomEvent) { - if (evt.detail.annotationId) { - let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); - this.document.replaceAnnotation(annotation, Object.assign(annotation, {attributes: evt.detail.attributes})); - } else if (evt.target !== null) { - let annotationId = evt.target.getAttribute('data-annotation-id'); - let annotation = this.document.annotations.find((a: Annotation) => a.id.toString(10) === annotationId); - this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); - } - } - + 'change text-selection': 'handleTextSelectionChange', + 'insertText text-input': 'handleTextInsert', + 'deleteText text-input': 'handleTextDelete', + 'replaceText text-input': 'handleTextReplace', + 'addAnnotation': 'handleAnnotationAdd', + 'deleteAnnotation': 'handleAnnotationDelete', + 'attributechange': 'handleAttributeChange' }; selection: Range | undefined; @@ -169,8 +84,9 @@ export default class OffsetEditor extends events(HTMLElement) { } addContentFeature(component: any) { - if (component.selectionButton) { - this.querySelector('selection-toolbar').shadowRoot.appendChild(component.selectionButton); + const selectionToolbar = this.querySelector('selection-toolbar'); + if (component.selectionButton && selectionToolbar instanceof Element) { + selectionToolbar.shadowRoot.appendChild(component.selectionButton); } if (component.annotationName) { @@ -187,6 +103,103 @@ export default class OffsetEditor extends events(HTMLElement) { super.connectedCallback(); this.scheduleRender(); } + + handleTextSelectionChange(evt: CustomEvent) { + this.selection = evt.detail; + let toolbar = this.querySelector('selection-toolbar'); + + let selectedAnnotations = this.document.annotations.filter((a: Annotation) => { + return (a.start <= evt.detail.start && a.end >= evt.detail.start) || + (a.start <= evt.detail.end && a.end >= evt.detail.end); + }); + + let selectionChangeEvent = new CustomEvent('selectionchange', { + detail: Object.assign({ + selectedAnnotations, + document: this.document + }, evt.detail), + bubbles: false + }); + toolbar.dispatchEvent(selectionChangeEvent); + } + + handleTextInsert(evt: CustomEvent) { + this.document.insertText(evt.detail.position, evt.detail.text); + this.selection.start += evt.detail.text.length; + this.selection.end += evt.detail.text.length; + } + + handleTextDelete(evt: CustomEvent) { + let deletion = evt.detail; + this.document.deleteText(deletion); + // FIXME the selection should just be an annotation that we transform. We shouldn't handle logic here. + if (this.selection.start < deletion.start) { + // do nothing. + } else if (this.selection.start < deletion.end) { + this.selection.start = this.selection.end = deletion.start; + } else { + let l = deletion.end - deletion.start; + this.selection.start -= l; + this.selection.end -= l; + } + } + + handleTextReplace(evt: CustomEvent) { + let replacement = evt.detail; + + this.document.deleteText(replacement); + this.document.insertText(replacement.start, replacement.text); + this.selection.start = replacement.start + replacement.text.length; + } + + handleAnnotationAdd(evt: CustomEvent) { + if (evt.detail.type === 'bold' || evt.detail.type === 'italic') { + + const contained = (a: Annotation, b: Annotation) => a.start >= b.start && a.end <= b.end; + const offset = (a: Annotation, b: Annotation) => a.start <= b.end && a.end >= b.start; + let overlapping = this.document.annotations.filter((a: Annotation) => a.type === evt.detail.type) + .filter((a: Annotation) => contained(a, evt.detail) || contained(evt.detail, a) || offset(a, evt.detail) || offset(evt.detail, a)); + + let min = overlapping.reduce((a: number, b: Annotation) => Math.min(a, b.start), this.document.content.length); + let max = overlapping.reduce((a: number, b: Annotation) => Math.max(a, b.end), 0); + + if (overlapping.length === 0) { + this.document.addAnnotations(evt.detail); + + } else if (min <= evt.detail.start && evt.detail.end <= max && overlapping.length === 1) { + // invert the state. + let prev = overlapping[0]; + let newFirst = Object.assign({}, prev, evt.detail, { start: prev.start, end: evt.detail.start }); + let newLast = Object.assign({}, prev, evt.detail, { start: evt.detail.end, end: prev.end }); + if (min !== evt.detail.start) this.document.addAnnotations(newFirst); + if (max !== evt.detail.end) this.document.addAnnotations(newLast); + + } else { + this.document.addAnnotations(Object.assign({}, overlapping[0], evt.detail, { start: Math.min(min, evt.detail.start), end: Math.max(max, evt.detail.end) })); + } + + overlapping.forEach((o: Annotation) => this.document.removeAnnotation(o)); + + } else { + this.document.addAnnotations(evt.detail); + } + } + + handleAnnotationDelete(evt: CustomEvent) { + let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); + this.document.removeAnnotation(annotation); + } + + handleAttributeChange(evt: CustomEvent) { + if (evt.detail.annotationId) { + let annotation = this.document.annotations.find((a: Annotation) => a.id === evt.detail.annotationId); + this.document.replaceAnnotation(annotation, Object.assign(annotation, {attributes: evt.detail.attributes})); + } else if (evt.target !== null) { + let annotationId = evt.target.getAttribute('data-annotation-id'); + let annotation = this.document.annotations.find((a: Annotation) => a.id.toString() === annotationId); + this.document.replaceAnnotation(annotation, Object.assign(annotation, evt.detail)); + } + } } if (!window.customElements.get('offset-editor')) { From b4bf2872d0fd079383f473aaa7c73f0f4827c673 Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 4 Sep 2018 09:21:48 -0500 Subject: [PATCH 102/104] Tweaks to improve dramatically improve performance of inspector. --- .../offset-inspector/public/superscript.ts | 2 +- .../annotation-inspector.ts | 2 +- .../annotations-inspector.ts | 46 ++++++++++++-- .../document-inspector/character-counter.ts | 12 +++- .../src/html-tree-inspector.ts | 10 ++- .../@atjson/offset-inspector/src/index.ts | 61 ++++++++++++++++--- 6 files changed, 110 insertions(+), 23 deletions(-) diff --git a/packages/@atjson/offset-inspector/public/superscript.ts b/packages/@atjson/offset-inspector/public/superscript.ts index 82f990fbf..2db1f7a9c 100644 --- a/packages/@atjson/offset-inspector/public/superscript.ts +++ b/packages/@atjson/offset-inspector/public/superscript.ts @@ -10,7 +10,7 @@ export default class Superscript { let el = document.createElement('button'); el.setAttribute('data-type', this.annotationName); el.innerHTML = this.annotationName; - let start + let start; let end; el.addEventListener('selectionchange', (evt: CustomEvent) => { diff --git a/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts index 70b04b227..407e7e89c 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotation-inspector.ts @@ -38,7 +38,7 @@ export default class AnnotationInspector extends WebComponent { } `; - static observedAttributes = ['type', 'start', 'end', 'attributes']; + static observedAttributes = ['type', 'start', 'end']; attributeChangedCallback(attribute) { switch (attribute) { diff --git a/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts index 9912a3e4d..0bd7b39f8 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/annotations-inspector.ts @@ -18,22 +18,56 @@ export default class AnnotationsInspector extends WebComponent { document: Document; updateBody() { - let body = ''; + let aInspectors = {}; + this.document.annotations.forEach(a => { + let id = a.id.toString(); + let b = this.shadowRoot.querySelector(`[id="${id}"]`); + aInspectors[id] = b; + }); + + this.shadowRoot.childNodes.forEach(c => { + if (!aInspectors[c.getAttribute('id')]) this.shadowRoot.removeChild(c); + }); + this.document.annotations.sort((a, b) => a.start - b.start).forEach(a => { - body += ``; + let aInspector; + if (aInspectors[a.id.toString()]) { + aInspector = aInspectors[a.id.toString()]; + } else { + aInspector = document.createElement('annotation-inspector'); + aInspector.setAttribute('id', a.id); + this.shadowRoot.appendChild(aInspector); + } + aInspector.setAttribute('type', a.type); + aInspector.setAttribute('start', a.start); + aInspector.setAttribute('end', a.end); + if (a.attributes) { Object.keys(a.attributes).forEach(key => { - body += ``; + let aAttribute = aInspector.querySelector(`[name="${key}"]`); + if (aAttribute === null) { + aAttribute = document.createElement('annotation-attribute'); + aAttribute.setAttribute('name', key); + aInspector.appendChild(aAttribute); + } + aAttribute.setAttribute('value', a.attributes[key]); }); } - body += ''; }); - this.shadowRoot.innerHTML = body; } setDocument(doc) { + // n.b. this really needs a document.removeEventListener, and probably should be refactored in general. + if (this.document === doc) return; this.document = doc; - this.document.addEventListener('change', () => window.requestAnimationFrame(() => this.updateBody())); + this.document.addEventListener('change', () => { + if (this._updateCallback) return; + this._updateCallback = () => { + this.updateBody(); + setTimeout(() => { delete this._updateCallback; }, 0); + }; + window.requestIdleCallback(this._updateCallback); + }; } } diff --git a/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts index 751b1686c..918295f94 100644 --- a/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts +++ b/packages/@atjson/offset-inspector/src/document-inspector/character-counter.ts @@ -42,7 +42,11 @@ export default class CharacterCounter extends WebComponent { const start = parseInt(this.getAttribute('start'), 10); const end = parseInt(this.getAttribute('end'), 10); let contentSpan = this.shadowRoot.querySelector('.content'); - let rawContent = this.getAttribute('content').replace(/\n/g, '¶'); + let rawContent = ''; + let contentAttr = this.getAttribute('content'); + if (typeof contentAttr === 'string') { + rawContent = contentAttr.replace(/\n/g, '¶'); + } let content = document.createElement('span'); let contentStart = document.createTextNode(rawContent.substr(0, start)); @@ -65,7 +69,7 @@ export default class CharacterCounter extends WebComponent { content.appendChild(highlight); content.appendChild(contentEnd); - contentSpan.innerHTML = ''; + if (contentSpan.children[0]) contentSpan.removeChild(contentSpan.children[0]); contentSpan.appendChild(content); } @@ -74,7 +78,9 @@ export default class CharacterCounter extends WebComponent { case 'start': case 'end': case 'content': - this.updateContent(); + window.requestIdleCallback(() => { + this.updateContent(); + }); break; } } diff --git a/packages/@atjson/offset-inspector/src/html-tree-inspector.ts b/packages/@atjson/offset-inspector/src/html-tree-inspector.ts index 8de290493..7fa86bff6 100644 --- a/packages/@atjson/offset-inspector/src/html-tree-inspector.ts +++ b/packages/@atjson/offset-inspector/src/html-tree-inspector.ts @@ -95,9 +95,9 @@ export default class HTMLTreeInspector extends WebComponent { document: Document; render(event: CustomEvent) { - if (this.deferred) clearTimeout(this.deferred); + if (this.deferred) return; - this.deferred = setTimeout(_ => { + this.deferred = () => { let doc = event.detail.document; let outputElement = this.shadowRoot.querySelector('.wrapper'); let rendered = new WebComponentRenderer(doc).render(); @@ -105,7 +105,11 @@ export default class HTMLTreeInspector extends WebComponent { let children = this.renderChildren(rendered.childNodes); outputElement.innerHTML = ''; outputElement.appendChild(children); - }, 100); + + delete this.deferred; + }; + + window.requestIdleCallback(this.deferred); } diff --git a/packages/@atjson/offset-inspector/src/index.ts b/packages/@atjson/offset-inspector/src/index.ts index ae1750d32..cb146068d 100644 --- a/packages/@atjson/offset-inspector/src/index.ts +++ b/packages/@atjson/offset-inspector/src/index.ts @@ -24,11 +24,7 @@ export default class OffsetEditorDemo extends WebComponent { ''; static events = { - 'change'(evt: CustomEvent) { - this.shadowRoot.querySelector('html-tree-inspector').dispatchEvent(new CustomEvent('change', {detail: {document: evt.detail.document}})); - this.renderMarkdown(evt.detail.document); - this.renderInspector(evt.detail.document); - }, + 'change': 'renderAll', 'click .tabs'(event) { let targetTabClass = event.path[0].getAttribute('data-target'); @@ -39,6 +35,8 @@ export default class OffsetEditorDemo extends WebComponent { this.shadowRoot.querySelector('.editor > .' + targetTabClass).classList.add('active'); this.shadowRoot.querySelector('.editor > .tabs > .active').classList.remove('active'); event.path[0].classList.add('active'); + + this.renderAll(); }, 'addComponent'(event) { @@ -134,11 +132,39 @@ export default class OffsetEditorDemo extends WebComponent { } `; + _pendingCallback: () => void; + _document?: Document; + + renderAll(evt?: CustomEvent) { + + if (evt) this._document = evt.detail.document; + + let doc: Document; + if (this._document instanceof Document) { + doc = this._document; + } else { + return; + } + + if (this._pendingCallback) return; + + this._pendingCallback = () => { + this.updateHtmlTreeInspector(doc); + this.renderMarkdown(doc); + this.renderInspector(doc); + delete this._pendingCallback; + }; + + window.requestIdleCallback(this._pendingCallback); + } + renderMarkdown(doc: Document) { - let outputElement = this.shadowRoot.querySelector('.markdown'); - let rendered = new CommonmarkRenderer().render(doc); - if (outputElement) { - outputElement.textContent = rendered; + if (this.activeTab('commonmark-tab')) { + let outputElement = this.shadowRoot.querySelector('.markdown'); + let rendered = new CommonmarkRenderer().render(doc); + if (outputElement) { + outputElement.textContent = rendered; + } } } @@ -154,6 +180,23 @@ export default class OffsetEditorDemo extends WebComponent { inspectorGadget.setSelection(editor.getSelection()); } } + + updateHtmlTreeInspector(doc: Document) { + if (this.activeTab('html-tab')) { + this.shadowRoot.querySelector('html-tree-inspector').dispatchEvent( + new CustomEvent('change', {detail: {document: doc}}) + ); + } + } + + activeTab(wanted: string) { + let activeTab = this.shadowRoot.querySelector('.tabs > .active'); + if (activeTab) { + return activeTab.classList.contains(wanted); + } else { + return false; + } + } } if (!window.customElements.get('offset-editor-demo')) { From d22c5f773863f2593f39106c66f780dadcd8fc1f Mon Sep 17 00:00:00 2001 From: Blaine Cook Date: Tue, 4 Sep 2018 09:23:18 -0500 Subject: [PATCH 103/104] tiny cleanup --- packages/@atjson/editor/public/app.ts | 3 --- packages/@atjson/editor/src/index.ts | 7 ++++++- .../offset-core-components/src/components/blockquote.ts | 2 +- .../@atjson/offset-core-components/src/components/bold.ts | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/@atjson/editor/public/app.ts b/packages/@atjson/editor/public/app.ts index 526d24a10..e9e85aaa7 100644 --- a/packages/@atjson/editor/public/app.ts +++ b/packages/@atjson/editor/public/app.ts @@ -3,8 +3,6 @@ import '../src'; import OffsetEditor from '../src'; import './logo'; -import EditableLink from '../src/components/editable-link'; - // Web components in the registry can't be redefined, // so reload the page on every change if (module.hot) { @@ -16,7 +14,6 @@ if (module.hot) { document.addEventListener('DOMContentLoaded', () => { let editor: OffsetEditor = document.querySelector('offset-editor'); - editor.addContentFeature(EditableLink); let doc = new URL(location.toString()).searchParams.get('document'); if (doc) { diff --git a/packages/@atjson/editor/src/index.ts b/packages/@atjson/editor/src/index.ts index 9610d7227..01729297f 100644 --- a/packages/@atjson/editor/src/index.ts +++ b/packages/@atjson/editor/src/index.ts @@ -30,7 +30,12 @@ export default class OffsetEditor extends events(HTMLElement) { }; selection: Range | undefined; - document: Document | undefined; + document: Document; + + constructor() { + super(); + this.document = new Document(''); + } get value() { return this.document; diff --git a/packages/@atjson/offset-core-components/src/components/blockquote.ts b/packages/@atjson/offset-core-components/src/components/blockquote.ts index 04c377e4c..aa99fc50a 100644 --- a/packages/@atjson/offset-core-components/src/components/blockquote.ts +++ b/packages/@atjson/offset-core-components/src/components/blockquote.ts @@ -2,7 +2,7 @@ export default class OffsetBlockquoteElement { static annotationName = 'blockquote'; - static elementRenderer = (node: any): Element => { + static elementRenderer(): Element { return document.createElement('blockquote'); } } diff --git a/packages/@atjson/offset-core-components/src/components/bold.ts b/packages/@atjson/offset-core-components/src/components/bold.ts index ab4995df8..e8fbd709d 100644 --- a/packages/@atjson/offset-core-components/src/components/bold.ts +++ b/packages/@atjson/offset-core-components/src/components/bold.ts @@ -2,7 +2,7 @@ export default class OffsetBoldElement { static annotationName = 'bold'; - static elementRenderer = (node: any): Element => { + static elementRenderer(): Element { return document.createElement('strong'); } } From 2bdabc9ea2812b460d821aa5fd941708115b3919 Mon Sep 17 00:00:00 2001 From: David Wu Spencer Date: Fri, 7 Sep 2018 13:45:25 -0400 Subject: [PATCH 104/104] =?UTF-8?q?=F0=9F=9B=80=20Add=20non-emitting=20tsc?= =?UTF-8?q?onfig.json=20to=20editor/test.=20(#79)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sets a TypeScript compilation context for ts files in test/ allowing VSCode (among other editors) to surface TypeScript errors. --- packages/@atjson/editor/test/tsconfig.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/@atjson/editor/test/tsconfig.json diff --git a/packages/@atjson/editor/test/tsconfig.json b/packages/@atjson/editor/test/tsconfig.json new file mode 100644 index 000000000..37564fe47 --- /dev/null +++ b/packages/@atjson/editor/test/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "noEmit": true + }, + "include": [ + "**/*" + ] +}