@containerbase/base 14.62.0 → 14.63.1

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 CHANGED
@@ -112,8 +112,9 @@ A reader can replace its urls the same way, so a mirror configured for container
112
112
  ```ts
113
113
  import { getUrlReplacements, replaceUrl } from '@containerbase/base';
114
114
 
115
- const { replacements, invalid } = getUrlReplacements(); // reads `process.env`
116
- // `invalid` lists the `URL_REPLACE_<n>_FROM` variables without a value or `_TO` counterpart
115
+ const { replacements, invalid, withoutScheme } = getUrlReplacements(); // reads `process.env`
116
+ // `invalid` lists the `URL_REPLACE_<n>_FROM` variables without a value or `_TO` counterpart,
117
+ // `withoutScheme` the ones whose value doesn't start with `http://` or `https://`
117
118
  replaceUrl(
118
119
  'https://containerbase.github.io/tool-versions/v1/node.json',
119
120
  replacements,
@@ -121,6 +122,19 @@ replaceUrl(
121
122
  );
122
123
  ```
123
124
 
125
+ `replaceUrl` applies the cdn first, then the replacements like `replaceUrlPrefix(url, rules)`: in order, each to the result of the previous ones, and only when the url starts with its `from`.
126
+ `replaceUrlPrefix` has no cdn step and returns the replaced url with the rules that matched, other fields of the rules are kept.
127
+ End `from` and `to` with a `/`, like `https://example.com/`, so a rule only matches that host: `https://example.com` also matches `https://example.com.test/`.
128
+
129
+ ```ts
130
+ import { replaceUrlPrefix } from '@containerbase/base';
131
+
132
+ const { url, applied } = replaceUrlPrefix('https://registry.npmjs.org/foo', [
133
+ { from: 'https://registry.npmjs.org/', to: 'https://npm.example.test/' },
134
+ ]);
135
+ // url: 'https://npm.example.test/foo', applied: [the rule]
136
+ ```
137
+
124
138
  A tool's data may list `minCb` ranges, the oldest containerbase version which can install a version and every version above it.
125
139
  `filterByMinCb(data, cbVersion)` returns the `versions` the given containerbase version can install, in the order of the data, and the `cb` values of the unmet ranges as `needed`.
126
140
  A `cbVersion` which isn't a release, like `0.0.0-PLACEHOLDER` (see `isReleaseVersion(version)`), skips the filter:
package/dist/index.d.ts CHANGED
@@ -8,8 +8,8 @@ export { configure, getLogger, isConfigured } from './logger.ts';
8
8
  export { filterByMinCb, minCbByVersion } from './min-cb.ts';
9
9
  export { isReleaseVersion } from './release-version.ts';
10
10
  export { isToolVersionsFormat, toolVersionsFormat, toolVersionsFormatPath, } from './tool-versions-format.ts';
11
- export type { UrlReplacement, UrlReplacements } from './url.ts';
12
- export { getUrlReplacements, replaceUrl } from './url.ts';
11
+ export type { UrlPrefixResult, UrlPrefixRule, UrlReplacement, UrlReplacements, } from './url.ts';
12
+ export { getUrlReplacements, replaceUrl, replaceUrlPrefix } from './url.ts';
13
13
  export { tools };
14
14
  /**
15
15
  * The Ubuntu release the default containerbase image is built from, the
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { configure, getLogger, isConfigured } from "./logger.js";
4
4
  export { filterByMinCb, minCbByVersion } from "./min-cb.js";
5
5
  export { isReleaseVersion } from "./release-version.js";
6
6
  export { isToolVersionsFormat, toolVersionsFormat, toolVersionsFormatPath, } from "./tool-versions-format.js";
7
- export { getUrlReplacements, replaceUrl } from "./url.js";
7
+ export { getUrlReplacements, replaceUrl, replaceUrlPrefix } from "./url.js";
8
8
  export { tools };
9
9
  /**
10
10
  * The Ubuntu release the default containerbase image is built from, the
package/dist/url.d.ts CHANGED
@@ -9,6 +9,12 @@ export interface UrlReplacements {
9
9
  * their `URL_REPLACE_<n>_TO` counterpart are empty or missing.
10
10
  */
11
11
  invalid: string[];
12
+ /**
13
+ * The `URL_REPLACE_<n>_FROM` variables whose value doesn't start with
14
+ * `http://` or `https://`, like a bare host. They are used, but only match
15
+ * urls which start with them.
16
+ */
17
+ withoutScheme: string[];
12
18
  }
13
19
  /**
14
20
  * Reads the url replacements from the `URL_REPLACE_<n>_FROM` and
@@ -20,8 +26,9 @@ export declare function getUrlReplacements(env?: Record<string, string | undefin
20
26
  /**
21
27
  * Replaces a url the way containerbase does for its downloads: with a `cdn`,
22
28
  * `https://` is replaced by it first, eg. `https://example.com/file` becomes
23
- * `<cdn>/example.com/file`. Then every replacement is applied in order, each
24
- * replacing the first occurrence of its `from` text.
29
+ * `<cdn>/example.com/file`. Then the replacements are applied in order like
30
+ * `replaceUrlPrefix`, each to the result of the previous ones and only when
31
+ * the url starts with its `from`.
25
32
  *
26
33
  * @param url the url to replace
27
34
  * @param replacements the replacements, see `getUrlReplacements`
@@ -29,3 +36,30 @@ export declare function getUrlReplacements(env?: Record<string, string | undefin
29
36
  * @returns the replaced url
30
37
  */
