// src/composables/clientData.ts
import { inject } from "vue";
var clientDataSymbol = Symbol(
  __VUEPRESS_DEV__ ? "clientData" : ""
);
var useClientData = () => {
  const clientData = inject(clientDataSymbol);
  if (!clientData) {
    throw new Error("useClientData() is called without provider.");
  }
  return clientData;
};

// src/composables/clientDataUtils.ts
var useLayouts = () => useClientData().layouts;
var usePageComponent = () => useClientData().pageComponent;
var usePageData = () => useClientData().pageData;
var usePageFrontmatter = () => useClientData().pageFrontmatter;
var usePageHead = () => useClientData().pageHead;
var usePageLang = () => useClientData().pageLang;
var usePageLayout = () => useClientData().pageLayout;
var useRedirects = () => useClientData().redirects;
var useRouteLocale = () => useClientData().routeLocale;
var useRoutePath = () => useClientData().routePath;
var useRoutes = () => useClientData().routes;
var useSiteData = () => useClientData().siteData;
var useSiteLocaleData = () => useClientData().siteLocaleData;

// src/composables/updateHead.ts
import { inject as inject2 } from "vue";
var updateHeadSymbol = Symbol(
  __VUEPRESS_DEV__ ? "updateHead" : ""
);
var useUpdateHead = () => {
  const updateHead = inject2(updateHeadSymbol);
  if (!updateHead) {
    throw new Error("useUpdateHead() is called without provider.");
  }
  return updateHead;
};

// src/router/resolveRoutePath.ts
import { normalizeRoutePath } from "@vuepress/shared";

// src/internal/routes.ts
import {
  redirects as redirectsRaw,
  routes as routesRaw
} from "@internal/routes";
import { shallowRef } from "vue";
var redirects = shallowRef(redirectsRaw);
var routes = shallowRef(routesRaw);
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
  __VUE_HMR_RUNTIME__.updateRedirects = (data) => {
    redirects.value = data;
  };
  __VUE_HMR_RUNTIME__.updateRoutes = (data) => {
    routes.value = data;
  };
}

// src/router/resolveRoutePath.ts
var resolveRoutePath = (pathname, currentPath) => {
  const normalizedRoutePath = normalizeRoutePath(pathname, currentPath);
  if (routes.value[normalizedRoutePath]) return normalizedRoutePath;
  const encodedRoutePath = encodeURI(normalizedRoutePath);
  if (routes.value[encodedRoutePath]) {
    return encodedRoutePath;
  }
  const redirectedRoutePath = redirects.value[normalizedRoutePath] || redirects.value[encodedRoutePath];
  if (redirectedRoutePath) {
    return redirectedRoutePath;
  }
  return normalizedRoutePath;
};

// src/router/resolveRoute.ts
import { splitPath } from "@vuepress/shared";
var resolveRoute = (path, currentPath) => {
  const { pathname, hashAndQueries } = splitPath(path);
  const routePath = resolveRoutePath(pathname, currentPath);
  const routeFullPath = routePath + hashAndQueries;
  if (!routes.value[routePath]) {
    return {
      ...routes.value["/404.html"],
      path: routeFullPath,
      notFound: true
    };
  }
  return {
    ...routes.value[routePath],
    path: routeFullPath,
    notFound: false
  };
};

// src/router/resolveRouteFullPath.ts
import { splitPath as splitPath2 } from "@vuepress/shared";
var resolveRouteFullPath = (path, currentPath) => {
  const { pathname, hashAndQueries } = splitPath2(path);
  return resolveRoutePath(pathname, currentPath) + hashAndQueries;
};

// src/router/index.ts
import { useRoute, useRouter } from "vue-router";

