From 6e256af7b66aff1b790ecd633bd3e17aac67a544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Brajevi=C4=87?= Date: Wed, 6 Nov 2019 21:55:09 +0100 Subject: [PATCH] Added support for both es and cjs modules. --- .gitignore | 4 + handler.js | 3 - index.js | 3 - link.js | 3 - package.json | 16 ++-- router.js | 3 - src/Link.tsx | 36 -------- src/NextRoute.ts | 52 ------------ src/Route.ts | 119 --------------------------- src/Router.ts | 46 ----------- src/Routes.ts | 13 --- src/getRequestHandler.ts | 16 ---- src/index.ts | 6 ++ src/lib/deepClone.ts | 27 ------ src/{lib => utils}/formatUrl.ts | 0 src/{lib => utils}/generatePath.ts | 0 src/{lib => utils}/isAbsolutePath.ts | 0 src/{lib => utils}/isFunction.ts | 0 src/{lib => utils}/mapValues.ts | 0 tests/Route.test.ts | 3 +- tests/Routes.test.ts | 4 +- tests/formatUrl.test.ts | 2 +- tests/generatePath.test.ts | 2 +- tests/isAbsolutePath.test.ts | 2 +- tests/isFunction.test.ts | 2 +- tests/mapValues.test.ts | 2 +- tsconfig.json | 9 +- 27 files changed, 32 insertions(+), 341 deletions(-) delete mode 100644 handler.js delete mode 100644 index.js delete mode 100644 link.js delete mode 100644 router.js delete mode 100644 src/Link.tsx delete mode 100644 src/NextRoute.ts delete mode 100644 src/Route.ts delete mode 100644 src/Router.ts delete mode 100644 src/Routes.ts delete mode 100644 src/getRequestHandler.ts create mode 100644 src/index.ts delete mode 100644 src/lib/deepClone.ts rename src/{lib => utils}/formatUrl.ts (100%) rename src/{lib => utils}/generatePath.ts (100%) rename src/{lib => utils}/isAbsolutePath.ts (100%) rename src/{lib => utils}/isFunction.ts (100%) rename src/{lib => utils}/mapValues.ts (100%) diff --git a/.gitignore b/.gitignore index 6704566..c359043 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,7 @@ dist # TernJS port file .tern-port + +# Build-generated files +es +lib \ No newline at end of file diff --git a/handler.js b/handler.js deleted file mode 100644 index 5c6b93a..0000000 --- a/handler.js +++ /dev/null @@ -1,3 +0,0 @@ -const { getRequestHandler } = require('./dist/getRequestHandler'); - -module.exports = getRequestHandler; diff --git a/index.js b/index.js deleted file mode 100644 index 14f2e2e..0000000 --- a/index.js +++ /dev/null @@ -1,3 +0,0 @@ -const { Route } = require('./dist/Route'); - -module.exports = Route; diff --git a/link.js b/link.js deleted file mode 100644 index 9bf5013..0000000 --- a/link.js +++ /dev/null @@ -1,3 +0,0 @@ -const { Link } = require('./dist/Link'); - -module.exports = Link; diff --git a/package.json b/package.json index 7e385b2..2777616 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "next-universal-route", - "version": "0.6.1", + "version": "0.7.0", "description": "Universal Next.js Route", - "main": "index.js", + "main": "./lib/index.js", + "module": "./es/index.js", + "modules.root": "./es", + "types": "./lib/index.d.ts", "author": "Miloš Brajević ", "repository": "brajevicm/next-universal-route", "license": "MIT", @@ -10,9 +13,10 @@ "lint": "tslint -c tslint.json --project tsconfig.json", "test": "jest --config jest.config.json && codecov", "test:watch": "jest --config jest.config.json --watchAll", - "build": "rimraf ./dist && tsc" + "build": " rimraf ./dist && npm run build:es && npm run build:lib", + "build:es": "tsc --module es2015 --target es5 --outDir es", + "build:lib": "tsc --module commonjs --target es5 --outDir lib" }, - "typings": "./dist/index.d.ts", "keywords": [ "react", "next", @@ -46,8 +50,8 @@ "typescript": "^3.6.4" }, "peerDependencies": { - "next": "^9", - "react": "^16" + "next": ">=2", + "react": "^15.4.2 || ^16" }, "dependencies": { "path-to-regexp": "^3.1.0", diff --git a/router.js b/router.js deleted file mode 100644 index 41d216d..0000000 --- a/router.js +++ /dev/null @@ -1,3 +0,0 @@ -const { Router } = require('./dist/Router'); - -module.exports = Router; diff --git a/src/Link.tsx b/src/Link.tsx deleted file mode 100644 index 3f66ec7..0000000 --- a/src/Link.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, { Children, ReactChildren } from 'react'; -import NextLink from 'next/link'; - -import { NextRoute } from './NextRoute'; - -type LinkProps = { - href: NextRoute | string; - replace?: boolean; - scroll?: boolean; - shallow?: boolean; - passHref?: boolean; - prefetch?: boolean; - children?: ReactChildren; -}; - -export const Link = (props: LinkProps) => { - const { href, ...rest } = props; - const newHref = typeof href === 'string' ? href : href.toHref(); - - if (typeof href === 'string' || href.isAbsolutePath) { - const child: any = Children.only(props.children); - const { children, ...newRest } = rest; - - if (props.passHref || (child.type === 'a' && !('href' in child.props))) { - return React.cloneElement(child, { href: newHref, ...newRest }); - } - - return ( - - {children} - - ); - } - - return ; -}; diff --git a/src/NextRoute.ts b/src/NextRoute.ts deleted file mode 100644 index 07156d4..0000000 --- a/src/NextRoute.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { stringify } from 'qs'; -import { generatePath } from './lib/generatePath'; -import { isAbsolutePath } from './lib/isAbsolutePath'; - -export class NextRoute { - public path: string; - public page?: string; - public params?: object; - public queryStringParams?: object; - public query?: object; - public isAbsolutePath: boolean; - - constructor( - path: string, - page?: string, - params?: object, - queryStringParams?: object, - query?: object - ) { - this.path = path; - this.page = page; - this.params = params; - this.queryStringParams = queryStringParams; - this.query = query; - this.isAbsolutePath = isAbsolutePath(path); - } - - public toAs(): string { - if (this.isAbsolutePath) { - return this.path; - } - - const path = generatePath(this.path, this.params); - const queryString = stringify(this.queryStringParams); - - return queryString ? `${path}?${queryString}` : path; - } - - public toHref(): string { - if (this.isAbsolutePath) { - return this.path; - } - - const queryString = stringify({ - ...this.query, - ...this.params, - ...this.queryStringParams - }); - - return queryString ? `${this.page}?${queryString}` : this.page; - } -} diff --git a/src/Route.ts b/src/Route.ts deleted file mode 100644 index 07539f7..0000000 --- a/src/Route.ts +++ /dev/null @@ -1,119 +0,0 @@ -import pathToRegexp from 'path-to-regexp'; -import { parse } from 'url'; - -import { NextRoute } from './NextRoute'; -import { isFunction } from './lib/isFunction'; -import { mapValues } from './lib/mapValues'; -import { formatUrl } from './lib/formatUrl'; - -export class Route { - public path: string; - public page?: string; - private _query: object; - private urlFormatter?: Function; - private params: object; - private queryStringParams: object; - - constructor(path: string, page?: string, urlFormatter?: Function) { - this.path = path; - this.setPage(`/${page}`); - this.urlFormatter = urlFormatter; - this.params = {}; - this.queryStringParams = {}; - } - - get query() { - return { ...this._query, ...this.queryStringParams }; - } - - public generateUrl(params: object = {}, queryStringParams?: object) { - const newParams = this.formatUrl({ ...this.params, ...params }); - const newQueryStringParams = this.formatUrl({ - ...this.queryStringParams, - ...queryStringParams - }); - - return new NextRoute( - this.path, - this.page, - newParams, - newQueryStringParams, - this._query - ); - } - - public generateFromUrl(url: string, params: object): NextRoute { - const { pathname, query } = this.parseUrl(url); - const keys = []; - const regex = pathToRegexp(this.path, keys); - const values = regex.exec(pathname); - - const newParams = this.getQuery(values.slice(1), keys); - const queryStringParams = { - ...this.queryStringParams, - ...query, - ...params - }; - - return this.generateUrl(newParams, queryStringParams); - } - - public isMatch(url: string) { - const { pathname, query } = this.parseUrl(url); - - const keys = []; - const regex = pathToRegexp(this.path, keys); - const isMatch = regex.test(pathname); - - if (isMatch) { - const values = regex.exec(pathname); - - this._query = { - ...this._query, - ...this.getQuery(values.slice(1), keys) - }; - - this.queryStringParams = query; - } - - return isMatch; - } - - private setPage(url: string): void { - const { pathname, query } = this.parseUrl(url); - - this._query = query; - this.page = pathname; - } - - private formatUrl(params: object): object { - let fn: Function = formatUrl; - - if (isFunction(this.urlFormatter)) { - fn = (string: string) => formatUrl(this.urlFormatter(string)); - } - - return mapValues(params, (param: string | number) => - typeof param === 'string' ? fn(param) : param - ); - } - - private getQuery(values, keys) { - return values.reduce((params, val, i) => { - return { - ...params, - [keys[i].name]: decodeURIComponent(val) - }; - }, {}); - } - - private parseUrl(url: string) { - const parsedUrl = parse(url, true); - const { pathname, query } = parsedUrl; - - return { - pathname, - query - }; - } -} diff --git a/src/Router.ts b/src/Router.ts deleted file mode 100644 index de37e78..0000000 --- a/src/Router.ts +++ /dev/null @@ -1,46 +0,0 @@ -import NextRouter, { NextRouter as NextRouterType } from 'next/router'; - -import { Route } from './Route'; -import { NextRoute } from './NextRoute'; - -// import { clone } from './lib/deepClone'; - -// TODO: Find the way to replace Next's Router completely -// const ClonedRouter = ((router: NextRouterType) => { -// const newRouter = clone(router); - -// newRouter.push = (href: NextRoute, options?: object) => -// router.push(href.toHref(), href.toAs(), options); - -// newRouter.prefetch = (href: NextRoute) => router.prefetch(href.toHref()); - -// newRouter.replace = (href: NextRoute, options?: object) => -// router.replace(href.toHref(), href.toAs(), options); - -// return newRouter; -// })(NextRouter); - -export const Router = ((router: NextRouterType) => { - const push = (href: NextRoute, options?: object) => - router.push(href.toHref(), href.toAs(), options); - - const prefetch = (href: NextRoute) => router.prefetch(href.toHref()); - - const replace = (href: NextRoute, options?: object) => - router.replace(href.toHref(), href.toAs(), options); - - const update = (href: Route, params: object) => - push( - href.generateFromUrl( - `${window.location.pathname}${window.location.search}`, - params - ) - ); - - return { - push, - prefetch, - replace, - update - }; -})(NextRouter); diff --git a/src/Routes.ts b/src/Routes.ts deleted file mode 100644 index 5e2fc43..0000000 --- a/src/Routes.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Route } from './Route'; - -export class Routes { - private routes: Route[]; - - constructor(routes) { - this.routes = Object.values(routes); - } - - public getRoute(url: string) { - return this.routes.filter(route => route.isMatch(url))[0]; - } -} diff --git a/src/getRequestHandler.ts b/src/getRequestHandler.ts deleted file mode 100644 index b0a89e7..0000000 --- a/src/getRequestHandler.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Routes } from './Routes'; - -export const getRequestHandler = (app, routes) => { - const nextHandler = app.getRequestHandler(); - const router = new Routes(routes); - - return (req, res) => { - const route = router.getRoute(req.url); - - if (route) { - app.render(req, res, route.page, route.query); - } else { - nextHandler(req, res, req.url); - } - }; -}; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..e19b1ac --- /dev/null +++ b/src/index.ts @@ -0,0 +1,6 @@ +import { Link } from './lib/Link'; +import { Router } from './lib/Router'; +import { Route } from './lib/Route'; +import { getRequestHandler } from './lib/getRequestHandler'; + +export { getRequestHandler, Route, Router, Link }; diff --git a/src/lib/deepClone.ts b/src/lib/deepClone.ts deleted file mode 100644 index fc8920a..0000000 --- a/src/lib/deepClone.ts +++ /dev/null @@ -1,27 +0,0 @@ -export const clone = obj => { - let copy; - - if (null == obj || 'object' != typeof obj) return obj; - - if (obj instanceof Date) { - copy = new Date(); - copy.setTime(obj.getTime()); - return copy; - } - - if (obj instanceof Array) { - copy = []; - for (let i = 0, len = obj.length; i < len; i++) { - copy[i] = clone(obj[i]); - } - return copy; - } - - if (obj instanceof Object) { - copy = {}; - for (let attr in obj) { - if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); - } - return copy; - } -}; diff --git a/src/lib/formatUrl.ts b/src/utils/formatUrl.ts similarity index 100% rename from src/lib/formatUrl.ts rename to src/utils/formatUrl.ts diff --git a/src/lib/generatePath.ts b/src/utils/generatePath.ts similarity index 100% rename from src/lib/generatePath.ts rename to src/utils/generatePath.ts diff --git a/src/lib/isAbsolutePath.ts b/src/utils/isAbsolutePath.ts similarity index 100% rename from src/lib/isAbsolutePath.ts rename to src/utils/isAbsolutePath.ts diff --git a/src/lib/isFunction.ts b/src/utils/isFunction.ts similarity index 100% rename from src/lib/isFunction.ts rename to src/utils/isFunction.ts diff --git a/src/lib/mapValues.ts b/src/utils/mapValues.ts similarity index 100% rename from src/lib/mapValues.ts rename to src/utils/mapValues.ts diff --git a/tests/Route.test.ts b/tests/Route.test.ts index 4f27c53..ef5887b 100644 --- a/tests/Route.test.ts +++ b/tests/Route.test.ts @@ -1,5 +1,4 @@ -import { Routes } from './../src/Routes'; -import { Route } from '../src/Route'; +import { Route } from '../src/lib/Route'; test('should construct NextRoute', () => { const testRoute = new Route('/', 'index'); diff --git a/tests/Routes.test.ts b/tests/Routes.test.ts index 5fdeb54..80d41fa 100644 --- a/tests/Routes.test.ts +++ b/tests/Routes.test.ts @@ -1,5 +1,5 @@ -import { Routes } from './../src/Routes'; -import { Route } from './../src/Route'; +import { Routes } from '../src/lib/Routes'; +import { Route } from '../src/lib/Route'; test('should match route from passed url', () => { const testRoute = new Route('/:first/:second', 'test?tab=first'); diff --git a/tests/formatUrl.test.ts b/tests/formatUrl.test.ts index 4297bca..22b6c38 100644 --- a/tests/formatUrl.test.ts +++ b/tests/formatUrl.test.ts @@ -1,4 +1,4 @@ -import { formatUrl } from '../src/lib/formatUrl'; +import { formatUrl } from '../src/utils/formatUrl'; test('should trim both whitespace and non-alphanumeric character', () => { const string = '!abc '; diff --git a/tests/generatePath.test.ts b/tests/generatePath.test.ts index ee7decd..f34dd23 100644 --- a/tests/generatePath.test.ts +++ b/tests/generatePath.test.ts @@ -1,4 +1,4 @@ -import { generatePath } from '../src/lib/generatePath'; +import { generatePath } from '../src/utils/generatePath'; test('should generate path according to passed params', () => { const path = '/page/:a/:b/:c'; diff --git a/tests/isAbsolutePath.test.ts b/tests/isAbsolutePath.test.ts index 5fa29fc..84f3055 100644 --- a/tests/isAbsolutePath.test.ts +++ b/tests/isAbsolutePath.test.ts @@ -1,4 +1,4 @@ -import { isAbsolutePath } from '../src/lib/isAbsolutePath'; +import { isAbsolutePath } from '../src/utils/isAbsolutePath'; test('should be absolute path', () => { const a = 'http://example.com'; diff --git a/tests/isFunction.test.ts b/tests/isFunction.test.ts index f33fc36..7347326 100644 --- a/tests/isFunction.test.ts +++ b/tests/isFunction.test.ts @@ -1,4 +1,4 @@ -import { isFunction } from '../src/lib/isFunction'; +import { isFunction } from '../src/utils/isFunction'; test('should be function', () => { const fn = () => {}; diff --git a/tests/mapValues.test.ts b/tests/mapValues.test.ts index 9c8ca10..cbb118f 100644 --- a/tests/mapValues.test.ts +++ b/tests/mapValues.test.ts @@ -1,4 +1,4 @@ -import { mapValues } from '../src/lib/mapValues'; +import { mapValues } from '../src/utils/mapValues'; test('should map values', () => { const obj = { a: 1, b: 2 }; diff --git a/tsconfig.json b/tsconfig.json index 2814a67..2f86ee7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,12 @@ { "compilerOptions": { - "outDir": "./dist", - "target": "es5", - "module": "commonjs", "removeComments": true, "declaration": true, "jsx": "react", - "esModuleInterop": true + "esModuleInterop": true, + "lib": ["es6", "dom"], + "moduleResolution": "node" }, "include": ["./src/**/*.tsx", "./src/**/*.ts"], - "exclude": ["node_modules"] + "exclude": ["node_modules", "tests"] }