import Types from '.';
import XRegExp from 'xregexp';
import { SEPARATOR } from '../constants.json';
/**
* A base type for all line types
*
* @example
* new Type(XRegExp.exec('Foo', XRegExp('(?<source>)')));
*
* @class Type
* @param {object} match The result of an XRegExp match
* @param {string} match.source The original native source
* @param {string} match.content The content of the line
*/
export default class Type {
constructor(match) {
this.meta = JSON.parse(match.meta);
this.match = match;
}
/**
* @property {string} content The human-readable content of the line
*/
get content() {
return this.match.content;
}
/**
* @property {string} groupType The type of group this line belongs to
* @see {@link Type.groupType}
*/
get groupType() {
return this.constructor.groupType;
}
/**
* @property {boolean} isNesting Whether this line is nestable in groups
*/
get isNesting() {
return false;
}
/**
* @property {boolean} isSummarized Whether this line is included in a Canvas
* document summary
*/
get isSummarized() {
return true;
}
/**
* @property {string} source The original native source of this line
*/
get source() {
return this.match.source;
}
/**
* @property {string} type A human-readable name for this type
* @see {@link Type.type}
*/
get type() {
return this.constructor.type;
}
/**
* @property {string} typeKey A short, typically one-character key to denote
* this line type
* @see {@link Type.typeKey}
*/
get typeKey() {
return this.constructor.typeKey;
}
/**
* @method
* @return {object} An object representing this line in a JSON-serializable
* form
*/
toJSON() {
return {
type: this.type,
content: this.content,
meta: this.meta
};
}
/**
* @method
* @param {Type} prev The line before the line being converted to Markdown
* @param {Type} next The line after the line being converted to Markdown
* @param {object} [context={}] Contextual information for the Markdown
* conversion
* @return {string} The Markdown representation of this line
*/
toMarkdown(_prev, _next, _context) {
throw new Error('Must implement `#toMarkdown` for each type');
}
/**
* @static
* @property {string} groupType The type of group this line belongs to
*/
static get groupType() {
return Types[this.type].groupType || 'canvas';
}
/**
* @static
* @property {string} type A human-readable name for this type
*/
static get type() {
throw new Error('Must implement `type` for each type');
}
/**
* @static
* @property {string} typeKey A short, typically one-character key to denote
* this line type
*/
static get typeKey() {
return Types[this.type].typeKey;
}
/**
* @static
* @property {XRegExp} markdownPattern An XRegExp object that matches the
* Markdown form of this line type
*/
static get markdownPattern() {
throw new Error('Must implement `markdownPattern` for each type');
}
/**
* @static
* @property {XRegExp} nativePattern An XRegExp object that matches the native
* form of this line type
*/
static get nativePattern() {
return XRegExp(`^
(?<source>
${this.typeKey}${SEPARATOR}
(?<meta> .*)${SEPARATOR}
(?<content> .*))$`, 'x');
}
/**
* Build a Canvas Native string of this type from a given content string and
* meta data object.
*
* @static
* @method
* @param {string} [content=''] The readable content for the native line
* @param {object} [meta={}] The metadata for the native line
*/
static buildNative(content = '', meta = {}) {
return [
this.typeKey,
JSON.stringify(meta),
content,
].join(SEPARATOR);
}
/**
* Match a Markdown string and return a line of this type if it matches.
*
* @static
* @method
* @param {string} markdown The Markdown to possibly match this line against
* @param {?object} [context={}] A context object containing the surrounding
* context of this line
* @return {?object} An object representing the match information for this
* line
*/
static matchMarkdown(markdown, _context) {
const match = XRegExp.exec(markdown, this.markdownPattern);
if (!match) {
return null;
}
const meta = {};
for (const key in match) {
if (!match.hasOwnProperty(key) || !/^meta_.+$/.test(key)) {
continue;
}
meta[key.split('_')[1]] = match[key];
}
const nativeString = this.buildNative(match.content, meta);
return this.matchNative(nativeString);
}
/**
* Match a native string and return a line of this type if it matches.
*
* @static
* @method
* @param {string} native The native string to possibly match this line
* against
* @return {?object} An object representing the match information for this
* line
*/
static matchNative(native) {
const match = XRegExp.exec(native, this.nativePattern);
return match ? new this(match) : null;
}
}