From b0d9292064e2cfb561474cfafa70b18868e14a95 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 13:26:54 +0000 Subject: [PATCH 01/23] Implement dot option --- README.md | 19 ++++++++++-- __tests__/labeler.test.ts | 18 +++++++++-- __tests__/main.test.ts | 63 ++++++++++++++++++++++++++++++--------- action.yml | 4 +++ src/labeler.ts | 32 ++++++++++++++------ 5 files changed, 109 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 2abc38b7..55bb580b 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,6 @@ repo: # Add '@domain/core' label to any change within the 'core' package @domain/core: -- package/core/* - package/core/**/* # Add 'test' label to any change to *.spec.js files within the source dir @@ -113,7 +112,23 @@ Various inputs are defined in [`action.yml`](action.yml) to let you configure th | `repo-token` | Token to use to authorize label changes. Typically the GITHUB_TOKEN secret | N/A | | `configuration-path` | The path to the label configuration file | `.github/labeler.yml` | | `sync-labels` | Whether or not to remove labels when matching files are reverted or no longer changed by the PR | `false` +| `dot` | Whether or not to auto-include paths starting with dot (e.g. `.github`) | `false` -# Contributions +When `dot` is disabled and you want to include _all_ files in a folder: + +```yml +label1: +- path/to/folder/**/* +- path/to/folder/**/.* +``` + +If `dot` is enabled: + +```yml +label1: +- path/to/folder/**/* +``` + +## Contributions Contributions are welcome! See the [Contributor's Guide](CONTRIBUTING.md). diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index 082ed672..c78bb407 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -15,15 +15,29 @@ const matchConfig = [{ any: ["*.txt"] }]; describe("checkGlobs", () => { it("returns true when our pattern does match changed files", () => { const changedFiles = ["foo.txt", "bar.txt"]; - const result = checkGlobs(changedFiles, matchConfig); + const result = checkGlobs(changedFiles, matchConfig, false); expect(result).toBeTruthy(); }); it("returns false when our pattern does not match changed files", () => { const changedFiles = ["foo.docx"]; - const result = checkGlobs(changedFiles, matchConfig); + const result = checkGlobs(changedFiles, matchConfig, false); expect(result).toBeFalsy(); }); + + it("returns false for a file starting with dot if `dot` option is false", () => { + const changedFiles = [".foo.txt"]; + const result = checkGlobs(changedFiles, matchConfig, false); + + expect(result).toBeFalsy(); + }); + + it("returns false for a file starting with dot if `dot` option is true", () => { + const changedFiles = [".foo.txt"]; + const result = checkGlobs(changedFiles, matchConfig, true); + + expect(result).toBeTruthy(); + }); }); diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index de145599..a39675de 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -18,10 +18,24 @@ const yamlFixtures = { "only_pdfs.yml": fs.readFileSync("__tests__/fixtures/only_pdfs.yml"), }; +const configureInput = ( + mockInput: Partial<{ + "repo-token": string; + "configuration-path": string; + "sync-labels": boolean; + dot: boolean; + }> +) => { + jest + .spyOn(core, "getInput") + .mockImplementation((name: string, ...opts) => mockInput[name]); +}; + afterAll(() => jest.restoreAllMocks()); describe("run", () => { - it("adds labels to PRs that match our glob patterns", async () => { + it("(with dot: false) adds labels to PRs that match our glob patterns", async () => { + configureInput({}); usingLabelerConfigYaml("only_pdfs.yml"); mockGitHubResponseChangedFiles("foo.pdf"); @@ -37,7 +51,36 @@ describe("run", () => { }); }); - it("does not add labels to PRs that do not match our glob patterns", async () => { + it("(with dot: true) adds labels to PRs that match our glob patterns", async () => { + configureInput({ dot: true }); + usingLabelerConfigYaml("only_pdfs.yml"); + mockGitHubResponseChangedFiles(".foo.pdf"); + + await run(); + + expect(removeLabelMock).toHaveBeenCalledTimes(0); + expect(addLabelsMock).toHaveBeenCalledTimes(1); + expect(addLabelsMock).toHaveBeenCalledWith({ + owner: "monalisa", + repo: "helloworld", + issue_number: 123, + labels: ["touched-a-pdf-file"], + }); + }); + + it("(with dot: false) does not add labels to PRs that do not match our glob patterns", async () => { + configureInput({}); + usingLabelerConfigYaml("only_pdfs.yml"); + mockGitHubResponseChangedFiles(".foo.pdf"); + + await run(); + + expect(removeLabelMock).toHaveBeenCalledTimes(0); + expect(addLabelsMock).toHaveBeenCalledTimes(0); + }); + + it("(with dot: true) does not add labels to PRs that do not match our glob patterns", async () => { + configureInput({ dot: true }); usingLabelerConfigYaml("only_pdfs.yml"); mockGitHubResponseChangedFiles("foo.txt"); @@ -48,15 +91,11 @@ describe("run", () => { }); it("(with sync-labels: true) it deletes preexisting PR labels that no longer match the glob pattern", async () => { - let mockInput = { + configureInput({ "repo-token": "foo", "configuration-path": "bar", "sync-labels": true, - }; - - jest - .spyOn(core, "getInput") - .mockImplementation((name: string, ...opts) => mockInput[name]); + }); usingLabelerConfigYaml("only_pdfs.yml"); mockGitHubResponseChangedFiles("foo.txt"); @@ -79,15 +118,11 @@ describe("run", () => { }); it("(with sync-labels: false) it issues no delete calls even when there are preexisting PR labels that no longer match the glob pattern", async () => { - let mockInput = { + configureInput({ "repo-token": "foo", "configuration-path": "bar", "sync-labels": false, - }; - - jest - .spyOn(core, "getInput") - .mockImplementation((name: string, ...opts) => mockInput[name]); + }); usingLabelerConfigYaml("only_pdfs.yml"); mockGitHubResponseChangedFiles("foo.txt"); diff --git a/action.yml b/action.yml index 16e71a8d..9cddef1c 100644 --- a/action.yml +++ b/action.yml @@ -12,6 +12,10 @@ inputs: description: 'Whether or not to remove labels when matching files are reverted' default: false required: false + dot: + description: 'Whether or not to auto-include paths starting with dot (e.g. `.github`)' + default: false + required: false runs: using: 'node12' diff --git a/src/labeler.ts b/src/labeler.ts index 59cf23f3..9d603d90 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -16,6 +16,7 @@ export async function run() { const token = core.getInput("repo-token", { required: true }); const configPath = core.getInput("configuration-path", { required: true }); const syncLabels = !!core.getInput("sync-labels", { required: false }); + const dot = !!core.getInput("dot", { required: false }); const prNumber = getPrNumber(); if (!prNumber) { @@ -42,7 +43,7 @@ export async function run() { const labelsToRemove: string[] = []; for (const [label, globs] of labelGlobs.entries()) { core.debug(`processing ${label}`); - if (checkGlobs(changedFiles, globs)) { + if (checkGlobs(changedFiles, globs, dot)) { labels.push(label); } else if (pullRequest.labels.find((l) => l.name === label)) { labelsToRemove.push(label); @@ -157,12 +158,13 @@ function printPattern(matcher: IMinimatch): string { export function checkGlobs( changedFiles: string[], - globs: StringOrMatchConfig[] + globs: StringOrMatchConfig[], + dot: boolean ): boolean { for (const glob of globs) { core.debug(` checking pattern ${JSON.stringify(glob)}`); const matchConfig = toMatchConfig(glob); - if (checkMatch(changedFiles, matchConfig)) { + if (checkMatch(changedFiles, matchConfig, dot)) { return true; } } @@ -184,8 +186,12 @@ function isMatch(changedFile: string, matchers: IMinimatch[]): boolean { } // equivalent to "Array.some()" but expanded for debugging and clarity -function checkAny(changedFiles: string[], globs: string[]): boolean { - const matchers = globs.map((g) => new Minimatch(g)); +function checkAny( + changedFiles: string[], + globs: string[], + dot: boolean +): boolean { + const matchers = globs.map((g) => new Minimatch(g, { dot })); core.debug(` checking "any" patterns`); for (const changedFile of changedFiles) { if (isMatch(changedFile, matchers)) { @@ -199,7 +205,11 @@ function checkAny(changedFiles: string[], globs: string[]): boolean { } // equivalent to "Array.every()" but expanded for debugging and clarity -function checkAll(changedFiles: string[], globs: string[]): boolean { +function checkAll( + changedFiles: string[], + globs: string[], + dot: boolean +): boolean { const matchers = globs.map((g) => new Minimatch(g)); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { @@ -213,15 +223,19 @@ function checkAll(changedFiles: string[], globs: string[]): boolean { return true; } -function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean { +function checkMatch( + changedFiles: string[], + matchConfig: MatchConfig, + dot: boolean +): boolean { if (matchConfig.all !== undefined) { - if (!checkAll(changedFiles, matchConfig.all)) { + if (!checkAll(changedFiles, matchConfig.all, dot)) { return false; } } if (matchConfig.any !== undefined) { - if (!checkAny(changedFiles, matchConfig.any)) { + if (!checkAny(changedFiles, matchConfig.any, dot)) { return false; } } From 6a0b7265cb13a476a705b5151e783160b18d9743 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 13:29:12 +0000 Subject: [PATCH 02/23] Rebuild --- dist/index.js | 331 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 261 insertions(+), 70 deletions(-) diff --git a/dist/index.js b/dist/index.js index a4b5fdf0..484cad16 100644 --- a/dist/index.js +++ b/dist/index.js @@ -46,6 +46,7 @@ function run() { const token = core.getInput("repo-token", { required: true }); const configPath = core.getInput("configuration-path", { required: true }); const syncLabels = !!core.getInput("sync-labels", { required: false }); + const dot = !!core.getInput("dot", { required: false }); const prNumber = getPrNumber(); if (!prNumber) { console.log("Could not get pull request number from context, exiting"); @@ -64,7 +65,7 @@ function run() { const labelsToRemove = []; for (const [label, globs] of labelGlobs.entries()) { core.debug(`processing ${label}`); - if (checkGlobs(changedFiles, globs)) { + if (checkGlobs(changedFiles, globs, dot)) { labels.push(label); } else if (pullRequest.labels.find((l) => l.name === label)) { @@ -154,11 +155,11 @@ function toMatchConfig(config) { function printPattern(matcher) { return (matcher.negate ? "!" : "") + matcher.pattern; } -function checkGlobs(changedFiles, globs) { +function checkGlobs(changedFiles, globs, dot) { for (const glob of globs) { core.debug(` checking pattern ${JSON.stringify(glob)}`); const matchConfig = toMatchConfig(glob); - if (checkMatch(changedFiles, matchConfig)) { + if (checkMatch(changedFiles, matchConfig, dot)) { return true; } } @@ -178,8 +179,8 @@ function isMatch(changedFile, matchers) { return true; } // equivalent to "Array.some()" but expanded for debugging and clarity -function checkAny(changedFiles, globs) { - const matchers = globs.map((g) => new minimatch_1.Minimatch(g)); +function checkAny(changedFiles, globs, dot) { + const matchers = globs.map((g) => new minimatch_1.Minimatch(g, { dot })); core.debug(` checking "any" patterns`); for (const changedFile of changedFiles) { if (isMatch(changedFile, matchers)) { @@ -191,7 +192,7 @@ function checkAny(changedFiles, globs) { return false; } // equivalent to "Array.every()" but expanded for debugging and clarity -function checkAll(changedFiles, globs) { +function checkAll(changedFiles, globs, dot) { const matchers = globs.map((g) => new minimatch_1.Minimatch(g)); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { @@ -203,14 +204,14 @@ function checkAll(changedFiles, globs) { core.debug(` "all" patterns matched all files`); return true; } -function checkMatch(changedFiles, matchConfig) { +function checkMatch(changedFiles, matchConfig, dot) { if (matchConfig.all !== undefined) { - if (!checkAll(changedFiles, matchConfig.all)) { + if (!checkAll(changedFiles, matchConfig.all, dot)) { return false; } } if (matchConfig.any !== undefined) { - if (!checkAny(changedFiles, matchConfig.any)) { + if (!checkAny(changedFiles, matchConfig.any, dot)) { return false; } } @@ -266,7 +267,7 @@ var __importStar = (this && this.__importStar) || function (mod) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.issue = exports.issueCommand = void 0; -const os = __importStar(__nccwpck_require__(2087)); +const os = __importStar(__nccwpck_require__(2037)); const utils_1 = __nccwpck_require__(5278); /** * Commands @@ -373,12 +374,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; +exports.getIDToken = exports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.notice = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getMultilineInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0; const command_1 = __nccwpck_require__(7351); const file_command_1 = __nccwpck_require__(717); const utils_1 = __nccwpck_require__(5278); -const os = __importStar(__nccwpck_require__(2087)); -const path = __importStar(__nccwpck_require__(5622)); +const os = __importStar(__nccwpck_require__(2037)); +const path = __importStar(__nccwpck_require__(1017)); +const oidc_utils_1 = __nccwpck_require__(8041); /** * The code to exit an action */ @@ -551,19 +553,30 @@ exports.debug = debug; /** * Adds an error issue * @param message error issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. */ -function error(message) { - command_1.issue('error', message instanceof Error ? message.toString() : message); +function error(message, properties = {}) { + command_1.issueCommand('error', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); } exports.error = error; /** - * Adds an warning issue + * Adds a warning issue * @param message warning issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. */ -function warning(message) { - command_1.issue('warning', message instanceof Error ? message.toString() : message); +function warning(message, properties = {}) { + command_1.issueCommand('warning', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); } exports.warning = warning; +/** + * Adds a notice issue + * @param message notice issue message. Errors will be converted to string via toString() + * @param properties optional properties to add to the annotation. + */ +function notice(message, properties = {}) { + command_1.issueCommand('notice', utils_1.toCommandProperties(properties), message instanceof Error ? message.toString() : message); +} +exports.notice = notice; /** * Writes info to log with console.log. * @param message info message @@ -636,6 +649,12 @@ function getState(name) { return process.env[`STATE_${name}`] || ''; } exports.getState = getState; +function getIDToken(aud) { + return __awaiter(this, void 0, void 0, function* () { + return yield oidc_utils_1.OidcClient.getIDToken(aud); + }); +} +exports.getIDToken = getIDToken; //# sourceMappingURL=core.js.map /***/ }), @@ -669,8 +688,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.issueCommand = void 0; // We use any as a valid input type /* eslint-disable @typescript-eslint/no-explicit-any */ -const fs = __importStar(__nccwpck_require__(5747)); -const os = __importStar(__nccwpck_require__(2087)); +const fs = __importStar(__nccwpck_require__(7147)); +const os = __importStar(__nccwpck_require__(2037)); const utils_1 = __nccwpck_require__(5278); function issueCommand(command, message) { const filePath = process.env[`GITHUB_${command}`]; @@ -689,6 +708,90 @@ exports.issueCommand = issueCommand; /***/ }), +/***/ 8041: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.OidcClient = void 0; +const http_client_1 = __nccwpck_require__(9925); +const auth_1 = __nccwpck_require__(3702); +const core_1 = __nccwpck_require__(2186); +class OidcClient { + static createHttpClient(allowRetry = true, maxRetry = 10) { + const requestOptions = { + allowRetries: allowRetry, + maxRetries: maxRetry + }; + return new http_client_1.HttpClient('actions/oidc-client', [new auth_1.BearerCredentialHandler(OidcClient.getRequestToken())], requestOptions); + } + static getRequestToken() { + const token = process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN']; + if (!token) { + throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_TOKEN env variable'); + } + return token; + } + static getIDTokenUrl() { + const runtimeUrl = process.env['ACTIONS_ID_TOKEN_REQUEST_URL']; + if (!runtimeUrl) { + throw new Error('Unable to get ACTIONS_ID_TOKEN_REQUEST_URL env variable'); + } + return runtimeUrl; + } + static getCall(id_token_url) { + var _a; + return __awaiter(this, void 0, void 0, function* () { + const httpclient = OidcClient.createHttpClient(); + const res = yield httpclient + .getJson(id_token_url) + .catch(error => { + throw new Error(`Failed to get ID Token. \n + Error Code : ${error.statusCode}\n + Error Message: ${error.result.message}`); + }); + const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value; + if (!id_token) { + throw new Error('Response json body do not have ID Token field'); + } + return id_token; + }); + } + static getIDToken(audience) { + return __awaiter(this, void 0, void 0, function* () { + try { + // New ID Token is requested from action service + let id_token_url = OidcClient.getIDTokenUrl(); + if (audience) { + const encodedAudience = encodeURIComponent(audience); + id_token_url = `${id_token_url}&audience=${encodedAudience}`; + } + core_1.debug(`ID token url is ${id_token_url}`); + const id_token = yield OidcClient.getCall(id_token_url); + core_1.setSecret(id_token); + return id_token; + } + catch (error) { + throw new Error(`Error message: ${error.message}`); + } + }); + } +} +exports.OidcClient = OidcClient; +//# sourceMappingURL=oidc-utils.js.map + +/***/ }), + /***/ 5278: /***/ ((__unused_webpack_module, exports) => { @@ -697,7 +800,7 @@ exports.issueCommand = issueCommand; // We use any as a valid input type /* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.toCommandValue = void 0; +exports.toCommandProperties = exports.toCommandValue = void 0; /** * Sanitizes an input into a string so it can be passed into issueCommand safely * @param input input to sanitize into a string @@ -712,6 +815,26 @@ function toCommandValue(input) { return JSON.stringify(input); } exports.toCommandValue = toCommandValue; +/** + * + * @param annotationProperties + * @returns The command properties to send with the actual annotation command + * See IssueCommandProperties: https://github.com/actions/runner/blob/main/src/Runner.Worker/ActionCommandManager.cs#L646 + */ +function toCommandProperties(annotationProperties) { + if (!Object.keys(annotationProperties).length) { + return {}; + } + return { + title: annotationProperties.title, + file: annotationProperties.file, + line: annotationProperties.startLine, + endLine: annotationProperties.endLine, + col: annotationProperties.startColumn, + endColumn: annotationProperties.endColumn + }; +} +exports.toCommandProperties = toCommandProperties; //# sourceMappingURL=utils.js.map /***/ }), @@ -723,8 +846,8 @@ exports.toCommandValue = toCommandValue; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Context = void 0; -const fs_1 = __nccwpck_require__(5747); -const os_1 = __nccwpck_require__(2087); +const fs_1 = __nccwpck_require__(7147); +const os_1 = __nccwpck_require__(2037); class Context { /** * Hydrate the context from the environment @@ -929,6 +1052,72 @@ function getOctokitOptions(token, options) { exports.getOctokitOptions = getOctokitOptions; //# sourceMappingURL=utils.js.map +/***/ }), + +/***/ 3702: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +class BasicCredentialHandler { + constructor(username, password) { + this.username = username; + this.password = password; + } + prepareRequest(options) { + options.headers['Authorization'] = + 'Basic ' + + Buffer.from(this.username + ':' + this.password).toString('base64'); + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.BasicCredentialHandler = BasicCredentialHandler; +class BearerCredentialHandler { + constructor(token) { + this.token = token; + } + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options) { + options.headers['Authorization'] = 'Bearer ' + this.token; + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.BearerCredentialHandler = BearerCredentialHandler; +class PersonalAccessTokenCredentialHandler { + constructor(token) { + this.token = token; + } + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options) { + options.headers['Authorization'] = + 'Basic ' + Buffer.from('PAT:' + this.token).toString('base64'); + } + // This handler cannot handle 401 + canHandleAuthentication(response) { + return false; + } + handleAuthentication(httpClient, requestInfo, objs) { + return null; + } +} +exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHandler; + + /***/ }), /***/ 9925: @@ -937,8 +1126,8 @@ exports.getOctokitOptions = getOctokitOptions; "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -const http = __nccwpck_require__(8605); -const https = __nccwpck_require__(7211); +const http = __nccwpck_require__(3685); +const https = __nccwpck_require__(5687); const pm = __nccwpck_require__(6443); let tunnel; var HttpCodes; @@ -7662,7 +7851,7 @@ module.exports = __nccwpck_require__(1035); -module.exports = __nccwpck_require__(2011).extend({ +module.exports = (__nccwpck_require__(2011).extend)({ implicit: [ __nccwpck_require__(9212), __nccwpck_require__(6104) @@ -7718,7 +7907,7 @@ module.exports = new Schema({ -module.exports = __nccwpck_require__(8562).extend({ +module.exports = (__nccwpck_require__(8562).extend)({ implicit: [ __nccwpck_require__(721), __nccwpck_require__(4993), @@ -8723,7 +8912,7 @@ minimatch.Minimatch = Minimatch var path = { sep: '/' } try { - path = __nccwpck_require__(5622) + path = __nccwpck_require__(1017) } catch (er) {} var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} @@ -9655,11 +9844,11 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } -var Stream = _interopDefault(__nccwpck_require__(2413)); -var http = _interopDefault(__nccwpck_require__(8605)); -var Url = _interopDefault(__nccwpck_require__(8835)); -var https = _interopDefault(__nccwpck_require__(7211)); -var zlib = _interopDefault(__nccwpck_require__(8761)); +var Stream = _interopDefault(__nccwpck_require__(2781)); +var http = _interopDefault(__nccwpck_require__(3685)); +var Url = _interopDefault(__nccwpck_require__(7310)); +var https = _interopDefault(__nccwpck_require__(5687)); +var zlib = _interopDefault(__nccwpck_require__(9796)); // Based on https://github.com/tmpvar/jsdom/blob/aa85b2abf07766ff7bf5c1f6daafb3726f2f2db5/lib/jsdom/living/blob.js @@ -9810,7 +9999,7 @@ FetchError.prototype.name = 'FetchError'; let convert; try { - convert = __nccwpck_require__(2877).convert; + convert = (__nccwpck_require__(2877).convert); } catch (e) {} const INTERNALS = Symbol('Body internals'); @@ -11293,7 +11482,7 @@ fetch.Promise = global.Promise; module.exports = exports = fetch; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.default = exports; +exports["default"] = exports; exports.Headers = Headers; exports.Request = Request; exports.Response = Response; @@ -11365,13 +11554,13 @@ module.exports = __nccwpck_require__(4219); "use strict"; -var net = __nccwpck_require__(1631); -var tls = __nccwpck_require__(4016); -var http = __nccwpck_require__(8605); -var https = __nccwpck_require__(7211); -var events = __nccwpck_require__(8614); -var assert = __nccwpck_require__(2357); -var util = __nccwpck_require__(1669); +var net = __nccwpck_require__(1808); +var tls = __nccwpck_require__(4404); +var http = __nccwpck_require__(3685); +var https = __nccwpck_require__(5687); +var events = __nccwpck_require__(2361); +var assert = __nccwpck_require__(9491); +var util = __nccwpck_require__(3837); exports.httpOverHttp = httpOverHttp; @@ -11705,107 +11894,107 @@ module.exports = eval("require")("encoding"); /***/ }), -/***/ 2357: +/***/ 9491: /***/ ((module) => { "use strict"; -module.exports = require("assert");; +module.exports = require("assert"); /***/ }), -/***/ 8614: +/***/ 2361: /***/ ((module) => { "use strict"; -module.exports = require("events");; +module.exports = require("events"); /***/ }), -/***/ 5747: +/***/ 7147: /***/ ((module) => { "use strict"; -module.exports = require("fs");; +module.exports = require("fs"); /***/ }), -/***/ 8605: +/***/ 3685: /***/ ((module) => { "use strict"; -module.exports = require("http");; +module.exports = require("http"); /***/ }), -/***/ 7211: +/***/ 5687: /***/ ((module) => { "use strict"; -module.exports = require("https");; +module.exports = require("https"); /***/ }), -/***/ 1631: +/***/ 1808: /***/ ((module) => { "use strict"; -module.exports = require("net");; +module.exports = require("net"); /***/ }), -/***/ 2087: +/***/ 2037: /***/ ((module) => { "use strict"; -module.exports = require("os");; +module.exports = require("os"); /***/ }), -/***/ 5622: +/***/ 1017: /***/ ((module) => { "use strict"; -module.exports = require("path");; +module.exports = require("path"); /***/ }), -/***/ 2413: +/***/ 2781: /***/ ((module) => { "use strict"; -module.exports = require("stream");; +module.exports = require("stream"); /***/ }), -/***/ 4016: +/***/ 4404: /***/ ((module) => { "use strict"; -module.exports = require("tls");; +module.exports = require("tls"); /***/ }), -/***/ 8835: +/***/ 7310: /***/ ((module) => { "use strict"; -module.exports = require("url");; +module.exports = require("url"); /***/ }), -/***/ 1669: +/***/ 3837: /***/ ((module) => { "use strict"; -module.exports = require("util");; +module.exports = require("util"); /***/ }), -/***/ 8761: +/***/ 9796: /***/ ((module) => { "use strict"; -module.exports = require("zlib");; +module.exports = require("zlib"); /***/ }) @@ -11844,7 +12033,9 @@ module.exports = require("zlib");; /************************************************************************/ /******/ /* webpack/runtime/compat */ /******/ -/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/";/************************************************************************/ +/******/ if (typeof __nccwpck_require__ !== 'undefined') __nccwpck_require__.ab = __dirname + "/"; +/******/ +/************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. (() => { @@ -11853,7 +12044,7 @@ var exports = __webpack_exports__; Object.defineProperty(exports, "__esModule", ({ value: true })); const labeler_1 = __nccwpck_require__(5272); -labeler_1.run(); +(0, labeler_1.run)(); })(); From 409a5a20951f76279e286a79a16ab740ab24ce81 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 13:34:07 +0000 Subject: [PATCH 03/23] Fix typo in test caption --- __tests__/labeler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index c78bb407..12dbd66c 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -34,7 +34,7 @@ describe("checkGlobs", () => { expect(result).toBeFalsy(); }); - it("returns false for a file starting with dot if `dot` option is true", () => { + it("returns true for a file starting with dot if `dot` option is true", () => { const changedFiles = [".foo.txt"]; const result = checkGlobs(changedFiles, matchConfig, true); From 920e9b6169a8eac836b64f9a4d3530a7442d5982 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 13:47:49 +0000 Subject: [PATCH 04/23] Add comments --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 55bb580b..b1663848 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,12 @@ From a boolean logic perspective, top-level match objects are `OR`-ed together a ```yml # Add 'label1' to any changes within 'example' folder or any subfolders +# (this does not apply to files starting with dot by default – see inputs table below) label1: - example/**/* # Add 'label2' to any file changes within 'example2' folder +# (this does not apply to files starting with dot by default – see inputs table below) label2: example2/* ``` From 8b8677b4ce798702964ad29c999034023823fa83 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 13:54:21 +0000 Subject: [PATCH 05/23] Improve warning --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1663848..ac1102aa 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,19 @@ label1: From a boolean logic perspective, top-level match objects are `OR`-ed together and individual match rules within an object are `AND`-ed. Combined with `!` negation, you can write complex matching rules. +> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) for apply globs. +> For historical reasons, paths starting with dot (e.g. `.github`) are not matched by default. +> You need to set `dot: true` to change this behavior. +> See [Inputs](#inputs) table below for details. + #### Basic Examples ```yml # Add 'label1' to any changes within 'example' folder or any subfolders -# (this does not apply to files starting with dot by default – see inputs table below) label1: - example/**/* # Add 'label2' to any file changes within 'example2' folder -# (this does not apply to files starting with dot by default – see inputs table below) label2: example2/* ``` From e05b7c1927677f76eaddd2b570f5fe402b4e9b38 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 14:45:39 +0000 Subject: [PATCH 06/23] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac1102aa..52380463 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ label1: From a boolean logic perspective, top-level match objects are `OR`-ed together and individual match rules within an object are `AND`-ed. Combined with `!` negation, you can write complex matching rules. -> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) for apply globs. +> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) to apply globs. > For historical reasons, paths starting with dot (e.g. `.github`) are not matched by default. > You need to set `dot: true` to change this behavior. > See [Inputs](#inputs) table below for details. From f3632d3e9f22e1ca1b266820319a46870ab143f7 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Fri, 4 Feb 2022 14:47:58 +0000 Subject: [PATCH 07/23] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52380463..e6fc422e 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ label1: From a boolean logic perspective, top-level match objects are `OR`-ed together and individual match rules within an object are `AND`-ed. Combined with `!` negation, you can write complex matching rules. -> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) to apply globs. +> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) to apply glob patterns. > For historical reasons, paths starting with dot (e.g. `.github`) are not matched by default. > You need to set `dot: true` to change this behavior. > See [Inputs](#inputs) table below for details. From 20251547f994a34235a76d9ad00a1ed0cece839f Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 5 Oct 2022 14:37:24 +0100 Subject: [PATCH 08/23] Simplify glob --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 33648db6..2c943bac 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Automatically label new pull requests based on the paths of files being changed. Create a `.github/labeler.yml` file with a list of labels and [minimatch](https://github.com/isaacs/minimatch) globs to match to apply the label. -The key is the name of the label in your repository that you want to add (eg: "merge conflict", "needs-updating") and the value is the path (glob) of the changed files (eg: `src/**/*`, `tests/*.spec.js`) or a match object. +The key is the name of the label in your repository that you want to add (eg: "merge conflict", "needs-updating") and the value is the path (glob) of the changed files (eg: `src/**`, `tests/*.spec.js`) or a match object. #### Match Object @@ -57,7 +57,7 @@ From a boolean logic perspective, top-level match objects are `OR`-ed together a ```yml # Add 'label1' to any changes within 'example' folder or any subfolders label1: -- example/**/* +- example/** # Add 'label2' to any file changes within 'example2' folder label2: example2/* @@ -72,7 +72,7 @@ repo: # Add '@domain/core' label to any change within the 'core' package @domain/core: -- package/core/**/* +- package/core/** # Add 'test' label to any change to *.spec.js files within the source dir test: @@ -80,7 +80,7 @@ test: # Add 'source' label to any change to src files within the source dir EXCEPT for the docs sub-folder source: -- any: ['src/**/*', '!src/docs/*'] +- any: ['src/**', '!src/docs/*'] # Add 'frontend` label to any change to *.js files as long as the `main.js` hasn't changed frontend: @@ -134,7 +134,7 @@ If `dot` is enabled: ```yml label1: -- path/to/folder/**/* +- path/to/folder/** ``` ## Contributions From 305cfeb74cfa5c4878bf6418b4815a4106f2e345 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Mon, 16 Jan 2023 17:40:12 +0000 Subject: [PATCH 09/23] Rebuild --- dist/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/index.js b/dist/index.js index de32171b..b555ecc8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -47,10 +47,10 @@ const minimatch_1 = __nccwpck_require__(3973); function run() { return __awaiter(this, void 0, void 0, function* () { try { - const token = core.getInput("repo-token", { required: true }); - const configPath = core.getInput("configuration-path", { required: true }); - const syncLabels = !!core.getInput("sync-labels", { required: false }); - const dot = !!core.getInput("dot", { required: false }); + const token = core.getInput('repo-token', { required: true }); + const configPath = core.getInput('configuration-path', { required: true }); + const syncLabels = !!core.getInput('sync-labels', { required: false }); + const dot = !!core.getInput('dot', { required: false }); const prNumber = getPrNumber(); if (!prNumber) { console.log('Could not get pull request number from context, exiting'); @@ -184,7 +184,7 @@ function isMatch(changedFile, matchers) { } // equivalent to "Array.some()" but expanded for debugging and clarity function checkAny(changedFiles, globs, dot) { - const matchers = globs.map((g) => new minimatch_1.Minimatch(g, { dot })); + const matchers = globs.map(g => new minimatch_1.Minimatch(g, { dot })); core.debug(` checking "any" patterns`); for (const changedFile of changedFiles) { if (isMatch(changedFile, matchers)) { @@ -197,7 +197,7 @@ function checkAny(changedFiles, globs, dot) { } // equivalent to "Array.every()" but expanded for debugging and clarity function checkAll(changedFiles, globs, dot) { - const matchers = globs.map((g) => new minimatch_1.Minimatch(g)); + const matchers = globs.map(g => new minimatch_1.Minimatch(g)); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { @@ -15252,4 +15252,4 @@ const labeler_1 = __nccwpck_require__(5272); module.exports = __webpack_exports__; /******/ })() -; +; \ No newline at end of file From b28379f6ed6d84fb1ae3bcd818d608a4c3257424 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Mon, 27 Mar 2023 09:44:05 +0100 Subject: [PATCH 10/23] Cleanup --- __tests__/main.test.ts | 37 +++++++++++-------------------------- dist/index.js | 2 +- src/labeler.ts | 2 +- 3 files changed, 13 insertions(+), 28 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index d6a84688..551317d9 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -22,13 +22,16 @@ const configureInput = ( mockInput: Partial<{ 'repo-token': string; 'configuration-path': string; - 'sync-labels': boolean; - dot: boolean; + 'sync-labels': string; + dot: string; }> ) => { jest .spyOn(core, 'getInput') .mockImplementation((name: string, ...opts) => mockInput[name]); + jest + .spyOn(core, 'getBooleanInput') + .mockImplementation((name: string, ...opts) => mockInput[name] === 'true'); }; afterAll(() => jest.restoreAllMocks()); @@ -52,7 +55,7 @@ describe('run', () => { }); it('(with dot: true) adds labels to PRs that match our glob patterns', async () => { - configureInput({dot: true}); + configureInput({dot: 'true'}); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('.foo.pdf'); @@ -80,7 +83,7 @@ describe('run', () => { }); it('(with dot: true) does not add labels to PRs that do not match our glob patterns', async () => { - configureInput({dot: true}); + configureInput({dot: 'true'}); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('foo.txt'); @@ -91,20 +94,11 @@ describe('run', () => { }); it('(with sync-labels: true) it deletes preexisting PR labels that no longer match the glob pattern', async () => { - const mockInput = { + configureInput({ 'repo-token': 'foo', 'configuration-path': 'bar', 'sync-labels': 'true' - }; - - jest - .spyOn(core, 'getInput') - .mockImplementation((name: string, ...opts) => mockInput[name]); - jest - .spyOn(core, 'getBooleanInput') - .mockImplementation( - (name: string, ...opts) => mockInput[name] === 'true' - ); + }); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('foo.txt'); @@ -127,20 +121,11 @@ describe('run', () => { }); it('(with sync-labels: false) it issues no delete calls even when there are preexisting PR labels that no longer match the glob pattern', async () => { - const mockInput = { + configureInput({ 'repo-token': 'foo', 'configuration-path': 'bar', 'sync-labels': 'false' - }; - - jest - .spyOn(core, 'getInput') - .mockImplementation((name: string, ...opts) => mockInput[name]); - jest - .spyOn(core, 'getBooleanInput') - .mockImplementation( - (name: string, ...opts) => mockInput[name] === 'true' - ); + }); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('foo.txt'); diff --git a/dist/index.js b/dist/index.js index ae651d96..7087f8e2 100644 --- a/dist/index.js +++ b/dist/index.js @@ -50,7 +50,7 @@ function run() { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', { required: true }); const syncLabels = core.getBooleanInput('sync-labels'); - const dot = !!core.getInput('dot', { required: false }); + const dot = !!core.getBooleanInput('dot', { required: false }); const prNumber = getPrNumber(); if (!prNumber) { core.info('Could not get pull request number from context, exiting'); diff --git a/src/labeler.ts b/src/labeler.ts index a996fc31..4fb70fb6 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -16,7 +16,7 @@ export async function run() { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', {required: true}); const syncLabels = core.getBooleanInput('sync-labels'); - const dot = !!core.getInput('dot', {required: false}); + const dot = !!core.getBooleanInput('dot', {required: false}); const prNumber = getPrNumber(); if (!prNumber) { From a7cc8a62ef0fcdcf8ff1516986c74c7f46ef6fa4 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Mon, 27 Mar 2023 09:47:52 +0100 Subject: [PATCH 11/23] Fix --- dist/index.js | 2 +- src/labeler.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/index.js b/dist/index.js index 7087f8e2..6a872db8 100644 --- a/dist/index.js +++ b/dist/index.js @@ -197,7 +197,7 @@ function checkAny(changedFiles, globs, dot) { } // equivalent to "Array.every()" but expanded for debugging and clarity function checkAll(changedFiles, globs, dot) { - const matchers = globs.map(g => new minimatch_1.Minimatch(g)); + const matchers = globs.map(g => new minimatch_1.Minimatch(g), { dot }); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { diff --git a/src/labeler.ts b/src/labeler.ts index 4fb70fb6..8788deb9 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -210,7 +210,7 @@ function checkAll( globs: string[], dot: boolean ): boolean { - const matchers = globs.map(g => new Minimatch(g)); + const matchers = globs.map(g => new Minimatch(g), {dot}); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { From 092c979868165ecf5f5709e508a5994b4342c3e7 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:44:56 +0100 Subject: [PATCH 12/23] Update src/labeler.ts Co-authored-by: AndreiLobanovich --- src/labeler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/labeler.ts b/src/labeler.ts index 59fac1fd..cd220bd6 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -210,7 +210,7 @@ function checkAll( globs: string[], dot: boolean ): boolean { - const matchers = globs.map(g => new Minimatch(g), {dot}); + const matchers = globs.map(g => new Minimatch(g, {dot})); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { From 60f44e7cf124e8d4ac709e4ad28d89681a83cacc Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:45:27 +0100 Subject: [PATCH 13/23] Fix unrelated test --- __tests__/main.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 7c8b8f46..1c49c2ab 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -31,7 +31,7 @@ const configureInput = ( .mockImplementation((name: string, ...opts) => mockInput[name]); jest .spyOn(core, 'getBooleanInput') - .mockImplementation((name: string, ...opts) => mockInput[name] === 'true'); + .mockImplementation((name: string, ...opts) => mockInput[name] === true); }; afterAll(() => jest.restoreAllMocks()); @@ -124,7 +124,7 @@ describe('run', () => { configureInput({ 'repo-token': 'foo', 'configuration-path': 'bar', - 'sync-labels': true + 'sync-labels': false }); usingLabelerConfigYaml('only_pdfs.yml'); From 97762039fea73f29b805ca76dfdfc8ca2344bcb8 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:46:05 +0100 Subject: [PATCH 14/23] Update build --- dist/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/index.js b/dist/index.js index 8702aa1b..ca024d77 100644 --- a/dist/index.js +++ b/dist/index.js @@ -197,7 +197,7 @@ function checkAny(changedFiles, globs, dot) { } // equivalent to "Array.every()" but expanded for debugging and clarity function checkAll(changedFiles, globs, dot) { - const matchers = globs.map(g => new minimatch_1.Minimatch(g), { dot }); + const matchers = globs.map(g => new minimatch_1.Minimatch(g, { dot })); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { From a27020c13528542173505c78211cc59cd398b18d Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:49:55 +0100 Subject: [PATCH 15/23] Undo unwanted change in diff --- src/labeler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/labeler.ts b/src/labeler.ts index cd220bd6..3bbe23c2 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -15,7 +15,7 @@ export async function run() { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', {required: true}); - const syncLabels = core.getBooleanInput('sync-labels', {required: false}); + const syncLabels = !!core.getBooleanInput('sync-labels', {required: false}); const dot = !!core.getBooleanInput('dot', {required: false}); const prNumber = getPrNumber(); From 44414dbc7d9734f29bd24f3cb8d6c986953b2854 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:50:00 +0100 Subject: [PATCH 16/23] Fix tests --- __tests__/main.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 1c49c2ab..2e5bb190 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -23,7 +23,7 @@ const configureInput = ( 'repo-token': string; 'configuration-path': string; 'sync-labels': boolean; - dot: string; + dot: boolean; }> ) => { jest @@ -55,7 +55,7 @@ describe('run', () => { }); it('(with dot: true) adds labels to PRs that match our glob patterns', async () => { - configureInput({dot: 'true'}); + configureInput({dot: true}); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('.foo.pdf'); @@ -83,7 +83,7 @@ describe('run', () => { }); it('(with dot: true) does not add labels to PRs that do not match our glob patterns', async () => { - configureInput({dot: 'true'}); + configureInput({dot: true}); usingLabelerConfigYaml('only_pdfs.yml'); mockGitHubResponseChangedFiles('foo.txt'); From 673c7e22a751603e5da666203a12de384b9030d1 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:50:27 +0100 Subject: [PATCH 17/23] Rebuild --- dist/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/index.js b/dist/index.js index ca024d77..185c4f2d 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49,7 +49,7 @@ function run() { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', { required: true }); - const syncLabels = core.getBooleanInput('sync-labels', { required: false }); + const syncLabels = !!core.getBooleanInput('sync-labels', { required: false }); const dot = !!core.getBooleanInput('dot', { required: false }); const prNumber = getPrNumber(); if (!prNumber) { From e3b3815c8deeb2f522f910d63d1ddbeaac97a0f7 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 01:54:22 +0100 Subject: [PATCH 18/23] Further diff reduction --- __tests__/main.test.ts | 3 --- dist/index.js | 4 ++-- src/labeler.ts | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index 2e5bb190..7aaf87d4 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -29,9 +29,6 @@ const configureInput = ( jest .spyOn(core, 'getInput') .mockImplementation((name: string, ...opts) => mockInput[name]); - jest - .spyOn(core, 'getBooleanInput') - .mockImplementation((name: string, ...opts) => mockInput[name] === true); }; afterAll(() => jest.restoreAllMocks()); diff --git a/dist/index.js b/dist/index.js index 185c4f2d..6f64c9e1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49,8 +49,8 @@ function run() { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', { required: true }); - const syncLabels = !!core.getBooleanInput('sync-labels', { required: false }); - const dot = !!core.getBooleanInput('dot', { required: false }); + const syncLabels = !!core.getInput('sync-labels', { required: false }); + const dot = !!core.getInput('dot', { required: false }); const prNumber = getPrNumber(); if (!prNumber) { core.info('Could not get pull request number from context, exiting'); diff --git a/src/labeler.ts b/src/labeler.ts index 3bbe23c2..79f11a3d 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -15,8 +15,8 @@ export async function run() { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', {required: true}); - const syncLabels = !!core.getBooleanInput('sync-labels', {required: false}); - const dot = !!core.getBooleanInput('dot', {required: false}); + const syncLabels = !!core.getInput('sync-labels', {required: false}); + const dot = !!core.getInput('dot', {required: false}); const prNumber = getPrNumber(); if (!prNumber) { From 54d434dac50244b6843390a0d6987c951785b0f3 Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 17:23:26 +0100 Subject: [PATCH 19/23] Remove `required: false` --- src/labeler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/labeler.ts b/src/labeler.ts index 79f11a3d..592959f0 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -15,8 +15,8 @@ export async function run() { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', {required: true}); - const syncLabels = !!core.getInput('sync-labels', {required: false}); - const dot = !!core.getInput('dot', {required: false}); + const syncLabels = !!core.getInput('sync-labels'); + const dot = !!core.getInput('dot'); const prNumber = getPrNumber(); if (!prNumber) { From 59d3310a72970937ed9bbdc21c5d457d287fb50e Mon Sep 17 00:00:00 2001 From: Alexander Kachkaev Date: Wed, 31 May 2023 17:32:09 +0100 Subject: [PATCH 20/23] Rebuild --- dist/index.js | 2475 +++++++++++++++++++++++++++++++------------------ 1 file changed, 1547 insertions(+), 928 deletions(-) diff --git a/dist/index.js b/dist/index.js index 6f64c9e1..364d6e9f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -43,14 +43,14 @@ exports.checkGlobs = exports.run = void 0; const core = __importStar(__nccwpck_require__(2186)); const github = __importStar(__nccwpck_require__(5438)); const yaml = __importStar(__nccwpck_require__(1917)); -const minimatch_1 = __nccwpck_require__(3973); +const minimatch_1 = __nccwpck_require__(2002); function run() { return __awaiter(this, void 0, void 0, function* () { try { const token = core.getInput('repo-token'); const configPath = core.getInput('configuration-path', { required: true }); - const syncLabels = !!core.getInput('sync-labels', { required: false }); - const dot = !!core.getInput('dot', { required: false }); + const syncLabels = !!core.getInput('sync-labels'); + const dot = !!core.getInput('dot'); const prNumber = getPrNumber(); if (!prNumber) { core.info('Could not get pull request number from context, exiting'); @@ -9229,931 +9229,6 @@ module.exports = new Type('tag:yaml.org,2002:timestamp', { }); -/***/ }), - -/***/ 4917: -/***/ ((module) => { - -const isWindows = typeof process === 'object' && - process && - process.platform === 'win32' -module.exports = isWindows ? { sep: '\\' } : { sep: '/' } - - -/***/ }), - -/***/ 3973: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -const minimatch = module.exports = (p, pattern, options = {}) => { - assertValidPattern(pattern) - - // shortcut: comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - return false - } - - return new Minimatch(pattern, options).match(p) -} - -module.exports = minimatch - -const path = __nccwpck_require__(4917) -minimatch.sep = path.sep - -const GLOBSTAR = Symbol('globstar **') -minimatch.GLOBSTAR = GLOBSTAR -const expand = __nccwpck_require__(3717) - -const plTypes = { - '!': { open: '(?:(?!(?:', close: '))[^/]*?)'}, - '?': { open: '(?:', close: ')?' }, - '+': { open: '(?:', close: ')+' }, - '*': { open: '(?:', close: ')*' }, - '@': { open: '(?:', close: ')' } -} - -// any single thing other than / -// don't need to escape / when using new RegExp() -const qmark = '[^/]' - -// * => any number of characters -const star = qmark + '*?' - -// ** when dots are allowed. Anything goes, except .. and . -// not (^ or / followed by one or two dots followed by $ or /), -// followed by anything, any number of times. -const twoStarDot = '(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?' - -// not a ^ or / followed by a dot, -// followed by anything, any number of times. -const twoStarNoDot = '(?:(?!(?:\\\/|^)\\.).)*?' - -// "abc" -> { a:true, b:true, c:true } -const charSet = s => s.split('').reduce((set, c) => { - set[c] = true - return set -}, {}) - -// characters that need to be escaped in RegExp. -const reSpecials = charSet('().*{}+?[]^$\\!') - -// characters that indicate we have to add the pattern start -const addPatternStartSet = charSet('[.(') - -// normalizes slashes. -const slashSplit = /\/+/ - -minimatch.filter = (pattern, options = {}) => - (p, i, list) => minimatch(p, pattern, options) - -const ext = (a, b = {}) => { - const t = {} - Object.keys(a).forEach(k => t[k] = a[k]) - Object.keys(b).forEach(k => t[k] = b[k]) - return t -} - -minimatch.defaults = def => { - if (!def || typeof def !== 'object' || !Object.keys(def).length) { - return minimatch - } - - const orig = minimatch - - const m = (p, pattern, options) => orig(p, pattern, ext(def, options)) - m.Minimatch = class Minimatch extends orig.Minimatch { - constructor (pattern, options) { - super(pattern, ext(def, options)) - } - } - m.Minimatch.defaults = options => orig.defaults(ext(def, options)).Minimatch - m.filter = (pattern, options) => orig.filter(pattern, ext(def, options)) - m.defaults = options => orig.defaults(ext(def, options)) - m.makeRe = (pattern, options) => orig.makeRe(pattern, ext(def, options)) - m.braceExpand = (pattern, options) => orig.braceExpand(pattern, ext(def, options)) - m.match = (list, pattern, options) => orig.match(list, pattern, ext(def, options)) - - return m -} - - - - - -// Brace expansion: -// a{b,c}d -> abd acd -// a{b,}c -> abc ac -// a{0..3}d -> a0d a1d a2d a3d -// a{b,c{d,e}f}g -> abg acdfg acefg -// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg -// -// Invalid sets are not expanded. -// a{2..}b -> a{2..}b -// a{b}c -> a{b}c -minimatch.braceExpand = (pattern, options) => braceExpand(pattern, options) - -const braceExpand = (pattern, options = {}) => { - assertValidPattern(pattern) - - // Thanks to Yeting Li for - // improving this regexp to avoid a ReDOS vulnerability. - if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { - // shortcut. no need to expand. - return [pattern] - } - - return expand(pattern) -} - -const MAX_PATTERN_LENGTH = 1024 * 64 -const assertValidPattern = pattern => { - if (typeof pattern !== 'string') { - throw new TypeError('invalid pattern') - } - - if (pattern.length > MAX_PATTERN_LENGTH) { - throw new TypeError('pattern is too long') - } -} - -// parse a component of the expanded set. -// At this point, no pattern may contain "/" in it -// so we're going to return a 2d array, where each entry is the full -// pattern, split on '/', and then turned into a regular expression. -// A regexp is made at the end which joins each array with an -// escaped /, and another full one which joins each regexp with |. -// -// Following the lead of Bash 4.1, note that "**" only has special meaning -// when it is the *only* thing in a path portion. Otherwise, any series -// of * is equivalent to a single *. Globstar behavior is enabled by -// default, and can be disabled by setting options.noglobstar. -const SUBPARSE = Symbol('subparse') - -minimatch.makeRe = (pattern, options) => - new Minimatch(pattern, options || {}).makeRe() - -minimatch.match = (list, pattern, options = {}) => { - const mm = new Minimatch(pattern, options) - list = list.filter(f => mm.match(f)) - if (mm.options.nonull && !list.length) { - list.push(pattern) - } - return list -} - -// replace stuff like \* with * -const globUnescape = s => s.replace(/\\(.)/g, '$1') -const charUnescape = s => s.replace(/\\([^-\]])/g, '$1') -const regExpEscape = s => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') -const braExpEscape = s => s.replace(/[[\]\\]/g, '\\$&') - -class Minimatch { - constructor (pattern, options) { - assertValidPattern(pattern) - - if (!options) options = {} - - this.options = options - this.set = [] - this.pattern = pattern - this.windowsPathsNoEscape = !!options.windowsPathsNoEscape || - options.allowWindowsEscape === false - if (this.windowsPathsNoEscape) { - this.pattern = this.pattern.replace(/\\/g, '/') - } - this.regexp = null - this.negate = false - this.comment = false - this.empty = false - this.partial = !!options.partial - - // make the set of regexps etc. - this.make() - } - - debug () {} - - make () { - const pattern = this.pattern - const options = this.options - - // empty patterns and comments match nothing. - if (!options.nocomment && pattern.charAt(0) === '#') { - this.comment = true - return - } - if (!pattern) { - this.empty = true - return - } - - // step 1: figure out negation, etc. - this.parseNegate() - - // step 2: expand braces - let set = this.globSet = this.braceExpand() - - if (options.debug) this.debug = (...args) => console.error(...args) - - this.debug(this.pattern, set) - - // step 3: now we have a set, so turn each one into a series of path-portion - // matching patterns. - // These will be regexps, except in the case of "**", which is - // set to the GLOBSTAR object for globstar behavior, - // and will not contain any / characters - set = this.globParts = set.map(s => s.split(slashSplit)) - - this.debug(this.pattern, set) - - // glob --> regexps - set = set.map((s, si, set) => s.map(this.parse, this)) - - this.debug(this.pattern, set) - - // filter out everything that didn't compile properly. - set = set.filter(s => s.indexOf(false) === -1) - - this.debug(this.pattern, set) - - this.set = set - } - - parseNegate () { - if (this.options.nonegate) return - - const pattern = this.pattern - let negate = false - let negateOffset = 0 - - for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) { - negate = !negate - negateOffset++ - } - - if (negateOffset) this.pattern = pattern.slice(negateOffset) - this.negate = negate - } - - // set partial to true to test if, for example, - // "/a/b" matches the start of "/*/b/*/d" - // Partial means, if you run out of file before you run - // out of pattern, then that's fine, as long as all - // the parts match. - matchOne (file, pattern, partial) { - var options = this.options - - this.debug('matchOne', - { 'this': this, file: file, pattern: pattern }) - - this.debug('matchOne', file.length, pattern.length) - - for (var fi = 0, - pi = 0, - fl = file.length, - pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi++, pi++) { - this.debug('matchOne loop') - var p = pattern[pi] - var f = file[fi] - - this.debug(pattern, p, f) - - // should be impossible. - // some invalid regexp stuff in the set. - /* istanbul ignore if */ - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - var pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for (; fi < fl; fi++) { - if (file[fi] === '.' || file[fi] === '..' || - (!options.dot && file[fi].charAt(0) === '.')) return false - } - return true - } - - // ok, let's see if we can swallow whatever we can. - while (fr < fl) { - var swallowee = file[fr] - - this.debug('\nglobstar while', file, fr, pattern, pr, swallowee) - - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === '.' || swallowee === '..' || - (!options.dot && swallowee.charAt(0) === '.')) { - this.debug('dot detected!', file, fr, pattern, pr) - break - } - - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr++ - } - } - - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - /* istanbul ignore if */ - if (partial) { - // ran out of file - this.debug('\n>>> no match, partial?', file, fr, pattern, pr) - if (fr === fl) return true - } - return false - } - - // something other than ** - // non-magic patterns just have to match exactly - // patterns with magic have been turned into regexps. - var hit - if (typeof p === 'string') { - hit = f === p - this.debug('string match', p, f, hit) - } else { - hit = f.match(p) - this.debug('pattern match', p, f, hit) - } - - if (!hit) return false - } - - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - - // now either we fell off the end of the pattern, or we're done. - if (fi === fl && pi === pl) { - // ran out of pattern and filename at the same time. - // an exact hit! - return true - } else if (fi === fl) { - // ran out of file, but still had pattern left. - // this is ok if we're doing the match as part of - // a glob fs traversal. - return partial - } else /* istanbul ignore else */ if (pi === pl) { - // ran out of pattern, still have file left. - // this is only acceptable if we're on the very last - // empty segment of a file with a trailing slash. - // a/* should match a/b/ - return (fi === fl - 1) && (file[fi] === '') - } - - // should be unreachable. - /* istanbul ignore next */ - throw new Error('wtf?') - } - - braceExpand () { - return braceExpand(this.pattern, this.options) - } - - parse (pattern, isSub) { - assertValidPattern(pattern) - - const options = this.options - - // shortcuts - if (pattern === '**') { - if (!options.noglobstar) - return GLOBSTAR - else - pattern = '*' - } - if (pattern === '') return '' - - let re = '' - let hasMagic = !!options.nocase - let escaping = false - // ? => one single character - const patternListStack = [] - const negativeLists = [] - let stateChar - let inClass = false - let reClassStart = -1 - let classStart = -1 - let cs - let pl - let sp - // . and .. never match anything that doesn't start with ., - // even when options.dot is set. - const patternStart = pattern.charAt(0) === '.' ? '' // anything - // not (start or / followed by . or .. followed by / or end) - : options.dot ? '(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))' - : '(?!\\.)' - - const clearStateChar = () => { - if (stateChar) { - // we had some state-tracking character - // that wasn't consumed by this pass. - switch (stateChar) { - case '*': - re += star - hasMagic = true - break - case '?': - re += qmark - hasMagic = true - break - default: - re += '\\' + stateChar - break - } - this.debug('clearStateChar %j %j', stateChar, re) - stateChar = false - } - } - - for (let i = 0, c; (i < pattern.length) && (c = pattern.charAt(i)); i++) { - this.debug('%s\t%s %s %j', pattern, i, re, c) - - // skip over any that are escaped. - if (escaping) { - /* istanbul ignore next - completely not allowed, even escaped. */ - if (c === '/') { - return false - } - - if (reSpecials[c]) { - re += '\\' - } - re += c - escaping = false - continue - } - - switch (c) { - /* istanbul ignore next */ - case '/': { - // Should already be path-split by now. - return false - } - - case '\\': - if (inClass && pattern.charAt(i + 1) === '-') { - re += c - continue - } - - clearStateChar() - escaping = true - continue - - // the various stateChar values - // for the "extglob" stuff. - case '?': - case '*': - case '+': - case '@': - case '!': - this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c) - - // all of those are literals inside a class, except that - // the glob [!a] means [^a] in regexp - if (inClass) { - this.debug(' in class') - if (c === '!' && i === classStart + 1) c = '^' - re += c - continue - } - - // if we already have a stateChar, then it means - // that there was something like ** or +? in there. - // Handle the stateChar, then proceed with this one. - this.debug('call clearStateChar %j', stateChar) - clearStateChar() - stateChar = c - // if extglob is disabled, then +(asdf|foo) isn't a thing. - // just clear the statechar *now*, rather than even diving into - // the patternList stuff. - if (options.noext) clearStateChar() - continue - - case '(': - if (inClass) { - re += '(' - continue - } - - if (!stateChar) { - re += '\\(' - continue - } - - patternListStack.push({ - type: stateChar, - start: i - 1, - reStart: re.length, - open: plTypes[stateChar].open, - close: plTypes[stateChar].close - }) - // negation is (?:(?!js)[^/]*) - re += stateChar === '!' ? '(?:(?!(?:' : '(?:' - this.debug('plType %j %j', stateChar, re) - stateChar = false - continue - - case ')': - if (inClass || !patternListStack.length) { - re += '\\)' - continue - } - - clearStateChar() - hasMagic = true - pl = patternListStack.pop() - // negation is (?:(?!js)[^/]*) - // The others are (?:) - re += pl.close - if (pl.type === '!') { - negativeLists.push(pl) - } - pl.reEnd = re.length - continue - - case '|': - if (inClass || !patternListStack.length) { - re += '\\|' - continue - } - - clearStateChar() - re += '|' - continue - - // these are mostly the same in regexp and glob - case '[': - // swallow any state-tracking char before the [ - clearStateChar() - - if (inClass) { - re += '\\' + c - continue - } - - inClass = true - classStart = i - reClassStart = re.length - re += c - continue - - case ']': - // a right bracket shall lose its special - // meaning and represent itself in - // a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - if (i === classStart + 1 || !inClass) { - re += '\\' + c - continue - } - - // split where the last [ was, make sure we don't have - // an invalid re. if so, re-walk the contents of the - // would-be class to re-translate any characters that - // were passed through as-is - // TODO: It would probably be faster to determine this - // without a try/catch and a new RegExp, but it's tricky - // to do safely. For now, this is safe and works. - cs = pattern.substring(classStart + 1, i) - try { - RegExp('[' + braExpEscape(charUnescape(cs)) + ']') - // looks good, finish up the class. - re += c - } catch (er) { - // out of order ranges in JS are errors, but in glob syntax, - // they're just a range that matches nothing. - re = re.substring(0, reClassStart) + '(?:$.)' // match nothing ever - } - hasMagic = true - inClass = false - continue - - default: - // swallow any state char that wasn't consumed - clearStateChar() - - if (reSpecials[c] && !(c === '^' && inClass)) { - re += '\\' - } - - re += c - break - - } // switch - } // for - - // handle the case where we left a class open. - // "[abc" is valid, equivalent to "\[abc" - if (inClass) { - // split where the last [ was, and escape it - // this is a huge pita. We now have to re-walk - // the contents of the would-be class to re-translate - // any characters that were passed through as-is - cs = pattern.slice(classStart + 1) - sp = this.parse(cs, SUBPARSE) - re = re.substring(0, reClassStart) + '\\[' + sp[0] - hasMagic = hasMagic || sp[1] - } - - // handle the case where we had a +( thing at the *end* - // of the pattern. - // each pattern list stack adds 3 chars, and we need to go through - // and escape any | chars that were passed through as-is for the regexp. - // Go through and escape them, taking care not to double-escape any - // | chars that were already escaped. - for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) { - let tail - tail = re.slice(pl.reStart + pl.open.length) - this.debug('setting tail', re, pl) - // maybe some even number of \, then maybe 1 \, followed by a | - tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => { - /* istanbul ignore else - should already be done */ - if (!$2) { - // the | isn't already escaped, so escape it. - $2 = '\\' - } - - // need to escape all those slashes *again*, without escaping the - // one that we need for escaping the | character. As it works out, - // escaping an even number of slashes can be done by simply repeating - // it exactly after itself. That's why this trick works. - // - // I am sorry that you have to see this. - return $1 + $1 + $2 + '|' - }) - - this.debug('tail=%j\n %s', tail, tail, pl, re) - const t = pl.type === '*' ? star - : pl.type === '?' ? qmark - : '\\' + pl.type - - hasMagic = true - re = re.slice(0, pl.reStart) + t + '\\(' + tail - } - - // handle trailing things that only matter at the very end. - clearStateChar() - if (escaping) { - // trailing \\ - re += '\\\\' - } - - // only need to apply the nodot start if the re starts with - // something that could conceivably capture a dot - const addPatternStart = addPatternStartSet[re.charAt(0)] - - // Hack to work around lack of negative lookbehind in JS - // A pattern like: *.!(x).!(y|z) needs to ensure that a name - // like 'a.xyz.yz' doesn't match. So, the first negative - // lookahead, has to look ALL the way ahead, to the end of - // the pattern. - for (let n = negativeLists.length - 1; n > -1; n--) { - const nl = negativeLists[n] - - const nlBefore = re.slice(0, nl.reStart) - const nlFirst = re.slice(nl.reStart, nl.reEnd - 8) - let nlAfter = re.slice(nl.reEnd) - const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter - - // Handle nested stuff like *(*.js|!(*.json)), where open parens - // mean that we should *not* include the ) in the bit that is considered - // "after" the negated section. - const openParensBefore = nlBefore.split('(').length - 1 - let cleanAfter = nlAfter - for (let i = 0; i < openParensBefore; i++) { - cleanAfter = cleanAfter.replace(/\)[+*?]?/, '') - } - nlAfter = cleanAfter - - const dollar = nlAfter === '' && isSub !== SUBPARSE ? '$' : '' - re = nlBefore + nlFirst + nlAfter + dollar + nlLast - } - - // if the re is not "" at this point, then we need to make sure - // it doesn't match against an empty path part. - // Otherwise a/* will match a/, which it should not. - if (re !== '' && hasMagic) { - re = '(?=.)' + re - } - - if (addPatternStart) { - re = patternStart + re - } - - // parsing just a piece of a larger pattern. - if (isSub === SUBPARSE) { - return [re, hasMagic] - } - - // skip the regexp for non-magical patterns - // unescape anything in it, though, so that it'll be - // an exact match against a file etc. - if (!hasMagic) { - return globUnescape(pattern) - } - - const flags = options.nocase ? 'i' : '' - try { - return Object.assign(new RegExp('^' + re + '$', flags), { - _glob: pattern, - _src: re, - }) - } catch (er) /* istanbul ignore next - should be impossible */ { - // If it was an invalid regular expression, then it can't match - // anything. This trick looks for a character after the end of - // the string, which is of course impossible, except in multi-line - // mode, but it's not a /m regex. - return new RegExp('$.') - } - } - - makeRe () { - if (this.regexp || this.regexp === false) return this.regexp - - // at this point, this.set is a 2d array of partial - // pattern strings, or "**". - // - // It's better to use .match(). This function shouldn't - // be used, really, but it's pretty convenient sometimes, - // when you just want to work with a regex. - const set = this.set - - if (!set.length) { - this.regexp = false - return this.regexp - } - const options = this.options - - const twoStar = options.noglobstar ? star - : options.dot ? twoStarDot - : twoStarNoDot - const flags = options.nocase ? 'i' : '' - - // coalesce globstars and regexpify non-globstar patterns - // if it's the only item, then we just do one twoStar - // if it's the first, and there are more, prepend (\/|twoStar\/)? to next - // if it's the last, append (\/twoStar|) to previous - // if it's in the middle, append (\/|\/twoStar\/) to previous - // then filter out GLOBSTAR symbols - let re = set.map(pattern => { - pattern = pattern.map(p => - typeof p === 'string' ? regExpEscape(p) - : p === GLOBSTAR ? GLOBSTAR - : p._src - ).reduce((set, p) => { - if (!(set[set.length - 1] === GLOBSTAR && p === GLOBSTAR)) { - set.push(p) - } - return set - }, []) - pattern.forEach((p, i) => { - if (p !== GLOBSTAR || pattern[i-1] === GLOBSTAR) { - return - } - if (i === 0) { - if (pattern.length > 1) { - pattern[i+1] = '(?:\\\/|' + twoStar + '\\\/)?' + pattern[i+1] - } else { - pattern[i] = twoStar - } - } else if (i === pattern.length - 1) { - pattern[i-1] += '(?:\\\/|' + twoStar + ')?' - } else { - pattern[i-1] += '(?:\\\/|\\\/' + twoStar + '\\\/)' + pattern[i+1] - pattern[i+1] = GLOBSTAR - } - }) - return pattern.filter(p => p !== GLOBSTAR).join('/') - }).join('|') - - // must match entire pattern - // ending in a * or ** will make it less strict. - re = '^(?:' + re + ')$' - - // can match anything, as long as it's not this. - if (this.negate) re = '^(?!' + re + ').*$' - - try { - this.regexp = new RegExp(re, flags) - } catch (ex) /* istanbul ignore next - should be impossible */ { - this.regexp = false - } - return this.regexp - } - - match (f, partial = this.partial) { - this.debug('match', f, this.pattern) - // short-circuit in the case of busted things. - // comments, etc. - if (this.comment) return false - if (this.empty) return f === '' - - if (f === '/' && partial) return true - - const options = this.options - - // windows: need to use /, not \ - if (path.sep !== '/') { - f = f.split(path.sep).join('/') - } - - // treat the test path as a set of pathparts. - f = f.split(slashSplit) - this.debug(this.pattern, 'split', f) - - // just ONE of the pattern sets in this.set needs to match - // in order for it to be valid. If negating, then just one - // match means that we have failed. - // Either way, return on the first hit. - - const set = this.set - this.debug(this.pattern, 'set', set) - - // Find the basename of the path by looking for the last non-empty segment - let filename - for (let i = f.length - 1; i >= 0; i--) { - filename = f[i] - if (filename) break - } - - for (let i = 0; i < set.length; i++) { - const pattern = set[i] - let file = f - if (options.matchBase && pattern.length === 1) { - file = [filename] - } - const hit = this.matchOne(file, pattern, partial) - if (hit) { - if (options.flipNegate) return true - return !this.negate - } - } - - // didn't get any hits. this is success if it's a negative - // pattern, failure otherwise. - if (options.flipNegate) return false - return this.negate - } - - static defaults (def) { - return minimatch.defaults(def).Minimatch - } -} - -minimatch.Minimatch = Minimatch - - /***/ }), /***/ 467: @@ -15192,6 +14267,1550 @@ module.exports = require("zlib"); /***/ }), +/***/ 5822: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +// translate the various posix character classes into unicode properties +// this works across all unicode locales +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.parseClass = void 0; +// { : [, /u flag required, negated] +const posixClasses = { + '[:alnum:]': ['\\p{L}\\p{Nl}\\p{Nd}', true], + '[:alpha:]': ['\\p{L}\\p{Nl}', true], + '[:ascii:]': ['\\x' + '00-\\x' + '7f', false], + '[:blank:]': ['\\p{Zs}\\t', true], + '[:cntrl:]': ['\\p{Cc}', true], + '[:digit:]': ['\\p{Nd}', true], + '[:graph:]': ['\\p{Z}\\p{C}', true, true], + '[:lower:]': ['\\p{Ll}', true], + '[:print:]': ['\\p{C}', true], + '[:punct:]': ['\\p{P}', true], + '[:space:]': ['\\p{Z}\\t\\r\\n\\v\\f', true], + '[:upper:]': ['\\p{Lu}', true], + '[:word:]': ['\\p{L}\\p{Nl}\\p{Nd}\\p{Pc}', true], + '[:xdigit:]': ['A-Fa-f0-9', false], +}; +// only need to escape a few things inside of brace expressions +// escapes: [ \ ] - +const braceEscape = (s) => s.replace(/[[\]\\-]/g, '\\$&'); +// escape all regexp magic characters +const regexpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); +// everything has already been escaped, we just have to join +const rangesToString = (ranges) => ranges.join(''); +// takes a glob string at a posix brace expression, and returns +// an equivalent regular expression source, and boolean indicating +// whether the /u flag needs to be applied, and the number of chars +// consumed to parse the character class. +// This also removes out of order ranges, and returns ($.) if the +// entire class just no good. +const parseClass = (glob, position) => { + const pos = position; + /* c8 ignore start */ + if (glob.charAt(pos) !== '[') { + throw new Error('not in a brace expression'); + } + /* c8 ignore stop */ + const ranges = []; + const negs = []; + let i = pos + 1; + let sawStart = false; + let uflag = false; + let escaping = false; + let negate = false; + let endPos = pos; + let rangeStart = ''; + WHILE: while (i < glob.length) { + const c = glob.charAt(i); + if ((c === '!' || c === '^') && i === pos + 1) { + negate = true; + i++; + continue; + } + if (c === ']' && sawStart && !escaping) { + endPos = i + 1; + break; + } + sawStart = true; + if (c === '\\') { + if (!escaping) { + escaping = true; + i++; + continue; + } + // escaped \ char, fall through and treat like normal char + } + if (c === '[' && !escaping) { + // either a posix class, a collation equivalent, or just a [ + for (const [cls, [unip, u, neg]] of Object.entries(posixClasses)) { + if (glob.startsWith(cls, i)) { + // invalid, [a-[] is fine, but not [a-[:alpha]] + if (rangeStart) { + return ['$.', false, glob.length - pos, true]; + } + i += cls.length; + if (neg) + negs.push(unip); + else + ranges.push(unip); + uflag = uflag || u; + continue WHILE; + } + } + } + // now it's just a normal character, effectively + escaping = false; + if (rangeStart) { + // throw this range away if it's not valid, but others + // can still match. + if (c > rangeStart) { + ranges.push(braceEscape(rangeStart) + '-' + braceEscape(c)); + } + else if (c === rangeStart) { + ranges.push(braceEscape(c)); + } + rangeStart = ''; + i++; + continue; + } + // now might be the start of a range. + // can be either c-d or c-] or c] or c] at this point + if (glob.startsWith('-]', i + 1)) { + ranges.push(braceEscape(c + '-')); + i += 2; + continue; + } + if (glob.startsWith('-', i + 1)) { + rangeStart = c; + i += 2; + continue; + } + // not the start of a range, just a single character + ranges.push(braceEscape(c)); + i++; + } + if (endPos < i) { + // didn't see the end of the class, not a valid class, + // but might still be valid as a literal match. + return ['', false, 0, false]; + } + // if we got no ranges and no negates, then we have a range that + // cannot possibly match anything, and that poisons the whole glob + if (!ranges.length && !negs.length) { + return ['$.', false, glob.length - pos, true]; + } + // if we got one positive range, and it's a single character, then that's + // not actually a magic pattern, it's just that one literal character. + // we should not treat that as "magic", we should just return the literal + // character. [_] is a perfectly valid way to escape glob magic chars. + if (negs.length === 0 && + ranges.length === 1 && + /^\\?.$/.test(ranges[0]) && + !negate) { + const r = ranges[0].length === 2 ? ranges[0].slice(-1) : ranges[0]; + return [regexpEscape(r), false, endPos - pos, false]; + } + const sranges = '[' + (negate ? '^' : '') + rangesToString(ranges) + ']'; + const snegs = '[' + (negate ? '' : '^') + rangesToString(negs) + ']'; + const comb = ranges.length && negs.length + ? '(' + sranges + '|' + snegs + ')' + : ranges.length + ? sranges + : snegs; + return [comb, uflag, endPos - pos, true]; +}; +exports.parseClass = parseClass; +//# sourceMappingURL=brace-expressions.js.map + +/***/ }), + +/***/ 9004: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.escape = void 0; +/** + * Escape all magic characters in a glob pattern. + * + * If the {@link windowsPathsNoEscape | GlobOptions.windowsPathsNoEscape} + * option is used, then characters are escaped by wrapping in `[]`, because + * a magic character wrapped in a character class can only be satisfied by + * that exact character. In this mode, `\` is _not_ escaped, because it is + * not interpreted as a magic character, but instead as a path separator. + */ +const escape = (s, { windowsPathsNoEscape = false, } = {}) => { + // don't need to escape +@! because we escape the parens + // that make those magic, and escaping ! as [!] isn't valid, + // because [!]] is a valid glob class meaning not ']'. + return windowsPathsNoEscape + ? s.replace(/[?*()[\]]/g, '[$&]') + : s.replace(/[?*()[\]\\]/g, '\\$&'); +}; +exports.escape = escape; +//# sourceMappingURL=escape.js.map + +/***/ }), + +/***/ 2002: +/***/ (function(module, __unused_webpack_exports, __nccwpck_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +const index_js_1 = __importDefault(__nccwpck_require__(1953)); +module.exports = Object.assign(index_js_1.default, { default: index_js_1.default, minimatch: index_js_1.default }); +//# sourceMappingURL=index-cjs.js.map + +/***/ }), + +/***/ 1953: +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { + +"use strict"; + +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.unescape = exports.escape = exports.Minimatch = exports.match = exports.makeRe = exports.braceExpand = exports.defaults = exports.filter = exports.GLOBSTAR = exports.sep = exports.minimatch = void 0; +const brace_expansion_1 = __importDefault(__nccwpck_require__(3717)); +const brace_expressions_js_1 = __nccwpck_require__(5822); +const escape_js_1 = __nccwpck_require__(9004); +const unescape_js_1 = __nccwpck_require__(7305); +const minimatch = (p, pattern, options = {}) => { + assertValidPattern(pattern); + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + return false; + } + return new Minimatch(pattern, options).match(p); +}; +exports.minimatch = minimatch; +exports["default"] = exports.minimatch; +// Optimized checking for the most common glob patterns. +const starDotExtRE = /^\*+([^+@!?\*\[\(]*)$/; +const starDotExtTest = (ext) => (f) => !f.startsWith('.') && f.endsWith(ext); +const starDotExtTestDot = (ext) => (f) => f.endsWith(ext); +const starDotExtTestNocase = (ext) => { + ext = ext.toLowerCase(); + return (f) => !f.startsWith('.') && f.toLowerCase().endsWith(ext); +}; +const starDotExtTestNocaseDot = (ext) => { + ext = ext.toLowerCase(); + return (f) => f.toLowerCase().endsWith(ext); +}; +const starDotStarRE = /^\*+\.\*+$/; +const starDotStarTest = (f) => !f.startsWith('.') && f.includes('.'); +const starDotStarTestDot = (f) => f !== '.' && f !== '..' && f.includes('.'); +const dotStarRE = /^\.\*+$/; +const dotStarTest = (f) => f !== '.' && f !== '..' && f.startsWith('.'); +const starRE = /^\*+$/; +const starTest = (f) => f.length !== 0 && !f.startsWith('.'); +const starTestDot = (f) => f.length !== 0 && f !== '.' && f !== '..'; +const qmarksRE = /^\?+([^+@!?\*\[\(]*)?$/; +const qmarksTestNocase = ([$0, ext = '']) => { + const noext = qmarksTestNoExt([$0]); + if (!ext) + return noext; + ext = ext.toLowerCase(); + return (f) => noext(f) && f.toLowerCase().endsWith(ext); +}; +const qmarksTestNocaseDot = ([$0, ext = '']) => { + const noext = qmarksTestNoExtDot([$0]); + if (!ext) + return noext; + ext = ext.toLowerCase(); + return (f) => noext(f) && f.toLowerCase().endsWith(ext); +}; +const qmarksTestDot = ([$0, ext = '']) => { + const noext = qmarksTestNoExtDot([$0]); + return !ext ? noext : (f) => noext(f) && f.endsWith(ext); +}; +const qmarksTest = ([$0, ext = '']) => { + const noext = qmarksTestNoExt([$0]); + return !ext ? noext : (f) => noext(f) && f.endsWith(ext); +}; +const qmarksTestNoExt = ([$0]) => { + const len = $0.length; + return (f) => f.length === len && !f.startsWith('.'); +}; +const qmarksTestNoExtDot = ([$0]) => { + const len = $0.length; + return (f) => f.length === len && f !== '.' && f !== '..'; +}; +/* c8 ignore start */ +const defaultPlatform = (typeof process === 'object' && process + ? (typeof process.env === 'object' && + process.env && + process.env.__MINIMATCH_TESTING_PLATFORM__) || + process.platform + : 'posix'); +const path = { + win32: { sep: '\\' }, + posix: { sep: '/' }, +}; +/* c8 ignore stop */ +exports.sep = defaultPlatform === 'win32' ? path.win32.sep : path.posix.sep; +exports.minimatch.sep = exports.sep; +exports.GLOBSTAR = Symbol('globstar **'); +exports.minimatch.GLOBSTAR = exports.GLOBSTAR; +const plTypes = { + '!': { open: '(?:(?!(?:', close: '))[^/]*?)' }, + '?': { open: '(?:', close: ')?' }, + '+': { open: '(?:', close: ')+' }, + '*': { open: '(?:', close: ')*' }, + '@': { open: '(?:', close: ')' }, +}; +// any single thing other than / +// don't need to escape / when using new RegExp() +const qmark = '[^/]'; +// * => any number of characters +const star = qmark + '*?'; +// ** when dots are allowed. Anything goes, except .. and . +// not (^ or / followed by one or two dots followed by $ or /), +// followed by anything, any number of times. +const twoStarDot = '(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?'; +// not a ^ or / followed by a dot, +// followed by anything, any number of times. +const twoStarNoDot = '(?:(?!(?:\\/|^)\\.).)*?'; +// "abc" -> { a:true, b:true, c:true } +const charSet = (s) => s.split('').reduce((set, c) => { + set[c] = true; + return set; +}, {}); +// characters that need to be escaped in RegExp. +const reSpecials = charSet('().*{}+?[]^$\\!'); +// characters that indicate we have to add the pattern start +const addPatternStartSet = charSet('[.('); +const filter = (pattern, options = {}) => (p) => (0, exports.minimatch)(p, pattern, options); +exports.filter = filter; +exports.minimatch.filter = exports.filter; +const ext = (a, b = {}) => Object.assign({}, a, b); +const defaults = (def) => { + if (!def || typeof def !== 'object' || !Object.keys(def).length) { + return exports.minimatch; + } + const orig = exports.minimatch; + const m = (p, pattern, options = {}) => orig(p, pattern, ext(def, options)); + return Object.assign(m, { + Minimatch: class Minimatch extends orig.Minimatch { + constructor(pattern, options = {}) { + super(pattern, ext(def, options)); + } + static defaults(options) { + return orig.defaults(ext(def, options)).Minimatch; + } + }, + unescape: (s, options = {}) => orig.unescape(s, ext(def, options)), + escape: (s, options = {}) => orig.escape(s, ext(def, options)), + filter: (pattern, options = {}) => orig.filter(pattern, ext(def, options)), + defaults: (options) => orig.defaults(ext(def, options)), + makeRe: (pattern, options = {}) => orig.makeRe(pattern, ext(def, options)), + braceExpand: (pattern, options = {}) => orig.braceExpand(pattern, ext(def, options)), + match: (list, pattern, options = {}) => orig.match(list, pattern, ext(def, options)), + sep: orig.sep, + GLOBSTAR: exports.GLOBSTAR, + }); +}; +exports.defaults = defaults; +exports.minimatch.defaults = exports.defaults; +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +const braceExpand = (pattern, options = {}) => { + assertValidPattern(pattern); + // Thanks to Yeting Li for + // improving this regexp to avoid a ReDOS vulnerability. + if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { + // shortcut. no need to expand. + return [pattern]; + } + return (0, brace_expansion_1.default)(pattern); +}; +exports.braceExpand = braceExpand; +exports.minimatch.braceExpand = exports.braceExpand; +const MAX_PATTERN_LENGTH = 1024 * 64; +const assertValidPattern = (pattern) => { + if (typeof pattern !== 'string') { + throw new TypeError('invalid pattern'); + } + if (pattern.length > MAX_PATTERN_LENGTH) { + throw new TypeError('pattern is too long'); + } +}; +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +const makeRe = (pattern, options = {}) => new Minimatch(pattern, options).makeRe(); +exports.makeRe = makeRe; +exports.minimatch.makeRe = exports.makeRe; +const match = (list, pattern, options = {}) => { + const mm = new Minimatch(pattern, options); + list = list.filter(f => mm.match(f)); + if (mm.options.nonull && !list.length) { + list.push(pattern); + } + return list; +}; +exports.match = match; +exports.minimatch.match = exports.match; +// replace stuff like \* with * +const globUnescape = (s) => s.replace(/\\(.)/g, '$1'); +const globMagic = /[?*]|[+@!]\(.*?\)|\[|\]/; +const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); +class Minimatch { + options; + set; + pattern; + windowsPathsNoEscape; + nonegate; + negate; + comment; + empty; + preserveMultipleSlashes; + partial; + globSet; + globParts; + nocase; + isWindows; + platform; + windowsNoMagicRoot; + regexp; + constructor(pattern, options = {}) { + assertValidPattern(pattern); + options = options || {}; + this.options = options; + this.pattern = pattern; + this.platform = options.platform || defaultPlatform; + this.isWindows = this.platform === 'win32'; + this.windowsPathsNoEscape = + !!options.windowsPathsNoEscape || options.allowWindowsEscape === false; + if (this.windowsPathsNoEscape) { + this.pattern = this.pattern.replace(/\\/g, '/'); + } + this.preserveMultipleSlashes = !!options.preserveMultipleSlashes; + this.regexp = null; + this.negate = false; + this.nonegate = !!options.nonegate; + this.comment = false; + this.empty = false; + this.partial = !!options.partial; + this.nocase = !!this.options.nocase; + this.windowsNoMagicRoot = + options.windowsNoMagicRoot !== undefined + ? options.windowsNoMagicRoot + : !!(this.isWindows && this.nocase); + this.globSet = []; + this.globParts = []; + this.set = []; + // make the set of regexps etc. + this.make(); + } + hasMagic() { + if (this.options.magicalBraces && this.set.length > 1) { + return true; + } + for (const pattern of this.set) { + for (const part of pattern) { + if (typeof part !== 'string') + return true; + } + } + return false; + } + debug(..._) { } + make() { + const pattern = this.pattern; + const options = this.options; + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === '#') { + this.comment = true; + return; + } + if (!pattern) { + this.empty = true; + return; + } + // step 1: figure out negation, etc. + this.parseNegate(); + // step 2: expand braces + this.globSet = [...new Set(this.braceExpand())]; + if (options.debug) { + this.debug = (...args) => console.error(...args); + } + this.debug(this.pattern, this.globSet); + // step 3: now we have a set, so turn each one into a series of + // path-portion matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + // + // First, we preprocess to make the glob pattern sets a bit simpler + // and deduped. There are some perf-killing patterns that can cause + // problems with a glob walk, but we can simplify them down a bit. + const rawGlobParts = this.globSet.map(s => this.slashSplit(s)); + this.globParts = this.preprocess(rawGlobParts); + this.debug(this.pattern, this.globParts); + // glob --> regexps + let set = this.globParts.map((s, _, __) => { + if (this.isWindows && this.windowsNoMagicRoot) { + // check if it's a drive or unc path. + const isUNC = s[0] === '' && + s[1] === '' && + (s[2] === '?' || !globMagic.test(s[2])) && + !globMagic.test(s[3]); + const isDrive = /^[a-z]:/i.test(s[0]); + if (isUNC) { + return [...s.slice(0, 4), ...s.slice(4).map(ss => this.parse(ss))]; + } + else if (isDrive) { + return [s[0], ...s.slice(1).map(ss => this.parse(ss))]; + } + } + return s.map(ss => this.parse(ss)); + }); + this.debug(this.pattern, set); + // filter out everything that didn't compile properly. + this.set = set.filter(s => s.indexOf(false) === -1); + // do not treat the ? in UNC paths as magic + if (this.isWindows) { + for (let i = 0; i < this.set.length; i++) { + const p = this.set[i]; + if (p[0] === '' && + p[1] === '' && + this.globParts[i][2] === '?' && + typeof p[3] === 'string' && + /^[a-z]:$/i.test(p[3])) { + p[2] = '?'; + } + } + } + this.debug(this.pattern, this.set); + } + // various transforms to equivalent pattern sets that are + // faster to process in a filesystem walk. The goal is to + // eliminate what we can, and push all ** patterns as far + // to the right as possible, even if it increases the number + // of patterns that we have to process. + preprocess(globParts) { + // if we're not in globstar mode, then turn all ** into * + if (this.options.noglobstar) { + for (let i = 0; i < globParts.length; i++) { + for (let j = 0; j < globParts[i].length; j++) { + if (globParts[i][j] === '**') { + globParts[i][j] = '*'; + } + } + } + } + const { optimizationLevel = 1 } = this.options; + if (optimizationLevel >= 2) { + // aggressive optimization for the purpose of fs walking + globParts = this.firstPhasePreProcess(globParts); + globParts = this.secondPhasePreProcess(globParts); + } + else if (optimizationLevel >= 1) { + // just basic optimizations to remove some .. parts + globParts = this.levelOneOptimize(globParts); + } + else { + globParts = this.adjascentGlobstarOptimize(globParts); + } + return globParts; + } + // just get rid of adjascent ** portions + adjascentGlobstarOptimize(globParts) { + return globParts.map(parts => { + let gs = -1; + while (-1 !== (gs = parts.indexOf('**', gs + 1))) { + let i = gs; + while (parts[i + 1] === '**') { + i++; + } + if (i !== gs) { + parts.splice(gs, i - gs); + } + } + return parts; + }); + } + // get rid of adjascent ** and resolve .. portions + levelOneOptimize(globParts) { + return globParts.map(parts => { + parts = parts.reduce((set, part) => { + const prev = set[set.length - 1]; + if (part === '**' && prev === '**') { + return set; + } + if (part === '..') { + if (prev && prev !== '..' && prev !== '.' && prev !== '**') { + set.pop(); + return set; + } + } + set.push(part); + return set; + }, []); + return parts.length === 0 ? [''] : parts; + }); + } + levelTwoFileOptimize(parts) { + if (!Array.isArray(parts)) { + parts = this.slashSplit(parts); + } + let didSomething = false; + do { + didSomething = false; + //
// -> 
/
+            if (!this.preserveMultipleSlashes) {
+                for (let i = 1; i < parts.length - 1; i++) {
+                    const p = parts[i];
+                    // don't squeeze out UNC patterns
+                    if (i === 1 && p === '' && parts[0] === '')
+                        continue;
+                    if (p === '.' || p === '') {
+                        didSomething = true;
+                        parts.splice(i, 1);
+                        i--;
+                    }
+                }
+                if (parts[0] === '.' &&
+                    parts.length === 2 &&
+                    (parts[1] === '.' || parts[1] === '')) {
+                    didSomething = true;
+                    parts.pop();
+                }
+            }
+            // 
/

