Skip to content

Commit

Permalink
feat(router): add @daffodil/router (#2708)
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 committed Jan 9, 2024
1 parent ea4c92b commit 2b61dd8
Show file tree
Hide file tree
Showing 26 changed files with 734 additions and 0 deletions.
37 changes: 37 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -2256,6 +2256,43 @@
}
}
}
},
"router": {
"projectType": "library",
"root": "libs/router",
"sourceRoot": "libs/router",
"prefix": "@daffodil",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "libs/router/tsconfig.lib.json",
"project": "libs/router/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "libs/router/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "libs/router/test.ts",
"tsConfig": "libs/router/tsconfig.spec.json",
"karmaConfig": "libs/router/karma.conf.js"
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": [
"libs/router/**/*.ts",
"libs/router/**/*.html"
]
}
}
}
}
},
"schematics": {
Expand Down
52 changes: 52 additions & 0 deletions libs/router/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
module.exports = {
extends: '../../.eslintrc.js',
ignorePatterns: [
'!**/*'
],
overrides: [
{
files: [
'*.ts'
],
parserOptions: {
project: [
'libs/router/tsconfig.lib.json',
'libs/router/tsconfig.spec.json'
],
createDefaultProgram: true
},
rules: {
'@angular-eslint/component-class-suffix': [
'error',
{
suffixes: [
'Component',
'Container'
]
}
],
'@angular-eslint/component-selector': [
'error',
{
type: 'lib',
prefix: 'kebab-case'
}
],
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'lib',
style: 'camelCase'
}
],
}
},
{
files: [
'*.html'
],
rules: {}
}
]
}
25 changes: 25 additions & 0 deletions libs/router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# @daffodil/router

Contains utilities useful for dealing with and adding features to the Angular router.

## Features

### Route Named Views
Adds the ability to define additional components in a `Route` config:
```ts
const routes = [
<DaffRouteWithNamedViews>{
...
data: {
daffNamedViews: {
key: MyComponent,
},
},
},
]
```

Each component is associated with a key and can be rendered like so:
```html
<ng-container daffRouterNamedViewOutlet="key"></ng-container>
```
10 changes: 10 additions & 0 deletions libs/router/karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
baseConfiguration = require('../../tools/karma/karma.conf');

module.exports = function (config) {
baseConfiguration(config);
config.set({
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage/libs/router'),
},
});
};
7 changes: 7 additions & 0 deletions libs/router/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/router",
"lib": {
"entryFile": "src/index.ts"
}
}
7 changes: 7 additions & 0 deletions libs/router/ng-package.prod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/router",
"lib": {
"entryFile": "src/index.ts"
}
}
38 changes: 38 additions & 0 deletions libs/router/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@daffodil/router",
"nx": {
"targets": {
"build": {
"outputs": ["{workspaceRoot}/dist/router"]
}
}
},
"version": "0.0.0-PLACEHOLDER",
"description": "Adds features and provides utils for the Angular router.",
"repository": {
"type": "git",
"url": "https://github.com/graycoreio/daffodil"
},
"author": "Graycore LLC",
"license": "MIT",
"bugs": {
"url": "https://github.com/graycoreio/daffodil/issues"
},
"scripts": {
"build": "ng build router --configuration production",
"lint": "cd ../.. && ng lint router",
"lint:fix": "npm run lint -- --fix",
"test": "ng test router --watch=false --browsers=ChromeHeadless",
"publish": "cd ../../dist/router && npm publish --access=public"
},
"peerDependencies": {
"@angular/common": "0.0.0-PLACEHOLDER",
"@angular/core": "0.0.0-PLACEHOLDER",
"@daffodil/core": "0.0.0-PLACEHOLDER",
"@angular/router": "0.0.0-PLACEHOLDER",
"rxjs": "0.0.0-PLACEHOLDER"
},
"devDependencies": {
"@daffodil/core": "0.0.0-PLACEHOLDER"
}
}
1 change: 1 addition & 0 deletions libs/router/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './public_api';
86 changes: 86 additions & 0 deletions libs/router/src/named-view/helpers/collect-named-views.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
DaffActivatedRouteSnapshotWithNamedViews,
DaffRouterNamedViews,
} from '@daffodil/router';