// src/components/RouteLink.ts
import { computed, defineComponent, h } from "vue";
import { useRoute as useRoute2, useRouter as useRouter2 } from "vue-router";
var guardEvent = (event) => {
  if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) return;
  if (event.defaultPrevented) return;
  if (event.button !== void 0 && event.button !== 0) return;
  if (event.currentTarget) {
    const target = event.currentTarget.getAttribute("target");
    if (target?.match(/\b_blank\b/i)) return;
  }
  event.preventDefault();
  return true;
};
var RouteLink = defineComponent({
  name: "RouteLink",
  props: {
    /**
     * The route path to link to
     */
    to: {
      type: String,
      required: true
    },
    /**
     * Whether the link is active to have an active class
     *
     * Notice that the active status is not automatically determined according to the current route.
     */
    active: Boolean,
    /**
     * The class to add when the link is active
     */
    activeClass: {
      type: String,
      default: "route-link-active"
    }
  },
  slots: Object,
  setup(props, { slots }) {
    const router = useRouter2();
    const route = useRoute2();
    const path = computed(
      () => props.to.startsWith("#") || props.to.startsWith("?") ? props.to : `${__VUEPRESS_BASE__}${resolveRouteFullPath(props.to, route.path).substring(1)}`
    );
    return () => h(
      "a",
      {
        class: ["route-link", { [props.activeClass]: props.active }],
        href: path.value,
        onClick: (event = {}) => {
          if (guardEvent(event)) {
            router.push(props.to).catch();
          }
        }
      },
      slots.default?.()
    );
  }
});

// src/components/AutoLink.ts
import { isLinkWithProtocol } from "@vuepress/shared";
import { computed as computed2, defineComponent as defineComponent2, h as h2, toRef } from "vue";
import { useRoute as useRoute3 } from "vue-router";
var AutoLink = defineComponent2({
  name: "AutoLink",
  props: {
    config: {
      type: Object,
      required: true
    }
  },
  slots: Object,
  setup(props, { slots }) {
    const config = toRef(props, "config");
    const route = useRoute3();
    const siteData = useSiteData();
    const withProtocol = computed2(() => isLinkWithProtocol(config.value.link));
    const linkTarget = computed2(
      () => config.value.target || (withProtocol.value ? "_blank" : void 0)
    );
    const isBlankTarget = computed2(() => linkTarget.value === "_blank");
    const isInternal = computed2(
      () => !withProtocol.value && !isBlankTarget.value
    );
    const linkRel = computed2(
      () => config.value.rel || (isBlankTarget.value ? "noopener noreferrer" : null)
    );
    const linkAriaLabel = computed2(
      () => config.value.ariaLabel ?? config.value.text
    );
    const shouldBeActiveInSubpath = computed2(() => {
      if (config.value.exact) return false;
      const localePaths = Object.keys(siteData.value.locales);
      return localePaths.length ? (
        // Check all the locales
        localePaths.every((key) => key !== config.value.link)
      ) : (
        // Check root
        config.value.link !== "/"
      );
    });
    const isActive = computed2(() => {
      if (!isInternal.value) return false;
      if (config.value.activeMatch) {
        return (config.value.activeMatch instanceof RegExp ? config.value.activeMatch : new RegExp(config.value.activeMatch, "u")).test(route.path);
      }
      if (shouldBeActiveInSubpath.value) {
        return route.path.startsWith(config.value.link);
      }
      return route.path === config.value.link;
    });
    return () => {
      const { before, after, default: defaultSlot } = slots;
      const content = defaultSlot?.(config.value) || [
        before?.(config.value),
        config.value.text,
        after?.(config.value)
      ];
      return isInternal.value ? h2(
        RouteLink,
        {
          "class": "auto-link",
          "to": config.value.link,
          "active": isActive.value,
          "aria-label": linkAriaLabel.value
        },
        () => content
      ) : h2(
        "a",
        {
          "class": "auto-link external-link",
          "href": config.value.link,
          "aria-label": linkAriaLabel.value,
          "rel": linkRel.value,
          "target": linkTarget.value
        },
        content
      );
    };
  }
});

// src/components/ClientOnly.ts
import { defineComponent as defineComponent3, onMounted, ref } from "vue";
var ClientOnly = defineComponent3({
  name: "ClientOnly",
  setup(_, ctx) {
    const isMounted = ref(false);
    onMounted(() => {
      isMounted.value = true;
    });
    return () => isMounted.value ? ctx.slots.default?.() : null;
  }
});

