Merge branch 'release/2.1.0'

merge-requests/3/merge v2.1.0
Nato Boram 2020-07-10 02:12:33 -04:00
commit e1343af330
42 changed files with 4568 additions and 3225 deletions

18
.browserslistrc Normal file
View File

@ -0,0 +1,18 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@ -3,11 +3,14 @@ root = true
[*] [*]
charset = utf-8 charset = utf-8
indent_style = space
indent_size = 2 indent_size = 2
indent_style = space
insert_final_newline = true insert_final_newline = true
max_line_length = 140
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md] [*.md]
max_line_length = off
trim_trailing_whitespace = false trim_trailing_whitespace = false

View File

@ -1,4 +1,4 @@
image: node:13 image: node:14
before_script: before_script:
- yarn - yarn

View File

@ -1,4 +1,6 @@
{ {
"line-length": false, "line-length": {
"line_length": 140
},
"no-duplicate-heading": false "no-duplicate-heading": false
} }

View File

@ -9,12 +9,13 @@
"hookyqr.beautify", "hookyqr.beautify",
"johnpapa.angular2", "johnpapa.angular2",
"ms-vscode.typescript-javascript-grammar", "ms-vscode.typescript-javascript-grammar",
"ms-vscode.vscode-typescript-next",
"ms-vscode.vscode-typescript-tslint-plugin", "ms-vscode.vscode-typescript-tslint-plugin",
"msjsdiag.debugger-for-chrome", "msjsdiag.debugger-for-chrome",
"visualstudioexptteam.vscodeintellicode", "visualstudioexptteam.vscodeintellicode",
], ],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace. // List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [ "unwantedRecommendations": [
"eg2.tslint" "eg2.tslint",
] ]
} }

View File

