We consider syntactic conventions and parsing methods that have worked well for us when applied over several dozen newly created plugins.
When we refer to configuring a plugin with specialized markup we could just as correctly say programming in a domain-specific language. However, with each reference to programming language we confront the attractive nuisance of compiler technology and turing completeness. We need neither.
Chorus of Voices asks, What words will mean things in the context of various representations? How will they form sentences that get things done? If each representation has its own markup how will these expressions influence representations outside their realm of discourse?
# Syntax
We favor syntax that does not rely on punctuation. We assume most text is to be interpreted literally as if it were in quotes. Most characters are to serve a user's need which we won't try to understand.
Where we have had keywords we have required that they be few in number and written in all capital letters. We expect them to be enumerated fully in the plugin's about page in simple sentences.
Say XYX to blah blah blah.
We preserve newlines when editing and sometimes treat the first word of a line as having special meaning or be the only place where we expect keywords. We sometimes treat blank lines as a significant separator.
# Parsing
We examine the text of an item when the plugin is asked to 'emit' on page rendering or after item editing.
emit = ($item, item) -> parse item.text
A common practice is to parse text one line at a time, returning an object for each, and reporting that in some enhanced representation including error notifications for lines that don't parse.
emit = ($item, item) -> report parse line for line in item.text.split /\n/
Parsing might switch on isolated keywords.
parse = (line) -> for keyword in line.match /[A-Z]+/g || [] switch keyword when 'ABC' then ... when 'XYZ' then ... else return {error: "don't know #{keyword}"}
Parsing might look only for keywords it knows.
parse = (line) -> line.match /^ABC\b/, -> return ... line.match /^XYZ\b/, -> return ... return {error: "no keyword found"}
Our convention for reporting parsing problems is to render the offending line on a pink background and to add a footnote-style asterisk who's hover will explain the error.
<span style="background-color:#fdd;"> ... <span title="error message">*</span> </span>
A plugin might expect to be configured by the programmer with options manually patched into the json of samples provided in about pages.
if item.submit? $item.append "<button>Submit</button>"
A plugin must treat whatever it finds in an item with some suspicion since items move freely through the federation. For example, text must be escaped one way or another before rendered into the dom.
escape = (line) -> line .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>')