@verdaccio/package-filter 14.0.0-next-9.55 → 14.0.0-next-9.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -8
- package/build/config/parser.js +2 -0
- package/build/config/parser.js.map +1 -1
- package/build/config/parser.mjs +2 -0
- package/build/config/parser.mjs.map +1 -1
- package/build/config/types.d.ts +1 -1
- package/build/filtering/matcher.d.ts +5 -0
- package/build/filtering/matcher.js +82 -16
- package/build/filtering/matcher.js.map +1 -1
- package/build/filtering/matcher.mjs +82 -17
- package/build/filtering/matcher.mjs.map +1 -1
- package/build/packageFilter.js +1 -1
- package/build/packageFilter.mjs +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -69,18 +69,20 @@ When both `minAgeDays` and `dateThreshold` are set, the **earlier** cutoff wins
|
|
|
69
69
|
|
|
70
70
|
### Block by Scope
|
|
71
71
|
|
|
72
|
-
Block all packages under a scope.
|
|
72
|
+
Block all packages under a scope. Scope values can be exact names or glob patterns.
|
|
73
|
+
Scope globs are matched against only the extracted scope name, for example `@babel`, so use patterns like `@babel*` or `@my-org-*` instead of `@babel/*`.
|
|
73
74
|
|
|
74
75
|
```yaml
|
|
75
76
|
filters:
|
|
76
77
|
'@verdaccio/package-filter':
|
|
77
78
|
block:
|
|
78
79
|
- scope: '@evilscope'
|
|
80
|
+
- scope: '@my-org-*'
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
### Block by Package Name
|
|
82
84
|
|
|
83
|
-
Block all versions of a specific package.
|
|
85
|
+
Block all versions of a specific package. Package values can be exact names or glob patterns.
|
|
84
86
|
|
|
85
87
|
```yaml
|
|
86
88
|
filters:
|
|
@@ -88,11 +90,13 @@ filters:
|
|
|
88
90
|
block:
|
|
89
91
|
- package: 'malicious-pkg'
|
|
90
92
|
- package: '@coolauthor/stolen'
|
|
93
|
+
- package: 'react-*'
|
|
94
|
+
- package: '@legacy/*'
|
|
91
95
|
```
|
|
92
96
|
|
|
93
97
|
### Block by Version Range
|
|
94
98
|
|
|
95
|
-
Block specific semver ranges of a package.
|
|
99
|
+
Block specific semver ranges of a package. Package values can be exact names or glob patterns. Version ranges use [semver](https://www.npmjs.com/package/semver) syntax.
|
|
96
100
|
|
|
97
101
|
```yaml
|
|
98
102
|
filters:
|
|
@@ -100,6 +104,8 @@ filters:
|
|
|
100
104
|
block:
|
|
101
105
|
- package: '@coolauthor/stolen'
|
|
102
106
|
versions: '>2.0.1'
|
|
107
|
+
- package: '@legacy/*'
|
|
108
|
+
versions: '>=3.0.0'
|
|
103
109
|
```
|
|
104
110
|
|
|
105
111
|
Multiple version ranges for the same package are merged:
|
|
@@ -161,11 +167,11 @@ filters:
|
|
|
161
167
|
|
|
162
168
|
Allow rules are checked before block rules. The granularity levels:
|
|
163
169
|
|
|
164
|
-
| Allow rule | Effect
|
|
165
|
-
| ------------------------------------ |
|
|
166
|
-
| `scope: '@x'`
|
|
167
|
-
| `package: 'x'`
|
|
168
|
-
| `package: 'x'` + `versions: '1.0.0'` | Only matching versions are exempted
|
|
170
|
+
| Allow rule | Effect |
|
|
171
|
+
| ------------------------------------ | ------------------------------------------ |
|
|
172
|
+
| `scope: '@x'` or `scope: '@x-*'` | Entire matching scope bypasses all rules |
|
|
173
|
+
| `package: 'x'` or `package: 'x-*'` | Entire matching package bypasses all rules |
|
|
174
|
+
| `package: 'x'` + `versions: '1.0.0'` | Only matching versions are exempted |
|
|
169
175
|
|
|
170
176
|
### Full Example
|
|
171
177
|
|
package/build/config/parser.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_runtime = require("../_virtual/_rolldown/runtime.js");
|
|
2
|
+
const require_matcher = require("../filtering/matcher.js");
|
|
2
3
|
let debug = require("debug");
|
|
3
4
|
debug = require_runtime.__toESM(debug);
|
|
4
5
|
let semver = require("semver");
|
|
@@ -28,6 +29,7 @@ function parseConfigRules(configRules) {
|
|
|
28
29
|
}
|
|
29
30
|
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
30
31
|
}
|
|
32
|
+
require_matcher.prepareRules(ruleMap);
|
|
31
33
|
return ruleMap;
|
|
32
34
|
}
|
|
33
35
|
function parseConfig(config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.js","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport { prepareRules } from '../filtering/matcher';\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n prepareRules(ruleMap);\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;;;;AAMA,IAAM,WAAA,GAAQ,MAAA,QAAA,CAAW,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,OAAA,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,gBAAA,aAAa,OAAO;CACpB,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,QAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,QAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,MAAM,oBAAoB,OAAO,sBAAsB;CAEvD,OAAO;EACL;EACA;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
|
package/build/config/parser.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { prepareRules } from "../filtering/matcher.mjs";
|
|
1
2
|
import buildDebug from "debug";
|
|
2
3
|
import { Range } from "semver";
|
|
3
4
|
//#region src/config/parser.ts
|
|
@@ -26,6 +27,7 @@ function parseConfigRules(configRules) {
|
|
|
26
27
|
}
|
|
27
28
|
throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);
|
|
28
29
|
}
|
|
30
|
+
prepareRules(ruleMap);
|
|
29
31
|
return ruleMap;
|
|
30
32
|
}
|
|
31
33
|
function parseConfig(config) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.mjs","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.mjs","names":[],"sources":["../../src/config/parser.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Range } from 'semver';\n\nimport { prepareRules } from '../filtering/matcher';\nimport type { ConfigRule, ParsedConfig, ParsedRule, PluginConfig } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:config');\n\nfunction parseConfigRules(configRules: ConfigRule[]): Map<string, ParsedRule> {\n const ruleMap = new Map<string, ParsedRule>();\n for (const rule of configRules) {\n if ('scope' in rule && typeof rule.scope === 'string') {\n if (!rule.scope.startsWith('@')) {\n throw new TypeError(`Scope value must start with @, found: ${rule.scope}`);\n }\n\n ruleMap.set(rule.scope, 'scope');\n continue;\n }\n\n if ('package' in rule && !('versions' in rule)) {\n ruleMap.set(rule.package, 'package');\n continue;\n }\n\n if ('package' in rule && 'versions' in rule) {\n const previousConfig = ruleMap.get(rule.package) || { versions: [] };\n\n if (typeof previousConfig === 'string') {\n throw new Error(\n `Package ${rule.package} is already specified by another strict rule ${previousConfig}`\n );\n }\n\n // Merge version ranges of the rules for the same package\n const range = new Range(rule.versions);\n ruleMap.set(rule.package, {\n versions: [...previousConfig.versions, range],\n strategy: rule.strategy ?? 'block',\n });\n\n continue;\n }\n\n throw new TypeError(`Could not parse rule ${JSON.stringify(rule, null, 4)}`);\n }\n\n prepareRules(ruleMap);\n return ruleMap;\n}\n\nexport function parseConfig(config: PluginConfig): ParsedConfig {\n debug('parsing config: %o', config);\n const blockMap = parseConfigRules(config.block ?? []);\n const allowMap = parseConfigRules(config.allow ?? []);\n debug('parsed %d block rules, %d allow rules', blockMap.size, allowMap.size);\n const dateThreshold = config.dateThreshold ? new Date(config.dateThreshold) : null;\n if (dateThreshold && isNaN(dateThreshold.getTime())) {\n throw new TypeError(`Invalid date ${config.dateThreshold} was provided for dateThreshold`);\n }\n\n const minAgeDays = config.minAgeDays ? Number(config.minAgeDays) : null;\n let minAgeMs: number | null = null;\n if (minAgeDays !== null) {\n if (isNaN(minAgeDays) || minAgeDays < 0) {\n throw new TypeError(`Invalid number ${config.minAgeDays} was provided for minAgeDays`);\n }\n\n minAgeMs = minAgeDays * 24 * 60 * 60 * 1000;\n }\n\n const excludeDeprecated = config.excludeDeprecated === true;\n\n return {\n dateThreshold,\n minAgeMs,\n excludeDeprecated,\n blockRules: blockMap,\n allowRules: allowMap,\n };\n}\n"],"mappings":";;;;AAMA,IAAM,QAAQ,WAAW,wCAAwC;AAEjE,SAAS,iBAAiB,aAAoD;CAC5E,MAAM,0BAAU,IAAI,IAAwB;CAC5C,KAAK,MAAM,QAAQ,aAAa;EAC9B,IAAI,WAAW,QAAQ,OAAO,KAAK,UAAU,UAAU;GACrD,IAAI,CAAC,KAAK,MAAM,WAAW,GAAG,GAC5B,MAAM,IAAI,UAAU,yCAAyC,KAAK,OAAO;GAG3E,QAAQ,IAAI,KAAK,OAAO,OAAO;GAC/B;EACF;EAEA,IAAI,aAAa,QAAQ,EAAE,cAAc,OAAO;GAC9C,QAAQ,IAAI,KAAK,SAAS,SAAS;GACnC;EACF;EAEA,IAAI,aAAa,QAAQ,cAAc,MAAM;GAC3C,MAAM,iBAAiB,QAAQ,IAAI,KAAK,OAAO,KAAK,EAAE,UAAU,CAAC,EAAE;GAEnE,IAAI,OAAO,mBAAmB,UAC5B,MAAM,IAAI,MACR,WAAW,KAAK,QAAQ,+CAA+C,gBACzE;GAIF,MAAM,QAAQ,IAAI,MAAM,KAAK,QAAQ;GACrC,QAAQ,IAAI,KAAK,SAAS;IACxB,UAAU,CAAC,GAAG,eAAe,UAAU,KAAK;IAC5C,UAAU,KAAK,YAAY;GAC7B,CAAC;GAED;EACF;EAEA,MAAM,IAAI,UAAU,wBAAwB,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG;CAC7E;CAEA,aAAa,OAAO;CACpB,OAAO;AACT;AAEA,SAAgB,YAAY,QAAoC;CAC9D,MAAM,sBAAsB,MAAM;CAClC,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,WAAW,iBAAiB,OAAO,SAAS,CAAC,CAAC;CACpD,MAAM,yCAAyC,SAAS,MAAM,SAAS,IAAI;CAC3E,MAAM,gBAAgB,OAAO,gBAAgB,IAAI,KAAK,OAAO,aAAa,IAAI;CAC9E,IAAI,iBAAiB,MAAM,cAAc,QAAQ,CAAC,GAChD,MAAM,IAAI,UAAU,gBAAgB,OAAO,cAAc,gCAAgC;CAG3F,MAAM,aAAa,OAAO,aAAa,OAAO,OAAO,UAAU,IAAI;CACnE,IAAI,WAA0B;CAC9B,IAAI,eAAe,MAAM;EACvB,IAAI,MAAM,UAAU,KAAK,aAAa,GACpC,MAAM,IAAI,UAAU,kBAAkB,OAAO,WAAW,6BAA6B;EAGvF,WAAW,aAAa,KAAK,KAAK,KAAK;CACzC;CAEA,MAAM,oBAAoB,OAAO,sBAAsB;CAEvD,OAAO;EACL;EACA;EACA;EACA,YAAY;EACZ,YAAY;CACd;AACF"}
|
package/build/config/types.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export interface ParsedConfigRule {
|
|
|
34
34
|
versions: Range[];
|
|
35
35
|
strategy?: BlockStrategy;
|
|
36
36
|
}
|
|
37
|
-
export type PackageScopeLevel = 'scope' | 'package'
|
|
37
|
+
export type PackageScopeLevel = 'scope' | 'package';
|
|
38
38
|
export type ParsedRule = ParsedConfigRule | PackageScopeLevel;
|
|
39
39
|
export interface ParsedConfig {
|
|
40
40
|
dateThreshold: Date | null;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { Manifest } from '@verdaccio/types';
|
|
2
2
|
import type { ParsedRule } from '../config/types';
|
|
3
3
|
import type { MatchResult } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Cache the compiled glob rules for a rule map. Call again after changing the map.
|
|
6
|
+
*/
|
|
7
|
+
export declare function prepareRules(rules: Map<string, ParsedRule>): void;
|
|
4
8
|
/**
|
|
5
9
|
* Try to find a rule that matches the package.
|
|
6
10
|
* If found, returns the rule and the matched package versions from the manifest.
|
|
11
|
+
* Rule maps are cached; call prepareRules after modifying them.
|
|
7
12
|
*/
|
|
8
13
|
export declare function matchRules(manifest: Manifest, rules: Map<string, ParsedRule>): MatchResult | undefined;
|
|
9
14
|
/**
|
|
@@ -3,8 +3,71 @@ const require_types = require("./types.js");
|
|
|
3
3
|
let debug = require("debug");
|
|
4
4
|
debug = require_runtime.__toESM(debug);
|
|
5
5
|
let semver = require("semver");
|
|
6
|
+
let minimatch = require("minimatch");
|
|
6
7
|
//#region src/filtering/matcher.ts
|
|
7
8
|
var debug$1 = (0, debug.default)("verdaccio:plugin:package-filter:filter");
|
|
9
|
+
var compiledGlobRules = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
var globMagic = /[\\*?[\]{}!]|[+@]\(/;
|
|
11
|
+
/**
|
|
12
|
+
* Compile patterns requiring glob or escape handling, grouped by rule type.
|
|
13
|
+
*/
|
|
14
|
+
function compileGlobRules(rules) {
|
|
15
|
+
const compiled = {
|
|
16
|
+
packages: [],
|
|
17
|
+
scopes: []
|
|
18
|
+
};
|
|
19
|
+
for (const [pattern, rule] of rules) {
|
|
20
|
+
if (!globMagic.test(pattern)) continue;
|
|
21
|
+
const compiledRule = {
|
|
22
|
+
pattern,
|
|
23
|
+
matcher: new minimatch.Minimatch(pattern),
|
|
24
|
+
rule
|
|
25
|
+
};
|
|
26
|
+
if (rule === "scope") compiled.scopes.push(compiledRule);
|
|
27
|
+
else compiled.packages.push(compiledRule);
|
|
28
|
+
}
|
|
29
|
+
return compiled;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Cache the compiled glob rules for a rule map. Call again after changing the map.
|
|
33
|
+
*/
|
|
34
|
+
function prepareRules(rules) {
|
|
35
|
+
compiledGlobRules.set(rules, compileGlobRules(rules));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Return cached glob rules, compiling and caching unprepared maps on first use.
|
|
39
|
+
*/
|
|
40
|
+
function getCompiledGlobRules(rules) {
|
|
41
|
+
let compiled = compiledGlobRules.get(rules);
|
|
42
|
+
if (!compiled) {
|
|
43
|
+
compiled = compileGlobRules(rules);
|
|
44
|
+
compiledGlobRules.set(rules, compiled);
|
|
45
|
+
}
|
|
46
|
+
return compiled;
|
|
47
|
+
}
|
|
48
|
+
function findScopeRule(scope, rules) {
|
|
49
|
+
if (!scope) return;
|
|
50
|
+
const exactRule = rules.get(scope);
|
|
51
|
+
if (exactRule === "scope") return {
|
|
52
|
+
scope,
|
|
53
|
+
rule: exactRule
|
|
54
|
+
};
|
|
55
|
+
for (const { pattern, matcher } of getCompiledGlobRules(rules).scopes) if (matcher.match(scope)) return {
|
|
56
|
+
scope: pattern,
|
|
57
|
+
rule: "scope"
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function findPackageRule(packageName, rules) {
|
|
61
|
+
const exactRule = rules.get(packageName);
|
|
62
|
+
if (exactRule) return {
|
|
63
|
+
pattern: packageName,
|
|
64
|
+
rule: exactRule
|
|
65
|
+
};
|
|
66
|
+
for (const { pattern, matcher, rule } of getCompiledGlobRules(rules).packages) if (matcher.match(packageName)) return {
|
|
67
|
+
pattern,
|
|
68
|
+
rule
|
|
69
|
+
};
|
|
70
|
+
}
|
|
8
71
|
/**
|
|
9
72
|
* Split a package name into name itself and scope.
|
|
10
73
|
*/
|
|
@@ -20,29 +83,31 @@ function splitName(name) {
|
|
|
20
83
|
/**
|
|
21
84
|
* Try to find a rule that matches the package.
|
|
22
85
|
* If found, returns the rule and the matched package versions from the manifest.
|
|
86
|
+
* Rule maps are cached; call prepareRules after modifying them.
|
|
23
87
|
*/
|
|
24
88
|
function matchRules(manifest, rules) {
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
89
|
+
const packageName = manifest.name;
|
|
90
|
+
if (!packageName) return;
|
|
91
|
+
const { scope } = splitName(packageName);
|
|
92
|
+
const scopeMatch = findScopeRule(scope, rules);
|
|
93
|
+
if (scopeMatch) {
|
|
94
|
+
debug$1("scope match: %s matched rule for %s", packageName, scopeMatch.scope);
|
|
95
|
+
return {
|
|
96
|
+
type: require_types.MatchType.SCOPE,
|
|
97
|
+
rule: scopeMatch.rule,
|
|
98
|
+
scope: scopeMatch.scope,
|
|
99
|
+
versions: Object.keys(manifest.versions)
|
|
100
|
+
};
|
|
37
101
|
}
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
102
|
+
const packageMatch = findPackageRule(packageName, rules);
|
|
103
|
+
if (!packageMatch) return;
|
|
104
|
+
const { rule } = packageMatch;
|
|
40
105
|
if (rule === "package") {
|
|
41
|
-
debug$1("package match: %s",
|
|
106
|
+
debug$1("package match: %s matched rule for %s", packageName, packageMatch.pattern);
|
|
42
107
|
return {
|
|
43
108
|
type: require_types.MatchType.PACKAGE,
|
|
44
109
|
rule,
|
|
45
|
-
package:
|
|
110
|
+
package: packageMatch.pattern,
|
|
46
111
|
versions: Object.keys(manifest.versions)
|
|
47
112
|
};
|
|
48
113
|
}
|
|
@@ -78,6 +143,7 @@ function resolveAllowList(allowMatch) {
|
|
|
78
143
|
}
|
|
79
144
|
//#endregion
|
|
80
145
|
exports.matchRules = matchRules;
|
|
146
|
+
exports.prepareRules = prepareRules;
|
|
81
147
|
exports.resolveAllowList = resolveAllowList;
|
|
82
148
|
|
|
83
149
|
//# sourceMappingURL=matcher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.js","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const
|
|
1
|
+
{"version":3,"file":"matcher.js","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Minimatch } from 'minimatch';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\ninterface CompiledGlobRule {\n pattern: string;\n matcher: Minimatch;\n rule: ParsedRule;\n}\n\ninterface CompiledGlobRules {\n packages: CompiledGlobRule[];\n scopes: CompiledGlobRule[];\n}\n\nconst compiledGlobRules = new WeakMap<Map<string, ParsedRule>, CompiledGlobRules>();\nconst globMagic = /[\\\\*?[\\]{}!]|[+@]\\(/;\n\n/**\n * Compile patterns requiring glob or escape handling, grouped by rule type.\n */\nfunction compileGlobRules(rules: Map<string, ParsedRule>): CompiledGlobRules {\n const compiled: CompiledGlobRules = { packages: [], scopes: [] };\n\n for (const [pattern, rule] of rules) {\n if (!globMagic.test(pattern)) {\n continue;\n }\n\n const matcher = new Minimatch(pattern);\n const compiledRule = { pattern, matcher, rule };\n if (rule === 'scope') {\n compiled.scopes.push(compiledRule);\n } else {\n compiled.packages.push(compiledRule);\n }\n }\n\n return compiled;\n}\n\n/**\n * Cache the compiled glob rules for a rule map. Call again after changing the map.\n */\nexport function prepareRules(rules: Map<string, ParsedRule>): void {\n compiledGlobRules.set(rules, compileGlobRules(rules));\n}\n\n/**\n * Return cached glob rules, compiling and caching unprepared maps on first use.\n */\nfunction getCompiledGlobRules(rules: Map<string, ParsedRule>): CompiledGlobRules {\n let compiled = compiledGlobRules.get(rules);\n if (!compiled) {\n compiled = compileGlobRules(rules);\n compiledGlobRules.set(rules, compiled);\n }\n\n return compiled;\n}\n\nfunction findScopeRule(\n scope: string | undefined,\n rules: Map<string, ParsedRule>\n): { scope: string; rule: 'scope' } | undefined {\n if (!scope) {\n return undefined;\n }\n\n const exactRule = rules.get(scope);\n if (exactRule === 'scope') {\n return { scope, rule: exactRule };\n }\n\n for (const { pattern, matcher } of getCompiledGlobRules(rules).scopes) {\n if (matcher.match(scope)) {\n return { scope: pattern, rule: 'scope' };\n }\n }\n\n return undefined;\n}\n\nfunction findPackageRule(\n packageName: string,\n rules: Map<string, ParsedRule>\n): { pattern: string; rule: ParsedRule } | undefined {\n const exactRule = rules.get(packageName);\n if (exactRule) {\n return { pattern: packageName, rule: exactRule };\n }\n\n for (const { pattern, matcher, rule } of getCompiledGlobRules(rules).packages) {\n if (matcher.match(packageName)) {\n return { pattern, rule };\n }\n }\n\n return undefined;\n}\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n * Rule maps are cached; call prepareRules after modifying them.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const packageName = manifest.name;\n if (!packageName) {\n return undefined;\n }\n\n const { scope } = splitName(packageName);\n const scopeMatch = findScopeRule(scope, rules);\n if (scopeMatch) {\n debug('scope match: %s matched rule for %s', packageName, scopeMatch.scope);\n return {\n type: MatchType.SCOPE,\n rule: scopeMatch.rule,\n scope: scopeMatch.scope,\n versions: Object.keys(manifest.versions),\n };\n }\n\n const packageMatch = findPackageRule(packageName, rules);\n if (!packageMatch) {\n // No match\n return undefined;\n }\n const { rule } = packageMatch;\n\n if (rule === 'package') {\n debug('package match: %s matched rule for %s', packageName, packageMatch.pattern);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: packageMatch.pattern,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n\n/**\n * Derive the allow-list outcome from a precomputed allow-rule match:\n * whether the whole package/scope is allow-listed, and which versions\n * (if any) are individually whitelisted.\n */\nexport function resolveAllowList(allowMatch: MatchResult | undefined): {\n allowAll: boolean;\n whitelistedVersions: string[];\n} {\n const allowAll =\n !!allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE);\n return { allowAll, whitelistedVersions: allowMatch?.versions ?? [] };\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,71 @@
|
|
|
1
1
|
import { MatchType } from "./types.mjs";
|
|
2
2
|
import buildDebug from "debug";
|
|
3
3
|
import { satisfies } from "semver";
|
|
4
|
+
import { Minimatch } from "minimatch";
|
|
4
5
|
//#region src/filtering/matcher.ts
|
|
5
6
|
var debug = buildDebug("verdaccio:plugin:package-filter:filter");
|
|
7
|
+
var compiledGlobRules = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
var globMagic = /[\\*?[\]{}!]|[+@]\(/;
|
|
9
|
+
/**
|
|
10
|
+
* Compile patterns requiring glob or escape handling, grouped by rule type.
|
|
11
|
+
*/
|
|
12
|
+
function compileGlobRules(rules) {
|
|
13
|
+
const compiled = {
|
|
14
|
+
packages: [],
|
|
15
|
+
scopes: []
|
|
16
|
+
};
|
|
17
|
+
for (const [pattern, rule] of rules) {
|
|
18
|
+
if (!globMagic.test(pattern)) continue;
|
|
19
|
+
const compiledRule = {
|
|
20
|
+
pattern,
|
|
21
|
+
matcher: new Minimatch(pattern),
|
|
22
|
+
rule
|
|
23
|
+
};
|
|
24
|
+
if (rule === "scope") compiled.scopes.push(compiledRule);
|
|
25
|
+
else compiled.packages.push(compiledRule);
|
|
26
|
+
}
|
|
27
|
+
return compiled;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Cache the compiled glob rules for a rule map. Call again after changing the map.
|
|
31
|
+
*/
|
|
32
|
+
function prepareRules(rules) {
|
|
33
|
+
compiledGlobRules.set(rules, compileGlobRules(rules));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Return cached glob rules, compiling and caching unprepared maps on first use.
|
|
37
|
+
*/
|
|
38
|
+
function getCompiledGlobRules(rules) {
|
|
39
|
+
let compiled = compiledGlobRules.get(rules);
|
|
40
|
+
if (!compiled) {
|
|
41
|
+
compiled = compileGlobRules(rules);
|
|
42
|
+
compiledGlobRules.set(rules, compiled);
|
|
43
|
+
}
|
|
44
|
+
return compiled;
|
|
45
|
+
}
|
|
46
|
+
function findScopeRule(scope, rules) {
|
|
47
|
+
if (!scope) return;
|
|
48
|
+
const exactRule = rules.get(scope);
|
|
49
|
+
if (exactRule === "scope") return {
|
|
50
|
+
scope,
|
|
51
|
+
rule: exactRule
|
|
52
|
+
};
|
|
53
|
+
for (const { pattern, matcher } of getCompiledGlobRules(rules).scopes) if (matcher.match(scope)) return {
|
|
54
|
+
scope: pattern,
|
|
55
|
+
rule: "scope"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function findPackageRule(packageName, rules) {
|
|
59
|
+
const exactRule = rules.get(packageName);
|
|
60
|
+
if (exactRule) return {
|
|
61
|
+
pattern: packageName,
|
|
62
|
+
rule: exactRule
|
|
63
|
+
};
|
|
64
|
+
for (const { pattern, matcher, rule } of getCompiledGlobRules(rules).packages) if (matcher.match(packageName)) return {
|
|
65
|
+
pattern,
|
|
66
|
+
rule
|
|
67
|
+
};
|
|
68
|
+
}
|
|
6
69
|
/**
|
|
7
70
|
* Split a package name into name itself and scope.
|
|
8
71
|
*/
|
|
@@ -18,29 +81,31 @@ function splitName(name) {
|
|
|
18
81
|
/**
|
|
19
82
|
* Try to find a rule that matches the package.
|
|
20
83
|
* If found, returns the rule and the matched package versions from the manifest.
|
|
84
|
+
* Rule maps are cached; call prepareRules after modifying them.
|
|
21
85
|
*/
|
|
22
86
|
function matchRules(manifest, rules) {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
87
|
+
const packageName = manifest.name;
|
|
88
|
+
if (!packageName) return;
|
|
89
|
+
const { scope } = splitName(packageName);
|
|
90
|
+
const scopeMatch = findScopeRule(scope, rules);
|
|
91
|
+
if (scopeMatch) {
|
|
92
|
+
debug("scope match: %s matched rule for %s", packageName, scopeMatch.scope);
|
|
93
|
+
return {
|
|
94
|
+
type: MatchType.SCOPE,
|
|
95
|
+
rule: scopeMatch.rule,
|
|
96
|
+
scope: scopeMatch.scope,
|
|
97
|
+
versions: Object.keys(manifest.versions)
|
|
98
|
+
};
|
|
35
99
|
}
|
|
36
|
-
const
|
|
37
|
-
if (!
|
|
100
|
+
const packageMatch = findPackageRule(packageName, rules);
|
|
101
|
+
if (!packageMatch) return;
|
|
102
|
+
const { rule } = packageMatch;
|
|
38
103
|
if (rule === "package") {
|
|
39
|
-
debug("package match: %s",
|
|
104
|
+
debug("package match: %s matched rule for %s", packageName, packageMatch.pattern);
|
|
40
105
|
return {
|
|
41
106
|
type: MatchType.PACKAGE,
|
|
42
107
|
rule,
|
|
43
|
-
package:
|
|
108
|
+
package: packageMatch.pattern,
|
|
44
109
|
versions: Object.keys(manifest.versions)
|
|
45
110
|
};
|
|
46
111
|
}
|
|
@@ -75,6 +140,6 @@ function resolveAllowList(allowMatch) {
|
|
|
75
140
|
};
|
|
76
141
|
}
|
|
77
142
|
//#endregion
|
|
78
|
-
export { matchRules, resolveAllowList };
|
|
143
|
+
export { matchRules, prepareRules, resolveAllowList };
|
|
79
144
|
|
|
80
145
|
//# sourceMappingURL=matcher.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matcher.mjs","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const
|
|
1
|
+
{"version":3,"file":"matcher.mjs","names":[],"sources":["../../src/filtering/matcher.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { Minimatch } from 'minimatch';\nimport { satisfies } from 'semver';\n\nimport type { Manifest } from '@verdaccio/types';\n\nimport type { ParsedRule } from '../config/types';\nimport type { MatchResult } from './types';\nimport { MatchType } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:package-filter:filter');\n\ninterface CompiledGlobRule {\n pattern: string;\n matcher: Minimatch;\n rule: ParsedRule;\n}\n\ninterface CompiledGlobRules {\n packages: CompiledGlobRule[];\n scopes: CompiledGlobRule[];\n}\n\nconst compiledGlobRules = new WeakMap<Map<string, ParsedRule>, CompiledGlobRules>();\nconst globMagic = /[\\\\*?[\\]{}!]|[+@]\\(/;\n\n/**\n * Compile patterns requiring glob or escape handling, grouped by rule type.\n */\nfunction compileGlobRules(rules: Map<string, ParsedRule>): CompiledGlobRules {\n const compiled: CompiledGlobRules = { packages: [], scopes: [] };\n\n for (const [pattern, rule] of rules) {\n if (!globMagic.test(pattern)) {\n continue;\n }\n\n const matcher = new Minimatch(pattern);\n const compiledRule = { pattern, matcher, rule };\n if (rule === 'scope') {\n compiled.scopes.push(compiledRule);\n } else {\n compiled.packages.push(compiledRule);\n }\n }\n\n return compiled;\n}\n\n/**\n * Cache the compiled glob rules for a rule map. Call again after changing the map.\n */\nexport function prepareRules(rules: Map<string, ParsedRule>): void {\n compiledGlobRules.set(rules, compileGlobRules(rules));\n}\n\n/**\n * Return cached glob rules, compiling and caching unprepared maps on first use.\n */\nfunction getCompiledGlobRules(rules: Map<string, ParsedRule>): CompiledGlobRules {\n let compiled = compiledGlobRules.get(rules);\n if (!compiled) {\n compiled = compileGlobRules(rules);\n compiledGlobRules.set(rules, compiled);\n }\n\n return compiled;\n}\n\nfunction findScopeRule(\n scope: string | undefined,\n rules: Map<string, ParsedRule>\n): { scope: string; rule: 'scope' } | undefined {\n if (!scope) {\n return undefined;\n }\n\n const exactRule = rules.get(scope);\n if (exactRule === 'scope') {\n return { scope, rule: exactRule };\n }\n\n for (const { pattern, matcher } of getCompiledGlobRules(rules).scopes) {\n if (matcher.match(scope)) {\n return { scope: pattern, rule: 'scope' };\n }\n }\n\n return undefined;\n}\n\nfunction findPackageRule(\n packageName: string,\n rules: Map<string, ParsedRule>\n): { pattern: string; rule: ParsedRule } | undefined {\n const exactRule = rules.get(packageName);\n if (exactRule) {\n return { pattern: packageName, rule: exactRule };\n }\n\n for (const { pattern, matcher, rule } of getCompiledGlobRules(rules).packages) {\n if (matcher.match(packageName)) {\n return { pattern, rule };\n }\n }\n\n return undefined;\n}\n\n/**\n * Split a package name into name itself and scope.\n */\nfunction splitName(name: string): { name: string; scope?: string } {\n if (!name) {\n return { name: '' };\n }\n\n const parts = name.split('/');\n\n if (parts.length > 1) {\n return {\n scope: parts[0],\n name: parts[1],\n };\n } else {\n return {\n name: parts[0],\n };\n }\n}\n\n/**\n * Try to find a rule that matches the package.\n * If found, returns the rule and the matched package versions from the manifest.\n * Rule maps are cached; call prepareRules after modifying them.\n */\nexport function matchRules(\n manifest: Manifest,\n rules: Map<string, ParsedRule>\n): MatchResult | undefined {\n const packageName = manifest.name;\n if (!packageName) {\n return undefined;\n }\n\n const { scope } = splitName(packageName);\n const scopeMatch = findScopeRule(scope, rules);\n if (scopeMatch) {\n debug('scope match: %s matched rule for %s', packageName, scopeMatch.scope);\n return {\n type: MatchType.SCOPE,\n rule: scopeMatch.rule,\n scope: scopeMatch.scope,\n versions: Object.keys(manifest.versions),\n };\n }\n\n const packageMatch = findPackageRule(packageName, rules);\n if (!packageMatch) {\n // No match\n return undefined;\n }\n const { rule } = packageMatch;\n\n if (rule === 'package') {\n debug('package match: %s matched rule for %s', packageName, packageMatch.pattern);\n return {\n type: MatchType.PACKAGE,\n rule,\n package: packageMatch.pattern,\n versions: Object.keys(manifest.versions),\n };\n }\n\n if (rule === 'scope') {\n throw new Error('Unexpected case - rule for package should never be \"scope\"');\n }\n\n const versionRanges = rule.versions;\n if (versionRanges.length === 0) {\n // No match\n return undefined;\n }\n\n const matchedVersions: string[] = [];\n Object.keys(manifest.versions).forEach((version) => {\n versionRanges.forEach((versionRange) => {\n if (\n satisfies(version, versionRange, {\n includePrerelease: true,\n loose: true,\n })\n ) {\n matchedVersions.push(version);\n }\n });\n });\n\n if (matchedVersions.length > 0) {\n debug(\n 'version match: %s matched %d versions: %o',\n manifest.name,\n matchedVersions.length,\n matchedVersions\n );\n }\n\n return {\n type: MatchType.VERSIONS,\n rule,\n versions: matchedVersions,\n };\n}\n\n/**\n * Derive the allow-list outcome from a precomputed allow-rule match:\n * whether the whole package/scope is allow-listed, and which versions\n * (if any) are individually whitelisted.\n */\nexport function resolveAllowList(allowMatch: MatchResult | undefined): {\n allowAll: boolean;\n whitelistedVersions: string[];\n} {\n const allowAll =\n !!allowMatch && (allowMatch.type === MatchType.SCOPE || allowMatch.type === MatchType.PACKAGE);\n return { allowAll, whitelistedVersions: allowMatch?.versions ?? [] };\n}\n"],"mappings":";;;;;AAUA,IAAM,QAAQ,WAAW,wCAAwC;AAajE,IAAM,oCAAoB,IAAI,QAAoD;AAClF,IAAM,YAAY;;;;AAKlB,SAAS,iBAAiB,OAAmD;CAC3E,MAAM,WAA8B;EAAE,UAAU,CAAC;EAAG,QAAQ,CAAC;CAAE;CAE/D,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO;EACnC,IAAI,CAAC,UAAU,KAAK,OAAO,GACzB;EAIF,MAAM,eAAe;GAAE;GAAS,SAAA,IADZ,UAAU,OACE;GAAS;EAAK;EAC9C,IAAI,SAAS,SACX,SAAS,OAAO,KAAK,YAAY;OAEjC,SAAS,SAAS,KAAK,YAAY;CAEvC;CAEA,OAAO;AACT;;;;AAKA,SAAgB,aAAa,OAAsC;CACjE,kBAAkB,IAAI,OAAO,iBAAiB,KAAK,CAAC;AACtD;;;;AAKA,SAAS,qBAAqB,OAAmD;CAC/E,IAAI,WAAW,kBAAkB,IAAI,KAAK;CAC1C,IAAI,CAAC,UAAU;EACb,WAAW,iBAAiB,KAAK;EACjC,kBAAkB,IAAI,OAAO,QAAQ;CACvC;CAEA,OAAO;AACT;AAEA,SAAS,cACP,OACA,OAC8C;CAC9C,IAAI,CAAC,OACH;CAGF,MAAM,YAAY,MAAM,IAAI,KAAK;CACjC,IAAI,cAAc,SAChB,OAAO;EAAE;EAAO,MAAM;CAAU;CAGlC,KAAK,MAAM,EAAE,SAAS,aAAa,qBAAqB,KAAK,CAAC,CAAC,QAC7D,IAAI,QAAQ,MAAM,KAAK,GACrB,OAAO;EAAE,OAAO;EAAS,MAAM;CAAQ;AAK7C;AAEA,SAAS,gBACP,aACA,OACmD;CACnD,MAAM,YAAY,MAAM,IAAI,WAAW;CACvC,IAAI,WACF,OAAO;EAAE,SAAS;EAAa,MAAM;CAAU;CAGjD,KAAK,MAAM,EAAE,SAAS,SAAS,UAAU,qBAAqB,KAAK,CAAC,CAAC,UACnE,IAAI,QAAQ,MAAM,WAAW,GAC3B,OAAO;EAAE;EAAS;CAAK;AAK7B;;;;AAKA,SAAS,UAAU,MAAgD;CACjE,IAAI,CAAC,MACH,OAAO,EAAE,MAAM,GAAG;CAGpB,MAAM,QAAQ,KAAK,MAAM,GAAG;CAE5B,IAAI,MAAM,SAAS,GACjB,OAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM;CACd;MAEA,OAAO,EACL,MAAM,MAAM,GACd;AAEJ;;;;;;AAOA,SAAgB,WACd,UACA,OACyB;CACzB,MAAM,cAAc,SAAS;CAC7B,IAAI,CAAC,aACH;CAGF,MAAM,EAAE,UAAU,UAAU,WAAW;CACvC,MAAM,aAAa,cAAc,OAAO,KAAK;CAC7C,IAAI,YAAY;EACd,MAAM,uCAAuC,aAAa,WAAW,KAAK;EAC1E,OAAO;GACL,MAAM,UAAU;GAChB,MAAM,WAAW;GACjB,OAAO,WAAW;GAClB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,MAAM,eAAe,gBAAgB,aAAa,KAAK;CACvD,IAAI,CAAC,cAEH;CAEF,MAAM,EAAE,SAAS;CAEjB,IAAI,SAAS,WAAW;EACtB,MAAM,yCAAyC,aAAa,aAAa,OAAO;EAChF,OAAO;GACL,MAAM,UAAU;GAChB;GACA,SAAS,aAAa;GACtB,UAAU,OAAO,KAAK,SAAS,QAAQ;EACzC;CACF;CAEA,IAAI,SAAS,SACX,MAAM,IAAI,MAAM,8DAA4D;CAG9E,MAAM,gBAAgB,KAAK;CAC3B,IAAI,cAAc,WAAW,GAE3B;CAGF,MAAM,kBAA4B,CAAC;CACnC,OAAO,KAAK,SAAS,QAAQ,CAAC,CAAC,SAAS,YAAY;EAClD,cAAc,SAAS,iBAAiB;GACtC,IACE,UAAU,SAAS,cAAc;IAC/B,mBAAmB;IACnB,OAAO;GACT,CAAC,GAED,gBAAgB,KAAK,OAAO;EAEhC,CAAC;CACH,CAAC;CAED,IAAI,gBAAgB,SAAS,GAC3B,MACE,6CACA,SAAS,MACT,gBAAgB,QAChB,eACF;CAGF,OAAO;EACL,MAAM,UAAU;EAChB;EACA,UAAU;CACZ;AACF;;;;;;AAOA,SAAgB,iBAAiB,YAG/B;CAGA,OAAO;EAAE,UADP,CAAC,CAAC,eAAe,WAAW,SAAS,UAAU,SAAS,WAAW,SAAS,UAAU;EACrE,qBAAqB,YAAY,YAAY,CAAC;CAAE;AACrE"}
|
package/build/packageFilter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const require_runtime = require("./_virtual/_rolldown/runtime.js");
|
|
2
|
-
const require_parser = require("./config/parser.js");
|
|
3
2
|
const require_matcher = require("./filtering/matcher.js");
|
|
3
|
+
const require_parser = require("./config/parser.js");
|
|
4
4
|
const require_deprecated = require("./filtering/deprecated.js");
|
|
5
5
|
const require_packageVersion = require("./filtering/packageVersion.js");
|
|
6
6
|
const require_publishDate = require("./filtering/publishDate.js");
|
package/build/packageFilter.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseConfig } from "./config/parser.mjs";
|
|
2
1
|
import { matchRules } from "./filtering/matcher.mjs";
|
|
2
|
+
import { parseConfig } from "./config/parser.mjs";
|
|
3
3
|
import { filterDeprecatedVersions } from "./filtering/deprecated.mjs";
|
|
4
4
|
import { filterBlockedVersions } from "./filtering/packageVersion.mjs";
|
|
5
5
|
import { filterVersionsByPublishDate } from "./filtering/publishDate.mjs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdaccio/package-filter",
|
|
3
|
-
"version": "14.0.0-next-9.
|
|
3
|
+
"version": "14.0.0-next-9.56",
|
|
4
4
|
"description": "Package filter plugin for Verdaccio that allows blocking packages by name, scope, version or date",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"private",
|
|
@@ -35,19 +35,20 @@
|
|
|
35
35
|
"node": ">=24"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@verdaccio/core": "9.0.0-next-9.
|
|
38
|
+
"@verdaccio/core": "9.0.0-next-9.32",
|
|
39
39
|
"debug": "4.4.3",
|
|
40
|
+
"minimatch": "10.2.6",
|
|
40
41
|
"semver": "7.8.5"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/debug": "4.1.13",
|
|
44
|
-
"@verdaccio/config": "9.0.0-next-9.
|
|
45
|
-
"@verdaccio/logger": "9.0.0-next-9.
|
|
46
|
-
"@verdaccio/plugin-verifier": "1.0.0-next-9.
|
|
47
|
-
"@verdaccio/types": "14.0.0-next-9.
|
|
45
|
+
"@verdaccio/config": "9.0.0-next-9.32",
|
|
46
|
+
"@verdaccio/logger": "9.0.0-next-9.32",
|
|
47
|
+
"@verdaccio/plugin-verifier": "1.0.0-next-9.28",
|
|
48
|
+
"@verdaccio/types": "14.0.0-next-9.15",
|
|
48
49
|
"rimraf": "6.1.3",
|
|
49
50
|
"vite": "8.2.2",
|
|
50
|
-
"vitest": "4.1.
|
|
51
|
+
"vitest": "4.1.11"
|
|
51
52
|
},
|
|
52
53
|
"funding": {
|
|
53
54
|
"type": "opencollective",
|