/../ ->

/
+            let dd = 0;
+            while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
+                const p = parts[dd - 1];
+                if (p && p !== '.' && p !== '..' && p !== '**') {
+                    didSomething = true;
+                    parts.splice(dd - 1, 2);
+                    dd -= 2;
+                }
+            }
+        } while (didSomething);
+        return parts.length === 0 ? [''] : parts;
+    }
+    // First phase: single-pattern processing
+    // 
 is 1 or more portions
+    //  is 1 or more portions
+    // 

is any portion other than ., .., '', or ** + // is . or '' + // + // **/.. is *brutal* for filesystem walking performance, because + // it effectively resets the recursive walk each time it occurs, + // and ** cannot be reduced out by a .. pattern part like a regexp + // or most strings (other than .., ., and '') can be. + // + //

/**/../

/

/ -> {

/../

/

/,

/**/

/

/} + //

// -> 
/
+    // 
/

/../ ->

/
+    // **/**/ -> **/
+    //
+    // **/*/ -> */**/ <== not valid because ** doesn't follow
+    // this WOULD be allowed if ** did follow symlinks, or * didn't
+    firstPhasePreProcess(globParts) {
+        let didSomething = false;
+        do {
+            didSomething = false;
+            // 
/**/../

/

/ -> {

/../

/

/,

/**/

/

/} + for (let parts of globParts) { + let gs = -1; + while (-1 !== (gs = parts.indexOf('**', gs + 1))) { + let gss = gs; + while (parts[gss + 1] === '**') { + //

/**/**/ -> 
/**/
+                        gss++;
+                    }
+                    // eg, if gs is 2 and gss is 4, that means we have 3 **
+                    // parts, and can remove 2 of them.
+                    if (gss > gs) {
+                        parts.splice(gs + 1, gss - gs);
+                    }
+                    let next = parts[gs + 1];
+                    const p = parts[gs + 2];
+                    const p2 = parts[gs + 3];
+                    if (next !== '..')
+                        continue;
+                    if (!p ||
+                        p === '.' ||
+                        p === '..' ||
+                        !p2 ||
+                        p2 === '.' ||
+                        p2 === '..') {
+                        continue;
+                    }
+                    didSomething = true;
+                    // edit parts in place, and push the new one
+                    parts.splice(gs, 1);
+                    const other = parts.slice(0);
+                    other[gs] = '**';
+                    globParts.push(other);
+                    gs--;
+                }
+                // 
// -> 
/
+                if (!this.preserveMultipleSlashes) {
+                    for (let i = 1; i < parts.length - 1; i++) {
+                        const p = parts[i];
+                        // don't squeeze out UNC patterns
+                        if (i === 1 && p === '' && parts[0] === '')
+                            continue;
+                        if (p === '.' || p === '') {
+                            didSomething = true;
+                            parts.splice(i, 1);
+                            i--;
+                        }
+                    }
+                    if (parts[0] === '.' &&
+                        parts.length === 2 &&
+                        (parts[1] === '.' || parts[1] === '')) {
+                        didSomething = true;
+                        parts.pop();
+                    }
+                }
+                // 
/

/../ ->

/
+                let dd = 0;
+                while (-1 !== (dd = parts.indexOf('..', dd + 1))) {
+                    const p = parts[dd - 1];
+                    if (p && p !== '.' && p !== '..' && p !== '**') {
+                        didSomething = true;
+                        const needDot = dd === 1 && parts[dd + 1] === '**';
+                        const splin = needDot ? ['.'] : [];
+                        parts.splice(dd - 1, 2, ...splin);
+                        if (parts.length === 0)
+                            parts.push('');
+                        dd -= 2;
+                    }
+                }
+            }
+        } while (didSomething);
+        return globParts;
+    }
+    // second phase: multi-pattern dedupes
+    // {
/*/,
/

/} ->

/*/
+    // {
/,
/} -> 
/
+    // {
/**/,
/} -> 
/**/
+    //
+    // {
/**/,
/**/

