@lvce-editor/api 8.82.0 → 8.83.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/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { registerDebugProvider, resetDebugProviderRegistry } from './parts/Debug
10
10
  export { executeCompletionProvider, executeResolveCompletionItemProvider, getCompletionProviderRegistrySnapshot, registerCompletionProvider, resetCompletionProviderRegistry, } from './parts/Completion/Completion.ts';
11
11
  export { executeDiagnosticProvider, getDiagnosticProviderRegistrySnapshot, registerDiagnosticProvider, resetDiagnosticProviderRegistry, } from './parts/Diagnostic/Diagnostic.ts';
12
12
  export { executeFormattingProvider, getFormattingProviderRegistrySnapshot, registerFormattingProvider, resetFormattingProviderRegistry, } from './parts/Formatting/Formatting.ts';
13
- export { exists, mkdir, readAsObjectUrl, readDirWithFileTypes, readFile, remove, stat, writeFile, type ReadAsObjectUrlResult, } from './parts/FileSystem/FileSystem.ts';
13
+ export { exists, getFileHash, mkdir, readAsObjectUrl, readDirWithFileTypes, readFile, remove, stat, writeFile, type ReadAsObjectUrlResult, } from './parts/FileSystem/FileSystem.ts';
14
14
  export { registerFileChangeHandler, type FileChangeHandler, type FileChanges } from './parts/FileChangeHandler/FileChangeHandler.ts';
15
15
  export { executeFileSystemProviderGetPathSeparator, executeFileSystemProviderIsReadonly, executeFileSystemProviderMkdir, executeFileSystemProviderReadDirWithFileTypes, executeFileSystemProviderReadFile, executeFileSystemProviderRemove, executeFileSystemProviderRename, executeFileSystemProviderWriteFile, getFileSystemProviderRegistrySnapshot, registerFileSystemProvider, resetFileSystemProviderRegistry, } from './parts/FileSystemProviderRegistry/FileSystemProviderRegistry.ts';
16
16
  export { confirm, getWorkspaceFolder, getWorkspaceUri, handleWorkspaceRefresh, openUri, setWorkspaceUri, showNotification, type NotificationType, } from './parts/Host/Host.ts';
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ export { registerDebugProvider, resetDebugProviderRegistry } from "./parts/Debug
10
10
  export { executeCompletionProvider, executeResolveCompletionItemProvider, getCompletionProviderRegistrySnapshot, registerCompletionProvider, resetCompletionProviderRegistry, } from "./parts/Completion/Completion.js";
11
11
  export { executeDiagnosticProvider, getDiagnosticProviderRegistrySnapshot, registerDiagnosticProvider, resetDiagnosticProviderRegistry, } from "./parts/Diagnostic/Diagnostic.js";
12
12
  export { executeFormattingProvider, getFormattingProviderRegistrySnapshot, registerFormattingProvider, resetFormattingProviderRegistry, } from "./parts/Formatting/Formatting.js";
13
- export { exists, mkdir, readAsObjectUrl, readDirWithFileTypes, readFile, remove, stat, writeFile, } from "./parts/FileSystem/FileSystem.js";
13
+ export { exists, getFileHash, mkdir, readAsObjectUrl, readDirWithFileTypes, readFile, remove, stat, writeFile, } from "./parts/FileSystem/FileSystem.js";
14
14
  export { registerFileChangeHandler } from "./parts/FileChangeHandler/FileChangeHandler.js";
15
15
  export { executeFileSystemProviderGetPathSeparator, executeFileSystemProviderIsReadonly, executeFileSystemProviderMkdir, executeFileSystemProviderReadDirWithFileTypes, executeFileSystemProviderReadFile, executeFileSystemProviderRemove, executeFileSystemProviderRename, executeFileSystemProviderWriteFile, getFileSystemProviderRegistrySnapshot, registerFileSystemProvider, resetFileSystemProviderRegistry, } from "./parts/FileSystemProviderRegistry/FileSystemProviderRegistry.js";
16
16
  export { confirm, getWorkspaceFolder, getWorkspaceUri, handleWorkspaceRefresh, openUri, setWorkspaceUri, showNotification, } from "./parts/Host/Host.js";
@@ -6,6 +6,7 @@ export interface ReadAsObjectUrlResult {
6
6
  }
7
7
  export declare const exists: (uri: string) => Promise<boolean>;
8
8
  export declare const readDirWithFileTypes: (uri: string) => Promise<readonly FileSystemDirent[]>;
9
+ export declare const getFileHash: (uri: string) => Promise<string>;
9
10
  export declare const readFile: (uri: string) => Promise<string>;
10
11
  export declare const readAsObjectUrl: (uri: string) => Promise<ReadAsObjectUrlResult>;
11
12
  export declare const mkdir: (uri: string) => Promise<void>;
