UNPKG

ecmarkup

Version:

Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.

229 lines (227 loc) 8.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const utils_1 = require("../../utils"); const ruleId = 'algorithm-line-style'; /* Checks that every algorithm step has one of these forms: - `If foo, bar.` - `If foo, then` + substeps - `If foo, bar, or baz; then` + substeps - `Else if foo, bar.` - `Else if foo, then` + substeps - `Else if foo, bar, or baz; then` + substeps - `Else, baz.` - `Else,` + substeps - `Repeat,` + substeps - `Repeat, while foo,` + substeps - `Repeat, until foo,` + substeps - `For each foo, bar.` - `For each foo, do` + substeps - `NOTE: Something.` - `Assert: Something.` - `Other.` - `Other:` + substeps */ function default_1(report, node, algorithmSource, parsedSteps) { const stepSeq = parsedSteps.get(node); if (stepSeq == null || stepSeq.items.length === 0) { return; } function locate(offset) { return (0, utils_1.offsetToLineAndColumn)(algorithmSource, offset); } let last = stepSeq.items[stepSeq.items.length - 1]; // If the step has a figure, it should end in `:` if (last.name === 'figure') { last = stepSeq.items[stepSeq.items.length - 2]; if (!(last.name === 'text' && /:\n +$/.test(last.contents))) { report({ ruleId, message: 'expected line with figure to end with ":"', ...locate(last.location.end.offset), }); } return; } const hasSubsteps = node.sublist !== null; const first = stepSeq.items[0]; const initialText = first.name === 'text' ? first.contents : ''; const finalText = last.name === 'text' ? last.contents : ''; if (/^(?:If |Else if)/.test(initialText)) { if (hasSubsteps) { if (node.sublist.name === 'ol') { const end = finalText.match(/[,;] then$/); if (!end) { report({ ruleId, message: `expected "If" with substeps to end with ", then"`, ...locate(last.location.end.offset), }); } else if (end[0][0] === ';' && !node.contents.some(c => c.name === 'text' && /,/.test(c.contents))) { report({ ruleId, message: `expected "If" with substeps to end with ", then" rather than "; then" when there are no other commas`, ...locate(last.location.end.offset - 6), }); } } else { if (!/:$/.test(finalText)) { report({ ruleId, message: `expected "If" with list to end with ":"`, ...locate(last.location.end.offset), }); } } } else { const lineSource = algorithmSource.slice(first.location.start.offset, last.location.end.offset); const ifThenMatch = lineSource.match(/^If[^,\n]+, then /); if (ifThenMatch != null) { report({ ruleId, message: `single-line "If" steps should not have a "then"`, ...locate(first.location.start.offset + ifThenMatch[0].length - 5), }); } if (!/(?:\.|\.\)|:)$/.test(finalText)) { report({ ruleId, message: `expected "If" without substeps to end with "." or ":"`, ...locate(last.location.end.offset), }); } } } else if (/^Else/.test(initialText)) { if (/^Else, if/.test(initialText)) { report({ ruleId, message: `prefer "Else if" over "Else, if"`, ...locate(first.location.start.offset + 4), }); } if (hasSubsteps) { if (stepSeq.items.length === 1 && initialText === 'Else,') { return; } if (!/,$/.test(finalText)) { report({ ruleId, message: `expected "Else" with substeps to end with ","`, ...locate(last.location.end.offset), }); } } else { if (!/(?:\.|\.\)|:)$/.test(finalText)) { report({ ruleId, message: `expected "Else" without substeps to end with "." or ":"`, ...locate(last.location.end.offset), }); } } } else if (/^Repeat\b/.test(initialText)) { if (!hasSubsteps) { report({ ruleId, line: node.contents[0].location.start.line, column: node.contents[0].location.start.column, message: 'expected "Repeat" to have substeps', }); } if (stepSeq.items.length === 1 && initialText === 'Repeat,') { return; } if (/ times:$/.test(finalText)) { return; } if (!/^Repeat, (?:while|until) /.test(initialText)) { report({ ruleId, message: `expected "Repeat" to look like "Repeat _n_ times:", "Repeat, while ..." or "Repeat, until ..."`, ...locate(first.location.start.offset), }); } if (!/,$/.test(finalText)) { report({ ruleId, message: 'expected "Repeat" to end with ","', ...locate(last.location.end.offset), }); } } else if (/^For each/.test(initialText)) { if (hasSubsteps) { if (!/, do$/.test(finalText)) { report({ ruleId, message: `expected "For each" with substeps to end with ", do"`, ...locate(last.location.end.offset), }); } } else { if (!/(?:\.|\.\))$/.test(finalText)) { report({ ruleId, message: `expected "For each" without substeps to end with "."`, ...locate(last.location.end.offset), }); } } } else { // these are not else-ifs because we still want to enforce the line-ending rules if (/^(NOTE|Assert): [a-z]/.test(initialText)) { const kind = initialText.match(/^(NOTE|Assert)/)[1]; report({ ruleId, message: `the clause after "${kind}:" should begin with a capital letter`, ...locate(first.location.start.offset + kind.length + 2), }); } if (/^NOTE:/i.test(initialText) && !/^NOTE:/.test(initialText)) { report({ ruleId, message: `"NOTE:" should be fully capitalized`, ...locate(first.location.start.offset), }); } if (/^Assert:/i.test(initialText) && !/^Assert:/.test(initialText)) { report({ ruleId, message: `"Assert:" should be capitalized`, ...locate(first.location.start.offset), }); } if (hasSubsteps) { if (!/:$/.test(finalText)) { report({ ruleId, message: `expected freeform line with substeps to end with ":"`, ...locate(last.location.end.offset), }); } } else if (!/(?:\.|\.\))$/.test(finalText)) { if (last.name === 'paren' && last.items.length > 0) { const lastItem = last.items[last.items.length - 1]; if (lastItem.name === 'text') { return; } } report({ ruleId, message: `expected freeform line to end with "."`, ...locate(last.location.end.offset), }); } } }