Ignore:
Timestamp:
Jun 13, 2022, 6:00:05 PM (3 years ago)
Author:
Ross Kirsling
Message:

jsc.exe --module-file should understand Windows paths
https://bugs.webkit.org/show_bug.cgi?id=241518

Reviewed by Yusuke Suzuki.

jsc.cpp's module loader was written without any accommodation for Windows, so:

  1. On Windows, recognize C:\foo as an absolute path and .\foo and ..\foo as dotted relative paths (allowing '/' too).
  2. On all platforms, stop misusing the URL(base, relative) constructor. This isn't the way to add file:/// to an abspath.

This ensures that module tests are able to run well on Windows.

  • Source/JavaScriptCore/jsc.cpp:

(isAbsolutePath): Added.
(isDottedRelativePath): Added.
(absoluteFileURL): Renamed from absolutePath.
(GlobalObject::moduleLoaderImportModule):
(GlobalObject::moduleLoaderResolve):
(JSC_DEFINE_HOST_FUNCTION):
(computeFilePath):
(runWithOptions):

Canonical link: https://commits.webkit.org/251514@main

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jsc.cpp

    r295428 r295509  
    845845}
    846846
    847 static URL absolutePath(const String& fileName)
    848 {
     847// FIXME: We may wish to support module specifiers beginning with a (back)slash on Windows. We could either:
     848// - align with V8 and SM:  treat '/foo' as './foo'
     849// - align with PowerShell: treat '/foo' as 'C:/foo'
     850static bool isAbsolutePath(StringView path)
     851{
     852#if OS(WINDOWS)
     853    // Just look for local drives like C:\.
     854    return path.length() > 2 && isASCIIAlpha(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/');
     855#else
     856    return path.startsWith('/');
     857#endif
     858}
     859
     860static bool isDottedRelativePath(StringView path)
     861{
     862#if OS(WINDOWS)
     863    auto length = path.length();
     864    if (length < 2 || path[0] != '.')
     865        return false;
     866
     867    if (path[1] == '/' || path[1] == '\\')
     868        return true;
     869
     870    return length > 2 && path[1] == '.' && (path[2] == '/' || path[2] == '\\');
     871#else
     872    return path.startsWith("./"_s) || path.startsWith("../"_s);
     873#endif
     874}
     875
     876static URL absoluteFileURL(const String& fileName)
     877{
     878    if (isAbsolutePath(fileName))
     879        return URL::fileURLWithFileSystemPath(fileName);
     880
    849881    auto directoryName = currentWorkingDirectory();
    850882    if (!directoryName.isValid())
     
    873905        RELEASE_AND_RETURN(scope, rejectWithError(createError(globalObject, makeString("Could not resolve the referrer's path '", referrer.string(), "', while trying to resolve module '", specifier, "'."))));
    874906
    875     if (!specifier.startsWith('/') && !specifier.startsWith("./"_s) && !specifier.startsWith("../"_s))
    876         RELEASE_AND_RETURN(scope, rejectWithError(createTypeError(globalObject, makeString("Module specifier, '"_s, specifier, "' does not start with \"/\", \"./\", or \"../\". Referenced from: "_s, referrer.fileSystemPath()))));
    877 
    878     URL moduleURL(referrer, specifier);
     907    bool specifierIsAbsolute = isAbsolutePath(specifier);
     908    if (!specifierIsAbsolute && !isDottedRelativePath(specifier))
     909        RELEASE_AND_RETURN(scope, rejectWithError(createTypeError(globalObject, makeString("Module specifier, '"_s, specifier, "' is not absolute and does not start with \"./\" or \"../\". Referenced from: "_s, referrer.fileSystemPath()))));
     910
     911    auto moduleURL = specifierIsAbsolute ? URL::fileURLWithFileSystemPath(specifier) : URL(referrer, specifier);
    879912    if (!moduleURL.isLocalFile())
    880913        RELEASE_AND_RETURN(scope, rejectWithError(createError(globalObject, makeString("Module url, '", moduleURL.string(), "' does not map to a local file."))));
     
    900933    auto resolvePath = [&] (const URL& directoryURL) -> Identifier {
    901934        String specifier = key.impl();
    902         if (!specifier.startsWith('/') && !specifier.startsWith("./"_s) && !specifier.startsWith("../"_s)) {
    903             throwTypeError(globalObject, scope, makeString("Module specifier, '"_s, specifier, "' does not start with \"/\", \"./\", or \"../\". Referenced from: "_s, directoryURL.fileSystemPath()));
     935        bool specifierIsAbsolute = isAbsolutePath(specifier);
     936        if (!specifierIsAbsolute && !isDottedRelativePath(specifier)) {
     937            throwTypeError(globalObject, scope, makeString("Module specifier, '"_s, specifier, "' is not absolute and does not start with \"./\" or \"../\". Referenced from: "_s, directoryURL.fileSystemPath()));
    904938            return { };
    905939        }
     
    910944        }
    911945
    912         URL resolvedURL(directoryURL, specifier);
     946        auto resolvedURL = specifierIsAbsolute ? URL::fileURLWithFileSystemPath(specifier) : URL(directoryURL, specifier);
    913947        if (!resolvedURL.isValid()) {
    914948            throwException(globalObject, scope, createError(globalObject, makeString("Resolved module url is not valid: ", resolvedURL.string())));
     
    15511585    StopWatch stopWatch;
    15521586    stopWatch.start();
    1553     evaluate(realm, jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception);
     1587    evaluate(realm, jscSource(script, SourceOrigin { absoluteFileURL(fileName) }, fileName), JSValue(), exception);
    15541588    stopWatch.stop();
    15551589
     
    16131647        }
    16141648    } else
    1615         path = absolutePath(fileName);
     1649        path = absoluteFileURL(fileName);
    16161650    return path;
    16171651}
     
    17031737
    17041738    JSValue syntaxException;
    1705     bool validSyntax = checkSyntax(globalObject, jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException);
     1739    bool validSyntax = checkSyntax(globalObject, jscSource(script, SourceOrigin { absoluteFileURL(fileName) }, fileName), &syntaxException);
    17061740    stopWatch.stop();
    17071741
     
    32523286
    32533287            if (isModule) {
    3254                 // If the passed file isn't an absolute path append "./" so the module loader doesn't think this is a bare-name specifier.
    3255                 fileName = fileName.startsWith('/') ? fileName : makeString("./", fileName);
     3288                // If necessary, prepend "./" so the module loader doesn't think this is a bare-name specifier.
     3289                fileName = isAbsolutePath(fileName) || isDottedRelativePath(fileName) ? fileName : makeString('.', pathSeparator(), fileName);
    32563290                promise = loadAndEvaluateModule(globalObject, fileName, jsUndefined(), jsUndefined());
    32573291                RETURN_IF_EXCEPTION(scope, void());
     
    32703304
    32713305        bool isLastFile = i == scripts.size() - 1;
    3272         SourceOrigin sourceOrigin { absolutePath(fileName) };
     3306        SourceOrigin sourceOrigin { absoluteFileURL(fileName) };
    32733307        if (isModule) {
    32743308            if (!promise) {
Note: See TracChangeset for help on using the changeset viewer.