Prepare some Sieve restructuring for GUI

This commit is contained in:
the-djmaze 2022-03-17 09:03:02 +01:00
parent 37bb9a9a97
commit ff9a89380c
15 changed files with 259 additions and 194 deletions

View file

@ -1,102 +1,20 @@
/** /**
* https://tools.ietf.org/html/rfc5228#section-2.9 * https://datatracker.ietf.org/doc/html/rfc5228#section-4
* Action commands do not take tests or blocks as arguments.
*/ */
import { capa } from 'Sieve/Utils'; import { capa } from 'Sieve/Utils';
import { import {
GrammarCommand, ActionCommand,
GrammarString, GrammarString,
GrammarStringList,
GrammarQuotedString GrammarQuotedString
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
/**
* https://tools.ietf.org/html/rfc5228#section-3.1
* Usage:
* if <test1: test> <block1: block>
* elsif <test2: test> <block2: block>
* else <block3: block>
*/
export class ConditionalCommand extends GrammarCommand
{
constructor()
{
super();
this.test = null;
}
toString()
{
return this.identifier + ' ' + this.test + ' ' + this.commands;
}
/*
public function pushArguments(array $args): void
{
args.forEach((arg, i) => {
if (':' === args[i-1][0]) {
this[args[i-1].replace(':','_')].value = arg.value;
}
});
print_r($args);
exit;
}
*/
}
export class IfCommand extends ConditionalCommand
{
}
export class ElsIfCommand extends ConditionalCommand
{
}
export class ElseCommand extends ConditionalCommand
{
toString()
{
return this.identifier + ' ' + this.commands;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.2
*/
export class RequireCommand extends GrammarCommand
{
constructor()
{
super();
this.capabilities = new GrammarStringList();
}
toString()
{
return 'require ' + this.capabilities + ';';
}
pushArguments(args)
{
if (args[0] instanceof GrammarStringList) {
this.capabilities = args[0];
} else if (args[0] instanceof GrammarQuotedString) {
this.capabilities.push(args[0]);
}
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.3
*/
export class StopCommand extends GrammarCommand
{
}
/** /**
* https://tools.ietf.org/html/rfc5228#section-4.1 * https://tools.ietf.org/html/rfc5228#section-4.1
*/ */
export class FileIntoCommand extends GrammarCommand export class FileIntoCommand extends ActionCommand
{ {
constructor() constructor()
{ {
@ -139,7 +57,7 @@ export class FileIntoCommand extends GrammarCommand
/** /**
* https://tools.ietf.org/html/rfc5228#section-4.2 * https://tools.ietf.org/html/rfc5228#section-4.2
*/ */
export class RedirectCommand extends GrammarCommand export class RedirectCommand extends ActionCommand
{ {
constructor() constructor()
{ {
@ -181,13 +99,13 @@ export class RedirectCommand extends GrammarCommand
/** /**
* https://tools.ietf.org/html/rfc5228#section-4.3 * https://tools.ietf.org/html/rfc5228#section-4.3
*/ */
export class KeepCommand extends GrammarCommand export class KeepCommand extends ActionCommand
{ {
} }
/** /**
* https://tools.ietf.org/html/rfc5228#section-4.4 * https://tools.ietf.org/html/rfc5228#section-4.4
*/ */
export class DiscardCommand extends GrammarCommand export class DiscardCommand extends ActionCommand
{ {
} }

View file

@ -0,0 +1,92 @@
/**
* https://tools.ietf.org/html/rfc5228#section-2.9
* A control structure is a control command that ends with a block instead of a semicolon.
*/
import {
GrammarCommand,
GrammarStringList,
GrammarQuotedString
} from 'Sieve/Grammar';
/**
* https://tools.ietf.org/html/rfc5228#section-3.1
* Usage:
* if <test1: test> <block1: block>
* elsif <test2: test> <block2: block>
* else <block3: block>
*/
export class ConditionalCommand extends GrammarCommand
{
constructor()
{
super();
this.test = null;
}
toString()
{
return this.identifier + ' ' + this.test + ' ' + this.commands;
}
/*
public function pushArguments(array $args): void
{
args.forEach((arg, i) => {
if (':' === args[i-1][0]) {
this[args[i-1].replace(':','_')].value = arg.value;
}
});
print_r($args);
exit;
}
*/
}
export class IfCommand extends ConditionalCommand
{
}
export class ElsIfCommand extends ConditionalCommand
{
}
export class ElseCommand extends ConditionalCommand
{
toString()
{
return this.identifier + ' ' + this.commands;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.2
*/
export class RequireCommand extends GrammarCommand
{
constructor()
{
super();
this.capabilities = new GrammarStringList();
}
toString()
{
return 'require ' + this.capabilities + ';';
}
pushArguments(args)
{
if (args[0] instanceof GrammarStringList) {
this.capabilities = args[0];
} else if (args[0] instanceof GrammarQuotedString) {
this.capabilities.push(args[0]);
}
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-3.3
*/
export class StopCommand extends GrammarCommand
{
}

View file

@ -8,7 +8,7 @@ import {
GrammarNumber, GrammarNumber,
GrammarString, GrammarString,
GrammarStringList, GrammarStringList,
GrammarTest, TestCommand,
GrammarTestList GrammarTestList
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
@ -31,7 +31,7 @@ const
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.1 * https://tools.ietf.org/html/rfc5228#section-5.1
*/ */
export class AddressTest extends GrammarTest export class AddressTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -98,7 +98,7 @@ export class AddressTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.2 * https://tools.ietf.org/html/rfc5228#section-5.2
*/ */
export class AllOfTest extends GrammarTest export class AllOfTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -115,7 +115,7 @@ export class AllOfTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.3 * https://tools.ietf.org/html/rfc5228#section-5.3
*/ */
export class AnyOfTest extends GrammarTest export class AnyOfTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -132,7 +132,7 @@ export class AnyOfTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.4 * https://tools.ietf.org/html/rfc5228#section-5.4
*/ */
export class EnvelopeTest extends GrammarTest export class EnvelopeTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -169,7 +169,7 @@ export class EnvelopeTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.5 * https://tools.ietf.org/html/rfc5228#section-5.5
*/ */
export class ExistsTest extends GrammarTest export class ExistsTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -214,7 +214,7 @@ export class ExistsTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.6 * https://tools.ietf.org/html/rfc5228#section-5.6
*/ */
export class FalseTest extends GrammarTest export class FalseTest extends TestCommand
{ {
toString() toString()
{ {
@ -225,7 +225,7 @@ export class FalseTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.7 * https://tools.ietf.org/html/rfc5228#section-5.7
*/ */
export class HeaderTest extends GrammarTest export class HeaderTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -304,12 +304,12 @@ export class HeaderTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.8 * https://tools.ietf.org/html/rfc5228#section-5.8
*/ */
export class NotTest extends GrammarTest export class NotTest extends TestCommand
{ {
constructor() constructor()
{ {
super(); super();
this.test = new GrammarTest; this.test = new TestCommand;
} }
toString() toString()
@ -326,7 +326,7 @@ export class NotTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.9 * https://tools.ietf.org/html/rfc5228#section-5.9
*/ */
export class SizeTest extends GrammarTest export class SizeTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -355,7 +355,7 @@ export class SizeTest extends GrammarTest
/** /**
* https://tools.ietf.org/html/rfc5228#section-5.10 * https://tools.ietf.org/html/rfc5228#section-5.10
*/ */
export class TrueTest extends GrammarTest export class TrueTest extends TestCommand
{ {
toString() toString()
{ {

View file

@ -5,10 +5,10 @@
import { import {
GrammarString, GrammarString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
export class BodyTest extends GrammarTest export class BodyTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -5,10 +5,10 @@
import { import {
GrammarQuotedString, GrammarQuotedString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
export class EnvironmentTest extends GrammarTest export class EnvironmentTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -6,7 +6,7 @@ import {
GrammarCommand, GrammarCommand,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
export class SetCommand extends GrammarCommand export class SetCommand extends GrammarCommand
@ -45,7 +45,7 @@ export class SetCommand extends GrammarCommand
} }
} }
export class StringTest extends GrammarTest export class StringTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -7,7 +7,7 @@ import {
GrammarQuotedString, GrammarQuotedString,
GrammarString, GrammarString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
class FlagCommand extends GrammarCommand class FlagCommand extends GrammarCommand
@ -63,7 +63,7 @@ export class RemoveFlagCommand extends FlagCommand
{ {
} }
export class HasFlagTest extends GrammarTest export class HasFlagTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -5,10 +5,10 @@
import { import {
GrammarQuotedString, GrammarQuotedString,
GrammarString, GrammarString,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
export class SpamTestTest extends GrammarTest export class SpamTestTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -41,7 +41,7 @@ export class SpamTestTest extends GrammarTest
} }
} }
export class VirusTestTest extends GrammarTest export class VirusTestTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -6,10 +6,10 @@ import {
GrammarNumber, GrammarNumber,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
export class DateTest extends GrammarTest export class DateTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -58,7 +58,7 @@ export class DateTest extends GrammarTest
} }
} }
export class CurrentDateTest extends GrammarTest export class CurrentDateTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -7,7 +7,7 @@ import {
GrammarNumber, GrammarNumber,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
/** /**
@ -72,7 +72,7 @@ export class NotifyCommand extends GrammarCommand
/** /**
* https://datatracker.ietf.org/doc/html/rfc5435#section-4 * https://datatracker.ietf.org/doc/html/rfc5435#section-4
*/ */
export class ValidNotifyMethodTest extends GrammarTest export class ValidNotifyMethodTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -94,7 +94,7 @@ export class ValidNotifyMethodTest extends GrammarTest
/** /**
* https://datatracker.ietf.org/doc/html/rfc5435#section-5 * https://datatracker.ietf.org/doc/html/rfc5435#section-5
*/ */
export class NotifyMethodCapabilityTest extends GrammarTest export class NotifyMethodCapabilityTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -4,7 +4,7 @@
import { import {
GrammarCommand, GrammarCommand,
GrammarTest, TestCommand,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList GrammarStringList
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
@ -12,7 +12,7 @@ import {
/** /**
* https://datatracker.ietf.org/doc/html/rfc5463#section-4 * https://datatracker.ietf.org/doc/html/rfc5463#section-4
*/ */
export class IHaveTest extends GrammarTest export class IHaveTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -3,7 +3,7 @@
*/ */
import { import {
GrammarTest, TestCommand,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList GrammarStringList
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
@ -11,7 +11,7 @@ import {
/** /**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.1 * https://datatracker.ietf.org/doc/html/rfc5490#section-3.1
*/ */
export class MailboxExistsTest extends GrammarTest export class MailboxExistsTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -37,7 +37,7 @@ export class MailboxExistsTest extends GrammarTest
/** /**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.3 * https://datatracker.ietf.org/doc/html/rfc5490#section-3.3
*/ */
export class MetadataTest extends GrammarTest export class MetadataTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -70,7 +70,7 @@ export class MetadataTest extends GrammarTest
/** /**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.4 * https://datatracker.ietf.org/doc/html/rfc5490#section-3.4
*/ */
export class MetadataExistsTest extends GrammarTest export class MetadataExistsTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -98,7 +98,7 @@ export class MetadataExistsTest extends GrammarTest
/** /**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.3 * https://datatracker.ietf.org/doc/html/rfc5490#section-3.3
*/ */
export class ServerMetadataTest extends GrammarTest export class ServerMetadataTest extends TestCommand
{ {
constructor() constructor()
{ {
@ -128,7 +128,7 @@ export class ServerMetadataTest extends GrammarTest
/** /**
* https://datatracker.ietf.org/doc/html/rfc5490#section-3.4 * https://datatracker.ietf.org/doc/html/rfc5490#section-3.4
*/ */
export class ServerMetadataExistsTest extends GrammarTest export class ServerMetadataExistsTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -4,13 +4,13 @@
import { import {
GrammarStringList, GrammarStringList,
GrammarTest TestCommand
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
/** /**
* https://datatracker.ietf.org/doc/html/rfc6134#section-2.7 * https://datatracker.ietf.org/doc/html/rfc6134#section-2.7
*/ */
export class ValidExtListTest extends GrammarTest export class ValidExtListTest extends TestCommand
{ {
constructor() constructor()
{ {

View file

@ -56,7 +56,7 @@ export class GrammarCommand
{ {
constructor(identifier) constructor(identifier)
{ {
this.identifier = identifier || this.constructor.name.toLowerCase().replace('command', ''); this.identifier = identifier || this.constructor.name.toLowerCase().replace(/(test|command|action)$/, '');
this.arguments = []; this.arguments = [];
this.commands = new GrammarCommands; this.commands = new GrammarCommands;
} }
@ -105,6 +105,114 @@ export class GrammarCommands extends Array
} }
} }
/**
* https://tools.ietf.org/html/rfc5228#section-3
*/
export class ControlCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
this.commands = new GrammarCommands;
}
toString()
{
let result = this.identifier;
if (this.arguments.length) {
result += ' ' + arrayToString(this.arguments, ' ');
}
return result + (
this.commands.length ? ' ' + this.commands : ';'
);
}
getComparators()
{
return ['i;ascii-casemap'];
}
getMatchTypes()
{
return [':is', ':contains', ':matches'];
}
pushArguments(args)
{
this.arguments = args;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-4
*/
export class ActionCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
}
toString()
{
let result = this.identifier;
if (this.arguments.length) {
result += ' ' + arrayToString(this.arguments, ' ');
}
return result + ';'
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5
*/
export class TestCommand extends GrammarCommand
{
constructor(identifier)
{
super(identifier);
// Almost every test has a comparator and match_type, so define them here
this.comparator = '';
this.match_type = ':is';
}
toString()
{
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
if (!getMatchTypes().includes(this.match_type)) {
throw 'Unsupported match-type ' + this.match_type;
}
return (this.identifier
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ (this.match_type ? ' ' + this.match_type : '')
+ ' ' + arrayToString(this.arguments, ' ')).trim();
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5.2
* https://tools.ietf.org/html/rfc5228#section-5.3
*/
export class GrammarTestList extends Array
{
toString()
{
if (1 < this.length) {
// return '(\r\n\t' + arrayToString(this, ',\r\n\t') + '\r\n)';
return '(' + this.join(', ') + ')';
}
return this.length ? this[0] : '';
}
push(value)
{
if (!(value instanceof TestCommand)) {
throw 'Not an instanceof Test';
}
super.push(value);
}
}
export class GrammarBracketComment extends GrammarComment export class GrammarBracketComment extends GrammarComment
{ {
toString() toString()
@ -221,59 +329,3 @@ GrammarMultiLine.fromString = string => {
} }
return new GrammarMultiLine(); return new GrammarMultiLine();
} }
/**
* https://tools.ietf.org/html/rfc5228#section-5
*/
export class GrammarTest
{
constructor(identifier)
{
this.identifier = identifier || this.constructor.name.toLowerCase().replace(/test$/, '');
// Almost every test has a comparator and match_type, so define them here
this.comparator = '',
this.match_type = ':is',
this.arguments = [];
}
toString()
{
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
if (!getMatchTypes().includes(this.match_type)) {
throw 'Unsupported match-type ' + this.match_type;
}
return (this.identifier
+ (this.comparator ? ' :comparator ' + this.comparator : '')
+ (this.match_type ? ' ' + this.match_type : '')
+ ' ' + arrayToString(this.arguments, ' ')).trim();
}
pushArguments(args)
{
this.arguments = args;
}
}
/**
* https://tools.ietf.org/html/rfc5228#section-5.2
* https://tools.ietf.org/html/rfc5228#section-5.3
*/
export class GrammarTestList extends Array
{
toString()
{
if (1 < this.length) {
// return '(\r\n\t' + arrayToString(this, ',\r\n\t') + '\r\n)';
return '(' + this.join(', ') + ')';
}
return this.length ? this[0] : '';
}
push(value)
{
if (!(value instanceof GrammarTest)) {
throw 'Not an instanceof Test';
}
super.push(value);
}
}

View file

@ -23,22 +23,25 @@ import {
GrammarNumber, GrammarNumber,
GrammarQuotedString, GrammarQuotedString,
GrammarStringList, GrammarStringList,
GrammarTest, TestCommand,
GrammarTestList GrammarTestList
} from 'Sieve/Grammar'; } from 'Sieve/Grammar';
import { import {
ConditionalCommand,
DiscardCommand, DiscardCommand,
FileIntoCommand,
KeepCommand,
RedirectCommand
} from 'Sieve/Commands/Actions';
import {
ConditionalCommand,
ElsIfCommand, ElsIfCommand,
ElseCommand, ElseCommand,
FileIntoCommand,
IfCommand, IfCommand,
KeepCommand,
RedirectCommand,
RequireCommand, RequireCommand,
StopCommand StopCommand
} from 'Sieve/Commands'; } from 'Sieve/Commands/Controls';
import { import {
AddressTest, AddressTest,
@ -51,7 +54,7 @@ import {
NotTest, NotTest,
SizeTest, SizeTest,
TrueTest TrueTest
} from 'Sieve/Tests'; } from 'Sieve/Commands/Tests';
import { BodyTest } from 'Sieve/Extensions/rfc5173'; import { BodyTest } from 'Sieve/Extensions/rfc5173';
import { EnvironmentTest } from 'Sieve/Extensions/rfc5183'; import { EnvironmentTest } from 'Sieve/Extensions/rfc5183';
@ -265,14 +268,14 @@ export const parseScript = (script, name = 'script.sieve') => {
|| command instanceof NotTest || command instanceof NotTest
|| command.tests instanceof GrammarTestList)) { || command.tests instanceof GrammarTestList)) {
console.error('Unknown test: ' + value); console.error('Unknown test: ' + value);
new_command = new GrammarTest(value); new_command = new TestCommand(value);
} else { } else {
console.error('Unknown command: ' + value); console.error('Unknown command: ' + value);
new_command = new GrammarCommand(value); new_command = new GrammarCommand(value);
} }
} }
if (new_command instanceof GrammarTest) { if (new_command instanceof TestCommand) {
if (command instanceof ConditionalCommand || command instanceof NotTest) { if (command instanceof ConditionalCommand || command instanceof NotTest) {
// if/elsif/else new_command // if/elsif/else new_command
// not new_command // not new_command