/} ->

/**/
+    // ^-- not valid because ** doens't follow symlinks
+    secondPhasePreProcess(globParts) {
+        for (let i = 0; i < globParts.length - 1; i++) {
+            for (let j = i + 1; j < globParts.length; j++) {
+                const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes);
+                if (!matched)
+                    continue;
+                globParts[i] = matched;
+                globParts[j] = [];
+            }
+        }
+        return globParts.filter(gs => gs.length);
+    }
+    partsMatch(a, b, emptyGSMatch = false) {
+        let ai = 0;
+        let bi = 0;
+        let result = [];
+        let which = '';
+        while (ai < a.length && bi < b.length) {
+            if (a[ai] === b[bi]) {
+                result.push(which === 'b' ? b[bi] : a[ai]);
+                ai++;
+                bi++;
+            }
+            else if (emptyGSMatch && a[ai] === '**' && b[bi] === a[ai + 1]) {
+                result.push(a[ai]);
+                ai++;
+            }
+            else if (emptyGSMatch && b[bi] === '**' && a[ai] === b[bi + 1]) {
+                result.push(b[bi]);
+                bi++;
+            }
+            else if (a[ai] === '*' &&
+                b[bi] &&
+                (this.options.dot || !b[bi].startsWith('.')) &&
+                b[bi] !== '**') {
+                if (which === 'b')
+                    return false;
+                which = 'a';
+                result.push(a[ai]);
+                ai++;
+                bi++;
+            }
+            else if (b[bi] === '*' &&
+                a[ai] &&
+                (this.options.dot || !a[ai].startsWith('.')) &&
+                a[ai] !== '**') {
+                if (which === 'a')
+                    return false;
+                which = 'b';
+                result.push(b[bi]);
+                ai++;
+                bi++;
+            }
+            else {
+                return false;
+            }
+        }
+        // if we fall out of the loop, it means they two are identical
+        // as long as their lengths match
+        return a.length === b.length && result;
+    }
+    parseNegate() {
+        if (this.nonegate)
+            return;
+        const pattern = this.pattern;
+        let negate = false;
+        let negateOffset = 0;
+        for (let i = 0; i < pattern.length && pattern.charAt(i) === '!'; i++) {
+            negate = !negate;
+            negateOffset++;
+        }
+        if (negateOffset)
+            this.pattern = pattern.slice(negateOffset);
+        this.negate = negate;
+    }
+    // set partial to true to test if, for example,
+    // "/a/b" matches the start of "/*/b/*/d"
+    // Partial means, if you run out of file before you run
+    // out of pattern, then that's fine, as long as all
+    // the parts match.
+    matchOne(file, pattern, partial = false) {
+        const options = this.options;
+        // a UNC pattern like //?/c:/* can match a path like c:/x
+        // and vice versa
+        if (this.isWindows) {
+            const fileUNC = file[0] === '' &&
+                file[1] === '' &&
+                file[2] === '?' &&
+                typeof file[3] === 'string' &&
+                /^[a-z]:$/i.test(file[3]);
+            const patternUNC = pattern[0] === '' &&
+                pattern[1] === '' &&
+                pattern[2] === '?' &&
+                typeof pattern[3] === 'string' &&
+                /^[a-z]:$/i.test(pattern[3]);
+            if (fileUNC && patternUNC) {
+                const fd = file[3];
+                const pd = pattern[3];
+                if (fd.toLowerCase() === pd.toLowerCase()) {
+                    file[3] = pd;
+                }
+            }
+            else if (patternUNC && typeof file[0] === 'string') {
+                const pd = pattern[3];
+                const fd = file[0];
+                if (pd.toLowerCase() === fd.toLowerCase()) {
+                    pattern[3] = fd;
+                    pattern = pattern.slice(3);
+                }
+            }
+            else if (fileUNC && typeof pattern[0] === 'string') {
+                const fd = file[3];
+                if (fd.toLowerCase() === pattern[0].toLowerCase()) {
+                    pattern[0] = fd;
+                    file = file.slice(3);
+                }
+            }
+        }
+        // resolve and reduce . and .. portions in the file as well.
+        // dont' need to do the second phase, because it's only one string[]
+        const { optimizationLevel = 1 } = this.options;
+        if (optimizationLevel >= 2) {
+            file = this.levelTwoFileOptimize(file);
+        }
+        this.debug('matchOne', this, { file, pattern });
+        this.debug('matchOne', file.length, pattern.length);
+        for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) {
+            this.debug('matchOne loop');
+            var p = pattern[pi];
+            var f = file[fi];
+            this.debug(pattern, p, f);
+            // should be impossible.
+            // some invalid regexp stuff in the set.
+            /* c8 ignore start */
+            if (p === false) {
+                return false;
+            }
+            /* c8 ignore stop */
+            if (p === exports.GLOBSTAR) {
+                this.debug('GLOBSTAR', [pattern, p, f]);
+                // "**"
+                // a/**/b/**/c would match the following:
+                // a/b/x/y/z/c
+                // a/x/y/z/b/c
+                // a/b/x/b/x/c
+                // a/b/c
+                // To do this, take the rest of the pattern after
+                // the **, and see if it would match the file remainder.
+                // If so, return success.
+                // If not, the ** "swallows" a segment, and try again.
+                // This is recursively awful.
+                //
+                // a/**/b/**/c matching a/b/x/y/z/c
+                // - a matches a
+                // - doublestar
+                //   - matchOne(b/x/y/z/c, b/**/c)
+                //     - b matches b
+                //     - doublestar
+                //       - matchOne(x/y/z/c, c) -> no
+                //       - matchOne(y/z/c, c) -> no
+                //       - matchOne(z/c, c) -> no
+                //       - matchOne(c, c) yes, hit
+                var fr = fi;
+                var pr = pi + 1;
+                if (pr === pl) {
+                    this.debug('** at the end');
+                    // a ** at the end will just swallow the rest.
+                    // We have found a match.
+                    // however, it will not swallow /.x, unless
+                    // options.dot is set.
+                    // . and .. are *never* matched by **, for explosively
+                    // exponential reasons.
+                    for (; fi < fl; fi++) {
+                        if (file[fi] === '.' ||
+                            file[fi] === '..' ||
+                            (!options.dot && file[fi].charAt(0) === '.'))
+                            return false;
+                    }
+                    return true;
+                }
+                // ok, let's see if we can swallow whatever we can.
+                while (fr < fl) {
+                    var swallowee = file[fr];
+                    this.debug('\nglobstar while', file, fr, pattern, pr, swallowee);
+                    // XXX remove this slice.  Just pass the start index.
+                    if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
+                        this.debug('globstar found match!', fr, fl, swallowee);
+                        // found a match.
+                        return true;
+                    }
+                    else {
+                        // can't swallow "." or ".." ever.
+                        // can only swallow ".foo" when explicitly asked.
+                        if (swallowee === '.' ||
+                            swallowee === '..' ||
+                            (!options.dot && swallowee.charAt(0) === '.')) {
+                            this.debug('dot detected!', file, fr, pattern, pr);
+                            break;
+                        }
+                        // ** swallows a segment, and continue.
+                        this.debug('globstar swallow a segment, and continue');
+                        fr++;
+                    }
+                }
+                // no match was found.
+                // However, in partial mode, we can't say this is necessarily over.
+                /* c8 ignore start */
+                if (partial) {
+                    // ran out of file
+                    this.debug('\n>>> no match, partial?', file, fr, pattern, pr);
+                    if (fr === fl) {
+                        return true;
+                    }
+                }
+                /* c8 ignore stop */
+                return false;
+            }
+            // something other than **
+            // non-magic patterns just have to match exactly
+            // patterns with magic have been turned into regexps.
+            let hit;
+            if (typeof p === 'string') {
+                hit = f === p;
+                this.debug('string match', p, f, hit);
+            }
+            else {
+                hit = p.test(f);
+                this.debug('pattern match', p, f, hit);
+            }
+            if (!hit)
+                return false;
+        }
+        // Note: ending in / means that we'll get a final ""
+        // at the end of the pattern.  This can only match a
+        // corresponding "" at the end of the file.
+        // If the file ends in /, then it can only match a
+        // a pattern that ends in /, unless the pattern just
+        // doesn't have any more for it. But, a/b/ should *not*
+        // match "a/b/*", even though "" matches against the
+        // [^/]*? pattern, except in partial mode, where it might
+        // simply not be reached yet.
+        // However, a/b/ should still satisfy a/*
+        // now either we fell off the end of the pattern, or we're done.
+        if (fi === fl && pi === pl) {
+            // ran out of pattern and filename at the same time.
+            // an exact hit!
+            return true;
+        }
+        else if (fi === fl) {
+            // ran out of file, but still had pattern left.
+            // this is ok if we're doing the match as part of
+            // a glob fs traversal.
+            return partial;
+        }
+        else if (pi === pl) {
+            // ran out of pattern, still have file left.
+            // this is only acceptable if we're on the very last
+            // empty segment of a file with a trailing slash.
+            // a/* should match a/b/
+            return fi === fl - 1 && file[fi] === '';
+            /* c8 ignore start */
+        }
+        else {
+            // should be unreachable.
+            throw new Error('wtf?');
+        }
+        /* c8 ignore stop */
+    }
+    braceExpand() {
+        return (0, exports.braceExpand)(this.pattern, this.options);
+    }
+    parse(pattern) {
+        assertValidPattern(pattern);
+        const options = this.options;
+        // shortcuts
+        if (pattern === '**')
+            return exports.GLOBSTAR;
+        if (pattern === '')
+            return '';
+        // far and away, the most common glob pattern parts are
+        // *, *.*, and *.  Add a fast check method for those.
+        let m;
+        let fastTest = null;
+        if ((m = pattern.match(starRE))) {
+            fastTest = options.dot ? starTestDot : starTest;
+        }
+        else if ((m = pattern.match(starDotExtRE))) {
+            fastTest = (options.nocase
+                ? options.dot
+                    ? starDotExtTestNocaseDot
+                    : starDotExtTestNocase
+                : options.dot
+                    ? starDotExtTestDot
+                    : starDotExtTest)(m[1]);
+        }
+        else if ((m = pattern.match(qmarksRE))) {
+            fastTest = (options.nocase
+                ? options.dot
+                    ? qmarksTestNocaseDot
+                    : qmarksTestNocase
+                : options.dot
+                    ? qmarksTestDot
+                    : qmarksTest)(m);
+        }
+        else if ((m = pattern.match(starDotStarRE))) {
+            fastTest = options.dot ? starDotStarTestDot : starDotStarTest;
+        }
+        else if ((m = pattern.match(dotStarRE))) {
+            fastTest = dotStarTest;
+        }
+        let re = '';
+        let hasMagic = false;
+        let escaping = false;
+        // ? => one single character
+        const patternListStack = [];
+        const negativeLists = [];
+        let stateChar = false;
+        let uflag = false;
+        let pl;
+        // . and .. never match anything that doesn't start with .,
+        // even when options.dot is set.  However, if the pattern
+        // starts with ., then traversal patterns can match.
+        let dotTravAllowed = pattern.charAt(0) === '.';
+        let dotFileAllowed = options.dot || dotTravAllowed;
+        const patternStart = () => dotTravAllowed
+            ? ''
+            : dotFileAllowed
+                ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
+                : '(?!\\.)';
+        const subPatternStart = (p) => p.charAt(0) === '.'
+            ? ''
+            : options.dot
+                ? '(?!(?:^|\\/)\\.{1,2}(?:$|\\/))'
+                : '(?!\\.)';
+        const clearStateChar = () => {
+            if (stateChar) {
+                // we had some state-tracking character
+                // that wasn't consumed by this pass.
+                switch (stateChar) {
+                    case '*':
+                        re += star;
+                        hasMagic = true;
+                        break;
+                    case '?':
+                        re += qmark;
+                        hasMagic = true;
+                        break;
+                    default:
+                        re += '\\' + stateChar;
+                        break;
+                }
+                this.debug('clearStateChar %j %j', stateChar, re);
+                stateChar = false;
+            }
+        };
+        for (let i = 0, c; i < pattern.length && (c = pattern.charAt(i)); i++) {
+            this.debug('%s\t%s %s %j', pattern, i, re, c);
+            // skip over any that are escaped.
+            if (escaping) {
+                // completely not allowed, even escaped.
+                // should be impossible.
+                /* c8 ignore start */
+                if (c === '/') {
+                    return false;
+                }
+                /* c8 ignore stop */
+                if (reSpecials[c]) {
+                    re += '\\';
+                }
+                re += c;
+                escaping = false;
+                continue;
+            }
+            switch (c) {
+                // Should already be path-split by now.
+                /* c8 ignore start */
+                case '/': {
+                    return false;
+                }
+                /* c8 ignore stop */
+                case '\\':
+                    clearStateChar();
+                    escaping = true;
+                    continue;
+                // the various stateChar values
+                // for the "extglob" stuff.
+                case '?':
+                case '*':
+                case '+':
+                case '@':
+                case '!':
+                    this.debug('%s\t%s %s %j <-- stateChar', pattern, i, re, c);
+                    // if we already have a stateChar, then it means
+                    // that there was something like ** or +? in there.
+                    // Handle the stateChar, then proceed with this one.
+                    this.debug('call clearStateChar %j', stateChar);
+                    clearStateChar();
+                    stateChar = c;
+                    // if extglob is disabled, then +(asdf|foo) isn't a thing.
+                    // just clear the statechar *now*, rather than even diving into
+                    // the patternList stuff.
+                    if (options.noext)
+                        clearStateChar();
+                    continue;
+                case '(': {
+                    if (!stateChar) {
+                        re += '\\(';
+                        continue;
+                    }
+                    const plEntry = {
+                        type: stateChar,
+                        start: i - 1,
+                        reStart: re.length,
+                        open: plTypes[stateChar].open,
+                        close: plTypes[stateChar].close,
+                    };
+                    this.debug(this.pattern, '\t', plEntry);
+                    patternListStack.push(plEntry);
+                    // negation is (?:(?!(?:js)(?:))[^/]*)
+                    re += plEntry.open;
+                    // next entry starts with a dot maybe?
+                    if (plEntry.start === 0 && plEntry.type !== '!') {
+                        dotTravAllowed = true;
+                        re += subPatternStart(pattern.slice(i + 1));
+                    }
+                    this.debug('plType %j %j', stateChar, re);
+                    stateChar = false;
+                    continue;
+                }
+                case ')': {
+                    const plEntry = patternListStack[patternListStack.length - 1];
+                    if (!plEntry) {
+                        re += '\\)';
+                        continue;
+                    }
+                    patternListStack.pop();
+                    // closing an extglob
+                    clearStateChar();
+                    hasMagic = true;
+                    pl = plEntry;
+                    // negation is (?:(?!js)[^/]*)
+                    // The others are (?:)
+                    re += pl.close;
+                    if (pl.type === '!') {
+                        negativeLists.push(Object.assign(pl, { reEnd: re.length }));
+                    }
+                    continue;
+                }
+                case '|': {
+                    const plEntry = patternListStack[patternListStack.length - 1];
+                    if (!plEntry) {
+                        re += '\\|';
+                        continue;
+                    }
+                    clearStateChar();
+                    re += '|';
+                    // next subpattern can start with a dot?
+                    if (plEntry.start === 0 && plEntry.type !== '!') {
+                        dotTravAllowed = true;
+                        re += subPatternStart(pattern.slice(i + 1));
+                    }
+                    continue;
+                }
+                // these are mostly the same in regexp and glob
+                case '[':
+                    // swallow any state-tracking char before the [
+                    clearStateChar();
+                    const [src, needUflag, consumed, magic] = (0, brace_expressions_js_1.parseClass)(pattern, i);
+                    if (consumed) {
+                        re += src;
+                        uflag = uflag || needUflag;
+                        i += consumed - 1;
+                        hasMagic = hasMagic || magic;
+                    }
+                    else {
+                        re += '\\[';
+                    }
+                    continue;
+                case ']':
+                    re += '\\' + c;
+                    continue;
+                default:
+                    // swallow any state char that wasn't consumed
+                    clearStateChar();
+                    re += regExpEscape(c);
+                    break;
+            } // switch
+        } // for
+        // handle the case where we had a +( thing at the *end*
+        // of the pattern.
+        // each pattern list stack adds 3 chars, and we need to go through
+        // and escape any | chars that were passed through as-is for the regexp.
+        // Go through and escape them, taking care not to double-escape any
+        // | chars that were already escaped.
+        for (pl = patternListStack.pop(); pl; pl = patternListStack.pop()) {
+            let tail;
+            tail = re.slice(pl.reStart + pl.open.length);
+            this.debug(this.pattern, 'setting tail', re, pl);
+            // maybe some even number of \, then maybe 1 \, followed by a |
+            tail = tail.replace(/((?:\\{2}){0,64})(\\?)\|/g, (_, $1, $2) => {
+                if (!$2) {
+                    // the | isn't already escaped, so escape it.
+                    $2 = '\\';
+                    // should already be done
+                    /* c8 ignore start */
+                }
+                /* c8 ignore stop */
+                // need to escape all those slashes *again*, without escaping the
+                // one that we need for escaping the | character.  As it works out,
+                // escaping an even number of slashes can be done by simply repeating
+                // it exactly after itself.  That's why this trick works.
+                //
+                // I am sorry that you have to see this.
+                return $1 + $1 + $2 + '|';
+            });
+            this.debug('tail=%j\n   %s', tail, tail, pl, re);
+            const t = pl.type === '*' ? star : pl.type === '?' ? qmark : '\\' + pl.type;
+            hasMagic = true;
+            re = re.slice(0, pl.reStart) + t + '\\(' + tail;
+        }
+        // handle trailing things that only matter at the very end.
+        clearStateChar();
+        if (escaping) {
+            // trailing \\
+            re += '\\\\';
+        }
+        // only need to apply the nodot start if the re starts with
+        // something that could conceivably capture a dot
+        const addPatternStart = addPatternStartSet[re.charAt(0)];
+        // Hack to work around lack of negative lookbehind in JS
+        // A pattern like: *.!(x).!(y|z) needs to ensure that a name
+        // like 'a.xyz.yz' doesn't match.  So, the first negative
+        // lookahead, has to look ALL the way ahead, to the end of
+        // the pattern.
+        for (let n = negativeLists.length - 1; n > -1; n--) {
+            const nl = negativeLists[n];
+            const nlBefore = re.slice(0, nl.reStart);
+            const nlFirst = re.slice(nl.reStart, nl.reEnd - 8);
+            let nlAfter = re.slice(nl.reEnd);
+            const nlLast = re.slice(nl.reEnd - 8, nl.reEnd) + nlAfter;
+            // Handle nested stuff like *(*.js|!(*.json)), where open parens
+            // mean that we should *not* include the ) in the bit that is considered
+            // "after" the negated section.
+            const closeParensBefore = nlBefore.split(')').length;
+            const openParensBefore = nlBefore.split('(').length - closeParensBefore;
+            let cleanAfter = nlAfter;
+            for (let i = 0; i < openParensBefore; i++) {
+                cleanAfter = cleanAfter.replace(/\)[+*?]?/, '');
+            }
+            nlAfter = cleanAfter;
+            const dollar = nlAfter === '' ? '(?:$|\\/)' : '';
+            re = nlBefore + nlFirst + nlAfter + dollar + nlLast;
+        }
+        // if the re is not "" at this point, then we need to make sure
+        // it doesn't match against an empty path part.
+        // Otherwise a/* will match a/, which it should not.
+        if (re !== '' && hasMagic) {
+            re = '(?=.)' + re;
+        }
+        if (addPatternStart) {
+            re = patternStart() + re;
+        }
+        // if it's nocase, and the lcase/uppercase don't match, it's magic
+        if (options.nocase && !hasMagic && !options.nocaseMagicOnly) {
+            hasMagic = pattern.toUpperCase() !== pattern.toLowerCase();
+        }
+        // skip the regexp for non-magical patterns
+        // unescape anything in it, though, so that it'll be
+        // an exact match against a file etc.
+        if (!hasMagic) {
+            return globUnescape(re);
+        }
+        const flags = (options.nocase ? 'i' : '') + (uflag ? 'u' : '');
+        try {
+            const ext = fastTest
+                ? {
+                    _glob: pattern,
+                    _src: re,
+                    test: fastTest,
+                }
+                : {
+                    _glob: pattern,
+                    _src: re,
+                };
+            return Object.assign(new RegExp('^' + re + '$', flags), ext);
+            /* c8 ignore start */
+        }
+        catch (er) {
+            // should be impossible
+            // If it was an invalid regular expression, then it can't match
+            // anything.  This trick looks for a character after the end of
+            // the string, which is of course impossible, except in multi-line
+            // mode, but it's not a /m regex.
+            this.debug('invalid regexp', er);
+            return new RegExp('$.');
+        }
+        /* c8 ignore stop */
+    }
+    makeRe() {
+        if (this.regexp || this.regexp === false)
+            return this.regexp;
+        // at this point, this.set is a 2d array of partial
+        // pattern strings, or "**".
+        //
+        // It's better to use .match().  This function shouldn't
+        // be used, really, but it's pretty convenient sometimes,
+        // when you just want to work with a regex.
+        const set = this.set;
+        if (!set.length) {
+            this.regexp = false;
+            return this.regexp;
+        }
+        const options = this.options;
+        const twoStar = options.noglobstar
+            ? star
+            : options.dot
+                ? twoStarDot
+                : twoStarNoDot;
+        const flags = options.nocase ? 'i' : '';
+        // regexpify non-globstar patterns
+        // if ** is only item, then we just do one twoStar
+        // if ** is first, and there are more, prepend (\/|twoStar\/)? to next
+        // if ** is last, append (\/twoStar|) to previous
+        // if ** is in the middle, append (\/|\/twoStar\/) to previous
+        // then filter out GLOBSTAR symbols
+        let re = set
+            .map(pattern => {
+            const pp = pattern.map(p => typeof p === 'string'
+                ? regExpEscape(p)
+                : p === exports.GLOBSTAR
+                    ? exports.GLOBSTAR
+                    : p._src);
+            pp.forEach((p, i) => {
+                const next = pp[i + 1];
+                const prev = pp[i - 1];
+                if (p !== exports.GLOBSTAR || prev === exports.GLOBSTAR) {
+                    return;
+                }
+                if (prev === undefined) {
+                    if (next !== undefined && next !== exports.GLOBSTAR) {
+                        pp[i + 1] = '(?:\\/|' + twoStar + '\\/)?' + next;
+                    }
+                    else {
+                        pp[i] = twoStar;
+                    }
+                }
+                else if (next === undefined) {
+                    pp[i - 1] = prev + '(?:\\/|' + twoStar + ')?';
+                }
+                else if (next !== exports.GLOBSTAR) {
+                    pp[i - 1] = prev + '(?:\\/|\\/' + twoStar + '\\/)' + next;
+                    pp[i + 1] = exports.GLOBSTAR;
+                }
+            });
+            return pp.filter(p => p !== exports.GLOBSTAR).join('/');
+        })
+            .join('|');
+        // must match entire pattern
+        // ending in a * or ** will make it less strict.
+        re = '^(?:' + re + ')$';
+        // can match anything, as long as it's not this.
+        if (this.negate)
+            re = '^(?!' + re + ').*$';
+        try {
+            this.regexp = new RegExp(re, flags);
+            /* c8 ignore start */
+        }
+        catch (ex) {
+            // should be impossible
+            this.regexp = false;
+        }
+        /* c8 ignore stop */
+        return this.regexp;
+    }
+    slashSplit(p) {
+        // if p starts with // on windows, we preserve that
+        // so that UNC paths aren't broken.  Otherwise, any number of
+        // / characters are coalesced into one, unless
+        // preserveMultipleSlashes is set to true.
+        if (this.preserveMultipleSlashes) {
+            return p.split('/');
+        }
+        else if (this.isWindows && /^\/\/[^\/]+/.test(p)) {
+            // add an extra '' for the one we lose
+            return ['', ...p.split(/\/+/)];
+        }
+        else {
+            return p.split(/\/+/);
+        }
+    }
+    match(f, partial = this.partial) {
+        this.debug('match', f, this.pattern);
+        // short-circuit in the case of busted things.
+        // comments, etc.
+        if (this.comment) {
+            return false;
+        }
+        if (this.empty) {
+            return f === '';
+        }
+        if (f === '/' && partial) {
+            return true;
+        }
+        const options = this.options;
+        // windows: need to use /, not \
+        if (this.isWindows) {
+            f = f.split('\\').join('/');
+        }
+        // treat the test path as a set of pathparts.
+        const ff = this.slashSplit(f);
+        this.debug(this.pattern, 'split', ff);
+        // just ONE of the pattern sets in this.set needs to match
+        // in order for it to be valid.  If negating, then just one
+        // match means that we have failed.
+        // Either way, return on the first hit.
+        const set = this.set;
+        this.debug(this.pattern, 'set', set);
+        // Find the basename of the path by looking for the last non-empty segment
+        let filename = ff[ff.length - 1];
+        if (!filename) {
+            for (let i = ff.length - 2; !filename && i >= 0; i--) {
+                filename = ff[i];
+            }
+        }
+        for (let i = 0; i < set.length; i++) {
+            const pattern = set[i];
+            let file = ff;
+            if (options.matchBase && pattern.length === 1) {
+                file = [filename];
+            }
+            const hit = this.matchOne(file, pattern, partial);
+            if (hit) {
+                if (options.flipNegate) {
+                    return true;
+                }
+                return !this.negate;
+            }
+        }
+        // didn't get any hits.  this is success if it's a negative
+        // pattern, failure otherwise.
+        if (options.flipNegate) {
+            return false;
+        }
+        return this.negate;
+    }
+    static defaults(def) {
+        return exports.minimatch.defaults(def).Minimatch;
+    }
+}
+exports.Minimatch = Minimatch;
+/* c8 ignore start */
+var escape_js_2 = __nccwpck_require__(9004);
+Object.defineProperty(exports, "escape", ({ enumerable: true, get: function () { return escape_js_2.escape; } }));
+var unescape_js_2 = __nccwpck_require__(7305);
+Object.defineProperty(exports, "unescape", ({ enumerable: true, get: function () { return unescape_js_2.unescape; } }));
+/* c8 ignore stop */
+exports.minimatch.Minimatch = Minimatch;
+exports.minimatch.escape = escape_js_1.escape;
+exports.minimatch.unescape = unescape_js_1.unescape;
+//# sourceMappingURL=index.js.map
+
+/***/ }),
+
+/***/ 7305:
+/***/ ((__unused_webpack_module, exports) => {
+
+"use strict";
+
+Object.defineProperty(exports, "__esModule", ({ value: true }));
+exports.unescape = void 0;
+/**
+ * Un-escape a string that has been escaped with {@link escape}.
+ *
+ * If the {@link windowsPathsNoEscape} option is used, then square-brace
+ * escapes are removed, but not backslash escapes.  For example, it will turn
+ * the string `'[*]'` into `*`, but it will not turn `'\\*'` into `'*'`,
+ * becuase `\` is a path separator in `windowsPathsNoEscape` mode.
+ *
+ * When `windowsPathsNoEscape` is not set, then both brace escapes and
+ * backslash escapes are removed.
+ *
+ * Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot be escaped
+ * or unescaped.
+ */
+const unescape = (s, { windowsPathsNoEscape = false, } = {}) => {
+    return windowsPathsNoEscape
+        ? s.replace(/\[([^\/\\])\]/g, '$1')
+        : s.replace(/((?!\\).|^)\[([^\/\\])\]/g, '$1$2').replace(/\\([^\/])/g, '$1');
+};
+exports.unescape = unescape;
+//# sourceMappingURL=unescape.js.map
+
+/***/ }),
+
 /***/ 1907:
 /***/ ((module) => {
 

From 71d2484daaf26523ee79447d458c78a3a1b122ee Mon Sep 17 00:00:00 2001
From: Alexander Kachkaev 
Date: Wed, 31 May 2023 18:46:23 +0100
Subject: [PATCH 21/23] Address review comment

---
 __tests__/main.test.ts | 3 +++
 src/labeler.ts         | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts
index 7aaf87d4..c4b77bc9 100644
--- a/__tests__/main.test.ts
+++ b/__tests__/main.test.ts
@@ -29,6 +29,9 @@ const configureInput = (
   jest
     .spyOn(core, 'getInput')
     .mockImplementation((name: string, ...opts) => mockInput[name]);
+  jest
+    .spyOn(core, 'getBooleanInput')
+    .mockImplementation((name: string, ...opts) => mockInput[name]);
 };
 
 afterAll(() => jest.restoreAllMocks());
diff --git a/src/labeler.ts b/src/labeler.ts
index 592959f0..6331857c 100644
--- a/src/labeler.ts
+++ b/src/labeler.ts
@@ -16,7 +16,7 @@ export async function run() {
     const token = core.getInput('repo-token');
     const configPath = core.getInput('configuration-path', {required: true});
     const syncLabels = !!core.getInput('sync-labels');
-    const dot = !!core.getInput('dot');
+    const dot = core.getBooleanInput('dot');
 
     const prNumber = getPrNumber();
     if (!prNumber) {

From 639ba81ab1bba531e30a7d24861c54eb53982160 Mon Sep 17 00:00:00 2001
From: Alexander Kachkaev 
Date: Wed, 31 May 2023 18:46:34 +0100
Subject: [PATCH 22/23] Rebuild

---
 dist/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dist/index.js b/dist/index.js
index 364d6e9f..f3695826 100644
--- a/dist/index.js
+++ b/dist/index.js
@@ -50,7 +50,7 @@ function run() {
             const token = core.getInput('repo-token');
             const configPath = core.getInput('configuration-path', { required: true });
             const syncLabels = !!core.getInput('sync-labels');
-            const dot = !!core.getInput('dot');
+            const dot = core.getBooleanInput('dot');
             const prNumber = getPrNumber();
             if (!prNumber) {
                 core.info('Could not get pull request number from context, exiting');

From d40596e5db2302f8bd180870610f0059a6e3ace2 Mon Sep 17 00:00:00 2001
From: Alexander Kachkaev 
Date: Fri, 2 Jun 2023 16:06:39 +0100
Subject: [PATCH 23/23] =?UTF-8?q?micromatch=20=E2=86=92=20minimatch?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 22cd0e8e..9ccc5312 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ label1:
 
 From a boolean logic perspective, top-level match objects are `OR`-ed together and individual match rules within an object are `AND`-ed. Combined with `!` negation, you can write complex matching rules.
 
-> ⚠️ This action uses [micromatch](https://www.npmjs.com/package/micromatch) to apply glob patterns.
+> ⚠️ This action uses [minimatch](https://www.npmjs.com/package/minimatch) to apply glob patterns.
 > For historical reasons, paths starting with dot (e.g. `.github`) are not matched by default.
 > You need to set `dot: true` to change this behavior.
 > See [Inputs](#inputs) table below for details.