from typing import Optional, Tuple, List, NamedTuple, Callable, Pattern import re import warnings from string import Template from urlmatch import urlmatch import modules.metadata as metadata import modules.inline as inline from modules.utilities import first, second, isSomething, strs, compose2, stripIndentation from modules.metadata import Metadata, PREFIX_TAG, Tag, Tag_string, Tag_boolean from modules.patterns import isMatchPattern, isIncludePattern, regexFromIncludePattern 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"""{PREFIX_TAG}{directive_include}/{PREFIX_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