vue#ComponentInternalInstance TypeScript Examples

The following examples show how to use vue#ComponentInternalInstance. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: i18n.ts    From vue-i18n-next with MIT License 6 votes vote down vote up
function getI18nInstance(instance: ComponentInternalInstance): I18n {
  if (!__BRIDGE__) {
    const i18n = inject(
      !instance.isCE
        ? instance.appContext.app.__VUE_I18N_SYMBOL__!
        : I18nInjectionKey
    )
    /* istanbul ignore if */
    if (!i18n) {
      throw createI18nError(
        !instance.isCE
          ? I18nErrorCodes.UNEXPECTED_ERROR
          : I18nErrorCodes.NOT_INSLALLED_WITH_PROVIDE
      )
    }
    return i18n
  } else {
    const vm = instance.proxy
    /* istanbul ignore if */
    if (vm == null) {
      throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR)
    }
    const i18n = (vm as any)._i18nBridgeRoot // eslint-disable-line @typescript-eslint/no-explicit-any
    /* istanbul ignore if */
    if (!i18n) {
      throw createI18nError(I18nErrorCodes.NOT_INSLALLED)
    }
    return i18n as I18n
  }
}
Example #2
Source File: use-current-instance.ts    From gitmars with GNU General Public License v3.0 6 votes vote down vote up
export default function useCurrentInstance(props?: string | string[]) {
    if (typeof props === 'string') props = [props]
    const { appContext, proxy } =
        getCurrentInstance() as ComponentInternalInstance
    const globalProperties = appContext.config.globalProperties
    let style = {}
    props && props.includes('style') && (style = useCssModule() as any)
    return {
        globalProperties,
        proxy,
        style
    }
}
Example #3
Source File: utils.ts    From vue-i18n-next with MIT License 6 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function getComponentOptions(instance: ComponentInternalInstance): any {
  return !__BRIDGE__ ? instance.type : instance.proxy!.$options
}
Example #4
Source File: i18n.ts    From vue-i18n-next with MIT License 6 votes vote down vote up
function getComposer(
  i18n: I18n,
  target: ComponentInternalInstance,
  useComponent = false
): Composer | null {
  let composer: Composer | null = null
  const root = target.root
  let current: ComponentInternalInstance | null = target.parent
  while (current != null) {
    const i18nInternal = i18n as unknown as I18nInternal
    if (i18n.mode === 'composition') {
      composer = i18nInternal.__getInstance(current)
    } else {
      if (!__LITE__ && __FEATURE_LEGACY_API__) {
        const vueI18n = i18nInternal.__getInstance(current)
        if (vueI18n != null) {
          composer = (vueI18n as VueI18n & VueI18nInternal)
            .__composer as Composer
          if (
            useComponent &&
            composer &&
            !(composer as any)[InejctWithOption] // eslint-disable-line @typescript-eslint/no-explicit-any
          ) {
            composer = null
          }
        }
      }
    }
    if (composer != null) {
      break
    }
    if (root === current) {
      break
    }
    current = current.parent
  }
  return composer
}
Example #5
Source File: useParent.ts    From elenext with MIT License 6 votes vote down vote up
useChildren = <T extends Record<string, unknown>>(key: InjectionKey<ParentProvide<T>>, data: T) => {
  const children: ComponentInternalInstance[] = reactive([])
  provide(key, {
    ...data,
    children,
    insert: (child: ComponentInternalInstance) => {
      children.push(child)
    },
    remove: (child: ComponentInternalInstance) => {
      const index = children.indexOf(child)
      children.splice(index, 1)
    }
  })
}
Example #6
Source File: directive.ts    From vue-i18n-next with MIT License 6 votes vote down vote up
function getComposer(
  i18n: I18n,
  instance: ComponentInternalInstance
): Composer {
  const i18nInternal = i18n as unknown as I18nInternal
  if (i18n.mode === 'composition') {
    return (i18nInternal.__getInstance(instance) || i18n.global) as Composer
  } else {
    const vueI18n = i18nInternal.__getInstance(instance)
    return vueI18n != null
      ? (vueI18n as unknown as VueI18nInternal).__composer
      : (i18n.global as unknown as VueI18nInternal).__composer
  }
}
Example #7
Source File: devtools.ts    From vue-i18n-next with MIT License 6 votes vote down vote up
function getComponentInstance(
  nodeId: string,
  i18n: _I18n
): ComponentInternalInstance | null {
  let instance: ComponentInternalInstance | null = null

  if (nodeId !== 'global') {
    for (const [component, composer] of i18n.__instances.entries()) {
      if (composer.id.toString() === nodeId) {
        instance = component
        break
      }
    }
  }

  return instance
}
Example #8
Source File: provider.ts    From fect with MIT License 6 votes vote down vote up
sortChildren = (
  parent: ComponentInternalInstance,
  publicChildren: ComponentPublicInstance[],
  internalChildren: ComponentInternalInstance[]
) => {
  const VNodes = flattenVNodes(parent.subTree.children)
  internalChildren.sort(
    // eslint-disable-next-line comma-dangle
    (a, b) => VNodes.indexOf(a.vnode) - VNodes.indexOf(b.vnode)
  )
  const orderedPublicChildren = internalChildren.map((item) => item.proxy)
  publicChildren.sort((a, b) => {
    const indexA = orderedPublicChildren.indexOf(a)
    const indexB = orderedPublicChildren.indexOf(b)
    return indexA - indexB
  })
}
Example #9
Source File: useParent.ts    From elenext with MIT License 6 votes vote down vote up
useParent = <T>(key: InjectionKey<ParentProvide<T>>) => {
  const instance = getCurrentInstance() as ComponentInternalInstance
  const parent = inject(key, null)
  const index = computed(() => parent?.children.indexOf(instance))

  parent?.insert(instance)
  onUnmounted(() => {
    parent?.remove(instance)
  })

  return { parent, index }
}
Example #10
Source File: provider.ts    From fect with MIT License 5 votes vote down vote up
createProvider = <
  // eslint-disable-next-line
  T extends ComponentPublicInstance = ComponentPublicInstance<{}, any>,
  ProvideValue = never
