Skip to content

Commit

Permalink
Merge pull request #51 from vordgi/get-47
Browse files Browse the repository at this point in the history
get-47 format package files
  • Loading branch information
vordgi committed Apr 16, 2024
2 parents a4414b1 + 68419e1 commit ae117ca
Show file tree
Hide file tree
Showing 12 changed files with 1,174 additions and 114 deletions.
22 changes: 22 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import tseslint from "typescript-eslint";

const ignores = ["**/node_modules/**", "**/dist/**", "**/*.js", "**/*.d.ts"];

export default [
{
rules: {
"prettier/prettier": [
"error",
{
endOfLine: "auto",
tabWidth: 4,
printWidth: 120,
arrowParens: "always",
},
],
},
},
...tseslint.configs.recommended,
eslintPluginPrettierRecommended,
].map((r) => Object.assign(r, { ignores }));
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"scripts": {
"nimpl:getters": "pnpm --filter @nimpl/getters",
"tests:nextjs-app": "pnpm --filter tests/nextjs-app",
"tests:server-contexts": "pnpm --filter tests/server-contexts"
"tests:server-contexts": "pnpm --filter tests/server-contexts",
"lint": "eslint \"package/\"",
"eslint": "eslint"
},
"repository": {
"type": "git",
Expand All @@ -16,5 +18,12 @@
"email": "vordgi1@gmail.com",
"url": "https://github.com/vordgi/"
},
"devDependencies": {
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"prettier": "^3.2.5",
"typescript-eslint": "^7.6.0"
},
"license": "MIC"
}
21 changes: 11 additions & 10 deletions package/src/create-server-context.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { ServerContext } from './types';
import { AsyncLocalStorage } from 'async_hooks';
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error';
import React from 'react';
import type { ServerContext } from "./types";
import { AsyncLocalStorage } from "async_hooks";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";
import React from "react";

const Enter = ({ storage, value }: { storage: any, value: any }) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Enter = ({ storage, value }: { storage: AsyncLocalStorage<{ value: unknown }>; value: unknown }) => {
storage.enterWith({ value });
return <></>;
}
};

function createServerContext<T>(defaultValue?: T): ServerContext<T> {
serverGetterInClientComponentError('createServerContext');
serverGetterInClientComponentError("createServerContext");

const storage: ServerContext<T>['_storage'] = new AsyncLocalStorage<{ value: T }>();
const storage: ServerContext<T>["_storage"] = new AsyncLocalStorage<{ value: T }>();

return {
Provider: async ({ children, value }) => {
Expand All @@ -20,15 +21,15 @@ function createServerContext<T>(defaultValue?: T): ServerContext<T> {
<Enter storage={storage} value={value} />
{children}
</>
)
);
},
Consumer: ({ children }) => {
const store = storage.getStore();
return children(store ? store.value : defaultValue);
},
_storage: storage,
_defaultValue: defaultValue,
}
};
}

export default createServerContext;
34 changes: 17 additions & 17 deletions package/src/get-page-config.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import { staticGenerationAsyncStorage } from 'next/dist/client/components/static-generation-async-storage.external'
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error'
import { staticGenerationAsyncStorage } from "next/dist/client/components/static-generation-async-storage.external";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";

export const getPageConfig = () => {
serverGetterInClientComponentError('getPageConfig');
serverGetterInClientComponentError("getPageConfig");

const store = staticGenerationAsyncStorage.getStore();
const store = staticGenerationAsyncStorage.getStore();

if (!store) return {};
if (!store) return {};

const basePath = process.env.__NEXT_ROUTER_BASEPATH || '';
const { pagePath, forceDynamic, forceStatic, dynamicShouldError, revalidate } = store || {};
let dynamic = 'auto';
if (forceDynamic) {
dynamic = 'force-dynamic';
} else if (forceStatic) {
dynamic = 'force-static';
} else if (dynamicShouldError) {
dynamic = 'error';
}
const basePath = process.env.__NEXT_ROUTER_BASEPATH || "";
const { pagePath, forceDynamic, forceStatic, dynamicShouldError, revalidate } = store || {};
let dynamic = "auto";
if (forceDynamic) {
dynamic = "force-dynamic";
} else if (forceStatic) {
dynamic = "force-static";
} else if (dynamicShouldError) {
dynamic = "error";
}

return { pagePath, dynamic, revalidate, basePath };
}
return { pagePath, dynamic, revalidate, basePath };
};
42 changes: 26 additions & 16 deletions package/src/get-params.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
import { staticGenerationAsyncStorage } from 'next/dist/client/components/static-generation-async-storage.external'
import { normalizeInterceptingRoutes, normalizePagePath, normalizePathname, parseSegments } from './utils';
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error';
import { staticGenerationAsyncStorage } from "next/dist/client/components/static-generation-async-storage.external";
import { normalizeInterceptingRoutes, normalizePagePath, normalizePathname, parseSegments } from "./utils";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";

