@wendoo/bridge-app 0.2.2
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 +44 -0
- package/dist/app-bridge.d.ts +77 -0
- package/dist/app-bridge.d.ts.map +1 -0
- package/dist/app-bridge.js +205 -0
- package/dist/app-environment-host.d.ts +524 -0
- package/dist/app-environment-host.d.ts.map +1 -0
- package/dist/app-environment-host.js +1560 -0
- package/dist/brain-diagnostics.d.ts +47 -0
- package/dist/brain-diagnostics.d.ts.map +1 -0
- package/dist/brain-diagnostics.js +100 -0
- package/dist/bridge-project.d.ts +32 -0
- package/dist/bridge-project.d.ts.map +1 -0
- package/dist/bridge-project.js +69 -0
- package/dist/compilation.d.ts +145 -0
- package/dist/compilation.d.ts.map +1 -0
- package/dist/compilation.js +404 -0
- package/dist/core-extension.d.ts +10 -0
- package/dist/core-extension.d.ts.map +1 -0
- package/dist/core-extension.js +9 -0
- package/dist/embedded-extension-id-gate.d.ts +38 -0
- package/dist/embedded-extension-id-gate.d.ts.map +1 -0
- package/dist/embedded-extension-id-gate.js +55 -0
- package/dist/embedded-extension-loader.d.ts +33 -0
- package/dist/embedded-extension-loader.d.ts.map +1 -0
- package/dist/embedded-extension-loader.js +90 -0
- package/dist/embedded-extension-vite-plugin.d.ts +34 -0
- package/dist/embedded-extension-vite-plugin.d.ts.map +1 -0
- package/dist/embedded-extension-vite-plugin.js +39 -0
- package/dist/embedded-extensions.d.ts +293 -0
- package/dist/embedded-extensions.d.ts.map +1 -0
- package/dist/embedded-extensions.js +526 -0
- package/dist/extension-catalog.d.ts +243 -0
- package/dist/extension-catalog.d.ts.map +1 -0
- package/dist/extension-catalog.js +408 -0
- package/dist/extension-install-log.d.ts +54 -0
- package/dist/extension-install-log.d.ts.map +1 -0
- package/dist/extension-install-log.js +22 -0
- package/dist/extension-install.d.ts +162 -0
- package/dist/extension-install.d.ts.map +1 -0
- package/dist/extension-install.js +412 -0
- package/dist/extension-report-presenter.d.ts +40 -0
- package/dist/extension-report-presenter.d.ts.map +1 -0
- package/dist/extension-report-presenter.js +36 -0
- package/dist/fetched-extension-snapshots.d.ts +66 -0
- package/dist/fetched-extension-snapshots.d.ts.map +1 -0
- package/dist/fetched-extension-snapshots.js +137 -0
- package/dist/folder-host-session.d.ts +85 -0
- package/dist/folder-host-session.d.ts.map +1 -0
- package/dist/folder-host-session.js +210 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/library-offer.d.ts +60 -0
- package/dist/library-offer.d.ts.map +1 -0
- package/dist/library-offer.js +47 -0
- package/dist/library-uninstall-guard.d.ts +66 -0
- package/dist/library-uninstall-guard.d.ts.map +1 -0
- package/dist/library-uninstall-guard.js +103 -0
- package/dist/manifest-files.d.ts +53 -0
- package/dist/manifest-files.d.ts.map +1 -0
- package/dist/manifest-files.js +242 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +2 -0
- package/dist/project-file-bridge.d.ts +10 -0
- package/dist/project-file-bridge.d.ts.map +1 -0
- package/dist/project-file-bridge.js +87 -0
- package/dist/user-tile-registration.d.ts +89 -0
- package/dist/user-tile-registration.d.ts.map +1 -0
- package/dist/user-tile-registration.js +100 -0
- package/dist/vfs-asset-url-provider.d.ts +22 -0
- package/dist/vfs-asset-url-provider.d.ts.map +1 -0
- package/dist/vfs-asset-url-provider.js +52 -0
- package/dist/workspace-folder-project-store.d.ts +125 -0
- package/dist/workspace-folder-project-store.d.ts.map +1 -0
- package/dist/workspace-folder-project-store.js +400 -0
- package/package.json +103 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { createInMemoryProjectFileSystem, WENDOO_JSON_PATH } from "@wendoo/app-host";
|
|
2
|
+
export { FOLDER_HOST_MODE_FOLDER, FOLDER_HOST_MODE_GLOBAL, FOLDER_HOST_MODE_URL_PARAM, FolderSessionErrorCode, } from "@wendoo/bridge-protocol";
|
|
3
|
+
export { createAppBridge } from "./app-bridge.js";
|
|
4
|
+
export { AppEnvironmentHost } from "./app-environment-host.js";
|
|
5
|
+
export { collectBrainErrorDiagnostics, collectBrainTileCompileDiagnostics } from "./brain-diagnostics.js";
|
|
6
|
+
export { CORE_LIB_COORDINATE, CORE_LIB_REFERENCE } from "./core-extension.js";
|
|
7
|
+
export { findEmbeddedExtensionsMissingStableIds, formatEmbeddedExtensionIdViolations, } from "./embedded-extension-id-gate.js";
|
|
8
|
+
export { CatalogMoveWarningCode, createCatalogMoveVersionLookup, ExtensionResolutionCycleError, resolveProjectExtensions, } from "./embedded-extensions.js";
|
|
9
|
+
export { buildExtensionCatalog, buildExtensionCatalogOffers, buildExtensionCatalogShelf, deriveProjectPlatformStack, ExtensionActionResultCode, installEmbeddedExtension, installExtensionReference, isExtensionCompatible, satisfiesRange, uninstallExtension, } from "./extension-catalog.js";
|
|
10
|
+
export { collectExtensionFetchClosure, diffProjectDiagnostics, floatingPinsFromSnapshots, movedClosureHasMissingContent, typecheckBrainProblems, } from "./extension-install.js";
|
|
11
|
+
export { appendExtensionInstallLog, EXTENSION_INSTALL_LOG_APP_DATA_KEY, parseExtensionInstallLog, } from "./extension-install-log.js";
|
|
12
|
+
export { presentExtensionTransaction } from "./extension-report-presenter.js";
|
|
13
|
+
export { decodeInstalledSnapshotFiles, fetchedContentFromSnapshots, INSTALLED_EXTENSIONS_APP_DATA_KEY, installedExtensionMetadataFromSnapshots, installedSnapshotFromFetched, parseInstalledExtensionMetadata, parseInstalledExtensionSnapshots, reconstructInstalledSnapshotsFromTree, serializeInstalledExtensionSnapshots, } from "./fetched-extension-snapshots.js";
|
|
14
|
+
export { connectFolderHostSession, createFolderCompileDiagnosticsPublisher, FolderSessionError, } from "./folder-host-session.js";
|
|
15
|
+
export { addOfferedLibrary } from "./library-offer.js";
|
|
16
|
+
export { collectLibraryUninstallImpact, runGuardedLibraryUninstall } from "./library-uninstall-guard.js";
|
|
17
|
+
export { applyCompiledUserTiles, collectMetadataFromCompile } from "./user-tile-registration.js";
|
|
18
|
+
export { createVfsAssetUrlProvider } from "./vfs-asset-url-provider.js";
|
|
19
|
+
export { WORKSPACE_FOLDER_PROJECT_COLLECTION_ID, WorkspaceFolderProjectStore, WorkspaceFolderStoreError, WorkspaceFolderStoreErrorCode, } from "./workspace-folder-project-store.js";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ExtensionActionResult } from "./extension-catalog.js";
|
|
2
|
+
import type { ExtensionInstallReport } from "./extension-install.js";
|
|
3
|
+
import type { ExtensionTransactionToasts } from "./extension-report-presenter.js";
|
|
4
|
+
/**
|
|
5
|
+
* What one attempt to install a reference answers: the app's own install
|
|
6
|
+
* outcome, narrowed to what an offer needs of it. `ok: false` is an input the
|
|
7
|
+
* app could not turn into an installable reference; `ok: true` carries the
|
|
8
|
+
* extensions-map result and, when the map changed, the transaction's report.
|
|
9
|
+
*/
|
|
10
|
+
export type LibraryInstallAttempt = {
|
|
11
|
+
/** False: the reference did not resolve to something installable; nothing changed. */
|
|
12
|
+
readonly ok: false;
|
|
13
|
+
/** Stable code of the rejection. */
|
|
14
|
+
readonly code: string;
|
|
15
|
+
/** Human-readable failure message. */
|
|
16
|
+
readonly message: string;
|
|
17
|
+
} | {
|
|
18
|
+
/** True: the reference resolved and the install action ran. */
|
|
19
|
+
readonly ok: true;
|
|
20
|
+
/** The extensions-map mutation result. */
|
|
21
|
+
readonly action: ExtensionActionResult;
|
|
22
|
+
/** The install transaction's report; absent when the action changed nothing. */
|
|
23
|
+
readonly report?: ExtensionInstallReport;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The toast surface a library offer reports through: the two an extension
|
|
27
|
+
* transaction always has, plus the note a commit that brought new problems with
|
|
28
|
+
* it carries.
|
|
29
|
+
*/
|
|
30
|
+
export interface LibraryOfferToasts extends ExtensionTransactionToasts {
|
|
31
|
+
/** The library was added, and new problems appeared with it. Names the library by display name. */
|
|
32
|
+
worsened(libraryName: string): void;
|
|
33
|
+
}
|
|
34
|
+
/** The app-side pieces one library offer's install runs through. */
|
|
35
|
+
export interface LibraryOfferInstallSurface {
|
|
36
|
+
/** The reference the app's approved catalog installs `coordinate` by; absent when it approves none. */
|
|
37
|
+
readonly approvedReference: (coordinate: string) => string | undefined;
|
|
38
|
+
/** Run the app's install transaction for `reference`. */
|
|
39
|
+
readonly install: (reference: string) => Promise<LibraryInstallAttempt>;
|
|
40
|
+
/** The display name the app reads `coordinate` by. */
|
|
41
|
+
readonly displayName: (coordinate: string) => string;
|
|
42
|
+
/** Where the attempt's outcome is presented. */
|
|
43
|
+
readonly toasts: LibraryOfferToasts;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Add the library at `coordinate` through the app's own install transaction and
|
|
47
|
+
* present what happened through `surface.toasts`: a refusal as `failed`, a
|
|
48
|
+
* commit as `confirmed`, and a commit that brought new problems with it as
|
|
49
|
+
* `worsened` after the confirmation. A coordinate the app's catalog approves no
|
|
50
|
+
* reference for is refused without running anything.
|
|
51
|
+
*
|
|
52
|
+
* Answers whether this attempt put the library in the project: `false` for a
|
|
53
|
+
* refusal, for a failure, and for a library the project already held, which runs
|
|
54
|
+
* no transaction and presents nothing.
|
|
55
|
+
*
|
|
56
|
+
* @param surface - The app's approved catalog, install transaction, display names, and toasts.
|
|
57
|
+
* @param coordinate - The `<owner>/<repo>` coordinate to add.
|
|
58
|
+
*/
|
|
59
|
+
export declare function addOfferedLibrary(surface: LibraryOfferInstallSurface, coordinate: string): Promise<boolean>;
|
|
60
|
+
//# sourceMappingURL=library-offer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library-offer.d.ts","sourceRoot":"","sources":["../src/library-offer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAEpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAGlF;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IACE,sFAAsF;IACtF,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,GACD;IACE,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAC1C,CAAC;AAEN;;;;GAIG;AACH,MAAM,WAAW,kBAAmB,SAAQ,0BAA0B;IACpE,mGAAmG;IACnG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,oEAAoE;AACpE,MAAM,WAAW,0BAA0B;IACzC,uGAAuG;IACvG,QAAQ,CAAC,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACvE,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACxE,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC;IACrD,gDAAgD;IAChD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;CACrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,0BAA0B,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA8BjH"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ExtensionActionResultCode } from "./extension-catalog.js";
|
|
2
|
+
import { presentExtensionTransaction } from "./extension-report-presenter.js";
|
|
3
|
+
/**
|
|
4
|
+
* Add the library at `coordinate` through the app's own install transaction and
|
|
5
|
+
* present what happened through `surface.toasts`: a refusal as `failed`, a
|
|
6
|
+
* commit as `confirmed`, and a commit that brought new problems with it as
|
|
7
|
+
* `worsened` after the confirmation. A coordinate the app's catalog approves no
|
|
8
|
+
* reference for is refused without running anything.
|
|
9
|
+
*
|
|
10
|
+
* Answers whether this attempt put the library in the project: `false` for a
|
|
11
|
+
* refusal, for a failure, and for a library the project already held, which runs
|
|
12
|
+
* no transaction and presents nothing.
|
|
13
|
+
*
|
|
14
|
+
* @param surface - The app's approved catalog, install transaction, display names, and toasts.
|
|
15
|
+
* @param coordinate - The `<owner>/<repo>` coordinate to add.
|
|
16
|
+
*/
|
|
17
|
+
export async function addOfferedLibrary(surface, coordinate) {
|
|
18
|
+
const reference = surface.approvedReference(coordinate);
|
|
19
|
+
if (reference === undefined) {
|
|
20
|
+
surface.toasts.failed({
|
|
21
|
+
code: ExtensionActionResultCode.UNKNOWN_COORDINATE,
|
|
22
|
+
message: `No approved library is shelved at "${coordinate}".`,
|
|
23
|
+
});
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const attempt = await surface.install(reference);
|
|
27
|
+
if (!attempt.ok) {
|
|
28
|
+
surface.toasts.failed({ code: attempt.code, message: attempt.message });
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (!attempt.action.ok) {
|
|
32
|
+
if (attempt.action.code === ExtensionActionResultCode.ALREADY_INSTALLED) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
surface.toasts.failed({ code: attempt.action.code, message: `Adding "${coordinate}" changed nothing.` });
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const libraryName = surface.displayName(coordinate);
|
|
39
|
+
presentExtensionTransaction({ report: attempt.report, flavor: "install", libraryName, toasts: surface.toasts });
|
|
40
|
+
if (attempt.report?.committed !== true) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (attempt.report.outcome.kind === "worsened") {
|
|
44
|
+
surface.toasts.worsened(libraryName);
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { FileContent } from "@wendoo/app-host";
|
|
2
|
+
import type { EmbeddedExtension, FetchedExtensionContentMap } from "./embedded-extensions.js";
|
|
3
|
+
/** A saved brain checked by the uninstall guard: its display name and persisted brain JSON. */
|
|
4
|
+
export interface UninstallGuardBrain {
|
|
5
|
+
/** The brain's display name, as listed to the user. */
|
|
6
|
+
readonly name: string;
|
|
7
|
+
/** The brain's persisted JSON (the plain object form of its stored bytes). */
|
|
8
|
+
readonly json: unknown;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* What uninstalling one library takes away from a project: the namespaces
|
|
12
|
+
* leaving the resolved closure, the saved brains referencing them, and the
|
|
13
|
+
* user content files importing them.
|
|
14
|
+
*/
|
|
15
|
+
export interface LibraryUninstallImpact {
|
|
16
|
+
/**
|
|
17
|
+
* The `<owner>/<repo>` namespaces that leave the resolved closure when the
|
|
18
|
+
* coordinate is removed: the coordinate itself plus every transitive
|
|
19
|
+
* dependency no remaining dependent still pulls in.
|
|
20
|
+
*/
|
|
21
|
+
readonly leavingNamespaces: ReadonlySet<string>;
|
|
22
|
+
/** Display names of saved brains referencing a leaving namespace, in input order. */
|
|
23
|
+
readonly brainNames: readonly string[];
|
|
24
|
+
/** Paths of user content files importing a leaving namespace through `@lib/`, in input order. */
|
|
25
|
+
readonly filePaths: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Compute what uninstalling `coordinate` takes away from a project. The
|
|
29
|
+
* leaving set is the closure delta: the origins resolved today that are no
|
|
30
|
+
* longer resolved once the coordinate's manifest entry is removed, so a
|
|
31
|
+
* transitive dependency kept alive by another dependent does not count. A
|
|
32
|
+
* brain counts as affected when any of its referenced namespaces is leaving;
|
|
33
|
+
* a file counts when any of its `@lib/` import coordinates is leaving.
|
|
34
|
+
*
|
|
35
|
+
* @param options.extensions - The project's current extensions map, keyed by coordinate.
|
|
36
|
+
* @param options.coordinate - The `<owner>/<repo>` coordinate being uninstalled.
|
|
37
|
+
* @param options.embedded - The host application's bundled embedded extensions.
|
|
38
|
+
* @param options.fetched - Installed fetched-extension content, keyed by reference.
|
|
39
|
+
* @param options.brains - The project's saved brains, each with its display name and persisted JSON.
|
|
40
|
+
* @param options.files - User content files by path; omit for a host with no user content files.
|
|
41
|
+
*/
|
|
42
|
+
export declare function collectLibraryUninstallImpact(options: {
|
|
43
|
+
extensions: Readonly<Record<string, string>> | undefined;
|
|
44
|
+
coordinate: string;
|
|
45
|
+
embedded: readonly EmbeddedExtension[];
|
|
46
|
+
fetched?: FetchedExtensionContentMap;
|
|
47
|
+
brains: readonly UninstallGuardBrain[];
|
|
48
|
+
files?: ReadonlyMap<string, FileContent>;
|
|
49
|
+
}): LibraryUninstallImpact;
|
|
50
|
+
/** Outcome of a guarded uninstall run. */
|
|
51
|
+
export type LibraryUninstallGuardOutcome = "removed" | "cancelled";
|
|
52
|
+
/**
|
|
53
|
+
* Run an uninstall behind the in-use guard. An empty impact uninstalls
|
|
54
|
+
* immediately; a non-empty impact asks `confirmRemoval` first and uninstalls
|
|
55
|
+
* only on an affirmative answer.
|
|
56
|
+
*
|
|
57
|
+
* @param options.impact - The computed uninstall impact.
|
|
58
|
+
* @param options.confirmRemoval - Asks the user to confirm removing an in-use library.
|
|
59
|
+
* @param options.uninstall - Performs the uninstall.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runGuardedLibraryUninstall(options: {
|
|
62
|
+
impact: Pick<LibraryUninstallImpact, "brainNames" | "filePaths">;
|
|
63
|
+
confirmRemoval: () => boolean | Promise<boolean>;
|
|
64
|
+
uninstall: () => void | Promise<void>;
|
|
65
|
+
}): Promise<LibraryUninstallGuardOutcome>;
|
|
66
|
+
//# sourceMappingURL=library-uninstall-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"library-uninstall-guard.d.ts","sourceRoot":"","sources":["../src/library-uninstall-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAIpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAG9F,+FAA+F;AAC/F,MAAM,WAAW,mBAAmB;IAClC,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChD,qFAAqF;IACrF,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iGAAiG;IACjG,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAmCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE;IACrD,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC,OAAO,CAAC,EAAE,0BAA0B,CAAC;IACrC,MAAM,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACvC,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CAC1C,GAAG,sBAAsB,CA2CzB;AAED,0CAA0C;AAC1C,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnE;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,MAAM,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,WAAW,CAAC,CAAC;IACjE,cAAc,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAOxC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { fileContentText } from "@wendoo/app-host";
|
|
2
|
+
import { renameBrainNamespaces } from "@wendoo/core/app";
|
|
3
|
+
import { EXTENSION_IMPORT_PREFIX } from "@wendoo/ts-compiler";
|
|
4
|
+
import { resolveProjectExtensions } from "./embedded-extensions.js";
|
|
5
|
+
/** Collect every library namespace a persisted brain references. */
|
|
6
|
+
function collectBrainNamespaces(json) {
|
|
7
|
+
const namespaces = new Set();
|
|
8
|
+
renameBrainNamespaces(json, (namespace) => {
|
|
9
|
+
namespaces.add(namespace);
|
|
10
|
+
return namespace;
|
|
11
|
+
});
|
|
12
|
+
return namespaces;
|
|
13
|
+
}
|
|
14
|
+
/** The `<owner>/<repo>` coordinates a file's `@lib/` import specifiers name. */
|
|
15
|
+
function collectFileImportCoordinates(content) {
|
|
16
|
+
const coordinates = new Set();
|
|
17
|
+
const pattern = new RegExp(`["']${EXTENSION_IMPORT_PREFIX}([^"'\\s]+)["']`, "g");
|
|
18
|
+
for (const match of content.matchAll(pattern)) {
|
|
19
|
+
const segments = match[1].split("/");
|
|
20
|
+
if (segments.length >= 2 && segments[0].length > 0 && segments[1].length > 0) {
|
|
21
|
+
coordinates.add(`${segments[0]}/${segments[1]}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return coordinates;
|
|
25
|
+
}
|
|
26
|
+
/** The set of origin namespaces in the resolved closure of an extensions map. */
|
|
27
|
+
function resolvedNamespaces(extensions, embedded, fetched) {
|
|
28
|
+
const resolved = resolveProjectExtensions(extensions, { embedded, fetched });
|
|
29
|
+
return new Set(resolved.dependencyMounts.map((mount) => mount.namespace));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Compute what uninstalling `coordinate` takes away from a project. The
|
|
33
|
+
* leaving set is the closure delta: the origins resolved today that are no
|
|
34
|
+
* longer resolved once the coordinate's manifest entry is removed, so a
|
|
35
|
+
* transitive dependency kept alive by another dependent does not count. A
|
|
36
|
+
* brain counts as affected when any of its referenced namespaces is leaving;
|
|
37
|
+
* a file counts when any of its `@lib/` import coordinates is leaving.
|
|
38
|
+
*
|
|
39
|
+
* @param options.extensions - The project's current extensions map, keyed by coordinate.
|
|
40
|
+
* @param options.coordinate - The `<owner>/<repo>` coordinate being uninstalled.
|
|
41
|
+
* @param options.embedded - The host application's bundled embedded extensions.
|
|
42
|
+
* @param options.fetched - Installed fetched-extension content, keyed by reference.
|
|
43
|
+
* @param options.brains - The project's saved brains, each with its display name and persisted JSON.
|
|
44
|
+
* @param options.files - User content files by path; omit for a host with no user content files.
|
|
45
|
+
*/
|
|
46
|
+
export function collectLibraryUninstallImpact(options) {
|
|
47
|
+
const current = options.extensions ?? {};
|
|
48
|
+
const next = {};
|
|
49
|
+
for (const [key, value] of Object.entries(current)) {
|
|
50
|
+
if (key !== options.coordinate) {
|
|
51
|
+
next[key] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const remaining = resolvedNamespaces(next, options.embedded, options.fetched);
|
|
55
|
+
const leavingNamespaces = new Set();
|
|
56
|
+
for (const namespace of resolvedNamespaces(current, options.embedded, options.fetched)) {
|
|
57
|
+
if (!remaining.has(namespace)) {
|
|
58
|
+
leavingNamespaces.add(namespace);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const brainNames = [];
|
|
62
|
+
for (const brain of options.brains) {
|
|
63
|
+
const referenced = collectBrainNamespaces(brain.json);
|
|
64
|
+
for (const namespace of leavingNamespaces) {
|
|
65
|
+
if (referenced.has(namespace)) {
|
|
66
|
+
brainNames.push(brain.name);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const filePaths = [];
|
|
72
|
+
for (const [path, content] of options.files ?? []) {
|
|
73
|
+
const text = fileContentText(content);
|
|
74
|
+
if (text === undefined) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const imported = collectFileImportCoordinates(text);
|
|
78
|
+
for (const namespace of leavingNamespaces) {
|
|
79
|
+
if (imported.has(namespace)) {
|
|
80
|
+
filePaths.push(path);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { leavingNamespaces, brainNames, filePaths };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run an uninstall behind the in-use guard. An empty impact uninstalls
|
|
89
|
+
* immediately; a non-empty impact asks `confirmRemoval` first and uninstalls
|
|
90
|
+
* only on an affirmative answer.
|
|
91
|
+
*
|
|
92
|
+
* @param options.impact - The computed uninstall impact.
|
|
93
|
+
* @param options.confirmRemoval - Asks the user to confirm removing an in-use library.
|
|
94
|
+
* @param options.uninstall - Performs the uninstall.
|
|
95
|
+
*/
|
|
96
|
+
export async function runGuardedLibraryUninstall(options) {
|
|
97
|
+
const inUse = options.impact.brainNames.length > 0 || options.impact.filePaths.length > 0;
|
|
98
|
+
if (inUse && !(await options.confirmRemoval())) {
|
|
99
|
+
return "cancelled";
|
|
100
|
+
}
|
|
101
|
+
await options.uninstall();
|
|
102
|
+
return "removed";
|
|
103
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queries and edits over a project content manifest's `files` list: the list
|
|
3
|
+
* names what is in the build, while the project may hold more files than it
|
|
4
|
+
* lists. Membership tells the two apart; the only error direction is a listed
|
|
5
|
+
* file that is absent from the project. The edit helpers toggle one entry in
|
|
6
|
+
* the manifest's JSON text while leaving every other byte of the document
|
|
7
|
+
* untouched.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalize a manifest `files` entry or project file path for comparison by
|
|
11
|
+
* stripping leading `./` and `/` segments. `"./a.ts"`, `"/a.ts"`, and
|
|
12
|
+
* `"a.ts"` all normalize to `"a.ts"`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeManifestFilePath(path: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* True when `path` is named by the manifest `files` list, comparing both
|
|
17
|
+
* sides with {@link normalizeManifestFilePath}.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isFileInBuild(files: readonly string[], path: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Return the `files` entries, as written, whose normalized path `exists`
|
|
22
|
+
* rejects. An empty result means every listed file is present. Paths absent
|
|
23
|
+
* from `files` are never reported, whatever `exists` answers for them.
|
|
24
|
+
*
|
|
25
|
+
* @param files - The manifest `files` list.
|
|
26
|
+
* @param exists - Presence test invoked with each entry's normalized path.
|
|
27
|
+
*/
|
|
28
|
+
export declare function findMissingListedFiles(files: readonly string[], exists: (path: string) => boolean): readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Read the `files` list from a manifest's JSON text without validating the
|
|
31
|
+
* rest of the document. Returns the string entries when the document is a
|
|
32
|
+
* JSON object whose `files` is an array holding at least one string, and
|
|
33
|
+
* `undefined` otherwise (including unparseable text).
|
|
34
|
+
*/
|
|
35
|
+
export declare function readManifestFilesList(manifestText: string): readonly string[] | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Add `path` (normalized) to the manifest text's `files` array, preserving
|
|
38
|
+
* every byte of the document outside that array and matching the array's
|
|
39
|
+
* existing one-entry-per-line or single-line formatting. Returns the edited
|
|
40
|
+
* text, or `undefined` when the document has no well-formed root-level
|
|
41
|
+
* string-array `files`, the entry is already listed, or the edit would not
|
|
42
|
+
* produce valid JSON.
|
|
43
|
+
*/
|
|
44
|
+
export declare function addManifestFilesEntry(manifestText: string, path: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Remove every `files` entry matching `path` (compared normalized) from the
|
|
47
|
+
* manifest text, preserving every byte of the document outside the `files`
|
|
48
|
+
* array. Returns the edited text, or `undefined` when the document has no
|
|
49
|
+
* well-formed root-level string-array `files`, no entry matches, or the edit
|
|
50
|
+
* would not produce valid JSON. Removing the last entry leaves `[]`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function removeManifestFilesEntry(manifestText: string, path: string): string | undefined;
|
|
53
|
+
//# sourceMappingURL=manifest-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-files.d.ts","sourceRoot":"","sources":["../src/manifest-files.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW9D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,MAAM,EAAE,CAErH;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAgBzF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmB5F;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoB/F"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queries and edits over a project content manifest's `files` list: the list
|
|
3
|
+
* names what is in the build, while the project may hold more files than it
|
|
4
|
+
* lists. Membership tells the two apart; the only error direction is a listed
|
|
5
|
+
* file that is absent from the project. The edit helpers toggle one entry in
|
|
6
|
+
* the manifest's JSON text while leaving every other byte of the document
|
|
7
|
+
* untouched.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Normalize a manifest `files` entry or project file path for comparison by
|
|
11
|
+
* stripping leading `./` and `/` segments. `"./a.ts"`, `"/a.ts"`, and
|
|
12
|
+
* `"a.ts"` all normalize to `"a.ts"`.
|
|
13
|
+
*/
|
|
14
|
+
export function normalizeManifestFilePath(path) {
|
|
15
|
+
let result = path;
|
|
16
|
+
for (;;) {
|
|
17
|
+
if (result.startsWith("./")) {
|
|
18
|
+
result = result.slice(2);
|
|
19
|
+
}
|
|
20
|
+
else if (result.startsWith("/")) {
|
|
21
|
+
result = result.slice(1);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* True when `path` is named by the manifest `files` list, comparing both
|
|
30
|
+
* sides with {@link normalizeManifestFilePath}.
|
|
31
|
+
*/
|
|
32
|
+
export function isFileInBuild(files, path) {
|
|
33
|
+
const target = normalizeManifestFilePath(path);
|
|
34
|
+
return files.some((entry) => normalizeManifestFilePath(entry) === target);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Return the `files` entries, as written, whose normalized path `exists`
|
|
38
|
+
* rejects. An empty result means every listed file is present. Paths absent
|
|
39
|
+
* from `files` are never reported, whatever `exists` answers for them.
|
|
40
|
+
*
|
|
41
|
+
* @param files - The manifest `files` list.
|
|
42
|
+
* @param exists - Presence test invoked with each entry's normalized path.
|
|
43
|
+
*/
|
|
44
|
+
export function findMissingListedFiles(files, exists) {
|
|
45
|
+
return files.filter((entry) => !exists(normalizeManifestFilePath(entry)));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Read the `files` list from a manifest's JSON text without validating the
|
|
49
|
+
* rest of the document. Returns the string entries when the document is a
|
|
50
|
+
* JSON object whose `files` is an array holding at least one string, and
|
|
51
|
+
* `undefined` otherwise (including unparseable text).
|
|
52
|
+
*/
|
|
53
|
+
export function readManifestFilesList(manifestText) {
|
|
54
|
+
let parsed;
|
|
55
|
+
try {
|
|
56
|
+
parsed = JSON.parse(manifestText);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const files = parsed.files;
|
|
65
|
+
if (!Array.isArray(files)) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
const entries = files.filter((entry) => typeof entry === "string");
|
|
69
|
+
return entries.length > 0 ? entries : undefined;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Add `path` (normalized) to the manifest text's `files` array, preserving
|
|
73
|
+
* every byte of the document outside that array and matching the array's
|
|
74
|
+
* existing one-entry-per-line or single-line formatting. Returns the edited
|
|
75
|
+
* text, or `undefined` when the document has no well-formed root-level
|
|
76
|
+
* string-array `files`, the entry is already listed, or the edit would not
|
|
77
|
+
* produce valid JSON.
|
|
78
|
+
*/
|
|
79
|
+
export function addManifestFilesEntry(manifestText, path) {
|
|
80
|
+
const span = findFilesArray(manifestText);
|
|
81
|
+
if (span === undefined)
|
|
82
|
+
return undefined;
|
|
83
|
+
const target = normalizeManifestFilePath(path);
|
|
84
|
+
if (span.elements.some((element) => normalizeManifestFilePath(element.value) === target)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const entryText = JSON.stringify(target);
|
|
88
|
+
let edited;
|
|
89
|
+
if (span.elements.length === 0) {
|
|
90
|
+
edited = manifestText.slice(0, span.start + 1) + entryText + manifestText.slice(span.end);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const first = span.elements[0];
|
|
94
|
+
const last = span.elements[span.elements.length - 1];
|
|
95
|
+
const leading = manifestText.slice(span.start + 1, first.start);
|
|
96
|
+
const separator = `,${leading === "" ? " " : leading}`;
|
|
97
|
+
edited = manifestText.slice(0, last.end) + separator + entryText + manifestText.slice(last.end);
|
|
98
|
+
}
|
|
99
|
+
return isValidJson(edited) ? edited : undefined;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Remove every `files` entry matching `path` (compared normalized) from the
|
|
103
|
+
* manifest text, preserving every byte of the document outside the `files`
|
|
104
|
+
* array. Returns the edited text, or `undefined` when the document has no
|
|
105
|
+
* well-formed root-level string-array `files`, no entry matches, or the edit
|
|
106
|
+
* would not produce valid JSON. Removing the last entry leaves `[]`.
|
|
107
|
+
*/
|
|
108
|
+
export function removeManifestFilesEntry(manifestText, path) {
|
|
109
|
+
const span = findFilesArray(manifestText);
|
|
110
|
+
if (span === undefined)
|
|
111
|
+
return undefined;
|
|
112
|
+
const target = normalizeManifestFilePath(path);
|
|
113
|
+
const kept = span.elements.filter((element) => normalizeManifestFilePath(element.value) !== target);
|
|
114
|
+
if (kept.length === span.elements.length)
|
|
115
|
+
return undefined;
|
|
116
|
+
let content;
|
|
117
|
+
if (kept.length === 0) {
|
|
118
|
+
content = "";
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const first = span.elements[0];
|
|
122
|
+
const last = span.elements[span.elements.length - 1];
|
|
123
|
+
const leading = manifestText.slice(span.start + 1, first.start);
|
|
124
|
+
const trailing = manifestText.slice(last.end, span.end);
|
|
125
|
+
const separator = span.elements.length >= 2 ? manifestText.slice(span.elements[0].end, span.elements[1].start) : "";
|
|
126
|
+
content =
|
|
127
|
+
leading + kept.map((element) => manifestText.slice(element.start, element.end)).join(separator) + trailing;
|
|
128
|
+
}
|
|
129
|
+
const edited = manifestText.slice(0, span.start + 1) + content + manifestText.slice(span.end);
|
|
130
|
+
return isValidJson(edited) ? edited : undefined;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Locate the root-level `files` array in JSON text. Only a `files` key of the
|
|
134
|
+
* document's root object counts; the same key nested deeper, or the word
|
|
135
|
+
* inside a string value, is ignored. Returns `undefined` when the key is
|
|
136
|
+
* absent, its value is not an array of strings, or the text is malformed.
|
|
137
|
+
*/
|
|
138
|
+
function findFilesArray(text) {
|
|
139
|
+
const stack = [];
|
|
140
|
+
let i = 0;
|
|
141
|
+
while (i < text.length) {
|
|
142
|
+
const ch = text[i];
|
|
143
|
+
if (ch === '"') {
|
|
144
|
+
const token = scanString(text, i);
|
|
145
|
+
if (token === undefined)
|
|
146
|
+
return undefined;
|
|
147
|
+
if (stack.length === 1 && stack[0] === "{" && token.value === "files") {
|
|
148
|
+
const colon = skipWhitespace(text, token.end);
|
|
149
|
+
if (text[colon] === ":") {
|
|
150
|
+
const open = skipWhitespace(text, colon + 1);
|
|
151
|
+
if (text[open] !== "[")
|
|
152
|
+
return undefined;
|
|
153
|
+
return scanFilesArray(text, open);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
i = token.end;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (ch === "{" || ch === "[") {
|
|
160
|
+
stack.push(ch);
|
|
161
|
+
}
|
|
162
|
+
else if (ch === "}" || ch === "]") {
|
|
163
|
+
stack.pop();
|
|
164
|
+
}
|
|
165
|
+
i++;
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
/** Scan the `files` array starting at its `[`; strings at element depth become elements. */
|
|
170
|
+
function scanFilesArray(text, open) {
|
|
171
|
+
const elements = [];
|
|
172
|
+
let depth = 1;
|
|
173
|
+
let i = open + 1;
|
|
174
|
+
while (i < text.length) {
|
|
175
|
+
const ch = text[i];
|
|
176
|
+
if (ch === '"') {
|
|
177
|
+
const token = scanString(text, i);
|
|
178
|
+
if (token === undefined)
|
|
179
|
+
return undefined;
|
|
180
|
+
if (depth !== 1)
|
|
181
|
+
return undefined;
|
|
182
|
+
elements.push(token);
|
|
183
|
+
i = token.end;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (ch === "{" || ch === "[") {
|
|
187
|
+
depth++;
|
|
188
|
+
}
|
|
189
|
+
else if (ch === "}" || ch === "]") {
|
|
190
|
+
depth--;
|
|
191
|
+
if (depth === 0) {
|
|
192
|
+
if (ch !== "]")
|
|
193
|
+
return undefined;
|
|
194
|
+
return { start: open, end: i, elements };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (ch !== "," && ch !== " " && ch !== "\t" && ch !== "\n" && ch !== "\r") {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
i++;
|
|
201
|
+
}
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
204
|
+
/** Scan one JSON string token starting at its opening quote. */
|
|
205
|
+
function scanString(text, start) {
|
|
206
|
+
let i = start + 1;
|
|
207
|
+
while (i < text.length) {
|
|
208
|
+
const ch = text[i];
|
|
209
|
+
if (ch === "\\") {
|
|
210
|
+
i += 2;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (ch === '"') {
|
|
214
|
+
const end = i + 1;
|
|
215
|
+
try {
|
|
216
|
+
return { start, end, value: JSON.parse(text.slice(start, end)) };
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
i++;
|
|
223
|
+
}
|
|
224
|
+
return undefined;
|
|
225
|
+
}
|
|
226
|
+
/** Index of the first non-whitespace character at or after `from`. */
|
|
227
|
+
function skipWhitespace(text, from) {
|
|
228
|
+
let i = from;
|
|
229
|
+
while (i < text.length && (text[i] === " " || text[i] === "\t" || text[i] === "\n" || text[i] === "\r")) {
|
|
230
|
+
i++;
|
|
231
|
+
}
|
|
232
|
+
return i;
|
|
233
|
+
}
|
|
234
|
+
function isValidJson(text) {
|
|
235
|
+
try {
|
|
236
|
+
JSON.parse(text);
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { buildEmbeddedExtensionFromDir, extensionSourceFiles, findMissingExtensionFiles, } from "./embedded-extension-loader.js";
|
|
2
|
+
export type { EmbeddedExtensionRegistration, EmbeddedExtensionsVitePlugin, } from "./embedded-extension-vite-plugin.js";
|
|
3
|
+
export { EMBEDDED_EXTENSIONS_MODULE_ID, embeddedExtensionsVitePlugin } from "./embedded-extension-vite-plugin.js";
|
|
4
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,gCAAgC,CAAC;AACxC,YAAY,EACV,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,6BAA6B,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC"}
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProjectFileChange, ProjectFileSnapshot } from "@wendoo/app-host";
|
|
2
|
+
import type { FileSystemSnapshot } from "@wendoo/bridge-client";
|
|
3
|
+
import type { FileSystemNotification } from "@wendoo/bridge-protocol";
|
|
4
|
+
/** Convert an app-host project file snapshot into a bridge-client snapshot. */
|
|
5
|
+
export declare function toFileSystemSnapshot(snapshot: ProjectFileSnapshot): FileSystemSnapshot;
|
|
6
|
+
/** Convert an app-host project file mutation into a bridge protocol notification. */
|
|
7
|
+
export declare function toFileSystemNotification(change: ProjectFileChange): FileSystemNotification;
|
|
8
|
+
/** Convert a bridge protocol notification into an app-host project file mutation. */
|
|
9
|
+
export declare function toProjectFileChange(notification: FileSystemNotification): ProjectFileChange;
|
|
10
|
+
//# sourceMappingURL=project-file-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-file-bridge.d.ts","sourceRoot":"","sources":["../src/project-file-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAA0B,MAAM,kBAAkB,CAAC;AAEvG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,kBAAkB,CAEtF;AAED,qFAAqF;AACrF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,GAAG,sBAAsB,CA+B1F;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,sBAAsB,GAAG,iBAAiB,CA+B3F"}
|