├── .github └── workflows │ └── CI.yml ├── .npmrc ├── .prettierignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── dist ├── commands.d.ts ├── editor-linter.d.ts ├── editor-registry.d.ts ├── helpers.d.ts ├── index.d.ts ├── index.js ├── index.js.map ├── indie-delegate.d.ts ├── indie-registry.d.ts ├── linter-registry.d.ts ├── main.d.ts ├── message-registry.d.ts ├── toggle-view.d.ts ├── tsconfig.tsbuildinfo ├── types │ ├── .eslintignore │ ├── atom.d.ts │ ├── index.d.ts │ ├── linter-ui-default.d.ts │ └── linter.d.ts ├── ui-registry.d.ts └── validate │ ├── helpers.d.ts │ └── index.d.ts ├── lib ├── commands.ts ├── editor-linter.ts ├── editor-registry.ts ├── helpers.ts ├── index.ts ├── indie-delegate.ts ├── indie-registry.ts ├── linter-registry.ts ├── main.ts ├── message-registry.ts ├── toggle-view.ts ├── tsconfig.json ├── types │ ├── .eslintignore │ ├── atom.d.ts │ ├── index.d.ts │ ├── linter-ui-default.d.ts │ └── linter.d.ts ├── ui-registry.ts └── validate │ ├── helpers.ts │ └── index.ts ├── package.json ├── pnpm-lock.yaml ├── prettier.config.js ├── rollup.config.js └── scripts └── get-ui-types.js /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | - pull_request 4 | - push 5 | 6 | jobs: 7 | Test: 8 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 9 | name: ${{ matrix.os }} - Atom ${{ matrix.atom_channel }} 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | os: 15 | - ubuntu-latest 16 | - macos-latest 17 | - windows-latest 18 | atom_channel: [stable, beta] 19 | steps: 20 | - uses: actions/checkout@v2 21 | - uses: UziTech/action-setup-atom@v1 22 | with: 23 | channel: ${{ matrix.atom_channel }} 24 | - name: Versions 25 | run: apm -v 26 | - name: Install APM dependencies 27 | run: | 28 | apm install 29 | - name: Run tests 👩🏾‍💻 30 | run: npm run test 31 | 32 | Lint: 33 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 34 | runs-on: ubuntu-latest 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | steps: 38 | - uses: actions/checkout@v2 39 | with: 40 | fetch-depth: 0 41 | - if: "!contains(github.event.head_commit.message, 'Prepare')" 42 | name: Commit lint ✨ 43 | uses: wagoid/commitlint-github-action@v2 44 | 45 | - name: Install dependencies 46 | run: npm install 47 | 48 | - name: Format ✨ 49 | run: npm run test.format 50 | 51 | - name: Lint ✨ 52 | run: npm run test.lint 53 | 54 | Release: 55 | needs: [Test, Lint] 56 | if: github.ref == 'refs/heads/master' && 57 | github.event.repository.fork == false 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v2 61 | - uses: UziTech/action-setup-atom@v1 62 | - uses: actions/setup-node@v1 63 | with: 64 | node-version: '12.x' 65 | - name: NPM install 66 | run: npm install 67 | - name: Build and Commit 68 | run: npm run build-commit 69 | # NOTE: uncomment when ready 70 | # - name: Release 🎉 71 | # uses: cycjimmy/semantic-release-action@v2 72 | # with: 73 | # extends: | 74 | # @semantic-release/apm-config 75 | # env: 76 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 77 | # ATOM_ACCESS_TOKEN: ${{ secrets.ATOM_ACCESS_TOKEN }} 78 | 79 | Skip: 80 | if: contains(github.event.head_commit.message, '[skip ci]') 81 | runs-on: ubuntu-latest 82 | steps: 83 | - name: Skip CI 🚫 84 | run: echo skip ci 85 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | public-hoist-pattern[]=* 2 | package-lock=false 3 | lockfile=true 4 | prefer-frozen-lockfile=false 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package.json 3 | package-lock.json 4 | pnpm-lock.yaml 5 | coverage 6 | build 7 | dist 8 | lib/types/linter-ui-default 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 3.4.0 2 | 3 | - feat: allow solutions to be an async callback 4 | - fix: add a warning when a provider is in the list of disabled providers 5 | - Update dependencies 6 | - other bug fixes 7 | 8 | ### 3.3.1 9 | 10 | - fix: update dependencies #1729 11 | fix: the issue with atom-package-deps not installing the linter dependency #1729 12 | - minor optimizations #1729 13 | 14 | ### 3.3.0 15 | 16 | - Fix subfolder git detection (#1715): 17 | if you add a project folder which is not a git repo but it contains folders which are git repos, then the repository detection now works correctly. The `repositoryForDirectory` function in `atom.project` is able to detect the repository for any Directory, even if it is in a subfolder. 18 | It is an async function, so some changes have to be made in up the call chain 19 | 20 | ### 3.2.3 21 | 22 | - Minor optimizations 23 | 24 | ### 3.2.2 25 | 26 | - Use class props and merge subscriptions.add (#1720) 27 | 28 | ### 3.2.1 29 | 30 | - Use strict-null check in TypeScript and fix some bugs (#1719) 31 | 32 | ### 3.2.0 33 | 34 | - Convert the codebase to TypeScript (#1718) 35 | 36 | ### 3.1.1 37 | 38 | - Minor optimizations 39 | 40 | ## 3.1.0 41 | 42 | - Now linter loads 13 times faster! (#1695) 43 | 44 | ## 3.0.0 45 | 46 | - Improve performance (#1706) 47 | - Rewrite diff check algorithm (#1706) 48 | - Fix linter fixes (#1706) 49 | 50 | In case you maintain a linter-ui packages (e.g. linter-ui-default, linter-minimap), see this guide for upgrading: https://github.com/steelbrain/linter/blob/master/docs/guides/upgrading-to-linter-v3.md 51 | 52 | ## 2.3.1 53 | 54 | - Upgrade dependencies to fix vulns 55 | 56 | ## 2.3.0 57 | 58 | - Remove support for legacy linter APIs 59 | - Add a button to open developer console on Linter error messages 60 | - Include `description` in message key (when string rather than promise) 61 | - Fix a bug where linter messages (file-scoped) would disappear when same buffer is opened in two editors and one of them is closed 62 | 63 | ## 2.2.0 64 | 65 | - `linter:debug` overhaul with more debug information 66 | - Add `linterName` support to messages API v2 (Thanks @hansonw from Facebook) 67 | 68 | ## 2.1.4 69 | 70 | - Hotfix release for a regression introduced in last version (sorry everyone) 71 | 72 | ## 2.1.3 73 | 74 | - Add `disabledProviders` config that tracks the list of disabled linter providers 75 | - Enhance linter provider error message to include opening instructions for dev tools 76 | 77 | ## 2.1.2 78 | 79 | - Hotfix release for a regression introduced in last version 80 | 81 | ## 2.1.1 82 | 83 | - Unset no longer available v1 configs 84 | - Make `linter.name` optional for v1 again 85 | - Do not show Linter v2 for greeter for new installations 86 | - Fix a bug where disabling and reenabling `linter-ui-default` would not add previously existent issues to the UI 87 | 88 | ## 2.1.0 89 | 90 | - Add support for Legacy Indie Providers v1 91 | - Move docs to GitHub pages, docs can now be found at [`steelbrain.me/linter`](http://steelbrain.me/linter) 92 | 93 | ## 2.0.0 94 | 95 | - Rewrite entire package 96 | - Add support for Linter Messages v2 97 | - Add support for Indie Providers v2 98 | - Drop support for Indie Providers v1 99 | 100 | ## Pre v2.0 101 | 102 | See the CHANGELOG for Pre v2.0 at [v1 CHANGELOG](https://github.com/steelbrain/linter/blob/v1/CHANGELOG.md) 103 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 steelbrain 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Linter 2 | 3 | [![Slack Badge](https://img.shields.io/badge/chat-atom.io%20slack-blue.svg?style=flat-square)](http://atom-slack.herokuapp.com/) 4 | [![Build Status](https://img.shields.io/circleci/project/steelbrain/linter.svg?style=flat-square)](https://circleci.com/gh/steelbrain/linter) 5 | [![Plugin installs!](https://img.shields.io/apm/dm/linter.svg?style=flat-square)](https://atom.io/packages/linter) 6 | [![Package version!](https://img.shields.io/apm/v/linter.svg?style=flat-square)](https://atom.io/packages/linter) 7 | [![Dependencies!](https://img.shields.io/david/steelbrain/Linter.svg?style=flat-square)](https://david-dm.org/steelbrain/linter) 8 | [![OpenCollective](https://opencollective.com/linter/backers/badge.svg)](#backers) 9 | [![OpenCollective](https://opencollective.com/linter/sponsors/badge.svg)](#sponsors) 10 | 11 | Linter is a base linter provider for the hackable [Atom Editor](http://atom.io). Additionally, you need to install a specific linter for your language. You will find a full list on [atomlinter.github.io](http://atomlinter.github.io/). 12 | 13 | It provides a top-level API to its consumer so that they can visualize errors and other types of messages with ease. 14 | 15 | ![Preview](https://cloud.githubusercontent.com/assets/4278113/23879933/1ab17e2a-0872-11e7-803d-3fe0ccfc6790.gif) 16 | 17 | #### How to / Installation 18 | 19 | You can install through the CLI by doing: 20 | 21 | ``` 22 | $ apm install linter 23 | ``` 24 | 25 | Or you can install from Settings view by searching for `Base Linter`, (this package might not show up when searching for `Linter`). 26 | 27 | Linter automatically installs `linter-ui-default`, which is required for the functionality of this package. 28 | 29 | #### API Documentation 30 | 31 | Please navigate to [steelbrain.me/linter](http://steelbrain.me/linter/) for Linter v2 documentation. 32 | 33 | #### Contribute 34 | 35 | Stick to imposed codestyle: 36 | 37 | - `$ npm i` 38 | - `$ npm lint` 39 | - `$ npm test` 40 | -------------------------------------------------------------------------------- /dist/commands.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable } from 'atom'; 2 | import type { Linter, UI } from './types'; 3 | import type IndieDelegate from './indie-delegate'; 4 | export declare class Commands { 5 | private emitter; 6 | private subscriptions; 7 | constructor(); 8 | lint(): void; 9 | debug(): void; 10 | enableLinter(): void; 11 | disableLinter(): void; 12 | toggleActiveEditor(): void; 13 | onShouldLint(callback: (...args: Array) => any): Disposable; 14 | onShouldDebug(callback: (...args: Array) => any): Disposable; 15 | onShouldToggleActiveEditor(callback: (...args: Array) => any): Disposable; 16 | onShouldToggleLinter(callback: (...args: Array) => any): Disposable; 17 | dispose(): void; 18 | } 19 | export declare function showDebug(standardLinters: Array, indieLinters: Array, uiProviders: Array): Promise; 20 | -------------------------------------------------------------------------------- /dist/editor-linter.d.ts: -------------------------------------------------------------------------------- 1 | import { Disposable } from 'atom'; 2 | import type { TextEditor } from 'atom'; 3 | export default class EditorLinter { 4 | private editor; 5 | private emitter; 6 | private subscriptions; 7 | constructor(editor: TextEditor); 8 | getEditor(): TextEditor; 9 | lint(onChange?: boolean): void; 10 | onShouldLint(callback: (...args: Array) => any): Disposable; 11 | onDidDestroy(callback: (...args: Array) => any): Disposable; 12 | dispose(): void; 13 | subscriptiveObserve(object: Record, eventName: string, callback: (...args: Array) => any): Disposable; 14 | } 15 | -------------------------------------------------------------------------------- /dist/editor-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable, TextEditor } from 'atom'; 2 | import EditorLinter from './editor-linter'; 3 | export default class EditorRegistry { 4 | private emitter; 5 | private lintOnOpen; 6 | private subscriptions; 7 | private editorLinters; 8 | constructor(); 9 | activate(): void; 10 | get(textEditor: TextEditor): EditorLinter | null | undefined; 11 | createFromTextEditor(textEditor: TextEditor): EditorLinter; 12 | hasSibling(editorLinter: EditorLinter): boolean; 13 | observe(callback: (editorLinter: EditorLinter) => void): Disposable; 14 | dispose(): void; 15 | } 16 | -------------------------------------------------------------------------------- /dist/helpers.d.ts: -------------------------------------------------------------------------------- 1 | import type { TextEditor } from 'atom'; 2 | import type { Linter, Message, MessageLike } from './types'; 3 | export declare const $version = "__$sb_linter_version"; 4 | export declare const $activated = "__$sb_linter_activated"; 5 | export declare const $requestLatest = "__$sb_linter_request_latest"; 6 | export declare const $requestLastReceived = "__$sb_linter_request_last_received"; 7 | export declare function shouldTriggerLinter(linter: Linter, wasTriggeredOnChange: boolean, scopes: Array): boolean; 8 | export declare function getEditorCursorScopes(textEditor: TextEditor): Array; 9 | export declare function isPathIgnored(filePath: string | null | undefined, ignoredGlob: string, ignoredVCS: boolean): Promise; 10 | export declare function updateMessageKey(message: Message): void; 11 | export declare function normalizeMessages(linterName: string, messages: Array): void; 12 | export declare function updateKeys(messages: Array): void; 13 | export declare function createKeyMessageMap(messages: Array): Map; 14 | interface FlaggedMessages { 15 | oldKept: Array; 16 | oldRemoved: Array; 17 | newAdded: Array; 18 | } 19 | export declare function flagMessages(inputs: Array, oldMessages: Array): FlaggedMessages | null; 20 | export declare function mergeArray(arr1: Array, arr2: Array): void; 21 | export {}; 22 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import { Disposable } from 'atom'; 2 | import type { UI, Linter as LinterProvider, Indie } from './types'; 3 | export declare function activate(): void; 4 | export declare function consumeLinter(linter: LinterProvider | Array): Disposable; 5 | export declare function consumeUI(ui: UI | Array): Disposable; 6 | export declare function provideIndie(): (indie: Indie) => import("./indie-delegate").default; 7 | export declare function deactivate(): void; 8 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("atom"),t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},i="object"==typeof t&&t&&t.Object===Object&&t,s="object"==typeof self&&self&&self.Object===Object&&self,r=i||s||Function("return this")(),n=r.Symbol,o=n,a=Object.prototype,d=a.hasOwnProperty,l=a.toString,c=o?o.toStringTag:void 0;var h=function(e){var t=d.call(e,c),i=e[c];try{e[c]=void 0;var s=!0}catch(e){}var r=l.call(e);return s&&(t?e[c]=i:delete e[c]),r},u=Object.prototype.toString;var g=h,p=function(e){return u.call(e)},f=n?n.toStringTag:void 0;var m=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":f&&f in Object(e)?g(e):p(e)};var b=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)},v=m,y=b;var w,_=function(e){if(!y(e))return!1;var t=v(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t},I=r["__core-js_shared__"],L=(w=/[^.]+$/.exec(I&&I.keys&&I.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"";var E=function(e){return!!L&&L in e},$=Function.prototype.toString;var D=_,P=E,M=b,C=function(e){if(null!=e){try{return $.call(e)}catch(e){}try{return e+""}catch(e){}}return""},j=/^\[object .+?Constructor\]$/,O=Function.prototype,A=Object.prototype,S=O.toString,U=A.hasOwnProperty,N=RegExp("^"+S.call(U).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");var T=function(e){return!(!M(e)||P(e))&&(D(e)?N:j).test(C(e))},k=function(e,t){return null==e?void 0:e[t]};var x=function(e,t){var i=k(e,t);return T(i)?i:void 0},R=x(Object,"create"),F=R;var B=function(){this.__data__=F?F(null):{},this.size=0};var z=function(e){var t=this.has(e)&&delete this.__data__[e];return this.size-=t?1:0,t},q=R,V=Object.prototype.hasOwnProperty;var G=function(e){var t=this.__data__;if(q){var i=t[e];return"__lodash_hash_undefined__"===i?void 0:i}return V.call(t,e)?t[e]:void 0},K=R,W=Object.prototype.hasOwnProperty;var Y=R;var X=B,H=z,J=G,Q=function(e){var t=this.__data__;return K?void 0!==t[e]:W.call(t,e)},Z=function(e,t){var i=this.__data__;return this.size+=this.has(e)?0:1,i[e]=Y&&void 0===t?"__lodash_hash_undefined__":t,this};function ee(e){var t=-1,i=null==e?0:e.length;for(this.clear();++t-1},pe=function(e,t){var i=this.__data__,s=le(i,e);return s<0?(++this.size,i.push([e,t])):i[s][1]=t,this};function fe(e){var t=-1,i=null==e?0:e.length;for(this.clear();++t-1};var qe=function(e,t,i){for(var s=-1,r=null==e?0:e.length;++s=200){var l=t?null:Ze(e);if(l)return et(l);o=!1,r=Qe,d=new Xe}else d=t?[]:a;e:for(;++s` • ${e}`));atom.notifications.addWarning(`[Linter] ${e}`,{dismissable:!0,detail:`${t}\n${s.join("\n")}`})}const rt=new Set(["error","warning","info"]);function nt(t,i){const s=[];if(Array.isArray(i)){let t=!1,r=!1,n=!1,o=!1,a=!1,d=!1,l=!1,c=!1,h=!1;for(let u=0,{length:g}=i;ue.concat(t.getScopeDescriptor().getScopesArray())),["*"]))}let ht;async function ut(t,i,s){if(!t)return!0;if(s){const i=new e.Directory(t),s=await atom.project.repositoryForDirectory(i);if(s&&s.isPathIgnored(t))return!0}const r="win32"===process.platform?t.replace(/\\/g,"/"):t;return ht||(ht=require("minimatch")),ht(r,i)}function gt(e){const{reference:t,location:i}=e;e.key=[`$LINTER:${e.linterName}`,`$LOCATION:${i.file}$${i.position.start.row}$${i.position.start.column}$${i.position.end.row}$${i.position.end.column}`,t?`$REFERENCE:${t.file}$${t.position?`${t.position.row}$${t.position.column}`:""}`:"$REFERENCE:null",`$EXCERPT:${e.excerpt}`,`$SEVERITY:${e.severity}`,e.icon?`$ICON:${e.icon}`:"$ICON:null",e.url?`$URL:${e.url}`:"$URL:null","string"==typeof e.description?`$DESCRIPTION:${e.description}`:"$DESCRIPTION:null"].join("")}function pt(e,t){for(let i=0,{length:s}=t;i!o.includes(e))),d=new Set;for(let e=0,t=a.length;e{vt(e,t)})),e}clearMessages(){this.subscriptions.disposed||(this.emitter.emit("did-update",[]),this.messages.clear())}setMessages(e,t=null){if("string"!=typeof e||!Array.isArray(t))throw new Error("Invalid Parameters to setMessages()");!this.subscriptions.disposed&&nt(this.name,t)&&(t.forEach((function(t){if(t.location.file!==e)throw console.debug("[Linter-UI-Default] Expected File",e,"Message",t),new Error("message.location.file does not match the given filePath")})),pt(this.name,t),this.messages.set(e,t),this.emitter.emit("did-update",this.getMessages()))}setAllMessages(e){if(!this.subscriptions.disposed&&(Array.isArray(e)&&!atom.inDevMode()||nt(this.name,e))){pt(this.name,e),this.messages.clear();for(let t=0,{length:i}=e;t{this.delegates.delete(i)})),i.onDidUpdate((e=>{this.emitter.emit("did-update",{linter:i,messages:e})})),this.emitter.emit("observe",i),i}getProviders(){return Array.from(this.delegates)}observe(e){return this.delegates.forEach(e),this.emitter.on("observe",e)}onDidUpdate(e){return this.emitter.on("did-update",e)}dispose(){for(const e of this.delegates)e.dispose();this.subscriptions.dispose()}}var _t=r,It=/\s/;var Lt=function(e){for(var t=e.length;t--&&It.test(e.charAt(t)););return t},Et=/^\s+/;var $t=m,Dt=function(e){return null!=e&&"object"==typeof e};var Pt=function(e){return e?e.slice(0,Lt(e)+1).replace(Et,""):e},Mt=b,Ct=function(e){return"symbol"==typeof e||Dt(e)&&"[object Symbol]"==$t(e)},jt=/^[-+]0x[0-9a-f]+$/i,Ot=/^0b[01]+$/i,At=/^0o[0-7]+$/i,St=parseInt;var Ut=b,Nt=function(){return _t.Date.now()},Tt=function(e){if("number"==typeof e)return e;if(Ct(e))return NaN;if(Mt(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=Mt(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=Pt(e);var i=Ot.test(e);return i||At.test(e)?St(e.slice(2),i?2:8):jt.test(e)?NaN:+e},kt=Math.max,xt=Math.min;var Rt=function(e,t,i){var s,r,n,o,a,d,l=0,c=!1,h=!1,u=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function g(t){var i=s,n=r;return s=r=void 0,l=t,o=e.apply(n,i)}function p(e){return l=e,a=setTimeout(m,t),c?g(e):o}function f(e){var i=e-d;return void 0===d||i>=t||i<0||h&&e-l>=n}function m(){var e=Nt();if(f(e))return b(e);a=setTimeout(m,function(e){var i=t-(e-d);return h?xt(i,n-(e-l)):i}(e))}function b(e){return a=void 0,u&&s?g(e):(s=r=void 0,o)}function v(){var e=Nt(),i=f(e);if(s=arguments,r=this,d=e,i){if(void 0===a)return p(d);if(h)return clearTimeout(a),a=setTimeout(m,t),g(d)}return void 0===a&&(a=setTimeout(m,t)),o}return t=Tt(t)||0,Ut(i)&&(c=!!i.leading,n=(h="maxWait"in i)?kt(Tt(i.maxWait)||0,t):n,u="trailing"in i?!!i.trailing:u),v.cancel=function(){void 0!==a&&clearTimeout(a),l=0,s=d=r=a=void 0},v.flush=function(){return void 0===a?o:b(Nt())},v};class Ft{constructor(){this.emitter=new e.Emitter,this.messages=[],this.messagesMap=new Set,this.subscriptions=new e.CompositeDisposable,this.debouncedUpdate=Rt(this.update,100,{leading:!0}),this.subscriptions.add(this.emitter)}set({messages:e,linter:t,buffer:i}){let s=null;for(const e of this.messagesMap)if(e.buffer===i&&e.linter===t){s=e;break}s?(s.messages=e,s.changed=!0):this.messagesMap.add({messages:e,linter:t,buffer:i,oldMessages:[],changed:!0,deleted:!1}),this.debouncedUpdate()}update(){const e={added:[],removed:[],messages:[]};for(const t of this.messagesMap){if(t.deleted){vt(e.removed,t.oldMessages),this.messagesMap.delete(t);continue}if(!t.changed){vt(e.messages,t.oldMessages);continue}const i=bt(t.messages,t.oldMessages);if(null!==i){const{oldKept:s,oldRemoved:r,newAdded:n}=i;vt(e.added,n),vt(e.removed,r);const o=n.concat(s);vt(e.messages,o),t.oldMessages=o}}(e.added.length||e.removed.length)&&(this.messages=e.messages,this.emitter.emit("did-update-messages",e))}onDidUpdateMessages(e){return this.emitter.on("did-update-messages",e)}deleteByBuffer(e){for(const t of this.messagesMap)t.buffer===e&&(t.deleted=!0);this.debouncedUpdate()}deleteByLinter(e){for(const t of this.messagesMap)t.linter===e&&(t.deleted=!0);this.debouncedUpdate()}dispose(){this.subscriptions.dispose()}}class Bt{constructor(){this.emitter=new e.Emitter,this.linters=new Set,this.lintOnChange=!0,this.ignoreVCS=!0,this.ignoreGlob="**/*.min.{js,css}",this.lintPreviewTabs=!0,this.subscriptions=new e.CompositeDisposable,this.disabledProviders=[],this.activeNotifications=new Set,this.subscriptions.add(this.emitter,atom.config.observe("linter.lintOnChange",(e=>{this.lintOnChange=e})),atom.config.observe("core.excludeVcsIgnoredPaths",(e=>{this.ignoreVCS=e})),atom.config.observe("linter.ignoreGlob",(e=>{this.ignoreGlob=e})),atom.config.observe("linter.lintPreviewTabs",(e=>{this.lintPreviewTabs=e})),atom.config.observe("linter.disabledProviders",(e=>{0!==e.length&&console.warn(`Linter package: disabled linter providers: ${e}`),this.disabledProviders=e})))}hasLinter(e){return this.linters.has(e)}addLinter(e){(function(e){const t=[];return e&&"object"==typeof e?("string"!=typeof e.name&&t.push("Linter.name must be a string"),("string"!=typeof e.scope||"file"!==e.scope&&"project"!==e.scope)&&t.push("Linter.scope must be either 'file' or 'project'"),"boolean"!=typeof e.lintsOnChange&&t.push("Linter.lintsOnChange must be a boolean"),Array.isArray(e.grammarScopes)||t.push("Linter.grammarScopes must be an Array"),"function"!=typeof e.lint&&t.push("Linter.lint must be a function")):t.push("Linter must be an object"),!t.length||(st("Invalid Linter received",`These issues were encountered while registering a Linter named '${e&&e.name?e.name:"Unknown"}'`,t),!1)})(e)&&(e[at]=!0,void 0===e.__$sb_linter_request_latest&&(e.__$sb_linter_request_latest=0),void 0===e[dt]&&(e[dt]=0),e.__$sb_linter_version=2,this.linters.add(e))}getProviders(){return Array.from(this.linters)}deleteLinter(e){this.linters.has(e)&&(e[at]=!1,this.linters.delete(e))}async lint({onChange:e,editor:t}){const i=t.getPath();if(e&&!this.lintOnChange||!this.lintPreviewTabs&&atom.workspace.getActivePane().getPendingItem()===t||await ut(t.getPath(),this.ignoreGlob,this.ignoreVCS))return!1;const s=ct(t),r=[];for(const n of this.linters){if(!lt(n,e,s))continue;if(this.disabledProviders.includes(n.name))continue;const o=++n.__$sb_linter_request_latest,a="file"===n.scope?t.getBuffer():null,d="file"===n.scope?i:null;this.emitter.emit("did-begin-linting",{number:o,linter:n,filePath:d}),r.push(new Promise((function(e){e(n.lint(t))})).then((e=>{if(this.emitter.emit("did-finish-linting",{number:o,linter:n,filePath:d}),n[dt]>=o||!n[at]||a&&!a.isAlive())return;if(n[dt]=o,a&&!a.isAlive())return;if(null==e)return;let t=!0;!atom.inDevMode()&&Array.isArray(e)||(t=nt(n.name,e)),t&&(pt(n.name,e),this.emitter.emit("did-update-messages",{messages:e,linter:n,buffer:a}))}),(e=>{this.emitter.emit("did-finish-linting",{number:o,linter:n,filePath:d}),console.error(`[Linter] Error running ${n.name}`,e);const t=`[Linter] Error running ${n.name}`;if(Array.from(this.activeNotifications).some((e=>e.getOptions().detail===t)))return;const i=atom.notifications.addError(t,{detail:"See Console for more info.",dismissable:!0,buttons:[{text:"Open Console",onDidClick:()=>{atom.openDevTools(),i.dismiss()}},{text:"Cancel",onDidClick:()=>{i.dismiss()}}]})})))}return await Promise.all(r),!0}onDidUpdateMessages(e){return this.emitter.on("did-update-messages",e)}onDidBeginLinting(e){return this.emitter.on("did-begin-linting",e)}onDidFinishLinting(e){return this.emitter.on("did-finish-linting",e)}dispose(){this.activeNotifications.forEach((e=>e.dismiss())),this.activeNotifications.clear(),this.linters.clear(),this.subscriptions.dispose()}}class zt{constructor(t){if(this.emitter=new e.Emitter,this.subscriptions=new e.CompositeDisposable,!atom.workspace.isTextEditor(t))throw new Error("EditorLinter expects a valid TextEditor");const i=t.getBuffer(),s=Rt((()=>{this.emitter.emit("should-lint",!1)}),50,{leading:!0});this.editor=t,this.subscriptions.add(this.editor.onDidDestroy((()=>this.dispose())),this.editor.onDidSave(s),i.onDidReload(s),this.subscriptiveObserve(atom.config,"linter.lintOnChangeInterval",(e=>i.onDidChange(Rt((()=>{this.emitter.emit("should-lint",!0)}),e)))))}getEditor(){return this.editor}lint(e=!1){this.emitter.emit("should-lint",e)}onShouldLint(e){return this.emitter.on("should-lint",e)}onDidDestroy(e){return this.emitter.on("did-destroy",e)}dispose(){this.emitter.emit("did-destroy"),this.subscriptions.dispose(),this.emitter.dispose()}subscriptiveObserve(t,i,s){let r=null;const n=t.observe(i,(e=>{r&&r.dispose(),r=s.call(this,e)}));return new e.Disposable((function(){n.dispose(),r&&r.dispose()}))}}class qt{constructor(){this.emitter=new e.Emitter,this.lintOnOpen=!0,this.subscriptions=new e.CompositeDisposable,this.editorLinters=new Map,this.subscriptions.add(this.emitter,atom.config.observe("linter.lintOnOpen",(e=>{this.lintOnOpen=e})))}activate(){this.subscriptions.add(atom.workspace.observeTextEditors((e=>{this.createFromTextEditor(e)})))}get(e){return this.editorLinters.get(e)}createFromTextEditor(e){let t=this.editorLinters.get(e);return t||(t=new zt(e),t.onDidDestroy((()=>{this.editorLinters.delete(e)})),this.editorLinters.set(e,t),this.emitter.emit("observe",t),this.lintOnOpen&&t.lint(),t)}hasSibling(e){const t=e.getEditor().getBuffer();return Array.from(this.editorLinters.keys()).some((e=>e.getBuffer()===t))}observe(e){return this.editorLinters.forEach(e),this.emitter.on("observe",e)}dispose(){for(const e of this.editorLinters.values())e.dispose();this.subscriptions.dispose()}}let Vt,Gt,Kt,Wt;function Yt(e){let t;if(e&&"object"==typeof e&&"string"==typeof e.name)t=e.name;else{if("string"!=typeof e)throw new Error("Unknown object passed to formatItem()");t=e}return` - ${t}`}function Xt(e,t){return e.name.localeCompare(t.name)}class Ht{constructor(){this.emitter=new e.Emitter,this.subscriptions=new e.CompositeDisposable,this.subscriptions.add(this.emitter,atom.commands.add("atom-workspace",{"linter:enable-linter":()=>this.enableLinter(),"linter:disable-linter":()=>this.disableLinter()}),atom.commands.add("atom-text-editor:not([mini])",{"linter:lint":()=>this.lint(),"linter:debug":()=>this.debug(),"linter:toggle-active-editor":()=>this.toggleActiveEditor()}))}lint(){this.emitter.emit("should-lint")}debug(){this.emitter.emit("should-debug")}enableLinter(){this.emitter.emit("should-toggle-linter","enable")}disableLinter(){this.emitter.emit("should-toggle-linter","disable")}toggleActiveEditor(){this.emitter.emit("should-toggle-active-editor")}onShouldLint(e){return this.emitter.on("should-lint",e)}onShouldDebug(e){return this.emitter.on("should-debug",e)}onShouldToggleActiveEditor(e){return this.emitter.on("should-toggle-active-editor",e)}onShouldToggleLinter(e){return this.emitter.on("should-toggle-linter",e)}dispose(){this.subscriptions.dispose()}}class Jt{constructor(t,i){this.emitter=new e.Emitter,this.subscriptions=new e.CompositeDisposable,this.disabledProviders=[],this.action=t,this.providers=i,this.subscriptions.add(this.emitter,atom.config.observe("linter.disabledProviders",(e=>{this.disabledProviders=e})))}getItems(){return"disable"===this.action?this.providers.filter((e=>!this.disabledProviders.includes(e))):this.disabledProviders}process(e){if("disable"===this.action)this.disabledProviders.push(e),this.emitter.emit("did-disable",e);else{const t=this.disabledProviders.indexOf(e);-1!==t&&this.disabledProviders.splice(t,1)}atom.config.set("linter.disabledProviders",this.disabledProviders)}show(){Gt||(Gt=require("atom-select-list"));const t=new Gt({items:this.getItems(),emptyMessage:"No matches found",elementForItem:e=>{const t=document.createElement("li");return t.textContent=e,t},didConfirmSelection:e=>{try{this.process(e),this.dispose()}catch(e){console.error("[Linter] Unable to process toggle:",e)}},didCancelSelection:()=>{this.dispose()},didConfirmEmptySelection:()=>{this.dispose()}}),i=atom.workspace.addModalPanel({item:t});t.focus(),this.subscriptions.add(new e.Disposable((function(){i.destroy()})))}onDidDispose(e){return this.emitter.on("did-dispose",e)}onDidDisable(e){return this.emitter.on("did-disable",e)}dispose(){this.emitter.emit("did-dispose"),this.subscriptions.dispose()}}class Qt{constructor(){this.commands=new Ht,this.subscriptions=new e.CompositeDisposable,this.idleCallbacks=new Set,this.subscriptions.add(this.commands),this.commands.onShouldLint((()=>{this.registryEditorsInit();const e=atom.workspace.getActiveTextEditor();if(void 0===e)return;const t=this.registryEditors.get(e);t&&t.lint()})),this.commands.onShouldToggleActiveEditor((()=>{const e=atom.workspace.getActiveTextEditor();if(void 0===e)return;this.registryEditorsInit();const t=this.registryEditors.get(e);t?t.dispose():e&&this.registryEditors.createFromTextEditor(e)})),this.commands.onShouldDebug((async()=>{this.registryUIInit(),this.registryIndieInit(),this.registryLintersInit(),await async function(e,t,i){Vt||(Vt=require("../package.json"));const s=atom.workspace.getActiveTextEditor();if(void 0===s)return;const r=ct(s),n=e.slice().sort(Xt),o=t.slice().sort(Xt),a=i.slice().sort(Xt),d=o.map(Yt).join("\n"),l=n.map(Yt).join("\n"),c=n.filter((e=>lt(e,!1,r))).map(Yt).join("\n"),h=r.map(Yt).join("\n"),u=a.map(Yt).join("\n"),g=atom.config.get("linter.ignoreGlob"),p=atom.config.get("core.excludeVcsIgnoredPaths"),f=atom.config.get("linter.disabledProviders").map(Yt).join("\n"),m=await ut(s.getPath(),g,p);atom.notifications.addInfo("Linter Debug Info",{detail:[`Platform: ${process.platform}`,`Atom Version: ${atom.getVersion()}`,`Linter Version: ${Vt.version}`,"Opened file is ignored: "+(m?"Yes":"No"),`Matching Linter Providers: \n${c}`,`Disabled Linter Providers: \n${f}`,`Standard Linter Providers: \n${l}`,`Indie Linter Providers: \n${d}`,`UI Providers: \n${u}`,`Ignore Glob: ${g}`,`VCS Ignored Paths are excluded: ${p}`,`Current File Scopes: \n${h}`].join("\n"),dismissable:!0})}(this.registryLinters.getProviders(),this.registryIndie.getProviders(),this.registryUI.getProviders())})),this.commands.onShouldToggleLinter((e=>{this.registryLintersInit();const t=new Jt(e,it(this.registryLinters.getProviders().map((e=>e.name))));t.onDidDispose((()=>{this.subscriptions.remove(t)})),t.onDidDisable((e=>{const t=this.registryLinters.getProviders().find((t=>t.name===e));t&&(this.registryMessagesInit(),this.registryMessages.deleteByLinter(t))})),t.show(),this.subscriptions.add(t)}));const t=window.requestIdleCallback((()=>{this.idleCallbacks.delete(t),this.subscriptions.add(atom.project.onDidChangePaths((()=>{this.commands.lint()})))}));this.idleCallbacks.add(t);const i=window.requestIdleCallback((()=>{this.idleCallbacks.delete(i),this.registryEditorsInit()}));this.idleCallbacks.add(i)}dispose(){this.idleCallbacks.forEach((e=>window.cancelIdleCallback(e))),this.idleCallbacks.clear(),this.subscriptions.dispose()}registryEditorsInit(){void 0===this.registryEditors&&(this.registryEditors=new qt,this.subscriptions.add(this.registryEditors),this.registryEditors.observe((e=>{e.onShouldLint((t=>{this.registryLintersInit(),this.registryLinters.lint({onChange:t,editor:e.getEditor()})})),e.onDidDestroy((()=>{this.registryMessagesInit(),this.registryEditors.hasSibling(e)||this.registryMessages.deleteByBuffer(e.getEditor().getBuffer())}))})),this.registryEditors.activate())}registryLintersInit(){void 0===this.registryLinters&&(this.registryLinters=new Bt,this.subscriptions.add(this.registryLinters),this.registryLinters.onDidUpdateMessages((({linter:e,messages:t,buffer:i})=>{this.registryMessagesInit(),this.registryMessages.set({linter:e,messages:t,buffer:i})})),this.registryLinters.onDidBeginLinting((({linter:e,filePath:t})=>{this.registryUIInit(),this.registryUI.didBeginLinting(e,t)})),this.registryLinters.onDidFinishLinting((({linter:e,filePath:t})=>{this.registryUIInit(),this.registryUI.didFinishLinting(e,t)})))}registryIndieInit(){void 0===this.registryIndie&&(this.registryIndie=new wt,this.subscriptions.add(this.registryIndie),this.registryIndie.observe((e=>{e.onDidDestroy((()=>{this.registryMessagesInit(),this.registryMessages.deleteByLinter(e)}))})),this.registryIndie.onDidUpdate((({linter:e,messages:t})=>{this.registryMessagesInit(),this.registryMessages.set({linter:e,messages:t,buffer:null})})))}registryMessagesInit(){this.registryMessages||(this.registryMessages=new Ft,this.subscriptions.add(this.registryMessages),this.registryMessages.onDidUpdateMessages((e=>{this.registryUIInit(),this.registryUI.render(e)})))}registryUIInit(){void 0===this.registryUI&&(this.registryUI=new ot,this.subscriptions.add(this.registryUI))}addUI(e){this.registryUIInit(),this.registryUI.add(e),this.registryMessagesInit();const t=this.registryMessages.messages;t.length&&e.render({added:t,messages:t,removed:[]})}deleteUI(e){this.registryUIInit(),this.registryUI.delete(e)}addLinter(e){this.registryLintersInit(),this.registryLinters.addLinter(e)}deleteLinter(e){this.registryLintersInit(),this.registryLinters.deleteLinter(e),this.registryMessagesInit(),this.registryMessages.deleteByLinter(e)}addIndie(e){return this.registryIndieInit(),this.registryIndie.register(e,2)}}exports.activate=function(){Wt=new e.CompositeDisposable,Kt=new Qt,Wt.add(Kt,atom.packages.onDidActivateInitialPackages((function(){atom.inSpecMode()||require("atom-package-deps").install("linter",!0)})))},exports.consumeLinter=function(t){const i=Array.isArray(t)?t:[t];for(const e of i)Kt.addLinter(e);return new e.Disposable((()=>{for(const e of i)Kt.deleteLinter(e)}))},exports.consumeUI=function(t){const i=Array.isArray(t)?t:[t];for(const e of i)Kt.addUI(e);return new e.Disposable((()=>{for(const e of i)Kt.deleteUI(e)}))},exports.deactivate=function(){Wt.dispose()},exports.provideIndie=function(){return e=>Kt.addIndie(e)}; 2 | //# sourceMappingURL=index.js.map 3 | -------------------------------------------------------------------------------- /dist/indie-delegate.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable } from 'atom'; 2 | import type { Indie, Message } from './types'; 3 | export default class IndieDelegate { 4 | private indie; 5 | scope: 'project'; 6 | private emitter; 7 | version: 2; 8 | private messages; 9 | private subscriptions; 10 | constructor(indie: Indie, version: 2); 11 | get name(): string; 12 | getMessages(): Array; 13 | clearMessages(): void; 14 | setMessages(filePath: string | Array>, messages?: Array | null | undefined): void; 15 | setAllMessages(messages: Array): void; 16 | onDidUpdate(callback: (...args: Array) => any): Disposable; 17 | onDidDestroy(callback: (...args: Array) => any): Disposable; 18 | dispose(): void; 19 | } 20 | -------------------------------------------------------------------------------- /dist/indie-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable } from 'atom'; 2 | import IndieDelegate from './indie-delegate'; 3 | import type { Indie } from './types'; 4 | export default class IndieRegistry { 5 | private emitter; 6 | private delegates; 7 | private subscriptions; 8 | constructor(); 9 | register(config: Indie, version: 2): IndieDelegate; 10 | getProviders(): Array; 11 | observe(callback: (...args: Array) => any): Disposable; 12 | onDidUpdate(callback: (...args: Array) => any): Disposable; 13 | dispose(): void; 14 | } 15 | -------------------------------------------------------------------------------- /dist/linter-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type { TextEditor, Disposable } from 'atom'; 2 | import type { Linter } from './types'; 3 | export default class LinterRegistry { 4 | private emitter; 5 | private linters; 6 | private lintOnChange; 7 | private ignoreVCS; 8 | private ignoreGlob; 9 | private lintPreviewTabs; 10 | private subscriptions; 11 | private disabledProviders; 12 | private activeNotifications; 13 | constructor(); 14 | hasLinter(linter: Linter): boolean; 15 | addLinter(linter: Linter): void; 16 | getProviders(): Array; 17 | deleteLinter(linter: Linter): void; 18 | lint({ onChange, editor }: { 19 | onChange: boolean; 20 | editor: TextEditor; 21 | }): Promise; 22 | onDidUpdateMessages(callback: (...args: Array) => any): Disposable; 23 | onDidBeginLinting(callback: (...args: Array) => any): Disposable; 24 | onDidFinishLinting(callback: (...args: Array) => any): Disposable; 25 | dispose(): void; 26 | } 27 | -------------------------------------------------------------------------------- /dist/main.d.ts: -------------------------------------------------------------------------------- 1 | import type { UI, Linter as LinterProvider, Indie } from './types'; 2 | declare class Linter { 3 | private commands; 4 | private registryUI?; 5 | private registryIndie?; 6 | private registryEditors?; 7 | private registryLinters?; 8 | private registryMessages?; 9 | private subscriptions; 10 | private idleCallbacks; 11 | constructor(); 12 | dispose(): void; 13 | registryEditorsInit(): void; 14 | registryLintersInit(): void; 15 | registryIndieInit(): void; 16 | registryMessagesInit(): void; 17 | registryUIInit(): void; 18 | addUI(ui: UI): void; 19 | deleteUI(ui: UI): void; 20 | addLinter(linter: LinterProvider): void; 21 | deleteLinter(linter: LinterProvider): void; 22 | addIndie(indie: Indie): import("./indie-delegate").default; 23 | } 24 | export default Linter; 25 | -------------------------------------------------------------------------------- /dist/message-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type { Disposable, TextBuffer } from 'atom'; 2 | import type { MessagesPatch, Message, Linter } from './types'; 3 | export default class MessageRegistry { 4 | private emitter; 5 | messages: Array; 6 | private messagesMap; 7 | private subscriptions; 8 | private debouncedUpdate; 9 | constructor(); 10 | set({ messages, linter, buffer }: { 11 | messages: Array; 12 | linter: Linter; 13 | buffer: TextBuffer | null; 14 | }): void; 15 | update(): void; 16 | onDidUpdateMessages(callback: (difference: MessagesPatch) => void): Disposable; 17 | deleteByBuffer(buffer: TextBuffer): void; 18 | deleteByLinter(linter: Linter): void; 19 | dispose(): void; 20 | } 21 | -------------------------------------------------------------------------------- /dist/toggle-view.d.ts: -------------------------------------------------------------------------------- 1 | import { Disposable } from 'atom'; 2 | declare type ToggleAction = 'enable' | 'disable'; 3 | export default class ToggleView { 4 | private action; 5 | private emitter; 6 | private providers; 7 | private subscriptions; 8 | private disabledProviders; 9 | constructor(action: ToggleAction, providers: Array); 10 | getItems(): Array; 11 | process(name: string): void; 12 | show(): void; 13 | onDidDispose(callback: () => any): Disposable; 14 | onDidDisable(callback: (name: string) => any): Disposable; 15 | dispose(): void; 16 | } 17 | export {}; 18 | -------------------------------------------------------------------------------- /dist/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"program":{"fileNames":["../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@4.3.4/node_modules/typescript/lib/lib.esnext.intl.d.ts","../node_modules/tslib/tslib.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostic_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/util/types.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/globals.global.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/ts3.6/base.d.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/base.d.ts","../node_modules/@types/node/index.d.ts","../node_modules/@types/atom/src/atom-environment.d.ts","../node_modules/@types/atom/src/text-editor-element.d.ts","../node_modules/@types/atom/dependencies/event-kit/index.d.ts","../node_modules/@types/atom/dependencies/first-mate/src/grammar.d.ts","../node_modules/@types/atom/dependencies/first-mate/src/first-mate.d.ts","../node_modules/@types/atom/dependencies/first-mate/index.d.ts","../node_modules/@types/atom/dependencies/pathwatcher/src/file.d.ts","../node_modules/@types/atom/dependencies/pathwatcher/src/directory.d.ts","../node_modules/@types/atom/dependencies/pathwatcher/src/main.d.ts","../node_modules/@types/atom/dependencies/pathwatcher/index.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/display-marker.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/display-marker-layer.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/helpers.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/marker.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/marker-layer.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/point.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/range.d.ts","../node_modules/@types/atom/dependencies/text-buffer/src/text-buffer.d.ts","../node_modules/@types/atom/dependencies/text-buffer/index.d.ts","../node_modules/@types/atom/src/buffered-node-process.d.ts","../node_modules/@types/atom/src/buffered-process.d.ts","../node_modules/@types/atom/src/clipboard.d.ts","../node_modules/@types/atom/src/color.d.ts","../node_modules/@types/atom/src/command-registry.d.ts","../node_modules/@types/atom/src/config.d.ts","../node_modules/@types/atom/src/config-schema.d.ts","../node_modules/@types/atom/src/context-menu-manager.d.ts","../node_modules/@types/atom/src/cursor.d.ts","../node_modules/@types/atom/src/decoration.d.ts","../node_modules/@types/atom/src/deserializer-manager.d.ts","../node_modules/@types/atom/src/dock.d.ts","../node_modules/@types/atom/src/get-window-load-settings.d.ts","../node_modules/@types/atom/src/git-repository.d.ts","../node_modules/@types/atom/src/grammar-registry.d.ts","../node_modules/@types/atom/src/gutter.d.ts","../node_modules/@types/atom/src/history-manager.d.ts","../node_modules/@types/atom/src/keymap-extensions.d.ts","../node_modules/@types/atom/src/layer-decoration.d.ts","../node_modules/@types/atom/src/menu-manager.d.ts","../node_modules/@types/atom/src/notification.d.ts","../node_modules/@types/atom/src/notification-manager.d.ts","../node_modules/@types/atom/src/other-types.d.ts","../node_modules/@types/atom/src/package.d.ts","../node_modules/@types/atom/src/package-manager.d.ts","../node_modules/@types/atom/src/pane.d.ts","../node_modules/@types/atom/src/panel.d.ts","../node_modules/@types/atom/src/path-watcher.d.ts","../node_modules/@types/atom/src/project.d.ts","../node_modules/@types/atom/src/scope-descriptor.d.ts","../node_modules/@types/atom/src/selection.d.ts","../node_modules/@types/atom/src/style-manager.d.ts","../node_modules/@types/atom/src/task.d.ts","../node_modules/@types/atom/src/text-editor.d.ts","../node_modules/@types/atom/src/text-editor-component.d.ts","../node_modules/@types/atom/src/text-editor-registry.d.ts","../node_modules/@types/atom/src/theme-manager.d.ts","../node_modules/@types/atom/src/tooltip.d.ts","../node_modules/@types/atom/src/tooltip-manager.d.ts","../node_modules/@types/atom/src/view-registry.d.ts","../node_modules/@types/atom/src/workspace.d.ts","../node_modules/@types/atom/src/workspace-center.d.ts","../node_modules/@types/atom/index.d.ts","../node_modules/@types/lodash/common/common.d.ts","../node_modules/@types/lodash/common/array.d.ts","../node_modules/@types/lodash/common/collection.d.ts","../node_modules/@types/lodash/common/date.d.ts","../node_modules/@types/lodash/common/function.d.ts","../node_modules/@types/lodash/common/lang.d.ts","../node_modules/@types/lodash/common/math.d.ts","../node_modules/@types/lodash/common/number.d.ts","../node_modules/@types/lodash/common/object.d.ts","../node_modules/@types/lodash/common/seq.d.ts","../node_modules/@types/lodash/common/string.d.ts","../node_modules/@types/lodash/common/util.d.ts","../node_modules/@types/lodash/index.d.ts","../node_modules/@types/lodash/uniq.d.ts","../lib/types/linter.d.ts","../lib/types/linter-ui-default/types/atom.d.ts","../lib/types/linter-ui-default/types/intentions.d.ts","../lib/types/linter-ui-default/types/linter.d.ts","../lib/types/linter-ui-default/types/index.d.ts","../lib/types/linter-ui-default/panel/delegate.d.ts","../lib/types/linter-ui-default/panel/dock.d.ts","../lib/types/linter-ui-default/panel/index.d.ts","../lib/types/linter-ui-default/commands.d.ts","../node_modules/@types/atom/status-bar/config.d.ts","../node_modules/@types/atom/status-bar/index.d.ts","../lib/types/linter-ui-default/status-bar/element.d.ts","../lib/types/linter-ui-default/status-bar/index.d.ts","../node_modules/atom-ide-base/types-packages/uri.d.ts","../node_modules/atom-ide-base/types-packages/busy-signal.d.ts","../node_modules/@types/atom/linter/config.d.ts","../node_modules/@types/atom/linter/index.d.ts","../node_modules/atom-ide-base/types-packages/code-actions.d.ts","../node_modules/atom-ide-base/types-packages/code-highlight.d.ts","../node_modules/atom-ide-base/types-packages/datatip.d.ts","../node_modules/atom-ide-base/types-packages/definitions.d.ts","../node_modules/atom-ide-base/types-packages/find-references.d.ts","../node_modules/atom-ide-base/types-packages/hyperclick.d.ts","../node_modules/atom-ide-base/types-packages/outline.d.ts","../node_modules/atom-ide-base/types-packages/sig-help.d.ts","../node_modules/@types/trusted-types/index.d.ts","../node_modules/@types/dompurify/index.d.ts","../node_modules/atom-ide-base/types-packages/markdown-service.d.ts","../node_modules/atom-ide-base/types-packages/text-edit.d.ts","../node_modules/atom-ide-base/types-packages/code-format.d.ts","../node_modules/atom-ide-base/types-packages/refactor.d.ts","../node_modules/atom-ide-base/types-packages/console.d.ts","../node_modules/atom-ide-base/types-packages/main.d.ts","../lib/types/linter-ui-default/busy-signal.d.ts","../lib/types/linter-ui-default/intentions.d.ts","../lib/types/linter-ui-default/tooltip/index.d.ts","../lib/types/linter-ui-default/editor/index.d.ts","../lib/types/linter-ui-default/editors.d.ts","../lib/types/linter-ui-default/tree-view/index.d.ts","../lib/types/linter-ui-default/main.d.ts","../lib/types/linter-ui-default.d.ts","../lib/types/index.d.ts","../node_modules/@types/minimatch/index.d.ts","../lib/helpers.ts","../lib/validate/helpers.ts","../lib/validate/index.ts","../lib/indie-delegate.ts","../lib/commands.ts","../node_modules/@types/lodash/debounce.d.ts","../lib/editor-linter.ts","../lib/editor-registry.ts","../lib/ui-registry.ts","../lib/indie-registry.ts","../lib/message-registry.ts","../lib/linter-registry.ts","../lib/toggle-view.ts","../lib/main.ts","../lib/index.ts","../lib/types/atom.d.ts","../lib/types/linter-ui-default/helpers.d.ts","../lib/types/linter-ui-default/index.d.ts","../lib/types/linter-ui-default/editor/helpers.d.ts","../node_modules/solid-js/types/jsx.d.ts","../node_modules/solid-js/types/reactive/signal.d.ts","../node_modules/solid-js/types/reactive/state.d.ts","../node_modules/solid-js/types/reactive/mutable.d.ts","../node_modules/solid-js/types/reactive/statemodifiers.d.ts","../node_modules/solid-js/types/reactive/scheduler.d.ts","../node_modules/solid-js/types/reactive/array.d.ts","../node_modules/solid-js/types/render/component.d.ts","../node_modules/solid-js/types/render/flow.d.ts","../node_modules/solid-js/types/render/suspense.d.ts","../node_modules/solid-js/types/render/hydration.d.ts","../node_modules/solid-js/types/render/index.d.ts","../node_modules/solid-js/types/index.d.ts","../lib/types/linter-ui-default/panel/component.d.ts","../lib/types/linter-ui-default/status-bar/helpers.d.ts","../lib/types/linter-ui-default/tooltip/delegate.d.ts","../lib/types/linter-ui-default/tooltip/fix-button.d.ts","../lib/types/linter-ui-default/tooltip/message.d.ts","../lib/types/linter-ui-default/tree-view/helpers.d.ts","../node_modules/@types/estree/index.d.ts","../node_modules/@types/jasmine/index.d.ts","../node_modules/@types/json-schema/index.d.ts","../node_modules/@types/json5/index.d.ts","../node_modules/@types/unist/index.d.ts","../node_modules/@types/mdast/index.d.ts","../node_modules/@types/prop-types/index.d.ts","../node_modules/@types/react/global.d.ts","../node_modules/csstype/index.d.ts","../node_modules/@types/scheduler/tracing.d.ts","../node_modules/@types/react/index.d.ts","../node_modules/@types/react-dom/index.d.ts","../node_modules/@types/requestidlecallback/index.d.ts","../node_modules/@types/resolve/index.d.ts","../node_modules/@types/scheduler/index.d.ts"],"fileInfos":[{"version":"ac3a8c4040e183ce38da69d23b96939112457d1936198e6542672b7963cf0fce","affectsGlobalScope":true},"dc47c4fa66b9b9890cf076304de2a9c5201e94b740cffdf09f87296d877d71f6","7a387c58583dfca701b6c85e0adaf43fb17d590fb16d5b2dc0a2fbd89f35c467","8a12173c586e95f4433e0c6dc446bc88346be73ffe9ca6eec7aa63c8f3dca7f9","5f4e733ced4e129482ae2186aae29fde948ab7182844c3a5a51dd346182c7b06",{"version":"1dad4fe1561d99dfd6709127608b99a76e5c2643626c800434f99c48038567ee","affectsGlobalScope":true},{"version":"cce43d02223f8049864f8568bed322c39424013275cd3bcc3f51492d8b546cb3","affectsGlobalScope":true},{"version":"43fb1d932e4966a39a41b464a12a81899d9ae5f2c829063f5571b6b87e6d2f9c","affectsGlobalScope":true},{"version":"cdccba9a388c2ee3fd6ad4018c640a471a6c060e96f1232062223063b0a5ac6a","affectsGlobalScope":true},{"version":"8dff1b4c2df638fcd976cbb0e636f23ab5968e836cd45084cc31d47d1ab19c49","affectsGlobalScope":true},{"version":"2bb4b3927299434052b37851a47bf5c39764f2ba88a888a107b32262e9292b7c","affectsGlobalScope":true},{"version":"810627a82ac06fb5166da5ada4159c4ec11978dfbb0805fe804c86406dab8357","affectsGlobalScope":true},{"version":"62d80405c46c3f4c527ee657ae9d43fda65a0bf582292429aea1e69144a522a6","affectsGlobalScope":true},{"version":"3013574108c36fd3aaca79764002b3717da09725a36a6fc02eac386593110f93","affectsGlobalScope":true},{"version":"8f4c9f651c8294a2eb1cbd12581fe25bfb901ab1d474bb93cd38c7e2f4be7a30","affectsGlobalScope":true},{"version":"3be5a1453daa63e031d266bf342f3943603873d890ab8b9ada95e22389389006","affectsGlobalScope":true},{"version":"17bb1fc99591b00515502d264fa55dc8370c45c5298f4a5c2083557dccba5a2a","affectsGlobalScope":true},{"version":"7ce9f0bde3307ca1f944119f6365f2d776d281a393b576a18a2f2893a2d75c98","affectsGlobalScope":true},{"version":"6a6b173e739a6a99629a8594bfb294cc7329bfb7b227f12e1f7c11bc163b8577","affectsGlobalScope":true},{"version":"12a310447c5d23c7d0d5ca2af606e3bd08afda69100166730ab92c62999ebb9d","affectsGlobalScope":true},{"version":"b0124885ef82641903d232172577f2ceb5d3e60aed4da1153bab4221e1f6dd4e","affectsGlobalScope":true},{"version":"0eb85d6c590b0d577919a79e0084fa1744c1beba6fd0d4e951432fa1ede5510a","affectsGlobalScope":true},{"version":"da233fc1c8a377ba9e0bed690a73c290d843c2c3d23a7bd7ec5cd3d7d73ba1e0","affectsGlobalScope":true},{"version":"df9c8a72ca8b0ed62f5470b41208a0587f0f73f0a7db28e5a1272cf92537518e","affectsGlobalScope":true},{"version":"bb2d3fb05a1d2ffbca947cc7cbc95d23e1d053d6595391bd325deb265a18d36c","affectsGlobalScope":true},{"version":"c80df75850fea5caa2afe43b9949338ce4e2de086f91713e9af1a06f973872b8","affectsGlobalScope":true},{"version":"60761e6ea886034af0f294f025a7199360ce4e2c8ba4ec6408bc049cf9b89799","affectsGlobalScope":true},{"version":"506b80b9951c9381dc5f11897b31fca5e2a65731d96ddefa19687fbc26b23c6e","affectsGlobalScope":true},"12f4cfe2fe60b810c3174537bc2ddb20c1067b7768643d12cb1266fd183afb75","c7bdc99177a2a94d25fb13722adaaf5b3291bf70b4d1b27584ba189dd3889ba3",{"version":"7c4064a324cd755a9b281d5795fc6ebd9dd713b1c356220185c61eb1b2d0f1af","affectsGlobalScope":true},"e23424b97418eca3226fd24de079f1203eb70360622e4e093af2aff14d4be6ec","ff16181fe134bb123283eb6777c624f6f3ee3f5c17d70b8447fa68af0935d312","54868134aa26f98b6fbc8d28040d8a0f5e64a1cb0dfac7f059b35cac99d626f2","04eaa93bd75f937f9184dcb95a7983800c5770cf8ddd8ac0f3734dc02f5b20ef",{"version":"7ddd5487c03df04c01a8618e06d875e167524902ed3dd9a2a9345a0ef5202d6f","affectsGlobalScope":true},"45ac321f2e15d268fd74a90ddaa6467dcaaff2c5b13f95b4b85831520fb7a491","dfc747ab8dd5f623055a4c26fd35e8cceca869fd3f1cf09701c941ca3679665a","c9f5f2920ff61d7158417b8440d5181ddc34a3dfef811a5677dd8a9fb91471e9","5cc0a492da3602510b8f5ed1852b1e0390002780d8758fbc8c0cd023ca7085f8","ec7dafafe751a5121f8f1c80201ebe7e7238c47e6329280a73c4d1ca4bb7fa28","64debeb10e4b7ae4ec9e89bfb4e04c6101ab98c3cc806d14e5488607cfec2753",{"version":"2866a528b2708aa272ec3eaafd3c980abb23aec1ef831cfc5eb2186b98c37ce5","affectsGlobalScope":true},{"version":"a5782d6cea81fe43d2db7ed41e789458c933ab3ab60602f7b5b14c4da3370496","affectsGlobalScope":true},"b86b7ff709a82ef3cba2184136c025989958bad483ffb13e4ca35d720245adf4","05b1c856de9c8f2c09c86a89455e25965342496ebe6d089760a9646c51295c76","c0d983dfc997b446ec8e456dea90e8c0c97ba896d55d7e34dfc351f32c405eb9","b447e123210c68f205f67b20c996c04a1eb64b0e591c5e06e164cd3d3a869b28","13257840c0850d4ebd7c2b17604a9e006f752de76c2400ebc752bc465c330452","42176966283d3835c34278b9b5c0f470d484c0c0c6a55c20a2c916a1ce69b6e8","0cff7901aedfe78e314f7d44088f07e2afa1b6e4f0473a4169b8456ca2fb245d","6ea59cf5479f3fad5db2caa4513d8d06d6cfee8d8df69e7a040c9b5b7f25f39c","e2236264a811ed1d09a2487a433e8f5216ae62378cf233954ae220cf886f6717","3ec1e108d587a5661ec790db607f482605ba9f3830e118ce578e3ffa3c42e22b","100b3bb9d39d2b1b5340f1bf45a52e94ef1692b45232b4ba00fac5c3cc56d331",{"version":"ec1a29ddaecb683aa360df0bd98ab5d4171d2d549554f7c5ab2a5c183a3dcb67","affectsGlobalScope":true},"7f77304372efe3c9967e5f9ea2061f1b4bf41dc3cda3c83cdd676f2e5af6b7e6","992c6f6be16c0a1d2eec13ece33adeea2c747ba27fcd078353a8f4bb5b4fea58","2597718d91e306949d89e285bf34c44192014ef541c3bd7cbb825c022749e974","a6b0abdb67d63ebe964ba5fee31bc3daf10c12eecd46b24d778426010c04c67e","ac4801ebc2355ba32329070123b1cd15891bf71b41dcaf9e75b4744832126a59","fd2298fba0640e7295e7bd545e2dfbfcccbb00c27019e501c87965a02bbdebf6","4fd3c4debadce3e9ab9dec3eb45f7f5e2e3d4ad65cf975a6d938d883cfb25a50","71ddd49185b68f27bfac127ef5d22cb2672c278e53e5370d9020ef50ca9c377d","b1ea7a6eaa7608e0e0529aebd323b526a79c6c05a4e519ae5c779675004dcdf1","9fcb033a6208485d8f3fadde31eb5cbcaf99149cff3e40c0dc53ebc6d0dff4e9","7df562288f949945cf69c21cd912100c2afedeeb7cdb219085f7f4b46cb7dde4","9d16690485ff1eb4f6fc57aebe237728fd8e03130c460919da3a35f4d9bd97f5","dcc6910d95a3625fd2b0487fda055988e46ab46c357a1b3618c27b4a8dd739c9","f4149f1aa299474c7040a35fe8f8ac2ad078cc1b190415adc1fff3ed52d490ea","3730099ed008776216268a97771de31753ef71e0a7d0ec650f588cba2a06ce44","8d649dbc429d7139a1d9a14ea2bf8af1dc089e0a879447539587463d4b6c248c","60c9e27816ec8ac8df7240598bb086e95b47edfb454c5cbf4003c812e0ed6e39","e361aecf17fc4034b4c122a1564471cdcd22ef3a51407803cb5a5fc020c04d02","4926467de88a92a4fc9971d8c6f21b91eca1c0e7fc2a46cc4638ab9440c73875",{"version":"2708349d5a11a5c2e5f3a0765259ebe7ee00cdcc8161cb9990cb4910328442a1","affectsGlobalScope":true},"fc0ae4a8ad3c762b96f9d2c3700cb879a373458cb0bf3175478e3b4f85f7ef2f","fabbec378e1ddd86fcf2662e716c2b8318acedb664ee3a4cba6f9e8ee8269cf1","b3593bd345ebea5e4d0a894c03251a3774b34df3d6db57075c18e089a599ba76","e61a21e9418f279bc480394a94d1581b2dee73747adcbdef999b6737e34d721b","13c7832f048b08604b7e88b69247aecf955bb7b27a0881c2f7f23bb645435479","538743c4a70f32d2f6af137ff44a043c49dc8da6ebe2ad5e7da60cc953630e29","d2104c54b34158356c4c17dd37c7dd29e1c7dc4c77d9077e921f37d0b0f5cb87","8989b83d1d34dc4ef1100cbcc0f983f69d63118aeca3de5947e1c431ccd21ccc","35c935b77ca1da8fbf901931e0d8f25bff1cdedc9cbc01d98180cb496c445c21","3d1ffbc8fc8790ce6eef1e4ce1e79bfd5e9d0bc7d4f7cac0e95c54a7e1141875","128307a9785a229de861f811864e872ccc7b98da7953f6a67168addf64164fae","79d8197c490b07c732957dfc053b0a1bceaeba6cca9d3de6ce784d6b949fca4b","a49b47dfb004f10f3b23bb790de0c74667dfd053f7eda02ac831c351c7875498","5af3737dddb6e952a498672892404be1105ec2751b09467fbb5fd4b95efbd99b","9a1aef5196a946220a7ef874a7bc7424efef78d23ba8ff20df281b36ef62837a","3e587a8ba8dccc8217a1dfe64ca76e132ed54fdcc794765d090e0aa0147aad67","4d6e6619818eca8ab323f7b2199d9f2b324492bbf8e28dd29e3be90eb3530e8e","05d99f695e6424963c16f8a990e2fd0b703a8079baa1445ef2915fe525efc85b","acf2768b45d187b81284aa4f8e716413ce8776a90a72e755403faba08eef7dbe","8acaecb37a96026cb6d1ddb3ca4ddb32722890d18f35bc6e019dc9703dd72529","88d9da0dab92c994d171a7999ca48974be8f99c041622a78d0b1f3ff27588fc1","dc172eb5106eefa395d091bdb0d8b1963a86aae82a6a7192c1910e7f11083ccd","edaf342a2f1528da49e69e479132a88102b8d9866b129bdcf1e59d86cbd6341f","2cb11a971470a03e828df7520b3153e514bfc5065597d0690a0439f7a5e4284a","839f9c729f3bfd673257683bb86879ba1c3f8b41f01c2a6a33295ebf14927ab5","9b37c5e6e6c985efb20425b725034100d4240afe789b2ea7c5760ab6205ab645","4d74b98b593856085848bde7d83f400ad2fe5a2c36ac9dfe863f96ac206ae55d","27656836bf9547d24ed317c044fe1a3feeb58aff8433ba7813d50e8f69088034","e42db4296d48fa63531ac389627d0577a0dd6f6491b47fd7398b17ff6abd2f6c","bddc0d81daa46345e19c159cbc90638380b24e8d6ddd89d1542c6d9e31ebeddc","a204b31c3672914ff68bb20bfdaae933bf7f8f943687c371b0fd32a3482fc5d4","aeed82530b6398bccd5920a2d4c19011102927c19ce0682dc94f70ecd457a4bb","c129f26b2f8b768c7fc6c5edfd7353599d2fa9fbd19c9175192a608d687ca9a4","41507092ec15c44f72df77d95847b87dccff5f9cce4a11ff6a6f0270f3df3e74","ef048a1d0f1a5f33453b2481987a0f5011e158b757fe4f4def16a2a31efd4623","0534a685ecb1022ec62f19fe7252137f652dde0d86404723e021ed714d44c442","0be9967f0df1fd5673b743b218dde9378b8d0aa0e4a8f364f567b0bd3f004d27","867d4bc564691a35170c6620b658d0f745229a3cc30016e08520181bb1a7f1d3","429c0ccb47f85fab9f0096859a31f2bc20e2b8a814022cd71f6e5cc88ee550f1","060abd605f5f3a963d04ce8a5242f751294d4ad135ad349751089e7c29aec0d0","6c83ec67f9e4afb6ca82b7be9548cc004e8d9ef6ac6aa29b2a6846cb9e5adb5d","23782509c8247596fc3cd2080fc4491e548e1b4587939b68eb4e390eca48b971","f50fa063598d47694feba8f4d91f9fcac813b2c6fdaa5981c6ff466952faaf48","69977ff2a9fb72635702a1d7bf86fab73cf5184d45921f27affac20bb0c3ceae","5a4381be6da0f0383519663bb25660e094c9fc7cb658bf60a2cc221ffa8c7cda","b193ed7441b78595000bcd07c92bfa1b36493910579f1c33daafe42a90600537","e0196a20e6956f17ecf8f04188d34e4b3102e2b6f068b68fdfcecdefaa506e7a","e3d78def8d4e6bb8397b25068fdae6eac9d181a75c78dcf20227a251ee00bce3","0d70c986f1a71c38bf3c3c6b54425c4ba624642231ea8471a21adcd69ecbdd4d","13508efda3383aae203a1a8b5b90b79f99fea1920b65db9ff4a39538934b6c10","3a46c481fc512cce568b39ab364bb02ec588fc276240caf34e015444a5fd26d2","9098640c076d1bdbe6daf7b48d08bb2200ac28cce6db7d08118ae676a99406c9","b64113de8d7989a04f8f94e2c125ac426b9a5797fc2245bf70b96e25c1a06d76","7916e7c886d2088f3a9cad90c7967426d23a92930baf4f9e3b027cb904bc5c09","833a669fdba855086b045a3021b9b51040bd46c565a44f5cae5393cf1e8093b8","c6e2264465eb2e8cb2e12b67adc878e3a397efd6328e550b0a1a5bffabcad66d","048f40812b2a786d92fc8db2f174d35fa64581859cef090087a0f392d4010a3d","b130b6175f23bb5d9e5006ea959b78db664fe4f01abb377258e789c49c4c7cfd","2163bfddb0e1569e330731191e593feb3582cd0d27518993b6970aa8d62016ed","d302ecc0b3d2c60e6408fd2469e726967c7114d5f89b97d82f316feb8557c69d","4782235ebc38ab1dada9c9bb80ee43982f076c6d420bb0772c40fe615901889c","8f3a97edf479a690f731502f11179ec8264e11876a2b5b960a8ed64201392d86","fe9b9da3ace303035d4492d77bfed0260b3d50a04e0fbb128f6c47dcc97e8618","26062553cec8ef883a3617e98d29b395419287e48f4102105a2ee80c1997bac1","13972f1ccb5602c28eba0b02e7f6012f9eaaa0a1d56fb091996a33d67df5b3f0","f2b32e966e35467d563af676842b4e0718f1cd634f2dfdce3972ae101e5a8564",{"version":"00ef4a4324556eab6e45809e757354899d1ded0f5b2134465ee10e450f9c8d61","affectsGlobalScope":true},"3594c022901a1c8993b0f78a3f534cfb81e7b619ed215348f7f6882f3db02abc","438284c7c455a29b9c0e2d1e72abc62ee93d9a163029ffe918a34c5db3b92da2","0c75b204aed9cf6ff1c7b4bed87a3ece0d9d6fc857a6350c0c95ed0c38c814e8","187119ff4f9553676a884e296089e131e8cc01691c546273b1d0089c3533ce42","782abf371043fc65a987f835a3acfd80602a30c3e2122f6d5756a86bf6913352","509235563ea2b939e1bbe92aae17e71e6a82ceab8f568b45fb4fce7d72523a32","9364c7566b0be2f7b70ff5285eb34686f83ccb01bda529b82d23b2a844653bfb","00baffbe8a2f2e4875367479489b5d43b5fc1429ecb4a4cc98cfc3009095f52a","82251920b05f30981c9a4109cb5f3169dce4b477effc845c6d781044a30e7672","3c92b6dfd43cc1c2485d9eba5ff0b74a19bb8725b692773ef1d66dac48cda4bd","4908e4c00832b26ce77a629de8501b0e23a903c094f9e79a7fec313a15da796a","2630a7cbb597e85d713b7ef47f2946d4280d3d4c02733282770741d40672b1a5",{"version":"0714e2046df66c0e93c3330d30dbc0565b3e8cd3ee302cf99e4ede6220e5fec8","affectsGlobalScope":true},"2c705ed6e0913da9d7f85665a5f402043def9de30a1595a5cd78cba2ad0f1113","fabb523b10d744cda3bf3aa5c444f23b0f84e90dffbff977852b1e0273c64d02","40a7ce0f1cb1da0cd28d6ca0e783fb3287a9909d3b4894a08d9506fcb20a15ae","5eba907c51c97728375acf5ac1054b81cee0598fc74fbb88d291d6007f248228","fabb523b10d744cda3bf3aa5c444f23b0f84e90dffbff977852b1e0273c64d02","3de199e46f47f48db134861f1d401f981e496c335b57f7c914c30c66d4895b54","0d2611db111f977f787c32eff054c92cb3ffa80b28570ffd64a8c9fd2ea0f07f","e91767998eed935c26743aa0d1cf4218202e05ab256f29ff30b9f084e12524f0","b0f71456def0fbe76cf1232bbeaa7c794dfc1866e572b6e0d30782ef1ac66fda","3e63da3b89f0d4bc5590b10fdaa2e05a50ce54494b152e2db2fdd99ae2c2d75a","564bc1cd1794d1ac395f4a608c33ec7ac9ec4434aa6c6306be64af0222e0deb4","aaca5c9dd91047a4fb74a022bdb37979f22795767b062ba984a7cf4d76e93155","2d4dc509e1b6cf9d241e8d0479e2ed91b69d67287e670a3f326dd58a3514d362","305ad3b5e4854a5576f47b0268f44c586804a80d763df3891914f49e9e3ac233","56e9508f9d3e8c96d3a3f1658371293e8bc04f814da40ab3fde1b41edce4c5dd","5a322435cefe415e1a9d2c73c27e191b4114aefed2b1a49ef1e175708461d2d3","e149341309d7f08a73ade2b661a2f127ba560b7ea1780e85acfe3cdcb3d92be0","4f873a462f3653de5ac9ac1dc5a8e3c124efb25990972db81b8abee3ebae3f0a","3fa688d7d75a12a6ba2c9b4720c42a8bae33d54f11dc3f6b700debe93bc70e6e","87dd41b85c6a3d3325a8b3ab428c9c1f76bc6d1b651c879fa97d59223451cdcd","481cfd5d6497706efc11bdebbdbace30075d5f898cdd41f8970f061cfe40a967","dcae2d4b58c4562a410821b554321861fb22a8d4c82348b0d733e23d2a908810","e0081090f7862a7c3017f72d44ee8e2a28573b65c9f739006867e69b8ecef980","ab168fc1219e2fbd709090fd102b12610e1c1a7e0615097f5d9ff19ca442fa12","9821433ffadcd2a35d5eecbb6b17a55629ef7237c3473fe2e73ee4923f8c64ec","bbd6304770e40338e35fda415a20b9dba0e38f7e1ba0b6ce26f42333e031e704",{"version":"8e21d8ac0b66ff00edcdb504c6b6cb8ff639d30397e4715b362bedc3fb461929","affectsGlobalScope":true},"207be99e8d7364b5c6893fd4454ab323da7ec9bfc6e75ad02faedf1b7037f302","0b5c66f11b459e6a588221ad4974b7a7dcc1ee606a3de28516b9bfd57a5a4d73","bfe6237b2761c335b61c7fe90fa3e451e582d5ff1109b9225f1e188dd59efd57","a494399a814393efdcd4066904822d0292e7b999bca3fc91478b0f4bad64967b","74e89ad35934a9146c55e67657e23447a56f06ee0273eb44ddf0d248e9d67fcd","3077b10aeb84262b97adbd643e603ee5db682f2fdb8ea7b61fbc44bf3513462c","397996b87ee1d1979b610ebff6140f7e3da356cac2b9952f87fe727544e082b2","aeb488363e8b97b53d6e49ed8eda6341c3100ee105d9077dbbcb0f732d85b68d","8466de725b1f3d3d9278d2fea988a12d0e19eff461480dccf9015f28632b47f2","90a414f883d4e44a6377d17fc5ac6ab0dd9089e908f5e5899714a8b7f8c5c291","936870224b252829383da1a8755e96be444cb4ac0d78ad65c6a8914b9e87ea1c","47841d2d805c79f1d772b80df95a889ea62b2b087c85d8f52453868c841532c9","1c95a3d48e38c6d76aabbf09e8c4ceca68fa66c5bf0fe04331b9aa9b4e097536","1559213b0b2cfd61509959db04cfedcf2a9418da168929a9eab4235670daa6a8","16da0a980e712de89b248575f2286ab3ba7fccc6ef29d31609d5ff650f8713d8","41d1568805d6cd94babdb6e67c1c527bb1dd7c3ac81ca50cf1dae1de978d6448","95c22bc19835e28e2e524a4bb8898eb5f2107b640d7279a6d3aade261916bbf2",{"version":"2f0956558720364251ecdd68d292d9fc9721b9e3a64d5702ec4c176803188e98","signature":"f451f5017fa682e9bed4060fb089237f617267ee46eb84fb25ca7cb181caff37"},{"version":"8266f1b0b010c777aca4a2e34f3f3097e2d3d47447b8743d397c6ef02a71e602","signature":"765f88b98eedda0cc935e1b5efdb420dd0a46efd9e037025cae699e6d59d6bed"},{"version":"693a78d1f70c0ad5b81da32e67e434630714f046e3bd442246c5d53dd500714f","signature":"778fca88a531fe304adca3712b75b721e5139086ee05d6caca5052f49085bdf2"},{"version":"a42c9e61e247431e85f3bcc027e68ee26237c7cb5c394a7aa000409fc45b7c7f","signature":"864f586de8cf2021b6ff4355a6d3362ecc03d409c208d3b235710cf226cba5ed"},{"version":"744ff34993e3210de11dc1b9dd9dc6337f286413367c788f7230a118f10b7045","signature":"ba7c7989c8aea3744b4efca86611a0805f745a96d5b02cfb7c59ccefc64f7bab"},"a5f9563c1315cffbc1e73072d96dcd42332f4eebbdffd7c3e904f545c9e9fe24",{"version":"32dba52f9574a9a4e87cae53be3547c0c01c0de98172f411b70b92a9d805a3b4","signature":"d35bad98de4bf4a59e201e6577b3f3caf808dcc3090f3b527c4e840a9c16b206"},{"version":"9a99b34a3c530c65ab99f9ba85b8e26eadccf97587f528e5201a221c5886c2f5","signature":"dbf602a3ab0bb6de315614309f5811a630ebbd10a2061299b3c846a9638cf1b9"},{"version":"9eb36bdc7295a875a5d3a12f86da764c6f75cd966a09ba714fcba9ade0fc54a2","signature":"0a994627b96aed7ba5111e01eace05e2e3d450b7807e9cf0dbdfd21f2208bddb"},{"version":"60add7f25bcf46e40d6897ddecb8aa4d3e4637f0cc00a6db2dc8b73f2262fce3","signature":"136df7ffb22ac8868a2f30a5d31c787883cfb9ebc626e4d2ea8bf98067eca37b"},{"version":"e418289909c69135b8da9687c7ae1d78ee95a9d2a913e25f90bca26d4477fb56","signature":"ad1baa1accca40edc2915377da4f22a22a4f25a4cf80a51a6e2c01916ad8a7ae"},{"version":"06f9a90d7dcdd4a186d11f0964ee53dc906cfcaff2f28e70499e2488c2d42fda","signature":"76f9de6e7c7f7db22c9cd087501fdbea03dfcb4b24180ccbb2ceabb969ce693c"},{"version":"9f530bd2da8bf176caafd43553acb04e5bbab03ec306a30fd0ba711b7c4bbe47","signature":"d61077e190bcf28e60e4dd16fbaa49ba0ee424a8d4079c9d0a97ff3f969c48db"},{"version":"deb32f4fee901e4307b496f0ab4005aa0112a15324f1fa66236935f4bb111a8a","signature":"8ea356568b036bea0b98c4282115555d781f9bf788dbb2d18397b4a1c369d435"},{"version":"be3b1569f6af2b5b55f61439d74efb1a28292f9c656ee717ac056037156ad6db","signature":"d7627c79d7c45864ffee11b9c307cab882a2d1214758401aa79882173f76a5e5"},"228d809f68d24e9b4b8b9436cb099038377923440acfa0a6e690b1241a3ab459","5ded28b9991c58604f94ba16e4298109cd961652d6ebef26cfe52a2308bab301","4ad2d657cb003038ad7a04e13cd166edef222b69c131957b0c18d24baca50d8e","45bfc379bc2531513f562592adb8f156411433d43163d31729048333f2a8cbac","ba32c620247e2a979def46398de1f325ade95f220caf09f2d0603b042b063588",{"version":"6df9df7b714c2ece84cd992f543f68c0d9e82b0c715f71a5195bc4a40b7f87ea","affectsGlobalScope":true},"359882c1f85356a70ded2918ab435f694e3457ebd068a54881f2d851cc95c58a","b8ae93362f3a394702e32a709bd5b5fd5f0b41f70a7c69c6aebee3ab9b372fce","fd12aa9f1885ab224a4aab7a606fa97e64cc001a43c0d9ba9cf61ce17af66d3b","a6d2eb77f390448a229ca63b4adadbcc549d203b8c038f1f7627a118f732969d","04232a3b351dc1cdd59fe7778e0f1524071cfbc25ee8c3a225fa5388a3f89737","862a9781c3759d0300abf33695ffb750d806e61b7cd9b6511dc03cf53dfe75bc","de414dc1e6b864dc413b0121c7516b5a863bbde720c23ee0560ac5748c9901e3","f13defcd8560dfa204e972a738ff1023b7ee53cc3feb915eb79e21b180801633","7d5e1a0a8229bff4e09ada4d800cc5ff52524ded0a80dcd8c355388bfa669f72","28b7e6541ccdfd120ccefb0f9f9ba5b4fed0ac2914f2e878746e31a4bad66411",{"version":"4cf68f67ed6899971ccb2be9984871b543eb57f571e14863828f7c4760c8b9cc","affectsGlobalScope":true},"7aa482eda885b9099d25c0cf8ad60269b01309e90527d4f77d6f6bc9b34f391b","1961799347940d9463635a412357399b08356d3ee70582dbd339cbe4783d3796","520dfb6751a459a4beac053823e35b3af0c27cae6af3f3eb92bf840647783279","800d3f53606e17fadc5a46878df1578547511a9d5d7bcfee473b7be4df70ca82","8bc5e5b41315e10f31d64ae3ad1258001c814f8e8f8d1dc91dc1f5a0ed139af8","991648d32f98e718a4dfe458269f6128105b8569d81244deacf0dd56a53e6145","89ccbe04e737ce613f5f04990271cfa84901446350b8551b0555ddf19319723b",{"version":"ab8d3b59008c23e35c1c0fbf0b63beb6f037491c4444590cd5487c6ab602ee81","affectsGlobalScope":true},"3a1e165b22a1cb8df82c44c9a09502fd2b33f160cd277de2cd3a055d8e5c6b27","96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","1320ee42b30487cceb6da9f230354fc34826111f76bf12f0ad76c717c12625b0","9a6d65d77455efaaaeff945bea30c38b8fe0922b807ba45cd23792392f1bfe76","a7e32dcb90bf0c1b7a1e4ac89b0f7747cbcba25e7beddc1ebf17be1e161842ad",{"version":"ecf78e637f710f340ec08d5d92b3f31b134a46a4fcf2e758690d8c46ce62cba6","affectsGlobalScope":true},"0a6f28e1d77b99b0ef7da2f0bf50f301ea8a7eb7b4f573e458e725452a477bd2","f5a8b384f182b3851cec3596ccc96cb7464f8d3469f48c74bf2befb782a19de5",{"version":"ca1f4045ec1a501a114d63e2f3f24e2dba00c0cb9030b3109f579d54c1e95d63","affectsGlobalScope":true},"b4dfafe583b829a382edccbe32303535d0785f0c02ba7f04418e2a81de97af8a",{"version":"7f70a9bac13a5ceadb6feacef228ea9461f195ce7263b0fe1f2b96da19715d8d","affectsGlobalScope":true},"8a19491eba2108d5c333c249699f40aff05ad312c04a17504573b27d91f0aede","3169db033165677f1d414baf0c82ba27801089ca1b66d97af464512a47df31b5"],"options":{"declaration":true,"emitDeclarationOnly":false,"emitDecoratorMetadata":true,"esModuleInterop":true,"experimentalDecorators":true,"importHelpers":true,"inlineSourceMap":false,"inlineSources":true,"jsx":2,"module":99,"noEmitHelpers":true,"noEmitOnError":false,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitReturns":true,"noImplicitThis":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./","removeComments":true,"skipLibCheck":true,"sourceMap":true,"strict":true,"strictNullChecks":true,"target":5},"fileIdsList":[[29,143,199,201,204],[29,143,206],[29,143,207],[29,143,157,199,200],[29,143,199,214],[29,143,199,201,203],[29,143,199,203,204],[29,143,157,199,205,208,209,210,211,212,213],[29,143,199,201,206],[29,143],[107,143,167,173],[158,198],[197],[143,162,190],[143,162],[143,193],[143,162,193],[143,162,194],[143,162,195],[168,190,192,197],[143,162,165,166,170,191,192,195,196],[163,232],[143,163],[143,162,163,164],[143],[143,162,168,169],[232],[162,232,235],[162,196],[159,160,161],[29,143,199,203],[29],[29,143,199,202],[86],[85],[90],[88,143],[45,89,143],[88,89],[99],[99,143],[45,92,93,94,95,96,97,98,99,143],[81,82,83,84,87,91,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142],[107,143,167,216],[143,173],[34,143],[143,167,173,216],[107,143,173,216],[167],[183],[144,146,147,148,149,150,151,152,153,154,155,156],[144,145,147,148,149,150,151,152,153,154,155,156],[145,146,147,148,149,150,151,152,153,154,155,156],[144,145,146,148,149,150,151,152,153,154,155,156],[144,145,146,147,149,150,151,152,153,154,155,156],[144,145,146,147,148,150,151,152,153,154,155,156],[144,145,146,147,148,149,151,152,153,154,155,156],[144,145,146,147,148,149,150,152,153,154,155,156],[144,145,146,147,148,149,150,151,153,154,155,156],[144,145,146,147,148,149,150,151,152,154,155,156],[144,145,146,147,148,149,150,151,152,153,155,156],[144,145,146,147,148,149,150,151,152,153,154,156],[156],[144,145,146,147,148,149,150,151,152,153,154,155],[243],[79],[78,79],[33,38],[44,45,52,61],[34,44,52],[70],[38,45,53],[61,66],[41,44,52],[42],[41],[44],[44,46,61,69],[44,45],[52,61,69],[44,45,47,52,61,66,69],[47,66,69],[80],[69],[41,44,61],[54],[32],[68],[59,70,73],[44,62],[61],[64],[38,52],[30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77],[52],[58],[71],[33,38,44,46,55,61,69,73],[249],[245,246,247,248],[81],[171],[143,174],[143,186],[143,171],[171,172,175,176,177,178,179,180,181,182,185,186,187,188,189],[184],[143,171,186],[220,221,222,223,224,225,226,231],[222],[220],[227,228,229,230],[143,199,204],[143,207],[143,199],[199,204],[199]],"referencedMap":[[205,1],[207,2],[208,3],[201,4],[215,5],[204,6],[210,7],[212,6],[214,8],[211,9],[213,10],[216,11],[199,12],[198,13],[191,14],[166,15],[219,16],[194,17],[195,18],[217,19],[218,20],[192,15],[197,21],[233,22],[163,15],[164,23],[165,24],[169,25],[170,26],[235,25],[236,27],[193,15],[237,28],[238,29],[196,15],[159,25],[162,30],[160,25],[161,25],[158,25],[209,31],[202,32],[203,33],[87,34],[86,35],[85,25],[91,36],[89,37],[88,38],[90,39],[100,40],[93,41],[92,41],[94,40],[96,41],[95,41],[98,40],[99,42],[143,43],[173,44],[174,45],[82,25],[101,25],[102,46],[105,25],[107,47],[106,25],[108,25],[109,25],[110,25],[111,25],[112,25],[114,25],[115,25],[116,25],[117,25],[118,25],[119,25],[120,25],[122,25],[121,25],[123,25],[125,25],[124,25],[126,25],[127,25],[128,25],[129,25],[131,25],[132,25],[133,25],[135,25],[83,25],[136,25],[134,25],[137,25],[139,25],[140,25],[142,25],[141,25],[167,48],[168,49],[184,50],[145,51],[146,52],[144,53],[147,54],[148,55],[149,56],[150,57],[151,58],[152,59],[153,60],[154,61],[155,62],[206,63],[156,64],[157,63],[244,65],[30,66],[80,67],[33,68],[34,69],[35,70],[36,71],[37,72],[38,73],[39,74],[41,75],[42,76],[43,77],[44,77],[45,78],[46,79],[47,80],[48,81],[49,82],[81,83],[50,77],[51,84],[52,85],[54,86],[55,87],[56,88],[59,77],[60,89],[61,90],[62,91],[64,77],[65,92],[66,93],[78,94],[68,95],[69,96],[70,97],[72,91],[74,98],[75,91],[250,99],[249,100],[252,101],[172,102],[175,103],[187,104],[176,25],[177,25],[178,105],[179,105],[180,25],[190,106],[185,107],[181,25],[188,108],[182,25],[186,25],[232,109],[223,110],[221,111],[224,110],[227,111],[228,111],[231,112],[229,111]],"exportedModulesMap":[[205,113],[207,25],[208,114],[201,115],[215,113],[204,115],[210,113],[212,115],[214,116],[211,115],[213,25],[216,11],[199,12],[198,13],[191,14],[166,15],[219,16],[194,17],[195,18],[217,19],[218,20],[192,15],[197,21],[233,22],[163,15],[164,23],[165,24],[169,25],[170,26],[235,25],[236,27],[193,15],[237,28],[238,29],[196,15],[159,25],[162,30],[160,25],[161,25],[158,25],[209,117],[203,117],[87,34],[86,35],[85,25],[91,36],[89,37],[88,38],[90,39],[100,40],[93,41],[92,41],[94,40],[96,41],[95,41],[98,40],[99,42],[143,43],[173,44],[174,45],[82,25],[101,25],[102,46],[105,25],[107,47],[106,25],[108,25],[109,25],[110,25],[111,25],[112,25],[114,25],[115,25],[116,25],[117,25],[118,25],[119,25],[120,25],[122,25],[121,25],[123,25],[125,25],[124,25],[126,25],[127,25],[128,25],[129,25],[131,25],[132,25],[133,25],[135,25],[83,25],[136,25],[134,25],[137,25],[139,25],[140,25],[142,25],[141,25],[167,48],[168,49],[184,50],[145,51],[146,52],[144,53],[147,54],[148,55],[149,56],[150,57],[151,58],[152,59],[153,60],[154,61],[155,62],[206,63],[156,64],[157,63],[244,65],[30,66],[80,67],[33,68],[34,69],[35,70],[36,71],[37,72],[38,73],[39,74],[41,75],[42,76],[43,77],[44,77],[45,78],[46,79],[47,80],[48,81],[49,82],[81,83],[50,77],[51,84],[52,85],[54,86],[55,87],[56,88],[59,77],[60,89],[61,90],[62,91],[64,77],[65,92],[66,93],[78,94],[68,95],[69,96],[70,97],[72,91],[74,98],[75,91],[250,99],[249,100],[252,101],[172,102],[175,103],[187,104],[176,25],[177,25],[178,105],[179,105],[180,25],[190,106],[185,107],[181,25],[188,108],[182,25],[186,25],[232,109],[223,110],[221,111],[224,110],[227,111],[228,111],[231,112],[229,111]],"semanticDiagnosticsPerFile":[205,207,208,201,215,204,210,212,214,211,213,216,199,198,191,166,219,194,195,217,218,192,197,233,163,164,165,169,234,170,235,236,193,237,238,196,159,162,160,161,158,209,202,203,6,8,7,2,9,10,11,12,13,14,15,16,3,4,20,17,18,19,21,22,23,5,24,25,26,27,1,28,84,87,86,85,91,89,88,90,100,93,92,94,96,95,97,98,99,143,173,174,82,101,102,103,104,105,107,106,108,109,110,111,112,113,114,115,116,117,118,119,120,122,121,123,125,124,126,127,128,129,130,131,132,133,135,83,136,134,137,139,138,140,142,141,167,168,184,239,240,241,242,145,146,144,147,148,149,150,151,152,153,154,155,206,156,157,244,200,79,30,32,80,33,34,35,36,37,38,39,40,41,42,43,44,45,46,31,76,47,48,49,81,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,78,68,69,70,71,72,73,77,74,75,245,250,246,249,251,252,253,248,183,243,172,175,187,176,189,177,178,179,180,190,185,181,188,182,186,171,247,232,220,226,223,225,221,222,224,227,228,230,231,229,29]},"version":"4.3.4"} -------------------------------------------------------------------------------- /dist/types/.eslintignore: -------------------------------------------------------------------------------- 1 | ./linter-ui-default/ 2 | -------------------------------------------------------------------------------- /dist/types/atom.d.ts: -------------------------------------------------------------------------------- 1 | import { TextEditor } from 'atom' 2 | 3 | // Missing Atom API 4 | declare module 'atom' { 5 | interface CompositeDisposable { 6 | disposed: boolean 7 | } 8 | interface Pane { 9 | getPendingItem(): TextEditor 10 | } 11 | interface Notification { 12 | getOptions(): { detail: string } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dist/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './linter' 2 | export * from './linter-ui-default' 3 | -------------------------------------------------------------------------------- /dist/types/linter-ui-default.d.ts: -------------------------------------------------------------------------------- 1 | export { default as UI } from './linter-ui-default/main' 2 | -------------------------------------------------------------------------------- /dist/types/linter.d.ts: -------------------------------------------------------------------------------- 1 | import { Range, Point, RangeCompatible, PointCompatible, TextEditor } from 'atom' 2 | 3 | export type MessageSolution = 4 | | { 5 | title?: string 6 | position: Range 7 | priority?: number 8 | currentText?: string 9 | replaceWith: string 10 | } 11 | | { 12 | title?: string 13 | position: Range 14 | priority?: number 15 | apply: () => any 16 | } 17 | 18 | export type Message = { 19 | // Automatically added by linter 20 | key: string 21 | version: 2 22 | linterName: string 23 | 24 | // From providers 25 | location: { 26 | file: string 27 | position: Range 28 | } 29 | reference?: { 30 | file: string 31 | position?: Point 32 | } 33 | url?: string 34 | icon?: string 35 | excerpt: string 36 | severity: 'error' | 'warning' | 'info' 37 | solutions?: Array | (() => Promise>) 38 | description?: string | (() => Promise | string) 39 | } 40 | 41 | /** Alias for {Message} */ 42 | export type LinterMessage = Message 43 | 44 | /** 45 | * @deprecated Wrong but convertible message format which might some providers use by mistake. This is converted to 46 | * MessageSolution by Linter using `normalizeMessages` 47 | */ 48 | export type MessageSolutionLike = Omit & { 49 | position: RangeCompatible 50 | } 51 | 52 | /** 53 | * @deprecated Wrong but convertible message format which some providers might use. This is converted to MessageSolution by 54 | * Linter using `normalizeMessages` 55 | */ 56 | export type MessageLike = Omit & { 57 | location: { 58 | file: string 59 | position: RangeCompatible 60 | } 61 | reference?: { 62 | file: string 63 | position?: PointCompatible 64 | } 65 | solutions?: Array | (() => Promise>) 66 | } 67 | 68 | export type LinterResult = Array | null | undefined 69 | export type Linter = { 70 | // Automatically added 71 | __$sb_linter_version: number 72 | __$sb_linter_activated: boolean 73 | __$sb_linter_request_latest: number 74 | __$sb_linter_request_last_received: number 75 | 76 | // From providers 77 | name: string 78 | scope: 'file' | 'project' 79 | lintOnFly?: boolean // <-- legacy 80 | lintsOnChange?: boolean 81 | grammarScopes: Array 82 | lint(textEditor: TextEditor): LinterResult | Promise 83 | } 84 | 85 | export type Indie = { 86 | name: string 87 | } 88 | 89 | export type MessagesPatch = { 90 | added: Array 91 | removed: Array 92 | messages: Array 93 | } 94 | -------------------------------------------------------------------------------- /dist/ui-registry.d.ts: -------------------------------------------------------------------------------- 1 | import type { Linter, UI, MessagesPatch } from './types'; 2 | export default class UIRegistry { 3 | private providers; 4 | private subscriptions; 5 | add(ui: UI): void; 6 | delete(provider: UI): void; 7 | getProviders(): Array; 8 | render(messages: MessagesPatch): void; 9 | didBeginLinting(linter: Linter, filePath: string): void; 10 | didFinishLinting(linter: Linter, filePath: string): void; 11 | dispose(): void; 12 | } 13 | -------------------------------------------------------------------------------- /dist/validate/helpers.d.ts: -------------------------------------------------------------------------------- 1 | export declare function showError(title: string, description: string, points: Array): void; 2 | -------------------------------------------------------------------------------- /dist/validate/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { UI, Linter, Message, Indie } from '../types'; 2 | declare function validateUI(ui: UI): boolean; 3 | declare function validateLinter(linter: Linter): boolean; 4 | declare function validateIndie(indie: Indie): boolean; 5 | declare function validateMessages(linterName: string, entries: Array): boolean; 6 | export { validateUI as ui, validateLinter as linter, validateIndie as indie, validateMessages as messages }; 7 | -------------------------------------------------------------------------------- /lib/commands.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable, Emitter } from 'atom' 2 | import type { Disposable } from 'atom' 3 | 4 | import * as Helpers from './helpers' 5 | import type { Linter, UI } from './types' 6 | import type IndieDelegate from './indie-delegate' 7 | 8 | let manifest: { version: number } 9 | 10 | function formatItem(item: { name: string } | string) { 11 | let itemName: string 12 | if (item && typeof item === 'object' && typeof item.name === 'string') { 13 | itemName = item.name 14 | } else if (typeof item === 'string') { 15 | itemName = item 16 | } else { 17 | throw new Error('Unknown object passed to formatItem()') 18 | } 19 | return ` - ${itemName}` 20 | } 21 | function sortByName(item1: { name: string }, item2: { name: string }) { 22 | return item1.name.localeCompare(item2.name) 23 | } 24 | 25 | export class Commands { 26 | private emitter: Emitter = new Emitter() 27 | private subscriptions: CompositeDisposable = new CompositeDisposable() 28 | 29 | constructor() { 30 | this.subscriptions.add( 31 | this.emitter, 32 | atom.commands.add('atom-workspace', { 33 | 'linter:enable-linter': () => this.enableLinter(), 34 | 'linter:disable-linter': () => this.disableLinter(), 35 | }), 36 | atom.commands.add('atom-text-editor:not([mini])', { 37 | 'linter:lint': () => this.lint(), 38 | 'linter:debug': () => this.debug(), 39 | 'linter:toggle-active-editor': () => this.toggleActiveEditor(), 40 | }), 41 | ) 42 | } 43 | lint() { 44 | this.emitter.emit('should-lint') 45 | } 46 | debug() { 47 | this.emitter.emit('should-debug') 48 | } 49 | enableLinter() { 50 | this.emitter.emit('should-toggle-linter', 'enable') 51 | } 52 | disableLinter() { 53 | this.emitter.emit('should-toggle-linter', 'disable') 54 | } 55 | toggleActiveEditor() { 56 | this.emitter.emit('should-toggle-active-editor') 57 | } 58 | 59 | /* eslint-disable @typescript-eslint/no-explicit-any */ 60 | onShouldLint(callback: (...args: Array) => any): Disposable { 61 | return this.emitter.on('should-lint', callback) 62 | } 63 | onShouldDebug(callback: (...args: Array) => any): Disposable { 64 | return this.emitter.on('should-debug', callback) 65 | } 66 | onShouldToggleActiveEditor(callback: (...args: Array) => any): Disposable { 67 | return this.emitter.on('should-toggle-active-editor', callback) 68 | } 69 | onShouldToggleLinter(callback: (...args: Array) => any): Disposable { 70 | return this.emitter.on('should-toggle-linter', callback) 71 | } 72 | /* eslint-disable @typescript-eslint/no-explicit-any */ 73 | 74 | dispose() { 75 | this.subscriptions.dispose() 76 | } 77 | } 78 | 79 | export async function showDebug(standardLinters: Array, indieLinters: Array, uiProviders: Array) { 80 | if (!manifest) { 81 | manifest = require('../package.json') 82 | } 83 | 84 | const textEditor = atom.workspace.getActiveTextEditor() 85 | if (textEditor === undefined) { 86 | return 87 | } 88 | const textEditorScopes = Helpers.getEditorCursorScopes(textEditor) 89 | const sortedLinters = standardLinters.slice().sort(sortByName) 90 | const sortedIndieLinters = indieLinters.slice().sort(sortByName) 91 | const sortedUIProviders = uiProviders.slice().sort(sortByName) 92 | 93 | const indieLinterNames = sortedIndieLinters.map(formatItem).join('\n') 94 | const standardLinterNames = sortedLinters.map(formatItem).join('\n') 95 | const matchingStandardLinters = sortedLinters 96 | .filter(linter => Helpers.shouldTriggerLinter(linter, false, textEditorScopes)) 97 | .map(formatItem) 98 | .join('\n') 99 | const humanizedScopes = textEditorScopes.map(formatItem).join('\n') 100 | const uiProviderNames = sortedUIProviders.map(formatItem).join('\n') 101 | 102 | const ignoreGlob = atom.config.get('linter.ignoreGlob') 103 | const ignoreVCSIgnoredPaths = atom.config.get('core.excludeVcsIgnoredPaths') 104 | const disabledLinters = atom.config.get('linter.disabledProviders').map(formatItem).join('\n') 105 | const filePathIgnored = await Helpers.isPathIgnored(textEditor.getPath(), ignoreGlob, ignoreVCSIgnoredPaths) 106 | 107 | atom.notifications.addInfo('Linter Debug Info', { 108 | detail: [ 109 | `Platform: ${process.platform}`, 110 | `Atom Version: ${atom.getVersion()}`, 111 | `Linter Version: ${manifest.version}`, 112 | `Opened file is ignored: ${filePathIgnored ? 'Yes' : 'No'}`, 113 | `Matching Linter Providers: \n${matchingStandardLinters}`, 114 | `Disabled Linter Providers: \n${disabledLinters}`, 115 | `Standard Linter Providers: \n${standardLinterNames}`, 116 | `Indie Linter Providers: \n${indieLinterNames}`, 117 | `UI Providers: \n${uiProviderNames}`, 118 | `Ignore Glob: ${ignoreGlob}`, 119 | `VCS Ignored Paths are excluded: ${ignoreVCSIgnoredPaths}`, 120 | `Current File Scopes: \n${humanizedScopes}`, 121 | ].join('\n'), 122 | dismissable: true, 123 | }) 124 | } 125 | -------------------------------------------------------------------------------- /lib/editor-linter.ts: -------------------------------------------------------------------------------- 1 | import { Emitter, CompositeDisposable, Disposable } from 'atom' 2 | import debounce from 'lodash/debounce' 3 | import type { TextEditor } from 'atom' 4 | 5 | export default class EditorLinter { 6 | private editor: TextEditor 7 | private emitter: Emitter = new Emitter() 8 | private subscriptions: CompositeDisposable = new CompositeDisposable() 9 | 10 | constructor(editor: TextEditor) { 11 | if (!atom.workspace.isTextEditor(editor)) { 12 | throw new Error('EditorLinter expects a valid TextEditor') 13 | } 14 | const editorBuffer = editor.getBuffer() 15 | const debouncedLint = debounce( 16 | () => { 17 | this.emitter.emit('should-lint', false) 18 | }, 19 | 50, 20 | { leading: true }, 21 | ) 22 | 23 | this.editor = editor 24 | 25 | this.subscriptions.add( 26 | this.editor.onDidDestroy(() => this.dispose()), 27 | 28 | // This debouncing is for beautifiers, if they change contents of the editor and save 29 | // Linter should count that group of events as one. 30 | this.editor.onDidSave(debouncedLint), 31 | 32 | // This is to relint in case of external changes to the opened file 33 | editorBuffer.onDidReload(debouncedLint), 34 | 35 | // NOTE: TextEditor::onDidChange immediately invokes the callback if the text editor was *just* created 36 | // Using TextBuffer::onDidChange doesn't have the same behavior so using it instead. 37 | this.subscriptiveObserve(atom.config, 'linter.lintOnChangeInterval', interval => 38 | editorBuffer.onDidChange( 39 | debounce(() => { 40 | this.emitter.emit('should-lint', true) 41 | }, interval), 42 | ), 43 | ), 44 | ) 45 | } 46 | getEditor(): TextEditor { 47 | return this.editor 48 | } 49 | lint(onChange: boolean = false) { 50 | this.emitter.emit('should-lint', onChange) 51 | } 52 | 53 | /* eslint-disable @typescript-eslint/no-explicit-any */ 54 | onShouldLint(callback: (...args: Array) => any): Disposable { 55 | return this.emitter.on('should-lint', callback) 56 | } 57 | onDidDestroy(callback: (...args: Array) => any): Disposable { 58 | return this.emitter.on('did-destroy', callback) 59 | } 60 | /* eslint-disable @typescript-eslint/no-explicit-any */ 61 | 62 | dispose() { 63 | this.emitter.emit('did-destroy') 64 | this.subscriptions.dispose() 65 | this.emitter.dispose() 66 | } 67 | 68 | subscriptiveObserve(object: Record, eventName: string, callback: (...args: Array) => any): Disposable { 69 | let subscription: Disposable | null = null 70 | const eventSubscription = object.observe(eventName, (props: Record) => { 71 | if (subscription) { 72 | subscription.dispose() 73 | } 74 | subscription = callback.call(this, props) 75 | }) 76 | 77 | return new Disposable(function () { 78 | eventSubscription.dispose() 79 | if (subscription) { 80 | subscription.dispose() 81 | } 82 | }) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/editor-registry.ts: -------------------------------------------------------------------------------- 1 | import { Emitter, CompositeDisposable } from 'atom' 2 | import type { Disposable, TextEditor } from 'atom' 3 | import EditorLinter from './editor-linter' 4 | 5 | export default class EditorRegistry { 6 | private emitter: Emitter = new Emitter() 7 | private lintOnOpen: boolean = true 8 | private subscriptions: CompositeDisposable = new CompositeDisposable() 9 | private editorLinters: Map = new Map() 10 | 11 | constructor() { 12 | this.subscriptions.add( 13 | this.emitter, 14 | atom.config.observe('linter.lintOnOpen', lintOnOpen => { 15 | this.lintOnOpen = lintOnOpen 16 | }), 17 | ) 18 | } 19 | activate() { 20 | this.subscriptions.add( 21 | atom.workspace.observeTextEditors(textEditor => { 22 | this.createFromTextEditor(textEditor) 23 | }), 24 | ) 25 | } 26 | get(textEditor: TextEditor): EditorLinter | null | undefined { 27 | return this.editorLinters.get(textEditor) 28 | } 29 | createFromTextEditor(textEditor: TextEditor): EditorLinter { 30 | let editorLinter = this.editorLinters.get(textEditor) 31 | if (editorLinter) { 32 | return editorLinter 33 | } 34 | editorLinter = new EditorLinter(textEditor) 35 | editorLinter.onDidDestroy(() => { 36 | this.editorLinters.delete(textEditor) 37 | }) 38 | this.editorLinters.set(textEditor, editorLinter) 39 | this.emitter.emit('observe', editorLinter) 40 | if (this.lintOnOpen) { 41 | editorLinter.lint() 42 | } 43 | return editorLinter 44 | } 45 | hasSibling(editorLinter: EditorLinter): boolean { 46 | const buffer = editorLinter.getEditor().getBuffer() 47 | 48 | return Array.from(this.editorLinters.keys()).some(item => item.getBuffer() === buffer) 49 | } 50 | observe(callback: (editorLinter: EditorLinter) => void): Disposable { 51 | this.editorLinters.forEach(callback) 52 | return this.emitter.on('observe', callback) 53 | } 54 | dispose() { 55 | for (const entry of this.editorLinters.values()) { 56 | entry.dispose() 57 | } 58 | this.subscriptions.dispose() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/helpers.ts: -------------------------------------------------------------------------------- 1 | import arrayUnique from 'lodash/uniq' 2 | import { Directory, Range, Point, PointCompatible, RangeCompatible } from 'atom' 3 | import type { TextEditor } from 'atom' 4 | import type { Linter, Message, MessageSolution, MessageLike, MessageSolutionLike } from './types' 5 | 6 | export const $version = '__$sb_linter_version' 7 | export const $activated = '__$sb_linter_activated' 8 | export const $requestLatest = '__$sb_linter_request_latest' 9 | export const $requestLastReceived = '__$sb_linter_request_last_received' 10 | 11 | export function shouldTriggerLinter(linter: Linter, wasTriggeredOnChange: boolean, scopes: Array): boolean { 12 | if (wasTriggeredOnChange && !linter.lintsOnChange) { 13 | return false 14 | } 15 | return scopes.some(function (scope) { 16 | return linter.grammarScopes.includes(scope) 17 | }) 18 | } 19 | 20 | export function getEditorCursorScopes(textEditor: TextEditor): Array { 21 | return arrayUnique( 22 | textEditor.getCursors().reduce((scopes, cursor) => scopes.concat(cursor.getScopeDescriptor().getScopesArray()), ['*']), 23 | ) 24 | } 25 | 26 | let minimatch: typeof import('minimatch') 27 | export async function isPathIgnored( 28 | filePath: string | null | undefined, 29 | ignoredGlob: string, 30 | ignoredVCS: boolean, 31 | ): Promise { 32 | if (!filePath) { 33 | return true 34 | } 35 | 36 | if (ignoredVCS) { 37 | const directory = new Directory(filePath) 38 | const repository = await atom.project.repositoryForDirectory(directory) 39 | if (repository && repository.isPathIgnored(filePath)) { 40 | return true 41 | } 42 | } 43 | const normalizedFilePath = process.platform === 'win32' ? filePath.replace(/\\/g, '/') : filePath 44 | if (!minimatch) { 45 | minimatch = require('minimatch') 46 | } 47 | return minimatch(normalizedFilePath, ignoredGlob) 48 | } 49 | 50 | export function updateMessageKey(message: Message) { 51 | const { reference, location } = message 52 | message.key = [ 53 | `$LINTER:${message.linterName}`, 54 | `$LOCATION:${location.file}$${location.position.start.row}$${location.position.start.column}$${location.position.end.row}$${location.position.end.column}`, 55 | reference 56 | ? `$REFERENCE:${reference.file}$${reference.position ? `${reference.position.row}$${reference.position.column}` : ''}` 57 | : '$REFERENCE:null', 58 | `$EXCERPT:${message.excerpt}`, 59 | `$SEVERITY:${message.severity}`, 60 | message.icon ? `$ICON:${message.icon}` : '$ICON:null', 61 | message.url ? `$URL:${message.url}` : '$URL:null', 62 | typeof message.description === 'string' ? `$DESCRIPTION:${message.description}` : '$DESCRIPTION:null', 63 | ].join('') 64 | } 65 | 66 | export function normalizeMessages(linterName: string, messages: Array) { 67 | for (let i = 0, { length } = messages; i < length; ++i) { 68 | const message = messages[i] 69 | const { reference, solutions } = message 70 | // convert RangeCompatible to Range and PointCompatible to Point 71 | // NOTE (this is not covered in the types, but done for backward compatibility) 72 | message.location.position = getRangeClass(message.location.position) 73 | if (reference !== undefined && reference.position !== undefined) { 74 | reference.position = getPointClass(reference.position) 75 | } 76 | if (Array.isArray(solutions)) { 77 | // NOTE if solutions is a {Promise} of an array, we don't normalize them! 78 | for (let j = 0, _length = solutions.length; j < _length; j++) { 79 | const solution: MessageSolution | MessageSolutionLike = solutions[j] 80 | solution.position = getRangeClass(solution.position) 81 | } 82 | } 83 | message.version = 2 84 | if (!message.linterName) { 85 | message.linterName = linterName 86 | } 87 | // now the message is a {Message} 88 | updateMessageKey(message as Message) 89 | } 90 | } 91 | 92 | /* convert RangeCompatible to Range */ 93 | function getPointClass(point: Point | PointCompatible): Point { 94 | if (!(point instanceof Point)) { 95 | return Point.fromObject(point) 96 | } 97 | return point 98 | } 99 | 100 | /* convert RangeCompatible to Range */ 101 | function getRangeClass(range: Range | RangeCompatible): Range { 102 | if (!(range instanceof Range)) { 103 | return Range.fromObject(range) 104 | } 105 | return range 106 | } 107 | 108 | // update the key of the given messages 109 | export function updateKeys(messages: Array) { 110 | messages.forEach(m => { 111 | updateMessageKey(m) 112 | }) 113 | } 114 | 115 | // create a map from keys to messages 116 | export function createKeyMessageMap(messages: Array): Map { 117 | const keyMessageMap = new Map() 118 | for (let i = 0, { length } = messages; i < length; ++i) { 119 | const message = messages[i] 120 | keyMessageMap.set(message.key, message) 121 | } 122 | return keyMessageMap 123 | } 124 | 125 | interface FlaggedMessages { 126 | oldKept: Array 127 | oldRemoved: Array 128 | newAdded: Array 129 | } 130 | 131 | // This fast function returns the new messages and old messages by comparing their key against the cache. 132 | // This prevents re-rendering the already rendered messages 133 | export function flagMessages(inputs: Array, oldMessages: Array): FlaggedMessages | null { 134 | // inputs check 135 | if (inputs === undefined || oldMessages === undefined) { 136 | return null 137 | } 138 | 139 | // All the messages of the linter are new, no need to diff 140 | // tag the messages for adding and save them to linter's cache 141 | if (!oldMessages.length) { 142 | // NOTE: No need to add .key here because normalizeMessages already does that 143 | return { oldKept: [], oldRemoved: [], newAdded: inputs } 144 | } 145 | 146 | // The linter has no messages anymore 147 | // tag all of its messages from cache for removal and empty the cache 148 | if (!inputs.length) { 149 | return { oldKept: [], oldRemoved: oldMessages, newAdded: [] } 150 | } 151 | 152 | // In all the other situations: 153 | // perform diff checking between the linter's new messages and its cache 154 | 155 | // create a map from keys to oldMessages 156 | const cache = createKeyMessageMap(oldMessages) 157 | 158 | // Find old kept and new added 159 | const newAdded: Set = new Set() 160 | const oldKept: Map = new Map() 161 | for (let iInput = 0, len = inputs.length; iInput < len; iInput++) { 162 | const input = inputs[iInput] 163 | if (cache.has(input.key)) { 164 | oldKept.set(input.key, input) 165 | } else { 166 | newAdded.add(input) 167 | } 168 | } 169 | 170 | // Find old removed 171 | const cacheKeys = Array.from(cache.keys()) 172 | const oldKeptKeys = Array.from(oldKept.keys()) 173 | 174 | const oldRemovedKeys = cacheKeys.filter(x => !oldKeptKeys.includes(x)) 175 | 176 | const oldRemoved: Set = new Set() 177 | for (let iRemoved = 0, RemovedKeysLen = oldRemovedKeys.length; iRemoved < RemovedKeysLen; iRemoved++) { 178 | // cache is created from oldMessages and oldRemovedKeys is a subset of oldMessages. So this will not be undefined 179 | oldRemoved.add(cache.get(oldRemovedKeys[iRemoved]) as Message) 180 | } 181 | 182 | return { 183 | oldKept: Array.from(oldKept.values()), 184 | oldRemoved: [...oldRemoved], 185 | newAdded: [...newAdded], 186 | } 187 | } 188 | 189 | // fast mergeArray function 190 | // https://uilicious.com/blog/javascript-array-push-is-945x-faster-than-array-concat/ 191 | /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ 192 | export function mergeArray(arr1: Array, arr2: Array) { 193 | if (!arr2.length) { 194 | return 195 | } 196 | Array.prototype.push.apply(arr1, arr2) 197 | } 198 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable, Disposable } from 'atom' 2 | 3 | import Linter from './main' 4 | import type { UI, Linter as LinterProvider, Indie } from './types' 5 | 6 | // Internal variables 7 | let instance: Linter 8 | let subscriptions: CompositeDisposable 9 | 10 | export function activate() { 11 | subscriptions = new CompositeDisposable() 12 | 13 | instance = new Linter() 14 | subscriptions.add( 15 | instance, 16 | atom.packages.onDidActivateInitialPackages(function () { 17 | if (!atom.inSpecMode()) { 18 | require('atom-package-deps').install('linter', true) 19 | } 20 | }), 21 | ) 22 | } 23 | export function consumeLinter(linter: LinterProvider | Array): Disposable { 24 | const linters = Array.isArray(linter) ? linter : [linter] 25 | 26 | for (const entry of linters) { 27 | instance.addLinter(entry) 28 | } 29 | return new Disposable(() => { 30 | for (const entry of linters) { 31 | instance.deleteLinter(entry) 32 | } 33 | }) 34 | } 35 | export function consumeUI(ui: UI | Array): Disposable { 36 | const uis = Array.isArray(ui) ? ui : [ui] 37 | 38 | for (const entry of uis) { 39 | instance.addUI(entry) 40 | } 41 | return new Disposable(() => { 42 | for (const entry of uis) { 43 | instance.deleteUI(entry) 44 | } 45 | }) 46 | } 47 | export function provideIndie() { 48 | return (indie: Indie) => instance.addIndie(indie) 49 | } 50 | export function deactivate() { 51 | subscriptions.dispose() 52 | } 53 | -------------------------------------------------------------------------------- /lib/indie-delegate.ts: -------------------------------------------------------------------------------- 1 | import { Emitter, CompositeDisposable } from 'atom' 2 | import type { Disposable } from 'atom' 3 | 4 | import * as Validate from './validate' 5 | import { normalizeMessages, mergeArray } from './helpers' 6 | import type { Indie, Message } from './types' 7 | 8 | export default class IndieDelegate { 9 | private indie: Indie 10 | scope: 'project' = 'project' 11 | private emitter: Emitter = new Emitter() 12 | version: 2 13 | private messages: Map> = new Map() 14 | private subscriptions: CompositeDisposable = new CompositeDisposable() 15 | 16 | constructor(indie: Indie, version: 2) { 17 | this.indie = indie 18 | this.version = version 19 | this.subscriptions.add(this.emitter) 20 | } 21 | get name(): string { 22 | return this.indie.name 23 | } 24 | getMessages(): Array { 25 | const out: Array = [] 26 | this.messages.forEach(m => { 27 | mergeArray(out, m) 28 | }) 29 | return out 30 | } 31 | clearMessages(): void { 32 | if (!this.subscriptions.disposed) { 33 | this.emitter.emit('did-update', []) 34 | this.messages.clear() 35 | } 36 | } 37 | setMessages(filePath: string | Array>, messages: Array | null | undefined = null): void { 38 | // v2 Support from here on 39 | if (typeof filePath !== 'string' || !Array.isArray(messages)) { 40 | throw new Error('Invalid Parameters to setMessages()') 41 | } 42 | if (this.subscriptions.disposed || !Validate.messages(this.name, messages)) { 43 | return 44 | } 45 | messages.forEach(function (message) { 46 | if (message.location.file !== filePath) { 47 | console.debug('[Linter-UI-Default] Expected File', filePath, 'Message', message) 48 | throw new Error('message.location.file does not match the given filePath') 49 | } 50 | }) 51 | 52 | normalizeMessages(this.name, messages) 53 | this.messages.set(filePath, messages) 54 | this.emitter.emit('did-update', this.getMessages()) 55 | } 56 | setAllMessages(messages: Array): void { 57 | if (this.subscriptions.disposed) { 58 | return 59 | } 60 | 61 | if (!Array.isArray(messages) || atom.inDevMode()) { 62 | if (!Validate.messages(this.name, messages)) { 63 | return 64 | } 65 | } 66 | normalizeMessages(this.name, messages) 67 | 68 | this.messages.clear() 69 | for (let i = 0, { length } = messages; i < length; ++i) { 70 | const message: Message = messages[i] 71 | const filePath = message.location.file 72 | let fileMessages = this.messages.get(filePath) 73 | if (!fileMessages) { 74 | this.messages.set(filePath, (fileMessages = [])) 75 | } 76 | fileMessages.push(message) 77 | } 78 | this.emitter.emit('did-update', this.getMessages()) 79 | } 80 | 81 | /* eslint-disable @typescript-eslint/no-explicit-any */ 82 | onDidUpdate(callback: (...args: Array) => any): Disposable { 83 | return this.emitter.on('did-update', callback) 84 | } 85 | onDidDestroy(callback: (...args: Array) => any): Disposable { 86 | return this.emitter.on('did-destroy', callback) 87 | } 88 | /* eslint-enable @typescript-eslint/no-explicit-any */ 89 | 90 | dispose(): void { 91 | this.emitter.emit('did-destroy') 92 | this.subscriptions.dispose() 93 | this.messages.clear() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/indie-registry.ts: -------------------------------------------------------------------------------- 1 | import { Emitter, CompositeDisposable } from 'atom' 2 | import type { Disposable } from 'atom' 3 | 4 | import IndieDelegate from './indie-delegate' 5 | import { indie as validateIndie } from './validate' 6 | import type { Indie } from './types' 7 | 8 | export default class IndieRegistry { 9 | private emitter: Emitter = new Emitter() 10 | private delegates: Set = new Set() 11 | private subscriptions: CompositeDisposable = new CompositeDisposable() 12 | 13 | constructor() { 14 | this.subscriptions.add(this.emitter) 15 | } 16 | // Public method 17 | register(config: Indie, version: 2): IndieDelegate { 18 | if (!validateIndie(config)) { 19 | throw new Error('Error registering Indie Linter') 20 | } 21 | const indieLinter = new IndieDelegate(config, version) 22 | this.delegates.add(indieLinter) 23 | indieLinter.onDidDestroy(() => { 24 | this.delegates.delete(indieLinter) 25 | }) 26 | indieLinter.onDidUpdate(messages => { 27 | this.emitter.emit('did-update', { linter: indieLinter, messages }) 28 | }) 29 | this.emitter.emit('observe', indieLinter) 30 | 31 | return indieLinter 32 | } 33 | getProviders(): Array { 34 | return Array.from(this.delegates) 35 | } 36 | 37 | /* eslint-disable @typescript-eslint/no-explicit-any */ 38 | observe(callback: (...args: Array) => any): Disposable { 39 | this.delegates.forEach(callback) 40 | return this.emitter.on('observe', callback) 41 | } 42 | onDidUpdate(callback: (...args: Array) => any): Disposable { 43 | return this.emitter.on('did-update', callback) 44 | } 45 | /* eslint-enable @typescript-eslint/no-explicit-any */ 46 | 47 | dispose() { 48 | for (const entry of this.delegates) { 49 | entry.dispose() 50 | } 51 | this.subscriptions.dispose() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/linter-registry.ts: -------------------------------------------------------------------------------- 1 | import { Emitter, CompositeDisposable } from 'atom' 2 | import type { TextEditor, Disposable, Notification } from 'atom' 3 | 4 | import * as Helpers from './helpers' 5 | import * as Validate from './validate' 6 | import { $version, $activated, $requestLatest, $requestLastReceived } from './helpers' 7 | import type { Linter } from './types' 8 | 9 | export default class LinterRegistry { 10 | private emitter: Emitter = new Emitter() 11 | private linters: Set = new Set() 12 | private lintOnChange: boolean = true 13 | private ignoreVCS: boolean = true 14 | private ignoreGlob: string = '**/*.min.{js,css}' 15 | private lintPreviewTabs: boolean = true 16 | private subscriptions: CompositeDisposable = new CompositeDisposable() 17 | private disabledProviders: Array = [] 18 | private activeNotifications: Set = new Set() 19 | 20 | constructor() { 21 | this.subscriptions.add( 22 | this.emitter, 23 | atom.config.observe('linter.lintOnChange', lintOnChange => { 24 | this.lintOnChange = lintOnChange 25 | }), 26 | atom.config.observe('core.excludeVcsIgnoredPaths', ignoreVCS => { 27 | this.ignoreVCS = ignoreVCS 28 | }), 29 | atom.config.observe('linter.ignoreGlob', ignoreGlob => { 30 | this.ignoreGlob = ignoreGlob 31 | }), 32 | atom.config.observe('linter.lintPreviewTabs', lintPreviewTabs => { 33 | this.lintPreviewTabs = lintPreviewTabs 34 | }), 35 | atom.config.observe('linter.disabledProviders', disabledProviders => { 36 | if (disabledProviders.length !== 0) { 37 | console.warn(`Linter package: disabled linter providers: ${disabledProviders}`) 38 | } 39 | this.disabledProviders = disabledProviders 40 | }), 41 | ) 42 | } 43 | hasLinter(linter: Linter): boolean { 44 | return this.linters.has(linter) 45 | } 46 | addLinter(linter: Linter) { 47 | if (!Validate.linter(linter)) { 48 | return 49 | } 50 | linter[$activated] = true 51 | if (typeof linter[$requestLatest] === 'undefined') { 52 | linter[$requestLatest] = 0 53 | } 54 | if (typeof linter[$requestLastReceived] === 'undefined') { 55 | linter[$requestLastReceived] = 0 56 | } 57 | linter[$version] = 2 58 | this.linters.add(linter) 59 | } 60 | getProviders(): Array { 61 | return Array.from(this.linters) 62 | } 63 | deleteLinter(linter: Linter) { 64 | if (!this.linters.has(linter)) { 65 | return 66 | } 67 | linter[$activated] = false 68 | this.linters.delete(linter) 69 | } 70 | async lint({ onChange, editor }: { onChange: boolean; editor: TextEditor }): Promise { 71 | const filePath = editor.getPath() 72 | 73 | if ( 74 | (onChange && !this.lintOnChange) || // Lint-on-change mismatch 75 | // Ignored by VCS, Glob, or simply not saved anywhere yet 76 | (!this.lintPreviewTabs && atom.workspace.getActivePane().getPendingItem() === editor) || // Ignore Preview tabs 77 | (await Helpers.isPathIgnored(editor.getPath(), this.ignoreGlob, this.ignoreVCS)) 78 | ) { 79 | return false 80 | } 81 | 82 | const scopes = Helpers.getEditorCursorScopes(editor) 83 | 84 | const promises = [] 85 | for (const linter of this.linters) { 86 | if (!Helpers.shouldTriggerLinter(linter, onChange, scopes)) { 87 | continue 88 | } 89 | if (this.disabledProviders.includes(linter.name)) { 90 | continue 91 | } 92 | const number = ++linter[$requestLatest] 93 | const statusBuffer = linter.scope === 'file' ? editor.getBuffer() : null 94 | const statusFilePath = linter.scope === 'file' ? filePath : null 95 | 96 | this.emitter.emit('did-begin-linting', { number, linter, filePath: statusFilePath }) 97 | promises.push( 98 | new Promise(function (resolve: (editor: ReturnType) => void) { 99 | resolve(linter.lint(editor)) 100 | }).then( 101 | messages => { 102 | this.emitter.emit('did-finish-linting', { number, linter, filePath: statusFilePath }) 103 | if (linter[$requestLastReceived] >= number || !linter[$activated] || (statusBuffer && !statusBuffer.isAlive())) { 104 | return 105 | } 106 | linter[$requestLastReceived] = number 107 | if (statusBuffer && !statusBuffer.isAlive()) { 108 | return 109 | } 110 | 111 | if (messages === null || messages === undefined) { 112 | // NOTE: Do NOT update the messages when providers return null 113 | return 114 | } 115 | 116 | let validity = true 117 | // NOTE: We are calling it when results are not an array to show a nice notification 118 | if (atom.inDevMode() || !Array.isArray(messages)) { 119 | validity = Validate.messages(linter.name, messages) 120 | } 121 | if (!validity) { 122 | return 123 | } 124 | 125 | Helpers.normalizeMessages(linter.name, messages) 126 | this.emitter.emit('did-update-messages', { messages, linter, buffer: statusBuffer }) 127 | }, 128 | error => { 129 | this.emitter.emit('did-finish-linting', { number, linter, filePath: statusFilePath }) 130 | 131 | console.error(`[Linter] Error running ${linter.name}`, error) 132 | const notificationMessage = `[Linter] Error running ${linter.name}` 133 | if (Array.from(this.activeNotifications).some(item => item.getOptions().detail === notificationMessage)) { 134 | // This message is still showing to the user! 135 | return 136 | } 137 | 138 | const notification = atom.notifications.addError(notificationMessage, { 139 | detail: 'See Console for more info.', 140 | dismissable: true, 141 | buttons: [ 142 | { 143 | text: 'Open Console', 144 | onDidClick: () => { 145 | atom.openDevTools() 146 | notification.dismiss() 147 | }, 148 | }, 149 | { 150 | text: 'Cancel', 151 | onDidClick: () => { 152 | notification.dismiss() 153 | }, 154 | }, 155 | ], 156 | }) 157 | }, 158 | ), 159 | ) 160 | } 161 | 162 | await Promise.all(promises) 163 | return true 164 | } 165 | 166 | /* eslint-disable @typescript-eslint/no-explicit-any */ 167 | onDidUpdateMessages(callback: (...args: Array) => any): Disposable { 168 | return this.emitter.on('did-update-messages', callback) 169 | } 170 | onDidBeginLinting(callback: (...args: Array) => any): Disposable { 171 | return this.emitter.on('did-begin-linting', callback) 172 | } 173 | onDidFinishLinting(callback: (...args: Array) => any): Disposable { 174 | return this.emitter.on('did-finish-linting', callback) 175 | } 176 | /* eslint-enable @typescript-eslint/no-explicit-any */ 177 | 178 | dispose() { 179 | this.activeNotifications.forEach(notification => notification.dismiss()) 180 | this.activeNotifications.clear() 181 | this.linters.clear() 182 | this.subscriptions.dispose() 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /lib/main.ts: -------------------------------------------------------------------------------- 1 | import arrayUnique from 'lodash/uniq' 2 | import { CompositeDisposable } from 'atom' 3 | 4 | import UIRegistry from './ui-registry' 5 | import IndieRegistry from './indie-registry' 6 | import MessageRegistry from './message-registry' 7 | import LinterRegistry from './linter-registry' 8 | import EditorsRegistry from './editor-registry' 9 | import { Commands, showDebug } from './commands' 10 | import ToggleView from './toggle-view' 11 | import type { UI, Linter as LinterProvider, Indie } from './types' 12 | 13 | class Linter { 14 | private commands: Commands = new Commands() 15 | private registryUI?: UIRegistry 16 | private registryIndie?: IndieRegistry 17 | private registryEditors?: EditorsRegistry 18 | private registryLinters?: LinterRegistry 19 | private registryMessages?: MessageRegistry 20 | private subscriptions: CompositeDisposable = new CompositeDisposable() 21 | private idleCallbacks: Set = new Set() 22 | 23 | constructor() { 24 | this.subscriptions.add(this.commands) 25 | 26 | this.commands.onShouldLint(() => { 27 | this.registryEditorsInit() 28 | const textEditor = atom.workspace.getActiveTextEditor() 29 | if (textEditor === undefined) { 30 | return 31 | } 32 | // this.registryEditors becomes valid inside registryEditorsInit 33 | const editorLinter = this.registryEditors!.get(textEditor) 34 | if (editorLinter) { 35 | editorLinter.lint() 36 | } 37 | }) 38 | this.commands.onShouldToggleActiveEditor(() => { 39 | const textEditor = atom.workspace.getActiveTextEditor() 40 | if (textEditor === undefined) { 41 | return 42 | } 43 | this.registryEditorsInit() 44 | // this.registryEditors becomes valid inside registryEditorsInit 45 | const editor = this.registryEditors!.get(textEditor) 46 | if (editor) { 47 | editor.dispose() 48 | } else if (textEditor) { 49 | // this.registryEditors becomes valid inside registryEditorsInit 50 | this.registryEditors!.createFromTextEditor(textEditor) 51 | } 52 | }) 53 | this.commands.onShouldDebug(async () => { 54 | this.registryUIInit() 55 | this.registryIndieInit() 56 | this.registryLintersInit() 57 | await showDebug( 58 | // this.registryLinters becomes valid inside registryLintersInit 59 | this.registryLinters!.getProviders(), 60 | // this.registryIndie becomes valid inside registryIndieInit 61 | this.registryIndie!.getProviders(), 62 | // this.registryUI becomes valid inside registryUIInit 63 | this.registryUI!.getProviders(), 64 | ) 65 | }) 66 | this.commands.onShouldToggleLinter(action => { 67 | this.registryLintersInit() 68 | // this.registryLinters becomes valid inside registryLintersInit 69 | const toggleView = new ToggleView(action, arrayUnique(this.registryLinters!.getProviders().map(linter => linter.name))) 70 | toggleView.onDidDispose(() => { 71 | this.subscriptions.remove(toggleView) 72 | }) 73 | toggleView.onDidDisable(name => { 74 | // this.registryLinters becomes valid inside registryLintersInit 75 | const linter = this.registryLinters!.getProviders().find(entry => entry.name === name) 76 | if (linter) { 77 | this.registryMessagesInit() 78 | // this.registryMessages becomes valid inside registryMessagesInit 79 | this.registryMessages!.deleteByLinter(linter) 80 | } 81 | }) 82 | toggleView.show() 83 | this.subscriptions.add(toggleView) 84 | }) 85 | 86 | const projectPathChangeCallbackID = window.requestIdleCallback( 87 | /* projectPathChange */ () => { 88 | this.idleCallbacks.delete(projectPathChangeCallbackID) 89 | // NOTE: Atom triggers this on boot so wait a while 90 | this.subscriptions.add( 91 | atom.project.onDidChangePaths(() => { 92 | this.commands.lint() 93 | }), 94 | ) 95 | }, 96 | ) 97 | this.idleCallbacks.add(projectPathChangeCallbackID) 98 | 99 | const registryEditorsInitCallbackID = window.requestIdleCallback( 100 | /* registryEditorsIdleInit */ () => { 101 | this.idleCallbacks.delete(registryEditorsInitCallbackID) 102 | // This will be called on the fly if needed, but needs to run on it's 103 | // own at some point or linting on open or on change will never trigger 104 | this.registryEditorsInit() 105 | }, 106 | ) 107 | this.idleCallbacks.add(registryEditorsInitCallbackID) 108 | } 109 | dispose() { 110 | this.idleCallbacks.forEach(callbackID => window.cancelIdleCallback(callbackID)) 111 | this.idleCallbacks.clear() 112 | this.subscriptions.dispose() 113 | } 114 | 115 | registryEditorsInit() { 116 | if (this.registryEditors !== undefined) { 117 | return 118 | } 119 | this.registryEditors = new EditorsRegistry() 120 | this.subscriptions.add(this.registryEditors) 121 | this.registryEditors.observe(editorLinter => { 122 | editorLinter.onShouldLint(onChange => { 123 | this.registryLintersInit() 124 | // this.registryLinters becomes valid inside registryLintersInit 125 | this.registryLinters!.lint({ onChange, editor: editorLinter.getEditor() }) 126 | }) 127 | editorLinter.onDidDestroy(() => { 128 | this.registryMessagesInit() 129 | if (!this.registryEditors!.hasSibling(editorLinter)) { 130 | // this.registryMessages becomes valid inside registryMessagesInit 131 | this.registryMessages!.deleteByBuffer(editorLinter.getEditor().getBuffer()) 132 | } 133 | }) 134 | }) 135 | this.registryEditors.activate() 136 | } 137 | registryLintersInit() { 138 | if (this.registryLinters !== undefined) { 139 | return 140 | } 141 | this.registryLinters = new LinterRegistry() 142 | this.subscriptions.add(this.registryLinters) 143 | this.registryLinters.onDidUpdateMessages(({ linter, messages, buffer }) => { 144 | this.registryMessagesInit() 145 | // this.registryMessages becomes valid inside registryMessagesInit 146 | this.registryMessages!.set({ linter, messages, buffer }) 147 | }) 148 | this.registryLinters.onDidBeginLinting(({ linter, filePath }) => { 149 | this.registryUIInit() 150 | // this.registryUI becomes valid inside registryUIInit 151 | this.registryUI!.didBeginLinting(linter, filePath) 152 | }) 153 | this.registryLinters.onDidFinishLinting(({ linter, filePath }) => { 154 | this.registryUIInit() 155 | // this.registryUI becomes valid inside registryUIInit 156 | this.registryUI!.didFinishLinting(linter, filePath) 157 | }) 158 | } 159 | registryIndieInit() { 160 | if (this.registryIndie !== undefined) { 161 | return 162 | } 163 | this.registryIndie = new IndieRegistry() 164 | this.subscriptions.add(this.registryIndie) 165 | this.registryIndie.observe(indieLinter => { 166 | indieLinter.onDidDestroy(() => { 167 | this.registryMessagesInit() 168 | // this.registryMessages becomes valid inside registryMessagesInit 169 | this.registryMessages!.deleteByLinter(indieLinter) 170 | }) 171 | }) 172 | this.registryIndie.onDidUpdate(({ linter, messages }) => { 173 | this.registryMessagesInit() 174 | // this.registryMessages becomes valid inside registryMessagesInit 175 | this.registryMessages!.set({ linter, messages, buffer: null }) 176 | }) 177 | } 178 | registryMessagesInit() { 179 | if (this.registryMessages) { 180 | return 181 | } 182 | this.registryMessages = new MessageRegistry() 183 | this.subscriptions.add(this.registryMessages) 184 | this.registryMessages.onDidUpdateMessages(difference => { 185 | this.registryUIInit() 186 | // this.registryUI becomes valid inside registryUIInit 187 | this.registryUI!.render(difference) 188 | }) 189 | } 190 | registryUIInit() { 191 | if (this.registryUI !== undefined) { 192 | return 193 | } 194 | this.registryUI = new UIRegistry() 195 | this.subscriptions.add(this.registryUI) 196 | } 197 | 198 | // API methods for providing/consuming services 199 | // UI 200 | addUI(ui: UI) { 201 | this.registryUIInit() 202 | // this.registryUI becomes valid inside registryUIInit 203 | this.registryUI!.add(ui) 204 | this.registryMessagesInit() 205 | // this.registryMessages becomes valid inside registryMessagesInit 206 | const messages = this.registryMessages!.messages 207 | if (messages.length) { 208 | ui.render({ added: messages, messages, removed: [] }) 209 | } 210 | } 211 | deleteUI(ui: UI) { 212 | this.registryUIInit() 213 | // this.registryUI becomes valid inside registryUIInit 214 | this.registryUI!.delete(ui) 215 | } 216 | // Standard Linter 217 | addLinter(linter: LinterProvider) { 218 | this.registryLintersInit() 219 | // this.registryLinters becomes valid inside registryLintersInit 220 | this.registryLinters!.addLinter(linter) 221 | } 222 | deleteLinter(linter: LinterProvider) { 223 | this.registryLintersInit() 224 | // this.registryLinters becomes valid inside registryLintersInit 225 | this.registryLinters!.deleteLinter(linter) 226 | this.registryMessagesInit() 227 | // this.registryMessages becomes valid inside registryMessagesInit 228 | this.registryMessages!.deleteByLinter(linter) 229 | } 230 | // Indie Linter 231 | addIndie(indie: Indie) { 232 | this.registryIndieInit() 233 | // this.registryIndie becomes valid inside registryIndieInit 234 | return this.registryIndie!.register(indie, 2) 235 | } 236 | } 237 | 238 | export default Linter 239 | -------------------------------------------------------------------------------- /lib/message-registry.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable, Emitter } from 'atom' 2 | import debounce from 'lodash/debounce' 3 | import type { Disposable, TextBuffer } from 'atom' 4 | import { flagMessages, mergeArray } from './helpers' 5 | import type { MessagesPatch, Message, Linter } from './types' 6 | 7 | type Linter$Message$Map = { 8 | buffer: TextBuffer | null | undefined 9 | linter: Linter 10 | changed: boolean 11 | deleted: boolean 12 | messages: Array 13 | oldMessages: Array 14 | } 15 | 16 | export default class MessageRegistry { 17 | private emitter: Emitter = new Emitter() 18 | messages: Array = [] 19 | private messagesMap: Set = new Set() 20 | private subscriptions: CompositeDisposable = new CompositeDisposable() 21 | private debouncedUpdate: () => void 22 | 23 | constructor() { 24 | this.debouncedUpdate = debounce(this.update, 100, { leading: true }) 25 | this.subscriptions.add(this.emitter) 26 | } 27 | set({ messages, linter, buffer }: { messages: Array; linter: Linter; buffer: TextBuffer | null }) { 28 | // check if the linter has been already set 29 | let found = null 30 | for (const entry of this.messagesMap) { 31 | if (entry.buffer === buffer && entry.linter === linter) { 32 | found = entry 33 | break 34 | } 35 | } 36 | 37 | if (found) { 38 | // found linter 39 | found.messages = messages 40 | found.changed = true 41 | } else { 42 | // new linter 43 | this.messagesMap.add({ messages, linter, buffer, oldMessages: [], changed: true, deleted: false }) 44 | } 45 | this.debouncedUpdate() 46 | } 47 | update() { 48 | // the final object sent to UI that contains the messages tagged for adding/removeal. messages is all the kept + added messages 49 | const result: { added: Array; removed: Array; messages: Array } = { 50 | added: [], 51 | removed: [], 52 | messages: [], 53 | } 54 | 55 | // looping over each linter 56 | for (const entry of this.messagesMap) { 57 | // if linter is deleted 58 | // tag the linter's cache for removal and delete it from the map 59 | if (entry.deleted) { 60 | mergeArray(result.removed, entry.oldMessages) 61 | this.messagesMap.delete(entry) 62 | continue 63 | } 64 | 65 | // if the linter is not changed 66 | // just use its cache (no added/removed and everything is kept) and skip the rest 67 | if (!entry.changed) { 68 | // TODO When this code acutally runs?! 69 | mergeArray(result.messages, entry.oldMessages) 70 | continue 71 | } 72 | 73 | // flag messages as oldKept, oldRemoved, newAdded 74 | const flaggedMessages = flagMessages(entry.messages, entry.oldMessages) 75 | 76 | // update the result and cache 77 | if (flaggedMessages !== null) { 78 | const { oldKept, oldRemoved, newAdded } = flaggedMessages 79 | mergeArray(result.added, newAdded) 80 | mergeArray(result.removed, oldRemoved) 81 | const allThisEntry = newAdded.concat(oldKept) 82 | mergeArray(result.messages, allThisEntry) 83 | entry.oldMessages = allThisEntry // update chache 84 | } 85 | } 86 | 87 | // if any messages is removed or added, then update the UI 88 | if (result.added.length || result.removed.length) { 89 | this.messages = result.messages 90 | this.emitter.emit('did-update-messages', result) 91 | } 92 | } 93 | onDidUpdateMessages(callback: (difference: MessagesPatch) => void): Disposable { 94 | return this.emitter.on('did-update-messages', callback) 95 | } 96 | deleteByBuffer(buffer: TextBuffer) { 97 | for (const entry of this.messagesMap) { 98 | if (entry.buffer === buffer) { 99 | entry.deleted = true 100 | } 101 | } 102 | this.debouncedUpdate() 103 | } 104 | deleteByLinter(linter: Linter) { 105 | for (const entry of this.messagesMap) { 106 | if (entry.linter === linter) { 107 | entry.deleted = true 108 | } 109 | } 110 | this.debouncedUpdate() 111 | } 112 | dispose() { 113 | this.subscriptions.dispose() 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lib/toggle-view.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable, Emitter, Disposable } from 'atom' 2 | 3 | // https://github.com/atom/atom-select-list/pull/31 4 | let SelectListView: any 5 | type ToggleAction = 'enable' | 'disable' 6 | 7 | export default class ToggleView { 8 | private action: ToggleAction 9 | private emitter: Emitter = new Emitter() 10 | private providers: Array 11 | private subscriptions: CompositeDisposable = new CompositeDisposable() 12 | private disabledProviders: Array = [] 13 | 14 | constructor(action: ToggleAction, providers: Array) { 15 | this.action = action 16 | this.providers = providers 17 | 18 | this.subscriptions.add( 19 | this.emitter, 20 | atom.config.observe('linter.disabledProviders', disabledProviders => { 21 | this.disabledProviders = disabledProviders 22 | }), 23 | ) 24 | } 25 | getItems(): Array { 26 | if (this.action === 'disable') { 27 | return this.providers.filter(name => !this.disabledProviders.includes(name)) 28 | } 29 | return this.disabledProviders 30 | } 31 | process(name: string): void { 32 | if (this.action === 'disable') { 33 | this.disabledProviders.push(name) 34 | this.emitter.emit('did-disable', name) 35 | } else { 36 | const index = this.disabledProviders.indexOf(name) 37 | if (index !== -1) { 38 | this.disabledProviders.splice(index, 1) 39 | } 40 | } 41 | atom.config.set('linter.disabledProviders', this.disabledProviders) 42 | } 43 | show() { 44 | if (!SelectListView) { 45 | SelectListView = require('atom-select-list') 46 | } 47 | const selectListView = new SelectListView({ 48 | items: this.getItems(), 49 | emptyMessage: 'No matches found', 50 | elementForItem: (item: any) => { 51 | const li = document.createElement('li') 52 | li.textContent = item 53 | return li 54 | }, 55 | didConfirmSelection: (item: any) => { 56 | try { 57 | this.process(item) 58 | this.dispose() 59 | } catch (e) { 60 | console.error('[Linter] Unable to process toggle:', e) 61 | } 62 | }, 63 | didCancelSelection: () => { 64 | this.dispose() 65 | }, 66 | didConfirmEmptySelection: () => { 67 | this.dispose() 68 | }, 69 | }) 70 | const panel = atom.workspace.addModalPanel({ item: selectListView }) 71 | 72 | selectListView.focus() 73 | this.subscriptions.add( 74 | new Disposable(function () { 75 | panel.destroy() 76 | }), 77 | ) 78 | } 79 | 80 | /* eslint-disable @typescript-eslint/no-explicit-any */ 81 | onDidDispose(callback: () => any): Disposable { 82 | return this.emitter.on('did-dispose', callback) 83 | } 84 | onDidDisable(callback: (name: string) => any): Disposable { 85 | return this.emitter.on('did-disable', callback) 86 | } 87 | /* eslint-enable @typescript-eslint/no-explicit-any */ 88 | 89 | dispose() { 90 | this.emitter.emit('did-dispose') 91 | this.subscriptions.dispose() 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "strictNullChecks": true, 5 | "noUnusedLocals": true, 6 | "noUnusedParameters": true, 7 | "noImplicitReturns": true, 8 | "noImplicitAny": true, 9 | "noImplicitThis": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "declaration": true, 12 | "emitDecoratorMetadata": true, 13 | "experimentalDecorators": true, 14 | "incremental": true, 15 | "sourceMap": true, 16 | "inlineSourceMap": false, 17 | "inlineSources": true, 18 | "preserveSymlinks": true, 19 | "removeComments": true, 20 | "jsx": "react", 21 | "lib": ["ES2018", "dom"], 22 | "target": "ES2018", 23 | "allowJs": true, 24 | "esModuleInterop": true, 25 | "module": "commonjs", 26 | "moduleResolution": "node", 27 | "importHelpers": false, 28 | "outDir": "../dist" 29 | }, 30 | "compileOnSave": false 31 | } 32 | -------------------------------------------------------------------------------- /lib/types/.eslintignore: -------------------------------------------------------------------------------- 1 | ./linter-ui-default/ 2 | -------------------------------------------------------------------------------- /lib/types/atom.d.ts: -------------------------------------------------------------------------------- 1 | import { TextEditor } from 'atom' 2 | 3 | // Missing Atom API 4 | declare module 'atom' { 5 | interface CompositeDisposable { 6 | disposed: boolean 7 | } 8 | interface Pane { 9 | getPendingItem(): TextEditor 10 | } 11 | interface Notification { 12 | getOptions(): { detail: string } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './linter' 2 | export * from './linter-ui-default' 3 | -------------------------------------------------------------------------------- /lib/types/linter-ui-default.d.ts: -------------------------------------------------------------------------------- 1 | export { default as UI } from './linter-ui-default/main' 2 | -------------------------------------------------------------------------------- /lib/types/linter.d.ts: -------------------------------------------------------------------------------- 1 | import { Range, Point, RangeCompatible, PointCompatible, TextEditor } from 'atom' 2 | 3 | export type MessageSolution = 4 | | { 5 | title?: string 6 | position: Range 7 | priority?: number 8 | currentText?: string 9 | replaceWith: string 10 | } 11 | | { 12 | title?: string 13 | position: Range 14 | priority?: number 15 | apply: () => any 16 | } 17 | 18 | export type Message = { 19 | // Automatically added by linter 20 | key: string 21 | version: 2 22 | linterName: string 23 | 24 | // From providers 25 | location: { 26 | file: string 27 | position: Range 28 | } 29 | reference?: { 30 | file: string 31 | position?: Point 32 | } 33 | url?: string 34 | icon?: string 35 | excerpt: string 36 | severity: 'error' | 'warning' | 'info' 37 | solutions?: Array | (() => Promise>) 38 | description?: string | (() => Promise | string) 39 | } 40 | 41 | /** Alias for {Message} */ 42 | export type LinterMessage = Message 43 | 44 | /** 45 | * @deprecated Wrong but convertible message format which some providers might use by mistake. This is converted to 46 | * MessageSolution by Linter using `normalizeMessages` 47 | */ 48 | export type MessageSolutionLike = Omit & { 49 | position: RangeCompatible 50 | } 51 | 52 | /** 53 | * @deprecated Wrong but convertible message format which some providers might use. This is converted to MessageSolution by 54 | * Linter using `normalizeMessages` 55 | */ 56 | export type MessageLike = Omit & { 57 | location: { 58 | file: string 59 | position: RangeCompatible 60 | } 61 | reference?: { 62 | file: string 63 | position?: PointCompatible 64 | } 65 | solutions?: Array | (() => Promise>) 66 | } 67 | 68 | export type LinterResult = Array | null | undefined 69 | export type Linter = { 70 | // Automatically added 71 | __$sb_linter_version: number 72 | __$sb_linter_activated: boolean 73 | __$sb_linter_request_latest: number 74 | __$sb_linter_request_last_received: number 75 | 76 | // From providers 77 | name: string 78 | scope: 'file' | 'project' 79 | lintOnFly?: boolean // <-- legacy 80 | lintsOnChange?: boolean 81 | grammarScopes: Array 82 | lint(textEditor: TextEditor): LinterResult | Promise 83 | } 84 | 85 | export type Indie = { 86 | name: string 87 | } 88 | 89 | export type MessagesPatch = { 90 | added: Array 91 | removed: Array 92 | messages: Array 93 | } 94 | -------------------------------------------------------------------------------- /lib/ui-registry.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable } from 'atom' 2 | import { ui as validateUI } from './validate' 3 | import type { Linter, UI, MessagesPatch } from './types' 4 | 5 | export default class UIRegistry { 6 | private providers: Set = new Set() 7 | private subscriptions: CompositeDisposable = new CompositeDisposable() 8 | 9 | add(ui: UI) { 10 | if (!this.providers.has(ui) && validateUI(ui)) { 11 | this.subscriptions.add(ui) 12 | this.providers.add(ui) 13 | } 14 | } 15 | delete(provider: UI) { 16 | if (this.providers.has(provider)) { 17 | provider.dispose() 18 | this.providers.delete(provider) 19 | } 20 | } 21 | getProviders(): Array { 22 | return Array.from(this.providers) 23 | } 24 | render(messages: MessagesPatch) { 25 | this.providers.forEach(function (provider) { 26 | provider.render(messages) 27 | }) 28 | } 29 | didBeginLinting(linter: Linter, filePath: string) { 30 | this.providers.forEach(function (provider) { 31 | provider.didBeginLinting(linter, filePath) 32 | }) 33 | } 34 | didFinishLinting(linter: Linter, filePath: string) { 35 | this.providers.forEach(function (provider) { 36 | provider.didFinishLinting(linter, filePath) 37 | }) 38 | } 39 | dispose() { 40 | this.providers.clear() 41 | this.subscriptions.dispose() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/validate/helpers.ts: -------------------------------------------------------------------------------- 1 | export function showError(title: string, description: string, points: Array) { 2 | const renderedPoints = points.map(item => ` • ${item}`) 3 | atom.notifications.addWarning(`[Linter] ${title}`, { 4 | dismissable: true, 5 | detail: `${description}\n${renderedPoints.join('\n')}`, 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /lib/validate/index.ts: -------------------------------------------------------------------------------- 1 | import { Range, Point } from 'atom' 2 | import { showError } from './helpers' 3 | import type { UI, Linter, Message, Indie } from '../types' 4 | 5 | const VALID_SEVERITY = new Set(['error', 'warning', 'info']) 6 | 7 | function validateUI(ui: UI): boolean { 8 | const messages = [] 9 | 10 | if (ui && typeof ui === 'object') { 11 | if (typeof ui.name !== 'string') { 12 | messages.push('UI.name must be a string') 13 | } 14 | if (typeof ui.didBeginLinting !== 'function') { 15 | messages.push('UI.didBeginLinting must be a function') 16 | } 17 | if (typeof ui.didFinishLinting !== 'function') { 18 | messages.push('UI.didFinishLinting must be a function') 19 | } 20 | if (typeof ui.render !== 'function') { 21 | messages.push('UI.render must be a function') 22 | } 23 | if (typeof ui.dispose !== 'function') { 24 | messages.push('UI.dispose must be a function') 25 | } 26 | } else { 27 | messages.push('UI must be an object') 28 | } 29 | 30 | if (messages.length) { 31 | showError( 32 | 'Invalid UI received', 33 | `These issues were encountered while registering the UI named '${ui && ui.name ? ui.name : 'Unknown'}'`, 34 | messages, 35 | ) 36 | return false 37 | } 38 | 39 | return true 40 | } 41 | 42 | function validateLinter(linter: Linter): boolean { 43 | const messages = [] 44 | 45 | if (linter && typeof linter === 'object') { 46 | if (typeof linter.name !== 'string') { 47 | messages.push('Linter.name must be a string') 48 | } 49 | if (typeof linter.scope !== 'string' || (linter.scope !== 'file' && linter.scope !== 'project')) { 50 | messages.push("Linter.scope must be either 'file' or 'project'") 51 | } 52 | if (typeof linter.lintsOnChange !== 'boolean') { 53 | messages.push('Linter.lintsOnChange must be a boolean') 54 | } 55 | if (!Array.isArray(linter.grammarScopes)) { 56 | messages.push('Linter.grammarScopes must be an Array') 57 | } 58 | if (typeof linter.lint !== 'function') { 59 | messages.push('Linter.lint must be a function') 60 | } 61 | } else { 62 | messages.push('Linter must be an object') 63 | } 64 | 65 | if (messages.length) { 66 | showError( 67 | 'Invalid Linter received', 68 | `These issues were encountered while registering a Linter named '${linter && linter.name ? linter.name : 'Unknown'}'`, 69 | messages, 70 | ) 71 | return false 72 | } 73 | 74 | return true 75 | } 76 | 77 | function validateIndie(indie: Indie): boolean { 78 | const messages = [] 79 | 80 | if (indie && typeof indie === 'object') { 81 | if (typeof indie.name !== 'string') { 82 | messages.push('Indie.name must be a string') 83 | } 84 | } else { 85 | messages.push('Indie must be an object') 86 | } 87 | 88 | if (messages.length) { 89 | showError( 90 | 'Invalid Indie received', 91 | `These issues were encountered while registering an Indie Linter named '${ 92 | indie && indie.name ? indie.name : 'Unknown' 93 | }'`, 94 | messages, 95 | ) 96 | return false 97 | } 98 | 99 | return true 100 | } 101 | 102 | function validateMessages(linterName: string, entries: Array): boolean { 103 | const messages = [] 104 | 105 | if (Array.isArray(entries)) { 106 | let invalidURL = false 107 | let invalidIcon = false 108 | let invalidExcerpt = false 109 | let invalidLocation = false 110 | let invalidSeverity = false 111 | let invalidSolution = false 112 | let invalidReference = false 113 | let invalidDescription = false 114 | let invalidLinterName = false 115 | 116 | for (let i = 0, { length } = entries; i < length; ++i) { 117 | const message = entries[i] 118 | const { reference } = message 119 | if (!invalidIcon && message.icon && typeof message.icon !== 'string') { 120 | invalidIcon = true 121 | messages.push('Message.icon must be a string') 122 | } 123 | if ( 124 | !invalidLocation && 125 | (!message.location || 126 | typeof message.location !== 'object' || 127 | typeof message.location.file !== 'string' || 128 | typeof message.location.position !== 'object' || 129 | !message.location.position) 130 | ) { 131 | invalidLocation = true 132 | messages.push('Message.location must be valid') 133 | } else if (!invalidLocation) { 134 | const range = Range.fromObject(message.location.position) 135 | if ( 136 | Number.isNaN(range.start.row) || 137 | Number.isNaN(range.start.column) || 138 | Number.isNaN(range.end.row) || 139 | Number.isNaN(range.end.column) 140 | ) { 141 | invalidLocation = true 142 | messages.push('Message.location.position should not contain NaN coordinates') 143 | } 144 | } 145 | if ( 146 | !invalidSolution && 147 | message.solutions && 148 | !Array.isArray(message.solutions) && 149 | !(message.solutions instanceof Promise) 150 | ) { 151 | invalidSolution = true 152 | messages.push('Message.solutions must be valid') 153 | } 154 | if ( 155 | !invalidReference && 156 | reference && 157 | (typeof reference !== 'object' || 158 | typeof reference.file !== 'string' || 159 | typeof reference.position !== 'object' || 160 | !reference.position) 161 | ) { 162 | invalidReference = true 163 | messages.push('Message.reference must be valid') 164 | } else if (!invalidReference && reference && reference.position !== undefined) { 165 | const position = Point.fromObject(reference.position) 166 | if (Number.isNaN(position.row) || Number.isNaN(position.column)) { 167 | invalidReference = true 168 | messages.push('Message.reference.position should not contain NaN coordinates') 169 | } 170 | } 171 | if (!invalidExcerpt && typeof message.excerpt !== 'string') { 172 | invalidExcerpt = true 173 | messages.push('Message.excerpt must be a string') 174 | } 175 | if (!invalidSeverity && !VALID_SEVERITY.has(message.severity)) { 176 | invalidSeverity = true 177 | messages.push("Message.severity must be 'error', 'warning' or 'info'") 178 | } 179 | if (!invalidURL && message.url && typeof message.url !== 'string') { 180 | invalidURL = true 181 | messages.push('Message.url must be a string') 182 | } 183 | if ( 184 | !invalidDescription && 185 | message.description && 186 | typeof message.description !== 'function' && 187 | typeof message.description !== 'string' 188 | ) { 189 | invalidDescription = true 190 | messages.push('Message.description must be a function or string') 191 | } 192 | if (!invalidLinterName && message.linterName && typeof message.linterName !== 'string') { 193 | invalidLinterName = true 194 | messages.push('Message.linterName must be a string') 195 | } 196 | } 197 | } else { 198 | messages.push('Linter Result must be an Array') 199 | } 200 | 201 | if (messages.length) { 202 | showError( 203 | 'Invalid Linter Result received', 204 | `These issues were encountered while processing messages from a linter named '${linterName}'`, 205 | messages, 206 | ) 207 | return false 208 | } 209 | 210 | return true 211 | } 212 | 213 | export { validateUI as ui, validateLinter as linter, validateIndie as indie, validateMessages as messages } 214 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linter", 3 | "main": "./dist/index.js", 4 | "author": "steelbrain", 5 | "readme": "./README.md", 6 | "version": "3.4.0", 7 | "description": "A Base Linter with Cow Powers", 8 | "repository": "https://github.com/steelbrain/linter", 9 | "license": "MIT", 10 | "keywords": [ 11 | "linter", 12 | "base linter" 13 | ], 14 | "private": true, 15 | "scripts": { 16 | "format": "prettier --write .", 17 | "test.format": "prettier . --check", 18 | "lint": "eslint . --fix", 19 | "test.lint": "eslint .", 20 | "test.only": "atom --test spec", 21 | "test": "npm run tsc.build && npm run build && npm run test.only", 22 | "clean": "shx rm -rf dist", 23 | "get.ui-types": "node ./scripts/get-ui-types.js", 24 | "tsc.types": "(tsc -p ./lib/tsconfig.json --emitDeclarationOnly || echo done) && (shx cp -r ./lib/types dist && shx rm -rf ./dist/types/linter-ui-default)", 25 | "tsc.dev": "npm run clean && cross-env NODE_ENV=development tsc --watch -p lib/tsconfig.json || echo done", 26 | "tsc.build": "npm run clean && cross-env NODE_ENV=production tsc -p lib/tsconfig.json || echo done", 27 | "dev": "npm run clean && cross-env NODE_ENV=development cross-env BABEL_KEEP_MODULES=true rollup -c -w", 28 | "build.bundle": "cross-env NODE_ENV=production cross-env BABEL_KEEP_MODULES=true rollup -c", 29 | "build": "npm run tsc.types && npm run build.bundle", 30 | "build-commit": "npm run clean && build-commit -o dist", 31 | "prepare": "npm run get.ui-types && npm run clean && npm run build", 32 | "prepublishOnly": "npm run build-commit" 33 | }, 34 | "engines": { 35 | "atom": ">=1.14.0 <2.0.0" 36 | }, 37 | "consumedServices": { 38 | "linter": { 39 | "versions": { 40 | "2.0.0": "consumeLinter" 41 | } 42 | }, 43 | "linter-ui": { 44 | "versions": { 45 | "1.0.0": "consumeUI" 46 | } 47 | } 48 | }, 49 | "providedServices": { 50 | "linter-indie": { 51 | "versions": { 52 | "2.0.0": "provideIndie" 53 | } 54 | } 55 | }, 56 | "activationHooks": [ 57 | "core:loaded-shell-environment" 58 | ], 59 | "dependencies": { 60 | "atom-package-deps": "^7.2.3", 61 | "atom-select-list": "^0.8.1", 62 | "lodash": "^4.17.21", 63 | "minimatch": "^3.0.4" 64 | }, 65 | "devDependencies": { 66 | "@types/atom": "^1.40.10", 67 | "@types/jasmine": "^3.7.7", 68 | "@types/lodash": "^4.14.170", 69 | "@types/minimatch": "^3.0.4", 70 | "@types/node": "^15.12.2", 71 | "@types/requestidlecallback": "^0.3.1", 72 | "atom-ide-base": "^3.1.1", 73 | "build-commit": "0.1.4", 74 | "cross-env": "^7.0.3", 75 | "eslint": "^7.28.0", 76 | "eslint-config-atomic": "^1.16.1", 77 | "fs-plus": "^3.1.1", 78 | "gitly": "<=2.2.2", 79 | "jasmine-fix": "^1.3.1", 80 | "prettier-config-atomic": "^2.0.5", 81 | "rollup": "^2.52.1", 82 | "rollup-plugin-atomic": "^2.3.2", 83 | "shx": "^0.3.3", 84 | "solid-js": "^0.26.5", 85 | "temp": "^0.9.4", 86 | "typescript": "^4.3.4" 87 | }, 88 | "package-deps": [ 89 | { 90 | "name": "linter-ui-default", 91 | "minimumVersion": "3.3.1" 92 | } 93 | ], 94 | "configSchema": { 95 | "lintPreviewTabs": { 96 | "type": "boolean", 97 | "description": "Lint tabs while they are still in preview status", 98 | "default": true, 99 | "order": 1 100 | }, 101 | "lintOnOpen": { 102 | "title": "Lint on Open", 103 | "description": "Lint files automatically when they are opened", 104 | "type": "boolean", 105 | "default": true, 106 | "order": 2 107 | }, 108 | "lintOnChange": { 109 | "title": "Lint on Change", 110 | "description": "Lint files while typing, without the need to save (only for supported providers)", 111 | "type": "boolean", 112 | "default": true, 113 | "order": 3 114 | }, 115 | "lintOnChangeInterval": { 116 | "title": "Lint on Change Interval", 117 | "description": "Interval at which linting is done as you type (in ms)", 118 | "type": "integer", 119 | "default": 300, 120 | "order": 4 121 | }, 122 | "ignoreGlob": { 123 | "title": "Ignore files matching this Glob", 124 | "type": "string", 125 | "default": "**/*.min.{js,css}", 126 | "order": 5 127 | }, 128 | "disabledProviders": { 129 | "title": "Disabled providers", 130 | "type": "array", 131 | "items": { 132 | "type": "string" 133 | }, 134 | "description": "Names of disabled linter providers", 135 | "default": [], 136 | "order": 6 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('prettier-config-atomic'), 3 | // this just to minimize the changes for linter-ui-default 4 | printWidth: 125, 5 | singleQuote: true, 6 | arrowParens: 'avoid', 7 | trailingComma: 'all', 8 | } 9 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createPlugins } from 'rollup-plugin-atomic' 2 | 3 | const plugins = createPlugins(['js', ['ts', { tsconfig: './lib/tsconfig.json', noEmitOnError: false, module: 'ESNext' }]]) 4 | 5 | // eslint-disable-next-line import/no-anonymous-default-export 6 | export default [ 7 | { 8 | input: 'lib/index.ts', 9 | output: [ 10 | { 11 | dir: 'dist', 12 | format: 'cjs', 13 | sourcemap: true, 14 | }, 15 | ], 16 | // loaded externally 17 | external: ['atom'], 18 | plugins, 19 | }, 20 | ] 21 | -------------------------------------------------------------------------------- /scripts/get-ui-types.js: -------------------------------------------------------------------------------- 1 | const { download, extract } = require('gitly') 2 | const { dirname, join } = require('path') 3 | const { shx } = require('shx/lib/shx') 4 | const { tmpdir } = require('os') 5 | 6 | ;(async function main() { 7 | const source = await download('steelbrain/linter-ui-default') 8 | const root = dirname(__dirname) 9 | const distFolder = join(root, 'lib', 'types', 'linter-ui-default') 10 | shx([, , 'rm', '-rf', distFolder]) 11 | // shx([, , "mkdir", "-p", distFolder]) 12 | 13 | const extractFolder = join(tmpdir(), 'linter-ui-default') 14 | shx([, , 'mkdir', '-p', extractFolder]) 15 | await extract(source, extractFolder) 16 | 17 | shx([, , 'mv', join(extractFolder, 'dist'), distFolder]) 18 | shx([, , 'rm', '-rf', extractFolder]) 19 | 20 | // avoid circular types 21 | shx([, , 'rm', '-rf', join(distFolder, 'types', 'linter')]) 22 | shx([, , 'rm', '-rf', join(distFolder, 'types', 'linter.d.ts')]) 23 | shx([, , 'cp', join(root, 'lib', 'types', 'linter.d.ts'), join(distFolder, 'types', 'linter.d.ts')]) 24 | })() 25 | --------------------------------------------------------------------------------