Skip to content
2 changes: 1 addition & 1 deletion .licenses/npm/fast-xml-parser.dep.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions __tests__/distributors/jetbrains-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import type {IncomingMessage} from 'http';
import {Readable} from 'stream';

import manifestData from '../data/jetbrains.json' with {type: 'json'};
import os from 'os';

// Mock @actions/core before importing source modules that depend on it
jest.unstable_mockModule('@actions/core', () => ({
Expand Down Expand Up @@ -81,6 +80,7 @@ describe('getAvailableVersions', () => {
jest.setTimeout(10_000);

let spyHttpClient: any;
let spyHttpClientHead: any;
let spyCoreError: any;
const originalGitHubToken = process.env.GITHUB_TOKEN;

Expand All @@ -93,6 +93,10 @@ describe('getAvailableVersions', () => {
headers: {},
result: []
});
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
spyHttpClientHead.mockResolvedValue({
message: {statusCode: 200}
} as any);

// Mock core.error to suppress error logs
spyCoreError = core.error as jest.Mock;
Expand Down Expand Up @@ -133,9 +137,7 @@ describe('getAvailableVersions', () => {
const availableVersions = await distribution['getAvailableVersions']();
expect(availableVersions).not.toBeNull();

const length =
os.platform() === 'win32' ? manifestData.length : manifestData.length + 2;
expect(availableVersions.length).toBe(length);
expect(availableVersions.length).toBe(manifestData.length + 2);
}, 10_000);

it('continues a stable request after an all-prerelease page', async () => {
Expand Down Expand Up @@ -358,6 +360,7 @@ describe('getAvailableVersions', () => {

it('retries a GitHub rate limit using Retry-After', async () => {
spyHttpClient.mockRestore();
spyHttpClientHead.mockRestore();
const sleep = jest.fn(async () => undefined);
const requestRaw = jest
.spyOn(HttpClient.prototype, 'requestRaw')
Expand Down
102 changes: 97 additions & 5 deletions dist/cleanup/767.index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18360,9 +18360,102 @@ function readAttributeStr(xmlData, i) {
}

/**
* Select all the attributes whether valid or invalid.
*/
const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g');
* Walk `attrStr` once, left to right, splitting it into attribute tokens.
*
* This replaces a regex that used to do the same job
* (`(\s*)([^\s=]+)(\s*=)?(\s*(['"])(([\s\S])*?)\5)?`). That regex led with an
* optional whitespace group followed by a required "non-whitespace" group.
* On a long run of whitespace that never resolves into an attribute name
* (e.g. a tag with thousands of trailing spaces before `>`), the engine
* backtracks the whitespace group one character at a time before giving up
* and moving to the next starting position — one full backtrack per
* position, which is quadratic in the length of the run.
*
* A single forward-only scan can never backtrack, so it can't be made slow
* this way no matter how much whitespace the input contains — it's always
* proportional to the length of the string, once.
*
* Each returned token mirrors the shape the old regex match array had, so
* the validation logic below (which reads token[1]..token[6]) didn't need
* to change:
* token.startIndex - where this token begins in attrStr
* token[1] - leading whitespace before the name
* token[2] - the attribute name
* token[3] - whitespace + '=' if present, else undefined
* token[4] - marker (any defined value) if a quoted value was found
* token[5] - the quote character used ('"' or "'")
* token[6] - the value's text, without the surrounding quotes
*
* A malformed leading character (e.g. a stray '=' with no name before it)
* is simply skipped over, one character at a time — the same outcome the
* old regex produced by failing to match at that position and retrying at
* the next one.
*/
function scanAttributeTokens(attrStr) {
const tokens = [];
const len = attrStr.length;
let i = 0;

while (i < len) {
const tokenStart = i;

// Leading whitespace before the name.
while (i < len && isWhiteSpace(attrStr[i])) i++;
if (i >= len) break; // trailing whitespace only — nothing left to read

if (attrStr[i] === '=') {
// No name before this '=' — not a valid attribute start. Move past
// just this one character and try again from the next position.
i = tokenStart + 1;
continue;
}

const leadingWs = attrStr.slice(tokenStart, i);

// Attribute name — everything up to the next whitespace or '='.
const nameStart = i;
while (i < len && !isWhiteSpace(attrStr[i]) && attrStr[i] !== '=') i++;
const name = attrStr.slice(nameStart, i);

// Optional whitespace + '='.
let equalsGroup; // whitespace + '=' text, or undefined if absent
let j = i;
while (j < len && isWhiteSpace(attrStr[j])) j++;
if (j < len && attrStr[j] === '=') {
equalsGroup = attrStr.slice(i, j + 1);
i = j + 1;
}

// Optional whitespace + quoted value.
let quoteChar;
let value;
let k = i;
while (k < len && isWhiteSpace(attrStr[k])) k++;
if (k < len && (attrStr[k] === '"' || attrStr[k] === "'")) {
const valueStart = k + 1;
const closeIdx = attrStr.indexOf(attrStr[k], valueStart);
if (closeIdx !== -1) {
quoteChar = attrStr[k];
value = attrStr.slice(valueStart, closeIdx);
i = closeIdx + 1;
}
// No closing quote found anywhere in the rest of the string — leave
// quoteChar/value undefined, same as the old regex's group failing
// to match a backreference-less run.
}

const token = { startIndex: tokenStart };
token[1] = leadingWs;
token[2] = name;
token[3] = equalsGroup;
token[4] = quoteChar !== undefined ? true : undefined;
token[5] = quoteChar;
token[6] = value;
tokens.push(token);
}

return tokens;
}

//attr, ="sd", a="amit's", a="sd"b="saf", ab cd=""

Expand All @@ -18371,7 +18464,7 @@ function validateAttributeString(attrStr, options) {

//if(attrStr.trim().length === 0) return true; //empty string

const matches = getAllMatches(attrStr, validAttrStrRegxp);
const matches = scanAttributeTokens(attrStr);
const attrNames = {};

for (let i = 0; i < matches.length; i++) {
Expand Down Expand Up @@ -18473,7 +18566,6 @@ function getLineNumberForPosition(xmlData, index) {
function getPositionFromMatch(match) {
return match.startIndex + match[1].length;
}

;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/fxp.js


Expand Down
100 changes: 96 additions & 4 deletions dist/setup/824.index.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,102 @@ function readAttributeStr(xmlData, i) {
}

/**
* Select all the attributes whether valid or invalid.
* Walk `attrStr` once, left to right, splitting it into attribute tokens.
*
* This replaces a regex that used to do the same job
* (`(\s*)([^\s=]+)(\s*=)?(\s*(['"])(([\s\S])*?)\5)?`). That regex led with an
* optional whitespace group followed by a required "non-whitespace" group.
* On a long run of whitespace that never resolves into an attribute name
* (e.g. a tag with thousands of trailing spaces before `>`), the engine
* backtracks the whitespace group one character at a time before giving up
* and moving to the next starting position — one full backtrack per
* position, which is quadratic in the length of the run.
*
* A single forward-only scan can never backtrack, so it can't be made slow
* this way no matter how much whitespace the input contains — it's always
* proportional to the length of the string, once.
*
* Each returned token mirrors the shape the old regex match array had, so
* the validation logic below (which reads token[1]..token[6]) didn't need
* to change:
* token.startIndex - where this token begins in attrStr
* token[1] - leading whitespace before the name
* token[2] - the attribute name
* token[3] - whitespace + '=' if present, else undefined
* token[4] - marker (any defined value) if a quoted value was found
* token[5] - the quote character used ('"' or "'")
* token[6] - the value's text, without the surrounding quotes
*
* A malformed leading character (e.g. a stray '=' with no name before it)
* is simply skipped over, one character at a time — the same outcome the
* old regex produced by failing to match at that position and retrying at
* the next one.
*/
const validAttrStrRegxp = new RegExp('(\\s*)([^\\s=]+)(\\s*=)?(\\s*([\'"])(([\\s\\S])*?)\\5)?', 'g');
function scanAttributeTokens(attrStr) {
const tokens = [];
const len = attrStr.length;
let i = 0;

while (i < len) {
const tokenStart = i;

// Leading whitespace before the name.
while (i < len && isWhiteSpace(attrStr[i])) i++;
if (i >= len) break; // trailing whitespace only — nothing left to read

if (attrStr[i] === '=') {
// No name before this '=' — not a valid attribute start. Move past
// just this one character and try again from the next position.
i = tokenStart + 1;
continue;
}

const leadingWs = attrStr.slice(tokenStart, i);

// Attribute name — everything up to the next whitespace or '='.
const nameStart = i;
while (i < len && !isWhiteSpace(attrStr[i]) && attrStr[i] !== '=') i++;
const name = attrStr.slice(nameStart, i);

// Optional whitespace + '='.
let equalsGroup; // whitespace + '=' text, or undefined if absent
let j = i;
while (j < len && isWhiteSpace(attrStr[j])) j++;
if (j < len && attrStr[j] === '=') {
equalsGroup = attrStr.slice(i, j + 1);
i = j + 1;
}

// Optional whitespace + quoted value.
let quoteChar;
let value;
let k = i;
while (k < len && isWhiteSpace(attrStr[k])) k++;
if (k < len && (attrStr[k] === '"' || attrStr[k] === "'")) {
const valueStart = k + 1;
const closeIdx = attrStr.indexOf(attrStr[k], valueStart);
if (closeIdx !== -1) {
quoteChar = attrStr[k];
value = attrStr.slice(valueStart, closeIdx);
i = closeIdx + 1;
}
// No closing quote found anywhere in the rest of the string — leave
// quoteChar/value undefined, same as the old regex's group failing
// to match a backreference-less run.
}

const token = { startIndex: tokenStart };
token[1] = leadingWs;
token[2] = name;
token[3] = equalsGroup;
token[4] = quoteChar !== undefined ? true : undefined;
token[5] = quoteChar;
token[6] = value;
tokens.push(token);
}

return tokens;
}

//attr, ="sd", a="amit's", a="sd"b="saf", ab cd=""

Expand All @@ -429,7 +522,7 @@ function validateAttributeString(attrStr, options) {

//if(attrStr.trim().length === 0) return true; //empty string

const matches = (0,_util_js__WEBPACK_IMPORTED_MODULE_0__/* .getAllMatches */ .Xe)(attrStr, validAttrStrRegxp);
const matches = scanAttributeTokens(attrStr);
const attrNames = {};

for (let i = 0; i < matches.length; i++) {
Expand Down Expand Up @@ -532,7 +625,6 @@ function getPositionFromMatch(match) {
return match.startIndex + match[1].length;
}


/***/ }),

/***/ 6009:
Expand Down
Loading
Loading