export const getParams = () => {
serverGetterInClientComponentError('getParams');
serverGetterInClientComponentError("getParams");

const store = staticGenerationAsyncStorage.getStore();

if (!store) return {};

const { urlPathname, pagePath = '/' } = store;
const { urlPathname, pagePath = "/" } = store;

const cleanUrlPathname = normalizePathname(urlPathname);
const cleanPagePath = normalizePagePath(pagePath);
const pagePathParts = cleanPagePath.split('/').slice(1).filter(part => !part.match(/^(\([^)]+\)|\@.+)$/));
const pagePathParts = cleanPagePath
.split("/")
.slice(1)
.filter((part) => !part.match(/^(\([^)]+\)|\@.+)$/));
const pagePathInterceptedParts = normalizeInterceptingRoutes(pagePathParts);
const pathnameParts = cleanUrlPathname.split('/').slice(1);
const pathnameParts = cleanUrlPathname.split("/").slice(1);

const isRootPage = cleanUrlPathname === '' && cleanPagePath === '';
const isRootPage = cleanUrlPathname === "" && cleanPagePath === "";
const isNotFoundPage = pagePath.match(/\/_not-found\/?$/);
const isValidCatchALl = cleanPagePath.match(/\/\[\.\.\.[^\]]+\]/) && pathnameParts.length >= pagePathInterceptedParts.length;
const isValidOptionalCatchALl = cleanPagePath.match(/\/\[\[\.\.\.[^\]]+\]\]/) && pathnameParts.length >= pagePathInterceptedParts.length - 1;
const isCorrectMatched = isRootPage || isNotFoundPage || pagePathInterceptedParts.length === pathnameParts.length || isValidCatchALl || isValidOptionalCatchALl;
const isValidCatchALl =
cleanPagePath.match(/\/\[\.\.\.[^\]]+\]/) && pathnameParts.length >= pagePathInterceptedParts.length;
const isValidOptionalCatchALl =
cleanPagePath.match(/\/\[\[\.\.\.[^\]]+\]\]/) && pathnameParts.length >= pagePathInterceptedParts.length - 1;
const isCorrectMatched =
isRootPage ||
isNotFoundPage ||
pagePathInterceptedParts.length === pathnameParts.length ||
isValidCatchALl ||
isValidOptionalCatchALl;

if (!isCorrectMatched) {
const createIssueUrl = new URL('https://github.com/vordgi/nimpl-getters/issues/new')
createIssueUrl.searchParams.set('title', 'Error parsing segments in get-params');
createIssueUrl.searchParams.set('body', `urlPathname: \`${urlPathname}\`;\n\npagePath: \`${pagePath}\`;`);
createIssueUrl.searchParams.append('labels', 'bug');
const createIssueUrl = new URL("https://github.com/vordgi/nimpl-getters/issues/new");
createIssueUrl.searchParams.set("title", "Error parsing segments in get-params");
createIssueUrl.searchParams.set("body", `urlPathname: \`${urlPathname}\`;\n\npagePath: \`${pagePath}\`;`);
createIssueUrl.searchParams.append("labels", "bug");
throw new Error(`Something went wrong. Please create an issue on Github: ${createIssueUrl}`);
}

const query = parseSegments(pagePathInterceptedParts, pathnameParts);
return query;
}
};
26 changes: 12 additions & 14 deletions package/src/get-pathname.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { staticGenerationAsyncStorage } from 'next/dist/client/components/static-generation-async-storage.external'
import { hasBasePath } from 'next/dist/client/has-base-path'
import { removeBasePath } from 'next/dist/client/remove-base-path'
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error'
import { staticGenerationAsyncStorage } from "next/dist/client/components/static-generation-async-storage.external";
import { hasBasePath } from "next/dist/client/has-base-path";
import { removeBasePath } from "next/dist/client/remove-base-path";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";

