mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-07 00:17:03 +03:00
Improve sieve parser
This commit is contained in:
parent
0a3a5f6d59
commit
c773b852a1
11 changed files with 124 additions and 106 deletions
|
|
@ -15,7 +15,6 @@ import {
|
||||||
} from 'Sieve/Commands/Actions';
|
} from 'Sieve/Commands/Actions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConditionalCommand,
|
|
||||||
ElsIfCommand,
|
ElsIfCommand,
|
||||||
ElseCommand,
|
ElseCommand,
|
||||||
IfCommand,
|
IfCommand,
|
||||||
|
|
@ -67,7 +66,6 @@ export const
|
||||||
IfCommand,
|
IfCommand,
|
||||||
ElsIfCommand,
|
ElsIfCommand,
|
||||||
ElseCommand,
|
ElseCommand,
|
||||||
ConditionalCommand,
|
|
||||||
RequireCommand,
|
RequireCommand,
|
||||||
StopCommand,
|
StopCommand,
|
||||||
// Action commands
|
// Action commands
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ export class FileIntoCommand extends ActionCommand
|
||||||
super();
|
super();
|
||||||
// QuotedString / MultiLine
|
// QuotedString / MultiLine
|
||||||
this._mailbox = new GrammarQuotedString();
|
this._mailbox = new GrammarQuotedString();
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc3894
|
||||||
|
this.copy = false;
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc5490#section-3.2
|
||||||
|
this.create = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get require() { return 'fileinto'; }
|
get require() { return 'fileinto'; }
|
||||||
|
|
@ -28,9 +32,7 @@ export class FileIntoCommand extends ActionCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
return 'fileinto'
|
return 'fileinto'
|
||||||
// https://datatracker.ietf.org/doc/html/rfc3894
|
|
||||||
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '')
|
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '')
|
||||||
// https://datatracker.ietf.org/doc/html/rfc5490#section-3.2
|
|
||||||
+ ((this.create && capa.includes('mailbox')) ? ' :create' : '')
|
+ ((this.create && capa.includes('mailbox')) ? ' :create' : '')
|
||||||
+ ' ' + this._mailbox
|
+ ' ' + this._mailbox
|
||||||
+ ';';
|
+ ';';
|
||||||
|
|
@ -64,15 +66,17 @@ export class RedirectCommand extends ActionCommand
|
||||||
super();
|
super();
|
||||||
// QuotedString / MultiLine
|
// QuotedString / MultiLine
|
||||||
this._address = new GrammarQuotedString();
|
this._address = new GrammarQuotedString();
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc3894
|
||||||
|
this.copy = false;
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
||||||
|
this.list = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
|
|
||||||
return 'redirect'
|
return 'redirect'
|
||||||
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
|
||||||
// + ((this.list && capa.includes('extlists')) ? ' :list ' + this.list : '')
|
// + ((this.list && capa.includes('extlists')) ? ' :list ' + this.list : '')
|
||||||
// https://datatracker.ietf.org/doc/html/rfc3894
|
|
||||||
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '')
|
+ ((this.copy && capa.includes('copy')) ? ' :copy' : '')
|
||||||
+ ' ' + this._address
|
+ ' ' + this._address
|
||||||
+ ';';
|
+ ';';
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ControlCommand,
|
ControlCommand,
|
||||||
|
GrammarCommands,
|
||||||
GrammarStringList,
|
GrammarStringList,
|
||||||
GrammarQuotedString
|
GrammarQuotedString
|
||||||
} from 'Sieve/Grammar';
|
} from 'Sieve/Grammar';
|
||||||
|
|
@ -16,37 +17,55 @@ import {
|
||||||
* elsif <test2: test> <block2: block>
|
* elsif <test2: test> <block2: block>
|
||||||
* else <block3: block>
|
* else <block3: block>
|
||||||
*/
|
*/
|
||||||
export class ConditionalCommand extends ControlCommand
|
export /*abstract*/ class ConditionalCommand extends ControlCommand
|
||||||
{
|
{
|
||||||
constructor(identifier)
|
constructor()
|
||||||
{
|
{
|
||||||
super(identifier);
|
|
||||||
this.test = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
toString()
|
|
||||||
{
|
|
||||||
return this.identifier + ' ' + this.test + ' ' + this.commands;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
public function pushArguments(array $args): void
|
if (this.constructor == ConditionalCommand) {
|
||||||
{
|
throw Error("Abstract class can't be instantiated.");
|
||||||
args.forEach((arg, i) => {
|
}
|
||||||
if (i && ':' === args[i-1][0]) {
|
|
||||||
this[args[i-1].replace(':','_')].value = arg.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
print_r($args);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
super();
|
||||||
|
this.commands = new GrammarCommands;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IfCommand extends ConditionalCommand
|
export class IfCommand extends ConditionalCommand
|
||||||
{
|
{
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
this._test = null; // must be descendent instanceof TestCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
get test()
|
||||||
|
{
|
||||||
|
return this._test;
|
||||||
|
}
|
||||||
|
|
||||||
|
set test(value)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (!value instanceof TestCommand) {
|
||||||
|
throw Error("test must be descendent instanceof TestCommand.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this._test = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (!this._test instanceof TestCommand) {
|
||||||
|
throw Error("test must be descendent instanceof TestCommand.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return this.identifier + ' ' + this._test + ' ' + this.commands;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ElsIfCommand extends ConditionalCommand
|
export class ElsIfCommand extends IfCommand
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ export class HeaderTest extends TestCommand
|
||||||
constructor()
|
constructor()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
this.match_type = ':is';
|
||||||
this.address_part = ':all';
|
this.address_part = ':all';
|
||||||
this.header_names = new GrammarStringList;
|
this.header_names = new GrammarStringList;
|
||||||
this.key_list = new GrammarStringList;
|
this.key_list = new GrammarStringList;
|
||||||
|
|
@ -316,11 +317,6 @@ export class NotTest extends TestCommand
|
||||||
{
|
{
|
||||||
return 'not ' + this.test;
|
return 'not ' + this.test;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushArguments()
|
|
||||||
{
|
|
||||||
throw 'No arguments';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ export class VacationCommand extends ActionCommand
|
||||||
}
|
}
|
||||||
if (this._from.length) {
|
if (this._from.length) {
|
||||||
result += ' :from ' + this._from;
|
result += ' :from ' + this._from;
|
||||||
// result += ' :from ' + this.arguments[':from'];
|
|
||||||
}
|
}
|
||||||
if (this.addresses.length) {
|
if (this.addresses.length) {
|
||||||
result += ' :addresses ' + this.addresses;
|
result += ' :addresses ' + this.addresses;
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,12 @@ class FlagCommand extends ActionCommand
|
||||||
if (args[0] instanceof GrammarQuotedString) {
|
if (args[0] instanceof GrammarQuotedString) {
|
||||||
this._variablename = args[0];
|
this._variablename = args[0];
|
||||||
}
|
}
|
||||||
if (args[1] instanceof GrammarString) {
|
args[0] = args[1];
|
||||||
this.list_of_flags = args[1];
|
}
|
||||||
}
|
if (args[0] instanceof GrammarStringList) {
|
||||||
} else if (args[0] instanceof GrammarString) {
|
|
||||||
this.list_of_flags = args[0];
|
this.list_of_flags = args[0];
|
||||||
|
} else if (args[0]) {
|
||||||
|
this.list_of_flags.push(args[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import {
|
||||||
GrammarString
|
GrammarString
|
||||||
} from 'Sieve/Grammar';
|
} from 'Sieve/Grammar';
|
||||||
|
|
||||||
class rfc5429Command extends ActionCommand
|
class /*abstract*/ rfc5429Command extends ActionCommand
|
||||||
{
|
{
|
||||||
constructor(identifier)
|
constructor()
|
||||||
{
|
{
|
||||||
super(identifier);
|
super();
|
||||||
this._reason = new GrammarQuotedString;
|
this._reason = new GrammarQuotedString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,7 +44,6 @@ class rfc5429Command extends ActionCommand
|
||||||
*/
|
*/
|
||||||
export class ErejectCommand extends rfc5429Command
|
export class ErejectCommand extends rfc5429Command
|
||||||
{
|
{
|
||||||
constructor() { super('ereject'); }
|
|
||||||
get require() { return 'ereject'; }
|
get require() { return 'ereject'; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,6 +52,5 @@ export class ErejectCommand extends rfc5429Command
|
||||||
*/
|
*/
|
||||||
export class RejectCommand extends rfc5429Command
|
export class RejectCommand extends rfc5429Command
|
||||||
{
|
{
|
||||||
constructor() { super('reject'); }
|
|
||||||
get require() { return 'reject'; }
|
get require() { return 'reject'; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
import {
|
import {
|
||||||
ActionCommand,
|
ActionCommand,
|
||||||
ControlCommand,
|
ControlCommand,
|
||||||
|
GrammarCommands,
|
||||||
GrammarNumber,
|
GrammarNumber,
|
||||||
GrammarQuotedString,
|
GrammarQuotedString,
|
||||||
GrammarString,
|
GrammarString,
|
||||||
|
|
@ -20,6 +21,7 @@ export class ForEveryPartCommand extends ControlCommand
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
this._name = new GrammarString;
|
this._name = new GrammarString;
|
||||||
|
this.commands = new GrammarCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
get require() { return 'foreverypart'; }
|
get require() { return 'foreverypart'; }
|
||||||
|
|
@ -27,7 +29,7 @@ export class ForEveryPartCommand extends ControlCommand
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
let result = 'foreverypart';
|
let result = 'foreverypart';
|
||||||
if (this._subject.length) {
|
if (this._name.length) {
|
||||||
result += ' :name ' + this._name;
|
result += ' :name ' + this._name;
|
||||||
}
|
}
|
||||||
return result + ' ' + this.commands;
|
return result + ' ' + this.commands;
|
||||||
|
|
@ -43,12 +45,15 @@ export class ForEveryPartCommand extends ControlCommand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be inside foreverypart
|
||||||
|
*/
|
||||||
export class BreakCommand extends ForEveryPartCommand
|
export class BreakCommand extends ForEveryPartCommand
|
||||||
{
|
{
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
let result = 'break';
|
let result = 'break';
|
||||||
if (this._subject.length) {
|
if (this._name.length) {
|
||||||
result += ' :name ' + this._name;
|
result += ' :name ' + this._name;
|
||||||
}
|
}
|
||||||
return result + ';';
|
return result + ';';
|
||||||
|
|
@ -82,7 +87,6 @@ export class ReplaceCommand extends ActionCommand
|
||||||
}
|
}
|
||||||
if (this._from.length) {
|
if (this._from.length) {
|
||||||
result += ' :from ' + this._from;
|
result += ' :from ' + this._from;
|
||||||
// result += ' :from ' + this.arguments[':from'];
|
|
||||||
}
|
}
|
||||||
return result + this.replacement + ';';
|
return result + this.replacement + ';';
|
||||||
}
|
}
|
||||||
|
|
@ -140,6 +144,7 @@ export class EncloseCommand extends ActionCommand
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://datatracker.ietf.org/doc/html/rfc5703#section-7
|
* https://datatracker.ietf.org/doc/html/rfc5703#section-7
|
||||||
|
* Should be inside foreverypart, else empty and flagged as a compilation error
|
||||||
*/
|
*/
|
||||||
export class ExtractTextCommand extends ActionCommand
|
export class ExtractTextCommand extends ActionCommand
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ export class GrammarString /*extends String*/
|
||||||
{
|
{
|
||||||
constructor(value = '')
|
constructor(value = '')
|
||||||
{
|
{
|
||||||
this._value = value;
|
this._value = value.toString ? value.toString() : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
toString()
|
toString()
|
||||||
|
|
@ -52,34 +52,26 @@ export class GrammarComment extends GrammarString
|
||||||
/**
|
/**
|
||||||
* https://tools.ietf.org/html/rfc5228#section-2.9
|
* https://tools.ietf.org/html/rfc5228#section-2.9
|
||||||
*/
|
*/
|
||||||
export class GrammarCommand
|
const cmdNameSuffix = /(test|command|action)$/;
|
||||||
|
export /*abstract*/ class GrammarCommand
|
||||||
{
|
{
|
||||||
constructor(identifier)
|
constructor(identifier)
|
||||||
{
|
{
|
||||||
this.identifier = identifier || this.constructor.name.toLowerCase().replace(/(test|command|action)$/, '');
|
/*
|
||||||
this.arguments = [];
|
if (this.constructor == GrammarCommand) {
|
||||||
this.commands = new GrammarCommands;
|
throw Error("Abstract class can't be instantiated.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.identifier = identifier || this.constructor.name.toLowerCase().replace(cmdNameSuffix, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
let result = this.identifier;
|
let result = this.identifier;
|
||||||
if (this.arguments.length) {
|
if (this.arguments?.length) {
|
||||||
result += ' ' + arrayToString(this.arguments, ' ');
|
result += ' ' + arrayToString(this.arguments, ' ');
|
||||||
}
|
}
|
||||||
return result + (
|
return result + ';';
|
||||||
this.commands.length ? ' ' + this.commands : ';'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getComparators()
|
|
||||||
{
|
|
||||||
return ['i;ascii-casemap'];
|
|
||||||
}
|
|
||||||
|
|
||||||
getMatchTypes()
|
|
||||||
{
|
|
||||||
return [':is', ':contains', ':matches'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pushArguments(args)
|
pushArguments(args)
|
||||||
|
|
@ -108,63 +100,47 @@ export class GrammarCommands extends Array
|
||||||
/**
|
/**
|
||||||
* https://tools.ietf.org/html/rfc5228#section-3
|
* https://tools.ietf.org/html/rfc5228#section-3
|
||||||
*/
|
*/
|
||||||
export class ControlCommand extends GrammarCommand
|
export /*abstract*/ class ControlCommand extends GrammarCommand
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
constructor(identifier)
|
constructor(identifier)
|
||||||
{
|
{
|
||||||
super(identifier);
|
if (this.constructor == ControlCommand) {
|
||||||
this.commands = new GrammarCommands;
|
throw Error("Abstract class can't be instantiated.");
|
||||||
}
|
|
||||||
|
|
||||||
toString()
|
|
||||||
{
|
|
||||||
let result = this.identifier;
|
|
||||||
if (this.arguments.length) {
|
|
||||||
result += ' ' + arrayToString(this.arguments, ' ');
|
|
||||||
}
|
}
|
||||||
return result + (
|
super(identifier);
|
||||||
this.commands.length ? ' ' + this.commands : ';'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getComparators()
|
|
||||||
{
|
|
||||||
return ['i;ascii-casemap'];
|
|
||||||
}
|
|
||||||
|
|
||||||
getMatchTypes()
|
|
||||||
{
|
|
||||||
return [':is', ':contains', ':matches'];
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* https://tools.ietf.org/html/rfc5228#section-4
|
* https://tools.ietf.org/html/rfc5228#section-4
|
||||||
*/
|
*/
|
||||||
export class ActionCommand extends GrammarCommand
|
export /*abstract*/ class ActionCommand extends GrammarCommand
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
constructor(identifier)
|
constructor(identifier)
|
||||||
{
|
{
|
||||||
|
if (this.constructor == ActionCommand) {
|
||||||
|
throw Error("Abstract class can't be instantiated.");
|
||||||
|
}
|
||||||
super(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
|
* https://tools.ietf.org/html/rfc5228#section-5
|
||||||
*/
|
*/
|
||||||
export class TestCommand extends GrammarCommand
|
export /*abstract*/ class TestCommand extends GrammarCommand
|
||||||
{
|
{
|
||||||
constructor(identifier)
|
constructor(identifier)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
if (this.constructor == TestCommand) {
|
||||||
|
throw Error("Abstract class can't be instantiated.");
|
||||||
|
}
|
||||||
|
*/
|
||||||
super(identifier);
|
super(identifier);
|
||||||
// Almost every test has a comparator and match_type, so define them here
|
// Almost every test has a comparator and match_type, so define them here
|
||||||
this.comparator = '';
|
this.comparator = '';
|
||||||
|
|
@ -251,6 +227,7 @@ export class GrammarStringList extends Array
|
||||||
{
|
{
|
||||||
toString()
|
toString()
|
||||||
{
|
{
|
||||||
|
// if there is only a single string, the brackets are optional
|
||||||
if (1 < this.length) {
|
if (1 < this.length) {
|
||||||
return '[' + this.join(',') + ']';
|
return '[' + this.join(',') + ']';
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +236,7 @@ export class GrammarStringList extends Array
|
||||||
|
|
||||||
push(value)
|
push(value)
|
||||||
{
|
{
|
||||||
if (!(value instanceof GrammarString)) {
|
if (!(value instanceof GrammarQuotedString)) {
|
||||||
value = new GrammarQuotedString(value);
|
value = new GrammarQuotedString(value);
|
||||||
}
|
}
|
||||||
super.push(value);
|
super.push(value);
|
||||||
|
|
@ -324,3 +301,23 @@ GrammarMultiLine.fromString = string => {
|
||||||
}
|
}
|
||||||
return new GrammarMultiLine();
|
return new GrammarMultiLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UnknownCommand 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 : ';'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,12 +154,10 @@ export const parseScript = (script, name = 'script.sieve') => {
|
||||||
pushArgs();
|
pushArgs();
|
||||||
value = value.toLowerCase();
|
value = value.toLowerCase();
|
||||||
let new_command;
|
let new_command;
|
||||||
if ('if' === value) {
|
if (Commands[value]) {
|
||||||
new_command = new ConditionalCommand(value);
|
if ('elsif' === value || 'else' === value) {
|
||||||
} else if ('elsif' === value || 'else' === value) {
|
// (prev_command instanceof ConditionalCommand) || error('Not after IF condition');
|
||||||
// (prev_command instanceof ConditionalCommand) || error('Not after IF condition');
|
}
|
||||||
new_command = new ConditionalCommand(value);
|
|
||||||
} else if (Commands[value]) {
|
|
||||||
if ('allof' === value || 'anyof' === value) {
|
if ('allof' === value || 'anyof' === value) {
|
||||||
// (command instanceof ConditionalCommand || command instanceof NotTest) || error('Test-list not in conditional');
|
// (command instanceof ConditionalCommand || command instanceof NotTest) || error('Test-list not in conditional');
|
||||||
}
|
}
|
||||||
|
|
@ -293,5 +291,6 @@ export const parseScript = (script, name = 'script.sieve') => {
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.requires = requires;
|
tree.requires = requires;
|
||||||
|
tree.toString = () => tree.join('\r\n');
|
||||||
return tree;
|
return tree;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ export const
|
||||||
koComputable = fn => ko.computed(fn, {'pure':true}),
|
koComputable = fn => ko.computed(fn, {'pure':true}),
|
||||||
|
|
||||||
arrayToString = (arr, separator) =>
|
arrayToString = (arr, separator) =>
|
||||||
arr.map(item => item.toString?.() || item).join(separator),
|
(arr || []).map(item => item.toString?.() || item).join(separator),
|
||||||
/*
|
/*
|
||||||
getNotificationMessage = code => {
|
getNotificationMessage = code => {
|
||||||
let key = getKeyByValue(Notifications, code);
|
let key = getKeyByValue(Notifications, code);
|
||||||
|
|
@ -58,6 +58,8 @@ export const
|
||||||
serverErrorDesc(text);
|
serverErrorDesc(text);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getComparators = () => ['i;ascii-casemap'],
|
||||||
|
|
||||||
getMatchTypes = (validOnly = 1) => {
|
getMatchTypes = (validOnly = 1) => {
|
||||||
let result = [':is',':contains',':matches'];
|
let result = [':is',':contains',':matches'];
|
||||||
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
// https://datatracker.ietf.org/doc/html/rfc6134#section-2.3
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue