@flowscripter/dynamic-cli-framework 5.2.2 → 5.3.0

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.
@@ -11,7 +11,7 @@ export class PluginAddSubCommand {
11
11
  positionals = [
12
12
  {
13
13
  name: "pluginId",
14
- description: "Plugin ID to install (e.g. @scope/name or @scope/name:version)",
14
+ description: "Plugin ID to install (e.g. @scope/name or @scope/name@version)",
15
15
  type: ValueTypeName.STRING,
16
16
  },
17
17
  ];
@@ -19,7 +19,7 @@ export class PluginAddSubCommand {
19
19
  const printerService = context.getServiceById(PRINTER_SERVICE_ID);
20
20
  const pluginService = context.getServiceById(PLUGIN_SERVICE_ID);
21
21
  const { pluginId, version } = parsePluginSpecifier(argumentValues["pluginId"]);
22
- const searchLabel = version ? `${pluginId}:${version}` : pluginId;
22
+ const searchLabel = version ? `${pluginId}@${version}` : pluginId;
23
23
  await printerService.info(`Searching for plugin: ${searchLabel}\n`, Icon.INFORMATION);
24
24
  let descriptor;
25
25
  for await (const d of pluginService.search({ text: pluginId })) {
@@ -1,14 +1,17 @@
1
1
  /**
2
- * Splits a plugin specifier into a bare plugin ID and an optional version.
2
+ * Splits a plugin specifier into a bare plugin ID and an optional version, following npm's own
3
+ * `[@scope/]name[@version]` convention (`:` is not used as a version separator anywhere in the
4
+ * npm/JS ecosystem, so it is not supported here).
3
5
  *
4
- * The specifier is split on the *last* `:` character, if present. Scoped npm package names
5
- * (e.g. `@scope/name`) never legitimately contain a literal `:`, so this split cannot collide
6
- * with the scope/slash structure of the plugin ID itself.
6
+ * A leading `@scope/` portion (if present) is stripped first, then the *last* `@` in the
7
+ * remainder - if any - is the version separator. This correctly distinguishes the scope marker
8
+ * (always the first character) from a version-separating `@` occurring later.
7
9
  *
8
- * Everything after the last `:` is always treated as the requested version, including
10
+ * Everything after the separator is always treated as the requested version, including
9
11
  * non-semver tags such as `latest` or `next` - no validation is performed on the tail.
10
12
  *
11
- * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name:3.0.0` or `name:latest`.
13
+ * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name@3.0.0` or
14
+ * `name@latest`.
12
15
  */
13
16
  export declare function parsePluginSpecifier(specifier: string): {
14
17
  pluginId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"parsePluginSpecifier.d.ts","sourceRoot":"","sources":["../../../../../src/service/plugin/command/parsePluginSpecifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAS9F"}
1
+ {"version":3,"file":"parsePluginSpecifier.d.ts","sourceRoot":"","sources":["../../../../../src/service/plugin/command/parsePluginSpecifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAY9F"}
@@ -1,22 +1,28 @@
1
1
  /**
2
- * Splits a plugin specifier into a bare plugin ID and an optional version.
2
+ * Splits a plugin specifier into a bare plugin ID and an optional version, following npm's own
3
+ * `[@scope/]name[@version]` convention (`:` is not used as a version separator anywhere in the
4
+ * npm/JS ecosystem, so it is not supported here).
3
5
  *
4
- * The specifier is split on the *last* `:` character, if present. Scoped npm package names
5
- * (e.g. `@scope/name`) never legitimately contain a literal `:`, so this split cannot collide
6
- * with the scope/slash structure of the plugin ID itself.
6
+ * A leading `@scope/` portion (if present) is stripped first, then the *last* `@` in the
7
+ * remainder - if any - is the version separator. This correctly distinguishes the scope marker
8
+ * (always the first character) from a version-separating `@` occurring later.
7
9
  *
8
- * Everything after the last `:` is always treated as the requested version, including
10
+ * Everything after the separator is always treated as the requested version, including
9
11
  * non-semver tags such as `latest` or `next` - no validation is performed on the tail.
10
12
  *
11
- * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name:3.0.0` or `name:latest`.
13
+ * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name@3.0.0` or
14
+ * `name@latest`.
12
15
  */
13
16
  export function parsePluginSpecifier(specifier) {
14
- const index = specifier.lastIndexOf(":");
15
- if (index === -1) {
17
+ const isScoped = specifier.startsWith("@");
18
+ const scopeEnd = isScoped ? specifier.indexOf("/") : -1;
19
+ const searchFrom = isScoped && scopeEnd !== -1 ? scopeEnd + 1 : 0;
20
+ const atIndex = specifier.lastIndexOf("@");
21
+ if (atIndex === -1 || atIndex < searchFrom) {
16
22
  return { pluginId: specifier };
17
23
  }
18
24
  return {
19
- pluginId: specifier.slice(0, index),
20
- version: specifier.slice(index + 1),
25
+ pluginId: specifier.slice(0, atIndex),
26
+ version: specifier.slice(atIndex + 1),
21
27
  };
22
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowscripter/dynamic-cli-framework",
3
- "version": "5.2.2",
3
+ "version": "5.3.0",
4
4
  "description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
5
5
  "keywords": [
6
6
  "bun",
@@ -18,7 +18,7 @@ export class PluginAddSubCommand implements SubCommand {
18
18
  readonly positionals = [
19
19
  {
20
20
  name: "pluginId",
21
- description: "Plugin ID to install (e.g. @scope/name or @scope/name:version)",
21
+ description: "Plugin ID to install (e.g. @scope/name or @scope/name@version)",
22
22
  type: ValueTypeName.STRING,
23
23
  },
24
24
  ];
@@ -28,7 +28,7 @@ export class PluginAddSubCommand implements SubCommand {
28
28
  const pluginService = context.getServiceById(PLUGIN_SERVICE_ID) as PluginService;
29
29
 
30
30
  const { pluginId, version } = parsePluginSpecifier(argumentValues["pluginId"] as string);
31
- const searchLabel = version ? `${pluginId}:${version}` : pluginId;
31
+ const searchLabel = version ? `${pluginId}@${version}` : pluginId;
32
32
  await printerService.info(`Searching for plugin: ${searchLabel}\n`, Icon.INFORMATION);
33
33
 
34
34
  let descriptor: VersionedPluginDescriptor | undefined;
@@ -1,22 +1,28 @@
1
1
  /**
2
- * Splits a plugin specifier into a bare plugin ID and an optional version.
2
+ * Splits a plugin specifier into a bare plugin ID and an optional version, following npm's own
3
+ * `[@scope/]name[@version]` convention (`:` is not used as a version separator anywhere in the
4
+ * npm/JS ecosystem, so it is not supported here).
3
5
  *
4
- * The specifier is split on the *last* `:` character, if present. Scoped npm package names
5
- * (e.g. `@scope/name`) never legitimately contain a literal `:`, so this split cannot collide
6
- * with the scope/slash structure of the plugin ID itself.
6
+ * A leading `@scope/` portion (if present) is stripped first, then the *last* `@` in the
7
+ * remainder - if any - is the version separator. This correctly distinguishes the scope marker
8
+ * (always the first character) from a version-separating `@` occurring later.
7
9
  *
8
- * Everything after the last `:` is always treated as the requested version, including
10
+ * Everything after the separator is always treated as the requested version, including
9
11
  * non-semver tags such as `latest` or `next` - no validation is performed on the tail.
10
12
  *
11
- * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name:3.0.0` or `name:latest`.
13
+ * @param specifier raw plugin specifier, e.g. `@scope/name`, `@scope/name@3.0.0` or
14
+ * `name@latest`.
12
15
  */
13
16
  export function parsePluginSpecifier(specifier: string): { pluginId: string; version?: string } {
14
- const index = specifier.lastIndexOf(":");
15
- if (index === -1) {
17
+ const isScoped = specifier.startsWith("@");
18
+ const scopeEnd = isScoped ? specifier.indexOf("/") : -1;
19
+ const searchFrom = isScoped && scopeEnd !== -1 ? scopeEnd + 1 : 0;
20
+ const atIndex = specifier.lastIndexOf("@");
21
+ if (atIndex === -1 || atIndex < searchFrom) {
16
22
  return { pluginId: specifier };
17
23
  }
18
24
  return {
19
- pluginId: specifier.slice(0, index),
20
- version: specifier.slice(index + 1),
25
+ pluginId: specifier.slice(0, atIndex),
26
+ version: specifier.slice(atIndex + 1),
21
27
  };
22
28
  }