>(
  key: InjectionKey<ProvideValue>
) => {
  const publicChildren: T[] = reactive([])
  const internalChildren: ComponentInternalInstance[] = reactive([])
  const parent = getCurrentInstance()!
  const provider = (value?: ProvideValue) => {
    const link = (child: ComponentInternalInstance) => {
      if (child.proxy) {
        internalChildren.push(child)
        publicChildren.push(child.proxy as T)
        sortChildren(parent, publicChildren, internalChildren)
      }
    }

    const unlink = (child: ComponentInternalInstance) => {
      const idx = internalChildren.indexOf(child)
      publicChildren.splice(idx, 1)
      internalChildren.splice(idx, 1)
    }
    provide(
      key,
      Object.assign(
        {
          link,
          unlink,
          children: publicChildren,
          internalChildren
        },
        value
      )
    )
  }
  return {
    children: publicChildren,
    provider
  }
}
Example #11
Source File: interpolate.ts    From vue3-gettext with MIT License 5 votes vote down vote up
interpolate =
  (plugin: Language) =>
  (msgid: string, context: any = {}, disableHtmlEscaping = false, parent?: ComponentInternalInstance | any) => {
    const silent = plugin.silent;
    if (!silent && MUSTACHE_SYNTAX_RE.test(msgid)) {
      console.warn(`Mustache syntax cannot be used with vue-gettext. Please use "%{}" instead of "{{}}" in: ${msgid}`);
    }

    const result = msgid.replace(INTERPOLATION_RE, (_match, token: string) => {
      const expression = token.trim();
      let evaluated: Object;

      const escapeHtmlMap = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#039;",
      };

      // Avoid eval() by splitting `expression` and looping through its different properties if any, see #55.
      function getProps(obj: any, expression: string) {
        const arr = expression.split(EVALUATION_RE).filter((x) => x);
        while (arr.length) {
          obj = obj[arr.shift()!];
        }
        return obj;
      }

      function evalInContext(context: any, expression: string, parent: any): string {
        try {
          evaluated = getProps(context, expression);
        } catch (e) {
          // Ignore errors, because this function may be called recursively later.
        }
        if (evaluated === undefined || evaluated === null) {
          if (parent) {
            // Recursively climb the parent chain to allow evaluation inside nested components, see #23 and #24.
            return evalInContext(parent.ctx, expression, parent.parent);
          } else {
            console.warn(`Cannot evaluate expression: ${expression}`);
            evaluated = expression;
          }
        }
        const result = evaluated.toString();
        if (disableHtmlEscaping) {
          // Do not escape HTML, see #78.
          return result;
        }
        // Escape HTML, see #78.
        return result.replace(/[&<>"']/g, (m: string) => escapeHtmlMap[m as keyof typeof escapeHtmlMap]);
      }

      return evalInContext(context, expression, parent);
    });

    return result;
  }
Example #12
Source File: InitData.ts    From screen-shot with MIT License 5 votes vote down vote up
/**
   * 设置实例属性
   * @param instanceParam
   */
  public setProperty(instanceParam: ComponentInternalInstance | null) {
    currentInstance = instanceParam;
  }
Example #13
Source File: InitData.ts    From screen-shot with MIT License 5 votes vote down vote up
currentInstance: ComponentInternalInstance | null | undefined
Example #14
Source File: i18n.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
export function createI18n(options: any = {}, VueI18nLegacy?: any): any {
  type _I18n = I18n & I18nInternal

  if (__BRIDGE__) {
    _legacyVueI18n = VueI18nLegacy
  }

  // prettier-ignore
  const __legacyMode = __LITE__
    ? false
    :  __FEATURE_LEGACY_API__ && isBoolean(options.legacy)
      ? options.legacy
      : __FEATURE_LEGACY_API__
  // prettier-ignore
  const __globalInjection = isBoolean(options.globalInjection)
      ? options.globalInjection
      : true
  // prettier-ignore
  const __allowComposition = __LITE__
    ? true
    :  __FEATURE_LEGACY_API__ && __legacyMode
      ? !!options.allowComposition
      : true
  const __instances = new Map<ComponentInternalInstance, VueI18n | Composer>()
  const [globalScope, __global] = createGlobal(
    options,
    __legacyMode,
    VueI18nLegacy
  )
  const symbol: InjectionKey<I18n> | string = /* #__PURE__*/ makeSymbol(
    __DEV__ ? 'vue-i18n' : ''
  )

  function __getInstance<Instance extends VueI18n | Composer>(
    component: ComponentInternalInstance
  ): Instance | null {
    return (__instances.get(component) as unknown as Instance) || null
  }
  function __setInstance<Instance extends VueI18n | Composer>(
    component: ComponentInternalInstance,
    instance: Instance
  ): void {
    __instances.set(component, instance)
  }
  function __deleteInstance(component: ComponentInternalInstance): void {
    __instances.delete(component)
  }

  if (!__BRIDGE__) {
    const i18n = {
      // mode
      get mode(): I18nMode {
        return !__LITE__ && __FEATURE_LEGACY_API__ && __legacyMode
          ? 'legacy'
          : 'composition'
      },
      // allowComposition
      get allowComposition(): boolean {
        return __allowComposition
      },
      // install plugin
      async install(app: App, ...options: unknown[]): Promise<void> {
        if (
          !__BRIDGE__ &&
          (__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) &&
          !__NODE_JS__
        ) {
          app.__VUE_I18N__ = i18n as unknown as _I18n
        }

        // setup global provider
        app.__VUE_I18N_SYMBOL__ = symbol
        app.provide(app.__VUE_I18N_SYMBOL__, i18n as unknown as I18n)

        // global method and properties injection for Composition API
        if (!__legacyMode && __globalInjection) {
          injectGlobalFields(app, i18n.global as Composer)
        }

        // install built-in components and directive
        if (!__LITE__ && __FEATURE_FULL_INSTALL__) {
          applyNext(app, i18n as I18n, ...options)
        }

        // setup mixin for Legacy API
        if (!__LITE__ && __FEATURE_LEGACY_API__ && __legacyMode) {
          app.mixin(
            defineMixinNext(
              __global as unknown as VueI18n,
              (__global as unknown as VueI18nInternal).__composer as Composer,
              i18n as unknown as I18nInternal
            )
          )
        }

        // release global scope
        const unmountApp = app.unmount
        app.unmount = () => {
          i18n.dispose()
          unmountApp()
        }

        // setup vue-devtools plugin
        if ((__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) && !__NODE_JS__) {
          const ret = await enableDevTools(app, i18n as _I18n)
          if (!ret) {
            throw createI18nError(
              I18nErrorCodes.CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN
            )
          }
          const emitter: VueDevToolsEmitter =
            createEmitter<VueDevToolsEmitterEvents>()
          if (__legacyMode) {
            const _vueI18n = __global as unknown as VueI18nInternal
            _vueI18n.__enableEmitter && _vueI18n.__enableEmitter(emitter)
          } else {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const _composer = __global as any
            _composer[EnableEmitter] && _composer[EnableEmitter](emitter)
          }
          emitter.on('*', addTimelineEvent)
        }
      },
      // global accessor
      get global() {
        return __global
      },
      dispose(): void {
        globalScope.stop()
      },
      // @internal
      __instances,
      // @internal
      __getInstance,
      // @internal
      __setInstance,
      // @internal
      __deleteInstance
    }
    return i18n
  } else {
    // extend legacy VueI18n instance

    const i18n = (__global as any)[LegacyInstanceSymbol] // eslint-disable-line @typescript-eslint/no-explicit-any
    let _localeWatcher: Function | null = null
    Object.defineProperty(i18n, 'global', {
      get() {
        return __global
      }
    })
    Object.defineProperty(i18n, 'mode', {
      get() {
        return __legacyMode ? 'legacy' : 'composition'
      }
    })
    Object.defineProperty(i18n, 'allowComposition', {
      get() {
        return __allowComposition
      }
    })
    Object.defineProperty(i18n, '__instances', {
      get() {
        return __instances
      }
    })
    Object.defineProperty(i18n, 'install', {
      writable: true,
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      value: (Vue: any, ...options: unknown[]) => {
        const version =
          (Vue && Vue.version && Number(Vue.version.split('.')[0])) || -1
        if (version !== 2) {
          throw createI18nError(I18nErrorCodes.BRIDGE_SUPPORT_VUE_2_ONLY)
        }

        __FEATURE_FULL_INSTALL__ && applyBridge(Vue, ...options)

        if (!__legacyMode && __globalInjection) {
          _localeWatcher = injectGlobalFieldsForBridge(
            Vue,
            i18n,
            __global as Composer
          )
        }
        Vue.mixin(defineMixinBridge(i18n, _legacyVueI18n))
      }
    })
    Object.defineProperty(i18n, 'dispose', {
      value: (): void => {
        _localeWatcher && _localeWatcher()
        globalScope.stop()
      }
    })
    const methodMap = {
      __getInstance,
      __setInstance,
      __deleteInstance
    }
    Object.keys(methodMap).forEach(
      key =>
        Object.defineProperty(i18n, key, { value: (methodMap as any)[key] }) // eslint-disable-line @typescript-eslint/no-explicit-any
    )
    return i18n
  }
}
Example #15
Source File: devtools.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
export async function enableDevTools(app: App, i18n: _I18n): Promise<boolean> {
  return new Promise((resolve, reject) => {
    try {
      setupDevtoolsPlugin(
        {
          id: VueDevToolsIDs.PLUGIN,
          label: VueDevToolsLabels[VueDevToolsIDs.PLUGIN],
          packageName: 'vue-i18n',
          homepage: 'https://vue-i18n.intlify.dev',
          logo: 'https://vue-i18n.intlify.dev/vue-i18n-devtools-logo.png',
          componentStateTypes: [VUE_I18N_COMPONENT_TYPES],
          app
        },
        api => {
          devtoolsApi = api

          api.on.visitComponentTree(({ componentInstance, treeNode }) => {
            updateComponentTreeTags(componentInstance, treeNode, i18n)
          })

          api.on.inspectComponent(({ componentInstance, instanceData }) => {
            if (
              componentInstance.vnode.el &&
              componentInstance.vnode.el.__VUE_I18N__ &&
              instanceData
            ) {
              if (i18n.mode === 'legacy') {
                // ignore global scope on legacy mode
                if (
                  componentInstance.vnode.el.__VUE_I18N__ !==
                  (i18n.global as unknown as VueI18nInternal).__composer
                ) {
                  inspectComposer(
                    instanceData,
                    componentInstance.vnode.el.__VUE_I18N__ as Composer
                  )
                }
              } else {
                inspectComposer(
                  instanceData,
                  componentInstance.vnode.el.__VUE_I18N__ as Composer
                )
              }
            }
          })

          api.addInspector({
            id: VueDevToolsIDs.CUSTOM_INSPECTOR,
            label: VueDevToolsLabels[VueDevToolsIDs.CUSTOM_INSPECTOR],
            icon: 'language',
            treeFilterPlaceholder:
              VueDevToolsPlaceholders[VueDevToolsIDs.CUSTOM_INSPECTOR]
          })

          api.on.getInspectorTree(payload => {
            if (
              payload.app === app &&
              payload.inspectorId === VueDevToolsIDs.CUSTOM_INSPECTOR
            ) {
              registerScope(payload, i18n)
            }
          })

          const roots = new Map<App, ComponentInternalInstance>()
          api.on.getInspectorState(async payload => {
            if (
              payload.app === app &&
              payload.inspectorId === VueDevToolsIDs.CUSTOM_INSPECTOR
            ) {
              api.unhighlightElement()

              inspectScope(payload, i18n)

              if (payload.nodeId === 'global') {
                if (!roots.has(payload.app)) {
                  const [root] = await api.getComponentInstances(payload.app)
                  roots.set(payload.app, root)
                }
                api.highlightElement(roots.get(payload.app))
              } else {
                const instance = getComponentInstance(payload.nodeId, i18n)
                instance && api.highlightElement(instance)
              }
            }
          })

          api.on.editInspectorState(payload => {
            if (
              payload.app === app &&
              payload.inspectorId === VueDevToolsIDs.CUSTOM_INSPECTOR
            ) {
              editScope(payload, i18n)
            }
          })

          api.addTimelineLayer({
            id: VueDevToolsIDs.TIMELINE,
            label: VueDevToolsLabels[VueDevToolsIDs.TIMELINE],
            color: VueDevToolsTimelineColors[VueDevToolsIDs.TIMELINE]
          })

          resolve(true)
        }
      )
    } catch (e) {
      console.error(e)
      reject(false)
    }
  })
}
Example #16
Source File: i18n.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
function setupLifeCycle(
  i18n: I18nInternal,
  target: ComponentInternalInstance,
  composer: Composer
): void {
  let emitter: VueDevToolsEmitter | null = null

  if (__BRIDGE__) {
    // assign legacy VueI18n instance to Vue2 instance
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const vm = target.proxy as any
    if (vm == null) {
      throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR)
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const _i18n = (composer as any)[LegacyInstanceSymbol]
    if (_i18n === i18n) {
      throw createI18nError(I18nErrorCodes.UNEXPECTED_ERROR)
    }
    vm._i18n = _i18n
    vm._i18n_bridge = true

    // browser only
    if (inBrowser) {
      vm._i18nWatcher = vm._i18n.watchI18nData()
      if (vm._i18n._sync) {
        vm._localeWatcher = vm._i18n.watchLocale()
      }
    }

    let subscribing = false
    onBeforeMount(() => {
      vm._i18n.subscribeDataChanging(vm)
      subscribing = true
    }, target)

    onUnmounted(() => {
      if (subscribing) {
        vm._i18n.unsubscribeDataChanging(vm)
        subscribing = false
      }
      if (vm._i18nWatcher) {
        vm._i18nWatcher()
        vm._i18n.destroyVM()
        delete vm._i18nWatcher
      }
      if (vm._localeWatcher) {
        vm._localeWatcher()
        delete vm._localeWatcher
      }
      delete vm._i18n_bridge
      delete vm._i18n
    }, target)
  } else {
    onMounted(() => {
      // inject composer instance to DOM for intlify-devtools
      if (
        (__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) &&
        !__NODE_JS__ &&
        target.vnode.el
      ) {
        target.vnode.el.__VUE_I18N__ = composer
        emitter = createEmitter<VueDevToolsEmitterEvents>()
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const _composer = composer as any
        _composer[EnableEmitter] && _composer[EnableEmitter](emitter)
        emitter.on('*', addTimelineEvent)
      }
    }, target)

    onUnmounted(() => {
      // remove composer instance from DOM for intlify-devtools
      if (
        (__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) &&
        !__NODE_JS__ &&
        target.vnode.el &&
        target.vnode.el.__VUE_I18N__
      ) {
        emitter && emitter.off('*', addTimelineEvent)
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const _composer = composer as any
        _composer[DisableEmitter] && _composer[DisableEmitter]()
        delete target.vnode.el.__VUE_I18N__
      }
      i18n.__deleteInstance(target)
    }, target)
  }
}
Example #17
Source File: i18n.ts    From vue-i18n-next with MIT License 4 votes vote down vote up
function useI18nForLegacy(
  instance: ComponentInternalInstance,
  scope: I18nScope,
  root: Composer,
  options: any = {} // eslint-disable-line @typescript-eslint/no-explicit-any
): Composer {
  type Message = VueMessageType

  const isLocale = scope === 'local'
  const _composer = shallowRef<Composer | null>(null)

  if (
    isLocale &&
    instance.proxy &&
    !(instance.proxy.$options.i18n || instance.proxy.$options.__i18n)
  ) {
    throw createI18nError(
      I18nErrorCodes.MUST_DEFINE_I18N_OPTION_IN_ALLOW_COMPOSITION
    )
  }

  const _inheritLocale = isBoolean(options.inheritLocale)
    ? options.inheritLocale
    : true

  const _locale = ref<Locale>(
    // prettier-ignore
    isLocale && _inheritLocale
    ? root.locale.value
    : isString(options.locale)
      ? options.locale
      : DEFAULT_LOCALE
  )

  const _fallbackLocale = ref<FallbackLocale>(
    // prettier-ignore
    isLocale && _inheritLocale
      ? root.fallbackLocale.value
      : isString(options.fallbackLocale) ||
        isArray(options.fallbackLocale) ||
        isPlainObject(options.fallbackLocale) ||
        options.fallbackLocale === false
        ? options.fallbackLocale
        : _locale.value
  )

  const _messages = ref<LocaleMessages<LocaleMessage<Message>>>(
    getLocaleMessages<LocaleMessages<LocaleMessage<Message>>>(
      _locale.value as Locale,
      options
    )
  )

  // prettier-ignore
  const _datetimeFormats = ref<DateTimeFormatsType>(
    isPlainObject(options.datetimeFormats)
      ? options.datetimeFormats
      : { [_locale.value]: {} }
  )

  // prettier-ignore
  const _numberFormats = ref<NumberFormatsType>(
    isPlainObject(options.numberFormats)
      ? options.numberFormats
      : { [_locale.value]: {} }
  )

  // prettier-ignore
  const _missingWarn = isLocale
    ? root.missingWarn
    : isBoolean(options.missingWarn) || isRegExp(options.missingWarn)
      ? options.missingWarn
      : true

  // prettier-ignore
  const _fallbackWarn = isLocale
    ? root.fallbackWarn
    : isBoolean(options.fallbackWarn) || isRegExp(options.fallbackWarn)
      ? options.fallbackWarn
      : true

  // prettier-ignore
  const _fallbackRoot = isLocale
    ? root.fallbackRoot
    : isBoolean(options.fallbackRoot)
      ? options.fallbackRoot
      : true

  // configure fall back to root
  const _fallbackFormat = !!options.fallbackFormat

  // runtime missing
  const _missing = isFunction(options.missing) ? options.missing : null

  // postTranslation handler
  const _postTranslation = isFunction(options.postTranslation)
    ? options.postTranslation
    : null

  // prettier-ignore
  const _warnHtmlMessage = isLocale
    ? root.warnHtmlMessage
    : isBoolean(options.warnHtmlMessage)
      ? options.warnHtmlMessage
      : true

  const _escapeParameter = !!options.escapeParameter

  // prettier-ignore
  const _modifiers = isLocale
    ? root.modifiers
    : isPlainObject(options.modifiers)
      ? options.modifiers
      : {}

  // pluralRules
  const _pluralRules = options.pluralRules || (isLocale && root.pluralRules)

  // track reactivity
  function trackReactivityValues() {
    return [
      _locale.value,
      _fallbackLocale.value,
      _messages.value,
      _datetimeFormats.value,
      _numberFormats.value
    ]
  }

  // locale
  const locale = computed({
    get: () => {
      return _composer.value ? _composer.value.locale.value : _locale.value
    },
    set: val => {
      if (_composer.value) {
        _composer.value.locale.value = val
      }
      _locale.value = val
    }
  })

  // fallbackLocale
  const fallbackLocale = computed({
    get: () => {
      return _composer.value
        ? _composer.value.fallbackLocale.value
        : _fallbackLocale.value
    },
    set: val => {
      if (_composer.value) {
        _composer.value.fallbackLocale.value = val
      }
      _fallbackLocale.value = val
    }
  })

  // messages
  const messages = computed<LocaleMessages<LocaleMessage<Message>, Message>>(
    () => {
      if (_composer.value) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return _composer.value.messages.value as any
      } else {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return _messages.value as any
      }
    }
  )

  const datetimeFormats = computed<DateTimeFormatsType>(
    () => _datetimeFormats.value
  )

  const numberFormats = computed<NumberFormatsType>(() => _numberFormats.value)

  function getPostTranslationHandler(): PostTranslationHandler<Message> | null {
    return _composer.value
      ? _composer.value.getPostTranslationHandler()
      : _postTranslation
  }

  function setPostTranslationHandler(
    handler: PostTranslationHandler<Message> | null
  ): void {
    if (_composer.value) {
      _composer.value.setPostTranslationHandler(handler)
    }
  }

  function getMissingHandler(): MissingHandler | null {
    return _composer.value ? _composer.value.getMissingHandler() : _missing
  }

  function setMissingHandler(handler: MissingHandler | null): void {
    if (_composer.value) {
      _composer.value.setMissingHandler(handler)
    }
  }

  function warpWithDeps<R>(fn: () => unknown) {
    trackReactivityValues()
    return fn() as R
  }

  function t(...args: unknown[]): string {
    return _composer.value
      ? warpWithDeps<string>(
          () => Reflect.apply(_composer.value!.t, null, [...args]) as string
        )
      : warpWithDeps<string>(() => '')
  }

  function rt(...args: unknown[]): string {
    return _composer.value
      ? Reflect.apply(_composer.value.rt, null, [...args])
      : ''
  }

  function d(...args: unknown[]): string {
    return _composer.value
      ? warpWithDeps<string>(
          () => Reflect.apply(_composer.value!.d, null, [...args]) as string
        )
      : warpWithDeps<string>(() => '')
  }

  function n(...args: unknown[]): string {
    return _composer.value
      ? warpWithDeps<string>(
          () => Reflect.apply(_composer.value!.n, null, [...args]) as string
        )
      : warpWithDeps<string>(() => '')
  }

  function tm(key: Path): LocaleMessageValue<Message> | {} {
    return _composer.value ? _composer.value.tm(key) : {}
  }

  function te(key: Path, locale?: Locale): boolean {
    return _composer.value ? _composer.value.te(key, locale) : false
  }

  function getLocaleMessage(locale: Locale): LocaleMessage<Message> {
    return _composer.value ? _composer.value.getLocaleMessage(locale) : {}
  }

  function setLocaleMessage(locale: Locale, message: LocaleMessage<Message>) {
    if (_composer.value) {
      _composer.value.setLocaleMessage(locale, message)
      _messages.value[locale] = message
    }
  }

  function mergeLocaleMessage(
    locale: Locale,
    message: LocaleMessageDictionary<Message>
  ): void {
    if (_composer.value) {
      _composer.value.mergeLocaleMessage(locale, message)
    }
  }

  function getDateTimeFormat(locale: Locale): DateTimeFormat {
    return _composer.value ? _composer.value.getDateTimeFormat(locale) : {}
  }

  function setDateTimeFormat(locale: Locale, format: DateTimeFormat): void {
    if (_composer.value) {
      _composer.value.setDateTimeFormat(locale, format)
      _datetimeFormats.value[locale] = format
    }
  }

  function mergeDateTimeFormat(locale: Locale, format: DateTimeFormat): void {
    if (_composer.value) {
      _composer.value.mergeDateTimeFormat(locale, format)
    }
  }

  function getNumberFormat(locale: Locale): NumberFormat {
    return _composer.value ? _composer.value.getNumberFormat(locale) : {}
  }

  function setNumberFormat(locale: Locale, format: NumberFormat): void {
    if (_composer.value) {
      _composer.value.setNumberFormat(locale, format)
      _numberFormats.value[locale] = format
    }
  }

  function mergeNumberFormat(locale: Locale, format: NumberFormat): void {
    if (_composer.value) {
      _composer.value.mergeNumberFormat(locale, format)
    }
  }

  const wrapper = {
    get id(): number {
      return _composer.value ? _composer.value.id : -1
    },
    locale,
    fallbackLocale,
    messages,
    datetimeFormats,
    numberFormats,
    get inheritLocale(): boolean {
      return _composer.value ? _composer.value.inheritLocale : _inheritLocale
    },
    set inheritLocale(val: boolean) {
      if (_composer.value) {
        _composer.value.inheritLocale = val
      }
    },
    get availableLocales(): Locale[] {
      return _composer.value
        ? _composer.value.availableLocales
        : Object.keys(_messages.value)
    },
    get modifiers(): LinkedModifiers {
      return (
        _composer.value ? _composer.value.modifiers : _modifiers
      ) as LinkedModifiers
    },
    get pluralRules(): PluralizationRules {
      return (
        _composer.value ? _composer.value.pluralRules : _pluralRules
      ) as PluralizationRules
    },
    get isGlobal(): boolean {
      return _composer.value ? _composer.value.isGlobal : false
    },
    get missingWarn(): boolean | RegExp {
      return _composer.value ? _composer.value.missingWarn : _missingWarn
    },
    set missingWarn(val: boolean | RegExp) {
      if (_composer.value) {
        _composer.value.missingWarn = val
      }
    },
    get fallbackWarn(): boolean | RegExp {
      return _composer.value ? _composer.value.fallbackWarn : _fallbackWarn
    },
    set fallbackWarn(val: boolean | RegExp) {
      if (_composer.value) {
        _composer.value.missingWarn = val
      }
    },
    get fallbackRoot(): boolean {
      return _composer.value ? _composer.value.fallbackRoot : _fallbackRoot
    },
    set fallbackRoot(val: boolean) {
      if (_composer.value) {
        _composer.value.fallbackRoot = val
      }
    },
    get fallbackFormat(): boolean {
      return _composer.value ? _composer.value.fallbackFormat : _fallbackFormat
    },
    set fallbackFormat(val: boolean) {
      if (_composer.value) {
        _composer.value.fallbackFormat = val
      }
    },
    get warnHtmlMessage(): boolean {
      return _composer.value
        ? _composer.value.warnHtmlMessage
        : _warnHtmlMessage
    },
    set warnHtmlMessage(val: boolean) {
      if (_composer.value) {
        _composer.value.warnHtmlMessage = val
      }
    },
    get escapeParameter(): boolean {
      return _composer.value
        ? _composer.value.escapeParameter
        : _escapeParameter
    },
    set escapeParameter(val: boolean) {
      if (_composer.value) {
        _composer.value.escapeParameter = val
      }
    },
    t,
    getPostTranslationHandler,
    setPostTranslationHandler,
    getMissingHandler,
    setMissingHandler,
    rt,
    d,
    n,
    tm,
    te,
    getLocaleMessage,
    setLocaleMessage,
    mergeLocaleMessage,
    getDateTimeFormat,
    setDateTimeFormat,
    mergeDateTimeFormat,
    getNumberFormat,
    setNumberFormat,
    mergeNumberFormat
  }

  function sync(composer: Composer): void {
    composer.locale.value = _locale.value
    composer.fallbackLocale.value = _fallbackLocale.value
    Object.keys(_messages.value).forEach(locale => {
      composer.mergeLocaleMessage(locale, _messages.value[locale])
    })
    Object.keys(_datetimeFormats.value).forEach(locale => {
      composer.mergeDateTimeFormat(locale, _datetimeFormats.value[locale])
    })
    Object.keys(_numberFormats.value).forEach(locale => {
      composer.mergeNumberFormat(locale, _numberFormats.value[locale])
    })
    composer.escapeParameter = _escapeParameter
    composer.fallbackFormat = _fallbackFormat
    composer.fallbackRoot = _fallbackRoot
    composer.fallbackWarn = _fallbackWarn
    composer.missingWarn = _missingWarn
    composer.warnHtmlMessage = _warnHtmlMessage
  }

  onBeforeMount(() => {
    if (instance.proxy == null || instance.proxy.$i18n == null) {
      throw createI18nError(I18nErrorCodes.NOT_AVAILABLE_COMPOSITION_IN_LEGACY)
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const composer = (_composer.value = (instance.proxy.$i18n as any)
      .__composer as Composer)
    if (scope === 'global') {
      _locale.value = composer.locale.value
      _fallbackLocale.value = composer.fallbackLocale.value
      _messages.value = composer.messages.value
      _datetimeFormats.value = composer.datetimeFormats.value
      _numberFormats.value = composer.numberFormats.value
    } else if (isLocale) {
      sync(composer)
    }
  })

  return wrapper as unknown as Composer
}