import re from string import Template from typing import Callable, List, NamedTuple, Optional, Pattern import warnings from urlmatch import urlmatch import modules.inline as inline import modules.metadata as metadata from modules.metadata import Metadata, Tag, Tag_boolean, Tag_string from modules.patterns import isIncludePattern, isMatchPattern, regexFromIncludePattern from modules.utilities import compose2, isSomething, stripIndentation, strs class UserscriptError(Exception): def __init__(self,*args,**kwargs): Exception.__init__(self,*args,**kwargs) REGEX_URL: Pattern = re.compile(r"^https?://") directive_name : str = "name" directive_version : str = "version" directive_run_at : str = "run-at" directive_match : str = "match" directive_include : str = "include" directive_exclude : str = "exclude" directive_noframes : str = "noframes" directive_downloadURL : str = "downloadURL" document_end : str = "document-end" document_start : str = "document-start" document_idle : str = "document-idle" tag_name: Tag_string = Tag_string( name = directive_name, unique = True, default = None, required = True, predicate = lambda val: val != "", ) tag_run_at: Tag_string = Tag_string( name = directive_run_at, unique = True, default = document_end, required = False, predicate = lambda val: val in [ document_end, document_start, document_idle ], ) tag_match: Tag_string = Tag_string( name = directive_match, unique = False, default = None, required = False, predicate = isMatchPattern, ) tag_include: Tag_string = Tag_string( name = directive_include, unique = False, default = None, required = False, predicate = isIncludePattern, ) tag_exclude: Tag_string = Tag_string( name = directive_exclude, unique = False, default = None, required = False, predicate = isIncludePattern, ) tag_noframes: Tag_boolean = Tag_boolean( name = directive_noframes, unique = True, default = False, required = False, predicate = None, ) tag_version: Tag_string = Tag_string( name = directive_version, unique = True, default = None, required = False, predicate = None, ) tag_downloadURL: Tag_string = Tag_string( name = directive_downloadURL, unique = True, default = None, required = False, predicate = lambda val: isSomething(REGEX_URL.match(val)), ) METADATA_TAGS: List[Tag] = [ tag_name, tag_run_at, tag_match, tag_noframes, tag_include, tag_exclude, tag_version, tag_downloadURL, ] validateMetadata: Callable[[Metadata], Metadata] = metadata.validator(METADATA_TAGS) STRING_WARNING_INVALID_REGEX: Template = Template(f"""{metadata.tag(directive_include)}/{metadata.tag(directive_exclude)} patterns starting and ending with `/` are interpreted as regular expressions, and this pattern is not a valid regex: $pattern The regex engine reported this error: $error """) class Userscript(NamedTuple): name: str version: Optional[str] content: str runAt: str noframes: bool matchPatterns: List[str] includePatternRegexes: List[Pattern] excludePatternRegexes: List[Pattern] downloadURL: Optional[str] unsafeSequences: List[str] # in