npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ng2-conventions-decorators

v2.1.0

Published

A set of minimal decorators for Angular2 that leverage established conventions to reduce boilerplate, improve maintainability, and improve type safety

Downloads

53

Readme

ng2-conventions-decorators

GitHub release npm npm npm Build Status A set of minimal decorators for Angular2 that leverage established conventions to reduce boilerplate, enforce consistent APIs, and leverage static type analysis.

Rationale

Angular 2 is very heavy on configuration, considerably heavier than AngularJS. For example, html element component directives should be given a kebab-case-name tag-name. This is both an official recommendation and a standard html convention. However, while AngularJS used a simple, easy to understand transformation to create these tag-names,

JavaScript

function someCustomElement() { ... }

angular.directive({ someCustomElement });

HTML

<some-custom-element></some-custom-element>

Angular 2 requires the tag-name be explicitly specified as a property of the component decorator factory's configuration object. This is just one of many examples but it clearly demonstrates the following issues:

  1. Violates DRY.
  2. Harder to maintain: You have to keep even more names in sync when refactoring.
  3. Verbose: Redundantly species configuration in strings.
  4. Error prone: Heavy use of optionality and simple strings fail to leverage strengths of Angular 2's foundational tools (e.g. TypeScript).
  5. Hard to teach: Recommended practices are now optional, but still expected, just optional. Angular 2 is opinionated, so there is no argument for flexibility or agnosticism.
  6. Harder to maintain: To know the tag name you need to use in html you have to read every component's definition or documentation.

Angular 2's AOT compilation process fails when a component contains private properties that are used in its markup. While this probably should not be the case at all it should at least be documented and enforced so that JIT mode and AOT mode have the same semantics and behavior. The included component decorator factory enforces this at the type level, providing an error when a component contains a private or protected property. This correctly gives you a static error in both JIT and AOT by communicating the intent missing from Angular 2's APIs.

@component(template) export class MyAwesomeComponent {
    prop = 'this is public';
} // OK
@component(template) export class MyAwesomeComponent {
    private prop = 'this is private';
} // Static Error

Installation

jspm

jspm i ng2-conventions-decorators

npm

npm i ng2-conventions-decorators --save

API

@pipe (decorator)

What?

A simple, and typechecked pipe decorator

How?

Use it just like @Pipe() except without the parenthesis and the redundant configuration object

@pipe export class LocalCurrencyPipe {
    transform(value: string) { ... }
}

is precisely equivalent to

@Pipe({ name: 'localCurrency' }) export class LocalCurrencyPipe {
    transform(value: string) { ... }
}

Furthermore

@pipe export class LocalCurrencyPipe {
    // forgot to implement transform
}

is a TypeScript compile error while

@Pipe({ name: 'localCurrency' }) export class LocalCurrencyPipe { 
    // forgot to implement transform
}

will fail at runtime.

Why?

  1. DRY
  2. Automatically creates camelCasedFunction name
  3. Convention over configuration
  4. Always pure, no confusing true defaulting boolean
  5. Ensures decorated class actually provides a transform(value) method at compile time
  6. When using TypeScript we both can and should take advantage of its semantic error checking
  7. No need for a decorator factory when a simple decorator is cleaner and more maintainable

@component (decorator factory)

What?

A minimal shorthand for the 90% case

How?

Use it just like @Component() to enjoy cleaner code and consistent selectors

@component(template, style) export class DynamicListViewComponent { }

is precisely equivalent to

@Component({
    template,
    styles: [style],
    selector: 'dynamic-list-view'
})
export class DynamicListViewComponent { }

Need additional configuration?

@component(template, style, {
    directives: [ListItem]
})
export class DynamicListViewComponent { }

Why?

  1. DRY
  2. Automatically create kebab-cased-element selector
  3. Convention over configuration
  4. Ensures standard selector naming conventions
  5. 99% of the time you only have one stylesheet per component

@input (decorator)

What?

A simple shorthand without an optional name argument

How?

Use it just like @Input() except without the parenthesis

@input initialItems = [];

is precisely equivalent to

@Input() initialItems = [];

which is precisely equivalent to

@Input('initialItems') initialItems = [];

Why?

  1. A shorter, cleaner, syntax that ensures standard naming conventions for input bindings
  2. Optional argument is 99.9% unused, so it should be a decorator, not a decorator factory

@output (decorator)

What?

A simple shorthand without an optional name argument

How?

Use it just like @Output() except without the parenthesis

@output itemAdded = new EventEmitter();

is precisely equivalent to

@Output() itemAdded = new EventEmitter();

which is precisely equivalent to

@Output('itemAdded') itemAdded = new EventEmitter();

Why?

  1. A shorter, cleaner, syntax that ensures standard naming conventions for output bindings
  2. Optional argument is 99.9% unused, so it should be a decorator, not a decorator factory

@injectable (decorator)

What?

A simple dependency injection annotation

How?

Use it just like @Injectable() except without the parenthesis

@injectable export class AccountProfileManager {
    constructor(
        readonly accountManager: AccountManager,
        readonly profileManager: ProfileManager
    ) { }
}

is precisely equivalent to

@Injectable() export class AccountProfileManager {
    constructor(
        readonly accountManager: AccountManager,
        readonly profileManager: ProfileManager
    ) { }
}

Why?

Since @Injectable from '@angular/core' takes no arguments, it should be a decorator, not a decorator factory

Implementation

As a quick look through the source will illustrate, all of the above are implemented by delegating to the underlying @angular/core so meaning that stay in sync and up to date.