@ -18,6 +18,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
### Security ### Security
## [2.1.0] - 2020-07-10
### Added
- Support for subdomain gateways
- Strict mode
- More icons
- IPFS colours
### Changed
- Better screenshot
- Upgraded to Angular 10
- Now uses `--chunker=buzhash`
- Updated `bootstrap` and `ipfs-css`
## [2.0.0] - 2019-12-03 ## [2.0.0] - 2019-12-03
Now based on Angular! Now based on Angular!
@ -26,7 +42,7 @@ Tests were done with `ipfs-npm` : They weren't successful. `ipfs-css` is only mi
### Added ### Added
* GitLab Pages - <https://natoboram.gitlab.io/public-gateway-cacher/> - GitLab Pages - <https://natoboram.gitlab.io/public-gateway-cacher/>
## [1.0.0] - 2019-11-28 ## [1.0.0] - 2019-11-28
@ -34,9 +50,9 @@ This version is a fork of [github.com/ipfs/public-gateway-checker](https://githu
## Types of changes ## Types of changes
* `Added` for new features. - `Added` for new features.
* `Changed` for changes in existing functionality. - `Changed` for changes in existing functionality.
* `Deprecated` for soon-to-be removed features. - `Deprecated` for soon-to-be removed features.
* `Removed` for now removed features. - `Removed` for now removed features.
* `Fixed` for any bug fixes. - `Fixed` for any bug fixes.
* `Security` in case of vulnerabilities. - `Security` in case of vulnerabilities.

View File

@ -1,16 +1,18 @@
# Public Gateway Cacher # Public Gateway Cacher
[![pipeline status](https://gitlab.com/NatoBoram/public-gateway-cacher/badges/master/pipeline.svg)](https://gitlab.com/NatoBoram/public-gateway-cacher/-/commits/master)
[![StackShare](https://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/NatoBoram/public-gateway-cacher)
Cache a specific hash on a bunch of public gateways. Cache a specific hash on a bunch of public gateways.
**Note :** All of these (except gateway.ipfs.io and ipfs.io) are hosted by third-parties and should be treated as such. You can view this website on [GitLab Pages](https://natoboram.gitlab.io/public-gateway-cacher) and [IPFS](https://bafybeiagzg6lcrzuwb7pdxhs4bc7iiexriaxy2kx5fogdaemnqg4oiydl4.ipfs.dweb.link).
You can view this website on [IPFS](https://bafybeibjf6z3sxavox6uahfl4vogkuenimlpvn4eghdv6mtsm55rpnalve.cf-ipfs.com). ![Screenshot](https://bafybeie7txrbzw6ipb62lplnpzsjpz7s4o5q7uufb5rjfelol2cuxeyzye.ipfs.dweb.link/Screenshot_2020-07-09%20Public%20Gateway%20Cacher.png)
Here's a screenshot : **NOTE :** All of these (except `ipfs.io` and `dweb.link`) are hosted by third-parties and should be treated as such.
![screenshot](https://ipfs.io/ipfs/QmUeCSd4gHio7MxZuRXCcLFXED9GpfntKcL87gmXvZV3ed) If you'd like to add a new public gateway, please go to
[github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue [here](https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new).
If you'd like to add a new public gateway, please go to [github.com/ipfs/public-gateway-checker](https://github.com/ipfs/public-gateway-checker), submit a pull request then open an issue here.
## Angular ## Angular

View File

@ -1,6 +1,10 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"cli": {
"packageManager": "yarn",
"analytics": "10b848ad-8b81-4346-852f-5eff89573a85"
},
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"public-gateway-cacher": { "public-gateway-cacher": {
@ -8,6 +12,9 @@
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"style": "scss" "style": "scss"
},
"@schematics/angular:application": {
"strict": true
} }
}, },
"root": "", "root": "",
@ -25,12 +32,7 @@
"aot": true, "aot": true,
"assets": [ "assets": [
"src/favicon.png", "src/favicon.png",
"src/assets", "src/assets"
{
"glob": "*",
"input": "node_modules/ipfs-css",
"output": "assets/ipfs-css"
}
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss"
@ -153,12 +155,7 @@
"karmaConfig": "karma.conf.js", "karmaConfig": "karma.conf.js",
"assets": [ "assets": [
"src/favicon.png", "src/favicon.png",
"src/assets", "src/assets"
{
"glob": "*",
"input": "node_modules/ipfs-css",
"output": "assets/ipfs-css"
}
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss"
@ -194,8 +191,5 @@
} }
} }
}, },
"defaultProject": "public-gateway-cacher", "defaultProject": "public-gateway-cacher"
"cli": {
"packageManager": "yarn"
}
} }

View File

@ -1,12 +0,0 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.

View File

@ -2,7 +2,7 @@
// Protractor configuration file, see link for more information // Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts // https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter'); const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
/** /**
* @type { import("protractor").Config } * @type { import("protractor").Config }
@ -21,12 +21,16 @@ exports.config = {
jasmineNodeOpts: { jasmineNodeOpts: {
showColors: true, showColors: true,
defaultTimeoutInterval: 30000, defaultTimeoutInterval: 30000,
print: function() {} print: function () { }
}, },
onPrepare() { onPrepare() {
require('ts-node').register({ require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json') project: require('path').join(__dirname, './tsconfig.json')
}); });
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayStacktrace: StacktraceOption.PRETTY
}
}));
} }
}; };

View File

@ -1,19 +1,19 @@
import { browser, logging } from 'protractor'; import { browser, logging } from 'protractor';
import { AppPage } from './app.po'; import { AppPage } from './app.po';
describe('workspace-project App', () => { describe('workspace-project App', (): void => {
let page: AppPage; let page: AppPage;
beforeEach(() => { beforeEach((): void => {
page = new AppPage(); page = new AppPage();
}); });
it('should display welcome message', () => { it('should display welcome message', (): void => {
page.navigateTo(); page.navigateTo();
expect(page.getTitleText()).toEqual('public-gateway-cacher app is running!'); expect(page.getTitleText()).toEqual('public-gateway-cacher app is running!');
}); });
afterEach(async () => { afterEach(async (): Promise<void> => {
// Assert that there are no errors emitted from the browser // Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER); const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({ expect(logs).not.toContain(jasmine.objectContaining({

View File

@ -1,11 +1,11 @@
import { browser, by, element } from 'protractor'; import { browser, by, element } from 'protractor';
export class AppPage { export class AppPage {
navigateTo() { navigateTo(): Promise<unknown> {
return browser.get(browser.baseUrl) as Promise<any>; return browser.get(browser.baseUrl) as Promise<unknown>;
} }
getTitleText() { getTitleText(): Promise<string> {
return element(by.css('app-root .content span')).getText() as Promise<string>; return element(by.css('pgc-root .content span')).getText() as Promise<string>;
} }
} }

View File

@ -1,9 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "../tsconfig.json", "extends": "../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"outDir": "../out-tsc/e2e", "outDir": "../out-tsc/e2e",
"module": "commonjs", "module": "commonjs",
"target": "es5", "target": "es2018",
"types": [ "types": [
"jasmine", "jasmine",
"jasminewd2", "jasminewd2",

View File

@ -1,6 +1,6 @@
{ {
"name": "public-gateway-cacher", "name": "public-gateway-cacher",
"version": "2.0.0", "version": "2.1.0",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --ssl", "start": "ng serve --ssl",
@ -11,52 +11,51 @@
"test": "ng test", "test": "ng test",
"lint": "ng lint", "lint": "ng lint",
"e2e": "ng e2e", "e2e": "ng e2e",
"yarn": "ipfs-yarn", "publish:ipfs": "yarn run build:ipfs && ipfs add --recursive --chunker=buzhash --cid-version=1 dist/angular",
"publish:ipfs": "yarn run build:ipfs; ipfs add --recursive --chunker=rabin --cid-version=1 dist/angular" "postinstall": "ngcc"
}, },
"private": false, "private": false,
"dependencies": { "dependencies": {
"@angular/animations": "~8.2.14", "@angular/animations": "~10.0.3",
"@angular/cdk": "~8.2.3", "@angular/cdk": "~10.0.1",
"@angular/common": "~8.2.14", "@angular/common": "~10.0.3",
"@angular/compiler": "~8.2.14", "@angular/compiler": "~10.0.3",
"@angular/core": "~8.2.14", "@angular/core": "~10.0.3",
"@angular/flex-layout": "^8.0.0-beta.27", "@angular/flex-layout": "^10.0.0-beta.32",
"@angular/forms": "~8.2.14", "@angular/forms": "~10.0.3",
"@angular/material": "^8.2.3", "@angular/material": "^10.0.1",
"@angular/platform-browser": "~8.2.14", "@angular/platform-browser": "~10.0.3",
"@angular/platform-browser-dynamic": "~8.2.14", "@angular/platform-browser-dynamic": "~10.0.3",
"@angular/router": "~8.2.14", "@angular/router": "~10.0.3",
"bootstrap": "^4.4.1", "bootstrap": "^4.5.0",
"hammerjs": "^2.0.8", "ipfs-css": "^1.2.0",
"ipfs-css": "^0.13.1", "rxjs": "~6.6.0",
"rxjs": "~6.5.3", "tslib": "^2.0.0",
"tslib": "^1.10.0", "zone.js": "~0.10.3"
"zone.js": "~0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.803.20", "@angular-devkit/build-angular": "~0.1000.2",
"@angular/cli": "~8.3.20", "@angular/cli": "~10.0.2",
"@angular/compiler-cli": "~8.2.14", "@angular/compiler-cli": "~10.0.3",
"@angular/language-service": "~8.2.14", "@angular/language-service": "~10.0.3",
"@types/jasmine": "~3.3.8", "@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4", "@types/node": "^12.11.1",
"codelyzer": "^5.0.0", "codelyzer": "^6.0.0",
"jasmine-core": "~3.4.0", "jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~4.2.1", "jasmine-spec-reporter": "~5.0.0",
"karma": "~4.1.0", "karma": "~5.0.0",
"karma-chrome-launcher": "~2.2.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.0.1", "karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~2.0.1", "karma-jasmine": "~3.3.0",
"karma-jasmine-html-reporter": "^1.4.0", "karma-jasmine-html-reporter": "^1.5.0",
"protractor": "~5.4.0", "protractor": "~7.0.0",
"rxjs-tslint-rules": "^4.26.3", "rxjs-tslint-rules": "^4.33.3",
"ts-node": "~7.0.0", "ts-node": "~8.10.2",
"tslint": "~5.15.0", "tslint": "~6.1.2",
"tslint-consistent-codestyle": "^1.16.0", "tslint-consistent-codestyle": "^1.16.0",
"tslint-origin-ordered-imports-rule": "^1.2.2", "tslint-origin-ordered-imports-rule": "^1.3.0-0",
"tslint-rxjs-subject-restrictions-rule": "^1.0.4", "tslint-rxjs-subject-restrictions-rule": "^1.0.4",
"typescript": "~3.5.3" "typescript": "~3.9.6"
} }
} }

View File

@ -1 +1,10 @@
<mat-toolbar color="primary" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="1em">
<h1>Public IPFS Cacher</h1>
<!-- Theme Switcher -->
<button mat-icon-button="">
<mat-icon (click)="themeService.switchTheme()">{{themeService.icon}}</mat-icon>
</button>
</mat-toolbar>
<router-outlet></router-outlet> <router-outlet></router-outlet>

View File

@ -1,9 +1,9 @@
import { TestBed, async } from '@angular/core/testing'; import { async, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
describe('AppComponent', () => { describe('AppComponent', (): void => {
beforeEach(async(() => { beforeEach(async((): void => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [
RouterTestingModule RouterTestingModule
@ -14,19 +14,19 @@ describe('AppComponent', () => {
}).compileComponents(); }).compileComponents();
})); }));
it('should create the app', () => { it('should create the app', (): void => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
}); });
it(`should have as title 'public-gateway-cacher'`, () => { it(`should have as title 'public-gateway-cacher'`, (): void => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance; const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('public-gateway-cacher'); expect(app.title).toEqual('public-gateway-cacher');
}); });
it('should render title', () => { it('should render title', (): void => {
const fixture = TestBed.createComponent(AppComponent); const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement; const compiled = fixture.debugElement.nativeElement;

View File

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { ThemeService } from './services/theme.service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -6,5 +7,7 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.scss'] styleUrls: ['./app.component.scss']
}) })
export class AppComponent { export class AppComponent {
title = 'public-gateway-cacher'; constructor(
public readonly themeService: ThemeService
) { }
} }

View File

@ -1,6 +1,10 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http'; import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
@ -16,6 +20,12 @@ import { AppComponent } from './app.component';
BrowserAnimationsModule, BrowserAnimationsModule,
HttpClientModule, HttpClientModule,
AppRoutingModule, AppRoutingModule,
// Material
FlexLayoutModule,
MatButtonModule,
MatIconModule,
MatToolbarModule,
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -0,0 +1,4 @@
export enum Protocol {
IPFS = 'ipfs',
IPNS = 'ipns',
}

View File

@ -0,0 +1,4 @@
export enum Theme {
Light = 'theme-light',
Dark = 'theme-dark',
}

9
src/app/package.json Normal file
View File

@ -0,0 +1,9 @@
{
"name": "public-gateway-cacher",
"private": true,
"description_1": "This is a special package.json file that is not used by package managers.",
"description_2": "It is used to tell the tools and bundlers whether the code under this directory is free of code with non-local side-effect. Any code that does have non-local side-effects can't be well optimized (tree-shaken) and will result in unnecessary increased payload size.",
"description_3": "It should be safe to set this option to 'false' for new applications, but existing code bases could be broken when built with the production config if the application code does contain non-local side-effects that the application depends on.",
"description_4": "To learn more about this file see: https://angular.io/config/app-package-json.",
"sideEffects": false
}

View File

@ -1,18 +1,16 @@
<div fxLayout="column" fxLayoutAlign="space-evenly center" fxLayoutGap="1em" class="container"> <div class="container" fxLayout="column" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<h1>Public IPFS Cacher</h1>
<!-- IPFS --> <!-- IPFS -->
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em"> <form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash --> <!-- Hash -->
<mat-form-field> <mat-form-field [color]="inputColour">
<mat-label>IPFS</mat-label> <mat-label>IPFS</mat-label>
<input matInput [(ngModel)]="ipfs" name="ipfs"> <input name="ipfs" [(ngModel)]="ipfs" matInput>
</mat-form-field> </mat-form-field>
<!-- Cache --> <!-- Cache -->
<button mat-flat-button color="primary" type="button" (click)="cacheIPFS()">Cache</button> <button (click)="cacheIPFS()" type="button" mat-flat-button color="primary">Cache</button>
</form> </form>
@ -20,29 +18,27 @@
<form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em"> <form fxLayout="row" fxLayoutAlign="space-evenly center" fxLayoutGap="1em">
<!-- Hash --> <!-- Hash -->
<mat-form-field> <mat-form-field [color]="inputColour">
<mat-label>IPNS</mat-label> <mat-label>IPNS</mat-label>
<input matInput [(ngModel)]="ipns" name="ipns"> <input name="ipns" [(ngModel)]="ipns" matInput>
</mat-form-field> </mat-form-field>
<!-- Cache --> <!-- Cache -->
<button mat-flat-button color="primary" type="button" (click)="cacheIPNS()">Cache</button> <button (click)="cacheIPNS()" type="button" mat-flat-button color="primary">Cache</button>
</form> </form>
<mat-progress-bar *ngIf="subscriptions.length" mode="determinate" [value]="dataSource.data.length / gateways.length * 100"> <mat-progress-bar [value]="dataSource.data.length / gateways.length * 100" *ngIf="subscriptions.length" mode="determinate"
color="primary">
</mat-progress-bar> </mat-progress-bar>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table class="mat-elevation-z8" [dataSource]="dataSource" mat-table>
<!-- Result Column --> <!-- Result Column -->
<ng-container matColumnDef="error"> <ng-container matColumnDef="icon">
<th mat-header-cell *matHeaderCellDef> Status </th> <th mat-header-cell *matHeaderCellDef> Status </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<div [ngSwitch]="element.error"> <span [matTooltip]="element.message"> {{ element.icon }} </span>
<div *ngSwitchCase="null"></div>
<div *ngSwitchDefault [matTooltip]="element.error.statusText"></div>
</div>
</td> </td>
</ng-container> </ng-container>
@ -50,12 +46,18 @@
<ng-container matColumnDef="gateway"> <ng-container matColumnDef="gateway">
<th mat-header-cell *matHeaderCellDef> Gateway </th> <th mat-header-cell *matHeaderCellDef> Gateway </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<div [ngSwitch]="element.error"> <div [ngSwitch]="element.ok">
<div *ngSwitchCase="null"> <div *ngSwitchCase="true">
<strong><a href="{{ element.gateway }}#x-ipfs-companion-no-redirect" class="aqua"> {{ element.gateway }} </a></strong> <strong>
<a class="aqua" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank">
{{ element.gateway }}
</a>
</strong>
</div> </div>
<div *ngSwitchDefault> <div *ngSwitchCase="false">
<a href="{{ element.gateway }}#x-ipfs-companion-no-redirect" class="aqua-muted"> {{ element.gateway }} </a> <a class="aqua-muted" href="{{ element.gateway }}#x-ipfs-companion-no-redirect" target="_blank">
{{ element.gateway }}
</a>
</div> </div>
</div> </div>
</td> </td>
@ -70,14 +72,15 @@
<h3>About</h3> <h3>About</h3>
<p> <p>
This allows you to cache a specific IPFS hash to a bunch of public gateways. This allows you to cache a specific IPFS hash to a bunch of public gateways.
It's inspired from <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>. It's inspired from <a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>.
The source code is available at <a The source code is available at <a class="link"
href="https://gitlab.com/NatoBoram/public-gateway-cacher">gitlab.com/NatoBoram/public-gateway-cacher</a>. href="https://gitlab.com/NatoBoram/public-gateway-cacher">gitlab.com/NatoBoram/public-gateway-cacher</a>.
</p> </p>
<p> <p>
If you'd like to add a new public gateway, If you'd like to add a new public gateway,
please go to <a href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>, please go to <a class="link" href="https://github.com/ipfs/public-gateway-checker">github.com/ipfs/public-gateway-checker</a>,
submit a pull request then open an issue <a href="https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new">here</a>. submit a pull request then open an issue <a class="link"
href="https://gitlab.com/NatoBoram/public-gateway-cacher/issues/new">here</a>.
</p> </p>
</div> </div>

View File

@ -15,7 +15,7 @@
padding: 1em; padding: 1em;
} }
.mat-column-error { .mat-column-icon {
text-align: center; text-align: center;
width: 5em; width: 5em;
max-width: 100%; max-width: 100%;

View File

@ -1,24 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { PagesComponent } from './pages.component'; import { PagesComponent } from './pages.component';
describe('PagesComponent', () => { describe('PagesComponent', (): void => {
let component: PagesComponent; let component: PagesComponent;
let fixture: ComponentFixture<PagesComponent>; let fixture: ComponentFixture<PagesComponent>;
beforeEach(async(() => { beforeEach(async((): void => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [PagesComponent] declarations: [PagesComponent]
}) })
.compileComponents(); .compileComponents();
})); }));
beforeEach(() => { beforeEach((): void => {
fixture = TestBed.createComponent(PagesComponent); fixture = TestBed.createComponent(PagesComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', (): void => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,75 +1,133 @@
import { HttpErrorResponse } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import { Component, OnInit, ViewChild } from '@angular/core'; import { Component, EventEmitter, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { ThemePalette } from '@angular/material/core';
import { MatTable, MatTableDataSource } from '@angular/material/table'; import { MatTable, MatTableDataSource } from '@angular/material/table';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { environment } from '../../environments/environment';
import { Protocol } from '../enums/protocol.enum';
import { Theme } from '../enums/theme.enum';
import { GatewayService } from '../services/gateway.service'; import { GatewayService } from '../services/gateway.service';
import { ThemeService } from '../services/theme.service';
@Component({ @Component({
selector: 'app-pages', selector: 'app-pages',
templateUrl: './pages.component.html', templateUrl: './pages.component.html',
styleUrls: ['./pages.component.scss'] styleUrls: ['./pages.component.scss']
}) })
export class PagesComponent implements OnInit { export class PagesComponent implements OnInit, OnDestroy {
gateways: string[]; @ViewChild(MatTable) matTable!: MatTable<Result>;
ipfs: string;
ipns: string;
dataSource: MatTableDataSource<Result>;
displayedColumns = [
'error',
'gateway',
];
subscriptions: Subscription[] = [];
@ViewChild(MatTable, { static: false }) matTable: MatTable<Result>; gateways!: string[];
inputColour: ThemePalette = 'primary';
ipfs = '';
ipns = '';
readonly dataSource = new MatTableDataSource<Result>([]);
readonly displayedColumns: ['icon', 'gateway'] = ['icon', 'gateway'];
readonly subscriptions: Subscription[] = [];
private readonly destroy$ = new EventEmitter<void>();
constructor( constructor(
private readonly gatewayService: GatewayService private readonly gatewayService: GatewayService,
private readonly themeService: ThemeService
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
this.dataSource = new MatTableDataSource([]); this.gatewayService.list().subscribe((gateways): void => { this.gateways = gateways; });
this.gatewayService.list().subscribe(gateways => this.gateways = gateways);
// Theme
this.setColours(this.themeService.current);
this.themeService.valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((theme): void => {
this.setColours(theme);
});
}
ngOnDestroy(): void {
this.destroy$.complete();
} }
cacheIPFS(): void { cacheIPFS(): void {
this.cache('ipfs', this.ipfs); this.ipfs = this.ipfs.trim();
this.cache(Protocol.IPFS, this.ipfs);
} }
cacheIPNS(): void { cacheIPNS(): void {
this.cache('ipns', this.ipns); this.ipns = this.ipns.trim();
this.cache(Protocol.IPNS, this.ipns);
} }
cache(type: string, hash: string): void { cache(protocol: Protocol, hashpath: string): void {
// Clear subscriptions
while (this.subscriptions.length) { while (this.subscriptions.length) {
const sub = this.subscriptions.pop(); const sub = this.subscriptions.pop();
if (!sub.closed) { if (sub && !sub.closed) {
sub.unsubscribe(); sub.unsubscribe();
} }
} }
// Clear table
this.dataSource.data = []; this.dataSource.data = [];
this.matTable.renderRows(); this.matTable.renderRows();
console.clear(); console.clear();
this.gateways.forEach(gateway => { this.gateways.forEach((gateway): void => {
this.subscriptions.push( this.subscriptions.push(
this.gatewayService.get(gateway, type, hash).subscribe(_ => { this.gatewayService.get(gateway, protocol, hashpath).subscribe((resp): void => {
this.dataSource.data.push({ gateway: `${gateway.replace(':type', type).replace(':hash', hash)}`, error: null }); this.dataSource.data.push({
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: resp.statusText,
icon: this.getIcon(resp.status),
ok: resp.ok,
});
this.matTable.renderRows(); this.matTable.renderRows();
}, (error: HttpErrorResponse) => { }, (error: HttpErrorResponse): void => {
this.dataSource.data.push({ gateway: `${gateway.replace(':type', type).replace(':hash', hash)}`, error }); this.dataSource.data.push({
gateway: this.gatewayService.url(gateway, protocol, hashpath),
message: error.statusText,
icon: this.getIcon(error.status),
ok: error.ok,
});
this.matTable.renderRows(); this.matTable.renderRows();
}) })
); );
}); });
}
private setColours(theme: Theme): void {
switch (theme) {
case Theme.Light:
this.inputColour = 'primary';
break;
case Theme.Dark:
this.inputColour = 'accent';
break;
default:
break;
}
}
private getIcon(status: number): string {
if (status >= 200 && status < 300) { return '✅'; }
switch (status) {
case 0: return '❌';
case 403: return '⛔';
case 404: return '❓';
case 500: return '❗';
default: return environment.production ? '❌' : '❔';
}
} }
} }
interface Result { interface Result {
gateway: string; gateway: string;
error: HttpErrorResponse; message: string;
icon: string;
ok: boolean;
} }

View File

@ -1,12 +1,11 @@
import { TestBed } from '@angular/core/testing'; import { TestBed, TestBedStatic } from '@angular/core/testing';
import { GatewayService } from './gateway.service'; import { GatewayService } from './gateway.service';
describe('GatewayService', () => { describe('GatewayService', (): void => {
beforeEach(() => TestBed.configureTestingModule({})); beforeEach((): TestBedStatic => TestBed.configureTestingModule({}));
it('should be created', () => { it('should be created', (): void => {
const service: GatewayService = TestBed.get(GatewayService); const service: GatewayService = TestBed.inject(GatewayService);
expect(service).toBeTruthy(); expect(service).toBeTruthy();
}); });
}); });

View File

@ -1,7 +1,8 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { environment } from '../../environments/environment'; import { environment } from '../../environments/environment';
import { Protocol } from '../enums/protocol.enum';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -16,14 +17,21 @@ export class GatewayService {
return this.http.get<string[]>( return this.http.get<string[]>(
environment.base_href && environment.base_href !== '/' environment.base_href && environment.base_href !== '/'
? `${environment.base_href}/assets/json/gateways.json` ? `${environment.base_href}/assets/json/gateways.json`
: `${document.querySelector('base').href}/assets/json/gateways.json` : `${document.querySelector('base')?.href}assets/json/gateways.json`
); );
} }
get(gateway: string, type: string, hash: string): Observable<Blob> { get(gateway: string, protocol: Protocol, hashpath: string): Observable<HttpResponse<string>> {
return this.http.get<Blob>(`${gateway.replace(':type', type).replace(':hash', hash)}#x-ipfs-companion-no-redirect`, { return this.http.get(`${this.url(gateway, protocol, hashpath)}#x-ipfs-companion-no-redirect`, {
responseType: 'blob' as 'json' observe: 'response',
responseType: 'text',
}); });
} }
url(gateway: string, protocol: Protocol, hashpath: string): string {
const splits: string[] = hashpath.split('/');
const url: string = gateway.replace(':type', protocol).replace(':hash', splits.shift() || '');
return splits.length ? [url, splits.join('/')].join('/') : url;
}
} }

View File

@ -0,0 +1,15 @@
import { TestBed } from '@angular/core/testing';
import { ThemeService } from './theme.service';
describe('ThemeService', (): void => {
let service: ThemeService;
beforeEach((): void => {
TestBed.configureTestingModule({});
service = TestBed.inject(ThemeService);
});
it('should be created', (): void => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { Theme } from '../enums/theme.enum';
function enumGuard<T>(enumeration: T): (token: unknown) => token is T[keyof T] {
return (token: unknown): token is T[keyof T] => Object.values(enumeration).includes(token);
}
@Injectable({
providedIn: 'root'
})
export class ThemeService {
current = Theme.Light;
icon = 'brightness_low';
readonly valueChanges: Observable<Theme>;
private readonly subject$ = new Subject<Theme>();
constructor() {
const stored = localStorage.getItem('theme');
if (enumGuard(Theme)(stored)) {
this.setTheme(stored);
}
this.valueChanges = this.subject$.asObservable();
}
switchTheme(): void {
this.setTheme(this.current === Theme.Light ? Theme.Dark : Theme.Light);
}
setTheme(theme: Theme): void {
document.querySelector('body')?.classList.remove(this.current);
document.querySelector('body')?.classList.add(theme);
this.current = theme;
this.icon = this.getIcon(theme);
this.subject$.next(theme);
localStorage.setItem('theme', theme);
}
getIcon(theme: Theme): string {
switch (theme) {
case Theme.Dark: return 'brightness_high';
case Theme.Light:
default: return 'brightness_low';
}
}
}

View File

@ -1,22 +1,16 @@
[ [
"https://ipfs.io/:type/:hash", "https://ipfs.io/:type/:hash",
"https://:hash.:type.dweb.link",
"https://gateway.ipfs.io/:type/:hash", "https://gateway.ipfs.io/:type/:hash",
"https://ipfs.infura.io/:type/:hash", "https://ipfs.infura.io/:type/:hash",
"https://rx14.co.uk/:type/:hash",
"https://ninetailed.ninja/:type/:hash", "https://ninetailed.ninja/:type/:hash",
"https://ipfs.globalupload.io/:hash", "https://ipfs.globalupload.io/:hash",
"https://ipfs.jes.xxx/:type/:hash",
"https://siderus.io/:type/:hash",
"https://eu.siderus.io/:type/:hash",
"https://na.siderus.io/:type/:hash",
"https://ap.siderus.io/:type/:hash",
"https://10.via0.com/:type/:hash", "https://10.via0.com/:type/:hash",
"https://ipfs.eternum.io/:type/:hash", "https://ipfs.eternum.io/:type/:hash",
"https://hardbin.com/:type/:hash", "https://hardbin.com/:type/:hash",
"https://ipfs.wa.hle.rs/:type/:hash",
"https://gateway.blocksec.com/:type/:hash", "https://gateway.blocksec.com/:type/:hash",
"https://ipfs.renehsz.com/:type/:hash",
"https://cloudflare-ipfs.com/:type/:hash", "https://cloudflare-ipfs.com/:type/:hash",
"https://:hash.:type.cf-ipfs.com",
"https://ipns.co/:hash", "https://ipns.co/:hash",
"https://ipfs.mrh.io/:type/:hash", "https://ipfs.mrh.io/:type/:hash",
"https://gateway.originprotocol.com/:type/:hash", "https://gateway.originprotocol.com/:type/:hash",
@ -33,7 +27,30 @@
"https://ipfs.privacytools.io/:type/:hash", "https://ipfs.privacytools.io/:type/:hash",
"https://ipfs.jeroendeneef.com/:type/:hash", "https://ipfs.jeroendeneef.com/:type/:hash",
"https://permaweb.io/:type/:hash", "https://permaweb.io/:type/:hash",
"https://ipfs.stibarc.gq/:type/:hash", "https://ipfs.stibarc.com/:type/:hash",
"https://ipfs.best-practice.se/:type/:hash", "https://ipfs.best-practice.se/:type/:hash",
"https://lineageos-on-ipfs.com/:type/:hash" "https://:hash.:type.2read.net",
"https://ipfs.2read.net/:type/:hash",
"https://storjipfs-gateway.com/:type/:hash",
"https://ipfs.runfission.com/:type/:hash",
"https://trusti.id/:type/:hash",
"https://:hash.:type.cosmos-ink.net",
"https://ipfs.overpi.com/:type/:hash",
"https://ipfs.lc/:type/:hash",
"https://ipfs.leiyun.org/:type/:hash",
"https://ipfs.ink/:type/:hash",
"https://filecoin.io/:type/:hash",
"https://ipfs.jes.xxx/:type/:hash",
"https://ipfs.oceanprotocol.com/:type/:hash",
"https://d26g9c7mfuzstv.cloudfront.net/:type/:hash",
"https://ipfsgateway.makersplace.com/:type/:hash",
"https://gateway.ravenland.org/:type/:hash",
"https://ipfs.smartsignature.io/:type/:hash",
"https://ipfs.funnychain.co/:type/:hash",
"https://ipfs.telos.miami/:type/:hash",
"https://robotizing.net/:type/:hash",
"https://ipfs.mttk.net/:type/:hash",
"https://ipfs.fleek.co/:type/:hash",
"https://ipfs.jbb.one/:type/:hash",
"https://ipfs.yt/:type/:hash"
] ]

View File

@ -17,12 +17,9 @@
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- IPFS-CSS -->
<link href="assets/ipfs-css/ipfs.css" rel="stylesheet">
</head> </head>
<body> <body class="mat-app-background theme-light">
<app-root></app-root> <app-root></app-root>
</body> </body>

View File

@ -1,6 +1,5 @@
import { enableProdMode } from '@angular/core'; import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import 'hammerjs';
import { AppModule } from './app/app.module'; import { AppModule } from './app/app.module';
import { environment } from './environments/environment'; import { environment } from './environments/environment';
@ -9,4 +8,4 @@ if (environment.production) {
} }
platformBrowserDynamic().bootstrapModule(AppModule) platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err)); .catch((err): void => console.error(err));

View File

@ -8,22 +8,32 @@
// Be sure that you only ever include this mixin once! // Be sure that you only ever include this mixin once!
@include mat-core(); @include mat-core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss // // Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker // // (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/ // // hue. Available color palettes: https://material.io/design/color/
$public-gateway-cacher-primary: mat-palette($mat-indigo); // $public-gateway-cacher-primary: mat-palette($mat-indigo);
$public-gateway-cacher-accent: mat-palette($mat-pink, A200, A100, A400); // $public-gateway-cacher-accent: mat-palette($mat-pink, A200, A100, A400);
// The warn palette is optional (defaults to red). // // The warn palette is optional (defaults to red).
$public-gateway-cacher-warn: mat-palette($mat-red); // $public-gateway-cacher-warn: mat-palette($mat-red);
// Create the theme object (a Sass map containing all of the palettes). // // Create the theme object (a Sass map containing all of the palettes).
$public-gateway-cacher-theme: mat-light-theme($public-gateway-cacher-primary, $public-gateway-cacher-accent, $public-gateway-cacher-warn); // $public-gateway-cacher-theme: mat-light-theme($public-gateway-cacher-primary, $public-gateway-cacher-accent, $public-gateway-cacher-warn);
// Include theme styles for core and each component used in your app. // // Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component // // Alternatively, you can import and @include the theme mixins for each component
// that you are using. // // that you are using.
@include angular-material-theme($public-gateway-cacher-theme); // @include angular-material-theme($public-gateway-cacher-theme);
@import 'styles/ipfs-themes.scss';
.theme-light {
@include angular-material-theme($ipfs-light-theme);
}
.theme-dark {
@include angular-material-theme($ipfs-dark-theme);
}
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */
@ -38,3 +48,4 @@ body {
} }
@import '~bootstrap/scss/bootstrap-grid.scss'; @import '~bootstrap/scss/bootstrap-grid.scss';
@import '~ipfs-css/theme.scss';

View File

@ -0,0 +1,23 @@
$ipfs-colour-navy: (default: #0B3A53,
lighter: #3e6480,
darker: #00142a,
contrast: (default: $light-primary-text,
lighter: $light-primary-text,
darker: $light-primary-text,
));
$ipfs-colour-aqua: (default: #69c5cd,
lighter: #9df8ff,
darker: #32949c,
contrast: (default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
));
$ipfs-colour-yellow: (default: #f39021,
lighter: #ffc155,
darker: #bb6200,
contrast: (default: $dark-primary-text,
lighter: $dark-primary-text,
darker: $dark-primary-text,
));

View File

@ -0,0 +1,5 @@
@import 'ipfs-colours.scss';
$ipfs-primary: mat-palette($ipfs-colour-navy, 'default', 'lighter', 'darker');
$ipfs-accent: mat-palette($ipfs-colour-aqua, 'default', 'lighter', 'darker');
$ipfs-warn: mat-palette($ipfs-colour-yellow, 'default', 'lighter', 'darker');

View File

@ -0,0 +1,4 @@
@import 'ipfs-palettes.scss';
$ipfs-light-theme: mat-light-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);
$ipfs-dark-theme: mat-dark-theme($ipfs-primary, $ipfs-accent, $ipfs-warn);

View File

@ -1,5 +1,6 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": []
@ -10,8 +11,5 @@
], ],
"include": [ "include": [
"src/**/*.d.ts" "src/**/*.d.ts"
], ]
"angularCompilerOptions": {
"enableIvy": false
}
} }

