@real-router/hash-plugin 0.2.11 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/hash-plugin",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "type": "commonjs",
5
5
  "description": "Hash-based routing plugin for Real-Router",
6
6
  "main": "./dist/cjs/index.js",
@@ -18,8 +18,7 @@
18
18
  }
19
19
  },
20
20
  "files": [
21
- "dist",
22
- "src"
21
+ "dist"
23
22
  ],
24
23
  "repository": {
25
24
  "type": "git",
@@ -43,7 +42,7 @@
43
42
  },
44
43
  "sideEffects": false,
45
44
  "dependencies": {
46
- "@real-router/core": "^0.45.0"
45
+ "@real-router/core": "^0.45.1"
47
46
  },
48
47
  "devDependencies": {
49
48
  "@testing-library/jest-dom": "6.9.1",
@@ -57,7 +56,7 @@
57
56
  "build": "tsdown --config-loader unrun",
58
57
  "type-check": "tsc --noEmit",
59
58
  "lint": "eslint --cache --ext .ts src/ tests/ --fix --max-warnings 0",
60
- "lint:package": "publint",
59
+ "lint:package": "bash ../../scripts/publint-filter.sh",
61
60
  "lint:types": "attw --pack .",
62
61
  "build:dist-only": "tsdown --config-loader unrun"
63
62
  }
