Skip to content

Commit

Permalink
Implement Mobiledoc parser for v0.3.0 format
Browse files Browse the repository at this point in the history
  • Loading branch information
rlivsey authored and mixonic committed Feb 2, 2016
1 parent a9c2d80 commit 2c32894
Show file tree
Hide file tree
Showing 4 changed files with 419 additions and 6 deletions.
169 changes: 169 additions & 0 deletions src/js/parsers/mobiledoc/0-3.js
@@ -0,0 +1,169 @@
import {
MOBILEDOC_MARKUP_SECTION_TYPE,
MOBILEDOC_IMAGE_SECTION_TYPE,
MOBILEDOC_LIST_SECTION_TYPE,
MOBILEDOC_CARD_SECTION_TYPE,
MOBILEDOC_MARKUP_MARKER_TYPE,
MOBILEDOC_ATOM_MARKER_TYPE
} from 'mobiledoc-kit/renderers/mobiledoc/0-3';
import { kvArrayToObject, filter } from "../../utils/array-utils";

/*
* Parses from mobiledoc -> post
*/
export default class MobiledocParser {
constructor(builder) {
this.builder = builder;
}

/**
* @method parse
* @param {Mobiledoc}
* @return {Post}
*/
parse({ version, sections, markups: markerTypes, cards: cardTypes, atoms: atomTypes }) {
try {
const post = this.builder.createPost();

this.markups = [];
this.markerTypes = this.parseMarkerTypes(markerTypes);
this.cardTypes = this.parseCardTypes(cardTypes);
this.atomTypes = this.parseAtomTypes(atomTypes);
this.parseSections(sections, post);

return post;
} catch (e) {
throw new Error(`Unable to parse mobiledoc: ${e.message}`);
}
}

parseMarkerTypes(markerTypes) {
return markerTypes.map((markerType) => this.parseMarkerType(markerType));
}

parseMarkerType([tagName, attributesArray]) {
const attributesObject = kvArrayToObject(attributesArray || []);
return this.builder.createMarkup(tagName, attributesObject);
}

parseCardTypes(cardTypes) {
return cardTypes.map((cardType) => this.parseCardType(cardType));
}

parseCardType([cardName, cardPayload]) {
return [cardName, cardPayload];
}

parseAtomTypes(atomTypes) {
return atomTypes.map((atomType) => this.parseAtomType(atomType));
}

parseAtomType([atomName, atomValue, atomPayload]) {
return [atomName, atomValue, atomPayload];
}

parseSections(sections, post) {
sections.forEach((section) => this.parseSection(section, post));
}

parseSection(section, post) {
let [type] = section;
switch(type) {
case MOBILEDOC_MARKUP_SECTION_TYPE:
this.parseMarkupSection(section, post);
break;
case MOBILEDOC_IMAGE_SECTION_TYPE:
this.parseImageSection(section, post);
break;
case MOBILEDOC_CARD_SECTION_TYPE:
this.parseCardSection(section, post);
break;
case MOBILEDOC_LIST_SECTION_TYPE:
this.parseListSection(section, post);
break;
default:
throw new Error(`Unexpected section type ${type}`);
}
}

getAtomTypeFromIndex(index) {
const atomType = this.atomTypes[index];
if (!atomType) {
throw new Error(`No atom definition found at index ${index}`);
}
return atomType;
}

getCardTypeFromIndex(index) {
const cardType = this.cardTypes[index];
if (!cardType) {
throw new Error(`No card definition found at index ${index}`);
}
return cardType;
}

parseCardSection([type, cardIndex], post) {
const [name, payload] = this.getCardTypeFromIndex(cardIndex);
const section = this.builder.createCardSection(name, payload);
post.sections.append(section);
}

parseImageSection([type, src], post) {
const section = this.builder.createImageSection(src);
post.sections.append(section);
}

parseMarkupSection([type, tagName, markers], post) {
const section = this.builder.createMarkupSection(tagName);
post.sections.append(section);
this.parseMarkers(markers, section);
// Strip blank markers after the have been created. This ensures any
// markup they include has been correctly populated.
filter(section.markers, m => m.isEmpty).forEach(m => {
section.markers.remove(m);
});
}

parseListSection([type, tagName, items], post) {
const section = this.builder.createListSection(tagName);
post.sections.append(section);
this.parseListItems(items, section);
}

parseListItems(items, section) {
items.forEach(i => this.parseListItem(i, section));
}

parseListItem(markers, section) {
const item = this.builder.createListItem();
this.parseMarkers(markers, item);
section.items.append(item);
}

parseMarkers(markers, parent) {
markers.forEach(m => this.parseMarker(m, parent));
}

parseMarker([type, markerTypeIndexes, closeCount, value], parent) {
markerTypeIndexes.forEach(index => {
this.markups.push(this.markerTypes[index]);
});

const marker = this.buildMarkerType(type, value);
parent.markers.append(marker);

this.markups = this.markups.slice(0, this.markups.length-closeCount);
}

buildMarkerType(type, value) {
switch (type) {
case MOBILEDOC_MARKUP_MARKER_TYPE:
return this.builder.createMarker(value, this.markups.slice());
case MOBILEDOC_ATOM_MARKER_TYPE:
const [atomName, atomValue, atomPayload] = this.getAtomTypeFromIndex(value);
return this.builder.createAtom(atomName, atomValue, atomPayload);
default:
throw new Error(`Unexpected marker type ${type}`);
}
}
}
9 changes: 7 additions & 2 deletions src/js/parsers/mobiledoc/index.js
@@ -1,5 +1,8 @@
import MobiledocParser_0_2 from './0-2';
import { MOBILEDOC_VERSION } from 'mobiledoc-kit/renderers/mobiledoc/0-2';
import MobiledocParser_0_3 from './0-3';

