Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
architecture: ${{ steps.calculate_architecture.outputs.result }}
cache: ${{ matrix.node-version == '6.x' && '' || 'npm' }}
if: matrix.node-version == '6.x'
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
architecture: ${{ steps.calculate_architecture.outputs.result }}
cache: "npm"
if: matrix.node-version != '6.x'
- run: |
sudo npm i npm@6.x
sudo npm install --ignore-engines
Expand Down
87 changes: 64 additions & 23 deletions lib/LoaderRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,60 @@ function utf8BufferToString(buf) {
}

const PATH_QUERY_FRAGMENT_REGEXP =
/^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
/^(#?(?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
const ZERO_ESCAPE_REGEXP = /\0(.)/g;

/**
* @param {string} str the path with query and fragment
* @returns {{ path: string, query: string, fragment: string }} parsed parts
* @param {string} identifier identifier
* @returns {[string, string, string]} parsed identifier
*/
function parsePathQueryFragment(str) {
const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
return {
path: match[1].replace(/\0(.)/g, "$1"),
query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
fragment: match[3] || "",
};
function parseIdentifier(identifier) {
const firstEscape = identifier.indexOf("\0");

if (firstEscape < 0) {
// Fast path for inputs that don't use \0 escaping.
const queryStart = identifier.indexOf("?");
// Start at index 1 to ignore a possible leading hash.
const fragmentStart = identifier.indexOf("#");

if (fragmentStart < 0) {
if (queryStart < 0) {
// No fragment, no query
return [identifier, "", ""];
}

// Query, no fragment
return [
identifier.slice(0, queryStart),
identifier.slice(queryStart),
"",
];
}

if (queryStart < 0 || fragmentStart < queryStart) {
// Fragment, no query
return [
identifier.slice(0, fragmentStart),
"",
identifier.slice(fragmentStart),
];
}

// Query and fragment
return [
identifier.slice(0, queryStart),
identifier.slice(queryStart, fragmentStart),
identifier.slice(fragmentStart),
];
}

const match = PATH_QUERY_FRAGMENT_REGEXP.exec(identifier);

return [
match[1].replace(ZERO_ESCAPE_REGEXP, "$1"),
match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : "",
match[3] || "",
];
}

function dirname(path) {
Expand Down Expand Up @@ -73,10 +114,10 @@ function createLoaderObject(loader) {
},
set(value) {
if (typeof value === "string") {
const splittedRequest = parsePathQueryFragment(value);
obj.path = splittedRequest.path;
obj.query = splittedRequest.query;
obj.fragment = splittedRequest.fragment;
const [path, query, fragment] = parseIdentifier(value);
obj.path = path;
obj.query = query;
obj.fragment = fragment;
obj.options = undefined;
obj.ident = undefined;
} else {
Expand Down Expand Up @@ -298,7 +339,7 @@ function iteratePitchingLoaders(options, loaderContext, callback) {
}

module.exports.getContext = function getContext(resource) {
const { path } = parsePathQueryFragment(resource);
const [path] = parseIdentifier(resource);
return dirname(path);
};

Expand All @@ -314,10 +355,10 @@ module.exports.runLoaders = function runLoaders(options, callback) {
readResource(resource, callback);
}).bind(null, options.readResource || readFile);

const splittedResource = resource && parsePathQueryFragment(resource);
const resourcePath = splittedResource ? splittedResource.path : "";
const resourceQuery = splittedResource ? splittedResource.query : "";
const resourceFragment = splittedResource ? splittedResource.fragment : "";
const splittedResource = resource && parseIdentifier(resource);
const resourcePath = splittedResource ? splittedResource[0] : "";
const resourceQuery = splittedResource ? splittedResource[1] : "";
const resourceFragment = splittedResource ? splittedResource[2] : "";
const contextDirectory = resourcePath ? dirname(resourcePath) : null;

// execution state
Expand Down Expand Up @@ -378,15 +419,15 @@ module.exports.runLoaders = function runLoaders(options, callback) {
);
},
set(value) {
const splittedResource = value && parsePathQueryFragment(value);
const splittedResource = value && parseIdentifier(value);
loaderContext.resourcePath = splittedResource
? splittedResource.path
? splittedResource[0]
: undefined;
loaderContext.resourceQuery = splittedResource
? splittedResource.query
? splittedResource[1]
: undefined;
loaderContext.resourceFragment = splittedResource
? splittedResource.fragment
? splittedResource[2]
: undefined;
},
});
Expand Down
Loading