29
tsconfig.base.json Normal file
View File

@ -0,0 +1,29 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true,
"strictTemplates": true
}
}

View File

@ -1,26 +1,20 @@
/*
This is a "Solution Style" tsconfig.json file, and is used by editors and TypeScripts language server to improve development experience.
It is not intended to be used to perform a compilation.
To learn more about this file see: https://angular.io/config/solution-tsconfig.
*/
{ {
"compileOnSave": false, "files": [],
"compilerOptions": { "references": [
"baseUrl": "./", {
"outDir": "./dist/out-tsc", "path": "./tsconfig.app.json"
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
}, },
"angularCompilerOptions": { {
"fullTemplateTypeCheck": true, "path": "./tsconfig.spec.json"
"strictInjectionParameters": true },
{
"path": "./e2e/tsconfig.json"
} }
]
} }

View File

@ -1,10 +1,10 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/spec", "outDir": "./out-tsc/spec",
"types": [ "types": [
"jasmine", "jasmine"
"node"
] ]
}, },
"files": [ "files": [
@ -14,8 +14,5 @@
"include": [ "include": [
"src/**/*.spec.ts", "src/**/*.spec.ts",
"src/**/*.d.ts" "src/**/*.d.ts"
], ]
"angularCompilerOptions": {
"enableIvy": false
}
} }