import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_2 } from 'mobiledoc-kit/renderers/mobiledoc/0-2';
import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3 } from 'mobiledoc-kit/renderers/mobiledoc/0-3';
import assert from 'mobiledoc-kit/utils/assert';

function parseVersion(mobiledoc) {
Expand All @@ -10,8 +13,10 @@ export default {
parse(builder, mobiledoc) {
let version = parseVersion(mobiledoc);
switch (version) {
case MOBILEDOC_VERSION:
case MOBILEDOC_VERSION_0_2:
return new MobiledocParser_0_2(builder).parse(mobiledoc);
case MOBILEDOC_VERSION_0_3:
return new MobiledocParser_0_3(builder).parse(mobiledoc);
default:
assert(`Unknown version of mobiledoc parser requested: ${version}`,
false);
Expand Down
8 changes: 4 additions & 4 deletions src/js/renderers/mobiledoc/0-3.js
Expand Up @@ -18,8 +18,8 @@ export const MOBILEDOC_IMAGE_SECTION_TYPE = 2;
export const MOBILEDOC_LIST_SECTION_TYPE = 3;
export const MOBILEDOC_CARD_SECTION_TYPE = 10;

export const MOBILEDOC_MARKUP_CONTENT_TYPE = 0;
export const MOBILEDOC_ATOM_CONTENT_TYPE = 1;
export const MOBILEDOC_MARKUP_MARKER_TYPE = 0;
export const MOBILEDOC_ATOM_MARKER_TYPE = 1;

const visitor = {
[POST_TYPE](node, opcodes) {
Expand Down Expand Up @@ -70,7 +70,7 @@ const postOpcodeCompiler = {
openMarker(closeCount, value) {
this.markupMarkerIds = [];
this.markers.push([
MOBILEDOC_MARKUP_CONTENT_TYPE,
MOBILEDOC_MARKUP_MARKER_TYPE,
this.markupMarkerIds,
closeCount,
value || ''
Expand Down Expand Up @@ -99,7 +99,7 @@ const postOpcodeCompiler = {
const index = this._findOrAddAtomTypeIndex(name, value, payload);
this.markupMarkerIds = [];
this.markers.push([
MOBILEDOC_ATOM_CONTENT_TYPE,
MOBILEDOC_ATOM_MARKER_TYPE,
this.markupMarkerIds,
closeCount,
index
Expand Down

0 comments on commit 2c32894

Please sign in to comment.