diff --git a/lib/modules/datasource/go/goproxy-parser.spec.ts b/lib/modules/datasource/go/goproxy-parser.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3dc0cd067f6e5e04c80ae590b585b32765deef19 --- /dev/null +++ b/lib/modules/datasource/go/goproxy-parser.spec.ts @@ -0,0 +1,135 @@ +import * as memCache from '../../../util/cache/memory'; +import { parseGoproxy, parseNoproxy } from './goproxy-parser'; + +describe('modules/datasource/go/goproxy-parser', () => { + beforeEach(() => { + memCache.init(); + }); + + describe('parseGoproxy', () => { + it('parses single url', () => { + const result = parseGoproxy('foo'); + expect(result).toMatchObject([{ url: 'foo' }]); + }); + + it('parses multiple urls', () => { + const result = parseGoproxy('foo,bar|baz,qux'); + expect(result).toMatchObject([ + { url: 'foo', fallback: ',' }, + { url: 'bar', fallback: '|' }, + { url: 'baz', fallback: ',' }, + { url: 'qux' }, + ]); + }); + + it('ignores everything starting from "direct" and "off" keywords', () => { + expect(parseGoproxy(undefined)).toBeEmpty(); + expect(parseGoproxy(undefined)).toBeEmpty(); + expect(parseGoproxy('')).toBeEmpty(); + expect(parseGoproxy('off')).toMatchObject([ + { url: 'off', fallback: '|' }, + ]); + expect(parseGoproxy('direct')).toMatchObject([ + { url: 'direct', fallback: '|' }, + ]); + expect(parseGoproxy('foo,off|direct,qux')).toMatchObject([ + { url: 'foo', fallback: ',' }, + { url: 'off', fallback: '|' }, + { url: 'direct', fallback: ',' }, + { url: 'qux', fallback: '|' }, + ]); + }); + + it('caches results', () => { + expect(parseGoproxy('foo,bar')).toBe(parseGoproxy('foo,bar')); + }); + }); + + describe('parseNoproxy', () => { + it('produces regex', () => { + expect(parseNoproxy(undefined)).toBeNull(); + expect(parseNoproxy(null)).toBeNull(); + expect(parseNoproxy('')).toBeNull(); + expect(parseNoproxy('/')).toBeNull(); + expect(parseNoproxy('*')?.source).toBe('^(?:[^\\/]*)(?:\\/.*)?$'); + expect(parseNoproxy('?')?.source).toBe('^(?:[^\\/])(?:\\/.*)?$'); + expect(parseNoproxy('foo')?.source).toBe('^(?:foo)(?:\\/.*)?$'); + expect(parseNoproxy('\\f\\o\\o')?.source).toBe('^(?:foo)(?:\\/.*)?$'); + expect(parseNoproxy('foo,bar')?.source).toBe('^(?:foo|bar)(?:\\/.*)?$'); + expect(parseNoproxy('[abc]')?.source).toBe('^(?:[abc])(?:\\/.*)?$'); + expect(parseNoproxy('[a-c]')?.source).toBe('^(?:[a-c])(?:\\/.*)?$'); + expect(parseNoproxy('[\\a-\\c]')?.source).toBe('^(?:[a-c])(?:\\/.*)?$'); + expect(parseNoproxy('a.b.c')?.source).toBe('^(?:a\\.b\\.c)(?:\\/.*)?$'); + expect(parseNoproxy('trailing/')?.source).toBe( + '^(?:trailing)(?:\\/.*)?$', + ); + }); + + it('matches on real package prefixes', () => { + expect(parseNoproxy('ex.co')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('ex.co/')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar')).toBeTrue(); + expect(parseNoproxy('*/foo/*')?.test('example.com/foo/bar')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/bar')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/baz')).toBeTrue(); + expect(parseNoproxy('ex.co')?.test('ex.co/foo/v2')).toBeTrue(); + + expect(parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar')).toBeTrue(); + expect(parseNoproxy('*/foo/*')?.test('example.com/foo/bar')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/bar')).toBeTrue(); + expect(parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/baz')).toBeTrue(); + expect( + parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test('ex.co/foo/bar'), + ).toBeTrue(); + expect( + parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test('ex.co/foo/baz'), + ).toBeTrue(); + expect( + parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test('ex.co/foo/qux'), + ).toBeFalse(); + + expect(parseNoproxy('ex')?.test('ex.co/foo')).toBeFalse(); + + expect(parseNoproxy('aba')?.test('x/aba')).toBeFalse(); + expect(parseNoproxy('x/b')?.test('x/aba')).toBeFalse(); + expect(parseNoproxy('x/ab')?.test('x/aba')).toBeFalse(); + expect(parseNoproxy('x/ab[a-b]')?.test('x/aba')).toBeTrue(); + }); + + it('matches on wildcards', () => { + expect(parseNoproxy('/*/')?.test('ex.co/foo')).toBeFalse(); + expect(parseNoproxy('*/foo')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('*/fo')?.test('ex.co/foo')).toBeFalse(); + expect(parseNoproxy('*/fo?')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('*/fo*')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('*fo*')?.test('ex.co/foo')).toBeFalse(); + + expect(parseNoproxy('*.co')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('ex*')?.test('ex.co/foo')).toBeTrue(); + expect(parseNoproxy('*/foo')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/foo/')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/foo/*')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/foo/*/')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/v2')?.test('ex.co/foo/v2')).toBeFalse(); + expect(parseNoproxy('*/*/v2')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/*/*')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/*/*/')?.test('ex.co/foo/v2')).toBeTrue(); + expect(parseNoproxy('*/*/*')?.test('ex.co/foo')).toBeFalse(); + expect(parseNoproxy('*/*/*/')?.test('ex.co/foo')).toBeFalse(); + + expect(parseNoproxy('*/*/*,,')?.test('ex.co/repo')).toBeFalse(); + expect(parseNoproxy('*/*/*,,*/repo')?.test('ex.co/repo')).toBeTrue(); + expect(parseNoproxy(',,*/repo')?.test('ex.co/repo')).toBeTrue(); + }); + + it('matches on character ranges', () => { + expect(parseNoproxy('x/ab[a-b]')?.test('x/aba')).toBeTrue(); + expect(parseNoproxy('x/ab[a-b]')?.test('x/abc')).toBeFalse(); + }); + + it('caches results', () => { + expect(parseNoproxy('foo/bar')).toBe(parseNoproxy('foo/bar')); + }); + }); +}); diff --git a/lib/modules/datasource/go/goproxy-parser.ts b/lib/modules/datasource/go/goproxy-parser.ts new file mode 100644 index 0000000000000000000000000000000000000000..78f8bdd4feae4a3937669d48757ec124eadb26db --- /dev/null +++ b/lib/modules/datasource/go/goproxy-parser.ts @@ -0,0 +1,115 @@ +import is from '@sindresorhus/is'; +import moo from 'moo'; +import * as memCache from '../../../util/cache/memory'; +import { regEx } from '../../../util/regex'; +import type { GoproxyItem } from './types'; + +/** + * Parse `GOPROXY` to the sequence of url + fallback strategy tags. + * + * @example + * parseGoproxy('foo.example.com|bar.example.com,baz.example.com') + * // [ + * // { url: 'foo.example.com', fallback: '|' }, + * // { url: 'bar.example.com', fallback: ',' }, + * // { url: 'baz.example.com', fallback: '|' }, + * // ] + * + * @see https://golang.org/ref/mod#goproxy-protocol + */ +export function parseGoproxy( + input: string | undefined = process.env.GOPROXY, +): GoproxyItem[] { + if (!is.string(input)) { + return []; + } + + const cacheKey = `goproxy::${input}`; + const cachedResult = memCache.get<GoproxyItem[]>(cacheKey); + if (cachedResult) { + return cachedResult; + } + + const result: GoproxyItem[] = input + .split(regEx(/([^,|]*(?:,|\|))/)) + .filter(Boolean) + .map((s) => s.split(/(?=,|\|)/)) // TODO: #12872 lookahead + .map(([url, separator]) => ({ + url, + fallback: separator === ',' ? ',' : '|', + })); + + memCache.set(cacheKey, result); + return result; +} + +// https://golang.org/pkg/path/#Match +const noproxyLexer = moo.states({ + main: { + separator: { + match: /\s*?,\s*?/, // TODO #12870 + value: (_: string) => '|', + }, + asterisk: { + match: '*', + value: (_: string) => '[^/]*', + }, + qmark: { + match: '?', + value: (_: string) => '[^/]', + }, + characterRangeOpen: { + match: '[', + push: 'characterRange', + value: (_: string) => '[', + }, + trailingSlash: { + match: /\/$/, + value: (_: string) => '', + }, + char: { + match: /[^*?\\[\n]/, + value: (s: string) => s.replace(regEx('\\.', 'g'), '\\.'), + }, + escapedChar: { + match: /\\./, // TODO #12870 + value: (s: string) => s.slice(1), + }, + }, + characterRange: { + char: /[^\\\]\n]/, // TODO #12870 + escapedChar: { + match: /\\./, // TODO #12870 + value: (s: string) => s.slice(1), + }, + characterRangeEnd: { + match: ']', + pop: 1, + }, + }, +}); + +export function parseNoproxy( + input: unknown = process.env.GONOPROXY ?? process.env.GOPRIVATE, +): RegExp | null { + if (!is.string(input)) { + return null; + } + + const cacheKey = `noproxy::${input}`; + const cachedResult = memCache.get<RegExp | null>(cacheKey); + if (cachedResult !== undefined) { + return cachedResult; + } + + const noproxyPattern = [...noproxyLexer.reset(input)] + .map(({ value }) => value) + .join(''); + + const result = noproxyPattern + ? regEx(`^(?:${noproxyPattern})(?:/.*)?$`) + : null; + + memCache.set(cacheKey, result); + return result; +} diff --git a/lib/modules/datasource/go/releases-goproxy.spec.ts b/lib/modules/datasource/go/releases-goproxy.spec.ts index 708c8e39ab41b2c8b597569f5e289f0fe815ca40..e7e37584051a783e0ff263748a62fd692d8f5da5 100644 --- a/lib/modules/datasource/go/releases-goproxy.spec.ts +++ b/lib/modules/datasource/go/releases-goproxy.spec.ts @@ -59,223 +59,6 @@ describe('modules/datasource/go/releases-goproxy', () => { }); }); - describe('parseGoproxy', () => { - it('parses single url', () => { - const result = datasource.parseGoproxy('foo'); - expect(result).toMatchObject([{ url: 'foo' }]); - }); - - it('parses multiple urls', () => { - const result = datasource.parseGoproxy('foo,bar|baz,qux'); - expect(result).toMatchObject([ - { url: 'foo', fallback: ',' }, - { url: 'bar', fallback: '|' }, - { url: 'baz', fallback: ',' }, - { url: 'qux' }, - ]); - }); - - it('ignores everything starting from "direct" and "off" keywords', () => { - expect(datasource.parseGoproxy(undefined)).toBeEmpty(); - expect(datasource.parseGoproxy(undefined)).toBeEmpty(); - expect(datasource.parseGoproxy('')).toBeEmpty(); - expect(datasource.parseGoproxy('off')).toMatchObject([ - { url: 'off', fallback: '|' }, - ]); - expect(datasource.parseGoproxy('direct')).toMatchObject([ - { url: 'direct', fallback: '|' }, - ]); - expect(datasource.parseGoproxy('foo,off|direct,qux')).toMatchObject([ - { url: 'foo', fallback: ',' }, - { url: 'off', fallback: '|' }, - { url: 'direct', fallback: ',' }, - { url: 'qux', fallback: '|' }, - ]); - }); - }); - - describe('GoProxyDatasource.parseNoproxy', () => { - it('produces regex', () => { - expect(GoProxyDatasource.parseNoproxy(undefined)).toBeNull(); - expect(GoProxyDatasource.parseNoproxy(null)).toBeNull(); - expect(GoProxyDatasource.parseNoproxy('')).toBeNull(); - expect(GoProxyDatasource.parseNoproxy('/')).toBeNull(); - expect(GoProxyDatasource.parseNoproxy('*')?.source).toBe( - '^(?:[^\\/]*)(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('?')?.source).toBe( - '^(?:[^\\/])(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('foo')?.source).toBe( - '^(?:foo)(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('\\f\\o\\o')?.source).toBe( - '^(?:foo)(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('foo,bar')?.source).toBe( - '^(?:foo|bar)(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('[abc]')?.source).toBe( - '^(?:[abc])(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('[a-c]')?.source).toBe( - '^(?:[a-c])(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('[\\a-\\c]')?.source).toBe( - '^(?:[a-c])(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('a.b.c')?.source).toBe( - '^(?:a\\.b\\.c)(?:\\/.*)?$', - ); - expect(GoProxyDatasource.parseNoproxy('trailing/')?.source).toBe( - '^(?:trailing)(?:\\/.*)?$', - ); - }); - - it('matches on real package prefixes', () => { - expect( - GoProxyDatasource.parseNoproxy('ex.co')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo/*')?.test('example.com/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/baz'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co')?.test('ex.co/foo/v2'), - ).toBeTrue(); - - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar')?.test('ex.co/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo/*')?.test('example.com/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/bar'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/*')?.test('ex.co/foo/baz'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test( - 'ex.co/foo/bar', - ), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test( - 'ex.co/foo/baz', - ), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex.co/foo/bar,ex.co/foo/baz')?.test( - 'ex.co/foo/qux', - ), - ).toBeFalse(); - - expect( - GoProxyDatasource.parseNoproxy('ex')?.test('ex.co/foo'), - ).toBeFalse(); - - expect(GoProxyDatasource.parseNoproxy('aba')?.test('x/aba')).toBeFalse(); - expect(GoProxyDatasource.parseNoproxy('x/b')?.test('x/aba')).toBeFalse(); - expect(GoProxyDatasource.parseNoproxy('x/ab')?.test('x/aba')).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('x/ab[a-b]')?.test('x/aba'), - ).toBeTrue(); - }); - - it('matches on wildcards', () => { - expect( - GoProxyDatasource.parseNoproxy('/*/')?.test('ex.co/foo'), - ).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('*/foo')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/fo')?.test('ex.co/foo'), - ).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('*/fo?')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/fo*')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*fo*')?.test('ex.co/foo'), - ).toBeFalse(); - - expect( - GoProxyDatasource.parseNoproxy('*.co')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('ex*')?.test('ex.co/foo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo/')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo/*')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/foo/*/')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/v2')?.test('ex.co/foo/v2'), - ).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('*/*/v2')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/*/*')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/*/*/')?.test('ex.co/foo/v2'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('*/*/*')?.test('ex.co/foo'), - ).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('*/*/*/')?.test('ex.co/foo'), - ).toBeFalse(); - - expect( - GoProxyDatasource.parseNoproxy('*/*/*,,')?.test('ex.co/repo'), - ).toBeFalse(); - expect( - GoProxyDatasource.parseNoproxy('*/*/*,,*/repo')?.test('ex.co/repo'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy(',,*/repo')?.test('ex.co/repo'), - ).toBeTrue(); - }); - - it('matches on character ranges', () => { - expect( - GoProxyDatasource.parseNoproxy('x/ab[a-b]')?.test('x/aba'), - ).toBeTrue(); - expect( - GoProxyDatasource.parseNoproxy('x/ab[a-b]')?.test('x/abc'), - ).toBeFalse(); - }); - }); - describe('getReleases', () => { const baseUrl = 'https://proxy.golang.org'; diff --git a/lib/modules/datasource/go/releases-goproxy.ts b/lib/modules/datasource/go/releases-goproxy.ts index fc98b95b23a71487c4e66b03f703654c39031ee0..b0a3e4700adc84cf0d4b82b113a7fff38163e156 100644 --- a/lib/modules/datasource/go/releases-goproxy.ts +++ b/lib/modules/datasource/go/releases-goproxy.ts @@ -1,6 +1,5 @@ import is from '@sindresorhus/is'; import { DateTime } from 'luxon'; -import moo from 'moo'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; import { filterMap } from '../../../util/filter-map'; @@ -12,10 +11,9 @@ import { Datasource } from '../datasource'; import type { GetReleasesConfig, Release, ReleaseResult } from '../types'; import { BaseGoDatasource } from './base'; import { getSourceUrl } from './common'; +import { parseGoproxy, parseNoproxy } from './goproxy-parser'; import { GoDirectDatasource } from './releases-direct'; -import type { GoproxyItem, VersionInfo } from './types'; - -const parsedGoproxy: Record<string, GoproxyItem[]> = {}; +import type { VersionInfo } from './types'; const modRegex = regEx(/^(?<baseMod>.*?)(?:[./]v(?<majorVersion>\d+))?$/); @@ -46,8 +44,8 @@ export class GoProxyDatasource extends Datasource { if (goproxy === 'direct') { return this.direct.getReleases(config); } - const proxyList = this.parseGoproxy(goproxy); - const noproxy = GoProxyDatasource.parseNoproxy(); + const proxyList = parseGoproxy(goproxy); + const noproxy = parseNoproxy(); let result: ReleaseResult | null = null; @@ -103,106 +101,6 @@ export class GoProxyDatasource extends Datasource { return result; } - /** - * Parse `GOPROXY` to the sequence of url + fallback strategy tags. - * - * @example - * parseGoproxy('foo.example.com|bar.example.com,baz.example.com') - * // [ - * // { url: 'foo.example.com', fallback: '|' }, - * // { url: 'bar.example.com', fallback: ',' }, - * // { url: 'baz.example.com', fallback: '|' }, - * // ] - * - * @see https://golang.org/ref/mod#goproxy-protocol - */ - parseGoproxy(input: string | undefined = process.env.GOPROXY): GoproxyItem[] { - if (!is.string(input)) { - return []; - } - - if (parsedGoproxy[input]) { - return parsedGoproxy[input]; - } - - const result: GoproxyItem[] = input - .split(regEx(/([^,|]*(?:,|\|))/)) - .filter(Boolean) - .map((s) => s.split(/(?=,|\|)/)) // TODO: #12872 lookahead - .map(([url, separator]) => ({ - url, - fallback: separator === ',' ? ',' : '|', - })); - - parsedGoproxy[input] = result; - return result; - } - // https://golang.org/pkg/path/#Match - static lexer = moo.states({ - main: { - separator: { - match: /\s*?,\s*?/, // TODO #12870 - value: (_: string) => '|', - }, - asterisk: { - match: '*', - value: (_: string) => '[^/]*', - }, - qmark: { - match: '?', - value: (_: string) => '[^/]', - }, - characterRangeOpen: { - match: '[', - push: 'characterRange', - value: (_: string) => '[', - }, - trailingSlash: { - match: /\/$/, - value: (_: string) => '', - }, - char: { - match: /[^*?\\[\n]/, - value: (s: string) => s.replace(regEx('\\.', 'g'), '\\.'), - }, - escapedChar: { - match: /\\./, // TODO #12870 - value: (s: string) => s.slice(1), - }, - }, - characterRange: { - char: /[^\\\]\n]/, // TODO #12870 - escapedChar: { - match: /\\./, // TODO #12870 - value: (s: string) => s.slice(1), - }, - characterRangeEnd: { - match: ']', - pop: 1, - }, - }, - }); - - static parsedNoproxy: Record<string, RegExp | null> = {}; - - static parseNoproxy( - input: unknown = process.env.GONOPROXY ?? process.env.GOPRIVATE, - ): RegExp | null { - if (!is.string(input)) { - return null; - } - if (this.parsedNoproxy[input] !== undefined) { - return this.parsedNoproxy[input]; - } - this.lexer.reset(input); - const noproxyPattern = [...this.lexer].map(({ value }) => value).join(''); - const result = noproxyPattern - ? regEx(`^(?:${noproxyPattern})(?:/.*)?$`) - : null; - this.parsedNoproxy[input] = result; - return result; - } - /** * Avoid ambiguity when serving from case-insensitive file systems. * @@ -344,7 +242,7 @@ export class GoProxyDatasource extends Datasource { static getCacheKey({ packageName }: GetReleasesConfig): string { const goproxy = process.env.GOPROXY; - const noproxy = GoProxyDatasource.parseNoproxy(); + const noproxy = parseNoproxy(); // TODO: types (#22198) return `${packageName}@@${goproxy}@@${noproxy?.toString()}`; }