godot-cli 0.13.3 → 0.15.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.
- package/CHANGELOG.md +12 -0
- package/README.md +38 -4
- package/dist/commands/install-extension.d.ts +2 -0
- package/dist/commands/install-extension.js +63 -0
- package/dist/commands/install-extension.js.map +1 -0
- package/dist/commands/install-plugin.js +5 -1
- package/dist/commands/install-plugin.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/install-extension.d.ts +20 -0
- package/dist/lib/install-extension.js +185 -0
- package/dist/lib/install-extension.js.map +1 -0
- package/dist/lib/install-plugin.js +23 -11
- package/dist/lib/install-plugin.js.map +1 -1
- package/dist/lib/types.d.ts +63 -2
- package/dist/lib.d.ts +4 -1
- package/dist/lib.js +4 -0
- package/dist/lib.js.map +1 -1
- package/dist/utils/addon-deps.d.ts +23 -0
- package/dist/utils/addon-deps.js +15 -0
- package/dist/utils/addon-deps.js.map +1 -1
- package/dist/utils/csproj-deps.d.ts +37 -1
- package/dist/utils/csproj-deps.js +104 -5
- package/dist/utils/csproj-deps.js.map +1 -1
- package/dist/utils/extension-install.d.ts +47 -0
- package/dist/utils/extension-install.js +249 -0
- package/dist/utils/extension-install.js.map +1 -0
- package/dist/utils/extensions-catalog.d.ts +54 -0
- package/dist/utils/extensions-catalog.js +222 -0
- package/dist/utils/extensions-catalog.js.map +1 -0
- package/package.json +1 -1
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ExtensionDescriptor } from '../utils/extensions-catalog.js';
|
|
1
2
|
/**
|
|
2
3
|
* Discriminated union describing every progress event the library can emit to
|
|
3
4
|
* the optional `onProgress` callback. Consumers narrow on `event.phase`.
|
|
@@ -360,11 +361,11 @@ export interface AddonMaterializeOutcome {
|
|
|
360
361
|
/** The local source directory used (`--source` path only). */
|
|
361
362
|
sourceDir?: string;
|
|
362
363
|
}
|
|
363
|
-
/** What `install-plugin` did to the consumer `.csproj`'s PackageReferences. */
|
|
364
|
+
/** What `install-plugin` did to the consumer `.csproj`'s PackageReferences + EmbeddedResources. */
|
|
364
365
|
export interface CsprojPatchOutcome {
|
|
365
366
|
/** Absolute path to the consumer `.csproj` that was patched, if one was found. */
|
|
366
367
|
csprojPath?: string;
|
|
367
|
-
/** True when the csproj text was modified. */
|
|
368
|
+
/** True when the csproj text was modified (pins and/or embeds). */
|
|
368
369
|
changed: boolean;
|
|
369
370
|
/** Per-package summary: each addon pin's add / update / unchanged outcome. */
|
|
370
371
|
packages: {
|
|
@@ -372,6 +373,12 @@ export interface CsprojPatchOutcome {
|
|
|
372
373
|
action: 'added' | 'updated' | 'unchanged';
|
|
373
374
|
version: string;
|
|
374
375
|
}[];
|
|
376
|
+
/** Per-resource summary: each addon `<EmbeddedResource>`'s add / update / unchanged outcome. */
|
|
377
|
+
embeds: {
|
|
378
|
+
include: string;
|
|
379
|
+
action: 'added' | 'updated' | 'unchanged';
|
|
380
|
+
logicalName: string;
|
|
381
|
+
}[];
|
|
375
382
|
}
|
|
376
383
|
export interface InstallPluginSuccess {
|
|
377
384
|
kind: 'success';
|
|
@@ -415,3 +422,57 @@ export interface RemovePluginFailure {
|
|
|
415
422
|
error: Error;
|
|
416
423
|
}
|
|
417
424
|
export type RemovePluginResult = RemovePluginSuccess | RemovePluginFailure;
|
|
425
|
+
/**
|
|
426
|
+
* What `installExtension` did to the consumer `.csproj` — the CLI mirror of the dock's
|
|
427
|
+
* `ExtensionInstallOutcome`:
|
|
428
|
+
* - `added` — the `<PackageReference>` was newly added (rebuild required).
|
|
429
|
+
* - `updated` — its version was bumped up (rebuild required).
|
|
430
|
+
* - `already-up-to-date`— present at an equal/newer version, or the descriptor has no pin (no write).
|
|
431
|
+
* - `no-project` — no consumer `.csproj` was found to install into (nothing written).
|
|
432
|
+
*/
|
|
433
|
+
export type ExtensionInstallOutcome = 'added' | 'updated' | 'already-up-to-date' | 'no-project';
|
|
434
|
+
export interface InstallExtensionOptions {
|
|
435
|
+
/** Absolute or relative path to the Godot project root (holds `project.godot` + the consumer `.csproj`). */
|
|
436
|
+
godotProjectPath: string;
|
|
437
|
+
/** The extension `<id>` to install — matched against the catalog by `packageId` (then `name`), case-insensitive. */
|
|
438
|
+
extensionId: string;
|
|
439
|
+
/** Override the catalog's pinned version for this install (the `--version` flag). Ignored when empty. */
|
|
440
|
+
version?: string;
|
|
441
|
+
/**
|
|
442
|
+
* Catalog to resolve `extensionId` against. Defaults to the bundled `EXTENSIONS_CATALOG`
|
|
443
|
+
* (single-sourced from `addons/godot_mcp/extensions.catalog.json`). Injectable for tests.
|
|
444
|
+
*/
|
|
445
|
+
catalog?: readonly ExtensionDescriptor[];
|
|
446
|
+
onProgress?: ProgressCallback;
|
|
447
|
+
}
|
|
448
|
+
export interface InstallExtensionSuccess {
|
|
449
|
+
kind: 'success';
|
|
450
|
+
success: true;
|
|
451
|
+
/** The classified outcome (added / updated / already-up-to-date / no-project). */
|
|
452
|
+
outcome: ExtensionInstallOutcome;
|
|
453
|
+
/** True when the `.csproj` was written (added or updated). */
|
|
454
|
+
changed: boolean;
|
|
455
|
+
/** True when a write happened, so the consumer must rebuild solutions (Godot has no programmatic restore). */
|
|
456
|
+
rebuildRequired: boolean;
|
|
457
|
+
/** The user-supplied id that resolved to the descriptor. */
|
|
458
|
+
extensionId: string;
|
|
459
|
+
/** The resolved descriptor's package id (the `<PackageReference Include>`). */
|
|
460
|
+
packageId: string;
|
|
461
|
+
/** Version currently referenced before this install: `null` when not installed, `''` when referenced unversioned. */
|
|
462
|
+
fromVersion: string | null;
|
|
463
|
+
/** The version this install targeted (catalog pin or `--version` override), or `null` when unpinned. */
|
|
464
|
+
toVersion: string | null;
|
|
465
|
+
/** Absolute path to the consumer `.csproj`, when one was located. */
|
|
466
|
+
csprojPath?: string;
|
|
467
|
+
/** A short human-readable status line, safe to print. */
|
|
468
|
+
message: string;
|
|
469
|
+
warnings: string[];
|
|
470
|
+
}
|
|
471
|
+
export interface InstallExtensionFailure {
|
|
472
|
+
kind: 'failure';
|
|
473
|
+
success: false;
|
|
474
|
+
projectGodotPath?: string;
|
|
475
|
+
warnings: string[];
|
|
476
|
+
error: Error;
|
|
477
|
+
}
|
|
478
|
+
export type InstallExtensionResult = InstallExtensionSuccess | InstallExtensionFailure;
|
package/dist/lib.d.ts
CHANGED
|
@@ -5,4 +5,7 @@ export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
|
5
5
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
6
6
|
export { setupSkills } from './lib/setup-skills.js';
|
|
7
7
|
export { installPlugin, removePlugin } from './lib/install-plugin.js';
|
|
8
|
-
export
|
|
8
|
+
export { installExtension } from './lib/install-extension.js';
|
|
9
|
+
export { EXTENSIONS_CATALOG, findExtension, hasVersion } from './utils/extensions-catalog.js';
|
|
10
|
+
export type { ExtensionDescriptor, ExtensionTool } from './utils/extensions-catalog.js';
|
|
11
|
+
export type { ProgressEvent, ProgressCallback, ResultKind, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectConnectionMode, BuildProjectOptions, BuildProjectResult, BuildProjectSuccess, BuildProjectFailure, BuildSkipReason, CreateProjectOptions, CreateProjectResult, CreateProjectSuccess, CreateProjectFailure, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, SetupSkillsOptions, SetupSkillsResult, SetupSkillsSuccess, SetupSkillsFailure, InstallPluginOptions, InstallPluginResult, InstallPluginSuccess, InstallPluginFailure, AddonMaterializeOutcome, CsprojPatchOutcome, RemovePluginOptions, RemovePluginResult, RemovePluginSuccess, RemovePluginFailure, InstallExtensionOptions, InstallExtensionResult, InstallExtensionSuccess, InstallExtensionFailure, ExtensionInstallOutcome, } from './lib/types.js';
|
package/dist/lib.js
CHANGED
|
@@ -19,4 +19,8 @@ export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
|
19
19
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
20
20
|
export { setupSkills } from './lib/setup-skills.js';
|
|
21
21
|
export { installPlugin, removePlugin } from './lib/install-plugin.js';
|
|
22
|
+
export { installExtension } from './lib/install-extension.js';
|
|
23
|
+
// Shared extension catalog (single-sourced from addons/godot_mcp/extensions.catalog.json)
|
|
24
|
+
// + its lookup helpers, so the app can render the same list the dock + CLI install from.
|
|
25
|
+
export { EXTENSIONS_CATALOG, findExtension, hasVersion } from './utils/extensions-catalog.js';
|
|
22
26
|
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,eAAe;AACf,+EAA+E;AAC/E,wDAAwD;AACxD,oDAAoD;AACpD,yEAAyE;AACzE,4DAA4D;AAC5D,+EAA+E;AAC/E,gEAAgE;AAChE,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,4CAA4C;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,eAAe;AACf,+EAA+E;AAC/E,wDAAwD;AACxD,oDAAoD;AACpD,yEAAyE;AACzE,4DAA4D;AAC5D,+EAA+E;AAC/E,gEAAgE;AAChE,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,4CAA4C;AAE5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE9D,0FAA0F;AAC1F,yFAAyF;AACzF,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -5,11 +5,34 @@ export interface AddonPackageReference {
|
|
|
5
5
|
/** The pinned version (the `Version=` attribute). */
|
|
6
6
|
version: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* A single `<EmbeddedResource>` the consumer csproj must declare so an asset the
|
|
10
|
+
* addon reads at editor runtime via `GetManifestResourceStream` is embedded into
|
|
11
|
+
* the consumer's compiled project assembly (Godot globs every `*.cs` into one
|
|
12
|
+
* assembly, but does NOT carry the addon's own `Godot-MCP.csproj` `<EmbeddedResource>`
|
|
13
|
+
* — the addon ships as source, not a NuGet package).
|
|
14
|
+
*/
|
|
15
|
+
export interface AddonEmbeddedResource {
|
|
16
|
+
/** The file to embed, relative to the consumer project root (the `Include=` attribute). */
|
|
17
|
+
include: string;
|
|
18
|
+
/** The manifest-resource name the addon resolves it by (the `LogicalName=` attribute). */
|
|
19
|
+
logicalName: string;
|
|
20
|
+
}
|
|
8
21
|
/**
|
|
9
22
|
* The exact NuGet `PackageReference`s the consumer's project `.csproj` needs,
|
|
10
23
|
* single-sourced from the addon's `Godot-MCP.csproj` pins. Order matches the
|
|
11
24
|
* addon csproj (ReflectorNet first, then McpPlugin).
|
|
12
25
|
*/
|
|
13
26
|
export declare const ADDON_PACKAGE_REFERENCES: readonly AddonPackageReference[];
|
|
27
|
+
/**
|
|
28
|
+
* The exact `<EmbeddedResource>`s the consumer's project `.csproj` needs, single-sourced
|
|
29
|
+
* from the addon's `Godot-MCP.csproj`. The extension catalog is read at editor runtime by
|
|
30
|
+
* the pure-managed `GodotExtensionRegistry` via `GetManifestResourceStream` (no `res://` /
|
|
31
|
+
* filesystem fallback), so without this embed a consumer that installs via `install-plugin`
|
|
32
|
+
* gets an EMPTY Extensions panel. A parity test (`cli/tests/addon-deps-parity.test.ts`)
|
|
33
|
+
* reads `Godot-MCP.csproj` and FAILS the build if these constants ever drift from the addon's
|
|
34
|
+
* own `<EmbeddedResource>` (Include path + LogicalName), mirroring the NuGet-pin tripwire.
|
|
35
|
+
*/
|
|
36
|
+
export declare const ADDON_EMBEDDED_RESOURCES: readonly AddonEmbeddedResource[];
|
|
14
37
|
/** The resource path of the addon manifest a consumer project loads the plugin from. */
|
|
15
38
|
export declare const ADDON_PLUGIN_CFG_RESOURCE = "res://addons/godot_mcp/plugin.cfg";
|
package/dist/utils/addon-deps.js
CHANGED
|
@@ -22,6 +22,21 @@ export const ADDON_PACKAGE_REFERENCES = [
|
|
|
22
22
|
{ id: 'com.IvanMurzak.ReflectorNet', version: '5.3.1' },
|
|
23
23
|
{ id: 'com.IvanMurzak.McpPlugin', version: '6.10.0' },
|
|
24
24
|
];
|
|
25
|
+
/**
|
|
26
|
+
* The exact `<EmbeddedResource>`s the consumer's project `.csproj` needs, single-sourced
|
|
27
|
+
* from the addon's `Godot-MCP.csproj`. The extension catalog is read at editor runtime by
|
|
28
|
+
* the pure-managed `GodotExtensionRegistry` via `GetManifestResourceStream` (no `res://` /
|
|
29
|
+
* filesystem fallback), so without this embed a consumer that installs via `install-plugin`
|
|
30
|
+
* gets an EMPTY Extensions panel. A parity test (`cli/tests/addon-deps-parity.test.ts`)
|
|
31
|
+
* reads `Godot-MCP.csproj` and FAILS the build if these constants ever drift from the addon's
|
|
32
|
+
* own `<EmbeddedResource>` (Include path + LogicalName), mirroring the NuGet-pin tripwire.
|
|
33
|
+
*/
|
|
34
|
+
export const ADDON_EMBEDDED_RESOURCES = [
|
|
35
|
+
{
|
|
36
|
+
include: 'addons/godot_mcp/extensions.catalog.json',
|
|
37
|
+
logicalName: 'Godot-MCP.extensions.catalog.json',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
25
40
|
/** The resource path of the addon manifest a consumer project loads the plugin from. */
|
|
26
41
|
export const ADDON_PLUGIN_CFG_RESOURCE = 'res://addons/godot_mcp/plugin.cfg';
|
|
27
42
|
//# sourceMappingURL=addon-deps.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addon-deps.js","sourceRoot":"","sources":["../../src/utils/addon-deps.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mFAAmF;AACnF,oEAAoE;AACpE,8EAA8E;AAC9E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,kFAAkF;AAClF,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,iFAAiF;AACjF,+CAA+C;AAC/C,EAAE;AACF,sEAAsE;
|
|
1
|
+
{"version":3,"file":"addon-deps.js","sourceRoot":"","sources":["../../src/utils/addon-deps.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mFAAmF;AACnF,oEAAoE;AACpE,8EAA8E;AAC9E,yEAAyE;AACzE,EAAE;AACF,6EAA6E;AAC7E,kFAAkF;AAClF,8EAA8E;AAC9E,4EAA4E;AAC5E,iFAAiF;AACjF,iFAAiF;AACjF,+CAA+C;AAC/C,EAAE;AACF,sEAAsE;AAwBtE;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE,EAAE,EAAE,EAAE,6BAA6B,EAAE,OAAO,EAAE,OAAO,EAAE;IACvD,EAAE,EAAE,EAAE,0BAA0B,EAAE,OAAO,EAAE,QAAQ,EAAE;CAC7C,CAAC;AAEX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAqC;IACxE;QACE,OAAO,EAAE,0CAA0C;QACnD,WAAW,EAAE,mCAAmC;KACjD;CACO,CAAC;AAEX,wFAAwF;AACxF,MAAM,CAAC,MAAM,yBAAyB,GAAG,mCAAmC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AddonPackageReference } from './addon-deps.js';
|
|
1
|
+
import { type AddonPackageReference, type AddonEmbeddedResource } from './addon-deps.js';
|
|
2
2
|
/**
|
|
3
3
|
* Idempotently reconcile a Godot consumer `.csproj`'s `<PackageReference>`s so it
|
|
4
4
|
* declares exactly the addon's two required NuGet pins (see `addon-deps.ts`).
|
|
@@ -37,4 +37,40 @@ export interface CsprojPatchResult {
|
|
|
37
37
|
/** One entry per required package describing what happened to it. */
|
|
38
38
|
changes: CsprojPatchChange[];
|
|
39
39
|
}
|
|
40
|
+
export type CsprojEmbedChange = {
|
|
41
|
+
include: string;
|
|
42
|
+
action: 'added';
|
|
43
|
+
logicalName: string;
|
|
44
|
+
} | {
|
|
45
|
+
include: string;
|
|
46
|
+
action: 'updated';
|
|
47
|
+
from: string;
|
|
48
|
+
logicalName: string;
|
|
49
|
+
} | {
|
|
50
|
+
include: string;
|
|
51
|
+
action: 'unchanged';
|
|
52
|
+
logicalName: string;
|
|
53
|
+
};
|
|
54
|
+
export interface CsprojEmbedResult {
|
|
55
|
+
/** The new csproj text (identical to input when nothing changed). */
|
|
56
|
+
text: string;
|
|
57
|
+
/** True when the text was modified. */
|
|
58
|
+
changed: boolean;
|
|
59
|
+
/** One entry per required embedded resource describing what happened to it. */
|
|
60
|
+
changes: CsprojEmbedChange[];
|
|
61
|
+
}
|
|
40
62
|
export declare function addAddonPackageReferences(csprojText: string, requiredRefs?: readonly AddonPackageReference[]): CsprojPatchResult;
|
|
63
|
+
/**
|
|
64
|
+
* Idempotently reconcile a Godot consumer `.csproj`'s `<EmbeddedResource>`s so it
|
|
65
|
+
* declares exactly the addon's required embeds (see `addon-deps.ts`
|
|
66
|
+
* `ADDON_EMBEDDED_RESOURCES`). Pure (operates on csproj TEXT, never touches the
|
|
67
|
+
* filesystem) and exported for unit tests. Sibling of `addAddonPackageReferences`.
|
|
68
|
+
* Handles, idempotently:
|
|
69
|
+
* - a project with NO `<EmbeddedResource>` ItemGroup (groups into one, else appends
|
|
70
|
+
* a fresh `<ItemGroup>` before `</Project>`);
|
|
71
|
+
* - a project that already embeds the resource with the right LogicalName (no change);
|
|
72
|
+
* - a project that embeds the same Include with a DIFFERENT LogicalName (reconciles
|
|
73
|
+
* in place);
|
|
74
|
+
* Re-running `install-plugin` therefore never duplicates the `<EmbeddedResource>`.
|
|
75
|
+
*/
|
|
76
|
+
export declare function addAddonEmbeddedResources(csprojText: string, requiredResources?: readonly AddonEmbeddedResource[]): CsprojEmbedResult;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ADDON_PACKAGE_REFERENCES } from './addon-deps.js';
|
|
1
|
+
import { ADDON_PACKAGE_REFERENCES, ADDON_EMBEDDED_RESOURCES, } from './addon-deps.js';
|
|
2
2
|
/** Escape a string for use inside a RegExp source. */
|
|
3
3
|
function escapeRegExp(value) {
|
|
4
4
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -18,16 +18,32 @@ function packageRefRegex(id) {
|
|
|
18
18
|
`|` +
|
|
19
19
|
`<PackageReference\\b[^>]*?\\bVersion\\s*=\\s*"([^"]*)"[^>]*?\\bInclude\\s*=\\s*"${escId}"[^>]*?(?:/>|></PackageReference>)`, 'i');
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Match an existing `<EmbeddedResource ... Include="<include>" ... />` element for a
|
|
23
|
+
* specific file path, capturing the whole element (in either attribute order, and
|
|
24
|
+
* whether self-closed `/>` or an explicit `></EmbeddedResource>` pair). The
|
|
25
|
+
* `LogicalName` is extracted from the captured element text separately so the regex
|
|
26
|
+
* stays order-agnostic and tolerant of an absent `LogicalName`.
|
|
27
|
+
*/
|
|
28
|
+
function embeddedResourceRegex(include) {
|
|
29
|
+
const escInclude = escapeRegExp(include);
|
|
30
|
+
return new RegExp(`<EmbeddedResource\\b[^>]*?\\bInclude\\s*=\\s*"${escInclude}"[^>]*?(?:/>|></EmbeddedResource>)`, 'i');
|
|
31
|
+
}
|
|
21
32
|
/** Render the canonical self-closing element for a required reference. */
|
|
22
33
|
function renderRef(ref) {
|
|
23
34
|
return `<PackageReference Include="${ref.id}" Version="${ref.version}" />`;
|
|
24
35
|
}
|
|
36
|
+
/** Render the canonical self-closing element for a required embedded resource. */
|
|
37
|
+
function renderEmbed(res) {
|
|
38
|
+
return `<EmbeddedResource Include="${res.include}" LogicalName="${res.logicalName}" />`;
|
|
39
|
+
}
|
|
25
40
|
/**
|
|
26
|
-
* Detect the indentation used by the FIRST existing `<PackageReference>`
|
|
27
|
-
* back to 4 spaces) so appended/inserted elements
|
|
41
|
+
* Detect the indentation used by the FIRST existing `<PackageReference>` /
|
|
42
|
+
* `<EmbeddedResource>` (or fall back to 4 spaces) so appended/inserted elements
|
|
43
|
+
* match the consumer's style.
|
|
28
44
|
*/
|
|
29
45
|
function detectIndent(text) {
|
|
30
|
-
const m = text.match(/\n([ \t]*)<PackageReference\b/);
|
|
46
|
+
const m = text.match(/\n([ \t]*)<(?:PackageReference|EmbeddedResource)\b/);
|
|
31
47
|
return m ? m[1] : ' ';
|
|
32
48
|
}
|
|
33
49
|
/**
|
|
@@ -101,16 +117,99 @@ export function addAddonPackageReferences(csprojText, requiredRefs = ADDON_PACKA
|
|
|
101
117
|
changes: orderedChanges,
|
|
102
118
|
};
|
|
103
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Idempotently reconcile a Godot consumer `.csproj`'s `<EmbeddedResource>`s so it
|
|
122
|
+
* declares exactly the addon's required embeds (see `addon-deps.ts`
|
|
123
|
+
* `ADDON_EMBEDDED_RESOURCES`). Pure (operates on csproj TEXT, never touches the
|
|
124
|
+
* filesystem) and exported for unit tests. Sibling of `addAddonPackageReferences`.
|
|
125
|
+
* Handles, idempotently:
|
|
126
|
+
* - a project with NO `<EmbeddedResource>` ItemGroup (groups into one, else appends
|
|
127
|
+
* a fresh `<ItemGroup>` before `</Project>`);
|
|
128
|
+
* - a project that already embeds the resource with the right LogicalName (no change);
|
|
129
|
+
* - a project that embeds the same Include with a DIFFERENT LogicalName (reconciles
|
|
130
|
+
* in place);
|
|
131
|
+
* Re-running `install-plugin` therefore never duplicates the `<EmbeddedResource>`.
|
|
132
|
+
*/
|
|
133
|
+
export function addAddonEmbeddedResources(csprojText, requiredResources = ADDON_EMBEDDED_RESOURCES) {
|
|
134
|
+
const changes = [];
|
|
135
|
+
let text = csprojText;
|
|
136
|
+
const indent = detectIndent(text);
|
|
137
|
+
const eol = detectEol(text);
|
|
138
|
+
// First pass: reconcile any embeds that already exist (possibly with a different
|
|
139
|
+
// LogicalName). Collect the ones still missing for the append pass.
|
|
140
|
+
const missing = [];
|
|
141
|
+
for (const res of requiredResources) {
|
|
142
|
+
const re = embeddedResourceRegex(res.include);
|
|
143
|
+
const match = text.match(re);
|
|
144
|
+
if (!match) {
|
|
145
|
+
missing.push(res);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const logicalMatch = match[0].match(/\bLogicalName\s*=\s*"([^"]*)"/i);
|
|
149
|
+
const existingLogical = logicalMatch ? logicalMatch[1] : '';
|
|
150
|
+
if (existingLogical === res.logicalName) {
|
|
151
|
+
changes.push({ include: res.include, action: 'unchanged', logicalName: res.logicalName });
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
// Reconcile in place: replace the whole element with the canonical embed.
|
|
155
|
+
text = text.replace(re, renderEmbed(res));
|
|
156
|
+
changes.push({ include: res.include, action: 'updated', from: existingLogical, logicalName: res.logicalName });
|
|
157
|
+
}
|
|
158
|
+
// Second pass: add the missing embeds. Prefer an existing <ItemGroup> that already
|
|
159
|
+
// holds an <EmbeddedResource> (group them together); else append a fresh
|
|
160
|
+
// <ItemGroup> just before </Project>. Deliberately NOT grouped with the
|
|
161
|
+
// PackageReference ItemGroup — the addon's own csproj keeps the two in separate
|
|
162
|
+
// groups, and this keeps the scaffold's layout identical.
|
|
163
|
+
if (missing.length > 0) {
|
|
164
|
+
const block = missing.map((res) => `${indent}${renderEmbed(res)}`).join(eol);
|
|
165
|
+
const embedItemGroupClose = findItemGroupCloseContaining(text, /<EmbeddedResource\b/i);
|
|
166
|
+
if (embedItemGroupClose !== -1) {
|
|
167
|
+
text = `${text.slice(0, embedItemGroupClose)}${block}${eol}${text.slice(embedItemGroupClose)}`;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const groupIndent = indent.length >= 2 ? indent.slice(0, Math.floor(indent.length / 2)) : ' ';
|
|
171
|
+
const newGroup = `${groupIndent}<ItemGroup>${eol}${block}${eol}${groupIndent}</ItemGroup>${eol}`;
|
|
172
|
+
const closeIdx = text.lastIndexOf('</Project>');
|
|
173
|
+
if (closeIdx === -1) {
|
|
174
|
+
text = `${text}${eol}${newGroup}`;
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
text = `${text.slice(0, closeIdx)}${newGroup}${text.slice(closeIdx)}`;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const res of missing) {
|
|
181
|
+
changes.push({ include: res.include, action: 'added', logicalName: res.logicalName });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Restore required-order in `changes` to match `requiredResources` for stable output.
|
|
185
|
+
const orderedChanges = requiredResources
|
|
186
|
+
.map((res) => changes.find((c) => c.include === res.include))
|
|
187
|
+
.filter((c) => c !== undefined);
|
|
188
|
+
return {
|
|
189
|
+
text,
|
|
190
|
+
changed: orderedChanges.some((c) => c.action !== 'unchanged'),
|
|
191
|
+
changes: orderedChanges,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
104
194
|
/**
|
|
105
195
|
* Return the index of the `</ItemGroup>` that closes the FIRST `<ItemGroup>`
|
|
106
196
|
* containing a `<PackageReference>`, or -1 when none exists. Used to group the
|
|
107
197
|
* added pins with the consumer's existing package references.
|
|
108
198
|
*/
|
|
109
199
|
function findPackageReferenceItemGroupClose(text) {
|
|
200
|
+
return findItemGroupCloseContaining(text, /<PackageReference\b/i);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Return the index of the `</ItemGroup>` that closes the FIRST `<ItemGroup>` whose
|
|
204
|
+
* body matches `childTagRe`, or -1 when none exists. Used to group an added element
|
|
205
|
+
* with the consumer's existing items of the same kind. `childTagRe` MUST NOT be a
|
|
206
|
+
* global regex (a stateful `lastIndex` would corrupt the `.test` below).
|
|
207
|
+
*/
|
|
208
|
+
function findItemGroupCloseContaining(text, childTagRe) {
|
|
110
209
|
const itemGroupRe = /<ItemGroup\b[^>]*>([\s\S]*?)<\/ItemGroup>/gi;
|
|
111
210
|
let m;
|
|
112
211
|
while ((m = itemGroupRe.exec(text)) !== null) {
|
|
113
|
-
if (
|
|
212
|
+
if (childTagRe.test(m[1])) {
|
|
114
213
|
// The close tag starts at the end of the match minus its length.
|
|
115
214
|
const closeTag = '</ItemGroup>';
|
|
116
215
|
return m.index + m[0].length - closeTag.length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csproj-deps.js","sourceRoot":"","sources":["../../src/utils/csproj-deps.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"csproj-deps.js","sourceRoot":"","sources":["../../src/utils/csproj-deps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,wBAAwB,GAGzB,MAAM,iBAAiB,CAAC;AA+CzB,sDAAsD;AACtD,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,EAAU;IACjC,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,CAAC,CAAC;IAC/B,qFAAqF;IACrF,gFAAgF;IAChF,gEAAgE;IAChE,OAAO,IAAI,MAAM,CACf,iDAAiD,KAAK,sEAAsE;QAC1H,GAAG;QACH,mFAAmF,KAAK,oCAAoC,EAC9H,GAAG,CACJ,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,IAAI,MAAM,CACf,iDAAiD,UAAU,oCAAoC,EAC/F,GAAG,CACJ,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAS,SAAS,CAAC,GAA0B;IAC3C,OAAO,8BAA8B,GAAG,CAAC,EAAE,cAAc,GAAG,CAAC,OAAO,MAAM,CAAC;AAC7E,CAAC;AAED,kFAAkF;AAClF,SAAS,WAAW,CAAC,GAA0B;IAC7C,OAAO,8BAA8B,GAAG,CAAC,OAAO,kBAAkB,GAAG,CAAC,WAAW,MAAM,CAAC;AAC1F,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAC3E,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAChD,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC;IACnD,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,eAAiD,wBAAwB;IAEzE,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE5B,yEAAyE;IACzE,0EAA0E;IAC1E,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,IAAI,eAAe,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACxE,SAAS;QACX,CAAC;QACD,wEAAwE;QACxE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,+EAA+E;IAC/E,gFAAgF;IAChF,sCAAsC;IACtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE3E,MAAM,iBAAiB,GAAG,kCAAkC,CAAC,IAAI,CAAC,CAAC;QACnE,IAAI,iBAAiB,KAAK,CAAC,CAAC,EAAE,CAAC;YAC7B,oEAAoE;YACpE,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC7F,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC/F,MAAM,QAAQ,GAAG,GAAG,WAAW,cAAc,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,WAAW,eAAe,GAAG,EAAE,CAAC;YACjG,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;YAChD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpB,wDAAwD;gBACxD,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,QAAQ,EAAE,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxE,CAAC;QACH,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,qFAAqF;IACrF,MAAM,cAAc,GAAG,YAAY;SAChC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;SAClD,MAAM,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAE1D,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;QAC7D,OAAO,EAAE,cAAc;KACxB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkB,EAClB,oBAAsD,wBAAwB;IAE9E,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE5B,iFAAiF;IACjF,oEAAoE;IACpE,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,MAAM,EAAE,GAAG,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACtE,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,IAAI,eAAe,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YAC1F,SAAS;QACX,CAAC;QACD,0EAA0E;QAC1E,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IACjH,CAAC;IAED,mFAAmF;IACnF,yEAAyE;IACzE,wEAAwE;IACxE,gFAAgF;IAChF,0DAA0D;IAC1D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE7E,MAAM,mBAAmB,GAAG,4BAA4B,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;QACvF,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACjG,CAAC;aAAM,CAAC;YACN,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC/F,MAAM,QAAQ,GAAG,GAAG,WAAW,cAAc,GAAG,GAAG,KAAK,GAAG,GAAG,GAAG,WAAW,eAAe,GAAG,EAAE,CAAC;YACjG,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;YAChD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpB,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,QAAQ,EAAE,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxE,CAAC;QACH,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAED,sFAAsF;IACtF,MAAM,cAAc,GAAG,iBAAiB;SACrC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC;SAC5D,MAAM,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAE1D,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;QAC7D,OAAO,EAAE,cAAc;KACxB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,kCAAkC,CAAC,IAAY;IACtD,OAAO,4BAA4B,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;AACpE,CAAC;AAED;;;;;GAKG;AACH,SAAS,4BAA4B,CAAC,IAAY,EAAE,UAAkB;IACpE,MAAM,WAAW,GAAG,6CAA6C,CAAC;IAClE,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1B,iEAAiE;YACjE,MAAM,QAAQ,GAAG,cAAc,CAAC;YAChC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QACjD,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ExtensionDescriptor } from './extensions-catalog.js';
|
|
2
|
+
export type ExtensionInstallAction = 'add' | 'update' | 'noop';
|
|
3
|
+
/**
|
|
4
|
+
* The MSBuild floating-version marker written for an UNPINNED (null/empty-version) descriptor.
|
|
5
|
+
* A versionless `<PackageReference Include="x" />` fails NuGet restore with NU1015, so the
|
|
6
|
+
* "float to latest" intent is materialized as `Version="*"`. Mirrors C# `ExtensionInstallPlanner.FloatVersion`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const FLOAT_VERSION = "*";
|
|
9
|
+
export interface ExtensionInstallPlan {
|
|
10
|
+
/** The add / update / no-op decision. */
|
|
11
|
+
action: ExtensionInstallAction;
|
|
12
|
+
/** The full `.csproj` text after applying the action (=== input for a no-op). */
|
|
13
|
+
resultingCsproj: string;
|
|
14
|
+
/** The package id the plan targets. */
|
|
15
|
+
packageId: string;
|
|
16
|
+
/** Version currently referenced: `null` when not installed; `''` when referenced without a version. */
|
|
17
|
+
fromVersion: string | null;
|
|
18
|
+
/** The version the plan writes: the descriptor's pin when set, `"*"` (the float marker) when unpinned and a reference is added or self-healed, `null` only on a no-op. */
|
|
19
|
+
toVersion: string | null;
|
|
20
|
+
}
|
|
21
|
+
/** Thrown by {@link planExtensionInstall} on a genuinely unparseable `.csproj` (the lib turns it into a structured failure). */
|
|
22
|
+
export declare class CsprojParseError extends Error {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Compare two dotted numeric version strings component-by-component as integers
|
|
26
|
+
* (so `1.10.0` > `1.2.0`, unlike an ordinal string compare). A trailing pre-release
|
|
27
|
+
* / build suffix on a component (`1.0.0-rc1`) is tolerated — only the leading integer
|
|
28
|
+
* of each component is read; a non-numeric component reads as 0. Missing trailing
|
|
29
|
+
* components are treated as 0 (`1.0` === `1.0.0`). Returns >0 when `a` is newer, <0
|
|
30
|
+
* when older, 0 when equal. Exact port of C# `InstalledStateDetector.CompareVersions`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
33
|
+
/**
|
|
34
|
+
* Parse every `<PackageReference>` in the `.csproj` into a `{ packageId → version }`
|
|
35
|
+
* map (ids lower-cased — NuGet ids are case-insensitive; value is the `Version`
|
|
36
|
+
* attribute, else a child `<Version>` element, else `''`). Returns an EMPTY map for
|
|
37
|
+
* empty/whitespace input. Port of C# `InstalledStateDetector.ParsePackageReferences`
|
|
38
|
+
* (the CLI never needs the bad-XML tolerance branch — the planner validates first).
|
|
39
|
+
*/
|
|
40
|
+
export declare function parsePackageReferences(csprojText: string | null | undefined): Map<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Compute the install plan for `descriptor` against `csprojText`. Port of
|
|
43
|
+
* `ExtensionInstallPlanner.Plan`. Throws {@link CsprojParseError} only on a genuinely
|
|
44
|
+
* malformed `.csproj` (no recognizable `<Project ...>` root) — the caller maps that to
|
|
45
|
+
* a structured failure rather than corrupting the file.
|
|
46
|
+
*/
|
|
47
|
+
export declare function planExtensionInstall(descriptor: ExtensionDescriptor, csprojText: string): ExtensionInstallPlan;
|