From 274b36f8c255e613aa318f1e1037aa1ecbd631e3 Mon Sep 17 00:00:00 2001 From: Outer Cloud Studio Date: Sun, 12 Nov 2023 14:20:03 -0600 Subject: [PATCH 001/634] start new fs api --- src/App.ts | 84 +++++++++++++++--------------- src/utils/filesystem/base/file.ts | 1 + src/utils/filesystem/pwa/file.ts | 3 ++ src/utils/filesystem/tauri/file.ts | 3 ++ 4 files changed, 49 insertions(+), 42 deletions(-) create mode 100644 src/utils/filesystem/base/file.ts create mode 100644 src/utils/filesystem/pwa/file.ts create mode 100644 src/utils/filesystem/tauri/file.ts diff --git a/src/App.ts b/src/App.ts index de174a13c..45b0377f7 100644 --- a/src/App.ts +++ b/src/App.ts @@ -221,48 +221,48 @@ export class App { static async main(appComponent: Vue) { console.time('[APP] Ready') - this._instance = markRaw(new App(appComponent)) - - await this.instance.beforeStartUp() - - this.instance.fileSystem.setup(await getStorageDirectory()) - - if (import.meta.env.VITE_IS_TAURI_APP) { - // TauriFs env -> bridge. folder is the same as getStorageDirectory() - await this.instance.bridgeFolderSetup.dispatch() - // Setup com.mojang folder - await this.instance.comMojang.setupComMojang() - // Load projects - this.instance.projectManager.loadProjects(true).then(() => { - this.instance.themeManager.updateTheme() - }) - } - - // Show changelog after an update - if (await get('firstStartAfterUpdate')) { - await set('firstStartAfterUpdate', false) - this.instance.windows.changelogWindow.open() - } - - // Load settings - const settingsLoaded = SettingsWindow.loadSettings(this.instance) - await settingsLoaded - - // Force data download - if (import.meta.env.DEV) - this.instance.dataLoader.loadData( - settingsState?.developers?.forceDataDownload ?? false - ) - - settingsLoaded.then(async () => { - await this.instance.dataLoader.fired - this.instance.themeManager.loadDefaultThemes(this.instance) - }) - - await this.instance.startUp() - - this.ready.dispatch(this.instance) - await this.instance.projectManager.selectLastProject() + // this._instance = markRaw(new App(appComponent)) + + // await this.instance.beforeStartUp() + + // this.instance.fileSystem.setup(await getStorageDirectory()) + + // if (import.meta.env.VITE_IS_TAURI_APP) { + // // TauriFs env -> bridge. folder is the same as getStorageDirectory() + // await this.instance.bridgeFolderSetup.dispatch() + // // Setup com.mojang folder + // await this.instance.comMojang.setupComMojang() + // // Load projects + // this.instance.projectManager.loadProjects(true).then(() => { + // this.instance.themeManager.updateTheme() + // }) + // } + + // // Show changelog after an update + // if (await get('firstStartAfterUpdate')) { + // await set('firstStartAfterUpdate', false) + // this.instance.windows.changelogWindow.open() + // } + + // // Load settings + // const settingsLoaded = SettingsWindow.loadSettings(this.instance) + // await settingsLoaded + + // // Force data download + // if (import.meta.env.DEV) + // this.instance.dataLoader.loadData( + // settingsState?.developers?.forceDataDownload ?? false + // ) + + // settingsLoaded.then(async () => { + // await this.instance.dataLoader.fired + // this.instance.themeManager.loadDefaultThemes(this.instance) + // }) + + // await this.instance.startUp() + + // this.ready.dispatch(this.instance) + // await this.instance.projectManager.selectLastProject() console.timeEnd('[APP] Ready') } diff --git a/src/utils/filesystem/base/file.ts b/src/utils/filesystem/base/file.ts new file mode 100644 index 000000000..ea457e4fc --- /dev/null +++ b/src/utils/filesystem/base/file.ts @@ -0,0 +1 @@ +export abstract class BaseFile {} diff --git a/src/utils/filesystem/pwa/file.ts b/src/utils/filesystem/pwa/file.ts new file mode 100644 index 000000000..47180d6eb --- /dev/null +++ b/src/utils/filesystem/pwa/file.ts @@ -0,0 +1,3 @@ +import { BaseFile } from '../base/file' + +export class PWAFile extends BaseFile {} diff --git a/src/utils/filesystem/tauri/file.ts b/src/utils/filesystem/tauri/file.ts new file mode 100644 index 000000000..e910d2413 --- /dev/null +++ b/src/utils/filesystem/tauri/file.ts @@ -0,0 +1,3 @@ +import { BaseFile } from '../base/file' + +export class TauriFile extends BaseFile {} From d12ec42d774f7b611cbb817918898c137856770d Mon Sep 17 00:00:00 2001 From: Outer Cloud Studio Date: Sun, 12 Nov 2023 23:02:29 -0600 Subject: [PATCH 002/634] work on new fs --- src/App.ts | 374 +----------------------- src/App.vue | 228 --------------- src/utils/fileSystem/BaseFileSystem.ts | 5 + src/utils/fileSystem/FileSystem.ts | 42 +++ src/utils/fileSystem/LocalFileSystem.ts | 3 + src/utils/fileSystem/PWAFileSystem.ts | 20 ++ src/utils/fileSystem/TauriFileSystem.ts | 3 + src/utils/filesystem/base/file.ts | 1 - src/utils/filesystem/pwa/file.ts | 3 - src/utils/filesystem/tauri/file.ts | 3 - 10 files changed, 77 insertions(+), 605 deletions(-) create mode 100644 src/utils/fileSystem/BaseFileSystem.ts create mode 100644 src/utils/fileSystem/FileSystem.ts create mode 100644 src/utils/fileSystem/LocalFileSystem.ts create mode 100644 src/utils/fileSystem/PWAFileSystem.ts create mode 100644 src/utils/fileSystem/TauriFileSystem.ts delete mode 100644 src/utils/filesystem/base/file.ts delete mode 100644 src/utils/filesystem/pwa/file.ts delete mode 100644 src/utils/filesystem/tauri/file.ts diff --git a/src/App.ts b/src/App.ts index 45b0377f7..4cc66528c 100644 --- a/src/App.ts +++ b/src/App.ts @@ -4,51 +4,8 @@ import '/@/components/Languages/LanguageManager' import Vue from 'vue' import { EventSystem } from '/@/components/Common/Event/EventSystem' import { Signal } from '/@/components/Common/Event/Signal' -import { FileTypeLibrary } from '/@/components/Data/FileType' -import { ThemeManager } from '/@/components/Extensions/Themes/ThemeManager' -import { FileSystem } from '/@/components/FileSystem/FileSystem' -import { FileSystemSetup } from '/@/components/FileSystem/Setup' -import { setupSidebar } from '/@/components/Sidebar/setup' -import { TaskManager } from '/@/components/TaskManager/TaskManager' -import { setupDefaultMenus } from '/@/components/Toolbar/setupDefaults' -import { PackTypeLibrary } from '/@/components/Data/PackType' -import { Windows } from '/@/components/Windows/Windows' -import { SettingsWindow } from '/@/components/Windows/Settings/SettingsWindow' -import { settingsState } from '/@/components/Windows/Settings/SettingsState' -import { DataLoader } from './components/Data/DataLoader' -import { KeyBindingManager } from '/@/components/Actions/KeyBindingManager' -import { ActionManager } from '/@/components/Actions/ActionManager' -import { Toolbar } from '/@/components/Toolbar/Toolbar' -import { WindowResize } from '/@/components/Common/WindowResize' -import { InstallApp } from '/@/components/App/Install' -import { LanguageManager } from '/@/components/Languages/LanguageManager' -import { ProjectManager } from '/@/components/Projects/ProjectManager' -import { ContextMenu } from '/@/components/ContextMenu/ContextMenu' -import { get, set } from 'idb-keyval' -import { GlobalExtensionLoader } from '/@/components/Extensions/GlobalExtensionLoader' -import { FileDropper } from '/@/components/FileDropper/FileDropper' -import { FileImportManager } from '/@/components/ImportFile/Manager' -import { ComMojang } from './components/OutputFolders/ComMojang/ComMojang' -import { isUsingFileSystemPolyfill } from '/@/components/FileSystem/Polyfill' -import { markRaw } from 'vue' -import { ConfiguredJsonLanguage } from '/@/components/Languages/Json/Main' -import { WindowState } from '/@/components/Windows/WindowState' -import { Mobile } from '/@/components/App/Mobile' -import { PackExplorer } from '/@/components/PackExplorer/PackExplorer' -import { PersistentNotification } from '/@/components/Notifications/PersistentNotification' -import { version as appVersion } from '/@/utils/app/version' -import { platform } from '/@/utils/os' -import { AnyDirectoryHandle } from '/@/components/FileSystem/Types' -import { getStorageDirectory } from '/@/utils/getStorageDirectory' -import { FolderImportManager } from '/@/components/ImportFolder/Manager' -import { StartParamManager } from '/@/components/StartParams/Manager' -import { ViewFolders } from '/@/components/ViewFolders/ViewFolders' -import { SidebarManager } from '/@/components/Sidebar/Manager' -import { ViewComMojangProject } from '/@/components/OutputFolders/ComMojang/Sidebar/ViewProject' -import { InformationWindow } from '/@/components/Windows/Common/Information/InformationWindow' -import { BottomPanel } from '/@/components/BottomPanel/BottomPanel' -import { SolidWindowManager } from './components/Solid/Window/Manager' -import { setupActions } from './components/Actions/Actions' +import { createFileSystem } from './utils/fileSystem/FileSystem' +import { PWAFileSystem } from './utils/fileSystem/PWAFileSystem' if (import.meta.env.VITE_IS_TAURI_APP) { // Import Tauri updater for native builds @@ -59,10 +16,6 @@ if (import.meta.env.VITE_IS_TAURI_APP) { } export class App { - public static readonly windowState = new WindowState() - public static readonly installApp = new InstallApp() - public static fileSystemSetup = new FileSystemSetup() - public static toolbar = new Toolbar() public static readonly eventSystem = new EventSystem([ 'projectChanged', 'currentTabSwitched', @@ -79,332 +32,13 @@ export class App { 'modifiedProject', ]) public static readonly ready = new Signal() - protected static _instance: Readonly + public static instance: Readonly - public readonly viewFolders = new ViewFolders() - public readonly viewComMojangProject = new ViewComMojangProject() - public readonly packExplorer = new PackExplorer() - public readonly keyBindingManager = new KeyBindingManager() - public readonly actionManager = new ActionManager(this.keyBindingManager) - public readonly themeManager: ThemeManager - public readonly taskManager = new TaskManager() - public readonly dataLoader = markRaw(new DataLoader(true)) - public readonly fileSystem = new FileSystem() - public readonly projectManager = new ProjectManager(this) - public readonly extensionLoader = new GlobalExtensionLoader(this) - public readonly windowResize = new WindowResize() - public readonly contextMenu = markRaw(new ContextMenu()) - public readonly fileDropper = new FileDropper(this) - public readonly fileImportManager = new FileImportManager(this.fileDropper) - public readonly folderImportManager = new FolderImportManager() - public readonly comMojang = new ComMojang(this) - public readonly configuredJsonLanguage = markRaw( - new ConfiguredJsonLanguage() - ) - public static readonly fileType = markRaw(new FileTypeLibrary()) - public static readonly packType = markRaw(new PackTypeLibrary()) - public static readonly sidebar = new SidebarManager() - public static readonly bottomPanel = markRaw(new BottomPanel()) - public static readonly solidWindows = markRaw(new SolidWindowManager()) - - public readonly mobile: Mobile - - public readonly languageManager = markRaw(new LanguageManager()) - // App start params - public readonly startParams = new StartParamManager() - - protected _windows: Windows - get windows() { - return this._windows - } - - get tabSystem() { - return this.projectManager.currentProject?.tabSystem - } - - get selectedProject() { - return this.projectManager.selectedProject - } - - get isNoProjectSelected() { - return ( - this.projectManager.currentProject === null || - this.projectManager.currentProject.isVirtualProject - ) - } - - get hasNoProjects() { - return ( - this.isNoProjectSelected && this.projectManager.totalProjects <= 1 - ) - } - get project() { - if (!this.projectManager.currentProject) - throw new Error( - `Trying to access project before it is defined. Make sure to await app.projectManager.projectReady.fired` - ) - return this.projectManager.currentProject - } - get projects() { - return Object.values(this.projectManager.state).filter( - (project) => !project.isVirtualProject - ) - } - get projectConfig() { - try { - return this.project.config - } catch { - throw new Error( - `Trying to access projectConfig before project is defined. Make sure to await app.projectManager.projectReady.fired` - ) - } - } - - static get instance() { - return this._instance - } - static getApp() { - return new Promise((resolve) => - App.ready.once((app) => resolve(app)) - ) - } - - constructor(appComponent: Vue) { - if (import.meta.env.PROD) this.dataLoader.loadData() - this.themeManager = new ThemeManager(appComponent.$vuetify) - this._windows = new Windows(this) - - this.mobile = new Mobile(appComponent.$vuetify) - - // Prompt the user whether they really want to close bridge. when unsaved tabs are open - const saveWarning = - 'Are you sure that you want to close bridge.? Unsaved progress will be lost.' - // Only prompt in prod mode so we can use HMR in dev mode - if (import.meta.env.PROD) { - window.addEventListener('beforeunload', (event) => { - if (this.shouldWarnBeforeClose) { - event.preventDefault() - event.returnValue = saveWarning - return saveWarning - } - }) - } - } - - get shouldWarnBeforeClose() { - if ( - !import.meta.env.VITE_IS_TAURI_APP && - isUsingFileSystemPolyfill.value - ) - return true - - return ( - this.tabSystem?.hasUnsavedTabs || this.taskManager.hasRunningTasks - ) - } - - static async openUrl(url: string, id?: string, openInBrowser = false) { - if (import.meta.env.VITE_IS_TAURI_APP) { - const { open } = await import('@tauri-apps/api/shell') - - return open(url) - } - - if (settingsState?.general?.openLinksInBrowser || openInBrowser) - return window.open(url, '_blank') - return window.open(url, id, 'toolbar=no,menubar=no,status=no') - } - - /** - * Starts the app - */ static async main(appComponent: Vue) { console.time('[APP] Ready') - // this._instance = markRaw(new App(appComponent)) - - // await this.instance.beforeStartUp() - - // this.instance.fileSystem.setup(await getStorageDirectory()) - - // if (import.meta.env.VITE_IS_TAURI_APP) { - // // TauriFs env -> bridge. folder is the same as getStorageDirectory() - // await this.instance.bridgeFolderSetup.dispatch() - // // Setup com.mojang folder - // await this.instance.comMojang.setupComMojang() - // // Load projects - // this.instance.projectManager.loadProjects(true).then(() => { - // this.instance.themeManager.updateTheme() - // }) - // } - - // // Show changelog after an update - // if (await get('firstStartAfterUpdate')) { - // await set('firstStartAfterUpdate', false) - // this.instance.windows.changelogWindow.open() - // } - - // // Load settings - // const settingsLoaded = SettingsWindow.loadSettings(this.instance) - // await settingsLoaded - - // // Force data download - // if (import.meta.env.DEV) - // this.instance.dataLoader.loadData( - // settingsState?.developers?.forceDataDownload ?? false - // ) - - // settingsLoaded.then(async () => { - // await this.instance.dataLoader.fired - // this.instance.themeManager.loadDefaultThemes(this.instance) - // }) - - // await this.instance.startUp() - - // this.ready.dispatch(this.instance) - // await this.instance.projectManager.selectLastProject() + this.instance = new App() console.timeEnd('[APP] Ready') } - - /** - * Everything that doesn't need access to the fileSystem should be there immediately - */ - async beforeStartUp() { - console.log( - `--- Running bridge. ${appVersion} on a "${platform()}" machine ---` - ) - console.time('[APP] beforeStartUp()') - // @ts-expect-error - if (navigator.clearAppBadge) - // @ts-expect-error - navigator.clearAppBadge() - - setupSidebar() - setupDefaultMenus(this) - setupActions(this) - - if (import.meta.env.PROD) { - const socialsMsg = new PersistentNotification({ - id: 'bridge-social-links', - icon: 'mdi-link-variant', - message: 'sidebar.notifications.socials.message', - color: '#1DA1F2', - textColor: 'white', - onClick: () => { - this.windows.socialsWindow.open() - socialsMsg.dispose() - }, - }) - - const gettingStarted = new PersistentNotification({ - id: 'bridge-getting-started', - icon: 'mdi-help-circle-outline', - message: 'sidebar.notifications.gettingStarted.message', - onClick: () => { - App.openUrl( - 'https://bridge-core.github.io/editor-docs/getting-started/' - ) - gettingStarted.dispose() - }, - }) - } - - // Warn about saving projects - if ( - isUsingFileSystemPolyfill.value && - !import.meta.env.VITE_IS_TAURI_APP - ) { - const saveWarning = new PersistentNotification({ - id: 'bridge-save-warning', - icon: 'mdi-alert-circle-outline', - message: 'general.fileSystemPolyfill.name', - color: 'warning', - textColor: 'white', - onClick: () => { - new InformationWindow({ - title: 'general.fileSystemPolyfill.name', - description: 'general.fileSystemPolyfill.description', - }) - saveWarning.dispose() - }, - }) - } - - console.timeEnd('[APP] beforeStartUp()') - } - - /** - * Setup systems that need to access the fileSystem - */ - async startUp() { - console.time('[APP] startUp()') - - await Promise.all([ - // Create default folders - this.fileSystem.mkdir('projects'), - this.fileSystem.mkdir('extensions'), - this.fileSystem.mkdir('data'), - - // Setup data helpers - App.fileType.setup(this.dataLoader), - App.packType.setup(this.dataLoader), - ]) - - // Ensure that a project is selected - this.projectManager.projectReady.fired.then(async () => { - // Then load global extensions - this.extensionLoader.loadExtensions() - }) - - console.timeEnd('[APP] startUp()') - } - - public readonly bridgeFolderSetup = new Signal() - async setupBridgeFolder(forceReselect = false) { - if (!forceReselect && this.bridgeFolderSetup.hasFired) return true - - let fileHandle = await get( - 'bridgeBaseDir' - ) - - if (fileHandle && !forceReselect) { - const permissionState = await fileHandle.requestPermission({ - mode: 'readwrite', - }) - if (permissionState !== 'granted') return false - } else { - try { - fileHandle = await window.showDirectoryPicker({ - mode: 'readwrite', - }) - } catch { - return false - } - - await set('bridgeBaseDir', fileHandle) - } - - this.fileSystem.setup(fileHandle) - - // Migrate old settings over to ~local/data/settings.json - if (await this.fileSystem.fileExists('data/settings.json')) { - await this.fileSystem.copyFile( - 'data/settings.json', - '~local/data/settings.json' - ) - await this.fileSystem.unlink('data/settings.json') - await SettingsWindow.loadSettings(this).then(async () => { - this.themeManager.loadDefaultThemes(this) - }) - } - - this.bridgeFolderSetup.dispatch() - await this.projectManager.loadProjects(true) - - await this.extensionLoader.loadExtensions() - await this.themeManager.updateTheme() - - return true - } } diff --git a/src/App.vue b/src/App.vue index 6482be2f4..fae9f24de 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,240 +4,12 @@ :style="{ fontFamily }" @contextmenu.native="/*$event.preventDefault()*/" > - - - - - - - - -
- - - - mdi-table-column - - - - - - - - - -
- - - - - - - -
- - - -
-
-
-
- - - - - - diff --git a/src/utils/fileSystem/BaseFileSystem.ts b/src/utils/fileSystem/BaseFileSystem.ts new file mode 100644 index 000000000..616539cf2 --- /dev/null +++ b/src/utils/fileSystem/BaseFileSystem.ts @@ -0,0 +1,5 @@ +/* FileSystems operate withing a base directory. All paths are then relative to this base directory. */ + +export abstract class BaseFileSystem { + public async writeFile(path: string, content: FileSystemWriteChunkType) {} +} diff --git a/src/utils/fileSystem/FileSystem.ts b/src/utils/fileSystem/FileSystem.ts new file mode 100644 index 000000000..664187c73 --- /dev/null +++ b/src/utils/fileSystem/FileSystem.ts @@ -0,0 +1,42 @@ +import { LocalFileSystem } from './LocalFileSystem' +import { PWAFileSystem } from './PWAFileSystem' +import { TauriFileSystem } from './TauriFileSystem' + +export async function createFileSystem() { + if (import.meta.env.VITE_IS_TAURI_APP) return new TauriFileSystem() + + if (supportsFileHandles()) return new PWAFileSystem() + + return new LocalFileSystem() +} + +function supportsFileHandles() { + return ( + !fileHandlesUnsupportedBrowser() && + typeof window.showDirectoryPicker === 'function' + ) +} + +function fileHandlesUnsupportedBrowser() { + const unsupportedChromeVersions = ['93', '94'] + + // @ts-ignore: TypeScript doesn't know about userAgentData yet + const userAgentData: any = navigator.userAgentData + if (!userAgentData) return true + + const chromeBrand = userAgentData.brands.find( + ({ brand }: any) => brand === 'Google Chrome' + ) + const edgeBrand = userAgentData.brands.find( + ({ brand }: any) => brand === 'Microsoft Edge' + ) + const operaBrand = userAgentData.brands.find( + ({ brand }: any) => brand === 'Opera GX' || brand === 'Opera' + ) + if (chromeBrand) + return unsupportedChromeVersions.includes(chromeBrand.version) + + if (edgeBrand || operaBrand) return false + + return true +} diff --git a/src/utils/fileSystem/LocalFileSystem.ts b/src/utils/fileSystem/LocalFileSystem.ts new file mode 100644 index 000000000..13ef1c572 --- /dev/null +++ b/src/utils/fileSystem/LocalFileSystem.ts @@ -0,0 +1,3 @@ +import { BaseFileSystem } from './BaseFileSystem' + +export class LocalFileSystem extends BaseFileSystem {} diff --git a/src/utils/fileSystem/PWAFileSystem.ts b/src/utils/fileSystem/PWAFileSystem.ts new file mode 100644 index 000000000..2d39d16f1 --- /dev/null +++ b/src/utils/fileSystem/PWAFileSystem.ts @@ -0,0 +1,20 @@ +import { BaseFileSystem } from './BaseFileSystem' + +export class PWAFileSystem extends BaseFileSystem { + public baseDirectory: FileSystemDirectoryHandle | null = null + + public async writeFile(path: string, content: FileSystemWriteChunkType) { + if (this.baseDirectory === null) return + + const handle = await this.baseDirectory.getFileHandle(path, { + create: true, + }) + + const writable: FileSystemWritableFileStream = + await handle.createWritable() + + await writable.write(content) + + await writable.close() + } +} diff --git a/src/utils/fileSystem/TauriFileSystem.ts b/src/utils/fileSystem/TauriFileSystem.ts new file mode 100644 index 000000000..ba903a181 --- /dev/null +++ b/src/utils/fileSystem/TauriFileSystem.ts @@ -0,0 +1,3 @@ +import { BaseFileSystem } from './BaseFileSystem' + +export class TauriFileSystem extends BaseFileSystem {} diff --git a/src/utils/filesystem/base/file.ts b/src/utils/filesystem/base/file.ts deleted file mode 100644 index ea457e4fc..000000000 --- a/src/utils/filesystem/base/file.ts +++ /dev/null @@ -1 +0,0 @@ -export abstract class BaseFile {} diff --git a/src/utils/filesystem/pwa/file.ts b/src/utils/filesystem/pwa/file.ts deleted file mode 100644 index 47180d6eb..000000000 --- a/src/utils/filesystem/pwa/file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFile } from '../base/file' - -export class PWAFile extends BaseFile {} diff --git a/src/utils/filesystem/tauri/file.ts b/src/utils/filesystem/tauri/file.ts deleted file mode 100644 index e910d2413..000000000 --- a/src/utils/filesystem/tauri/file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFile } from '../base/file' - -export class TauriFile extends BaseFile {} From 82ee0b58fc1c89c40f3ce825c8bbe9db061b51fe Mon Sep 17 00:00:00 2001 From: Outer Cloud Studio Date: Sun, 12 Nov 2023 23:02:43 -0600 Subject: [PATCH 003/634] Revert "work on new fs" This reverts commit d12ec42d774f7b611cbb817918898c137856770d. --- src/App.ts | 374 +++++++++++++++++++++++- src/App.vue | 228 +++++++++++++++ src/utils/fileSystem/BaseFileSystem.ts | 5 - src/utils/fileSystem/FileSystem.ts | 42 --- src/utils/fileSystem/LocalFileSystem.ts | 3 - src/utils/fileSystem/PWAFileSystem.ts | 20 -- src/utils/fileSystem/TauriFileSystem.ts | 3 - src/utils/filesystem/base/file.ts | 1 + src/utils/filesystem/pwa/file.ts | 3 + src/utils/filesystem/tauri/file.ts | 3 + 10 files changed, 605 insertions(+), 77 deletions(-) delete mode 100644 src/utils/fileSystem/BaseFileSystem.ts delete mode 100644 src/utils/fileSystem/FileSystem.ts delete mode 100644 src/utils/fileSystem/LocalFileSystem.ts delete mode 100644 src/utils/fileSystem/PWAFileSystem.ts delete mode 100644 src/utils/fileSystem/TauriFileSystem.ts create mode 100644 src/utils/filesystem/base/file.ts create mode 100644 src/utils/filesystem/pwa/file.ts create mode 100644 src/utils/filesystem/tauri/file.ts diff --git a/src/App.ts b/src/App.ts index 4cc66528c..45b0377f7 100644 --- a/src/App.ts +++ b/src/App.ts @@ -4,8 +4,51 @@ import '/@/components/Languages/LanguageManager' import Vue from 'vue' import { EventSystem } from '/@/components/Common/Event/EventSystem' import { Signal } from '/@/components/Common/Event/Signal' -import { createFileSystem } from './utils/fileSystem/FileSystem' -import { PWAFileSystem } from './utils/fileSystem/PWAFileSystem' +import { FileTypeLibrary } from '/@/components/Data/FileType' +import { ThemeManager } from '/@/components/Extensions/Themes/ThemeManager' +import { FileSystem } from '/@/components/FileSystem/FileSystem' +import { FileSystemSetup } from '/@/components/FileSystem/Setup' +import { setupSidebar } from '/@/components/Sidebar/setup' +import { TaskManager } from '/@/components/TaskManager/TaskManager' +import { setupDefaultMenus } from '/@/components/Toolbar/setupDefaults' +import { PackTypeLibrary } from '/@/components/Data/PackType' +import { Windows } from '/@/components/Windows/Windows' +import { SettingsWindow } from '/@/components/Windows/Settings/SettingsWindow' +import { settingsState } from '/@/components/Windows/Settings/SettingsState' +import { DataLoader } from './components/Data/DataLoader' +import { KeyBindingManager } from '/@/components/Actions/KeyBindingManager' +import { ActionManager } from '/@/components/Actions/ActionManager' +import { Toolbar } from '/@/components/Toolbar/Toolbar' +import { WindowResize } from '/@/components/Common/WindowResize' +import { InstallApp } from '/@/components/App/Install' +import { LanguageManager } from '/@/components/Languages/LanguageManager' +import { ProjectManager } from '/@/components/Projects/ProjectManager' +import { ContextMenu } from '/@/components/ContextMenu/ContextMenu' +import { get, set } from 'idb-keyval' +import { GlobalExtensionLoader } from '/@/components/Extensions/GlobalExtensionLoader' +import { FileDropper } from '/@/components/FileDropper/FileDropper' +import { FileImportManager } from '/@/components/ImportFile/Manager' +import { ComMojang } from './components/OutputFolders/ComMojang/ComMojang' +import { isUsingFileSystemPolyfill } from '/@/components/FileSystem/Polyfill' +import { markRaw } from 'vue' +import { ConfiguredJsonLanguage } from '/@/components/Languages/Json/Main' +import { WindowState } from '/@/components/Windows/WindowState' +import { Mobile } from '/@/components/App/Mobile' +import { PackExplorer } from '/@/components/PackExplorer/PackExplorer' +import { PersistentNotification } from '/@/components/Notifications/PersistentNotification' +import { version as appVersion } from '/@/utils/app/version' +import { platform } from '/@/utils/os' +import { AnyDirectoryHandle } from '/@/components/FileSystem/Types' +import { getStorageDirectory } from '/@/utils/getStorageDirectory' +import { FolderImportManager } from '/@/components/ImportFolder/Manager' +import { StartParamManager } from '/@/components/StartParams/Manager' +import { ViewFolders } from '/@/components/ViewFolders/ViewFolders' +import { SidebarManager } from '/@/components/Sidebar/Manager' +import { ViewComMojangProject } from '/@/components/OutputFolders/ComMojang/Sidebar/ViewProject' +import { InformationWindow } from '/@/components/Windows/Common/Information/InformationWindow' +import { BottomPanel } from '/@/components/BottomPanel/BottomPanel' +import { SolidWindowManager } from './components/Solid/Window/Manager' +import { setupActions } from './components/Actions/Actions' if (import.meta.env.VITE_IS_TAURI_APP) { // Import Tauri updater for native builds @@ -16,6 +59,10 @@ if (import.meta.env.VITE_IS_TAURI_APP) { } export class App { + public static readonly windowState = new WindowState() + public static readonly installApp = new InstallApp() + public static fileSystemSetup = new FileSystemSetup() + public static toolbar = new Toolbar() public static readonly eventSystem = new EventSystem([ 'projectChanged', 'currentTabSwitched', @@ -32,13 +79,332 @@ export class App { 'modifiedProject', ]) public static readonly ready = new Signal() - public static instance: Readonly + protected static _instance: Readonly + public readonly viewFolders = new ViewFolders() + public readonly viewComMojangProject = new ViewComMojangProject() + public readonly packExplorer = new PackExplorer() + public readonly keyBindingManager = new KeyBindingManager() + public readonly actionManager = new ActionManager(this.keyBindingManager) + public readonly themeManager: ThemeManager + public readonly taskManager = new TaskManager() + public readonly dataLoader = markRaw(new DataLoader(true)) + public readonly fileSystem = new FileSystem() + public readonly projectManager = new ProjectManager(this) + public readonly extensionLoader = new GlobalExtensionLoader(this) + public readonly windowResize = new WindowResize() + public readonly contextMenu = markRaw(new ContextMenu()) + public readonly fileDropper = new FileDropper(this) + public readonly fileImportManager = new FileImportManager(this.fileDropper) + public readonly folderImportManager = new FolderImportManager() + public readonly comMojang = new ComMojang(this) + public readonly configuredJsonLanguage = markRaw( + new ConfiguredJsonLanguage() + ) + public static readonly fileType = markRaw(new FileTypeLibrary()) + public static readonly packType = markRaw(new PackTypeLibrary()) + public static readonly sidebar = new SidebarManager() + public static readonly bottomPanel = markRaw(new BottomPanel()) + public static readonly solidWindows = markRaw(new SolidWindowManager()) + + public readonly mobile: Mobile + + public readonly languageManager = markRaw(new LanguageManager()) + // App start params + public readonly startParams = new StartParamManager() + + protected _windows: Windows + get windows() { + return this._windows + } + + get tabSystem() { + return this.projectManager.currentProject?.tabSystem + } + + get selectedProject() { + return this.projectManager.selectedProject + } + + get isNoProjectSelected() { + return ( + this.projectManager.currentProject === null || + this.projectManager.currentProject.isVirtualProject + ) + } + + get hasNoProjects() { + return ( + this.isNoProjectSelected && this.projectManager.totalProjects <= 1 + ) + } + get project() { + if (!this.projectManager.currentProject) + throw new Error( + `Trying to access project before it is defined. Make sure to await app.projectManager.projectReady.fired` + ) + return this.projectManager.currentProject + } + get projects() { + return Object.values(this.projectManager.state).filter( + (project) => !project.isVirtualProject + ) + } + get projectConfig() { + try { + return this.project.config + } catch { + throw new Error( + `Trying to access projectConfig before project is defined. Make sure to await app.projectManager.projectReady.fired` + ) + } + } + + static get instance() { + return this._instance + } + static getApp() { + return new Promise((resolve) => + App.ready.once((app) => resolve(app)) + ) + } + + constructor(appComponent: Vue) { + if (import.meta.env.PROD) this.dataLoader.loadData() + this.themeManager = new ThemeManager(appComponent.$vuetify) + this._windows = new Windows(this) + + this.mobile = new Mobile(appComponent.$vuetify) + + // Prompt the user whether they really want to close bridge. when unsaved tabs are open + const saveWarning = + 'Are you sure that you want to close bridge.? Unsaved progress will be lost.' + // Only prompt in prod mode so we can use HMR in dev mode + if (import.meta.env.PROD) { + window.addEventListener('beforeunload', (event) => { + if (this.shouldWarnBeforeClose) { + event.preventDefault() + event.returnValue = saveWarning + return saveWarning + } + }) + } + } + + get shouldWarnBeforeClose() { + if ( + !import.meta.env.VITE_IS_TAURI_APP && + isUsingFileSystemPolyfill.value + ) + return true + + return ( + this.tabSystem?.hasUnsavedTabs || this.taskManager.hasRunningTasks + ) + } + + static async openUrl(url: string, id?: string, openInBrowser = false) { + if (import.meta.env.VITE_IS_TAURI_APP) { + const { open } = await import('@tauri-apps/api/shell') + + return open(url) + } + + if (settingsState?.general?.openLinksInBrowser || openInBrowser) + return window.open(url, '_blank') + return window.open(url, id, 'toolbar=no,menubar=no,status=no') + } + + /** + * Starts the app + */ static async main(appComponent: Vue) { console.time('[APP] Ready') - this.instance = new App() + // this._instance = markRaw(new App(appComponent)) + + // await this.instance.beforeStartUp() + + // this.instance.fileSystem.setup(await getStorageDirectory()) + + // if (import.meta.env.VITE_IS_TAURI_APP) { + // // TauriFs env -> bridge. folder is the same as getStorageDirectory() + // await this.instance.bridgeFolderSetup.dispatch() + // // Setup com.mojang folder + // await this.instance.comMojang.setupComMojang() + // // Load projects + // this.instance.projectManager.loadProjects(true).then(() => { + // this.instance.themeManager.updateTheme() + // }) + // } + + // // Show changelog after an update + // if (await get('firstStartAfterUpdate')) { + // await set('firstStartAfterUpdate', false) + // this.instance.windows.changelogWindow.open() + // } + + // // Load settings + // const settingsLoaded = SettingsWindow.loadSettings(this.instance) + // await settingsLoaded + + // // Force data download + // if (import.meta.env.DEV) + // this.instance.dataLoader.loadData( + // settingsState?.developers?.forceDataDownload ?? false + // ) + + // settingsLoaded.then(async () => { + // await this.instance.dataLoader.fired + // this.instance.themeManager.loadDefaultThemes(this.instance) + // }) + + // await this.instance.startUp() + + // this.ready.dispatch(this.instance) + // await this.instance.projectManager.selectLastProject() console.timeEnd('[APP] Ready') } + + /** + * Everything that doesn't need access to the fileSystem should be there immediately + */ + async beforeStartUp() { + console.log( + `--- Running bridge. ${appVersion} on a "${platform()}" machine ---` + ) + console.time('[APP] beforeStartUp()') + // @ts-expect-error + if (navigator.clearAppBadge) + // @ts-expect-error + navigator.clearAppBadge() + + setupSidebar() + setupDefaultMenus(this) + setupActions(this) + + if (import.meta.env.PROD) { + const socialsMsg = new PersistentNotification({ + id: 'bridge-social-links', + icon: 'mdi-link-variant', + message: 'sidebar.notifications.socials.message', + color: '#1DA1F2', + textColor: 'white', + onClick: () => { + this.windows.socialsWindow.open() + socialsMsg.dispose() + }, + }) + + const gettingStarted = new PersistentNotification({ + id: 'bridge-getting-started', + icon: 'mdi-help-circle-outline', + message: 'sidebar.notifications.gettingStarted.message', + onClick: () => { + App.openUrl( + 'https://bridge-core.github.io/editor-docs/getting-started/' + ) + gettingStarted.dispose() + }, + }) + } + + // Warn about saving projects + if ( + isUsingFileSystemPolyfill.value && + !import.meta.env.VITE_IS_TAURI_APP + ) { + const saveWarning = new PersistentNotification({ + id: 'bridge-save-warning', + icon: 'mdi-alert-circle-outline', + message: 'general.fileSystemPolyfill.name', + color: 'warning', + textColor: 'white', + onClick: () => { + new InformationWindow({ + title: 'general.fileSystemPolyfill.name', + description: 'general.fileSystemPolyfill.description', + }) + saveWarning.dispose() + }, + }) + } + + console.timeEnd('[APP] beforeStartUp()') + } + + /** + * Setup systems that need to access the fileSystem + */ + async startUp() { + console.time('[APP] startUp()') + + await Promise.all([ + // Create default folders + this.fileSystem.mkdir('projects'), + this.fileSystem.mkdir('extensions'), + this.fileSystem.mkdir('data'), + + // Setup data helpers + App.fileType.setup(this.dataLoader), + App.packType.setup(this.dataLoader), + ]) + + // Ensure that a project is selected + this.projectManager.projectReady.fired.then(async () => { + // Then load global extensions + this.extensionLoader.loadExtensions() + }) + + console.timeEnd('[APP] startUp()') + } + + public readonly bridgeFolderSetup = new Signal() + async setupBridgeFolder(forceReselect = false) { + if (!forceReselect && this.bridgeFolderSetup.hasFired) return true + + let fileHandle = await get( + 'bridgeBaseDir' + ) + + if (fileHandle && !forceReselect) { + const permissionState = await fileHandle.requestPermission({ + mode: 'readwrite', + }) + if (permissionState !== 'granted') return false + } else { + try { + fileHandle = await window.showDirectoryPicker({ + mode: 'readwrite', + }) + } catch { + return false + } + + await set('bridgeBaseDir', fileHandle) + } + + this.fileSystem.setup(fileHandle) + + // Migrate old settings over to ~local/data/settings.json + if (await this.fileSystem.fileExists('data/settings.json')) { + await this.fileSystem.copyFile( + 'data/settings.json', + '~local/data/settings.json' + ) + await this.fileSystem.unlink('data/settings.json') + await SettingsWindow.loadSettings(this).then(async () => { + this.themeManager.loadDefaultThemes(this) + }) + } + + this.bridgeFolderSetup.dispatch() + await this.projectManager.loadProjects(true) + + await this.extensionLoader.loadExtensions() + await this.themeManager.updateTheme() + + return true + } } diff --git a/src/App.vue b/src/App.vue index fae9f24de..6482be2f4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,12 +4,240 @@ :style="{ fontFamily }" @contextmenu.native="/*$event.preventDefault()*/" > + + + + + + + + +
+ + + + mdi-table-column + + + + + + + + + +
+ + + + + + + +
+ + + +
+
+
+
+ + + + + + diff --git a/src/utils/fileSystem/BaseFileSystem.ts b/src/utils/fileSystem/BaseFileSystem.ts deleted file mode 100644 index 616539cf2..000000000 --- a/src/utils/fileSystem/BaseFileSystem.ts +++ /dev/null @@ -1,5 +0,0 @@ -/* FileSystems operate withing a base directory. All paths are then relative to this base directory. */ - -export abstract class BaseFileSystem { - public async writeFile(path: string, content: FileSystemWriteChunkType) {} -} diff --git a/src/utils/fileSystem/FileSystem.ts b/src/utils/fileSystem/FileSystem.ts deleted file mode 100644 index 664187c73..000000000 --- a/src/utils/fileSystem/FileSystem.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { LocalFileSystem } from './LocalFileSystem' -import { PWAFileSystem } from './PWAFileSystem' -import { TauriFileSystem } from './TauriFileSystem' - -export async function createFileSystem() { - if (import.meta.env.VITE_IS_TAURI_APP) return new TauriFileSystem() - - if (supportsFileHandles()) return new PWAFileSystem() - - return new LocalFileSystem() -} - -function supportsFileHandles() { - return ( - !fileHandlesUnsupportedBrowser() && - typeof window.showDirectoryPicker === 'function' - ) -} - -function fileHandlesUnsupportedBrowser() { - const unsupportedChromeVersions = ['93', '94'] - - // @ts-ignore: TypeScript doesn't know about userAgentData yet - const userAgentData: any = navigator.userAgentData - if (!userAgentData) return true - - const chromeBrand = userAgentData.brands.find( - ({ brand }: any) => brand === 'Google Chrome' - ) - const edgeBrand = userAgentData.brands.find( - ({ brand }: any) => brand === 'Microsoft Edge' - ) - const operaBrand = userAgentData.brands.find( - ({ brand }: any) => brand === 'Opera GX' || brand === 'Opera' - ) - if (chromeBrand) - return unsupportedChromeVersions.includes(chromeBrand.version) - - if (edgeBrand || operaBrand) return false - - return true -} diff --git a/src/utils/fileSystem/LocalFileSystem.ts b/src/utils/fileSystem/LocalFileSystem.ts deleted file mode 100644 index 13ef1c572..000000000 --- a/src/utils/fileSystem/LocalFileSystem.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFileSystem } from './BaseFileSystem' - -export class LocalFileSystem extends BaseFileSystem {} diff --git a/src/utils/fileSystem/PWAFileSystem.ts b/src/utils/fileSystem/PWAFileSystem.ts deleted file mode 100644 index 2d39d16f1..000000000 --- a/src/utils/fileSystem/PWAFileSystem.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BaseFileSystem } from './BaseFileSystem' - -export class PWAFileSystem extends BaseFileSystem { - public baseDirectory: FileSystemDirectoryHandle | null = null - - public async writeFile(path: string, content: FileSystemWriteChunkType) { - if (this.baseDirectory === null) return - - const handle = await this.baseDirectory.getFileHandle(path, { - create: true, - }) - - const writable: FileSystemWritableFileStream = - await handle.createWritable() - - await writable.write(content) - - await writable.close() - } -} diff --git a/src/utils/fileSystem/TauriFileSystem.ts b/src/utils/fileSystem/TauriFileSystem.ts deleted file mode 100644 index ba903a181..000000000 --- a/src/utils/fileSystem/TauriFileSystem.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFileSystem } from './BaseFileSystem' - -export class TauriFileSystem extends BaseFileSystem {} diff --git a/src/utils/filesystem/base/file.ts b/src/utils/filesystem/base/file.ts new file mode 100644 index 000000000..ea457e4fc --- /dev/null +++ b/src/utils/filesystem/base/file.ts @@ -0,0 +1 @@ +export abstract class BaseFile {} diff --git a/src/utils/filesystem/pwa/file.ts b/src/utils/filesystem/pwa/file.ts new file mode 100644 index 000000000..47180d6eb --- /dev/null +++ b/src/utils/filesystem/pwa/file.ts @@ -0,0 +1,3 @@ +import { BaseFile } from '../base/file' + +export class PWAFile extends BaseFile {} diff --git a/src/utils/filesystem/tauri/file.ts b/src/utils/filesystem/tauri/file.ts new file mode 100644 index 000000000..e910d2413 --- /dev/null +++ b/src/utils/filesystem/tauri/file.ts @@ -0,0 +1,3 @@ +import { BaseFile } from '../base/file' + +export class TauriFile extends BaseFile {} From c97eb5de5d43c900b664779455f6cba70767e938 Mon Sep 17 00:00:00 2001 From: Outer Cloud Studio Date: Sun, 12 Nov 2023 23:02:47 -0600 Subject: [PATCH 004/634] Revert "start new fs api" This reverts commit 274b36f8c255e613aa318f1e1037aa1ecbd631e3. --- src/App.ts | 84 +++++++++++++++--------------- src/utils/filesystem/base/file.ts | 1 - src/utils/filesystem/pwa/file.ts | 3 -- src/utils/filesystem/tauri/file.ts | 3 -- 4 files changed, 42 insertions(+), 49 deletions(-) delete mode 100644 src/utils/filesystem/base/file.ts delete mode 100644 src/utils/filesystem/pwa/file.ts delete mode 100644 src/utils/filesystem/tauri/file.ts diff --git a/src/App.ts b/src/App.ts index 45b0377f7..de174a13c 100644 --- a/src/App.ts +++ b/src/App.ts @@ -221,48 +221,48 @@ export class App { static async main(appComponent: Vue) { console.time('[APP] Ready') - // this._instance = markRaw(new App(appComponent)) - - // await this.instance.beforeStartUp() - - // this.instance.fileSystem.setup(await getStorageDirectory()) - - // if (import.meta.env.VITE_IS_TAURI_APP) { - // // TauriFs env -> bridge. folder is the same as getStorageDirectory() - // await this.instance.bridgeFolderSetup.dispatch() - // // Setup com.mojang folder - // await this.instance.comMojang.setupComMojang() - // // Load projects - // this.instance.projectManager.loadProjects(true).then(() => { - // this.instance.themeManager.updateTheme() - // }) - // } - - // // Show changelog after an update - // if (await get('firstStartAfterUpdate')) { - // await set('firstStartAfterUpdate', false) - // this.instance.windows.changelogWindow.open() - // } - - // // Load settings - // const settingsLoaded = SettingsWindow.loadSettings(this.instance) - // await settingsLoaded - - // // Force data download - // if (import.meta.env.DEV) - // this.instance.dataLoader.loadData( - // settingsState?.developers?.forceDataDownload ?? false - // ) - - // settingsLoaded.then(async () => { - // await this.instance.dataLoader.fired - // this.instance.themeManager.loadDefaultThemes(this.instance) - // }) - - // await this.instance.startUp() - - // this.ready.dispatch(this.instance) - // await this.instance.projectManager.selectLastProject() + this._instance = markRaw(new App(appComponent)) + + await this.instance.beforeStartUp() + + this.instance.fileSystem.setup(await getStorageDirectory()) + + if (import.meta.env.VITE_IS_TAURI_APP) { + // TauriFs env -> bridge. folder is the same as getStorageDirectory() + await this.instance.bridgeFolderSetup.dispatch() + // Setup com.mojang folder + await this.instance.comMojang.setupComMojang() + // Load projects + this.instance.projectManager.loadProjects(true).then(() => { + this.instance.themeManager.updateTheme() + }) + } + + // Show changelog after an update + if (await get('firstStartAfterUpdate')) { + await set('firstStartAfterUpdate', false) + this.instance.windows.changelogWindow.open() + } + + // Load settings + const settingsLoaded = SettingsWindow.loadSettings(this.instance) + await settingsLoaded + + // Force data download + if (import.meta.env.DEV) + this.instance.dataLoader.loadData( + settingsState?.developers?.forceDataDownload ?? false + ) + + settingsLoaded.then(async () => { + await this.instance.dataLoader.fired + this.instance.themeManager.loadDefaultThemes(this.instance) + }) + + await this.instance.startUp() + + this.ready.dispatch(this.instance) + await this.instance.projectManager.selectLastProject() console.timeEnd('[APP] Ready') } diff --git a/src/utils/filesystem/base/file.ts b/src/utils/filesystem/base/file.ts deleted file mode 100644 index ea457e4fc..000000000 --- a/src/utils/filesystem/base/file.ts +++ /dev/null @@ -1 +0,0 @@ -export abstract class BaseFile {} diff --git a/src/utils/filesystem/pwa/file.ts b/src/utils/filesystem/pwa/file.ts deleted file mode 100644 index 47180d6eb..000000000 --- a/src/utils/filesystem/pwa/file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFile } from '../base/file' - -export class PWAFile extends BaseFile {} diff --git a/src/utils/filesystem/tauri/file.ts b/src/utils/filesystem/tauri/file.ts deleted file mode 100644 index e910d2413..000000000 --- a/src/utils/filesystem/tauri/file.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { BaseFile } from '../base/file' - -export class TauriFile extends BaseFile {} From 26960be43e187dfd4ba231337b185e22b9c6a8d3 Mon Sep 17 00:00:00 2001 From: Outer Cloud Studio Date: Sun, 12 Nov 2023 23:33:06 -0600 Subject: [PATCH 005/634] launch vue 3 --- index.html | 1 + node_modules/vue-template-compiler/LICENSE | 21 - node_modules/vue-template-compiler/README.md | 162 - node_modules/vue-template-compiler/browser.js | 7118 ----------------- node_modules/vue-template-compiler/build.js | 6655 --------------- node_modules/vue-template-compiler/index.js | 18 - .../vue-template-compiler/package.json | 35 - .../vue-template-compiler/types/index.d.ts | 247 - package-lock.json | 5243 +++++++----- package.json | 11 +- src/App.ts | 405 +- src/App.vue | 356 +- src/main.ts | 54 +- tsconfig.json | 4 +- vite.config.ts | 7 +- 15 files changed, 3212 insertions(+), 17125 deletions(-) delete mode 100644 node_modules/vue-template-compiler/LICENSE delete mode 100644 node_modules/vue-template-compiler/README.md delete mode 100644 node_modules/vue-template-compiler/browser.js delete mode 100644 node_modules/vue-template-compiler/build.js delete mode 100644 node_modules/vue-template-compiler/index.js delete mode 100644 node_modules/vue-template-compiler/package.json delete mode 100644 node_modules/vue-template-compiler/types/index.d.ts diff --git a/index.html b/index.html index 35275fbc3..0aed78fc1 100644 --- a/index.html +++ b/index.html @@ -243,6 +243,7 @@ } self.setImmediate = setTimeout + diff --git a/node_modules/vue-template-compiler/LICENSE b/node_modules/vue-template-compiler/LICENSE deleted file mode 100644 index b65dd9e62..000000000 --- a/node_modules/vue-template-compiler/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-present, Yuxi (Evan) You - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/node_modules/vue-template-compiler/README.md b/node_modules/vue-template-compiler/README.md deleted file mode 100644 index fa0a64bb7..000000000 --- a/node_modules/vue-template-compiler/README.md +++ /dev/null @@ -1,162 +0,0 @@ -# vue-template-compiler - -> This package is auto-generated. For pull requests please see [src/platforms/web/entry-compiler.js](https://github.com/vuejs/vue/tree/dev/src/platforms/web/entry-compiler.js). - -This package can be used to pre-compile Vue 2.0 templates into render functions to avoid runtime-compilation overhead and CSP restrictions. In most cases you should be using it with [`vue-loader`](https://github.com/vuejs/vue-loader), you will only need it separately if you are writing build tools with very specific needs. - -## Installation - -``` bash -npm install vue-template-compiler -``` - -``` js -const compiler = require('vue-template-compiler') -``` - -## API - -### compiler.compile(template, [options]) - -Compiles a template string and returns compiled JavaScript code. The returned result is an object of the following format: - -``` js -{ - ast: ?ASTElement, // parsed template elements to AST - render: string, // main render function code - staticRenderFns: Array, // render code for static sub trees, if any - errors: Array // template syntax errors, if any -} -``` - -Note the returned function code uses `with` and thus cannot be used in strict mode code. - -#### Options - -- `outputSourceRange` *new in 2.6* - - Type: `boolean` - - Default: `false` - - Set this to true will cause the `errors` returned in the compiled result become objects in the form of `{ msg, start, end }`. The `start` and `end` properties are numbers that mark the code range of the error source in the template. This can be passed on to the `compiler.generateCodeFrame` API to generate a code frame for the error. - -- `whitespace` - - Type: `string` - - Valid values: `'preserve' | 'condense'` - - Default: `'preserve'` - - The default value `'preserve'` handles whitespaces as follows: - - - A whitespace-only text node between element tags is condensed into a single space. - - All other whitespaces are preserved as-is. - - If set to `'condense'`: - - - A whitespace-only text node between element tags is removed if it contains new lines. Otherwise, it is condensed into a single space. - - Consecutive whitespaces inside a non-whitespace-only text node are condensed into a single space. - - Using condense mode will result in smaller compiled code size and slightly improved performance. However, it will produce minor visual layout differences compared to plain HTML in certain cases. - - **This option does not affect the `
` tag.**
-
-  Example:
-
-  ``` html
-  
-  
- - foo - bar -
- - -
- foo - bar
- - -
foo bar
- ``` - -- `modules` - - It's possible to hook into the compilation process to support custom template features. **However, beware that by injecting custom compile-time modules, your templates will not work with other build tools built on standard built-in modules, e.g `vue-loader` and `vueify`.** - - An array of compiler modules. For details on compiler modules, refer to the `ModuleOptions` type in [flow declarations](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L47-L59) and the [built-in modules](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/modules). - -- `directives` - - An object where the key is the directive name and the value is a function that transforms an template AST node. For example: - - ``` js - compiler.compile('
', { - directives: { - test (node, directiveMeta) { - // transform node based on directiveMeta - } - } - }) - ``` - - By default, a compile-time directive will extract the directive and the directive will not be present at runtime. If you want the directive to also be handled by a runtime definition, return `true` in the transform function. - - Refer to the implementation of some [built-in compile-time directives](https://github.com/vuejs/vue/tree/dev/src/platforms/web/compiler/directives). - -- `preserveWhitespace` **Deprecated since 2.6** - - Type: `boolean` - - Default: `true` - - By default, the compiled render function preserves all whitespace characters between HTML tags. If set to `false`, whitespace between tags will be ignored. This can result in slightly better performance but may affect layout for inline elements. - ---- - -### compiler.compileToFunctions(template) - -Similar to `compiler.compile`, but directly returns instantiated functions: - -``` js -{ - render: Function, - staticRenderFns: Array -} -``` - -This is only useful at runtime with pre-configured builds, so it doesn't accept any compile-time options. In addition, this method uses `new Function()` so it is not CSP-compliant. - ---- - -### compiler.ssrCompile(template, [options]) - -> 2.4.0+ - -Same as `compiler.compile` but generates SSR-specific render function code by optimizing parts of the template into string concatenation in order to improve SSR performance. - -This is used by default in `vue-loader@>=12` and can be disabled using the [`optimizeSSR`](https://vue-loader.vuejs.org/en/options.html#optimizessr) option. - ---- - -### compiler.ssrCompileToFunctions(template) - -> 2.4.0+ - -Same as `compiler.compileToFunction` but generates SSR-specific render function code by optimizing parts of the template into string concatenation in order to improve SSR performance. - ---- - -### compiler.parseComponent(file, [options]) - -Parse a SFC (single-file component, or `*.vue` file) into a descriptor (refer to the `SFCDescriptor` type in [flow declarations](https://github.com/vuejs/vue/blob/dev/flow/compiler.js)). This is used in SFC build tools like `vue-loader` and `vueify`. - ---- - -### compiler.generateCodeFrame(template, start, end) - -Generate a code frame that highlights the part in `template` defined by `start` and `end`. Useful for error reporting in higher-level tooling. - -#### Options - -#### `pad` - -`pad` is useful when you are piping the extracted content into other pre-processors, as you will get correct line numbers or character indices if there are any syntax errors. - -- with `{ pad: "line" }`, the extracted content for each block will be prefixed with one newline for each line in the leading content from the original file to ensure that the line numbers align with the original file. -- with `{ pad: "space" }`, the extracted content for each block will be prefixed with one space for each character in the leading content from the original file to ensure that the character count remains the same as the original file. diff --git a/node_modules/vue-template-compiler/browser.js b/node_modules/vue-template-compiler/browser.js deleted file mode 100644 index 95bca1188..000000000 --- a/node_modules/vue-template-compiler/browser.js +++ /dev/null @@ -1,7118 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.VueTemplateCompiler = {})); -})(this, (function (exports) { 'use strict'; - - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - var splitRE$1 = /\r?\n/g; - var emptyRE = /^\s*$/; - var needFixRE = /^(\r?\n)*[\t\s]/; - - var deIndent = function deindent (str) { - if (!needFixRE.test(str)) { - return str - } - var lines = str.split(splitRE$1); - var min = Infinity; - var type, cur, c; - for (var i = 0; i < lines.length; i++) { - var line = lines[i]; - if (!emptyRE.test(line)) { - if (!type) { - c = line.charAt(0); - if (c === ' ' || c === '\t') { - type = c; - cur = count(line, type); - if (cur < min) { - min = cur; - } - } else { - return str - } - } else { - cur = count(line, type); - if (cur < min) { - min = cur; - } - } - } - } - return lines.map(function (line) { - return line.slice(min) - }).join('\n') - }; - - function count (line, type) { - var i = 0; - while (line.charAt(i) === type) { - i++; - } - return i - } - - var emptyObject = Object.freeze({}); - var isArray = Array.isArray; - // These helpers produce better VM code in JS engines due to their - // explicitness and function inlining. - function isUndef(v) { - return v === undefined || v === null; - } - function isDef(v) { - return v !== undefined && v !== null; - } - function isTrue(v) { - return v === true; - } - function isFalse(v) { - return v === false; - } - /** - * Check if value is primitive. - */ - function isPrimitive(value) { - return (typeof value === 'string' || - typeof value === 'number' || - // $flow-disable-line - typeof value === 'symbol' || - typeof value === 'boolean'); - } - function isFunction(value) { - return typeof value === 'function'; - } - /** - * Quick object check - this is primarily used to tell - * objects from primitive values when we know the value - * is a JSON-compliant type. - */ - function isObject(obj) { - return obj !== null && typeof obj === 'object'; - } - /** - * Get the raw type string of a value, e.g., [object Object]. - */ - var _toString = Object.prototype.toString; - function toRawType(value) { - return _toString.call(value).slice(8, -1); - } - /** - * Strict object type check. Only returns true - * for plain JavaScript objects. - */ - function isPlainObject(obj) { - return _toString.call(obj) === '[object Object]'; - } - /** - * Check if val is a valid array index. - */ - function isValidArrayIndex(val) { - var n = parseFloat(String(val)); - return n >= 0 && Math.floor(n) === n && isFinite(val); - } - function isPromise(val) { - return (isDef(val) && - typeof val.then === 'function' && - typeof val.catch === 'function'); - } - /** - * Convert a value to a string that is actually rendered. - */ - function toString(val) { - return val == null - ? '' - : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) - ? JSON.stringify(val, null, 2) - : String(val); - } - /** - * Convert an input value to a number for persistence. - * If the conversion fails, return original string. - */ - function toNumber(val) { - var n = parseFloat(val); - return isNaN(n) ? val : n; - } - /** - * Make a map and return a function for checking if a key - * is in that map. - */ - function makeMap(str, expectsLowerCase) { - var map = Object.create(null); - var list = str.split(','); - for (var i = 0; i < list.length; i++) { - map[list[i]] = true; - } - return expectsLowerCase ? function (val) { return map[val.toLowerCase()]; } : function (val) { return map[val]; }; - } - /** - * Check if a tag is a built-in tag. - */ - var isBuiltInTag = makeMap('slot,component', true); - /** - * Check if an attribute is a reserved attribute. - */ - var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); - /** - * Remove an item from an array. - */ - function remove$1(arr, item) { - if (arr.length) { - var index = arr.indexOf(item); - if (index > -1) { - return arr.splice(index, 1); - } - } - } - /** - * Check whether an object has the property. - */ - var hasOwnProperty = Object.prototype.hasOwnProperty; - function hasOwn(obj, key) { - return hasOwnProperty.call(obj, key); - } - /** - * Create a cached version of a pure function. - */ - function cached(fn) { - var cache = Object.create(null); - return function cachedFn(str) { - var hit = cache[str]; - return hit || (cache[str] = fn(str)); - }; - } - /** - * Camelize a hyphen-delimited string. - */ - var camelizeRE = /-(\w)/g; - var camelize = cached(function (str) { - return str.replace(camelizeRE, function (_, c) { return (c ? c.toUpperCase() : ''); }); - }); - /** - * Capitalize a string. - */ - var capitalize = cached(function (str) { - return str.charAt(0).toUpperCase() + str.slice(1); - }); - /** - * Hyphenate a camelCase string. - */ - var hyphenateRE = /\B([A-Z])/g; - var hyphenate = cached(function (str) { - return str.replace(hyphenateRE, '-$1').toLowerCase(); - }); - /** - * Mix properties into target object. - */ - function extend(to, _from) { - for (var key in _from) { - to[key] = _from[key]; - } - return to; - } - /** - * Merge an Array of Objects into a single Object. - */ - function toObject(arr) { - var res = {}; - for (var i = 0; i < arr.length; i++) { - if (arr[i]) { - extend(res, arr[i]); - } - } - return res; - } - /* eslint-disable no-unused-vars */ - /** - * Perform no operation. - * Stubbing args to make Flow happy without leaving useless transpiled code - * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). - */ - function noop(a, b, c) { } - /** - * Always return false. - */ - var no = function (a, b, c) { return false; }; - /* eslint-enable no-unused-vars */ - /** - * Return the same value. - */ - var identity = function (_) { return _; }; - /** - * Generate a string containing static keys from compiler modules. - */ - function genStaticKeys$1(modules) { - return modules - .reduce(function (keys, m) { - return keys.concat(m.staticKeys || []); - }, []) - .join(','); - } - /** - * Check if two values are loosely equal - that is, - * if they are plain objects, do they have the same shape? - */ - function looseEqual(a, b) { - if (a === b) - return true; - var isObjectA = isObject(a); - var isObjectB = isObject(b); - if (isObjectA && isObjectB) { - try { - var isArrayA = Array.isArray(a); - var isArrayB = Array.isArray(b); - if (isArrayA && isArrayB) { - return (a.length === b.length && - a.every(function (e, i) { - return looseEqual(e, b[i]); - })); - } - else if (a instanceof Date && b instanceof Date) { - return a.getTime() === b.getTime(); - } - else if (!isArrayA && !isArrayB) { - var keysA = Object.keys(a); - var keysB = Object.keys(b); - return (keysA.length === keysB.length && - keysA.every(function (key) { - return looseEqual(a[key], b[key]); - })); - } - else { - /* istanbul ignore next */ - return false; - } - } - catch (e) { - /* istanbul ignore next */ - return false; - } - } - else if (!isObjectA && !isObjectB) { - return String(a) === String(b); - } - else { - return false; - } - } - /** - * Return the first index at which a loosely equal value can be - * found in the array (if value is a plain object, the array must - * contain an object of the same shape), or -1 if it is not present. - */ - function looseIndexOf(arr, val) { - for (var i = 0; i < arr.length; i++) { - if (looseEqual(arr[i], val)) - return i; - } - return -1; - } - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill - function hasChanged(x, y) { - if (x === y) { - return x === 0 && 1 / x !== 1 / y; - } - else { - return x === x || y === y; - } - } - - var isUnaryTag = makeMap('area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' + - 'link,meta,param,source,track,wbr'); - // Elements that you can, intentionally, leave open - // (and which close themselves) - var canBeLeftOpenTag = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source'); - // HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3 - // Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content - var isNonPhrasingTag = makeMap('address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' + - 'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' + - 'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' + - 'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' + - 'title,tr,track'); - - /** - * unicode letters used for parsing html tags, component names and property paths. - * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname - * skipping \u10000-\uEFFFF due to it freezing up PhantomJS - */ - var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; - /** - * Define a property. - */ - function def(obj, key, val, enumerable) { - Object.defineProperty(obj, key, { - value: val, - enumerable: !!enumerable, - writable: true, - configurable: true - }); - } - - /** - * Not type-checking this file because it's mostly vendor code. - */ - // Regular Expressions for parsing tags and attributes - var attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; - var dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/; - var ncname = "[a-zA-Z_][\\-\\.0-9_a-zA-Z".concat(unicodeRegExp.source, "]*"); - var qnameCapture = "((?:".concat(ncname, "\\:)?").concat(ncname, ")"); - var startTagOpen = new RegExp("^<".concat(qnameCapture)); - var startTagClose = /^\s*(\/?)>/; - var endTag = new RegExp("^<\\/".concat(qnameCapture, "[^>]*>")); - var doctype = /^]+>/i; - // #7298: escape - to avoid being passed as HTML comment when inlined in page - var comment = /^', - '"': '"', - '&': '&', - ' ': '\n', - ' ': '\t', - ''': "'" - }; - var encodedAttr = /&(?:lt|gt|quot|amp|#39);/g; - var encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#39|#10|#9);/g; - // #5992 - var isIgnoreNewlineTag = makeMap('pre,textarea', true); - var shouldIgnoreFirstNewline = function (tag, html) { - return tag && isIgnoreNewlineTag(tag) && html[0] === '\n'; - }; - function decodeAttr(value, shouldDecodeNewlines) { - var re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr; - return value.replace(re, function (match) { return decodingMap[match]; }); - } - function parseHTML(html, options) { - var stack = []; - var expectHTML = options.expectHTML; - var isUnaryTag = options.isUnaryTag || no; - var canBeLeftOpenTag = options.canBeLeftOpenTag || no; - var index = 0; - var last, lastTag; - var _loop_1 = function () { - last = html; - // Make sure we're not in a plaintext content element like script/style - if (!lastTag || !isPlainTextElement(lastTag)) { - var textEnd = html.indexOf('<'); - if (textEnd === 0) { - // Comment: - if (comment.test(html)) { - var commentEnd = html.indexOf('-->'); - if (commentEnd >= 0) { - if (options.shouldKeepComment && options.comment) { - options.comment(html.substring(4, commentEnd), index, index + commentEnd + 3); - } - advance(commentEnd + 3); - return "continue"; - } - } - // http://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment - if (conditionalComment.test(html)) { - var conditionalEnd = html.indexOf(']>'); - if (conditionalEnd >= 0) { - advance(conditionalEnd + 2); - return "continue"; - } - } - // Doctype: - var doctypeMatch = html.match(doctype); - if (doctypeMatch) { - advance(doctypeMatch[0].length); - return "continue"; - } - // End tag: - var endTagMatch = html.match(endTag); - if (endTagMatch) { - var curIndex = index; - advance(endTagMatch[0].length); - parseEndTag(endTagMatch[1], curIndex, index); - return "continue"; - } - // Start tag: - var startTagMatch = parseStartTag(); - if (startTagMatch) { - handleStartTag(startTagMatch); - if (shouldIgnoreFirstNewline(startTagMatch.tagName, html)) { - advance(1); - } - return "continue"; - } - } - var text = void 0, rest = void 0, next = void 0; - if (textEnd >= 0) { - rest = html.slice(textEnd); - while (!endTag.test(rest) && - !startTagOpen.test(rest) && - !comment.test(rest) && - !conditionalComment.test(rest)) { - // < in plain text, be forgiving and treat it as text - next = rest.indexOf('<', 1); - if (next < 0) - break; - textEnd += next; - rest = html.slice(textEnd); - } - text = html.substring(0, textEnd); - } - if (textEnd < 0) { - text = html; - } - if (text) { - advance(text.length); - } - if (options.chars && text) { - options.chars(text, index - text.length, index); - } - } - else { - var endTagLength_1 = 0; - var stackedTag_1 = lastTag.toLowerCase(); - var reStackedTag = reCache[stackedTag_1] || - (reCache[stackedTag_1] = new RegExp('([\\s\\S]*?)(]*>)', 'i')); - var rest = html.replace(reStackedTag, function (all, text, endTag) { - endTagLength_1 = endTag.length; - if (!isPlainTextElement(stackedTag_1) && stackedTag_1 !== 'noscript') { - text = text - .replace(//g, '$1') // #7298 - .replace(//g, '$1'); - } - if (shouldIgnoreFirstNewline(stackedTag_1, text)) { - text = text.slice(1); - } - if (options.chars) { - options.chars(text); - } - return ''; - }); - index += html.length - rest.length; - html = rest; - parseEndTag(stackedTag_1, index - endTagLength_1, index); - } - if (html === last) { - options.chars && options.chars(html); - if (!stack.length && options.warn) { - options.warn("Mal-formatted tag at end of template: \"".concat(html, "\""), { - start: index + html.length - }); - } - return "break"; - } - }; - while (html) { - var state_1 = _loop_1(); - if (state_1 === "break") - break; - } - // Clean up any remaining tags - parseEndTag(); - function advance(n) { - index += n; - html = html.substring(n); - } - function parseStartTag() { - var start = html.match(startTagOpen); - if (start) { - var match = { - tagName: start[1], - attrs: [], - start: index - }; - advance(start[0].length); - var end = void 0, attr = void 0; - while (!(end = html.match(startTagClose)) && - (attr = html.match(dynamicArgAttribute) || html.match(attribute))) { - attr.start = index; - advance(attr[0].length); - attr.end = index; - match.attrs.push(attr); - } - if (end) { - match.unarySlash = end[1]; - advance(end[0].length); - match.end = index; - return match; - } - } - } - function handleStartTag(match) { - var tagName = match.tagName; - var unarySlash = match.unarySlash; - if (expectHTML) { - if (lastTag === 'p' && isNonPhrasingTag(tagName)) { - parseEndTag(lastTag); - } - if (canBeLeftOpenTag(tagName) && lastTag === tagName) { - parseEndTag(tagName); - } - } - var unary = isUnaryTag(tagName) || !!unarySlash; - var l = match.attrs.length; - var attrs = new Array(l); - for (var i = 0; i < l; i++) { - var args = match.attrs[i]; - var value = args[3] || args[4] || args[5] || ''; - var shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' - ? options.shouldDecodeNewlinesForHref - : options.shouldDecodeNewlines; - attrs[i] = { - name: args[1], - value: decodeAttr(value, shouldDecodeNewlines) - }; - if (options.outputSourceRange) { - attrs[i].start = args.start + args[0].match(/^\s*/).length; - attrs[i].end = args.end; - } - } - if (!unary) { - stack.push({ - tag: tagName, - lowerCasedTag: tagName.toLowerCase(), - attrs: attrs, - start: match.start, - end: match.end - }); - lastTag = tagName; - } - if (options.start) { - options.start(tagName, attrs, unary, match.start, match.end); - } - } - function parseEndTag(tagName, start, end) { - var pos, lowerCasedTagName; - if (start == null) - start = index; - if (end == null) - end = index; - // Find the closest opened tag of the same type - if (tagName) { - lowerCasedTagName = tagName.toLowerCase(); - for (pos = stack.length - 1; pos >= 0; pos--) { - if (stack[pos].lowerCasedTag === lowerCasedTagName) { - break; - } - } - } - else { - // If no tag name is provided, clean shop - pos = 0; - } - if (pos >= 0) { - // Close all the open elements, up the stack - for (var i = stack.length - 1; i >= pos; i--) { - if ((i > pos || !tagName) && options.warn) { - options.warn("tag <".concat(stack[i].tag, "> has no matching end tag."), { - start: stack[i].start, - end: stack[i].end - }); - } - if (options.end) { - options.end(stack[i].tag, start, end); - } - } - // Remove the open elements from the stack - stack.length = pos; - lastTag = pos && stack[pos - 1].tag; - } - else if (lowerCasedTagName === 'br') { - if (options.start) { - options.start(tagName, [], true, start, end); - } - } - else if (lowerCasedTagName === 'p') { - if (options.start) { - options.start(tagName, [], false, start, end); - } - if (options.end) { - options.end(tagName, start, end); - } - } - } - } - - var DEFAULT_FILENAME = 'anonymous.vue'; - var splitRE = /\r?\n/g; - var replaceRE = /./g; - var isSpecialTag = makeMap('script,style,template', true); - /** - * Parse a single-file component (*.vue) file into an SFC Descriptor Object. - */ - function parseComponent(source, options) { - if (options === void 0) { options = {}; } - var sfc = { - source: source, - filename: DEFAULT_FILENAME, - template: null, - script: null, - scriptSetup: null, - styles: [], - customBlocks: [], - cssVars: [], - errors: [], - shouldForceReload: null // attached in parse() by compiler-sfc - }; - var depth = 0; - var currentBlock = null; - var warn = function (msg) { - sfc.errors.push(msg); - }; - if (options.outputSourceRange) { - warn = function (msg, range) { - var data = { msg: msg }; - if (range.start != null) { - data.start = range.start; - } - if (range.end != null) { - data.end = range.end; - } - sfc.errors.push(data); - }; - } - function start(tag, attrs, unary, start, end) { - if (depth === 0) { - currentBlock = { - type: tag, - content: '', - start: end, - end: 0, - attrs: attrs.reduce(function (cumulated, _a) { - var name = _a.name, value = _a.value; - cumulated[name] = value || true; - return cumulated; - }, {}) - }; - if (typeof currentBlock.attrs.src === 'string') { - currentBlock.src = currentBlock.attrs.src; - } - if (isSpecialTag(tag)) { - checkAttrs(currentBlock, attrs); - if (tag === 'script') { - var block = currentBlock; - if (block.attrs.setup) { - block.setup = currentBlock.attrs.setup; - sfc.scriptSetup = block; - } - else { - sfc.script = block; - } - } - else if (tag === 'style') { - sfc.styles.push(currentBlock); - } - else { - sfc[tag] = currentBlock; - } - } - else { - // custom blocks - sfc.customBlocks.push(currentBlock); - } - } - if (!unary) { - depth++; - } - } - function checkAttrs(block, attrs) { - for (var i = 0; i < attrs.length; i++) { - var attr = attrs[i]; - if (attr.name === 'lang') { - block.lang = attr.value; - } - if (attr.name === 'scoped') { - block.scoped = true; - } - if (attr.name === 'module') { - block.module = attr.value || true; - } - } - } - function end(tag, start) { - if (depth === 1 && currentBlock) { - currentBlock.end = start; - var text = source.slice(currentBlock.start, currentBlock.end); - if (options.deindent === true || - // by default, deindent unless it's script with default lang or ts - (options.deindent !== false && - !(currentBlock.type === 'script' && - (!currentBlock.lang || currentBlock.lang === 'ts')))) { - text = deIndent(text); - } - // pad content so that linters and pre-processors can output correct - // line numbers in errors and warnings - if (currentBlock.type !== 'template' && options.pad) { - text = padContent(currentBlock, options.pad) + text; - } - currentBlock.content = text; - currentBlock = null; - } - depth--; - } - function padContent(block, pad) { - if (pad === 'space') { - return source.slice(0, block.start).replace(replaceRE, ' '); - } - else { - var offset = source.slice(0, block.start).split(splitRE).length; - var padChar = block.type === 'script' && !block.lang ? '//\n' : '\n'; - return Array(offset).join(padChar); - } - } - parseHTML(source, { - warn: warn, - start: start, - end: end, - outputSourceRange: options.outputSourceRange - }); - return sfc; - } - - // can we use __proto__? - var hasProto = '__proto__' in {}; - // Browser environment sniffing - var inBrowser = typeof window !== 'undefined'; - var UA = inBrowser && window.navigator.userAgent.toLowerCase(); - var isIE = UA && /msie|trident/.test(UA); - UA && UA.indexOf('msie 9.0') > 0; - var isEdge = UA && UA.indexOf('edge/') > 0; - UA && UA.indexOf('android') > 0; - UA && /iphone|ipad|ipod|ios/.test(UA); - UA && /chrome\/\d+/.test(UA) && !isEdge; - UA && /phantomjs/.test(UA); - UA && UA.match(/firefox\/(\d+)/); - // Firefox has a "watch" function on Object.prototype... - // @ts-expect-error firebox support - var nativeWatch = {}.watch; - var supportsPassive = false; - if (inBrowser) { - try { - var opts = {}; - Object.defineProperty(opts, 'passive', { - get: function () { - /* istanbul ignore next */ - supportsPassive = true; - } - }); // https://github.com/facebook/flow/issues/285 - window.addEventListener('test-passive', null, opts); - } - catch (e) { } - } - // this needs to be lazy-evaled because vue may be required before - // vue-server-renderer can set VUE_ENV - var _isServer; - var isServerRendering = function () { - if (_isServer === undefined) { - /* istanbul ignore if */ - if (!inBrowser && typeof global !== 'undefined') { - // detect presence of vue-server-renderer and avoid - // Webpack shimming the process - _isServer = - global['process'] && global['process'].env.VUE_ENV === 'server'; - } - else { - _isServer = false; - } - } - return _isServer; - }; - /* istanbul ignore next */ - function isNative(Ctor) { - return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); - } - var hasSymbol = typeof Symbol !== 'undefined' && - isNative(Symbol) && - typeof Reflect !== 'undefined' && - isNative(Reflect.ownKeys); - var _Set; // $flow-disable-line - /* istanbul ignore if */ if (typeof Set !== 'undefined' && isNative(Set)) { - // use native Set when available. - _Set = Set; - } - else { - // a non-standard Set polyfill that only works with primitive keys. - _Set = /** @class */ (function () { - function Set() { - this.set = Object.create(null); - } - Set.prototype.has = function (key) { - return this.set[key] === true; - }; - Set.prototype.add = function (key) { - this.set[key] = true; - }; - Set.prototype.clear = function () { - this.set = Object.create(null); - }; - return Set; - }()); - } - - var ASSET_TYPES = ['component', 'directive', 'filter']; - var LIFECYCLE_HOOKS = [ - 'beforeCreate', - 'created', - 'beforeMount', - 'mounted', - 'beforeUpdate', - 'updated', - 'beforeDestroy', - 'destroyed', - 'activated', - 'deactivated', - 'errorCaptured', - 'serverPrefetch', - 'renderTracked', - 'renderTriggered' - ]; - - var config = { - /** - * Option merge strategies (used in core/util/options) - */ - // $flow-disable-line - optionMergeStrategies: Object.create(null), - /** - * Whether to suppress warnings. - */ - silent: false, - /** - * Show production mode tip message on boot? - */ - productionTip: true, - /** - * Whether to enable devtools - */ - devtools: true, - /** - * Whether to record perf - */ - performance: false, - /** - * Error handler for watcher errors - */ - errorHandler: null, - /** - * Warn handler for watcher warns - */ - warnHandler: null, - /** - * Ignore certain custom elements - */ - ignoredElements: [], - /** - * Custom user key aliases for v-on - */ - // $flow-disable-line - keyCodes: Object.create(null), - /** - * Check if a tag is reserved so that it cannot be registered as a - * component. This is platform-dependent and may be overwritten. - */ - isReservedTag: no, - /** - * Check if an attribute is reserved so that it cannot be used as a component - * prop. This is platform-dependent and may be overwritten. - */ - isReservedAttr: no, - /** - * Check if a tag is an unknown element. - * Platform-dependent. - */ - isUnknownElement: no, - /** - * Get the namespace of an element - */ - getTagNamespace: noop, - /** - * Parse the real tag name for the specific platform. - */ - parsePlatformTagName: identity, - /** - * Check if an attribute must be bound using property, e.g. value - * Platform-dependent. - */ - mustUseProp: no, - /** - * Perform updates asynchronously. Intended to be used by Vue Test Utils - * This will significantly reduce performance if set to false. - */ - async: true, - /** - * Exposed for legacy reasons - */ - _lifecycleHooks: LIFECYCLE_HOOKS - }; - - var currentInstance = null; - /** - * @internal - */ - function setCurrentInstance(vm) { - if (vm === void 0) { vm = null; } - if (!vm) - currentInstance && currentInstance._scope.off(); - currentInstance = vm; - vm && vm._scope.on(); - } - - /** - * @internal - */ - var VNode = /** @class */ (function () { - function VNode(tag, data, children, text, elm, context, componentOptions, asyncFactory) { - this.tag = tag; - this.data = data; - this.children = children; - this.text = text; - this.elm = elm; - this.ns = undefined; - this.context = context; - this.fnContext = undefined; - this.fnOptions = undefined; - this.fnScopeId = undefined; - this.key = data && data.key; - this.componentOptions = componentOptions; - this.componentInstance = undefined; - this.parent = undefined; - this.raw = false; - this.isStatic = false; - this.isRootInsert = true; - this.isComment = false; - this.isCloned = false; - this.isOnce = false; - this.asyncFactory = asyncFactory; - this.asyncMeta = undefined; - this.isAsyncPlaceholder = false; - } - Object.defineProperty(VNode.prototype, "child", { - // DEPRECATED: alias for componentInstance for backwards compat. - /* istanbul ignore next */ - get: function () { - return this.componentInstance; - }, - enumerable: false, - configurable: true - }); - return VNode; - }()); - var createEmptyVNode = function (text) { - if (text === void 0) { text = ''; } - var node = new VNode(); - node.text = text; - node.isComment = true; - return node; - }; - function createTextVNode(val) { - return new VNode(undefined, undefined, undefined, String(val)); - } - // optimized shallow clone - // used for static nodes and slot nodes because they may be reused across - // multiple renders, cloning them avoids errors when DOM manipulations rely - // on their elm reference. - function cloneVNode(vnode) { - var cloned = new VNode(vnode.tag, vnode.data, - // #7975 - // clone children array to avoid mutating original in case of cloning - // a child. - vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, vnode.componentOptions, vnode.asyncFactory); - cloned.ns = vnode.ns; - cloned.isStatic = vnode.isStatic; - cloned.key = vnode.key; - cloned.isComment = vnode.isComment; - cloned.fnContext = vnode.fnContext; - cloned.fnOptions = vnode.fnOptions; - cloned.fnScopeId = vnode.fnScopeId; - cloned.asyncMeta = vnode.asyncMeta; - cloned.isCloned = true; - return cloned; - } - - /* not type checking this file because flow doesn't play well with Proxy */ - { - makeMap('Infinity,undefined,NaN,isFinite,isNaN,' + - 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + - 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' + - 'require' // for Webpack/Browserify - ); - var hasProxy_1 = typeof Proxy !== 'undefined' && isNative(Proxy); - if (hasProxy_1) { - var isBuiltInModifier_1 = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); - config.keyCodes = new Proxy(config.keyCodes, { - set: function (target, key, value) { - if (isBuiltInModifier_1(key)) { - warn$2("Avoid overwriting built-in modifier in config.keyCodes: .".concat(key)); - return false; - } - else { - target[key] = value; - return true; - } - } - }); - } - } - - /****************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */ - - var __assign = function() { - __assign = Object.assign || function __assign(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); - }; - - var uid = 0; - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - * @internal - */ - var Dep = /** @class */ (function () { - function Dep() { - this.id = uid++; - this.subs = []; - } - Dep.prototype.addSub = function (sub) { - this.subs.push(sub); - }; - Dep.prototype.removeSub = function (sub) { - remove$1(this.subs, sub); - }; - Dep.prototype.depend = function (info) { - if (Dep.target) { - Dep.target.addDep(this); - if (info && Dep.target.onTrack) { - Dep.target.onTrack(__assign({ effect: Dep.target }, info)); - } - } - }; - Dep.prototype.notify = function (info) { - // stabilize the subscriber list first - var subs = this.subs.slice(); - for (var i = 0, l = subs.length; i < l; i++) { - if (info) { - var sub = subs[i]; - sub.onTrigger && - sub.onTrigger(__assign({ effect: subs[i] }, info)); - } - subs[i].update(); - } - }; - return Dep; - }()); - // The current target watcher being evaluated. - // This is globally unique because only one watcher - // can be evaluated at a time. - Dep.target = null; - var targetStack = []; - function pushTarget(target) { - targetStack.push(target); - Dep.target = target; - } - function popTarget() { - targetStack.pop(); - Dep.target = targetStack[targetStack.length - 1]; - } - - /* - * not type checking this file because flow doesn't play well with - * dynamically accessing methods on Array prototype - */ - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto); - var methodsToPatch = [ - 'push', - 'pop', - 'shift', - 'unshift', - 'splice', - 'sort', - 'reverse' - ]; - /** - * Intercept mutating methods and emit events - */ - methodsToPatch.forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator() { - var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; - } - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - case 'unshift': - inserted = args; - break; - case 'splice': - inserted = args.slice(2); - break; - } - if (inserted) - ob.observeArray(inserted); - // notify change - { - ob.dep.notify({ - type: "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */, - target: this, - key: method - }); - } - return result; - }); - }); - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - var NO_INIITIAL_VALUE = {}; - /** - * In some cases we may want to disable observation inside a component's - * update computation. - */ - var shouldObserve = true; - function toggleObserving(value) { - shouldObserve = value; - } - // ssr mock dep - var mockDep = { - notify: noop, - depend: noop, - addSub: noop, - removeSub: noop - }; - /** - * Observer class that is attached to each observed - * object. Once attached, the observer converts the target - * object's property keys into getter/setters that - * collect dependencies and dispatch updates. - */ - var Observer = /** @class */ (function () { - function Observer(value, shallow, mock) { - if (shallow === void 0) { shallow = false; } - if (mock === void 0) { mock = false; } - this.value = value; - this.shallow = shallow; - this.mock = mock; - // this.value = value - this.dep = mock ? mockDep : new Dep(); - this.vmCount = 0; - def(value, '__ob__', this); - if (isArray(value)) { - if (!mock) { - if (hasProto) { - value.__proto__ = arrayMethods; - /* eslint-enable no-proto */ - } - else { - for (var i = 0, l = arrayKeys.length; i < l; i++) { - var key = arrayKeys[i]; - def(value, key, arrayMethods[key]); - } - } - } - if (!shallow) { - this.observeArray(value); - } - } - else { - /** - * Walk through all properties and convert them into - * getter/setters. This method should only be called when - * value type is Object. - */ - var keys = Object.keys(value); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock); - } - } - } - /** - * Observe a list of Array items. - */ - Observer.prototype.observeArray = function (value) { - for (var i = 0, l = value.length; i < l; i++) { - observe(value[i], false, this.mock); - } - }; - return Observer; - }()); - // helpers - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - */ - function observe(value, shallow, ssrMockReactivity) { - if (!isObject(value) || isRef(value) || value instanceof VNode) { - return; - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } - else if (shouldObserve && - (ssrMockReactivity || !isServerRendering()) && - (isArray(value) || isPlainObject(value)) && - Object.isExtensible(value) && - !value.__v_skip /* ReactiveFlags.SKIP */) { - ob = new Observer(value, shallow, ssrMockReactivity); - } - return ob; - } - /** - * Define a reactive property on an Object. - */ - function defineReactive(obj, key, val, customSetter, shallow, mock) { - var dep = new Dep(); - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return; - } - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - if ((!getter || setter) && - (val === NO_INIITIAL_VALUE || arguments.length === 2)) { - val = obj[key]; - } - var childOb = !shallow && observe(val, false, mock); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter() { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - { - dep.depend({ - target: obj, - type: "get" /* TrackOpTypes.GET */, - key: key - }); - } - if (childOb) { - childOb.dep.depend(); - if (isArray(value)) { - dependArray(value); - } - } - } - return isRef(value) && !shallow ? value.value : value; - }, - set: function reactiveSetter(newVal) { - var value = getter ? getter.call(obj) : val; - if (!hasChanged(value, newVal)) { - return; - } - if (customSetter) { - customSetter(); - } - if (setter) { - setter.call(obj, newVal); - } - else if (getter) { - // #7981: for accessor properties without setter - return; - } - else if (!shallow && isRef(value) && !isRef(newVal)) { - value.value = newVal; - return; - } - else { - val = newVal; - } - childOb = !shallow && observe(newVal, false, mock); - { - dep.notify({ - type: "set" /* TriggerOpTypes.SET */, - target: obj, - key: key, - newValue: newVal, - oldValue: value - }); - } - } - }); - return dep; - } - function set(target, key, val) { - if ((isUndef(target) || isPrimitive(target))) { - warn$2("Cannot set reactive property on undefined, null, or primitive value: ".concat(target)); - } - if (isReadonly(target)) { - warn$2("Set operation on key \"".concat(key, "\" failed: target is readonly.")); - return; - } - var ob = target.__ob__; - if (isArray(target) && isValidArrayIndex(key)) { - target.length = Math.max(target.length, key); - target.splice(key, 1, val); - // when mocking for SSR, array methods are not hijacked - if (ob && !ob.shallow && ob.mock) { - observe(val, false, true); - } - return val; - } - if (key in target && !(key in Object.prototype)) { - target[key] = val; - return val; - } - if (target._isVue || (ob && ob.vmCount)) { - warn$2('Avoid adding reactive properties to a Vue instance or its root $data ' + - 'at runtime - declare it upfront in the data option.'); - return val; - } - if (!ob) { - target[key] = val; - return val; - } - defineReactive(ob.value, key, val, undefined, ob.shallow, ob.mock); - { - ob.dep.notify({ - type: "add" /* TriggerOpTypes.ADD */, - target: target, - key: key, - newValue: val, - oldValue: undefined - }); - } - return val; - } - /** - * Collect dependencies on array elements when the array is touched, since - * we cannot intercept array element access like property getters. - */ - function dependArray(value) { - for (var e = void 0, i = 0, l = value.length; i < l; i++) { - e = value[i]; - if (e && e.__ob__) { - e.__ob__.dep.depend(); - } - if (isArray(e)) { - dependArray(e); - } - } - } - - function isReadonly(value) { - return !!(value && value.__v_isReadonly); - } - - function isRef(r) { - return !!(r && r.__v_isRef === true); - } - - { - var perf_1 = inBrowser && window.performance; - /* istanbul ignore if */ - if (perf_1 && - // @ts-ignore - perf_1.mark && - // @ts-ignore - perf_1.measure && - // @ts-ignore - perf_1.clearMarks && - // @ts-ignore - perf_1.clearMeasures) ; - } - - var normalizeEvent = cached(function (name) { - var passive = name.charAt(0) === '&'; - name = passive ? name.slice(1) : name; - var once = name.charAt(0) === '~'; // Prefixed last, checked first - name = once ? name.slice(1) : name; - var capture = name.charAt(0) === '!'; - name = capture ? name.slice(1) : name; - return { - name: name, - once: once, - capture: capture, - passive: passive - }; - }); - function createFnInvoker(fns, vm) { - function invoker() { - var fns = invoker.fns; - if (isArray(fns)) { - var cloned = fns.slice(); - for (var i = 0; i < cloned.length; i++) { - invokeWithErrorHandling(cloned[i], null, arguments, vm, "v-on handler"); - } - } - else { - // return handler return value for single handlers - return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler"); - } - } - invoker.fns = fns; - return invoker; - } - function updateListeners(on, oldOn, add, remove, createOnceHandler, vm) { - var name, cur, old, event; - for (name in on) { - cur = on[name]; - old = oldOn[name]; - event = normalizeEvent(name); - if (isUndef(cur)) { - warn$2("Invalid handler for event \"".concat(event.name, "\": got ") + String(cur), vm); - } - else if (isUndef(old)) { - if (isUndef(cur.fns)) { - cur = on[name] = createFnInvoker(cur, vm); - } - if (isTrue(event.once)) { - cur = on[name] = createOnceHandler(event.name, cur, event.capture); - } - add(event.name, cur, event.capture, event.passive, event.params); - } - else if (cur !== old) { - old.fns = cur; - on[name] = old; - } - } - for (name in oldOn) { - if (isUndef(on[name])) { - event = normalizeEvent(name); - remove(event.name, oldOn[name], event.capture); - } - } - } - - function extractPropsFromVNodeData(data, Ctor, tag) { - // we are only extracting raw values here. - // validation and default values are handled in the child - // component itself. - var propOptions = Ctor.options.props; - if (isUndef(propOptions)) { - return; - } - var res = {}; - var attrs = data.attrs, props = data.props; - if (isDef(attrs) || isDef(props)) { - for (var key in propOptions) { - var altKey = hyphenate(key); - { - var keyInLowerCase = key.toLowerCase(); - if (key !== keyInLowerCase && attrs && hasOwn(attrs, keyInLowerCase)) { - tip("Prop \"".concat(keyInLowerCase, "\" is passed to component ") + - "".concat(formatComponentName( - // @ts-expect-error tag is string - tag || Ctor), ", but the declared prop name is") + - " \"".concat(key, "\". ") + - "Note that HTML attributes are case-insensitive and camelCased " + - "props need to use their kebab-case equivalents when using in-DOM " + - "templates. You should probably use \"".concat(altKey, "\" instead of \"").concat(key, "\".")); - } - } - checkProp(res, props, key, altKey, true) || - checkProp(res, attrs, key, altKey, false); - } - } - return res; - } - function checkProp(res, hash, key, altKey, preserve) { - if (isDef(hash)) { - if (hasOwn(hash, key)) { - res[key] = hash[key]; - if (!preserve) { - delete hash[key]; - } - return true; - } - else if (hasOwn(hash, altKey)) { - res[key] = hash[altKey]; - if (!preserve) { - delete hash[altKey]; - } - return true; - } - } - return false; - } - - // The template compiler attempts to minimize the need for normalization by - // statically analyzing the template at compile time. - // - // For plain HTML markup, normalization can be completely skipped because the - // generated render function is guaranteed to return Array. There are - // two cases where extra normalization is needed: - // 1. When the children contains components - because a functional component - // may return an Array instead of a single root. In this case, just a simple - // normalization is needed - if any child is an Array, we flatten the whole - // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep - // because functional components already normalize their own children. - function simpleNormalizeChildren(children) { - for (var i = 0; i < children.length; i++) { - if (isArray(children[i])) { - return Array.prototype.concat.apply([], children); - } - } - return children; - } - // 2. When the children contains constructs that always generated nested Arrays, - // e.g.