@@ -32,6 +32,9 @@ export const exists = async (uri) => {
32
32
  export const readDirWithFileTypes = async (uri) => {
33
33
  return FileSystemWorker.readDirWithFileTypes(uri);
34
34
  };
35
+ export const getFileHash = async (uri) => {
36
+ return FileSystemWorker.invoke('FileSystem.getFileHash', uri);
37
+ };
35
38
  export const readFile = async (uri) => {
36
39
  if (isMemory(uri)) {
37
40
  return ExtensionManagementWorker.invoke('ExtensionApi.readFile', uri);
@@ -3,8 +3,8 @@ import type { OutputChannelRegistrySnapshot } from '../OutputChannelRegistrySnap
3
3
  export declare const activateOutputChannels: () => void;
4
4
  export declare const createOutputChannel: (id: string) => OutputChannel;
5
5
  export declare const getOutputChannelRegistrySnapshot: () => OutputChannelRegistrySnapshot;
6
- export declare const getOutputChannelLogs: (id: string) => string | undefined;
7
- export declare const clearOutputChannel: (id: string) => boolean;
6
+ export declare const getOutputChannelLogs: (id: string) => Promise<string | undefined>;
7
+ export declare const clearOutputChannel: (id: string) => Promise<boolean>;
8
8
  export declare const resetOutputChannelRegistry: () => void;
9
9
  export type { OutputChannel } from '../OutputChannelHandle/OutputChannelHandle.ts';
10
10
  export type { OutputChannelRegistrySnapshot } from '../OutputChannelRegistrySnapshot/OutputChannelRegistrySnapshot.ts';
@@ -1,7 +1,8 @@
1
1
  import * as ExtensionApiCommandRegistry from "../ExtensionApiCommandRegistry/ExtensionApiCommandRegistry.js";
2
2
  import { ExtensionApiError } from "../ExtensionApiError/ExtensionApiError.js";
3
+ import * as OutputChannelStorage from "../OutputChannelStorage/OutputChannelStorage.js";
3
4
  const outputChannels = Object.create(null);
4
- const outputChannelLogs = Object.create(null);
5
+ const outputChannelHandles = Object.create(null);
5
6
  let isActivated = false;
6
7
  const RE_DASH_CASE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
7
8
  const assertOutputChannelId = (id) => {
@@ -19,28 +20,38 @@ const assertCanWrite = (id) => {
19
20
  };
20
21
  class ExtensionOutputChannel {
21
22
  #id;
23
+ #pendingWrite;
22
24
  constructor(id) {
23
25
  this.#id = id;
24
26
  }
27
+ #initialize() {
28
+ this.#pendingWrite ||= OutputChannelStorage.clear(this.#id);
29
+ return this.#pendingWrite;
30
+ }
31
+ #queueWrite(write) {
32
+ this.#pendingWrite = this.#initialize().then(write);
33
+ return this.#pendingWrite;
34
+ }
25
35
  async append(text) {
26
36
  assertCanWrite(this.#id);
27
- outputChannelLogs[this.#id] += text;
37
+ await this.#queueWrite(() => OutputChannelStorage.append(this.#id, text));
28
38
  }
29
39
  async appendLine(text) {
30
40
  assertCanWrite(this.#id);
31
- outputChannelLogs[this.#id] += `${text}\n`;
41
+ await this.#queueWrite(() => OutputChannelStorage.append(this.#id, `${text}\n`));
32
42
  }
33
43
  async clear() {
34
44
  assertCanWrite(this.#id);
35
- outputChannelLogs[this.#id] = '';
45
+ await this.#queueWrite(() => OutputChannelStorage.clear(this.#id));
36
46
  }
37
47
  async getLogs() {
38
48
  assertCanWrite(this.#id);
39
- return outputChannelLogs[this.#id];
49
+ await this.#initialize();
50
+ return OutputChannelStorage.getLogs(this.#id);
40
51
  }
41
52
  async replace(text) {
42
53
  assertCanWrite(this.#id);
43
- outputChannelLogs[this.#id] = text;
54
+ await this.#queueWrite(() => OutputChannelStorage.replace(this.#id, text));
44
55
  }
45
56
  }
46
57
  export const activateOutputChannels = () => {
@@ -54,23 +65,25 @@ export const createOutputChannel = (id) => {
54
65
  outputChannels[id] = {
55
66
  id,
56
67
  };
57
- outputChannelLogs[id] = '';
58
68
  ExtensionApiCommandRegistry.registerCommandMap(commandMap);
59
- return new ExtensionOutputChannel(id);
69
+ const handle = new ExtensionOutputChannel(id);
70
+ outputChannelHandles[id] = handle;
71
+ return handle;
60
72
  };
61
73
  export const getOutputChannelRegistrySnapshot = () => {
62
74
  return {
63
75
  outputChannels: Object.values(outputChannels),
64
76
  };
65
77
  };
66
- export const getOutputChannelLogs = (id) => {
67
- return outputChannelLogs[id];
78
+ export const getOutputChannelLogs = async (id) => {
79
+ return outputChannelHandles[id]?.getLogs();
68
80
  };
69
- export const clearOutputChannel = (id) => {
70
- if (!(id in outputChannelLogs)) {
81
+ export const clearOutputChannel = async (id) => {
82
+ const handle = outputChannelHandles[id];
83
+ if (!handle) {
71
84
  return false;
72
85
  }
73
- outputChannelLogs[id] = '';
86
+ await handle.clear();
74
87
  return true;
75
88
  };
76
89
  const commandMap = {
@@ -82,8 +95,8 @@ export const resetOutputChannelRegistry = () => {
82
95
  for (const id of Object.keys(outputChannels)) {
83
96
  delete outputChannels[id];
84
97
  }
85
- for (const id of Object.keys(outputChannelLogs)) {
86
- delete outputChannelLogs[id];
98
+ for (const id of Object.keys(outputChannelHandles)) {
99
+ delete outputChannelHandles[id];
87
100
  }
88
101
  isActivated = false;
89
102
  };
@@ -0,0 +1,4 @@
1
+ export declare const append: (channelId: string, text: string) => Promise<void>;
2
+ export declare const clear: (channelId: string) => Promise<void>;
3
+ export declare const getLogs: (channelId: string) => Promise<string>;
4
+ export declare const replace: (channelId: string, text: string) => Promise<void>;
@@ -0,0 +1,79 @@
1
+ const databasePrefix = 'lvce-editor-extension-output';
2
+ const databaseVersion = 1;
3
+ const objectStoreName = 'chunks';
4
+ const channelIdIndexName = 'channelId';
5
+ let databasePromise;
6
+ const getDatabaseName = () => {
7
+ const extensionPath = typeof location === 'undefined' ? 'test' : location.pathname;
8
+ return `${databasePrefix}:${extensionPath}`;
9
+ };
10
+ const openDatabase = () => {
11
+ return new Promise((resolve, reject) => {
12
+ const request = indexedDB.open(getDatabaseName(), databaseVersion);
13
+ request.onerror = () => reject(request.error);
14
+ request.onupgradeneeded = () => {
15
+ const database = request.result;
16
+ const objectStore = database.createObjectStore(objectStoreName, {
17
+ autoIncrement: true,
18
+ });
19
+ objectStore.createIndex(channelIdIndexName, 'channelId');
20
+ };
21
+ request.onsuccess = () => resolve(request.result);
22
+ });
23
+ };
24
+ const getDatabase = () => {
25
+ databasePromise ||= openDatabase();
26
+ return databasePromise;
27
+ };
28
+ const waitForTransaction = (transaction) => {
29
+ return new Promise((resolve, reject) => {
30
+ transaction.onabort = () => reject(transaction.error);
31
+ transaction.onerror = () => reject(transaction.error);
32
+ transaction.oncomplete = () => resolve();
33
+ });
34
+ };
35
+ const deleteChannelChunks = (objectStore, channelId, onComplete = () => { }) => {
36
+ const index = objectStore.index(channelIdIndexName);
37
+ const request = index.openKeyCursor(IDBKeyRange.only(channelId));
38
+ request.onsuccess = () => {
39
+ const cursor = request.result;
40
+ if (!cursor) {
41
+ onComplete();
42
+ return;
43
+ }
44
+ objectStore.delete(cursor.primaryKey);
45
+ cursor.continue();
46
+ };
47
+ };
48
+ export const append = async (channelId, text) => {
49
+ const database = await getDatabase();
50
+ const transaction = database.transaction(objectStoreName, 'readwrite');
51
+ transaction.objectStore(objectStoreName).add({ channelId, text });
52
+ await waitForTransaction(transaction);
53
+ };
54
+ export const clear = async (channelId) => {
55
+ const database = await getDatabase();
56
+ const transaction = database.transaction(objectStoreName, 'readwrite');
57
+ deleteChannelChunks(transaction.objectStore(objectStoreName), channelId);
58
+ await waitForTransaction(transaction);
59
+ };
60
+ export const getLogs = async (channelId) => {
61
+ const database = await getDatabase();
62
+ const transaction = database.transaction(objectStoreName, 'readonly');
63
+ const request = transaction.objectStore(objectStoreName).index(channelIdIndexName).getAll(IDBKeyRange.only(channelId));
64
+ const chunks = await new Promise((resolve, reject) => {
65
+ request.onerror = () => reject(request.error);
66
+ request.onsuccess = () => resolve(request.result);
67
+ });
68
+ await waitForTransaction(transaction);
69
+ return chunks.map((chunk) => chunk.text).join('');
70
+ };
71
+ export const replace = async (channelId, text) => {
72
+ const database = await getDatabase();
73
+ const transaction = database.transaction(objectStoreName, 'readwrite');
74
+ const objectStore = transaction.objectStore(objectStoreName);
75
+ deleteChannelChunks(objectStore, channelId, () => {
76
+ objectStore.add({ channelId, text });
77
+ });
78
+ await waitForTransaction(transaction);
79
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/api",
3
- "version": "8.82.0",
3
+ "version": "8.83.1",
4
4
  "description": "Tree-shakeable extension API for Lvce Editor extensions.",
5
5
  "keywords": [
6
6
  "lvce-editor",