// src/components/Content.ts
import { computed as computed3, defineAsyncComponent, defineComponent as defineComponent4, h as h3 } from "vue";
var Content = defineComponent4({
  // eslint-disable-next-line vue/no-reserved-component-names
  name: "Content",
  props: {
    path: {
      type: String,
      required: false,
      default: ""
    }
  },
  setup(props) {
    const pageComponent = usePageComponent();
    const ContentComponent = computed3(() => {
      if (!props.path) return pageComponent.value;
      const route = resolveRoute(props.path);
      return defineAsyncComponent(() => route.loader().then(({ comp }) => comp));
    });
    return () => h3(ContentComponent.value);
  }
});

// src/resolvers.ts
import { dedupeHead, isString, resolveLocalePath } from "@vuepress/shared";
import { reactive } from "vue";

// src/constants.ts
var LAYOUT_NAME_DEFAULT = "Layout";
var LANG_DEFAULT = "en-US";

// src/resolvers.ts
var resolvers = reactive({
  /**
   * Resolve layouts component map
   */
  resolveLayouts: (clientConfigs) => clientConfigs.reduce(
    (prev, item) => ({
      ...prev,
      ...item.layouts
    }),
    {}
  ),
  /**
   * Merge the head config in frontmatter and site locale
   *
   * Frontmatter should take priority over site locale
   */
  resolvePageHead: (pageHeadTitle, pageFrontmatter, siteLocaleDate) => {
    const description = isString(pageFrontmatter.description) ? pageFrontmatter.description : siteLocaleDate.description;
    const head = [
      ...Array.isArray(pageFrontmatter.head) ? pageFrontmatter.head : [],
      ...siteLocaleDate.head,
      ["title", {}, pageHeadTitle],
      ["meta", { name: "description", content: description }]
    ];
    return dedupeHead(head);
  },
  /**
   * Resolve the content of page head title
   *
   * It would be used as the content of the `<title>` tag
   */
  resolvePageHeadTitle: (pageData, siteLocaleDate) => [pageData.title, siteLocaleDate.title].filter((item) => !!item).join(" | "),
  /**
   * Resolve page language from page data
   *
   * It would be used as the `lang` attribute of `<html>` tag
   */
  resolvePageLang: (pageData, siteLocaleData) => pageData.lang || siteLocaleData.lang || LANG_DEFAULT,
  /**
   * Resolve layout component of current page
   */
  resolvePageLayout: (pageData, layouts) => {
    const layoutName = isString(pageData.frontmatter.layout) ? pageData.frontmatter.layout : LAYOUT_NAME_DEFAULT;
    if (!layouts[layoutName]) {
      throw new Error(`[vuepress] Cannot resolve layout: ${layoutName}`);
    }
    return layouts[layoutName];
  },
  /**
   * Resolve locale path according to route path and locales config
   */
  resolveRouteLocale: (locales, routePath) => resolveLocalePath(locales, decodeURI(routePath)),
  /**
   * Resolve site data for specific locale
   *
   * It would merge the locales fields to the root fields
   */
  resolveSiteLocaleData: ({ base, locales, ...siteData }, routeLocale) => ({
    ...siteData,
    ...locales[routeLocale],
    head: [
      // when merging head, the locales head should be placed before root head
      // to get higher priority
      ...locales[routeLocale]?.head ?? [],
      ...siteData.head ?? []
    ]
  })
});

// src/utils/defineClientConfig.ts
var defineClientConfig = (clientConfig = {}) => clientConfig;

// src/utils/withBase.ts
import { isLinkHttp, removeLeadingSlash } from "@vuepress/shared";
var withBase = (url) => {
  if (isLinkHttp(url)) return url;
  return `${__VUEPRESS_BASE__}${removeLeadingSlash(url)}`;
};

export {
  clientDataSymbol,
  useClientData,
  useLayouts,
  usePageComponent,
  usePageData,
  usePageFrontmatter,
  usePageHead,
  usePageLang,
  usePageLayout,
  useRedirects,
  useRouteLocale,
  useRoutePath,
  useRoutes,
  useSiteData,
  useSiteLocaleData,
  updateHeadSymbol,
  useUpdateHead,
  redirects,
  routes,
  resolveRoutePath,
  resolveRoute,
  resolveRouteFullPath,
  useRoute,
  useRouter,
  RouteLink,
  AutoLink,
  ClientOnly,
  Content,
  resolvers,
  defineClientConfig,
  withBase
};
