index.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. var CommentParser = (function (exports) {
  2. 'use strict';
  3. /** @deprecated */
  4. exports.Markers = void 0;
  5. (function (Markers) {
  6. Markers["start"] = "/**";
  7. Markers["nostart"] = "/***";
  8. Markers["delim"] = "*";
  9. Markers["end"] = "*/";
  10. })(exports.Markers = exports.Markers || (exports.Markers = {}));
  11. function isSpace(source) {
  12. return /^\s+$/.test(source);
  13. }
  14. function splitCR(source) {
  15. const matches = source.match(/\r+$/);
  16. return matches == null
  17. ? ['', source]
  18. : [source.slice(-matches[0].length), source.slice(0, -matches[0].length)];
  19. }
  20. function splitSpace(source) {
  21. const matches = source.match(/^\s+/);
  22. return matches == null
  23. ? ['', source]
  24. : [source.slice(0, matches[0].length), source.slice(matches[0].length)];
  25. }
  26. function splitLines(source) {
  27. return source.split(/\n/);
  28. }
  29. function seedBlock(block = {}) {
  30. return Object.assign({ description: '', tags: [], source: [], problems: [] }, block);
  31. }
  32. function seedSpec(spec = {}) {
  33. return Object.assign({ tag: '', name: '', type: '', optional: false, description: '', problems: [], source: [] }, spec);
  34. }
  35. function seedTokens(tokens = {}) {
  36. return Object.assign({ start: '', delimiter: '', postDelimiter: '', tag: '', postTag: '', name: '', postName: '', type: '', postType: '', description: '', end: '', lineEnd: '' }, tokens);
  37. }
  38. /**
  39. * Assures Block.tags[].source contains references to the Block.source items,
  40. * using Block.source as a source of truth. This is a counterpart of rewireSpecs
  41. * @param block parsed coments block
  42. */
  43. function rewireSource(block) {
  44. const source = block.source.reduce((acc, line) => acc.set(line.number, line), new Map());
  45. for (const spec of block.tags) {
  46. spec.source = spec.source.map((line) => source.get(line.number));
  47. }
  48. return block;
  49. }
  50. /**
  51. * Assures Block.source contains references to the Block.tags[].source items,
  52. * using Block.tags[].source as a source of truth. This is a counterpart of rewireSource
  53. * @param block parsed coments block
  54. */
  55. function rewireSpecs(block) {
  56. const source = block.tags.reduce((acc, spec) => spec.source.reduce((acc, line) => acc.set(line.number, line), acc), new Map());
  57. block.source = block.source.map((line) => source.get(line.number) || line);
  58. return block;
  59. }
  60. const reTag = /^@\S+/;
  61. /**
  62. * Creates configured `Parser`
  63. * @param {Partial<Options>} options
  64. */
  65. function getParser$3({ fence = '```', } = {}) {
  66. const fencer = getFencer(fence);
  67. const toggleFence = (source, isFenced) => fencer(source) ? !isFenced : isFenced;
  68. return function parseBlock(source) {
  69. // start with description section
  70. const sections = [[]];
  71. let isFenced = false;
  72. for (const line of source) {
  73. if (reTag.test(line.tokens.description) && !isFenced) {
  74. sections.push([line]);
  75. }
  76. else {
  77. sections[sections.length - 1].push(line);
  78. }
  79. isFenced = toggleFence(line.tokens.description, isFenced);
  80. }
  81. return sections;
  82. };
  83. }
  84. function getFencer(fence) {
  85. if (typeof fence === 'string')
  86. return (source) => source.split(fence).length % 2 === 0;
  87. return fence;
  88. }
  89. function getParser$2({ startLine = 0, markers = exports.Markers, } = {}) {
  90. let block = null;
  91. let num = startLine;
  92. return function parseSource(source) {
  93. let rest = source;
  94. const tokens = seedTokens();
  95. [tokens.lineEnd, rest] = splitCR(rest);
  96. [tokens.start, rest] = splitSpace(rest);
  97. if (block === null &&
  98. rest.startsWith(markers.start) &&
  99. !rest.startsWith(markers.nostart)) {
  100. block = [];
  101. tokens.delimiter = rest.slice(0, markers.start.length);
  102. rest = rest.slice(markers.start.length);
  103. [tokens.postDelimiter, rest] = splitSpace(rest);
  104. }
  105. if (block === null) {
  106. num++;
  107. return null;
  108. }
  109. const isClosed = rest.trimRight().endsWith(markers.end);
  110. if (tokens.delimiter === '' &&
  111. rest.startsWith(markers.delim) &&
  112. !rest.startsWith(markers.end)) {
  113. tokens.delimiter = markers.delim;
  114. rest = rest.slice(markers.delim.length);
  115. [tokens.postDelimiter, rest] = splitSpace(rest);
  116. }
  117. if (isClosed) {
  118. const trimmed = rest.trimRight();
  119. tokens.end = rest.slice(trimmed.length - markers.end.length);
  120. rest = trimmed.slice(0, -markers.end.length);
  121. }
  122. tokens.description = rest;
  123. block.push({ number: num, source, tokens });
  124. num++;
  125. if (isClosed) {
  126. const result = block.slice();
  127. block = null;
  128. return result;
  129. }
  130. return null;
  131. };
  132. }
  133. function getParser$1({ tokenizers }) {
  134. return function parseSpec(source) {
  135. var _a;
  136. let spec = seedSpec({ source });
  137. for (const tokenize of tokenizers) {
  138. spec = tokenize(spec);
  139. if ((_a = spec.problems[spec.problems.length - 1]) === null || _a === void 0 ? void 0 : _a.critical)
  140. break;
  141. }
  142. return spec;
  143. };
  144. }
  145. /**
  146. * Splits the `@prefix` from remaining `Spec.lines[].token.description` into the `tag` token,
  147. * and populates `spec.tag`
  148. */
  149. function tagTokenizer() {
  150. return (spec) => {
  151. const { tokens } = spec.source[0];
  152. const match = tokens.description.match(/\s*(@(\S+))(\s*)/);
  153. if (match === null) {
  154. spec.problems.push({
  155. code: 'spec:tag:prefix',
  156. message: 'tag should start with "@" symbol',
  157. line: spec.source[0].number,
  158. critical: true,
  159. });
  160. return spec;
  161. }
  162. tokens.tag = match[1];
  163. tokens.postTag = match[3];
  164. tokens.description = tokens.description.slice(match[0].length);
  165. spec.tag = match[2];
  166. return spec;
  167. };
  168. }
  169. /**
  170. * Sets splits remaining `Spec.lines[].tokes.description` into `type` and `description`
  171. * tokens and populates Spec.type`
  172. *
  173. * @param {Spacing} spacing tells how to deal with a whitespace
  174. * for type values going over multiple lines
  175. */
  176. function typeTokenizer(spacing = 'compact') {
  177. const join = getJoiner$1(spacing);
  178. return (spec) => {
  179. let curlies = 0;
  180. let lines = [];
  181. for (const [i, { tokens }] of spec.source.entries()) {
  182. let type = '';
  183. if (i === 0 && tokens.description[0] !== '{')
  184. return spec;
  185. for (const ch of tokens.description) {
  186. if (ch === '{')
  187. curlies++;
  188. if (ch === '}')
  189. curlies--;
  190. type += ch;
  191. if (curlies === 0)
  192. break;
  193. }
  194. lines.push([tokens, type]);
  195. if (curlies === 0)
  196. break;
  197. }
  198. if (curlies !== 0) {
  199. spec.problems.push({
  200. code: 'spec:type:unpaired-curlies',
  201. message: 'unpaired curlies',
  202. line: spec.source[0].number,
  203. critical: true,
  204. });
  205. return spec;
  206. }
  207. const parts = [];
  208. const offset = lines[0][0].postDelimiter.length;
  209. for (const [i, [tokens, type]] of lines.entries()) {
  210. tokens.type = type;
  211. if (i > 0) {
  212. tokens.type = tokens.postDelimiter.slice(offset) + type;
  213. tokens.postDelimiter = tokens.postDelimiter.slice(0, offset);
  214. }
  215. [tokens.postType, tokens.description] = splitSpace(tokens.description.slice(type.length));
  216. parts.push(tokens.type);
  217. }
  218. parts[0] = parts[0].slice(1);
  219. parts[parts.length - 1] = parts[parts.length - 1].slice(0, -1);
  220. spec.type = join(parts);
  221. return spec;
  222. };
  223. }
  224. const trim = (x) => x.trim();
  225. function getJoiner$1(spacing) {
  226. if (spacing === 'compact')
  227. return (t) => t.map(trim).join('');
  228. else if (spacing === 'preserve')
  229. return (t) => t.join('\n');
  230. else
  231. return spacing;
  232. }
  233. const isQuoted = (s) => s && s.startsWith('"') && s.endsWith('"');
  234. /**
  235. * Splits remaining `spec.lines[].tokens.description` into `name` and `descriptions` tokens,
  236. * and populates the `spec.name`
  237. */
  238. function nameTokenizer() {
  239. const typeEnd = (num, { tokens }, i) => tokens.type === '' ? num : i;
  240. return (spec) => {
  241. // look for the name in the line where {type} ends
  242. const { tokens } = spec.source[spec.source.reduce(typeEnd, 0)];
  243. const source = tokens.description.trimLeft();
  244. const quotedGroups = source.split('"');
  245. // if it starts with quoted group, assume it is a literal
  246. if (quotedGroups.length > 1 &&
  247. quotedGroups[0] === '' &&
  248. quotedGroups.length % 2 === 1) {
  249. spec.name = quotedGroups[1];
  250. tokens.name = `"${quotedGroups[1]}"`;
  251. [tokens.postName, tokens.description] = splitSpace(source.slice(tokens.name.length));
  252. return spec;
  253. }
  254. let brackets = 0;
  255. let name = '';
  256. let optional = false;
  257. let defaultValue;
  258. // assume name is non-space string or anything wrapped into brackets
  259. for (const ch of source) {
  260. if (brackets === 0 && isSpace(ch))
  261. break;
  262. if (ch === '[')
  263. brackets++;
  264. if (ch === ']')
  265. brackets--;
  266. name += ch;
  267. }
  268. if (brackets !== 0) {
  269. spec.problems.push({
  270. code: 'spec:name:unpaired-brackets',
  271. message: 'unpaired brackets',
  272. line: spec.source[0].number,
  273. critical: true,
  274. });
  275. return spec;
  276. }
  277. const nameToken = name;
  278. if (name[0] === '[' && name[name.length - 1] === ']') {
  279. optional = true;
  280. name = name.slice(1, -1);
  281. const parts = name.split('=');
  282. name = parts[0].trim();
  283. if (parts[1] !== undefined)
  284. defaultValue = parts.slice(1).join('=').trim();
  285. if (name === '') {
  286. spec.problems.push({
  287. code: 'spec:name:empty-name',
  288. message: 'empty name',
  289. line: spec.source[0].number,
  290. critical: true,
  291. });
  292. return spec;
  293. }
  294. if (defaultValue === '') {
  295. spec.problems.push({
  296. code: 'spec:name:empty-default',
  297. message: 'empty default value',
  298. line: spec.source[0].number,
  299. critical: true,
  300. });
  301. return spec;
  302. }
  303. // has "=" and is not a string, except for "=>"
  304. if (!isQuoted(defaultValue) && /=(?!>)/.test(defaultValue)) {
  305. spec.problems.push({
  306. code: 'spec:name:invalid-default',
  307. message: 'invalid default value syntax',
  308. line: spec.source[0].number,
  309. critical: true,
  310. });
  311. return spec;
  312. }
  313. }
  314. spec.optional = optional;
  315. spec.name = name;
  316. tokens.name = nameToken;
  317. if (defaultValue !== undefined)
  318. spec.default = defaultValue;
  319. [tokens.postName, tokens.description] = splitSpace(source.slice(tokens.name.length));
  320. return spec;
  321. };
  322. }
  323. /**
  324. * Makes no changes to `spec.lines[].tokens` but joins them into `spec.description`
  325. * following given spacing srtategy
  326. * @param {Spacing} spacing tells how to handle the whitespace
  327. * @param {BlockMarkers} markers tells how to handle comment block delimitation
  328. */
  329. function descriptionTokenizer(spacing = 'compact', markers = exports.Markers) {
  330. const join = getJoiner(spacing);
  331. return (spec) => {
  332. spec.description = join(spec.source, markers);
  333. return spec;
  334. };
  335. }
  336. function getJoiner(spacing) {
  337. if (spacing === 'compact')
  338. return compactJoiner;
  339. if (spacing === 'preserve')
  340. return preserveJoiner;
  341. return spacing;
  342. }
  343. function compactJoiner(lines, markers = exports.Markers) {
  344. return lines
  345. .map(({ tokens: { description } }) => description.trim())
  346. .filter((description) => description !== '')
  347. .join(' ');
  348. }
  349. const lineNo = (num, { tokens }, i) => tokens.type === '' ? num : i;
  350. const getDescription = ({ tokens }) => (tokens.delimiter === '' ? tokens.start : tokens.postDelimiter.slice(1)) +
  351. tokens.description;
  352. function preserveJoiner(lines, markers = exports.Markers) {
  353. if (lines.length === 0)
  354. return '';
  355. // skip the opening line with no description
  356. if (lines[0].tokens.description === '' &&
  357. lines[0].tokens.delimiter === markers.start)
  358. lines = lines.slice(1);
  359. // skip the closing line with no description
  360. const lastLine = lines[lines.length - 1];
  361. if (lastLine !== undefined &&
  362. lastLine.tokens.description === '' &&
  363. lastLine.tokens.end.endsWith(markers.end))
  364. lines = lines.slice(0, -1);
  365. // description starts at the last line of type definition
  366. lines = lines.slice(lines.reduce(lineNo, 0));
  367. return lines.map(getDescription).join('\n');
  368. }
  369. function getParser({ startLine = 0, fence = '```', spacing = 'compact', markers = exports.Markers, tokenizers = [
  370. tagTokenizer(),
  371. typeTokenizer(spacing),
  372. nameTokenizer(),
  373. descriptionTokenizer(spacing),
  374. ], } = {}) {
  375. if (startLine < 0 || startLine % 1 > 0)
  376. throw new Error('Invalid startLine');
  377. const parseSource = getParser$2({ startLine, markers });
  378. const parseBlock = getParser$3({ fence });
  379. const parseSpec = getParser$1({ tokenizers });
  380. const joinDescription = getJoiner(spacing);
  381. return function (source) {
  382. const blocks = [];
  383. for (const line of splitLines(source)) {
  384. const lines = parseSource(line);
  385. if (lines === null)
  386. continue;
  387. const sections = parseBlock(lines);
  388. const specs = sections.slice(1).map(parseSpec);
  389. blocks.push({
  390. description: joinDescription(sections[0], markers),
  391. tags: specs,
  392. source: lines,
  393. problems: specs.reduce((acc, spec) => acc.concat(spec.problems), []),
  394. });
  395. }
  396. return blocks;
  397. };
  398. }
  399. function join(tokens) {
  400. return (tokens.start +
  401. tokens.delimiter +
  402. tokens.postDelimiter +
  403. tokens.tag +
  404. tokens.postTag +
  405. tokens.type +
  406. tokens.postType +
  407. tokens.name +
  408. tokens.postName +
  409. tokens.description +
  410. tokens.end +
  411. tokens.lineEnd);
  412. }
  413. function getStringifier() {
  414. return (block) => block.source.map(({ tokens }) => join(tokens)).join('\n');
  415. }
  416. var __rest$2 = (window && window.__rest) || function (s, e) {
  417. var t = {};
  418. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  419. t[p] = s[p];
  420. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  421. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  422. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  423. t[p[i]] = s[p[i]];
  424. }
  425. return t;
  426. };
  427. const zeroWidth$1 = {
  428. start: 0,
  429. tag: 0,
  430. type: 0,
  431. name: 0,
  432. };
  433. const getWidth = (markers = exports.Markers) => (w, { tokens: t }) => ({
  434. start: t.delimiter === markers.start ? t.start.length : w.start,
  435. tag: Math.max(w.tag, t.tag.length),
  436. type: Math.max(w.type, t.type.length),
  437. name: Math.max(w.name, t.name.length),
  438. });
  439. const space = (len) => ''.padStart(len, ' ');
  440. function align$1(markers = exports.Markers) {
  441. let intoTags = false;
  442. let w;
  443. function update(line) {
  444. const tokens = Object.assign({}, line.tokens);
  445. if (tokens.tag !== '')
  446. intoTags = true;
  447. const isEmpty = tokens.tag === '' &&
  448. tokens.name === '' &&
  449. tokens.type === '' &&
  450. tokens.description === '';
  451. // dangling '*/'
  452. if (tokens.end === markers.end && isEmpty) {
  453. tokens.start = space(w.start + 1);
  454. return Object.assign(Object.assign({}, line), { tokens });
  455. }
  456. switch (tokens.delimiter) {
  457. case markers.start:
  458. tokens.start = space(w.start);
  459. break;
  460. case markers.delim:
  461. tokens.start = space(w.start + 1);
  462. break;
  463. default:
  464. tokens.delimiter = '';
  465. tokens.start = space(w.start + 2); // compensate delimiter
  466. }
  467. if (!intoTags) {
  468. tokens.postDelimiter = tokens.description === '' ? '' : ' ';
  469. return Object.assign(Object.assign({}, line), { tokens });
  470. }
  471. const nothingAfter = {
  472. delim: false,
  473. tag: false,
  474. type: false,
  475. name: false,
  476. };
  477. if (tokens.description === '') {
  478. nothingAfter.name = true;
  479. tokens.postName = '';
  480. if (tokens.name === '') {
  481. nothingAfter.type = true;
  482. tokens.postType = '';
  483. if (tokens.type === '') {
  484. nothingAfter.tag = true;
  485. tokens.postTag = '';
  486. if (tokens.tag === '') {
  487. nothingAfter.delim = true;
  488. }
  489. }
  490. }
  491. }
  492. tokens.postDelimiter = nothingAfter.delim ? '' : ' ';
  493. if (!nothingAfter.tag)
  494. tokens.postTag = space(w.tag - tokens.tag.length + 1);
  495. if (!nothingAfter.type)
  496. tokens.postType = space(w.type - tokens.type.length + 1);
  497. if (!nothingAfter.name)
  498. tokens.postName = space(w.name - tokens.name.length + 1);
  499. return Object.assign(Object.assign({}, line), { tokens });
  500. }
  501. return (_a) => {
  502. var { source } = _a, fields = __rest$2(_a, ["source"]);
  503. w = source.reduce(getWidth(markers), Object.assign({}, zeroWidth$1));
  504. return rewireSource(Object.assign(Object.assign({}, fields), { source: source.map(update) }));
  505. };
  506. }
  507. var __rest$1 = (window && window.__rest) || function (s, e) {
  508. var t = {};
  509. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  510. t[p] = s[p];
  511. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  512. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  513. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  514. t[p[i]] = s[p[i]];
  515. }
  516. return t;
  517. };
  518. const pull = (offset) => (str) => str.slice(offset);
  519. const push = (offset) => {
  520. const space = ''.padStart(offset, ' ');
  521. return (str) => str + space;
  522. };
  523. function indent(pos) {
  524. let shift;
  525. const pad = (start) => {
  526. if (shift === undefined) {
  527. const offset = pos - start.length;
  528. shift = offset > 0 ? push(offset) : pull(-offset);
  529. }
  530. return shift(start);
  531. };
  532. const update = (line) => (Object.assign(Object.assign({}, line), { tokens: Object.assign(Object.assign({}, line.tokens), { start: pad(line.tokens.start) }) }));
  533. return (_a) => {
  534. var { source } = _a, fields = __rest$1(_a, ["source"]);
  535. return rewireSource(Object.assign(Object.assign({}, fields), { source: source.map(update) }));
  536. };
  537. }
  538. var __rest = (window && window.__rest) || function (s, e) {
  539. var t = {};
  540. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  541. t[p] = s[p];
  542. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  543. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  544. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  545. t[p[i]] = s[p[i]];
  546. }
  547. return t;
  548. };
  549. function crlf(ending) {
  550. function update(line) {
  551. return Object.assign(Object.assign({}, line), { tokens: Object.assign(Object.assign({}, line.tokens), { lineEnd: ending === 'LF' ? '' : '\r' }) });
  552. }
  553. return (_a) => {
  554. var { source } = _a, fields = __rest(_a, ["source"]);
  555. return rewireSource(Object.assign(Object.assign({}, fields), { source: source.map(update) }));
  556. };
  557. }
  558. function flow(...transforms) {
  559. return (block) => transforms.reduce((block, t) => t(block), block);
  560. }
  561. const zeroWidth = {
  562. line: 0,
  563. start: 0,
  564. delimiter: 0,
  565. postDelimiter: 0,
  566. tag: 0,
  567. postTag: 0,
  568. name: 0,
  569. postName: 0,
  570. type: 0,
  571. postType: 0,
  572. description: 0,
  573. end: 0,
  574. lineEnd: 0,
  575. };
  576. const headers = { lineEnd: 'CR' };
  577. const fields = Object.keys(zeroWidth);
  578. const repr = (x) => (isSpace(x) ? `{${x.length}}` : x);
  579. const frame = (line) => '|' + line.join('|') + '|';
  580. const align = (width, tokens) => Object.keys(tokens).map((k) => repr(tokens[k]).padEnd(width[k]));
  581. function inspect({ source }) {
  582. var _a, _b;
  583. if (source.length === 0)
  584. return '';
  585. const width = Object.assign({}, zeroWidth);
  586. for (const f of fields)
  587. width[f] = ((_a = headers[f]) !== null && _a !== void 0 ? _a : f).length;
  588. for (const { number, tokens } of source) {
  589. width.line = Math.max(width.line, number.toString().length);
  590. for (const k in tokens)
  591. width[k] = Math.max(width[k], repr(tokens[k]).length);
  592. }
  593. const lines = [[], []];
  594. for (const f of fields)
  595. lines[0].push(((_b = headers[f]) !== null && _b !== void 0 ? _b : f).padEnd(width[f]));
  596. for (const f of fields)
  597. lines[1].push('-'.padEnd(width[f], '-'));
  598. for (const { number, tokens } of source) {
  599. const line = number.toString().padStart(width.line);
  600. lines.push([line, ...align(width, tokens)]);
  601. }
  602. return lines.map(frame).join('\n');
  603. }
  604. function parse(source, options = {}) {
  605. return getParser(options)(source);
  606. }
  607. const stringify = getStringifier();
  608. const transforms = {
  609. flow: flow,
  610. align: align$1,
  611. indent: indent,
  612. crlf: crlf,
  613. };
  614. const tokenizers = {
  615. tag: tagTokenizer,
  616. type: typeTokenizer,
  617. name: nameTokenizer,
  618. description: descriptionTokenizer,
  619. };
  620. const util = { rewireSpecs, rewireSource, seedBlock, seedTokens };
  621. exports.inspect = inspect;
  622. exports.parse = parse;
  623. exports.stringify = stringify;
  624. exports.tokenizers = tokenizers;
  625. exports.transforms = transforms;
  626. exports.util = util;
  627. Object.defineProperty(exports, '__esModule', { value: true });
  628. return exports;
  629. }({}));