import { daffRouterNamedViewsCollect } from './collect-named-views';

class TestClass {}
class TestClass1 {}

describe('@daffodil/router | daffRouterNamedViewsCollect', () => {
let route: DaffActivatedRouteSnapshotWithNamedViews;
let result: DaffRouterNamedViews;

beforeEach(() => {
route = <DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
root: TestClass,
overwrite: TestClass,
},
},
children: [
<DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
'00': TestClass,
},
},
children: [
<DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
10: TestClass,
},
},
children: [],
},
<DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
11: TestClass,
overwrite: TestClass1,
},
},
children: [
<DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
20: TestClass,
},
},
children: [],
},
],
},
],
},
<DaffActivatedRouteSnapshotWithNamedViews><unknown>{
data: {
daffNamedViews: {
'01': TestClass,
},
},
children: [],
},
],
};

result = daffRouterNamedViewsCollect(route);
});

it('should collect all the named views and combine them into a single dict', () => {
expect(result['root']).toBeDefined();
expect(result['00']).toBeDefined();
expect(result['01']).toBeDefined();
expect(result[10]).toBeDefined();
expect(result[11]).toBeDefined();
expect(result[20]).toBeDefined();
expect(result['overwrite']).toBeDefined();
});

it('should give precedence to more deeply nested routes when there is a collision', () => {
expect(result['overwrite']).toEqual(TestClass1);
});
});
23 changes: 23 additions & 0 deletions libs/router/src/named-view/helpers/collect-named-views.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { collect } from '@daffodil/core';

import {
DaffActivatedRouteSnapshotWithNamedViews,
DaffRouterNamedViews,
} from '../models/public_api';

/**
* Collects all named views defined in the entire tree of routes.
*/
export const daffRouterNamedViewsCollect = (route: DaffActivatedRouteSnapshotWithNamedViews): DaffRouterNamedViews => {
const ary = collect(route, (r) => r.children);
const ret = ary.reduce(
(acc, r) => r.data.daffNamedViews
? {
...acc,
...r.data.daffNamedViews,
}
: acc,
<DaffRouterNamedViews>{},
);
return ret;
};
1 change: 1 addition & 0 deletions libs/router/src/named-view/helpers/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { daffRouterNamedViewsCollect } from './collect-named-views';
12 changes: 12 additions & 0 deletions libs/router/src/named-view/models/activated-route-snapshot.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ActivatedRouteSnapshot } from '@angular/router';

import { DaffRouterNamedViews } from './named-views.type';

/**
* A route that contains named views.
*/
export interface DaffActivatedRouteSnapshotWithNamedViews extends ActivatedRouteSnapshot {
data: {
daffNamedViews?: DaffRouterNamedViews;
} & ActivatedRouteSnapshot['data'];
}
6 changes: 6 additions & 0 deletions libs/router/src/named-view/models/named-views.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Route } from '@angular/router';

/**
* A dictionary of components that can be stored in route data.
*/
export type DaffRouterNamedViews= Record<string, Route['component']>;
3 changes: 3 additions & 0 deletions libs/router/src/named-view/models/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { DaffActivatedRouteSnapshotWithNamedViews } from './activated-route-snapshot.type';
export { DaffRouterNamedViews } from './named-views.type';
export { DaffRouteWithNamedViews } from './route.type';
12 changes: 12 additions & 0 deletions libs/router/src/named-view/models/route.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Route } from '@angular/router';

import { DaffRouterNamedViews } from './named-views.type';

/**
* A route that contains named views.
*/
export interface DaffRouteWithNamedViews extends Route {
data?: {
daffNamedViews?: DaffRouterNamedViews;
} & Route['data'];
}
Loading

0 comments on commit 2b61dd8

Please sign in to comment.