@npmstuff/argdown-core
Version:
A pluggable parser for the Argdown argumentation syntax
1,007 lines • 54.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModelPlugin = exports.InterpretationModes = void 0;
const chevrotain_1 = require("chevrotain");
const argdownLexer = __importStar(require("./../lexer"));
const ArgdownPluginError_1 = require("../ArgdownPluginError");
const lodash_defaultsdeep_1 = __importDefault(require("lodash.defaultsdeep"));
const lodash_last_1 = __importDefault(require("lodash.last"));
const lodash_union_1 = __importDefault(require("lodash.union"));
const lodash_merge_1 = __importDefault(require("lodash.merge"));
const model_1 = require("../model/model");
const RuleNames_1 = require("../RuleNames");
const TokenNames_1 = require("../TokenNames");
const utils_1 = require("../utils");
const utils_2 = require("../utils");
const shortcodes_1 = require("./shortcodes");
var InterpretationModes;
(function (InterpretationModes) {
InterpretationModes["LOOSE"] = "loose";
InterpretationModes["STRICT"] = "strict";
})(InterpretationModes = exports.InterpretationModes || (exports.InterpretationModes = {}));
const defaultSettings = {
mode: InterpretationModes.LOOSE,
removeTagsFromText: false,
transformArgumentRelations: true,
shortcodes: utils_1.ensure.object(shortcodes_1.shortcodes)
};
class ModelPlugin {
constructor(config) {
this.name = "ModelPlugin";
this.defaults = {};
this.getSettings = (request) => {
if (!(0, utils_1.isObject)(request.model)) {
request.model = {};
}
return request.model;
};
this.prepare = request => {
(0, utils_1.mergeDefaults)(this.getSettings(request), this.defaults);
};
this.transformArgumentRelations = (response) => {
const newRelations = [];
for (let relation of response.relations) {
let addRelation = true;
if (!relation.from) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-relation-source", "Relation without source.");
}
if (!relation.to) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-relation-target", "Relation without target.");
}
const fromIsReconstructedArgument = relation.from.type === model_1.ArgdownTypes.ARGUMENT &&
(0, model_1.isReconstructed)(relation.from);
const toIsReconstructedArgument = relation.to.type === model_1.ArgdownTypes.ARGUMENT &&
(0, model_1.isReconstructed)(relation.to);
if (fromIsReconstructedArgument) {
let argument = relation.from;
this.removeRelationFromSource(relation);
let conclusionStatement = argument.pcs[argument.pcs.length - 1];
let equivalenceClass = response.statements[conclusionStatement.title];
relation.from = equivalenceClass;
let relationExists = false;
for (let existingRelation of equivalenceClass.relations) {
if (relation.to == existingRelation.to &&
relation.relationType === existingRelation.relationType) {
relationExists = true;
existingRelation.occurrences.push(...relation.occurrences);
break;
}
}
if (!relationExists) {
equivalenceClass.relations.push(relation);
}
else {
this.removeRelationFromTarget(relation);
addRelation = false;
}
}
if (toIsReconstructedArgument &&
relation.relationType === model_1.RelationType.UNDERCUT) {
let argument = relation.to;
let inference = (0, lodash_last_1.default)(argument.pcs).inference;
relation.to = inference;
this.removeRelationFromTarget(relation);
let relationExists = false;
for (let existingRelation of inference.relations) {
if (relation.from == existingRelation.from &&
relation.relationType === existingRelation.relationType) {
relationExists = true;
existingRelation.occurrences.push(...relation.occurrences);
break;
}
}
if (!relationExists) {
inference.relations.push(relation);
}
else {
this.removeRelationFromSource(relation);
addRelation = false;
}
}
if (addRelation) {
newRelations.push(relation);
}
}
response.relations = newRelations;
};
this.transformStatementRelations = (response) => {
const newRelations = [];
for (let relation of response.relations) {
let addRelation = true;
const isS2SRelation = relation.from.type === model_1.ArgdownTypes.EQUIVALENCE_CLASS &&
relation.to.type === model_1.ArgdownTypes.EQUIVALENCE_CLASS;
if (isS2SRelation) {
if (relation.relationType === model_1.RelationType.SUPPORT) {
relation.relationType = model_1.RelationType.ENTAILS;
}
else if (relation.relationType === model_1.RelationType.ATTACK) {
const relationExists = relation.from.relations.find(r => {
return (r.relationType === model_1.RelationType.CONTRARY &&
((r.from === relation.from && r.to === relation.to) ||
(r.from === relation.to && r.to === relation.from)));
});
if (relationExists !== undefined) {
this.removeRelationFromSource(relation);
this.removeRelationFromTarget(relation);
addRelation = false;
}
else {
relation.relationType = model_1.RelationType.CONTRARY;
}
}
}
if (addRelation) {
newRelations.push(relation);
}
}
response.relations = newRelations;
};
this.removeRelationFromSource = (relation) => {
let indexSource = relation.from.relations.indexOf(relation);
relation.from.relations.splice(indexSource, 1);
};
this.removeRelationFromTarget = (relation) => {
let indexTarget = relation.to.relations.indexOf(relation);
relation.to.relations.splice(indexTarget, 1);
};
this.removeRedundantEC2ARelations = (response) => {
const newRelations = [];
for (let relation of response.relations) {
if (relation.from.type !== model_1.ArgdownTypes.EQUIVALENCE_CLASS ||
relation.relationType !== model_1.RelationType.ATTACK ||
relation.to.type !== model_1.ArgdownTypes.ARGUMENT) {
newRelations.push(relation);
continue;
}
const argument = relation.to;
if (!argument.pcs) {
newRelations.push(relation);
continue;
}
const ec = relation.from;
const ec2ecRelation = ec.relations.find(otherRelation => (0, utils_2.other)(otherRelation, ec).type === model_1.ArgdownTypes.EQUIVALENCE_CLASS &&
((otherRelation.relationType === model_1.RelationType.ATTACK &&
otherRelation.from === ec) ||
otherRelation.relationType === model_1.RelationType.CONTRADICTORY ||
otherRelation.relationType === model_1.RelationType.CONTRARY) &&
!!argument.pcs.find(s => s.title === (0, utils_2.other)(otherRelation, ec).title &&
s.role === model_1.StatementRole.PREMISE));
if (ec2ecRelation) {
this.removeRelationFromSource(relation);
this.removeRelationFromTarget(relation);
ec2ecRelation.occurrences.push(...relation.occurrences);
continue;
}
else {
newRelations.push(relation);
continue;
}
}
response.relations = newRelations;
};
this.assignSectionOfFirstMemberIfWithoutSection = (node) => {
if (!node.section && node.members && node.members.length > 0) {
node.section = node.members[0].section;
}
};
this.run = (request, response) => {
(0, ArgdownPluginError_1.checkResponseFields)(this, response, [
"ast",
"statements",
"arguments",
"relations"
]);
for (let ec of Object.values(response.statements)) {
this.assignSectionOfFirstMemberIfWithoutSection(ec);
}
for (let argument of Object.values(response.arguments)) {
this.assignSectionOfFirstMemberIfWithoutSection(argument);
}
const settings = this.getSettings(request);
if (settings.transformArgumentRelations) {
this.transformArgumentRelations(response);
}
if (settings.mode === InterpretationModes.STRICT) {
this.transformStatementRelations(response);
}
this.removeRedundantEC2ARelations(response);
return response;
};
this.defaults = (0, lodash_defaultsdeep_1.default)({}, config, defaultSettings);
this.name = "ModelPlugin";
let $ = this;
const statementReferencePattern = /\[(.+)\]/;
const statementDefinitionPattern = /\[(.+)\]\:/;
const statementMentionPattern = /\@\[(.+)\](\s?)/;
const argumentReferencePattern = /\<(.+)\>/;
const argumentDefinitionPattern = /\<(.+)\>\:/;
const argumentMentionPattern = /\@\<(.+)\>(\s?)/;
const linkPattern = /\[(.+)\]\((.+)\)/;
const tagPattern = /#(?:\(([^\)]+)\)|([a-zA-z0-9-\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+))/;
let uniqueTitleCounter = 0;
function getUniqueTitle() {
uniqueTitleCounter++;
return "Untitled " + uniqueTitleCounter;
}
let currentStatement = null;
let currentRelationParent = null;
let currentArgument = null;
let currentPCS = null;
let currentInference = null;
let rangesStack = [];
let relationParentsStack = [];
let currentRelation = null;
let currentHeading = null;
let currentSection = null;
let sectionCounter = 0;
let tagCounter = 0;
const getRelationMember = (response, relationParent) => {
let target = relationParent;
if (relationParent.type === model_1.ArgdownTypes.STATEMENT) {
if (!relationParent.title)
relationParent.title = getUniqueTitle();
if (relationParent.role === model_1.StatementRole.ARGUMENT_DESCRIPTION) {
return getArgument(response.arguments, relationParent.title);
}
else {
return getEquivalenceClass(response.statements, relationParent.title);
}
}
else {
return target;
}
};
const getArgument = (argumentsDict, title) => {
if (title) {
currentArgument = argumentsDict[title];
}
if (!title || !currentArgument) {
currentArgument = {
type: model_1.ArgdownTypes.ARGUMENT,
relations: [],
members: [],
pcs: []
};
if (!title) {
currentArgument.title = getUniqueTitle();
}
else {
currentArgument.title = title;
}
argumentsDict[currentArgument.title] = currentArgument;
}
currentRelationParent = currentArgument;
return currentArgument;
};
const addTags = (newTags, object) => {
if (!object.tags) {
object.tags = [];
}
object.tags = (0, lodash_union_1.default)(object.tags, newTags);
};
const onRelationExit = (_request, response, node) => {
let relation = node.relation;
if (!node.children || node.children.length < 2) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-ast-node-children", "Relation without children.");
}
let contentNode = node.children[1];
let content = contentNode.argument || contentNode.statement;
if (!content) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-ast-node-relation-member", "Relation member not found.");
}
let target = getRelationMember(response, content);
if (relation) {
if (relation.from) {
relation.to = target;
}
else {
relation.from = target;
}
let relationExists = false;
const relationSource = relation.from;
for (let existingRelation of relationSource.relations) {
if (relation.to === existingRelation.to &&
relation.relationType === existingRelation.relationType) {
relationExists = true;
existingRelation.occurrences.push(...relation.occurrences);
break;
}
else if (relation.relationType === model_1.RelationType.CONTRADICTORY &&
relation.relationType === existingRelation.relationType &&
relation.from === existingRelation.to &&
relation.to === existingRelation.from) {
relationExists = true;
existingRelation.occurrences.push(...relation.occurrences);
break;
}
}
if (!relationExists) {
if (!relation.from || !relation.to) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-relation-member", "Missing relation source or target.");
}
response.relations.push(relation);
relation.from.relations.push(relation);
relation.to.relations.push(relation);
}
}
};
this.tokenListeners = {
[TokenNames_1.TokenNames.STATEMENT_DEFINITION]: (_request, _response, token, parentNode) => {
let match = statementDefinitionPattern.exec(token.image);
if (match != null && currentStatement) {
currentStatement.title = match[1];
token.title = currentStatement.title;
parentNode.statement = currentStatement;
}
},
[TokenNames_1.TokenNames.STATEMENT_REFERENCE]: (_request, _response, token, parentNode) => {
let match = statementReferencePattern.exec(token.image);
if (match != null && currentStatement) {
currentStatement.title = match[1];
currentStatement.isReference = true;
token.title = currentStatement.title;
parentNode.statement = currentStatement;
}
},
[TokenNames_1.TokenNames.STATEMENT_MENTION]: (_request, _response, token) => {
let match = statementMentionPattern.exec(token.image);
if (match) {
token.title = match[1];
if (token.image[token.image.length - 1] == " ") {
token.trailingWhitespace = " ";
}
else {
token.trailingWhitespace = "";
}
const target = currentHeading || currentStatement;
if (target) {
const previousText = target.text || "";
const newText = previousText + token.image;
target.text = newText;
if (!target.ranges) {
target.ranges = [];
}
let range = {
type: model_1.RangeType.STATEMENT_MENTION,
title: token.title,
start: previousText.length,
stop: newText.length - 1
};
target.ranges.push(range);
}
}
},
[TokenNames_1.TokenNames.ARGUMENT_REFERENCE]: (_request, _response, token) => {
let match = argumentReferencePattern.exec(token.image);
if (match != null && currentStatement) {
let title = match[1];
currentStatement.title = title;
currentStatement.isReference = true;
token.title = title;
}
},
[TokenNames_1.TokenNames.ARGUMENT_DEFINITION]: (_request, _response, token) => {
let match = argumentDefinitionPattern.exec(token.image);
if (match != null && currentStatement) {
let title = match[1];
currentStatement.title = title;
token.title = title;
}
},
[TokenNames_1.TokenNames.ARGUMENT_MENTION]: (_request, _response, token) => {
const target = currentHeading ? currentHeading : currentStatement;
let match = argumentMentionPattern.exec(token.image);
if (match) {
token.title = match[1];
if (token.image[token.image.length - 1] == " ") {
token.trailingWhitespace = " ";
}
else {
token.trailingWhitespace = "";
}
if (target) {
const previousText = target.text || "";
const newText = previousText + token.image;
target.text = newText;
if (!target.ranges) {
target.ranges = [];
}
let range = {
type: model_1.RangeType.ARGUMENT_MENTION,
title: token.title,
start: previousText.length,
stop: newText.length - 1
};
target.ranges.push(range);
}
}
},
[TokenNames_1.TokenNames.LINK]: (_request, _response, token) => {
const target = currentHeading ? currentHeading : currentStatement;
if (!target) {
return;
}
let match = linkPattern.exec(token.image);
if (!match || match.length < 3) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "invalid-link", "Could not match link.");
}
token.url = match[2];
token.text = match[1];
const oldText = target.text || "";
const newText = oldText + token.text;
target.text = newText;
let linkRange = {
type: "link",
start: oldText.length,
stop: newText.length - 1
};
linkRange.url = token.url;
if (token.image[token.image.length - 1] == " ") {
target.text += " ";
token.trailingWhitespace = " ";
}
else {
token.trailingWhitespace = "";
}
if (!target.ranges) {
target.ranges = [];
}
target.ranges.push(linkRange);
},
[TokenNames_1.TokenNames.TAG]: (request, response, token) => {
const target = currentHeading || currentStatement;
if (!target) {
return;
}
let match = tagPattern.exec(token.image);
if (!match || match.length < 2) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "invalid-tag", "Could not parse tag.");
}
let tag = match[1] || match[2];
const settings = $.getSettings(request);
token.tag = tag;
if (!settings.removeTagsFromText) {
const oldText = target.text || "";
const newText = oldText + token.image;
let tagRange = {
type: model_1.RangeType.TAG,
start: oldText.length,
stop: newText.length - 1
};
token.text = token.image;
target.text = newText;
tagRange.tag = token.tag;
if (!target.ranges) {
target.ranges = [];
}
target.ranges.push(tagRange);
}
target.tags = target.tags || [];
let tags = target.tags;
if (target.tags.indexOf(tag) === -1) {
tags.push(tag);
}
let tagData = response.tags[tag];
if (!tagData) {
tagData = {
tag: tag,
cssClass: (0, utils_1.stringToClassName)("tag-" + tag),
occurrenceIndex: tagCounter
};
response.tags[tag] = tagData;
tagCounter++;
}
},
[TokenNames_1.TokenNames.NEWLINE]: (_request, _response, _token, parentNode, childIndex) => {
const target = currentHeading ? currentHeading : currentStatement;
if (!target) {
return;
}
const oldText = target.text || "";
if (childIndex !== parentNode.children.length - 1 &&
oldText.charAt(oldText.length - 1) !== " ") {
target.text = oldText + " ";
}
}
};
this.ruleListeners = {
[RuleNames_1.RuleNames.ARGDOWN + "Entry"]: (_request, response) => {
response.statements = {};
response.arguments = {};
response.sections = [];
response.relations = [];
response.tags = {};
uniqueTitleCounter = 0;
currentHeading = null;
currentSection = null;
currentRelationParent = null;
currentPCS = null;
currentInference = null;
currentArgument = null;
rangesStack = [];
relationParentsStack = [];
currentRelation = null;
sectionCounter = 0;
tagCounter = 0;
},
[RuleNames_1.RuleNames.ARGDOWN + "Exit"]: (_req, _resp, token) => {
const lastChild = token.children && token.children.length > 0
? token.children[token.children.length - 1]
: null;
while (currentSection && lastChild && lastChild.endLine) {
currentSection.endLine = lastChild.endLine;
currentSection.endOffset = lastChild.endOffset;
currentSection.endColumn = lastChild.endColumn;
currentSection = currentSection.parent || null;
}
},
[RuleNames_1.RuleNames.HEADING + "Entry"]: (_request, _response, node) => {
currentHeading = node;
currentHeading.text = "";
currentHeading.ranges = [];
},
[RuleNames_1.RuleNames.HEADING + "Exit"]: (request, response, node) => {
if (!currentHeading) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-heading", "Missing heading.");
}
if (node.children) {
let headingStart = node.children[0];
currentHeading.level = headingStart.image.length - 1;
sectionCounter++;
let sectionId = "s" + sectionCounter;
const title = currentHeading.text ? currentHeading.text.trim() : "";
let newSection = {
type: model_1.ArgdownTypes.SECTION,
id: sectionId,
level: currentHeading.level,
title: title,
children: []
};
if (!response.maxSectionLevel ||
currentHeading.level > response.maxSectionLevel) {
response.maxSectionLevel = currentHeading.level;
}
newSection.tags = currentHeading.tags;
newSection.ranges = currentHeading.ranges;
newSection.startLine = node.startLine;
newSection.startColumn = node.startColumn;
newSection.heading = currentHeading;
newSection.data = currentHeading.data;
const groupSettings = request.group;
if (newSection.data) {
if (newSection.data.isGroup !== undefined &&
(!groupSettings || !groupSettings.ignoreIsGroup)) {
newSection.isGroup = newSection.data.isGroup;
}
if (newSection.data.isClosed !== undefined &&
(!groupSettings || !groupSettings.ignoreIsClosed)) {
newSection.isClosed = newSection.data.isClosed;
}
}
if (groupSettings && (0, utils_1.isObject)(groupSettings.sections)) {
const groupConfig = groupSettings.sections[newSection.title];
if (groupConfig) {
newSection.isGroup = groupConfig.isGroup;
newSection.isClosed = groupConfig.isClosed;
}
else {
newSection.isGroup =
newSection.isGroup === undefined ? false : newSection.isGroup;
}
}
if (!currentSection) {
response.sections.push(newSection);
}
else {
let previous = currentSection;
while (previous && previous.level >= newSection.level) {
previous.endOffset = newSection.startOffset - 1;
previous.endLine = newSection.startLine - 1;
previous.endColumn = 0;
previous = previous.parent || null;
}
if (previous && previous.level < newSection.level) {
previous.children.push(newSection);
newSection.parent = previous;
}
else {
response.sections.push(newSection);
}
}
currentSection = newSection;
currentHeading.section = newSection;
currentHeading = null;
}
},
[RuleNames_1.RuleNames.STATEMENT + "Entry"]: (_request, _response, node, parentNode) => {
currentStatement = {
type: model_1.ArgdownTypes.STATEMENT
};
if (parentNode.name === "argdown") {
currentStatement.role = model_1.StatementRole.TOP_LEVEL_STATEMENT;
currentStatement.isTopLevel = true;
}
else if (currentRelation) {
currentStatement.role = model_1.StatementRole.RELATION_STATEMENT;
}
currentRelationParent = currentStatement;
node.statement = currentStatement;
},
[RuleNames_1.RuleNames.STATEMENT + "Exit"]: (_request, response, node) => {
let statement = node.statement;
if (!statement) {
return;
}
statement.startLine = node.startLine;
statement.startColumn = node.startColumn;
statement.endLine = node.endLine;
statement.endColumn = node.endColumn;
statement.data = node.data;
if (!statement.title || statement.title == "") {
statement.title = getUniqueTitle();
}
let equivalenceClass = getEquivalenceClass(response.statements, statement.title);
node.equivalenceClass = equivalenceClass;
if (statement.tags) {
addTags(statement.tags, equivalenceClass);
}
if (statement.data) {
equivalenceClass.data = (0, lodash_merge_1.default)(equivalenceClass.data, statement.data);
}
if (currentSection) {
statement.section = currentSection;
}
equivalenceClass.members.push(statement);
const isInGroup = statement.data && statement.data.isInGroup !== undefined
? statement.data.isInGroup
: undefined;
const ecTakesSection = isInGroup === true ||
(!statement.isReference &&
isInGroup === undefined &&
equivalenceClass.section === undefined);
if (ecTakesSection) {
equivalenceClass.section = statement.section;
}
if (statement.role === model_1.StatementRole.TOP_LEVEL_STATEMENT) {
equivalenceClass.isUsedAsTopLevelStatement = true;
}
else if (statement.role === model_1.StatementRole.RELATION_STATEMENT) {
equivalenceClass.isUsedAsRelationStatement = true;
}
currentStatement = null;
},
[RuleNames_1.RuleNames.ARGUMENT + "Entry"]: (_request, _response, node, parentNode) => {
const desc = {
type: model_1.ArgdownTypes.STATEMENT,
role: model_1.StatementRole.ARGUMENT_DESCRIPTION,
text: ""
};
currentStatement = desc;
desc.startLine = node.startLine;
desc.endLine = node.endLine;
desc.startColumn = node.startColumn;
desc.endColumn = node.endColumn;
desc.isTopLevel = !parentNode || parentNode.name === RuleNames_1.RuleNames.ARGDOWN;
if (currentSection) {
currentStatement.section = currentSection;
}
currentRelationParent = currentStatement;
node.statement = desc;
},
[RuleNames_1.RuleNames.ARGUMENT + "Exit"]: (_request, response, node) => {
let desc = node.statement;
if (!desc) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-argument-description", "Missing argument description.");
}
desc.startLine = node.startLine;
desc.startColumn = node.startColumn;
desc.endLine = node.endLine;
desc.endColumn = node.endColumn;
desc.data = node.data;
if (!desc.title || desc.title == "") {
desc.title = getUniqueTitle();
}
const argument = getArgument(response.arguments, desc.title);
node.argument = argument;
if (desc.tags) {
addTags(desc.tags, argument);
}
if (desc.data) {
argument.data = (0, lodash_merge_1.default)(argument.data, desc.data);
}
if (currentSection) {
desc.section = currentSection;
}
argument.members.push(desc);
const isInGroup = desc.data && desc.data.isInGroup !== undefined
? desc.data.isInGroup
: undefined;
const argumentTakesSection = isInGroup === true ||
(!desc.isReference &&
isInGroup === undefined &&
argument.section === undefined);
if (argumentTakesSection) {
argument.section = desc.section;
}
response.arguments[argument.title] = argument;
currentStatement = null;
currentArgument = null;
},
[RuleNames_1.RuleNames.PCS + "Entry"]: (_request, response, node, parentNode, childIndex) => {
let argument = null;
let argumentDescription;
if (childIndex !== null &&
childIndex > 0 &&
parentNode &&
parentNode.children) {
let precedingSibling = parentNode.children[childIndex - 1];
if ((0, model_1.isRuleNode)(precedingSibling) &&
precedingSibling.name === RuleNames_1.RuleNames.ARGUMENT) {
argumentDescription = precedingSibling.statement;
argument = precedingSibling.argument;
}
else if ((0, model_1.isTokenNode)(precedingSibling) &&
(0, chevrotain_1.tokenMatcher)(precedingSibling, argdownLexer.Emptyline)) {
precedingSibling = parentNode.children[childIndex - 2];
if ((0, model_1.isRuleNode)(precedingSibling) &&
precedingSibling.name === RuleNames_1.RuleNames.ARGUMENT) {
argumentDescription = precedingSibling.statement;
argument = precedingSibling.argument;
}
}
}
if (!argument) {
argument = getArgument(response.arguments);
}
if (currentSection) {
argument.section = currentSection;
}
if (argument.pcs.length > 0) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "multiple-pcs-assignments", `Multiple premise-conclusion-structures assigned to argument <${argument.title}>. You can only assign one pcs per argument.`);
}
argument.pcs = [];
if (argumentDescription) {
argumentDescription.pcs = argument.pcs;
}
node.argument = argument;
currentPCS = argument;
},
[RuleNames_1.RuleNames.PCS + "Exit"]: (_request, response, node) => {
const argument = node.argument;
if (!argument) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-argument", "Missing argument.");
}
if (argument.pcs.length == 0) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-argument-statements", "Missing argument statements.");
}
const lastStatement = argument.pcs[argument.pcs.length - 1];
if (lastStatement.role === model_1.StatementRole.INTERMEDIARY_CONCLUSION) {
lastStatement.role = model_1.StatementRole.MAIN_CONCLUSION;
const ec = response.statements[lastStatement.title];
ec.isUsedAsMainConclusion = true;
if (!ec.members.find(s => s.role === model_1.StatementRole.INTERMEDIARY_CONCLUSION)) {
ec.isUsedAsIntermediaryConclusion = false;
}
}
else {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-main-conclusion", "Missing main conclusions.");
}
argument.startLine = node.startLine;
argument.startColumn = node.startColumn;
argument.endLine = node.endLine;
argument.endColumn = node.endColumn;
currentStatement = null;
currentArgument = null;
currentPCS = null;
},
[RuleNames_1.RuleNames.PCS_STATEMENT + "Exit"]: (_request, response, node, parentNode, childIndex) => {
if (!currentPCS) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-argument-reconstruction", "Missing argument reconstruction.");
}
if (node.children && node.children.length > 1) {
let statementNode = node.children[1];
let statement = statementNode.statement;
if (!statement) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-statement", "Missing statement.");
}
let ec = getEquivalenceClass(response.statements, statement.title);
statement.role = model_1.StatementRole.PREMISE;
statement.argumentTitle = currentPCS.title;
if (childIndex !== null &&
childIndex > 0 &&
parentNode &&
parentNode.children) {
let precedingSibling = parentNode.children[childIndex - 1];
if (precedingSibling.name === RuleNames_1.RuleNames.INFERENCE) {
statement.role = model_1.StatementRole.INTERMEDIARY_CONCLUSION;
const conclusion = statement;
ec.isUsedAsIntermediaryConclusion = true;
conclusion.inference = precedingSibling.inference;
conclusion.inference.conclusionIndex = currentPCS.pcs.length;
conclusion.inference.argumentTitle = currentPCS.title;
}
}
if (statement.role == model_1.StatementRole.PREMISE) {
ec.isUsedAsPremise = true;
}
currentPCS.pcs.push(statement);
node.statement = statement;
node.statementNr = currentPCS.pcs.length;
}
},
[RuleNames_1.RuleNames.INFERENCE + "Entry"]: (_request, _response, node) => {
currentInference = {
type: model_1.ArgdownTypes.INFERENCE,
relations: []
};
currentInference.relations = [];
currentInference.inferenceRules = [];
currentInference.startLine = node.startLine;
currentInference.startColumn = node.startColumn;
currentInference.endLine = node.endLine;
currentInference.endColumn = node.endColumn;
node.inference = currentInference;
currentRelationParent = currentInference;
relationParentsStack.push(currentInference);
},
[RuleNames_1.RuleNames.INFERENCE + "Exit"]: (_request, _response, node) => {
if (!currentInference) {
return;
}
currentInference.data = node.data;
},
[RuleNames_1.RuleNames.INFERENCE_RULES + "Exit"]: (_request, _response, node) => {
if (!currentInference) {
return;
}
if (node.children) {
for (let child of node.children) {
if ((0, model_1.isRuleNode)(child) && child.name == RuleNames_1.RuleNames.FREESTYLE_TEXT) {
if (!currentInference.inferenceRules) {
currentInference.inferenceRules = [];
}
const text = child.text ? child.text.trim() : "";
currentInference.inferenceRules.push(text);
}
}
}
},
[RuleNames_1.RuleNames.INCOMING_SUPPORT + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.SUPPORT,
occurrences: [node]
};
currentRelation.from = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.INCOMING_SUPPORT + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.INCOMING_ATTACK + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.ATTACK,
occurrences: [node]
};
currentRelation.from = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.INCOMING_ATTACK + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.OUTGOING_SUPPORT + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.SUPPORT,
occurrences: [node]
};
currentRelation.to = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.OUTGOING_SUPPORT + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.OUTGOING_ATTACK + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.ATTACK,
occurrences: [node]
};
currentRelation.to = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.OUTGOING_ATTACK + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.CONTRADICTION + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.CONTRADICTORY,
occurrences: [node]
};
currentRelation.from = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.CONTRADICTION + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.OUTGOING_UNDERCUT + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.UNDERCUT,
occurrences: [node]
};
if (target && target.type === model_1.ArgdownTypes.EQUIVALENCE_CLASS) {
if (currentInference) {
currentRelation.to = currentInference;
}
else {
currentRelation.to = target;
}
}
else {
currentRelation.to = target;
}
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.OUTGOING_UNDERCUT + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.INCOMING_UNDERCUT + "Entry"]: (_request, _response, node) => {
const target = (0, lodash_last_1.default)(relationParentsStack);
currentRelation = {
type: model_1.ArgdownTypes.RELATION,
relationType: model_1.RelationType.UNDERCUT,
occurrences: [node]
};
currentRelation.from = target;
node.relation = currentRelation;
},
[RuleNames_1.RuleNames.INCOMING_UNDERCUT + "Exit"]: onRelationExit,
[RuleNames_1.RuleNames.RELATIONS + "Entry"]: (_request, response) => {
if (!currentRelationParent) {
throw new ArgdownPluginError_1.ArgdownPluginError(this.name, "missing-ast-node-relation-parent", "Parent of relation missing.");
}
relationParentsStack.push(getRelationMember(response, currentRelationParent));
},
[RuleNames_1.RuleNames.RELATIONS + "Exit"]: () => {
currentRelation = null;
relationParentsStack.pop();
},
[RuleNames_1.RuleNames.FREESTYLE_TEXT + "Entry"]: (request, _response, node) => {
const target = currentHeading ? currentHeading : currentStatement;
node.text = "";
const settings = $.getSettings(request);
if (node.children) {
for (let child of node.children) {
if ((0, model_1.isTokenNode)(child) && child.image !== undefined) {
if ((0, chevrotain_1.tokenMatcher)(child, argdownLexer.EscapedChar)) {
node.text += child.image.substring(1, child.image.length);
}
else if ((0, chevrotain_1.tokenMatcher)(child, argdownLexer.SpecialChar)) {
const specialCharTrimmed = child.image.trim();
const specialCharInfo = settings.shortcodes[specialCharTrimmed];
if (specialCharInfo) {
const startPos = node.text ? node.text.length : 0;
node.text += specialCharInfo.unicode;
if (child.image[child.image.length - 1] == " ") {
node.text += " ";
}
let specialCharRange