View File

@ -3,14 +3,56 @@
"tslint:recommended", "tslint:recommended",
"rxjs-tslint-rules" "rxjs-tslint-rules"
], ],
"linterOptions": {
"exclude": [
"**/*-routing.module.ts",
"src/polyfills.ts",
"src/test.ts",
"**/*.po.ts"
]
},
"rules": { "rules": {
"align": {
"options": [
"parameters",
"statements"
]
},
"array-type": false, "array-type": false,
"arrow-parens": false, "arrow-parens": false,
"arrow-return-shorthand": [
true,
"multiline"
],
"ban-types": [
true,
[
"Object",
"Use {} instead."
],
[
"String"
]
],
"callable-types": true,
"component-class-suffix": true,
"component-max-inline-declarations": true,
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"contextual-decorator": false,
"contextual-lifecycle": true,
"curly": true,
"cyclomatic-complexity": [
true,
20
],
"deprecation": { "deprecation": {
"severity": "warning" "severity": "warning"
}, },
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true, "directive-class-suffix": true,
"directive-selector": [ "directive-selector": [
true, true,
@ -18,23 +60,34 @@
"app", "app",
"camelCase" "camelCase"
], ],
"component-selector": [ "encoding": true,
true, "eofline": true,
"element",
"app",
"kebab-case"
],
"import-blacklist": [ "import-blacklist": [
true, true,
"rxjs/Rx" "rxjs/Rx"
], ],
"import-destructuring-spacing": true,
"import-spacing": true,
"increment-decrement": [
true,
"allow-post"
],
"indent": {
"options": [
"spaces"
]
},
"interface-name": false, "interface-name": false,
"max-classes-per-file": false, "max-classes-per-file": false,
"max-file-line-count": [
true,
400
],
"max-line-length": [ "max-line-length": [
true, true,
{ {
"limit": 140, "ignore-pattern": "^import |^export {(.*?)}|class [a-zA-Z]+ implements |// ",
"ignore-pattern": "^import |^export {(.*?)}|class [a-zA-Z]+ implements |// " "limit": 140
} }
], ],
"member-access": false, "member-access": false,
@ -57,6 +110,17 @@
] ]
} }
], ],
"newline-before-return": false,
"no-any": [
true,
{
"ignore-rest-args": true
}
],
"no-arg": true,
"no-attribute-decorator": true,
"no-collapsible-if": true,
"no-conflicting-lifecycle": true,
"no-consecutive-blank-lines": [ "no-consecutive-blank-lines": [
true, true,
1 1
@ -69,18 +133,72 @@
"timeEnd", "timeEnd",
"trace" "trace"
], ],
"no-default-export": true,
"no-default-import": true,
"no-duplicate-imports": true,
"no-duplicate-super": true,
"no-duplicate-switch-case": true,
"no-empty": [ "no-empty": [
true, true,
"allow-empty-functions" "allow-empty-functions"
], ],
"no-for-in-array": true,
"no-forward-ref": true,
"no-host-metadata-property": true,
"no-implicit-dependencies": [
false,
"dev"
],
"no-import-side-effect": [
true,
{
"ignore-module": "(hammerjs|core-js|zone.js)"
}
],
"no-inferrable-types": [ "no-inferrable-types": [
true, true,
"ignore-params" "ignore-params"
], ],
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-invalid-template-strings": true,
"no-invalid-this": [
true,
"check-function-in-method"
],
"no-lifecycle-call": true,
"no-misused-new": true,
"no-non-null-assertion": true, "no-non-null-assertion": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"no-pipe-impure": true,
"no-queries-metadata-property": true,
"no-redundant-jsdoc": true, "no-redundant-jsdoc": true,
"no-reference": true,
"no-require-imports": true,
"no-return-await": true,
"no-return-undefined": true,
"no-static-this": true,
"no-switch-case-fall-through": true, "no-switch-case-fall-through": true,
"no-use-before-declare": true, "no-tautology-expression": true,
"no-this-assignment": true,
"no-trailing-whitespace": true,
"no-unbound-method": true,
"no-unnecessary-callback-wrapper": true,
"no-unnecessary-class": [
true,
"allow-constructor-only",
"allow-static-only",
"allow-empty-class"
],
"no-unnecessary-initializer": true,
"no-unnecessary-type-assertion": true,
"no-unsafe-finally": true,
"no-unused": true,
"no-unused-css": true,
"no-var-keyword": true,
"no-var-requires": false, "no-var-requires": false,
"object-literal-key-quotes": [ "object-literal-key-quotes": [
true, true,
@ -88,43 +206,60 @@
], ],
"object-literal-sort-keys": false, "object-literal-sort-keys": false,
"ordered-imports": false, "ordered-imports": false,
"origin-ordered-imports": [
true
],
"prefer-const": true,
"prefer-inline-decorator": false,
"prefer-output-readonly": true,
"prefer-readonly": true,
"prefer-template": true,
"quotemark": [ "quotemark": [
true, true,
"single" "single"
], ],
"no-conflicting-lifecycle": true, "radix": false,
"no-host-metadata-property": true, "restrict-plus-operands": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"origin-ordered-imports": [
true
],
"rx-subject-restrictions": true, "rx-subject-restrictions": true,
"ban-types": [ "rxjs-no-compat": true,
true, "rxjs-no-internal": true,
[ "semicolon": {
"Object", "options": [
"Use {} instead." "always"
],
[
"String"
] ]
], },
"no-unnecessary-class": [ "space-before-function-paren": [
true, true,
"allow-constructor-only", {
"allow-static-only", "anonymous": "never",
"allow-empty-class" "asyncArrow": "always",
"constructor": "never",
"method": "never",
"named": "never"
}
],
"space-within-parens": true,
"template-banana-in-box": true,
"template-conditional-complexity": true,
"template-no-call-expression": true,
"template-no-negated-async": true,
"template-use-track-by-function": true,
"trailing-comma": [
true,
{
"esSpecCompliant": true,
"multiline": {
"arrays": "ignore",
"functions": "never",
"objects": "ignore",
"typeLiterals": "ignore"
}
}
],
"triple-equals": [
true,
"allow-null-check"
], ],
"no-for-in-array": true,
"typedef": [ "typedef": [
true, true,
"call-signature", "call-signature",
@ -132,115 +267,35 @@
"object-destructuring", "object-destructuring",
"arrow-call-signature" "arrow-call-signature"
], ],
"no-unused": true, "typedef-whitespace": {
"no-return-undefined": true, "options": [
"no-collapsible-if": true,
"arrow-return-shorthand": [
true,
"multiline"
],
"no-static-this": true,
"template-use-track-by-function": true,
"prefer-template": true,
"contextual-decorator": false,
"no-pipe-impure": true,
"component-max-inline-declarations": true,
"no-attribute-decorator": true,
"no-forward-ref": true,
"no-lifecycle-call": true,
"template-no-call-expression": true,
"no-unused-css": true,
"prefer-output-readonly": true,
"template-conditional-complexity": true,
"use-pipe-decorator": true,
"use-component-view-encapsulation": true,
"no-queries-metadata-property": true,
"prefer-inline-decorator": false,
"import-destructuring-spacing": true,
"newline-before-return": false,
"no-trailing-whitespace": true,
"space-within-parens": true,
"space-before-function-paren": [
true,
{ {
"anonymous": "never", "call-signature": "nospace",
"named": "never", "index-signature": "nospace",
"asyncArrow": "always", "parameter": "nospace",
"method": "never", "property-declaration": "nospace",
"constructor": "never" "variable-declaration": "nospace"
} },
],
"max-file-line-count": [
true,
400
],
"cyclomatic-complexity": [
true,
20
],
"encoding": true,
"no-unsafe-finally": true,
"no-duplicate-switch-case": true,
"increment-decrement": [
true,
"allow-post"
],
"triple-equals": [
true,
"allow-null-check"
],
"no-invalid-template-strings": true,
"no-unnecessary-type-assertion": true,
"callable-types": true,
"no-reference": true,
"no-default-import": true,
"no-default-export": true,
"no-require-imports": true,
"no-duplicate-imports": true,
"no-import-side-effect": [
true,
{ {
"ignore-module": "(hammerjs|core-js|zone.js)" "call-signature": "onespace",
"index-signature": "onespace",
"parameter": "onespace",
"property-declaration": "onespace",
"variable-declaration": "onespace"
} }
], ]
"no-implicit-dependencies": [ },
true,
"dev"
],
"no-unnecessary-initializer": true,
"no-var-keyword": true,
"prefer-const": true,
"no-return-await": true,
"no-unnecessary-callback-wrapper": true,
"no-arg": true,
"eofline": true,
"no-tautology-expression": true,
"use-isnan": true,
"restrict-plus-operands": true,
"no-this-assignment": true,
"no-invalid-this": [
true,
"check-function-in-method"
],
"no-unbound-method": true,
"prefer-readonly": true,
"radix": false,
"no-misused-new": true,
"no-duplicate-super": true,
"rxjs-no-compat": true,
"rxjs-no-internal": true,
"unnecessary-else": [ "unnecessary-else": [
true, true,
{ {
"allow-else-if": true "allow-else-if": true
} }
], ],
"no-any": [ "use-component-view-encapsulation": true,
true, "use-isnan": true,
{ "use-lifecycle-interface": true,
"ignore-rest-args": true "use-pipe-decorator": true,
} "use-pipe-transform-interface": true,
],
"variable-name": { "variable-name": {
"options": [ "options": [
"ban-keywords", "ban-keywords",
@ -249,31 +304,21 @@
"allow-pascal-case" "allow-pascal-case"
] ]
}, },
"trailing-comma": [ "whitespace": {
true, "options": [
{ "check-branch",
"multiline": { "check-decl",
"objects": "ignore", "check-operator",
"arrays": "ignore", "check-separator",
"functions": "never", "check-type",
"typeLiterals": "ignore" "check-typecast"
},
"esSpecCompliant": true
}
] ]
}
}, },
"rulesDirectory": [ "rulesDirectory": [
"codelyzer", "codelyzer",
"node_modules/tslint-origin-ordered-imports-rule/dist", "node_modules/tslint-origin-ordered-imports-rule/dist",
"node_modules/tslint-rxjs-subject-restrictions-rule/dist", "node_modules/tslint-rxjs-subject-restrictions-rule/dist",
"node_modules/tslint-consistent-codestyle/rules" "node_modules/tslint-consistent-codestyle/rules"
],
"linterOptions": {
"exclude": [
"**/*-routing.module.ts",
"src/polyfills.ts",
"src/test.ts",
"**/*.po.ts"
] ]
}
} }

6671
yarn.lock

File diff suppressed because it is too large Load Diff