package/src/constants.ts DELETED
@@ -1,16 +0,0 @@
1
- // packages/hash-plugin/src/constants.ts
2
-
3
- import type { HashPluginOptions } from "./types";
4
-
5
- export const defaultOptions: Required<HashPluginOptions> = {
6
- hashPrefix: "",
7
- base: "",
8
- forceDeactivate: true,
9
- };
10
-
11
- /**
12
- * Source identifier for transitions triggered by browser events.
13
- */
14
- export const source = "popstate";
15
-
16
- export const LOGGER_CONTEXT = "hash-plugin";
package/src/factory.ts DELETED
@@ -1,59 +0,0 @@
1
- import { getPluginApi } from "@real-router/core/api";
2
- import {
3
- createSafeBrowser,
4
- normalizeBase,
5
- safelyEncodePath,
6
- } from "browser-env";
7
-
8
- import { defaultOptions, source } from "./constants";
9
- import { createHashPrefixRegex, extractHashPath } from "./hash-utils";
10
- import { HashPlugin } from "./plugin";
11
- import { validateOptions } from "./validation";
12
-
13
- import type { HashPluginOptions } from "./types";
14
- import type { PluginFactory, Router } from "@real-router/core";
15
- import type { Browser, SharedFactoryState } from "browser-env";
16
-
17
- export function hashPluginFactory(
18
- opts?: Partial<HashPluginOptions>,
19
- browser?: Browser,
20
- ): PluginFactory {
21
- validateOptions(opts);
22
-
23
- const options: Required<HashPluginOptions> = { ...defaultOptions, ...opts };
24
-
25
- options.base = normalizeBase(options.base);
26
-
27
- const prefixRegex = createHashPrefixRegex(options.hashPrefix);
28
- const resolvedBrowser =
29
- browser ??
30
- createSafeBrowser(
31
- () =>
32
- safelyEncodePath(
33
- extractHashPath(globalThis.location.hash, prefixRegex),
34
- ) + globalThis.location.search,
35
- "hash-plugin",
36
- );
37
-
38
- const transitionOptions = {
39
- forceDeactivate: options.forceDeactivate,
40
- source,
41
- replace: true as const,
42
- };
43
-
44
- const shared: SharedFactoryState = { removePopStateListener: undefined };
45
-
46
- return function hashPlugin(routerBase) {
47
- const plugin = new HashPlugin(
48
- routerBase as Router,
49
- getPluginApi(routerBase),
50
- options,
51
- resolvedBrowser,
52
- prefixRegex,
53
- transitionOptions,
54
- shared,
55
- );
56
-
57
- return plugin.getPlugin();
58
- };
59
- }
package/src/hash-utils.ts DELETED
@@ -1,44 +0,0 @@
1
- // packages/hash-plugin/src/hash-utils.ts
2
-
3
- import { safeParseUrl } from "browser-env";
4
-
5
- import { LOGGER_CONTEXT } from "./constants";
6
-
7
- function escapeRegExp(str: string): string {
8
- return str.replaceAll(/[$()*+.?[\\\]^{|}-]/g, String.raw`\$&`);
9
- }
10
-
11
- export function createHashPrefixRegex(hashPrefix: string): RegExp | null {
12
- if (!hashPrefix) {
13
- return null;
14
- }
15
-
16
- return new RegExp(`^#${escapeRegExp(hashPrefix)}`);
17
- }
18
-
19
- /**
20
- * Extract path from URL hash, stripping hash prefix.
21
- *
22
- * @param hash - URL hash (e.g., "#/path" or "#!/path")
23
- * @param prefixRegex - Pre-compiled regex for prefix stripping (null if no prefix)
24
- * @returns Extracted path (e.g., "/path")
25
- */
26
- export function extractHashPath(
27
- hash: string,
28
- prefixRegex: RegExp | null,
29
- ): string {
30
- const path = prefixRegex ? hash.replace(prefixRegex, "") : hash.slice(1);
31
-
32
- return path || "/";
33
- }
34
-
35
- export function hashUrlToPath(
36
- url: string,
37
- prefixRegex: RegExp | null,
38
- ): string | null {
39
- const parsedUrl = safeParseUrl(url, LOGGER_CONTEXT);
40
-
41
- return parsedUrl
42
- ? extractHashPath(parsedUrl.hash, prefixRegex) + parsedUrl.search
43
- : null;
44
- }
package/src/index.ts DELETED
@@ -1,48 +0,0 @@
1
- // packages/hash-plugin/src/index.ts
2
- /* eslint-disable @typescript-eslint/method-signature-style -- method syntax required for declaration merging overload (property syntax causes TS2717) */
3
- // Public API exports for hash-plugin
4
-
5
- import type { Params, State } from "@real-router/core";
6
-
7
- // Main plugin factory
8
- export { hashPluginFactory } from "./factory";
9
-
10
- // Types
11
- export type { HashPluginOptions } from "./types";
12
-
13
- export type { Browser } from "browser-env";
14
-
15
- // Type guards
16
- export { isStateStrict as isState } from "type-guards";
17
-
18
- /**
19
- * Module augmentation for real-router.
20
- * Extends Router interface with hash plugin methods.
21
- */
22
- declare module "@real-router/core" {
23
- interface Router {
24
- /**
25
- * Builds full URL for a route with base path and hash prefix.
26
- * Added by hash plugin.
27
- */
28
- buildUrl: (name: string, params?: Params) => string;
29
-
30
- /**
31
- * Matches URL and returns corresponding state.
32
- * Added by hash plugin.
33
- */
34
- matchUrl: (url: string) => State | undefined;
35
-
36
- /**
37
- * Replaces current history state without triggering navigation.
38
- * Added by hash plugin.
39
- */
40
- replaceHistoryState: (
41
- name: string,
42
- params?: Params,
43
- title?: string,
44
- ) => void;
45
-
46
- start(path?: string): Promise<State>;
47
- }
48
- }
package/src/plugin.ts DELETED
@@ -1,110 +0,0 @@
1
- import {
2
- createPopstateHandler,
3
- createPopstateLifecycle,
4
- createStartInterceptor,
5
- createReplaceHistoryState,
6
- shouldReplaceHistory,
7
- updateBrowserState,
8
- } from "browser-env";
9
-
10
- import { hashUrlToPath } from "./hash-utils";
11
-
12
- import type { HashPluginOptions } from "./types";
13
- import type {
14
- NavigationOptions,
15
- Params,
16
- Router,
17
- State,
18
- Plugin,
19
- } from "@real-router/core";
20
- import type { PluginApi } from "@real-router/core/api";
21
- import type { Browser, SharedFactoryState } from "browser-env";
22
-
23
- export class HashPlugin {
24
- readonly #router: Router;
25
- readonly #browser: Browser;
26
- readonly #removeStartInterceptor: () => void;
27
- readonly #removeExtensions: () => void;
28
- readonly #lifecycle: Pick<Plugin, "onStart" | "onStop" | "teardown">;
29
-
30
- constructor(
31
- router: Router,
32
- api: PluginApi,
33
- options: Required<HashPluginOptions>,
34
- browser: Browser,
35
- prefixRegex: RegExp | null,
36
- transitionOptions: {
37
- source: string;
38
- replace: true;
39
- forceDeactivate?: boolean;
40
- },
41
- shared: SharedFactoryState,
42
- ) {
43
- this.#router = router;
44
- this.#browser = browser;
45
-
46
- this.#removeStartInterceptor = createStartInterceptor(api, browser);
47
-
48
- const urlPrefix = `${options.base}#${options.hashPrefix}`;
49
- const pluginBuildUrl = (route: string, params?: Params) =>
50
- urlPrefix + router.buildPath(route, params);
51
-
52
- this.#removeExtensions = api.extendRouter({
53
- buildUrl: pluginBuildUrl,
54
- matchUrl: (url: string) => {
55
- const path = hashUrlToPath(url, prefixRegex);
56
-
57
- return path ? api.matchPath(path) : undefined;
58
- },
59
- replaceHistoryState: createReplaceHistoryState(
60
- api,
61
- router,
62
- browser,
63
- pluginBuildUrl,
64
- ),
65
- });
66
-
67
- const handler = createPopstateHandler({
68
- router,
69
- api,
70
- browser,
71
- allowNotFound: api.getOptions().allowNotFound,
72
- transitionOptions,
73
- loggerContext: "hash-plugin",
74
- buildUrl: (name: string, params?: Params) =>
75
- router.buildUrl(name, params),
76
- });
77
-
78
- this.#lifecycle = createPopstateLifecycle({
79
- browser,
80
- shared,
81
- handler,
82
- cleanup: () => {
83
- this.#removeStartInterceptor();
84
- this.#removeExtensions();
85
- },
86
- });
87
- }
88
-
89
- getPlugin(): Plugin {
90
- return {
91
- ...this.#lifecycle,
92
-
93
- onTransitionSuccess: (
94
- toState: State,
95
- fromState: State | undefined,
96
- navOptions: NavigationOptions,
97
- ) => {
98
- const replaceHistory = shouldReplaceHistory(
99
- navOptions,
100
- toState,
101
- fromState,
102
- );
103
-
104
- const url = this.#router.buildUrl(toState.name, toState.params);
105
-
106
- updateBrowserState(toState, url, replaceHistory, this.#browser);
107
- },
108
- };
109
- }
110
- }
package/src/types.ts DELETED
@@ -1,28 +0,0 @@
1
- // packages/hash-plugin/src/types.ts
2
-
3
- /**
4
- * Hash-based routing plugin configuration.
5
- * Uses URL hash fragment for navigation (e.g., example.com/#/path).
6
- */
7
- export interface HashPluginOptions {
8
- /**
9
- * Prefix for hash (e.g., "!" for "#!/path").
10
- *
11
- * @default ""
12
- */
13
- hashPrefix?: string;
14
-
15
- /**
16
- * Base path prepended before hash (e.g., "/app" → "/app#/path").
17
- *
18
- * @default ""
19
- */
20
- base?: string;
21
-
22
- /**
23
- * Force deactivation of current route even if canDeactivate returns false.
24
- *
25
- * @default true
26
- */
27
- forceDeactivate?: boolean;
28
- }
package/src/validation.ts DELETED
@@ -1,10 +0,0 @@
1
- import { createOptionsValidator } from "browser-env";
2
-
3
- import { LOGGER_CONTEXT, defaultOptions } from "./constants";
4
-
5
- import type { HashPluginOptions } from "./types";
6
-
7
- export const validateOptions = createOptionsValidator<HashPluginOptions>(
8
- defaultOptions,
9
- LOGGER_CONTEXT,
10
- );