├── .editorconfig ├── .gitignore ├── .vscode └── settings.json ├── LICENSE.md ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── main.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── file.service.spec.ts │ ├── file.service.ts │ ├── md-viewer │ │ ├── md-viewer.component.css │ │ ├── md-viewer.component.html │ │ ├── md-viewer.component.spec.ts │ │ └── md-viewer.component.ts │ ├── modulebar │ │ ├── modulebar.component.css │ │ ├── modulebar.component.html │ │ ├── modulebar.component.spec.ts │ │ └── modulebar.component.ts │ └── projectbar │ │ ├── projectbar.component.css │ │ ├── projectbar.component.html │ │ ├── projectbar.component.spec.ts │ │ └── projectbar.component.ts ├── assets │ ├── .gitkeep │ ├── README.md │ ├── down.png │ ├── github-markdown.css │ ├── logo.icns │ └── moddoc.svg ├── browserslist ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── tslint.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /release-builds 8 | 9 | # dependencies 10 | /node_modules 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeBackground": "#b52e31", 4 | "titleBar.inactiveBackground": "#b52e3199", 5 | "titleBar.activeForeground": "#e7e7e7", 6 | "titleBar.inactiveForeground": "#e7e7e799" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Moddoc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## Moddoc 4 | 5 | 🐶 Best way to see the Documentation of Node Modules in your Project. 6 | 7 |
8 | 9 | 10 | 11 | ## Prerequisites 12 | 13 | Before running this locally you must have these installed 14 | 15 | + Node 16 | + Electron 17 | 18 | ## Installing 19 | 20 | It's built in electron so the process to start this is really easy 21 | 22 | 1. `npm install` 23 | 2. `npm install electron -g` 24 | 3. `npm run electron-tsc` 25 | 26 | That's it. 27 | 28 | ## Features 29 | 30 | ***1. Open multiple projects at a time*** 31 | 32 | ***2. Shows both dependencies and dev dependencies*** 33 | 34 | ***3. Quick copy widget*** 35 | 36 | ***4. In-app browser for external links*** 37 | 38 | ***5. Offline access to Documentation*** 39 | 40 | ## Contributing 41 | 42 | Feel free to contribute to this project and treat it like your own. 😊 43 | 44 | ## License 45 | 46 | MIT License 47 | 48 | ## Author 49 | 50 | [Sarthak Sharma](https://twitter.com/sarthology) 51 | 52 | ## Acknowledgments 53 | 54 | Icons used from [flaticon](https://flaticon.com) 55 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "moddoc": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css" 27 | ], 28 | "scripts": [] 29 | }, 30 | "configurations": { 31 | "production": { 32 | "fileReplacements": [ 33 | { 34 | "replace": "src/environments/environment.ts", 35 | "with": "src/environments/environment.prod.ts" 36 | } 37 | ], 38 | "optimization": true, 39 | "outputHashing": "all", 40 | "sourceMap": false, 41 | "extractCss": true, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true 47 | } 48 | } 49 | }, 50 | "serve": { 51 | "builder": "@angular-devkit/build-angular:dev-server", 52 | "options": { 53 | "browserTarget": "moddoc:build" 54 | }, 55 | "configurations": { 56 | "production": { 57 | "browserTarget": "moddoc:build:production" 58 | } 59 | } 60 | }, 61 | "extract-i18n": { 62 | "builder": "@angular-devkit/build-angular:extract-i18n", 63 | "options": { 64 | "browserTarget": "moddoc:build" 65 | } 66 | }, 67 | "test": { 68 | "builder": "@angular-devkit/build-angular:karma", 69 | "options": { 70 | "main": "src/test.ts", 71 | "polyfills": "src/polyfills.ts", 72 | "tsConfig": "src/tsconfig.spec.json", 73 | "karmaConfig": "src/karma.conf.js", 74 | "styles": [ 75 | "src/styles.css" 76 | ], 77 | "scripts": [], 78 | "assets": [ 79 | "src/favicon.ico", 80 | "src/assets" 81 | ] 82 | } 83 | }, 84 | "lint": { 85 | "builder": "@angular-devkit/build-angular:tslint", 86 | "options": { 87 | "tsConfig": [ 88 | "src/tsconfig.app.json", 89 | "src/tsconfig.spec.json" 90 | ], 91 | "exclude": [ 92 | "**/node_modules/**" 93 | ] 94 | } 95 | } 96 | } 97 | }, 98 | "moddoc-e2e": { 99 | "root": "e2e/", 100 | "projectType": "application", 101 | "architect": { 102 | "e2e": { 103 | "builder": "@angular-devkit/build-angular:protractor", 104 | "options": { 105 | "protractorConfig": "e2e/protractor.conf.js", 106 | "devServerTarget": "moddoc:serve" 107 | }, 108 | "configurations": { 109 | "production": { 110 | "devServerTarget": "moddoc:serve:production" 111 | } 112 | } 113 | }, 114 | "lint": { 115 | "builder": "@angular-devkit/build-angular:tslint", 116 | "options": { 117 | "tsConfig": "e2e/tsconfig.e2e.json", 118 | "exclude": [ 119 | "**/node_modules/**" 120 | ] 121 | } 122 | } 123 | } 124 | } 125 | }, 126 | "defaultProject": "moddoc" 127 | } -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('workspace-project App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to moddoc!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { 4 | app, 5 | BrowserWindow, 6 | ipcMain, 7 | dialog, 8 | clipboard, 9 | Menu, 10 | MenuItem 11 | } = require('electron'); 12 | const path = require('path'); 13 | const url = require('url'); 14 | const fs = require('fs'); 15 | const os = require('os'); 16 | const { autoUpdater } = require('electron-updater'); 17 | const macAddress = require('macaddress'); 18 | const pJSON = require('./package.json'); 19 | 20 | let win, initialData; 21 | const menu = new Menu(); 22 | menu.append( 23 | new MenuItem({ 24 | label: 'Remove', 25 | click() { 26 | BrowserWindow.getFocusedWindow().webContents.send('removeProject'); 27 | } 28 | }) 29 | ); 30 | 31 | const isPackaged = !process.defaultApp; 32 | 33 | const input = isPackaged ? process.argv[1] : process.argv.splice(2)[0]; 34 | 35 | function createWindow() { 36 | win = new BrowserWindow(); 37 | 38 | win.maximize(); 39 | 40 | // load the dist folder from Angular 41 | win.loadURL( 42 | url.format({ 43 | pathname: path.join(__dirname, '/dist/index.html'), 44 | protocol: 'file:', 45 | slashes: true 46 | }) 47 | ); 48 | 49 | // The following is optional and will open the DevTools: 50 | 51 | win.on('closed', () => { 52 | win = null; 53 | }); 54 | } 55 | 56 | function addAnalytics() { 57 | macAddress.one(function(err, mac) { 58 | BrowserWindow.getFocusedWindow().webContents.send('addAnalytics', { 59 | macAddress: mac, 60 | os: os.platform(), 61 | version: pJSON.version 62 | }); 63 | }); 64 | } 65 | 66 | app.on('ready', () => { 67 | createWindow(); 68 | autoUpdater.checkForUpdates(); 69 | if (input) { 70 | initialData = addProject(input); 71 | } 72 | }); 73 | 74 | ipcMain.on('getFiles', (event, arg) => { 75 | if (initialData && input) { 76 | initialData 77 | ? (initialData = { file: input, ...initialData }) 78 | : (initialData = null); 79 | win.webContents.send('getFilesResponse', initialData); 80 | initialData = null; 81 | } else { 82 | dialog.showOpenDialog({ properties: ['openDirectory'] }, filePaths => { 83 | if (filePaths) { 84 | let data = addProject(filePaths[0]); 85 | data ? (data = { file: filePaths[0], ...data }) : (data = null); 86 | win.webContents.send('getFilesResponse', data); 87 | } else win.webContents.send('getFilesResponse', null); 88 | }); 89 | } 90 | }); 91 | 92 | ipcMain.on('copyCode', (event, code) => { 93 | clipboard.writeText(code); 94 | }); 95 | 96 | ipcMain.on('onFileError', event => { 97 | dialog.showErrorBox('No Readme', "This package don't have a readme file."); 98 | }); 99 | 100 | ipcMain.on('onAlreadyExist', event => { 101 | dialog.showErrorBox( 102 | 'Duplicate Project', 103 | 'This package already being added. Add another.' 104 | ); 105 | }); 106 | 107 | ipcMain.on('openMenu', event => { 108 | menu.popup(); 109 | }); 110 | 111 | // on macOS, closing the window doesn't quit the app 112 | app.on('window-all-closed', () => { 113 | if (process.platform !== 'darwin') { 114 | app.quit(); 115 | } 116 | }); 117 | 118 | // initialize the app's main window 119 | app.on('activate', () => { 120 | if (win === null) { 121 | createWindow(); 122 | } 123 | }); 124 | 125 | let addProject = filePath => { 126 | if (fs.existsSync(filePath + '/package.json')) { 127 | data = fs.readFileSync(filePath + '/package.json', 'utf8'); 128 | addAnalytics(); 129 | return JSON.parse(data); 130 | } else { 131 | dialog.showMessageBox({ 132 | type: 'info', 133 | message: 'Your Project is not node based.', 134 | buttons: ['ok'] 135 | }); 136 | return null; 137 | } 138 | }; 139 | 140 | autoUpdater.on('update-available', () => { 141 | dialog.showMessageBox( 142 | { 143 | type: 'info', 144 | title: 'Found Updates', 145 | message: 'Found updates, do you want update now?', 146 | buttons: ['Sure', 'No'] 147 | }, 148 | buttonIndex => { 149 | if (buttonIndex === 0) { 150 | autoUpdater.downloadUpdate(); 151 | 152 | dialog.showMessageBox({ 153 | type: 'info', 154 | title: 'Downloading', 155 | message: 'Updates are downloading, will notify once done.' 156 | }); 157 | } 158 | } 159 | ); 160 | }); 161 | 162 | autoUpdater.on('update-downloaded', () => { 163 | dialog.showMessageBox( 164 | { 165 | title: 'Install Updates', 166 | message: 'Updates downloaded, application will be quit for update...' 167 | }, 168 | () => { 169 | setImmediate(() => autoUpdater.quitAndInstall()); 170 | } 171 | ); 172 | }); 173 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "moddoc", 3 | "description": "A new way to read Documentation of Node Modules", 4 | "version": "0.0.1", 5 | "main": "main.js", 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "build": "ng build --prod --base-href ./", 10 | "test": "ng test", 11 | "lint": "ng lint", 12 | "e2e": "ng e2e", 13 | "electron-tsc": "ng build --base-href ./ && electron .", 14 | "build:mac": "npm run build && build --linux", 15 | "build:linux": "npm run build && build --linux", 16 | "ship": "build --mac -p always" 17 | }, 18 | "build": { 19 | "appId": "com.github.sarthak.moddoc", 20 | "productName": "moddoc", 21 | "files": [ 22 | "**/*", 23 | "dist/**/*" 24 | ], 25 | "directories": { 26 | "output": "release", 27 | "buildResources": "dist" 28 | }, 29 | "linux": { 30 | "category": "Utility", 31 | "target": [ 32 | { 33 | "target": "deb", 34 | "arch": [ 35 | "x64" 36 | ] 37 | } 38 | ] 39 | } 40 | }, 41 | "author": "Sarthology ", 42 | "license": "MIT", 43 | "private": true, 44 | "dependencies": { 45 | "@angular/animations": "^6.1.0", 46 | "@angular/common": "^6.1.0", 47 | "@angular/compiler": "^6.1.0", 48 | "@angular/core": "^6.1.0", 49 | "@angular/forms": "^6.1.0", 50 | "@angular/http": "^6.1.0", 51 | "@angular/platform-browser": "^6.1.0", 52 | "@angular/platform-browser-dynamic": "^6.1.0", 53 | "@angular/router": "^6.1.0", 54 | "core-js": "^2.5.4", 55 | "electron-store": "^3.2.0", 56 | "electron-updater": "^4.0.6", 57 | "github-markdown-css": "^3.0.1", 58 | "macaddress": "^0.2.9", 59 | "ngx-electron": "^2.1.1", 60 | "ngx-markdown": "^7.1.4", 61 | "rxjs": "~6.2.0", 62 | "zone.js": "~0.8.26" 63 | }, 64 | "devDependencies": { 65 | "@angular-devkit/build-angular": "~0.8.0", 66 | "@angular/cli": "~6.2.3", 67 | "@angular/compiler-cli": "^6.1.0", 68 | "@angular/language-service": "^6.1.0", 69 | "@types/jasmine": "~2.8.8", 70 | "@types/jasminewd2": "~2.0.3", 71 | "@types/node": "^8.9.5", 72 | "codelyzer": "~4.3.0", 73 | "electron": "^4.0.1", 74 | "electron-builder": "^20.39.0", 75 | "jasmine-core": "~2.99.1", 76 | "jasmine-spec-reporter": "~4.2.1", 77 | "karma": "~3.0.0", 78 | "karma-chrome-launcher": "~2.2.0", 79 | "karma-coverage-istanbul-reporter": "~2.0.1", 80 | "karma-jasmine": "~1.1.2", 81 | "karma-jasmine-html-reporter": "^0.2.2", 82 | "protractor": "~5.4.0", 83 | "ts-node": "~7.0.0", 84 | "tslint": "~5.11.0", 85 | "typescript": "~2.9.2" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/app.component.css -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | describe('AppComponent', () => { 4 | beforeEach(async(() => { 5 | TestBed.configureTestingModule({ 6 | declarations: [ 7 | AppComponent 8 | ], 9 | }).compileComponents(); 10 | })); 11 | it('should create the app', async(() => { 12 | const fixture = TestBed.createComponent(AppComponent); 13 | const app = fixture.debugElement.componentInstance; 14 | expect(app).toBeTruthy(); 15 | })); 16 | it(`should have as title 'moddoc'`, async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app.title).toEqual('moddoc'); 20 | })); 21 | it('should render title in a h1 tag', async(() => { 22 | const fixture = TestBed.createComponent(AppComponent); 23 | fixture.detectChanges(); 24 | const compiled = fixture.debugElement.nativeElement; 25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to moddoc!'); 26 | })); 27 | }); 28 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'moddoc'; 10 | public src:string; 11 | public project:object; 12 | 13 | constructor(){ 14 | 15 | } 16 | 17 | receiveModule($event) { 18 | this.src = $event 19 | } 20 | 21 | receiveProject($event) { 22 | console.log($event); 23 | 24 | this.project = $event 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; 3 | import { MarkdownModule } from 'ngx-markdown'; 4 | 5 | import { AppComponent } from './app.component'; 6 | import { HttpClientModule, HttpClient } from '@angular/common/http'; 7 | import { MdViewerComponent } from './md-viewer/md-viewer.component'; 8 | import { ProjectbarComponent } from './projectbar/projectbar.component'; 9 | import { ModulebarComponent } from './modulebar/modulebar.component'; 10 | import { NgxElectronModule } from 'ngx-electron'; 11 | 12 | @NgModule({ 13 | declarations: [ 14 | AppComponent, 15 | MdViewerComponent, 16 | ProjectbarComponent, 17 | ModulebarComponent 18 | ], 19 | imports: [ 20 | BrowserModule, 21 | HttpClientModule, 22 | MarkdownModule.forRoot({ loader: HttpClient }), 23 | NgxElectronModule 24 | ], 25 | providers: [], 26 | bootstrap: [AppComponent], 27 | schemas: [NO_ERRORS_SCHEMA,CUSTOM_ELEMENTS_SCHEMA] 28 | }) 29 | export class AppModule { } 30 | -------------------------------------------------------------------------------- /src/app/file.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { FileService } from './file.service'; 4 | 5 | describe('FileService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: FileService = TestBed.get(FileService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/file.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ElectronService } from 'ngx-electron'; 3 | import { Subject } from 'rxjs/internal/Subject'; 4 | import { HttpClient } from '@angular/common/http'; 5 | import { environment } from 'src/environments/environment'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class FileService { 11 | public projects: Array<{ file: string; data: Object }> = []; 12 | public currentModule: string; 13 | public _listners = new Subject(); 14 | 15 | constructor( 16 | private _electronService: ElectronService, 17 | private http: HttpClient 18 | ) { 19 | this._electronService.ipcRenderer.on('addAnalytics', (event, data) => { 20 | this.http 21 | .post(environment.API + '/addUser', { 22 | macAddress: data.macAddress, 23 | platform: data.os, 24 | version: data.version 25 | }) 26 | .subscribe( 27 | res => { 28 | // Success 29 | }, 30 | err => { 31 | // Show error dialog 32 | } 33 | ); 34 | }); 35 | } 36 | 37 | async getFiles() { 38 | return new Promise((resolve, reject) => { 39 | this._electronService.ipcRenderer.once( 40 | 'getFilesResponse', 41 | (event, arg) => { 42 | if (arg && this.distinct(this.projects, arg)) { 43 | this.projects.push(arg); 44 | resolve(arg); 45 | } else { 46 | reject(); 47 | } 48 | } 49 | ); 50 | this._electronService.ipcRenderer.send('getFiles'); 51 | }); 52 | } 53 | 54 | copyCode(data) { 55 | return this._electronService.ipcRenderer.send('copyCode', data); 56 | } 57 | 58 | noFileError(error) { 59 | return this._electronService.ipcRenderer.send('onFileError', error); 60 | } 61 | distinct(projects: any, arg) { 62 | if (projects.filter(project => project.file === arg.file).length === 1) { 63 | this._electronService.ipcRenderer.send('onAlreadyExist', 'project'); 64 | return false; 65 | } else if (projects.length === 0) { 66 | return true; 67 | } else { 68 | return true; 69 | } 70 | } 71 | 72 | async openMenu(project) { 73 | return new Promise>((res, rej) => { 74 | this._electronService.ipcRenderer.on('removeProject', event => { 75 | this.projects = this.projects.filter( 76 | element => element.file != project.file 77 | ); 78 | res(this.projects); 79 | }); 80 | this._electronService.ipcRenderer.send('openMenu'); 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/app/md-viewer/md-viewer.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/md-viewer/md-viewer.component.css -------------------------------------------------------------------------------- /src/app/md-viewer/md-viewer.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
< Back
7 | 8 |
9 | 10 |
11 | -------------------------------------------------------------------------------- /src/app/md-viewer/md-viewer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MdViewerComponent } from './md-viewer.component'; 4 | 5 | describe('MdViewerComponent', () => { 6 | let component: MdViewerComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MdViewerComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MdViewerComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/md-viewer/md-viewer.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import { MarkdownService } from 'ngx-markdown'; 3 | import { FileService } from '../file.service'; 4 | 5 | @Component({ 6 | selector: 'md-viewer', 7 | templateUrl: './md-viewer.component.html', 8 | styleUrls: ['./md-viewer.component.css'] 9 | }) 10 | export class MdViewerComponent implements OnInit { 11 | @Input() src: string; 12 | public externalLink: string; 13 | public copyText; 14 | 15 | constructor( 16 | private markdownService: MarkdownService, 17 | private fileService: FileService 18 | ) {} 19 | 20 | ngOnInit() { 21 | this.markdownService.renderer.heading = (text: string, level: number) => { 22 | if (text.indexOf(':') === text.length - 1) text = text.replace(':', ''); 23 | const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); 24 | return ( 25 | '' + text + '' 26 | ); 27 | }; 28 | this.copyText = event => { 29 | this.fileService.copyCode(event.target.parentNode.nextSibling.innerText); 30 | event.target.innerText = 'copied'; 31 | setTimeout(() => { 32 | event.target.innerText = 'copy'; 33 | }, 2000); 34 | }; 35 | 36 | this.fileService._listners.subscribe(res => { 37 | console.log('s'); 38 | this.clear(); 39 | }); 40 | } 41 | 42 | onLoad(e) { 43 | this.src = null; 44 | window.scrollTo(0, 0); 45 | document 46 | .querySelector('.markdown-body') 47 | .setAttribute('style', 'display:block'); 48 | document.querySelectorAll('a').forEach(e => { 49 | let href = e.getAttribute('href'); 50 | e.onclick = event => { 51 | event.preventDefault(); 52 | if (href.indexOf('#') === 0) { 53 | var top = document.getElementById(href.split('#')[1]).offsetTop; 54 | window.scrollTo(0, top); 55 | } else { 56 | document 57 | .querySelector('.markdown-body') 58 | .setAttribute('style', 'display:none'); 59 | document 60 | .querySelector('.browser-body') 61 | .setAttribute('style', 'display:block'); 62 | document.querySelector('webview').setAttribute('src', href); 63 | } 64 | }; 65 | }); 66 | 67 | document.querySelectorAll('pre').forEach(e => { 68 | var span = document.createElement('div'); 69 | span.innerHTML = 'copy'; 70 | span.id = 'clipper'; 71 | e.insertBefore(span, e.firstChild); 72 | span.addEventListener('click', this.copyText, false); 73 | }); 74 | } 75 | 76 | noError(e) { 77 | this.fileService.noFileError(e); 78 | } 79 | 80 | reset() { 81 | document 82 | .querySelector('.markdown-body') 83 | .setAttribute('style', 'display:block'); 84 | document 85 | .querySelector('.browser-body') 86 | .setAttribute('style', 'display:none'); 87 | } 88 | 89 | clear() { 90 | document 91 | .querySelector('.markdown-body') 92 | .setAttribute('style', 'display:none'); 93 | document 94 | .querySelector('.browser-body') 95 | .setAttribute('style', 'display:none'); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/app/modulebar/modulebar.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/modulebar/modulebar.component.css -------------------------------------------------------------------------------- /src/app/modulebar/modulebar.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Modules

4 |
5 |
6 |
7 |
8 |

Dependencies List

9 |
10 |
11 |
12 |

{{dev}} {{project.dependencies[dev]}}

13 |
14 |
15 |
16 |
17 |
18 |

Dev Dependencies List

19 |
20 |
21 |
22 |

{{dev}} {{project.devDependencies[dev]}}

23 |
24 |
25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /src/app/modulebar/modulebar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ModulebarComponent } from './modulebar.component'; 4 | 5 | describe('ModulebarComponent', () => { 6 | let component: ModulebarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ModulebarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ModulebarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/modulebar/modulebar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'modulebar', 5 | templateUrl: './modulebar.component.html', 6 | styleUrls: ['./modulebar.component.css'] 7 | }) 8 | 9 | export class ModulebarComponent implements OnInit { 10 | 11 | public moduleHide:boolean = true; 12 | public devHide:boolean = true; 13 | public objectKeys = Object.keys; 14 | 15 | @Output() currentModule = new EventEmitter(); 16 | @Input() project: {file:string}; 17 | 18 | constructor() { } 19 | 20 | ngOnInit() { 21 | } 22 | 23 | setCurrentModule(module){ 24 | this.currentModule.emit(this.project.file +"/node_modules/"+module+"/README.md"); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/projectbar/projectbar.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/projectbar/projectbar.component.css -------------------------------------------------------------------------------- /src/app/projectbar/projectbar.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |

Projects

6 |
7 |
8 |
10 |

{{project.name}}

11 | {{highlightProject()}} 12 |
13 |
14 |
15 |
16 |

+

17 |
18 |
-------------------------------------------------------------------------------- /src/app/projectbar/projectbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProjectbarComponent } from './projectbar.component'; 4 | 5 | describe('ProjectbarComponent', () => { 6 | let component: ProjectbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ProjectbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ProjectbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/projectbar/projectbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, EventEmitter } from '@angular/core'; 2 | import { FileService } from '../file.service'; 3 | 4 | @Component({ 5 | selector: 'projectbar', 6 | templateUrl: './projectbar.component.html', 7 | styleUrls: ['./projectbar.component.css'] 8 | }) 9 | export class ProjectbarComponent implements OnInit { 10 | public projects: Array = this.fileService.projects; 11 | public clicked: any = null; 12 | 13 | @Output() currentProject = new EventEmitter(); 14 | 15 | constructor(private fileService: FileService) {} 16 | 17 | ngOnInit() { 18 | this.fileService.getFiles().then((project: Object) => { 19 | this.currentProject.emit(project); 20 | }); 21 | } 22 | 23 | addProject(event) { 24 | event.target.style = 'display:none;'; 25 | this.fileService 26 | .getFiles() 27 | .then((project: Object) => { 28 | this.currentProject.emit(project); 29 | event.target.style = 'display:block;'; 30 | }) 31 | .catch(() => { 32 | event.target.style = 'display:block;'; 33 | }); 34 | } 35 | 36 | setCurrentProject(project, event) { 37 | this.clicked = event; 38 | this.currentProject.emit(project); 39 | } 40 | 41 | highlightProject() { 42 | if (document.querySelector('.active-project')) { 43 | document 44 | .querySelector('.active-project') 45 | .classList.remove('active-project'); 46 | } 47 | if (this.clicked === null) { 48 | document 49 | .getElementById('project-names') 50 | .lastElementChild.classList.add('active-project'); 51 | } else if (this.clicked) { 52 | this.clicked.target.closest('.project').classList.add('active-project'); 53 | this.clicked = null; 54 | } 55 | } 56 | 57 | onRightClick(project) { 58 | this.fileService.openMenu(project).then(res => { 59 | this.projects = res; 60 | this.currentProject.emit(null); 61 | this.fileService._listners.next('reset'); 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/README.md: -------------------------------------------------------------------------------- 1 | [![npm][npm]][npm-url] 2 | [![node][node]][node-url] 3 | [![deps][deps]][deps-url] 4 | [![tests][tests]][tests-url] 5 | [![coverage][cover]][cover-url] 6 | [![chat][chat]][chat-url] 7 | 8 |
9 | 10 | 12 | 13 |

File Loader

14 |

Instructs webpack to emit the required object as file and to return its public URL

15 |
16 | 17 |

Install

18 | 19 | ```bash 20 | npm install --save-dev file-loader 21 | ``` 22 | 23 |

Usage

24 | 25 | By default the filename of the resulting file is the MD5 hash of the file's contents with the original extension of the required resource. 26 | 27 | ```js 28 | import img from './file.png' 29 | ``` 30 | 31 | **webpack.config.js** 32 | ```js 33 | module.exports = { 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.(png|jpg|gif)$/, 38 | use: [ 39 | { 40 | loader: 'file-loader', 41 | options: {} 42 | } 43 | ] 44 | } 45 | ] 46 | } 47 | } 48 | ``` 49 | 50 | Emits `file.png` as file in the output directory and returns the public URL 51 | 52 | ``` 53 | "/public/path/0dcbbaa7013869e351f.png" 54 | ``` 55 | 56 |

Options

57 | 58 | |Name|Type|Default|Description| 59 | |:--:|:--:|:-----:|:----------| 60 | |**`name`**|`{String\|Function}`|`[hash].[ext]`|Configure a custom filename template for your file| 61 | |**`regExp`**|`{RegExp}`|`'undefined'`|Let you extract some parts of the file path to reuse them in the `name` property| 62 | |**`context`**|`{String}`|`this.options.context`|Configure a custom file context, defaults to `webpack.config.js` [context](https://webpack.js.org/configuration/entry-context/#context)| 63 | |**`publicPath`**|`{String\|Function}`|[`__webpack_public_path__ `](https://webpack.js.org/api/module-variables/#__webpack_public_path__-webpack-specific-)|Configure a custom `public` path for your file| 64 | |**`outputPath`**|`{String\|Function}`|`'undefined'`|Configure a custom `output` path for your file| 65 | |**`useRelativePath`**|`{Boolean}`|`false`|Should be `true` if you wish to generate a `context` relative URL for each file| 66 | |**`emitFile`**|`{Boolean}`|`true`|By default a file is emitted, however this can be disabled if required (e.g. for server side packages)| 67 | 68 | ### `name` 69 | 70 | You can configure a custom filename template for your file using the query parameter `name`. For instance, to copy a file from your `context` directory into the output directory retaining the full directory structure, you might use 71 | 72 | #### `{String}` 73 | 74 | **webpack.config.js** 75 | ```js 76 | { 77 | loader: 'file-loader', 78 | options: { 79 | name: '[path][name].[ext]' 80 | } 81 | } 82 | ``` 83 | 84 | #### `{Function}` 85 | 86 | **webpack.config.js** 87 | ```js 88 | { 89 | loader: 'file-loader', 90 | options: { 91 | name (file) { 92 | if (env === 'development') { 93 | return '[path][name].[ext]' 94 | } 95 | 96 | return '[hash].[ext]' 97 | } 98 | } 99 | } 100 | ``` 101 | 102 | ### `regExp` 103 | 104 | Defines a `regExp` to match some parts of the file path. These capture groups can be reused in the `name` property using `[N]` placeholder. Note that `[0]` will be replaced by the entire tested string, whereas `[1]` will contain the first capturing parenthesis of your regex and so on... 105 | 106 | ```js 107 | import img from './customer01/file.png' 108 | ``` 109 | 110 | **webpack.config.js** 111 | ```js 112 | { 113 | loader: 'file-loader', 114 | options: { 115 | regExp: /\/([a-z0-9]+)\/[a-z0-9]+\.png$/, 116 | name: '[1]-[name].[ext]' 117 | } 118 | } 119 | ``` 120 | 121 | ``` 122 | customer01-file.png 123 | ``` 124 | 125 | #### `placeholders` 126 | 127 | |Name|Type|Default|Description| 128 | |:--:|:--:|:-----:|:----------| 129 | |**`[ext]`**|`{String}`|`file.extname`|The extension of the resource| 130 | |**`[name]`**|`{String}`|`file.basename`|The basename of the resource| 131 | |**`[path]`**|`{String}`|`file.dirname`|The path of the resource relative to the `context`| 132 | |**`[hash]`**|`{String}`|`md5`|The hash of the content, hashes below for more info| 133 | |**`[N]`**|`{String}`|``|The `n-th` match obtained from matching the current file name against the `regExp`| 134 | 135 | #### `hashes` 136 | 137 | `[:hash::]` optionally you can configure 138 | 139 | |Name|Type|Default|Description| 140 | |:--:|:--:|:-----:|:----------| 141 | |**`hashType`**|`{String}`|`md5`|`sha1`, `md5`, `sha256`, `sha512`| 142 | |**`digestType`**|`{String}`|`hex`|`hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`| 143 | |**`length`**|`{Number}`|`9999`|The length in chars| 144 | 145 | By default, the path and name you specify will output the file in that same directory and will also use that same URL path to access the file. 146 | 147 | ### `context` 148 | 149 | **webpack.config.js** 150 | ```js 151 | { 152 | loader: 'file-loader', 153 | options: { 154 | name: '[path][name].[ext]', 155 | context: '' 156 | } 157 | } 158 | ``` 159 | 160 | You can specify custom `output` and `public` paths by using `outputPath`, `publicPath` and `useRelativePath` 161 | 162 | ### `publicPath` 163 | 164 | **webpack.config.js** 165 | ```js 166 | { 167 | loader: 'file-loader', 168 | options: { 169 | name: '[path][name].[ext]', 170 | publicPath: 'assets/' 171 | } 172 | } 173 | ``` 174 | 175 | ### `outputPath` 176 | 177 | **webpack.config.js** 178 | ```js 179 | { 180 | loader: 'file-loader', 181 | options: { 182 | name: '[path][name].[ext]', 183 | outputPath: 'images/' 184 | } 185 | } 186 | ``` 187 | 188 | ### `useRelativePath` 189 | 190 | `useRelativePath` should be `true` if you wish to generate a relative URL to the for each file context. 191 | 192 | ```js 193 | { 194 | loader: 'file-loader', 195 | options: { 196 | useRelativePath: process.env.NODE_ENV === "production" 197 | } 198 | } 199 | ``` 200 | 201 | ### `emitFile` 202 | 203 | By default a file is emitted, however this can be disabled if required (e.g. for server side packages). 204 | 205 | ```js 206 | import img from './file.png' 207 | ``` 208 | 209 | ```js 210 | { 211 | loader: 'file-loader', 212 | options: { 213 | emitFile: false 214 | } 215 | } 216 | ``` 217 | 218 | > ⚠️ Returns the public URL but does **not** emit a file 219 | 220 | ``` 221 | `${publicPath}/0dcbbaa701328e351f.png` 222 | ``` 223 | 224 |

Examples

225 | 226 | 227 | ```js 228 | import png from 'image.png' 229 | ``` 230 | 231 | **webpack.config.js** 232 | ```js 233 | { 234 | loader: 'file-loader', 235 | options: { 236 | name: 'dirname/[hash].[ext]' 237 | } 238 | } 239 | ``` 240 | 241 | ``` 242 | dirname/0dcbbaa701328ae351f.png 243 | ``` 244 | 245 | **webpack.config.js** 246 | ```js 247 | { 248 | loader: 'file-loader', 249 | options: { 250 | name: '[sha512:hash:base64:7].[ext]' 251 | } 252 | } 253 | ``` 254 | 255 | ``` 256 | gdyb21L.png 257 | ``` 258 | 259 | ```js 260 | import png from 'path/to/file.png' 261 | ``` 262 | 263 | **webpack.config.js** 264 | ```js 265 | { 266 | loader: 'file-loader', 267 | options: { 268 | name: '[path][name].[ext]?[hash]' 269 | } 270 | } 271 | ``` 272 | 273 | ``` 274 | path/to/file.png?e43b20c069c4a01867c31e98cbce33c9 275 | ``` 276 | 277 |

Maintainers

278 | 279 | 280 | 281 | 282 | 289 | 296 | 303 | 310 | 311 | 312 |
283 | 284 | 285 |
286 | Juho Vepsäläinen 287 |
288 |
290 | 291 | 292 |
293 | Joshua Wiens 294 |
295 |
297 | 298 | 299 |
300 | Michael Ciniawsky 301 |
302 |
304 | 305 | 306 |
307 | Alexander Krasnoyarov 308 |
309 |
313 | 314 | 315 | [npm]: https://img.shields.io/npm/v/file-loader.svg 316 | [npm-url]: https://npmjs.com/package/file-loader 317 | 318 | [node]: https://img.shields.io/node/v/file-loader.svg 319 | [node-url]: https://nodejs.org 320 | 321 | [deps]: https://david-dm.org/webpack-contrib/file-loader.svg 322 | [deps-url]: https://david-dm.org/webpack-contrib/file-loader 323 | 324 | [tests]: http://img.shields.io/travis/webpack-contrib/file-loader.svg 325 | [tests-url]: https://travis-ci.org/webpack-contrib/file-loader 326 | 327 | [cover]: https://img.shields.io/codecov/c/github/webpack-contrib/file-loader.svg 328 | [cover-url]: https://codecov.io/gh/webpack-contrib/file-loader 329 | 330 | [chat]: https://badges.gitter.im/webpack/webpack.svg 331 | [chat-url]: https://gitter.im/webpack/webpack 332 | -------------------------------------------------------------------------------- /src/assets/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/assets/down.png -------------------------------------------------------------------------------- /src/assets/github-markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: octicons-link; 3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff'); 4 | } 5 | 6 | .markdown-body .octicon { 7 | display: inline-block; 8 | fill: currentColor; 9 | vertical-align: text-bottom; 10 | } 11 | 12 | .markdown-body .anchor { 13 | float: left; 14 | line-height: 1; 15 | margin-left: -20px; 16 | padding-right: 4px; 17 | } 18 | 19 | .markdown-body .anchor:focus { 20 | outline: none; 21 | } 22 | 23 | .markdown-body h1 .octicon-link, 24 | .markdown-body h2 .octicon-link, 25 | .markdown-body h3 .octicon-link, 26 | .markdown-body h4 .octicon-link, 27 | .markdown-body h5 .octicon-link, 28 | .markdown-body h6 .octicon-link { 29 | color: #1b1f23; 30 | vertical-align: middle; 31 | visibility: hidden; 32 | } 33 | 34 | .markdown-body h1:hover .anchor, 35 | .markdown-body h2:hover .anchor, 36 | .markdown-body h3:hover .anchor, 37 | .markdown-body h4:hover .anchor, 38 | .markdown-body h5:hover .anchor, 39 | .markdown-body h6:hover .anchor { 40 | text-decoration: none; 41 | } 42 | 43 | .markdown-body h1:hover .anchor .octicon-link, 44 | .markdown-body h2:hover .anchor .octicon-link, 45 | .markdown-body h3:hover .anchor .octicon-link, 46 | .markdown-body h4:hover .anchor .octicon-link, 47 | .markdown-body h5:hover .anchor .octicon-link, 48 | .markdown-body h6:hover .anchor .octicon-link { 49 | visibility: visible; 50 | } 51 | 52 | .markdown-body { 53 | -ms-text-size-adjust: 100%; 54 | -webkit-text-size-adjust: 100%; 55 | color: #24292e; 56 | line-height: 1.5; 57 | font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol; 58 | font-size: 16px; 59 | line-height: 1.5; 60 | word-wrap: break-word; 61 | } 62 | 63 | .markdown-body .pl-c { 64 | color: #6a737d; 65 | } 66 | 67 | .markdown-body .pl-c1, 68 | .markdown-body .pl-s .pl-v { 69 | color: #005cc5; 70 | } 71 | 72 | .markdown-body .pl-e, 73 | .markdown-body .pl-en { 74 | color: #6f42c1; 75 | } 76 | 77 | .markdown-body .pl-s .pl-s1, 78 | .markdown-body .pl-smi { 79 | color: #24292e; 80 | } 81 | 82 | .markdown-body .pl-ent { 83 | color: #22863a; 84 | } 85 | 86 | .markdown-body .pl-k { 87 | color: #d73a49; 88 | } 89 | 90 | .markdown-body .pl-pds, 91 | .markdown-body .pl-s, 92 | .markdown-body .pl-s .pl-pse .pl-s1, 93 | .markdown-body .pl-sr, 94 | .markdown-body .pl-sr .pl-cce, 95 | .markdown-body .pl-sr .pl-sra, 96 | .markdown-body .pl-sr .pl-sre { 97 | color: #032f62; 98 | } 99 | 100 | .markdown-body .pl-smw, 101 | .markdown-body .pl-v { 102 | color: #e36209; 103 | } 104 | 105 | .markdown-body .pl-bu { 106 | color: #b31d28; 107 | } 108 | 109 | .markdown-body .pl-ii { 110 | background-color: #b31d28; 111 | color: #fafbfc; 112 | } 113 | 114 | .markdown-body .pl-c2 { 115 | background-color: #d73a49; 116 | color: #fafbfc; 117 | } 118 | 119 | .markdown-body .pl-c2:before { 120 | content: "^M"; 121 | } 122 | 123 | .markdown-body .pl-sr .pl-cce { 124 | color: #22863a; 125 | font-weight: 700; 126 | } 127 | 128 | .markdown-body .pl-ml { 129 | color: #735c0f; 130 | } 131 | 132 | .markdown-body .pl-mh, 133 | .markdown-body .pl-mh .pl-en, 134 | .markdown-body .pl-ms { 135 | color: #005cc5; 136 | font-weight: 700; 137 | } 138 | 139 | .markdown-body .pl-mi { 140 | color: #24292e; 141 | font-style: italic; 142 | } 143 | 144 | .markdown-body .pl-mb { 145 | color: #24292e; 146 | font-weight: 700; 147 | } 148 | 149 | .markdown-body .pl-md { 150 | background-color: #ffeef0; 151 | color: #b31d28; 152 | } 153 | 154 | .markdown-body .pl-mi1 { 155 | background-color: #f0fff4; 156 | color: #22863a; 157 | } 158 | 159 | .markdown-body .pl-mc { 160 | background-color: #ffebda; 161 | color: #e36209; 162 | } 163 | 164 | .markdown-body .pl-mi2 { 165 | background-color: #005cc5; 166 | color: #f6f8fa; 167 | } 168 | 169 | .markdown-body .pl-mdr { 170 | color: #6f42c1; 171 | font-weight: 700; 172 | } 173 | 174 | .markdown-body .pl-ba { 175 | color: #586069; 176 | } 177 | 178 | .markdown-body .pl-sg { 179 | color: #959da5; 180 | } 181 | 182 | .markdown-body .pl-corl { 183 | color: #032f62; 184 | text-decoration: underline; 185 | } 186 | 187 | .markdown-body details { 188 | display: block; 189 | } 190 | 191 | .markdown-body summary { 192 | display: list-item; 193 | } 194 | 195 | .markdown-body a { 196 | background-color: transparent; 197 | } 198 | 199 | .markdown-body a:active, 200 | .markdown-body a:hover { 201 | outline-width: 0; 202 | } 203 | 204 | .markdown-body strong { 205 | font-weight: inherit; 206 | font-weight: bolder; 207 | } 208 | 209 | .markdown-body h1 { 210 | font-size: 2em; 211 | margin: .67em 0; 212 | } 213 | 214 | .markdown-body img { 215 | border-style: none; 216 | } 217 | 218 | .markdown-body code, 219 | .markdown-body kbd, 220 | .markdown-body pre { 221 | font-family: monospace,monospace; 222 | font-size: 1em; 223 | } 224 | 225 | .markdown-body hr { 226 | box-sizing: content-box; 227 | height: 0; 228 | overflow: visible; 229 | } 230 | 231 | .markdown-body input { 232 | font: inherit; 233 | margin: 0; 234 | } 235 | 236 | .markdown-body input { 237 | overflow: visible; 238 | } 239 | 240 | .markdown-body [type=checkbox] { 241 | box-sizing: border-box; 242 | padding: 0; 243 | } 244 | 245 | .markdown-body * { 246 | box-sizing: border-box; 247 | } 248 | 249 | .markdown-body input { 250 | font-family: inherit; 251 | font-size: inherit; 252 | line-height: inherit; 253 | } 254 | 255 | .markdown-body a { 256 | color: #0366d6; 257 | text-decoration: none; 258 | } 259 | 260 | .markdown-body a:hover { 261 | text-decoration: underline; 262 | } 263 | 264 | .markdown-body strong { 265 | font-weight: 600; 266 | } 267 | 268 | .markdown-body hr { 269 | background: transparent; 270 | border: 0; 271 | border-bottom: 1px solid #dfe2e5; 272 | height: 0; 273 | margin: 15px 0; 274 | overflow: hidden; 275 | } 276 | 277 | .markdown-body hr:before { 278 | content: ""; 279 | display: table; 280 | } 281 | 282 | .markdown-body hr:after { 283 | clear: both; 284 | content: ""; 285 | display: table; 286 | } 287 | 288 | .markdown-body table { 289 | border-collapse: collapse; 290 | border-spacing: 0; 291 | } 292 | 293 | .markdown-body td, 294 | .markdown-body th { 295 | padding: 0; 296 | } 297 | 298 | .markdown-body details summary { 299 | cursor: pointer; 300 | } 301 | 302 | .markdown-body h1, 303 | .markdown-body h2, 304 | .markdown-body h3, 305 | .markdown-body h4, 306 | .markdown-body h5, 307 | .markdown-body h6 { 308 | margin-bottom: 0; 309 | margin-top: 0; 310 | } 311 | 312 | .markdown-body h1 { 313 | font-size: 32px; 314 | } 315 | 316 | .markdown-body h1, 317 | .markdown-body h2 { 318 | font-weight: 600; 319 | } 320 | 321 | .markdown-body h2 { 322 | font-size: 24px; 323 | } 324 | 325 | .markdown-body h3 { 326 | font-size: 20px; 327 | } 328 | 329 | .markdown-body h3, 330 | .markdown-body h4 { 331 | font-weight: 600; 332 | } 333 | 334 | .markdown-body h4 { 335 | font-size: 16px; 336 | } 337 | 338 | .markdown-body h5 { 339 | font-size: 14px; 340 | } 341 | 342 | .markdown-body h5, 343 | .markdown-body h6 { 344 | font-weight: 600; 345 | } 346 | 347 | .markdown-body h6 { 348 | font-size: 12px; 349 | } 350 | 351 | .markdown-body p { 352 | margin-bottom: 10px; 353 | margin-top: 0; 354 | } 355 | 356 | .markdown-body blockquote { 357 | margin: 0; 358 | } 359 | 360 | .markdown-body ol, 361 | .markdown-body ul { 362 | margin-bottom: 0; 363 | margin-top: 0; 364 | padding-left: 0; 365 | } 366 | 367 | .markdown-body ol ol, 368 | .markdown-body ul ol { 369 | list-style-type: lower-roman; 370 | } 371 | 372 | .markdown-body ol ol ol, 373 | .markdown-body ol ul ol, 374 | .markdown-body ul ol ol, 375 | .markdown-body ul ul ol { 376 | list-style-type: lower-alpha; 377 | } 378 | 379 | .markdown-body dd { 380 | margin-left: 0; 381 | } 382 | 383 | .markdown-body code, 384 | .markdown-body pre { 385 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; 386 | font-size: 12px; 387 | } 388 | 389 | .markdown-body pre { 390 | margin-bottom: 0; 391 | margin-top: 0; 392 | } 393 | 394 | .markdown-body input::-webkit-inner-spin-button, 395 | .markdown-body input::-webkit-outer-spin-button { 396 | -webkit-appearance: none; 397 | appearance: none; 398 | margin: 0; 399 | } 400 | 401 | .markdown-body .border { 402 | border: 1px solid #e1e4e8!important; 403 | } 404 | 405 | .markdown-body .border-0 { 406 | border: 0!important; 407 | } 408 | 409 | .markdown-body .border-bottom { 410 | border-bottom: 1px solid #e1e4e8!important; 411 | } 412 | 413 | .markdown-body .rounded-1 { 414 | border-radius: 3px!important; 415 | } 416 | 417 | .markdown-body .bg-white { 418 | background-color: #fff!important; 419 | } 420 | 421 | .markdown-body .bg-gray-light { 422 | background-color: #fafbfc!important; 423 | } 424 | 425 | .markdown-body .text-gray-light { 426 | color: #6a737d!important; 427 | } 428 | 429 | .markdown-body .mb-0 { 430 | margin-bottom: 0!important; 431 | } 432 | 433 | .markdown-body .my-2 { 434 | margin-bottom: 8px!important; 435 | margin-top: 8px!important; 436 | } 437 | 438 | .markdown-body .pl-0 { 439 | padding-left: 0!important; 440 | } 441 | 442 | .markdown-body .py-0 { 443 | padding-bottom: 0!important; 444 | padding-top: 0!important; 445 | } 446 | 447 | .markdown-body .pl-1 { 448 | padding-left: 4px!important; 449 | } 450 | 451 | .markdown-body .pl-2 { 452 | padding-left: 8px!important; 453 | } 454 | 455 | .markdown-body .py-2 { 456 | padding-bottom: 8px!important; 457 | padding-top: 8px!important; 458 | } 459 | 460 | .markdown-body .pl-3, 461 | .markdown-body .px-3 { 462 | padding-left: 16px!important; 463 | } 464 | 465 | .markdown-body .px-3 { 466 | padding-right: 16px!important; 467 | } 468 | 469 | .markdown-body .pl-4 { 470 | padding-left: 24px!important; 471 | } 472 | 473 | .markdown-body .pl-5 { 474 | padding-left: 32px!important; 475 | } 476 | 477 | .markdown-body .pl-6 { 478 | padding-left: 40px!important; 479 | } 480 | 481 | .markdown-body .f6 { 482 | font-size: 12px!important; 483 | } 484 | 485 | .markdown-body .lh-condensed { 486 | line-height: 1.25!important; 487 | } 488 | 489 | .markdown-body .text-bold { 490 | font-weight: 600!important; 491 | } 492 | 493 | .markdown-body:before { 494 | content: ""; 495 | display: table; 496 | } 497 | 498 | .markdown-body:after { 499 | clear: both; 500 | content: ""; 501 | display: table; 502 | } 503 | 504 | .markdown-body>:first-child { 505 | margin-top: 0!important; 506 | } 507 | 508 | .markdown-body>:last-child { 509 | margin-bottom: 0!important; 510 | } 511 | 512 | .markdown-body a:not([href]) { 513 | color: inherit; 514 | text-decoration: none; 515 | } 516 | 517 | .markdown-body blockquote, 518 | .markdown-body dl, 519 | .markdown-body ol, 520 | .markdown-body p, 521 | .markdown-body pre, 522 | .markdown-body table, 523 | .markdown-body ul { 524 | margin-bottom: 16px; 525 | margin-top: 0; 526 | } 527 | 528 | .markdown-body hr { 529 | background-color: #e1e4e8; 530 | border: 0; 531 | height: .25em; 532 | margin: 24px 0; 533 | padding: 0; 534 | } 535 | 536 | .markdown-body blockquote { 537 | border-left: .25em solid #dfe2e5; 538 | color: #6a737d; 539 | padding: 0 1em; 540 | } 541 | 542 | .markdown-body blockquote>:first-child { 543 | margin-top: 0; 544 | } 545 | 546 | .markdown-body blockquote>:last-child { 547 | margin-bottom: 0; 548 | } 549 | 550 | .markdown-body kbd { 551 | background-color: #fafbfc; 552 | border: 1px solid #c6cbd1; 553 | border-bottom-color: #959da5; 554 | border-radius: 3px; 555 | box-shadow: inset 0 -1px 0 #959da5; 556 | color: #444d56; 557 | display: inline-block; 558 | font-size: 11px; 559 | line-height: 10px; 560 | padding: 3px 5px; 561 | vertical-align: middle; 562 | } 563 | 564 | .markdown-body h1, 565 | .markdown-body h2, 566 | .markdown-body h3, 567 | .markdown-body h4, 568 | .markdown-body h5, 569 | .markdown-body h6 { 570 | font-weight: 600; 571 | line-height: 1.25; 572 | margin-bottom: 16px; 573 | margin-top: 24px; 574 | } 575 | 576 | .markdown-body h1 { 577 | font-size: 2em; 578 | } 579 | 580 | .markdown-body h1, 581 | .markdown-body h2 { 582 | border-bottom: 1px solid #eaecef; 583 | padding-bottom: .3em; 584 | } 585 | 586 | .markdown-body h2 { 587 | font-size: 1.5em; 588 | } 589 | 590 | .markdown-body h3 { 591 | font-size: 1.25em; 592 | } 593 | 594 | .markdown-body h4 { 595 | font-size: 1em; 596 | } 597 | 598 | .markdown-body h5 { 599 | font-size: .875em; 600 | } 601 | 602 | .markdown-body h6 { 603 | color: #6a737d; 604 | font-size: .85em; 605 | } 606 | 607 | .markdown-body ol, 608 | .markdown-body ul { 609 | padding-left: 2em; 610 | } 611 | 612 | .markdown-body ol ol, 613 | .markdown-body ol ul, 614 | .markdown-body ul ol, 615 | .markdown-body ul ul { 616 | margin-bottom: 0; 617 | margin-top: 0; 618 | } 619 | 620 | .markdown-body li { 621 | word-wrap: break-all; 622 | } 623 | 624 | .markdown-body li>p { 625 | margin-top: 16px; 626 | } 627 | 628 | .markdown-body li+li { 629 | margin-top: .25em; 630 | } 631 | 632 | .markdown-body dl { 633 | padding: 0; 634 | } 635 | 636 | .markdown-body dl dt { 637 | font-size: 1em; 638 | font-style: italic; 639 | font-weight: 600; 640 | margin-top: 16px; 641 | padding: 0; 642 | } 643 | 644 | .markdown-body dl dd { 645 | margin-bottom: 16px; 646 | padding: 0 16px; 647 | } 648 | 649 | .markdown-body table { 650 | display: block; 651 | overflow: auto; 652 | width: 100%; 653 | } 654 | 655 | .markdown-body table th { 656 | font-weight: 600; 657 | } 658 | 659 | .markdown-body table td, 660 | .markdown-body table th { 661 | border: 1px solid #dfe2e5; 662 | padding: 6px 13px; 663 | } 664 | 665 | .markdown-body table tr { 666 | background-color: #fff; 667 | border-top: 1px solid #c6cbd1; 668 | } 669 | 670 | .markdown-body table tr:nth-child(2n) { 671 | background-color: #f6f8fa; 672 | } 673 | 674 | .markdown-body img { 675 | background-color: #fff; 676 | box-sizing: content-box; 677 | max-width: 100%; 678 | } 679 | 680 | .markdown-body img[align=right] { 681 | padding-left: 20px; 682 | } 683 | 684 | .markdown-body img[align=left] { 685 | padding-right: 20px; 686 | } 687 | 688 | .markdown-body code { 689 | background-color: rgba(27,31,35,.05); 690 | border-radius: 3px; 691 | font-size: 85%; 692 | margin: 0; 693 | padding: .2em .4em; 694 | } 695 | 696 | .markdown-body pre { 697 | word-wrap: normal; 698 | } 699 | 700 | .markdown-body pre>code { 701 | background: transparent; 702 | border: 0; 703 | font-size: 100%; 704 | margin: 0; 705 | padding: 0; 706 | white-space: pre; 707 | word-break: normal; 708 | } 709 | 710 | .markdown-body .highlight { 711 | margin-bottom: 16px; 712 | } 713 | 714 | .markdown-body .highlight pre { 715 | margin-bottom: 0; 716 | word-break: normal; 717 | } 718 | 719 | .markdown-body .highlight pre, 720 | .markdown-body pre { 721 | background-color: #f6f8fa; 722 | border-radius: 3px; 723 | font-size: 85%; 724 | line-height: 1.45; 725 | overflow: auto; 726 | padding: 16px; 727 | } 728 | 729 | .markdown-body pre code { 730 | background-color: transparent; 731 | border: 0; 732 | display: inline; 733 | line-height: inherit; 734 | margin: 0; 735 | max-width: auto; 736 | overflow: visible; 737 | padding: 0; 738 | word-wrap: normal; 739 | } 740 | 741 | .markdown-body .commit-tease-sha { 742 | color: #444d56; 743 | display: inline-block; 744 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; 745 | font-size: 90%; 746 | } 747 | 748 | .markdown-body .blob-wrapper { 749 | border-bottom-left-radius: 3px; 750 | border-bottom-right-radius: 3px; 751 | overflow-x: auto; 752 | overflow-y: hidden; 753 | } 754 | 755 | .markdown-body .blob-wrapper-embedded { 756 | max-height: 240px; 757 | overflow-y: auto; 758 | } 759 | 760 | .markdown-body .blob-num { 761 | -moz-user-select: none; 762 | -ms-user-select: none; 763 | -webkit-user-select: none; 764 | color: rgba(27,31,35,.3); 765 | cursor: pointer; 766 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; 767 | font-size: 12px; 768 | line-height: 20px; 769 | min-width: 50px; 770 | padding-left: 10px; 771 | padding-right: 10px; 772 | text-align: right; 773 | user-select: none; 774 | vertical-align: top; 775 | white-space: nowrap; 776 | width: 1%; 777 | } 778 | 779 | .markdown-body .blob-num:hover { 780 | color: rgba(27,31,35,.6); 781 | } 782 | 783 | .markdown-body .blob-num:before { 784 | content: attr(data-line-number); 785 | } 786 | 787 | .markdown-body .blob-code { 788 | line-height: 20px; 789 | padding-left: 10px; 790 | padding-right: 10px; 791 | position: relative; 792 | vertical-align: top; 793 | } 794 | 795 | .markdown-body .blob-code-inner { 796 | color: #24292e; 797 | font-family: SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; 798 | font-size: 12px; 799 | overflow: visible; 800 | white-space: pre; 801 | word-wrap: normal; 802 | } 803 | 804 | .markdown-body .pl-token.active, 805 | .markdown-body .pl-token:hover { 806 | background: #ffea7f; 807 | cursor: pointer; 808 | } 809 | 810 | .markdown-body kbd { 811 | background-color: #fafbfc; 812 | border: 1px solid #d1d5da; 813 | border-bottom-color: #c6cbd1; 814 | border-radius: 3px; 815 | box-shadow: inset 0 -1px 0 #c6cbd1; 816 | color: #444d56; 817 | display: inline-block; 818 | font: 11px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; 819 | line-height: 10px; 820 | padding: 3px 5px; 821 | vertical-align: middle; 822 | } 823 | 824 | .markdown-body :checked+.radio-label { 825 | border-color: #0366d6; 826 | position: relative; 827 | z-index: 1; 828 | } 829 | 830 | .markdown-body .tab-size[data-tab-size="1"] { 831 | -moz-tab-size: 1; 832 | tab-size: 1; 833 | } 834 | 835 | .markdown-body .tab-size[data-tab-size="2"] { 836 | -moz-tab-size: 2; 837 | tab-size: 2; 838 | } 839 | 840 | .markdown-body .tab-size[data-tab-size="3"] { 841 | -moz-tab-size: 3; 842 | tab-size: 3; 843 | } 844 | 845 | .markdown-body .tab-size[data-tab-size="4"] { 846 | -moz-tab-size: 4; 847 | tab-size: 4; 848 | } 849 | 850 | .markdown-body .tab-size[data-tab-size="5"] { 851 | -moz-tab-size: 5; 852 | tab-size: 5; 853 | } 854 | 855 | .markdown-body .tab-size[data-tab-size="6"] { 856 | -moz-tab-size: 6; 857 | tab-size: 6; 858 | } 859 | 860 | .markdown-body .tab-size[data-tab-size="7"] { 861 | -moz-tab-size: 7; 862 | tab-size: 7; 863 | } 864 | 865 | .markdown-body .tab-size[data-tab-size="8"] { 866 | -moz-tab-size: 8; 867 | tab-size: 8; 868 | } 869 | 870 | .markdown-body .tab-size[data-tab-size="9"] { 871 | -moz-tab-size: 9; 872 | tab-size: 9; 873 | } 874 | 875 | .markdown-body .tab-size[data-tab-size="10"] { 876 | -moz-tab-size: 10; 877 | tab-size: 10; 878 | } 879 | 880 | .markdown-body .tab-size[data-tab-size="11"] { 881 | -moz-tab-size: 11; 882 | tab-size: 11; 883 | } 884 | 885 | .markdown-body .tab-size[data-tab-size="12"] { 886 | -moz-tab-size: 12; 887 | tab-size: 12; 888 | } 889 | 890 | .markdown-body .task-list-item { 891 | list-style-type: none; 892 | } 893 | 894 | .markdown-body .task-list-item+.task-list-item { 895 | margin-top: 3px; 896 | } 897 | 898 | .markdown-body .task-list-item input { 899 | margin: 0 .2em .25em -1.6em; 900 | vertical-align: middle; 901 | } 902 | 903 | .markdown-body hr { 904 | border-bottom-color: #eee; 905 | } 906 | 907 | .markdown-body .pl-0 { 908 | padding-left: 0!important; 909 | } 910 | 911 | .markdown-body .pl-1 { 912 | padding-left: 4px!important; 913 | } 914 | 915 | .markdown-body .pl-2 { 916 | padding-left: 8px!important; 917 | } 918 | 919 | .markdown-body .pl-3 { 920 | padding-left: 16px!important; 921 | } 922 | 923 | .markdown-body .pl-4 { 924 | padding-left: 24px!important; 925 | } 926 | 927 | .markdown-body .pl-5 { 928 | padding-left: 32px!important; 929 | } 930 | 931 | .markdown-body .pl-6 { 932 | padding-left: 40px!important; 933 | } 934 | 935 | .markdown-body .pl-7 { 936 | padding-left: 48px!important; 937 | } 938 | 939 | .markdown-body .pl-8 { 940 | padding-left: 64px!important; 941 | } 942 | 943 | .markdown-body .pl-9 { 944 | padding-left: 80px!important; 945 | } 946 | 947 | .markdown-body .pl-10 { 948 | padding-left: 96px!important; 949 | } 950 | 951 | .markdown-body .pl-11 { 952 | padding-left: 112px!important; 953 | } 954 | 955 | .markdown-body .pl-12 { 956 | padding-left: 128px!important; 957 | } 958 | -------------------------------------------------------------------------------- /src/assets/logo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/assets/logo.icns -------------------------------------------------------------------------------- /src/assets/moddoc.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 24 | 26 | 28 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | API: 'https://tmxnx.com/moddoc' 4 | }; 5 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | API: 'http://localhost:3000/moddoc' 8 | }; 9 | 10 | /* 11 | * For easier debugging in development mode, you can import the following file 12 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 13 | * 14 | * This import should be commented out in production mode because it will have a negative impact 15 | * on performance if an error is thrown. 16 | */ 17 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 18 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Moddoc 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: ['html', 'lcovonly'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | 14 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Web Animations `@angular/platform-browser/animations` 51 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 52 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 53 | **/ 54 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 55 | 56 | /** 57 | * By default, zone.js will patch all possible macroTask and DomEvents 58 | * user can disable parts of macroTask/DomEvents patch by setting following flags 59 | */ 60 | 61 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 62 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 63 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 64 | 65 | /* 66 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 67 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 68 | */ 69 | // (window as any).__Zone_enable_cross_context_check = true; 70 | 71 | /*************************************************************************************************** 72 | * Zone JS is required by default for Angular itself. 73 | */ 74 | import 'zone.js/dist/zone'; // Included with Angular CLI. 75 | 76 | 77 | 78 | /*************************************************************************************************** 79 | * APPLICATION IMPORTS 80 | */ 81 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | body { 3 | margin: 0px; 4 | } 5 | 6 | .main { 7 | height: 100vh; 8 | } 9 | 10 | .menubar { 11 | width: 100%; 12 | height: 6vh; 13 | background: #182231; 14 | border-bottom: 1px solid rgb(23, 21, 35); 15 | } 16 | modulebar{ 17 | background-image: linear-gradient(-120deg, #d87f58, #bb4949); 18 | overflow-x: hidden; 19 | overflow-y: scroll; 20 | user-select: none; 21 | } 22 | .sidebar { 23 | width: 300px; 24 | height: 100vh; 25 | position: fixed; 26 | display: grid; 27 | grid-template-columns: 1fr 4fr; 28 | user-select: none; 29 | } 30 | 31 | .projectbar { 32 | background-color: #182231; 33 | border-right: 1px solid rgb(23, 21, 35); 34 | display: flex; 35 | height: 100vh; 36 | flex-direction: column; 37 | justify-content: space-between; 38 | user-select: none; 39 | } 40 | 41 | .project { 42 | color: white; 43 | font-family: sans-serif; 44 | font-weight: 700; 45 | font-size: 13px; 46 | transition: background 1s; 47 | width: 100%; 48 | height: 50px; 49 | padding: 0px 0px; 50 | border-bottom: 1px solid rgb(23, 21, 35); 51 | cursor: pointer; 52 | } 53 | .project:hover { 54 | background: #2d3846; 55 | } 56 | .active-project{ 57 | background: #2d3846; 58 | } 59 | .project-head { 60 | text-transform: uppercase; 61 | color: white; 62 | font-family: sans-serif; 63 | } 64 | .project-head p { 65 | padding: 10px 5px; 66 | border-bottom: 1px solid rgb(23, 21, 35); 67 | margin: 0; 68 | color: #f1ad49; 69 | font-size: 12px; 70 | font-weight: bolder; 71 | } 72 | .project p { 73 | margin: 0px; 74 | padding: 15px 10px; 75 | text-transform: capitalize; 76 | } 77 | .add-project { 78 | text-align: center; 79 | color: #e9ad55; 80 | cursor: pointer; 81 | } 82 | 83 | .module-head { 84 | font-family: sans-serif; 85 | color: #111419; 86 | font-weight: 700; 87 | font-size: 14px; 88 | border-top: 1px solid #111419; 89 | border-bottom: 1px solid #111419; 90 | cursor: pointer; 91 | } 92 | .module-head p { 93 | margin: 0; 94 | padding: 10px 10px; 95 | } 96 | 97 | .package-list { 98 | font-family: sans-serif; 99 | font-size: 13px; 100 | font-weight: 100; 101 | color: white; 102 | padding: 10px 10px; 103 | } 104 | .project-list { 105 | overflow-x: hidden; 106 | overflow-y: scroll; 107 | } 108 | .down-arrow img { 109 | width: 10px; 110 | padding: 0px 5px; 111 | cursor: pointer; 112 | } 113 | .package p { 114 | margin: 0px 25px 5px 25px; 115 | text-transform: capitalize; 116 | } 117 | .package span { 118 | font-size: 9px; 119 | color: #111419; 120 | } 121 | .package { 122 | cursor: pointer; 123 | } 124 | .logo { 125 | width: 40px; 126 | padding: 5px 15px; 127 | } 128 | .module-banner h1 { 129 | margin: 0; 130 | font-family: sans-serif; 131 | font-size: 14px; 132 | color: #111419; 133 | } 134 | .module-banner { 135 | padding: 10px; 136 | } 137 | .markdown-body { 138 | box-sizing: border-box; 139 | min-width: 200px; 140 | max-width: 980px; 141 | margin: 0 auto; 142 | padding: 45px; 143 | } 144 | .browser-body { 145 | display: none; 146 | } 147 | webview { 148 | border: none; 149 | width: 100%; 150 | height: -webkit-fill-available; 151 | } 152 | #clipper { 153 | width: 100%; 154 | text-align: right; 155 | margin: -5px 8px; 156 | font-size: 10px; 157 | } 158 | #clipper span { 159 | cursor: pointer; 160 | background: white; 161 | padding: 4px; 162 | user-select: none; 163 | } 164 | .markdown-body-frame { 165 | max-width: 0px; 166 | margin-top: 50px; 167 | } 168 | .browser { 169 | font-family: sans-serif; 170 | padding: 10px; 171 | font-weight: lighter; 172 | color: #dc3545; 173 | cursor: pointer; 174 | } 175 | @media (max-width: 767px) { 176 | .markdown-body { 177 | padding: 15px; 178 | } 179 | } 180 | .view-window { 181 | margin-left: 300px; 182 | } 183 | .inactive-tab { 184 | border-bottom: none; 185 | } 186 | .inactive-tab .down-arrow img, 187 | .inactive-dev-tab .down-arrow img { 188 | transform: rotateZ(-90deg); 189 | } 190 | ::-webkit-scrollbar { 191 | width: 0px; 192 | background: transparent; /* make scrollbar transparent */ 193 | } 194 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | false, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ], 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es5", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2017", 18 | "dom", 19 | "dom.iterable" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs/Rx" 22 | ], 23 | "import-spacing": true, 24 | "indent": [ 25 | true, 26 | "spaces" 27 | ], 28 | "interface-over-type-literal": true, 29 | "label-position": true, 30 | "max-line-length": [ 31 | true, 32 | 140 33 | ], 34 | "member-access": false, 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-arg": true, 47 | "no-bitwise": true, 48 | "no-console": [ 49 | true, 50 | "debug", 51 | "info", 52 | "time", 53 | "timeEnd", 54 | "trace" 55 | ], 56 | "no-construct": true, 57 | "no-debugger": true, 58 | "no-duplicate-super": true, 59 | "no-empty": false, 60 | "no-empty-interface": true, 61 | "no-eval": true, 62 | "no-inferrable-types": [ 63 | true, 64 | "ignore-params" 65 | ], 66 | "no-misused-new": true, 67 | "no-non-null-assertion": true, 68 | "no-redundant-jsdoc": true, 69 | "no-shadowed-variable": true, 70 | "no-string-literal": false, 71 | "no-string-throw": true, 72 | "no-switch-case-fall-through": true, 73 | "no-trailing-whitespace": true, 74 | "no-unnecessary-initializer": true, 75 | "no-unused-expression": true, 76 | "no-use-before-declare": true, 77 | "no-var-keyword": true, 78 | "object-literal-sort-keys": false, 79 | "one-line": [ 80 | true, 81 | "check-open-brace", 82 | "check-catch", 83 | "check-else", 84 | "check-whitespace" 85 | ], 86 | "prefer-const": true, 87 | "quotemark": [ 88 | true, 89 | "single" 90 | ], 91 | "radix": true, 92 | "semicolon": [ 93 | true, 94 | "always" 95 | ], 96 | "triple-equals": [ 97 | true, 98 | "allow-null-check" 99 | ], 100 | "typedef-whitespace": [ 101 | true, 102 | { 103 | "call-signature": "nospace", 104 | "index-signature": "nospace", 105 | "parameter": "nospace", 106 | "property-declaration": "nospace", 107 | "variable-declaration": "nospace" 108 | } 109 | ], 110 | "unified-signatures": true, 111 | "variable-name": false, 112 | "whitespace": [ 113 | true, 114 | "check-branch", 115 | "check-decl", 116 | "check-operator", 117 | "check-separator", 118 | "check-type" 119 | ], 120 | "no-output-on-prefix": true, 121 | "use-input-property-decorator": true, 122 | "use-output-property-decorator": true, 123 | "use-host-property-decorator": true, 124 | "no-input-rename": true, 125 | "no-output-rename": true, 126 | "use-life-cycle-interface": true, 127 | "use-pipe-transform-interface": true, 128 | "component-class-suffix": true, 129 | "directive-class-suffix": true 130 | } 131 | } 132 | --------------------------------------------------------------------------------