import monoucha/javascript
import types/referrer
import types/url
type
ParserMetadata* = enum
pmParserInserted, pmNotParserInserted
ScriptType* = enum
stNone, stClassic, stModule, stImportMap
ScriptResultType* = enum
srtNull, srtScript, srtImportMapParse, srtFetching
RequestDestination* = enum
rdNone = ""
rdAudio = "audio"
rdAudioworklet = "audioworklet"
rdDocument = "document"
rdEmbed = "embed"
rdFont = "font"
rdFrame = "frame"
rdIframe = "iframe"
rdImage = "image"
rdJson = "json"
rdManifest = "manifest"
rdObject = "object"
rdPaintworklet = "paintworklet"
rdReport = "report"
rdScript = "script"
rdServiceworker = "serviceworker"
rdSharedworker = "sharedworker"
rdStyle = "style"
rdTrack = "track"
rdWorker = "worker"
rdXslt = "xslt"
CredentialsMode* = enum
cmSameOrigin = "same-origin"
cmOmit = "omit"
cmInclude = "include"
type
EnvironmentSettings* = ref object
scripting*: bool
moduleMap*: ModuleMap
origin*: Origin
Script* = ref object
#TODO setings
baseURL*: URL
options*: ScriptOptions
mutedErrors*: bool
#TODO parse error/error to rethrow
record*: JSValue
ScriptOptions* = object
nonce*: string
integrity*: string
parserMetadata*: ParserMetadata
credentialsMode*: CredentialsMode
referrerPolicy*: Option[ReferrerPolicy]
renderBlocking*: bool
ScriptResult* = ref object
case t*: ScriptResultType
of srtNull, srtFetching:
discard
of srtScript:
script*: Script
of srtImportMapParse:
discard #TODO
ModuleMapEntry = object
key: tuple[url, moduleType: string]
value*: ScriptResult
ModuleMap* = seq[ModuleMapEntry]
# Forward declaration hack
# set in html/dom
var windowConsoleError*: proc(ctx: JSContext; ss: varargs[string]) {.nimcall.}
proc find*(moduleMap: ModuleMap; url: URL; moduleType: string): int =
let surl = $url
for i, entry in moduleMap:
if entry.key.moduleType == moduleType and entry.key.url == surl:
return i
return -1
proc set*(moduleMap: var ModuleMap; url: URL; moduleType: string;
value: ScriptResult; ctx: JSContext) =
let i = moduleMap.find(url, moduleType)
if i != -1:
if moduleMap[i].value.t == srtScript:
JS_FreeValue(ctx, moduleMap[i].value.script.record)
moduleMap[i].value = value
else:
moduleMap.add(ModuleMapEntry(key: ($url, moduleType), value: value))
func moduleTypeToRequestDest*(moduleType: string; default: RequestDestination):
RequestDestination =
if moduleType == "json":
return rdJson
if moduleType == "css":
return rdStyle
return default
proc newClassicScript*(ctx: JSContext; source: string; baseURL: URL;
options: ScriptOptions; mutedErrors = false): ScriptResult =
let urls = baseURL.serialize(excludepassword = true)
let record = ctx.compileScript(source, urls)
return ScriptResult(
t: srtScript,
script: Script(
record: record,
baseURL: baseURL,
options: options,
mutedErrors: mutedErrors
)
)
proc newJSModuleScript*(ctx: JSContext; source: string; baseURL: URL;
options: ScriptOptions): ScriptResult =
let urls = baseURL.serialize(excludepassword = true)
let record = ctx.compileModule(source, urls)
return ScriptResult(
t: srtScript,
script: Script(
record: record,
baseURL: baseURL,
options: options
)
)
proc logException*(ctx: JSContext) =
windowConsoleError(ctx, ctx.getExceptionMsg())