nuxt-typed-router
Advanced tools
Comparing version 0.1.14 to 0.2.0
@@ -1,117 +0,125 @@ | ||
// @ts-check | ||
import fs from 'fs'; | ||
import * as prettier from 'prettier'; | ||
import { camelCase } from 'lodash'; | ||
import chalk from 'chalk'; | ||
const path = require('path'); | ||
const logSymbols = require('log-symbols'); | ||
function typedRouterModule(moduleOptions) { | ||
const options = { ...this.options.typedRouter, ...moduleOptions }; | ||
this.addPlugin({ | ||
src: path.resolve(__dirname, './templates/nuxt-typed-router.js'), | ||
}); | ||
this.nuxt.hook('build:extendRoutes', async routes => { | ||
try { | ||
// Redirect with @ | ||
this.extendRoutes(async existingRoutes => { | ||
let formatedRoutes; | ||
const recursiveMatch = (route, parent) => { | ||
if (route.path && route.path.startsWith('@') && !!parent) { | ||
route.path = route.path.split('@')[1]; | ||
const parentsChildren = parent.children; | ||
if (parentsChildren) { | ||
let defaultName = null; | ||
if (route.name) { | ||
defaultName = route.name; | ||
} else if (route.children) { | ||
const child = route.children.find(f => f.path === ''); | ||
if (child) { | ||
defaultName = child.name; | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const fs_1 = __importDefault(require("fs")); | ||
const prettier = __importStar(require("prettier")); | ||
const lodash_1 = require("lodash"); | ||
const chalk_1 = __importDefault(require("chalk")); | ||
const path_1 = __importDefault(require("path")); | ||
const log_symbols_1 = __importDefault(require("log-symbols")); | ||
require("./templates/nuxt-typed-router"); | ||
const typedRouterModule = function (moduleOptions) { | ||
const { filePath = `${this.options.srcDir}/__routes.js`, routesObjectName = 'routerPagesNames', stripAtFromName = false, } = { ...this.options.typedRouter, ...moduleOptions }; | ||
this.nuxt.hook('build:extendRoutes', async (routes) => { | ||
try { | ||
this.extendRoutes(async (existingRoutes) => { | ||
let formatedRoutes; | ||
const recursiveMatch = (route, parent) => { | ||
var _a; | ||
if (route.path && route.path.startsWith('@') && !!parent) { | ||
route.path = route.path.split('@')[1]; | ||
if (stripAtFromName && route.name) { | ||
const [left, right] = (_a = route.name) === null || _a === void 0 ? void 0 : _a.split('@'); | ||
route.name = `${left}${right}`; | ||
} | ||
const parentsChildren = parent.children; | ||
if (parentsChildren) { | ||
let defaultName = null; | ||
if (route.name) { | ||
defaultName = route.name; | ||
} | ||
else if (route.children) { | ||
const child = route.children.find((f) => f.path === ''); | ||
if (child) { | ||
defaultName = child.name; | ||
} | ||
} | ||
else { | ||
defaultName = null; | ||
} | ||
parentsChildren.push({ | ||
path: '', | ||
name: `${parent.name}-index`, | ||
redirect: { | ||
...(defaultName && { name: defaultName }), | ||
...(!defaultName && { path: route.path }), | ||
}, | ||
}); | ||
} | ||
} | ||
if (route.children) { | ||
route.children.forEach((child) => recursiveMatch(child, route)); | ||
} | ||
}; | ||
existingRoutes.map((route) => recursiveMatch(route)); | ||
formatedRoutes = existingRoutes; | ||
let routesObject = '{'; | ||
const recursiveTypedRoutes = (route, level) => { | ||
const routeName = route.name; | ||
if (route.children) { | ||
const [parentName, parentName2] = route.path.split('/'); | ||
routesObject += `${lodash_1.camelCase(parentName || parentName2 || 'index')}:{`; | ||
route.children.map((r) => recursiveTypedRoutes(r, level + 1)); | ||
routesObject += '},'; | ||
} | ||
else if (routeName) { | ||
let splitted = routeName.split('-'); | ||
splitted = splitted.slice(level, splitted.length); | ||
routesObject += `'${lodash_1.camelCase(splitted.join('-')) || 'index'}': '${routeName}',`; | ||
} | ||
}; | ||
formatedRoutes.map((r) => recursiveTypedRoutes(r, 0)); | ||
routesObject += '}'; | ||
const template = `export const ${routesObjectName} = ${routesObject};`; | ||
const templateForLocal = `export default ${routesObject};`; | ||
try { | ||
let prettierFoundOptions = await prettier.resolveConfig(process.cwd()); | ||
if (!prettierFoundOptions) { | ||
prettierFoundOptions = require('../.prettierrc'); | ||
} | ||
const formatedModelsFile = prettier.format(template, { | ||
...prettierFoundOptions, | ||
parser: 'typescript', | ||
}); | ||
const savePath = path_1.default.resolve(process.cwd(), filePath); | ||
await fs_1.default.writeFileSync(savePath, formatedModelsFile); | ||
await fs_1.default.writeFileSync(path_1.default.resolve(__dirname, './generated.js'), templateForLocal); | ||
console.log(log_symbols_1.default.success, `Route definition file generated at ${chalk_1.default.blue(savePath)}`); | ||
this.addPlugin({ | ||
src: path_1.default.resolve(__dirname, './templates/nuxt-typed-router.js'), | ||
}); | ||
} | ||
} else { | ||
defaultName = null; | ||
} | ||
parentsChildren.push({ | ||
path: '', | ||
name: `${parent.name}-index`, | ||
redirect: { | ||
...(defaultName && { name: defaultName }), | ||
...(!defaultName && { path: route.path }), | ||
}, | ||
}); | ||
} | ||
} | ||
if (route.children) { | ||
route.children.forEach(child => recursiveMatch(child, route)); | ||
} | ||
}; | ||
existingRoutes.map(route => recursiveMatch(route)); | ||
formatedRoutes = existingRoutes; | ||
// Typed router | ||
let routesInterfaces = '{'; | ||
let routesEnum = []; | ||
const recursiveTypedRoutes = (route, level) => { | ||
const routeName = route.name; | ||
if (route.children) { | ||
const [parentName, parentName2] = route.path.split('/'); | ||
routesInterfaces += `${camelCase(parentName || parentName2 || 'index')}:{`; | ||
route.children.map(r => recursiveTypedRoutes(r, level + 1)); | ||
routesInterfaces += '},'; | ||
} else if (routeName) { | ||
let splitted = routeName.split('-'); | ||
splitted = splitted.slice(level, splitted.length); | ||
routesInterfaces += `'${camelCase(splitted.join('-')) || 'index'}': '${routeName}',`; | ||
routesEnum.push(`'${route.name}'`); | ||
} | ||
}; | ||
formatedRoutes.map(r => recursiveTypedRoutes(r, 0)); | ||
routesInterfaces += '}'; | ||
const template = ` | ||
export const ${options.routesObjectName || 'routerPagesNames'} = ${routesInterfaces};`; | ||
const routesEnumsTemplate = `export type RouteNames = ${routesEnum.join('|')};`; | ||
try { | ||
if (options.filePath) { | ||
let prettierFoundOptions = await prettier.resolveConfig(process.cwd()); | ||
if (!prettierFoundOptions) { | ||
prettierFoundOptions = require('../.prettierrc'); | ||
} | ||
const formatedModelsFile = prettier.format(template, { | ||
...prettierFoundOptions, | ||
parser: 'typescript', | ||
catch (e) { | ||
console.error(chalk_1.default.red('Error while saving route definitions file'), '\n' + e); | ||
} | ||
return formatedRoutes; | ||
}); | ||
const savePath = path.resolve(process.cwd(), options.filePath); | ||
await fs.writeFileSync(savePath, formatedModelsFile); | ||
console.log( | ||
logSymbols.success, | ||
`Route definition file generated at ${chalk.blue(savePath)}` | ||
); | ||
} | ||
await fs.writeFileSync( | ||
path.resolve(__dirname, '../types/__generated.ts'), | ||
routesEnumsTemplate | ||
); | ||
} catch (e) { | ||
console.error(chalk.red('Error while saving route definitions file'), '\n' + e); | ||
} | ||
return formatedRoutes; | ||
}); | ||
} catch (e) { | ||
console.error(chalk.red('Error while generating routes definitions model'), '\n' + e); | ||
} | ||
}); | ||
} | ||
catch (e) { | ||
console.error(chalk_1.default.red('Error while generating routes definitions model'), '\n' + e); | ||
} | ||
}); | ||
}; | ||
module.exports = typedRouterModule; | ||
module.exports.meta = require('../package.json'); |
@@ -1,6 +0,9 @@ | ||
import Vue from 'vue'; | ||
export default (ctx, inject) => { | ||
inject('typedRouter', ctx.app.router); | ||
inject('typedRoute', ctx.route); | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const generated_js_1 = __importDefault(require("../generated.js")); | ||
exports.default = (ctx, inject) => { | ||
inject('$routeNames', generated_js_1.default); | ||
}; |
{ | ||
"name": "nuxt-typed-router", | ||
"version": "0.1.14", | ||
"version": "0.2.0", | ||
"description": "Provide autocompletion for pages route names generated by Nuxt router", | ||
@@ -16,2 +16,7 @@ "main": "lib/module.js", | ||
], | ||
"scripts": { | ||
"dev": "tsc -p ./tsconfig.json --pretty --watch", | ||
"build": "tsc -p ./tsconfig.json --pretty", | ||
"prepublish": "yarn build" | ||
}, | ||
"publishConfig": { | ||
@@ -30,5 +35,12 @@ "access": "public" | ||
"log-symbols": "^4.0.0", | ||
"prettier": "^2.1.2", | ||
"prettier": "^2.2.0" | ||
}, | ||
"devDependencies": { | ||
"@nuxt/types": "^2.14.7", | ||
"@types/lodash": "^4.14.165", | ||
"@types/node": "^14.14.10", | ||
"@types/prettier": "^2.1.5", | ||
"typescript": "^4.1.2", | ||
"vue-router": "^3.4.9" | ||
} | ||
} |
@@ -5,3 +5,11 @@ # 🚦Typed Router Module | ||
[![npm downloads][npm-downloads-src]][npm-downloads-href] | ||
[![npm downloads][npm-total-downloads-src]][npm-downloads-href] | ||
<img src='https://img.shields.io/npm/l/simple-graphql-to-typescript.svg'> | ||
[npm-version-src]: https://img.shields.io/npm/v/nuxt-typed-router.svg | ||
[npm-version-href]: https://www.npmjs.com/package/nuxt-typed-router | ||
[npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-typed-router.svg | ||
[npm-total-downloads-src]: https://img.shields.io/npm/dt/nuxt-typed-router.svg | ||
[npm-downloads-href]: https://www.npmjs.com/package/nuxt-typed-router | ||
> Provide a safe typed router to nuxt with auto-generated typed definitions for route names | ||
@@ -58,5 +66,11 @@ | ||
filePath?: string; | ||
// Name of the routesNames object (ex: "routesTree") | ||
// Default: "routerPagesNames" | ||
routesObjectName?: string; | ||
// Strip `@` sign from declared routes (ex: `admin/@home.vue` will be accessed like this `routerPagesNames.admin.home` | ||
// and the route name will be `admin-home` instead of `admin-@home`) | ||
// Default: true | ||
stripAtFromNames?: boolean; | ||
}; | ||
@@ -69,2 +83,14 @@ ``` | ||
# For Typescript users | ||
Add `nuxt-typed-router/types` to your `tsconfig.json` types | ||
```js | ||
{ | ||
"types": ["@nuxt/types", "nuxt-typed-router/types"], | ||
} | ||
``` | ||
# Javascript Users | ||
## - `routerPagesNames` global object | ||
@@ -134,10 +160,8 @@ | ||
You can just import it now | ||
You can use it from the injected `$routeNames` option on your components | ||
```javascript | ||
import { routerPagesNames } from '~/models/__routes.js'; | ||
export default { | ||
mounted() { | ||
this.$router.push({ name: routerPagesNames.index.content }); | ||
this.$router.push({ name: this.$routeNames.index.content }); | ||
}, | ||
@@ -147,37 +171,14 @@ }; | ||
## - `$typedRouter` | ||
Or you can just import it | ||
A global `$typedRouter` method is added to the Nuxt context and is accessible in your components and context. It's an alias of Vue `$router`, but the typings are modified so the `name` options is typed with the routes names generated from the pages directory | ||
```javascript | ||
import { routerPagesNames } from '~/models/__routes.js'; | ||
### _Why not directly modifying the types of `$router` and `$route` ?_ | ||
That was the idea when I builded this module initially, but I got confronted with Typescript limitations for modifying already defined third-party lib typings. | ||
If I wanted to modify vue-router types, i could have just written this: | ||
```typescript | ||
declare module 'vue-router/types' { | ||
export interface Location { | ||
name: 'login' | 'home'; | ||
} | ||
} | ||
export default { | ||
mounted() { | ||
this.$router.push({ name: routerPagesNames.index.content }); | ||
}, | ||
}; | ||
``` | ||
Unfortunately that's not possible, Typescript throws this errors: | ||
- `Subsequent property declarations must have the same type. Property 'name' must be of type 'string', but here has type '"login" | "home"` | ||
- `All declarations of 'name' must have identical modifiers` | ||
So the only way for now is to have an alternative `$typedRouter`, or a global enum-like object. | ||
### _Requirements_ | ||
For your IDE to augment the Vue types, you need to explicitly import the module in your Nuxt config | ||
```javascript | ||
// nuxt.config.js | ||
import 'nuxt-typed-router'; | ||
``` | ||
### _Usage_ | ||
@@ -184,0 +185,0 @@ |
@@ -1,45 +0,2 @@ | ||
import Vue from 'vue'; | ||
import * as TypedRouter from './vue'; | ||
export default TypedRouter; | ||
interface NuxtTypedRouterOptions { | ||
filePath?: string; | ||
routesObjectName?: string; | ||
} | ||
declare module '@nuxt/vue-app' { | ||
interface Context { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
} | ||
interface NuxtAppOptions { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
} | ||
interface Configuration { | ||
typedRouter?: NuxtTypedRouterOptions; | ||
} | ||
} | ||
// Nuxt 2.9+ | ||
declare module '@nuxt/types' { | ||
interface Configuration { | ||
typedRouter?: NuxtTypedRouterOptions; | ||
} | ||
interface Context { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
} | ||
interface NuxtAppOptions { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
} | ||
} | ||
declare module 'vue/types/vue' { | ||
interface Vue { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
$typedRoute: TypedRouter.TypedRoute; | ||
} | ||
} | ||
declare module 'vuex/types/index' { | ||
interface Store<S> { | ||
$typedRouter: TypedRouter.TypedVueRouter; | ||
} | ||
} | ||
export { NuxtTypedRouterOptions } from './types'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,42 +0,7 @@ | ||
import VueRouter, { Location, Route, RouteRecord } from 'vue-router'; | ||
import { RouteNames } from './__generated'; | ||
import { ErrorHandler } from 'vue-router/types/router'; | ||
import Vue, { AsyncComponent, ComponentOptions } from 'vue'; | ||
export { RouteNames }; | ||
export interface NuxtTypedRouterOptions { | ||
filePath?: string; | ||
import pagesNamesModel from './generated.ts'; | ||
declare module 'vue/types/vue' { | ||
interface Vue { | ||
$routesNames: typeof pagesNamesModel; | ||
} | ||
} | ||
export type Component = ComponentOptions<Vue> | typeof Vue | AsyncComponent; | ||
export interface TypedVueRouter extends VueRouter { | ||
push(location: TypedRawLocation): Promise<TypedRoute>; | ||
replace(location: TypedRawLocation): Promise<TypedRoute>; | ||
push(location: TypedRawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; | ||
replace(location: TypedRawLocation, onComplete?: Function, onAbort?: ErrorHandler): void; | ||
getMatchedComponents(to?: TypedRawLocation | TypedRoute): Component[]; | ||
resolve( | ||
to: TypedRawLocation, | ||
current?: TypedRoute, | ||
append?: boolean | ||
): { | ||
location: TypedLocation; | ||
route: TypedRoute; | ||
href: string; | ||
normalizedTo: TypedLocation; | ||
resolved: TypedRoute; | ||
}; | ||
} | ||
export type TypedRawLocation = string | TypedLocation; | ||
export interface TypedLocation extends Location { | ||
name?: RouteNames; | ||
} | ||
export interface TypedRoute extends Route { | ||
name?: RouteNames; | ||
} | ||
export interface TypedRouteRecord extends RouteRecord { | ||
name?: RouteNames; | ||
} | ||
//# sourceMappingURL=vue.d.ts.map |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
15008
4
10
223
6
147
1
- Removedvue-router@^3.4.9
- Removedvue-router@3.6.5(transitive)
Updatedprettier@^2.2.0