export function getPathname() {
serverGetterInClientComponentError('getPathname')
serverGetterInClientComponentError("getPathname");

const store = staticGenerationAsyncStorage.getStore()
const store = staticGenerationAsyncStorage.getStore();

if (!store) return null
if (!store) return null;

const { urlPathname } = store
const url = new URL(urlPathname, 'http://n')
const { urlPathname } = store;
const url = new URL(urlPathname, "http://n");

const pathname = hasBasePath(url.pathname)
? removeBasePath(url.pathname)
: url.pathname
const pathname = hasBasePath(url.pathname) ? removeBasePath(url.pathname) : url.pathname;

return pathname
}
return pathname;
}
44 changes: 23 additions & 21 deletions package/src/get-search-params.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
import { staticGenerationAsyncStorage } from 'next/dist/client/components/static-generation-async-storage.external'
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error'
import { ReadonlyURLSearchParams } from 'next/navigation'
import { stripInternalSearchParams } from 'next/dist/server/internal-utils'
import { staticGenerationAsyncStorage } from "next/dist/client/components/static-generation-async-storage.external";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";
import { ReadonlyURLSearchParams } from "next/navigation";
import { stripInternalSearchParams } from "next/dist/server/internal-utils";

/** @deprecated getSearchParams is deprecated. [Read more](https://nimpl.tech/getters/current-getters/get-search-params) */
export function getSearchParams(opts?: { ignoreDynamicOptionErrors?: boolean }) {
serverGetterInClientComponentError('getSearchParams')
console.error('getSearchParams is deprecated. Read more - https://nimpl.tech/getters/current-getters/get-search-params')
serverGetterInClientComponentError("getSearchParams");
console.error(
"getSearchParams is deprecated. Read more - https://nimpl.tech/getters/current-getters/get-search-params",
);

const store = staticGenerationAsyncStorage.getStore()
const store = staticGenerationAsyncStorage.getStore();

if (!store) return new URLSearchParams()
if (!store) return new URLSearchParams();

const { urlPathname, forceStatic, forceDynamic, dynamicShouldError } = store
const { urlPathname, forceStatic, forceDynamic, dynamicShouldError } = store;

if (!opts?.ignoreDynamicOptionErrors) {
if (forceStatic) {
throw new Error('Сannot get client search parameters with dynamic=force-static setting')
} else if (dynamicShouldError) {
throw new Error('Сannot get client search parameters with dynamic=error setting')
} else if (!forceDynamic) {
console.warn('Do not use getSearchParams with unselected dynamic setting, use force-dynamic instead')
if (!opts?.ignoreDynamicOptionErrors) {
if (forceStatic) {
throw new Error("Сannot get client search parameters with dynamic=force-static setting");
} else if (dynamicShouldError) {
throw new Error("Сannot get client search parameters with dynamic=error setting");
} else if (!forceDynamic) {
console.warn("Do not use getSearchParams with unselected dynamic setting, use force-dynamic instead");
}
}
}

const url = new URL(urlPathname, 'http://n')
const strippedUrl = stripInternalSearchParams(url, true)
const readonlySearchParams = new ReadonlyURLSearchParams(strippedUrl.searchParams)
const url = new URL(urlPathname, "http://n");
const strippedUrl = stripInternalSearchParams(url, true);
const readonlySearchParams = new ReadonlyURLSearchParams(strippedUrl.searchParams);

return readonlySearchParams
return readonlySearchParams;
}
6 changes: 3 additions & 3 deletions package/src/get-server-context.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ServerContext } from './types';
import { serverGetterInClientComponentError } from './server-getter-in-client-component-error';
import type { ServerContext } from "./types";
import { serverGetterInClientComponentError } from "./server-getter-in-client-component-error";