31
38
  export declare function replaceUrl(url: string, replacements: readonly UrlReplacement[], cdn?: string): string;
39
+ /** A url prefix replacement rule, other fields are kept as they are. */
40
+ export interface UrlPrefixRule {
41
+ /** The url prefix to replace. */
42
+ from: string;
43
+ /** Its replacement. */
44
+ to: string;
45
+ }
46
+ /** The result of `replaceUrlPrefix`. */
47
+ export interface UrlPrefixResult<T extends UrlPrefixRule> {
48
+ /** The replaced url. */
49
+ url: string;
50
+ /** The rules which matched, in order. */
51
+ applied: T[];
52
+ }
53
+ /**
54
+ * Replaces url prefixes: the rules are applied in order, each one to the
55
+ * result of the previous ones, and a rule only applies when the url starts
56
+ * with its `from`, which is then replaced by its `to`. A `from` elsewhere in
57
+ * the url never matches, and unlike `replaceUrl` there is no cdn. End `from`
58
+ * and `to` with a `/`, like `https://example.com/`, so a rule only matches that
59
+ * host: `https://example.com` also matches `https://example.com.test/`.
60
+ *
61
+ * @param url the url to replace
62
+ * @param rules the rules, in order
63
+ * @returns the replaced url and the rules which matched
64
+ */
65
+ export declare function replaceUrlPrefix<T extends UrlPrefixRule>(url: string, rules: readonly T[]): UrlPrefixResult<T>;
package/dist/url.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const fromRe = /^URL_REPLACE_\d+_FROM$/;
2
+ const schemeRe = /^https?:\/\//;
2
3
  const collator = new Intl.Collator('en', {
3
4
  sensitivity: 'base',
4
5
  numeric: true,
@@ -10,7 +11,11 @@ const collator = new Intl.Collator('en', {
10
11
  * @param env the environment to read, `process.env` by default
11
12
  */
12
13
  export function getUrlReplacements(env = process.env) {
13
- const result = { replacements: [], invalid: [] };
14
+ const result = {
15
+ replacements: [],
16
+ invalid: [],
17
+ withoutScheme: [],
18
+ };
14
19
  for (const from of Object.keys(env)
15
20
  .filter((key) => fromRe.test(key))
16
21
  .sort((a, b) => collator.compare(a, b))) {
@@ -19,6 +24,9 @@ export function getUrlReplacements(env = process.env) {
19
24
  const toValue = env[to];
20
25
  if (fromValue && toValue) {
21
26
  result.replacements.push([fromValue, toValue]);
27
+ if (!schemeRe.test(fromValue)) {
28
+ result.withoutScheme.push(from);
29
+ }
22
30
  }
23
31
  else {
24
32
  result.invalid.push(from);
@@ -29,8 +37,9 @@ export function getUrlReplacements(env = process.env) {
29
37
  /**
30
38
  * Replaces a url the way containerbase does for its downloads: with a `cdn`,
31
39
  * `https://` is replaced by it first, eg. `https://example.com/file` becomes
32
- * `<cdn>/example.com/file`. Then every replacement is applied in order, each
33
- * replacing the first occurrence of its `from` text.
40
+ * `<cdn>/example.com/file`. Then the replacements are applied in order like
41
+ * `replaceUrlPrefix`, each to the result of the previous ones and only when
42
+ * the url starts with its `from`.
34
43
  *
35
44
  * @param url the url to replace
36
45
  * @param replacements the replacements, see `getUrlReplacements`
@@ -42,8 +51,28 @@ export function replaceUrl(url, replacements, cdn) {
42
51
  if (cdn) {
43
52
  result = result.replace(/^https:\//, cdn.replace(/\/$/, ''));
44
53
  }
45
- for (const [from, to] of replacements) {
46
- result = result.replace(from, to);
54
+ return replaceUrlPrefix(result, replacements.map(([from, to]) => ({ from, to }))).url;
55
+ }
56
+ /**
57
+ * Replaces url prefixes: the rules are applied in order, each one to the
58
+ * result of the previous ones, and a rule only applies when the url starts
59
+ * with its `from`, which is then replaced by its `to`. A `from` elsewhere in
60
+ * the url never matches, and unlike `replaceUrl` there is no cdn. End `from`
61
+ * and `to` with a `/`, like `https://example.com/`, so a rule only matches that
62
+ * host: `https://example.com` also matches `https://example.com.test/`.
63
+ *
64
+ * @param url the url to replace
65
+ * @param rules the rules, in order
66
+ * @returns the replaced url and the rules which matched
67
+ */
68
+ export function replaceUrlPrefix(url, rules) {
69
+ let result = url;
70
+ const applied = [];
71
+ for (const rule of rules) {
72
+ if (result.startsWith(rule.from)) {
73
+ result = rule.to + result.slice(rule.from.length);
74
+ applied.push(rule);
75
+ }
47
76
  }
48
- return result;
77
+ return { url: result, applied };
49
78
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@containerbase/base",
3
- "version": "14.62.0",
3
+ "version": "14.63.1",
4
4
  "description": "Metadata about the tools supported by containerbase",
5
5
  "keywords": [
6
6
  "containerbase",