function getServerContext<T>({ _storage, _defaultValue }: ServerContext<T>) {
serverGetterInClientComponentError('getServerContext');
serverGetterInClientComponentError("getServerContext");

const store = _storage.getStore();

Expand Down
18 changes: 8 additions & 10 deletions package/src/server-getter-in-client-component-error.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React from 'react'
import React from "react";

export function serverGetterInClientComponentError(
getterName: string
): void | never {
if (process.env.NODE_ENV !== 'production') {
// If useState is defined we're in a client component
if (Boolean(React.useState)) {
throw new Error(`${getterName} only works in Server Components`)
export function serverGetterInClientComponentError(getterName: string): void | never {
if (process.env.NODE_ENV !== "production") {
// If useState is defined we're in a client component
if (Boolean(React.useState)) {
throw new Error(`${getterName} only works in Server Components`);
}
}
}
}
}
6 changes: 3 additions & 3 deletions package/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { AsyncLocalStorage } from "async_hooks";

export type ServerContext<T> = {
Provider: ({ children, value }: { children: React.ReactNode; value: T; }) => React.ReactNode;
Consumer: ({ children }: { children: (context: T | undefined) => React.ReactNode; }) => React.ReactNode;
Provider: ({ children, value }: { children: React.ReactNode; value: T }) => React.ReactNode;
Consumer: ({ children }: { children: (context: T | undefined) => React.ReactNode }) => React.ReactNode;
_storage: AsyncLocalStorage<{ value: T }>;
_defaultValue: T | undefined;
};
};
36 changes: 18 additions & 18 deletions package/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
export const normalizePathname = (pathname: string) => {
const cleanPathname = pathname && new URL(pathname, 'http://n').pathname;
const pathnameWithoutTrailingSlash = cleanPathname?.replace(/^(\/.*)\/$/, '$1');
const pathnameWithoutFileType = pathnameWithoutTrailingSlash?.replace(/\/_not-found$/, '');
return pathnameWithoutFileType || '/';
}
const cleanPathname = pathname && new URL(pathname, "http://n").pathname;
const pathnameWithoutTrailingSlash = cleanPathname?.replace(/^(\/.*)\/$/, "$1");
const pathnameWithoutFileType = pathnameWithoutTrailingSlash?.replace(/\/_not-found$/, "");
return pathnameWithoutFileType || "/";
};

export const normalizePagePath = (pagePath: string) => {
const cleanPagePath = pagePath && new URL(pagePath, 'http://n').pathname;
const pagePathWithoutFileType = cleanPagePath?.replace(/(\/page|\/_not-found)$/, '');
return pagePathWithoutFileType || '/';
}
const cleanPagePath = pagePath && new URL(pagePath, "http://n").pathname;
const pagePathWithoutFileType = cleanPagePath?.replace(/(\/page|\/_not-found)$/, "");
return pagePathWithoutFileType || "/";
};

export const parseSegments = (pagePathParts: string[], pathnameParts: string[]) => {
const query = pagePathParts.reduce<{[key: string]: string | string[]}>((acc, cur, index) => {
const query = pagePathParts.reduce<{ [key: string]: string | string[] }>((acc, cur, index) => {
const optionalCatchAllSegment = cur.match(/^\[\[\.\.\.([^\]]+)\]\]$/);
if (optionalCatchAllSegment) {
const key = optionalCatchAllSegment[1];
Expand Down Expand Up @@ -41,7 +41,7 @@ export const parseSegments = (pagePathParts: string[], pathnameParts: string[])
}, {});

return query;
}
};

export const normalizeInterceptingRoutes = (pageParts: string[]) => {
let skip = 0;
Expand All @@ -53,19 +53,19 @@ export const normalizeInterceptingRoutes = (pageParts: string[]) => {
continue;
}

if (pagepart.startsWith('(...)')) {
normilizedParts.push(pagepart.replace(/^\(\.\.\.\)/, ''));
if (pagepart.startsWith("(...)")) {
normilizedParts.push(pagepart.replace(/^\(\.\.\.\)/, ""));
break;
} else if (pagepart.startsWith('(.)')) {
normilizedParts.push(pagepart.replace(/^\(\.\)/, ''));
} else if (pagepart.startsWith('(..)')) {
} else if (pagepart.startsWith("(.)")) {
normilizedParts.push(pagepart.replace(/^\(\.\)/, ""));
} else if (pagepart.startsWith("(..)")) {
const skipLeafs = pagepart.match(/\(\.\.\)/g);
skip += skipLeafs?.length || 0;
normilizedParts.push(pagepart.replace(/^(\(\.\.\))+/, ''));
normilizedParts.push(pagepart.replace(/^(\(\.\.\))+/, ""));
} else {
normilizedParts.push(pagepart);
}
}

return normilizedParts.reverse();
}
};

0 comments on commit ae117ca

Please sign in to comment.