mirror of
https://github.com/atom/atom.git
synced 2026-01-25 14:59:03 -05:00
➡️ Migrate core package 'deprecation-cop' into ./packages
This commit is contained in:
9
package-lock.json
generated
9
package-lock.json
generated
@@ -1712,8 +1712,7 @@
|
||||
}
|
||||
},
|
||||
"deprecation-cop": {
|
||||
"version": "https://www.atom.io/api/packages/deprecation-cop/versions/0.56.9/tarball",
|
||||
"integrity": "sha512-dTKNhWcDgK6Y5cR8dwZ507QW15lob+Lp//P71wXoTVidXboDqH13Y1yQ7Av5qASscv7fqp5GcvLhQWF55W5yng==",
|
||||
"version": "file:packages/deprecation-cop",
|
||||
"requires": {
|
||||
"etch": "0.9.0",
|
||||
"fs-plus": "^3.0.0",
|
||||
@@ -1724,13 +1723,11 @@
|
||||
"dependencies": {
|
||||
"etch": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/etch/-/etch-0.9.0.tgz",
|
||||
"integrity": "sha1-CSJpiPLO4GkL3yCMyyXkFNXfrV8="
|
||||
"bundled": true
|
||||
},
|
||||
"grim": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/grim/-/grim-2.0.2.tgz",
|
||||
"integrity": "sha1-52CinKe4NDsMH/r2ziDyGkbuiu0=",
|
||||
"bundled": true,
|
||||
"requires": {
|
||||
"event-kit": "^2.0.0"
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"command-palette": "https://www.atom.io/api/packages/command-palette/versions/0.43.5/tarball",
|
||||
"dalek": "https://www.atom.io/api/packages/dalek/versions/0.2.2/tarball",
|
||||
"dedent": "^0.7.0",
|
||||
"deprecation-cop": "https://www.atom.io/api/packages/deprecation-cop/versions/0.56.9/tarball",
|
||||
"deprecation-cop": "file:packages/deprecation-cop",
|
||||
"dev-live-reload": "file:packages/dev-live-reload",
|
||||
"devtron": "1.3.0",
|
||||
"encoding-selector": "https://www.atom.io/api/packages/encoding-selector/versions/0.23.9/tarball",
|
||||
@@ -196,7 +196,7 @@
|
||||
"bracket-matcher": "0.89.3",
|
||||
"command-palette": "0.43.5",
|
||||
"dalek": "0.2.2",
|
||||
"deprecation-cop": "0.56.9",
|
||||
"deprecation-cop": "file:./packages/deprecation-cop",
|
||||
"dev-live-reload": "file:./packages/dev-live-reload",
|
||||
"encoding-selector": "0.23.9",
|
||||
"exception-reporting": "file:./packages/exception-reporting",
|
||||
|
||||
@@ -27,7 +27,7 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
|
||||
| **bracket-matcher** | [`atom/bracket-matcher`][bracket-matcher] | |
|
||||
| **command-palette** | [`atom/command-palette`][command-palette] | |
|
||||
| **dalek** | [`atom/dalek`][dalek] | [#17838](https://github.com/atom/atom/issues/17838) |
|
||||
| **deprecation-cop** | [`atom/deprecation-cop`][deprecation-cop] | [#17839](https://github.com/atom/atom/issues/17839) |
|
||||
| **deprecation-cop** | [`./deprecation-cop`](./deprecation-cop) | [#17839](https://github.com/atom/atom/issues/17839) |
|
||||
| **dev-live-reload** | [`./dev-live-reload`](dev-live-reload) | [#17840](https://github.com/atom/atom/issues/17840) |
|
||||
| **encoding-selector** | [`atom/encoding-selector`][encoding-selector] | [#17841](https://github.com/atom/atom/issues/17841) |
|
||||
| **exception-reporting** | [`./exception-reporting`](./exception-reporting) | [#17842](https://github.com/atom/atom/issues/17842) |
|
||||
@@ -114,7 +114,6 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
|
||||
[bracket-matcher]: https://github.com/atom/bracket-matcher
|
||||
[command-palette]: https://github.com/atom/command-palette
|
||||
[dalek]: https://github.com/atom/dalek
|
||||
[deprecation-cop]: https://github.com/atom/deprecation-cop
|
||||
[encoding-selector]: https://github.com/atom/encoding-selector
|
||||
[find-and-replace]: https://github.com/atom/find-and-replace
|
||||
[fuzzy-finder]: https://github.com/atom/fuzzy-finder
|
||||
|
||||
1
packages/deprecation-cop/.coffeelintignore
Normal file
1
packages/deprecation-cop/.coffeelintignore
Normal file
@@ -0,0 +1 @@
|
||||
spec/fixtures
|
||||
3
packages/deprecation-cop/.gitignore
vendored
Normal file
3
packages/deprecation-cop/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
node_modules
|
||||
20
packages/deprecation-cop/LICENSE.md
Normal file
20
packages/deprecation-cop/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 <Your name here>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
6
packages/deprecation-cop/README.md
Normal file
6
packages/deprecation-cop/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Deprecation Cop package
|
||||
[](https://travis-ci.org/atom/deprecation-cop) [](https://ci.appveyor.com/project/Atom/deprecation-cop/branch/master) [](https://david-dm.org/atom/deprecation-cop)
|
||||
|
||||
Shows a list of deprecated methods calls. Ideally it should show nothing!
|
||||
|
||||

|
||||
37
packages/deprecation-cop/coffeelint.json
Normal file
37
packages/deprecation-cop/coffeelint.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"max_line_length": {
|
||||
"level": "ignore"
|
||||
},
|
||||
"no_empty_param_list": {
|
||||
"level": "error"
|
||||
},
|
||||
"arrow_spacing": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_interpolation_in_single_quotes": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_debugger": {
|
||||
"level": "error"
|
||||
},
|
||||
"prefer_english_operator": {
|
||||
"level": "error"
|
||||
},
|
||||
"colon_assignment_spacing": {
|
||||
"spacing": {
|
||||
"left": 0,
|
||||
"right": 1
|
||||
},
|
||||
"level": "error"
|
||||
},
|
||||
"braces_spacing": {
|
||||
"spaces": 0,
|
||||
"level": "error"
|
||||
},
|
||||
"spacing_after_comma": {
|
||||
"level": "error"
|
||||
},
|
||||
"no_stand_alone_at": {
|
||||
"level": "error"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{CompositeDisposable, Disposable} = require 'atom'
|
||||
_ = require 'underscore-plus'
|
||||
Grim = require 'grim'
|
||||
|
||||
module.exports =
|
||||
class DeprecationCopStatusBarView
|
||||
lastLength: null
|
||||
toolTipDisposable: null
|
||||
|
||||
constructor: ->
|
||||
@subscriptions = new CompositeDisposable
|
||||
|
||||
@element = document.createElement('div')
|
||||
@element.classList.add('deprecation-cop-status', 'inline-block', 'text-warning')
|
||||
@element.setAttribute('tabindex', -1)
|
||||
|
||||
@icon = document.createElement('span')
|
||||
@icon.classList.add('icon', 'icon-alert')
|
||||
@element.appendChild(@icon)
|
||||
|
||||
@deprecationNumber = document.createElement('span')
|
||||
@deprecationNumber.classList.add('deprecation-number')
|
||||
@deprecationNumber.textContent = '0'
|
||||
@element.appendChild(@deprecationNumber)
|
||||
|
||||
clickHandler = ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
atom.commands.dispatch workspaceElement, 'deprecation-cop:view'
|
||||
@element.addEventListener('click', clickHandler)
|
||||
@subscriptions.add(new Disposable(=> @element.removeEventListener('click', clickHandler)))
|
||||
|
||||
@update()
|
||||
|
||||
debouncedUpdateDeprecatedSelectorCount = _.debounce(@update, 1000)
|
||||
|
||||
@subscriptions.add Grim.on 'updated', @update
|
||||
# TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
|
||||
if atom.styles.onDidUpdateDeprecations?
|
||||
@subscriptions.add(atom.styles.onDidUpdateDeprecations(debouncedUpdateDeprecatedSelectorCount))
|
||||
|
||||
destroy: ->
|
||||
@subscriptions.dispose()
|
||||
@element.remove()
|
||||
|
||||
getDeprecatedCallCount: ->
|
||||
Grim.getDeprecations().map((d) -> d.getStackCount()).reduce(((a, b) -> a + b), 0)
|
||||
|
||||
getDeprecatedStyleSheetsCount: ->
|
||||
# TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
|
||||
if atom.styles.getDeprecations?
|
||||
Object.keys(atom.styles.getDeprecations()).length
|
||||
else
|
||||
0
|
||||
|
||||
update: =>
|
||||
length = @getDeprecatedCallCount() + @getDeprecatedStyleSheetsCount()
|
||||
|
||||
return if @lastLength is length
|
||||
|
||||
@lastLength = length
|
||||
@deprecationNumber.textContent = "#{_.pluralize(length, 'deprecation')}"
|
||||
@toolTipDisposable?.dispose()
|
||||
@toolTipDisposable = atom.tooltips.add @element, title: "#{_.pluralize(length, 'call')} to deprecated methods"
|
||||
|
||||
if length is 0
|
||||
@element.style.display = 'none'
|
||||
else
|
||||
@element.style.display = ''
|
||||
467
packages/deprecation-cop/lib/deprecation-cop-view.js
Normal file
467
packages/deprecation-cop/lib/deprecation-cop-view.js
Normal file
@@ -0,0 +1,467 @@
|
||||
/** @babel */
|
||||
/** @jsx etch.dom */
|
||||
|
||||
import _ from 'underscore-plus'
|
||||
import {CompositeDisposable} from 'atom'
|
||||
import etch from 'etch'
|
||||
import fs from 'fs-plus'
|
||||
import Grim from 'grim'
|
||||
import marked from 'marked'
|
||||
import path from 'path'
|
||||
import shell from 'shell'
|
||||
|
||||
export default class DeprecationCopView {
|
||||
constructor ({uri}) {
|
||||
this.uri = uri
|
||||
this.subscriptions = new CompositeDisposable
|
||||
this.subscriptions.add(Grim.on('updated', () => { etch.update(this) }))
|
||||
// TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
|
||||
if (atom.styles.onDidUpdateDeprecations) {
|
||||
this.subscriptions.add(atom.styles.onDidUpdateDeprecations(() => { etch.update(this) }))
|
||||
}
|
||||
etch.initialize(this)
|
||||
this.subscriptions.add(atom.commands.add(this.element, {
|
||||
'core:move-up': () => { this.scrollUp() },
|
||||
'core:move-down': () => { this.scrollDown() },
|
||||
'core:page-up': () => { this.pageUp() },
|
||||
'core:page-down': () => { this.pageDown() },
|
||||
'core:move-to-top': () => { this.scrollToTop() },
|
||||
'core:move-to-bottom': () => { this.scrollToBottom() }
|
||||
}))
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return {
|
||||
deserializer: this.constructor.name,
|
||||
uri: this.getURI(),
|
||||
version: 1
|
||||
}
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.subscriptions.dispose()
|
||||
return etch.destroy(this)
|
||||
}
|
||||
|
||||
update () {
|
||||
return etch.update(this)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='deprecation-cop pane-item native-key-bindings' tabIndex='-1'>
|
||||
<div className='panel'>
|
||||
<div className='padded deprecation-overview'>
|
||||
<div className='pull-right btn-group'>
|
||||
<button
|
||||
className='btn btn-primary check-for-update'
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.checkForUpdates()
|
||||
}}>Check for Updates</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='panel-heading'><span>Deprecated calls</span></div>
|
||||
<ul className='list-tree has-collapsable-children'>
|
||||
{this.renderDeprecatedCalls()}
|
||||
</ul>
|
||||
|
||||
<div className='panel-heading'><span>Deprecated selectors</span></div>
|
||||
<ul className='selectors list-tree has-collapsable-children'>
|
||||
{this.renderDeprecatedSelectors()}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderDeprecatedCalls () {
|
||||
const deprecationsByPackageName = this.getDeprecatedCallsByPackageName()
|
||||
const packageNames = Object.keys(deprecationsByPackageName)
|
||||
if (packageNames.length === 0) {
|
||||
return <li className='list-item'>No deprecated calls</li>
|
||||
} else {
|
||||
return packageNames.sort().map((packageName) => (
|
||||
<li className='deprecation list-nested-item collapsed'>
|
||||
<div className='deprecation-info list-item' onclick={(event) => event.target.parentElement.classList.toggle('collapsed')}>
|
||||
<span className='text-highlight'>{packageName || 'atom core'}</span>
|
||||
<span>{` (${_.pluralize(deprecationsByPackageName[packageName].length, 'deprecation')})`}</span>
|
||||
</div>
|
||||
|
||||
<ul className='list'>
|
||||
{this.renderPackageActionsIfNeeded(packageName)}
|
||||
{deprecationsByPackageName[packageName].map(({deprecation, stack}) => (
|
||||
<li className='list-item deprecation-detail'>
|
||||
<span className='text-warning icon icon-alert' />
|
||||
<div className='list-item deprecation-message' innerHTML={marked(deprecation.getMessage())} />
|
||||
{this.renderIssueURLIfNeeded(packageName, deprecation, this.buildIssueURL(packageName, deprecation, stack))}
|
||||
<div className='stack-trace'>
|
||||
{stack.map(({functionName, location}) => (
|
||||
<div className='stack-line'>
|
||||
<span>{functionName}</span>
|
||||
<span> - </span>
|
||||
<a
|
||||
className='stack-line-location'
|
||||
href={location}
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.openLocation(location)
|
||||
}}>{location}</a>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
renderDeprecatedSelectors () {
|
||||
const deprecationsByPackageName = this.getDeprecatedSelectorsByPackageName()
|
||||
const packageNames = Object.keys(deprecationsByPackageName)
|
||||
if (packageNames.length === 0) {
|
||||
return (
|
||||
<li className='list-item'>No deprecated selectors</li>
|
||||
)
|
||||
} else {
|
||||
return packageNames.map((packageName) => (
|
||||
<li className='deprecation list-nested-item collapsed'>
|
||||
<div className='deprecation-info list-item' onclick={(event) => event.target.parentElement.classList.toggle('collapsed')}>
|
||||
<span className='text-highlight'>{packageName}</span>
|
||||
</div>
|
||||
|
||||
<ul className='list'>
|
||||
{this.renderPackageActionsIfNeeded(packageName)}
|
||||
{deprecationsByPackageName[packageName].map(({packagePath, sourcePath, deprecation}) => {
|
||||
const relativeSourcePath = path.relative(packagePath, sourcePath)
|
||||
const issueTitle = `Deprecated selector in \`${relativeSourcePath}\``
|
||||
const issueBody = `In \`${relativeSourcePath}\`: \n\n${deprecation.message}`
|
||||
return (
|
||||
<li className='list-item source-file'>
|
||||
<a
|
||||
className='source-url'
|
||||
href={sourcePath}
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.openLocation(sourcePath)
|
||||
}}>{relativeSourcePath}</a>
|
||||
<ul className='list'>
|
||||
<li className='list-item deprecation-detail'>
|
||||
<span className='text-warning icon icon-alert' />
|
||||
<div className='list-item deprecation-message' innerHTML={marked(deprecation.message)} />
|
||||
{this.renderSelectorIssueURLIfNeeded(packageName, issueTitle, issueBody)}
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
renderPackageActionsIfNeeded (packageName) {
|
||||
if (packageName && atom.packages.getLoadedPackage(packageName)) {
|
||||
return (
|
||||
<div className='padded'>
|
||||
<div className='btn-group'>
|
||||
<button
|
||||
className='btn check-for-update'
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.checkForUpdates()
|
||||
}}>Check for Update</button>
|
||||
<button
|
||||
className='btn disable-package'
|
||||
data-package-name={packageName}
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.disablePackage(packageName)
|
||||
}}>Disable Package</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
encodeURI (str) {
|
||||
return encodeURI(str).replace(/#/g, '%23').replace(/;/g, '%3B').replace(/%20/g, '+')
|
||||
}
|
||||
|
||||
renderSelectorIssueURLIfNeeded (packageName, issueTitle, issueBody) {
|
||||
const repoURL = this.getRepoURL(packageName)
|
||||
if (repoURL) {
|
||||
const issueURL = `${repoURL}/issues/new?title=${this.encodeURI(issueTitle)}&body=${this.encodeURI(issueBody)}`
|
||||
return (
|
||||
<div className='btn-toolbar'>
|
||||
<button
|
||||
className='btn issue-url'
|
||||
data-issue-title={issueTitle}
|
||||
data-repo-url={repoURL}
|
||||
data-issue-url={issueURL}
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.openIssueURL(repoURL, issueURL, issueTitle)
|
||||
}}>Report Issue</button>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
renderIssueURLIfNeeded (packageName, deprecation, issueURL) {
|
||||
if (packageName && issueURL) {
|
||||
const repoURL = this.getRepoURL(packageName)
|
||||
const issueTitle = `${deprecation.getOriginName()} is deprecated.`
|
||||
return (
|
||||
<div className='btn-toolbar'>
|
||||
<button
|
||||
className='btn issue-url'
|
||||
data-issue-title={issueTitle}
|
||||
data-repo-url={repoURL}
|
||||
data-issue-url={issueURL}
|
||||
onclick={(event) => {
|
||||
event.preventDefault()
|
||||
this.openIssueURL(repoURL, issueURL, issueTitle)
|
||||
}}>Report Issue</button>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
buildIssueURL (packageName, deprecation, stack) {
|
||||
const repoURL = this.getRepoURL(packageName)
|
||||
if (repoURL) {
|
||||
const title = `${deprecation.getOriginName()} is deprecated.`
|
||||
const stacktrace = stack.map(({functionName, location}) => `${functionName} (${location})`).join("\n")
|
||||
const body = `${deprecation.getMessage()}\n\`\`\`\n${stacktrace}\n\`\`\``
|
||||
return `${repoURL}/issues/new?title=${encodeURI(title)}&body=${encodeURI(body)}`
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async openIssueURL (repoURL, issueURL, issueTitle) {
|
||||
const issue = await this.findSimilarIssue(repoURL, issueTitle)
|
||||
if (issue) {
|
||||
shell.openExternal(issue.html_url)
|
||||
} else if (process.platform === 'win32') {
|
||||
// Windows will not launch URLs greater than ~2000 bytes so we need to shrink it
|
||||
shell.openExternal((await this.shortenURL(issueURL)) || issueURL)
|
||||
} else {
|
||||
shell.openExternal(issueURL)
|
||||
}
|
||||
}
|
||||
|
||||
async findSimilarIssue (repoURL, issueTitle) {
|
||||
const url = 'https://api.github.com/search/issues'
|
||||
const repo = repoURL.replace(/http(s)?:\/\/(\d+\.)?github.com\//gi, '')
|
||||
const query = `${issueTitle} repo:${repo}`
|
||||
const response = await window.fetch(`${url}?q=${encodeURI(query)}&sort=created`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
if (data.items) {
|
||||
const issues = {}
|
||||
for (const issue of data.items) {
|
||||
if (issue.title.includes(issueTitle) && !issues[issue.state]) {
|
||||
issues[issue.state] = issue
|
||||
}
|
||||
}
|
||||
|
||||
return (issues.open || issues.closed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async shortenURL (url) {
|
||||
let encodedUrl = encodeURIComponent(url).substr(0, 5000) // is.gd has 5000 char limit
|
||||
let incompletePercentEncoding = encodedUrl.indexOf('%', encodedUrl.length - 2)
|
||||
if (incompletePercentEncoding >= 0) { // Handle an incomplete % encoding cut-off
|
||||
encodedUrl = encodedUrl.substr(0, incompletePercentEncoding)
|
||||
}
|
||||
|
||||
let result = await fetch('https://is.gd/create.php?format=simple', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: `url=${encodedUrl}`
|
||||
})
|
||||
|
||||
return result.text()
|
||||
}
|
||||
|
||||
getRepoURL (packageName) {
|
||||
const loadedPackage = atom.packages.getLoadedPackage(packageName)
|
||||
if (loadedPackage && loadedPackage.metadata && loadedPackage.metadata.repository) {
|
||||
const url = loadedPackage.metadata.repository.url || loadedPackage.metadata.repository
|
||||
return url.replace(/\.git$/, '')
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
getDeprecatedCallsByPackageName () {
|
||||
const deprecatedCalls = Grim.getDeprecations()
|
||||
deprecatedCalls.sort((a, b) => b.getCallCount() - a.getCallCount())
|
||||
const deprecatedCallsByPackageName = {}
|
||||
for (const deprecation of deprecatedCalls) {
|
||||
const stacks = deprecation.getStacks()
|
||||
stacks.sort((a, b) => b.callCount - a.callCount)
|
||||
for (const stack of stacks) {
|
||||
let packageName = null
|
||||
if (stack.metadata && stack.metadata.packageName) {
|
||||
packageName = stack.metadata.packageName
|
||||
} else {
|
||||
packageName = (this.getPackageName(stack) || '').toLowerCase()
|
||||
}
|
||||
|
||||
deprecatedCallsByPackageName[packageName] = deprecatedCallsByPackageName[packageName] || []
|
||||
deprecatedCallsByPackageName[packageName].push({deprecation, stack})
|
||||
}
|
||||
}
|
||||
return deprecatedCallsByPackageName
|
||||
}
|
||||
|
||||
getDeprecatedSelectorsByPackageName () {
|
||||
const deprecatedSelectorsByPackageName = {}
|
||||
if (atom.styles.getDeprecations) {
|
||||
const deprecatedSelectorsBySourcePath = atom.styles.getDeprecations()
|
||||
for (const sourcePath of Object.keys(deprecatedSelectorsBySourcePath)) {
|
||||
const deprecation = deprecatedSelectorsBySourcePath[sourcePath]
|
||||
const components = sourcePath.split(path.sep)
|
||||
const packagesComponentIndex = components.indexOf('packages')
|
||||
let packageName = null
|
||||
let packagePath = null
|
||||
if (packagesComponentIndex === -1) {
|
||||
packageName = 'Other' // could be Atom Core or the personal style sheet
|
||||
packagePath = ''
|
||||
} else {
|
||||
packageName = components[packagesComponentIndex + 1]
|
||||
packagePath = components.slice(0, packagesComponentIndex + 1).join(path.sep)
|
||||
}
|
||||
|
||||
deprecatedSelectorsByPackageName[packageName] = deprecatedSelectorsByPackageName[packageName] || []
|
||||
deprecatedSelectorsByPackageName[packageName].push({packagePath, sourcePath, deprecation})
|
||||
}
|
||||
}
|
||||
|
||||
return deprecatedSelectorsByPackageName
|
||||
}
|
||||
|
||||
getPackageName (stack) {
|
||||
const packagePaths = this.getPackagePathsByPackageName()
|
||||
for (const [packageName, packagePath] of packagePaths) {
|
||||
if (packagePath.includes('.atom/dev/packages') || packagePath.includes('.atom/packages')) {
|
||||
packagePaths.set(packageName, fs.absolute(packagePath))
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 1; i < stack.length; i++) {
|
||||
const {fileName} = stack[i]
|
||||
|
||||
// Empty when it was run from the dev console
|
||||
if (!fileName) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Continue to next stack entry if call is in node_modules
|
||||
if (fileName.includes(`${path.sep}node_modules${path.sep}`)) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (const [packageName, packagePath] of packagePaths) {
|
||||
const relativePath = path.relative(packagePath, fileName)
|
||||
if (!/^\.\./.test(relativePath)) {
|
||||
return packageName
|
||||
}
|
||||
}
|
||||
|
||||
if (atom.getUserInitScriptPath() === fileName) {
|
||||
return `Your local ${path.basename(fileName)} file`
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
getPackagePathsByPackageName () {
|
||||
if (this.packagePathsByPackageName) {
|
||||
return this.packagePathsByPackageName
|
||||
} else {
|
||||
this.packagePathsByPackageName = new Map()
|
||||
for (const pack of atom.packages.getLoadedPackages()) {
|
||||
this.packagePathsByPackageName.set(pack.name, pack.path)
|
||||
}
|
||||
return this.packagePathsByPackageName
|
||||
}
|
||||
}
|
||||
|
||||
checkForUpdates () {
|
||||
atom.workspace.open('atom://config/updates')
|
||||
}
|
||||
|
||||
disablePackage (packageName) {
|
||||
if (packageName) {
|
||||
atom.packages.disablePackage(packageName)
|
||||
}
|
||||
}
|
||||
|
||||
openLocation (location) {
|
||||
let pathToOpen = location.replace('file://', '')
|
||||
if (process.platform === 'win32') {
|
||||
pathToOpen = pathToOpen.replace(/^\//, '')
|
||||
}
|
||||
atom.open({pathsToOpen: [pathToOpen]})
|
||||
}
|
||||
|
||||
getURI () {
|
||||
return this.uri
|
||||
}
|
||||
|
||||
getTitle () {
|
||||
return 'Deprecation Cop'
|
||||
}
|
||||
|
||||
getIconName () {
|
||||
return 'alert'
|
||||
}
|
||||
|
||||
scrollUp () {
|
||||
this.element.scrollTop -= document.body.offsetHeight / 20
|
||||
}
|
||||
|
||||
scrollDown () {
|
||||
this.element.scrollTop += document.body.offsetHeight / 20
|
||||
}
|
||||
|
||||
pageUp () {
|
||||
this.element.scrollTop -= this.element.offsetHeight
|
||||
}
|
||||
|
||||
pageDown () {
|
||||
this.element.scrollTop += this.element.offsetHeight
|
||||
}
|
||||
|
||||
scrollToTop () {
|
||||
this.element.scrollTop = 0
|
||||
}
|
||||
|
||||
scrollToBottom () {
|
||||
this.element.scrollTop = this.element.scrollHeight
|
||||
}
|
||||
}
|
||||
39
packages/deprecation-cop/lib/main.js
Normal file
39
packages/deprecation-cop/lib/main.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const {Disposable, CompositeDisposable} = require('atom')
|
||||
const DeprecationCopView = require('./deprecation-cop-view')
|
||||
const DeprecationCopStatusBarView = require('./deprecation-cop-status-bar-view')
|
||||
const ViewURI = 'atom://deprecation-cop'
|
||||
|
||||
class DeprecationCopPackage {
|
||||
activate () {
|
||||
this.disposables = new CompositeDisposable()
|
||||
this.disposables.add(atom.workspace.addOpener((uri) => {
|
||||
if (uri === ViewURI) {
|
||||
return this.deserializeDeprecationCopView({uri})
|
||||
}
|
||||
}))
|
||||
this.disposables.add(atom.commands.add('atom-workspace', 'deprecation-cop:view', () => {
|
||||
atom.workspace.open(ViewURI)
|
||||
}))
|
||||
}
|
||||
|
||||
deactivate () {
|
||||
this.disposables.dispose()
|
||||
const pane = atom.workspace.paneForURI(ViewURI)
|
||||
if (pane) {
|
||||
pane.destroyItem(pane.itemForURI(ViewURI))
|
||||
}
|
||||
}
|
||||
|
||||
deserializeDeprecationCopView (state) {
|
||||
return new DeprecationCopView(state)
|
||||
}
|
||||
|
||||
consumeStatusBar (statusBar) {
|
||||
const statusBarView = new DeprecationCopStatusBarView()
|
||||
const statusBarTile = statusBar.addRightTile({item: statusBarView, priority: 150})
|
||||
this.disposables.add(new Disposable(() => { statusBarView.destroy() }))
|
||||
this.disposables.add(new Disposable(() => { statusBarTile.destroy() }))
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new DeprecationCopPackage()
|
||||
31
packages/deprecation-cop/package.json
Normal file
31
packages/deprecation-cop/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "deprecation-cop",
|
||||
"main": "./lib/main",
|
||||
"version": "0.56.9",
|
||||
"description": "Shows a list of deprecated calls",
|
||||
"repository": "https://github.com/atom/atom",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": ">0.50.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"etch": "0.9.0",
|
||||
"fs-plus": "^3.0.0",
|
||||
"grim": "^2.0.1",
|
||||
"marked": "^0.3.6",
|
||||
"underscore-plus": "^1.0.0"
|
||||
},
|
||||
"consumedServices": {
|
||||
"status-bar": {
|
||||
"versions": {
|
||||
"^1.0.0": "consumeStatusBar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deserializers": {
|
||||
"DeprecationCopView": "deserializeDeprecationCopView"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coffeelint": "^1.9.7"
|
||||
}
|
||||
}
|
||||
36
packages/deprecation-cop/spec/deprecation-cop-spec.coffee
Normal file
36
packages/deprecation-cop/spec/deprecation-cop-spec.coffee
Normal file
@@ -0,0 +1,36 @@
|
||||
DeprecationCopView = require '../lib/deprecation-cop-view'
|
||||
|
||||
describe "DeprecationCop", ->
|
||||
[activationPromise, workspaceElement] = []
|
||||
|
||||
beforeEach ->
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
activationPromise = atom.packages.activatePackage('deprecation-cop')
|
||||
expect(atom.workspace.getActivePane().getActiveItem()).not.toExist()
|
||||
|
||||
describe "when the deprecation-cop:view event is triggered", ->
|
||||
it "displays the deprecation cop pane", ->
|
||||
atom.commands.dispatch workspaceElement, 'deprecation-cop:view'
|
||||
|
||||
waitsForPromise ->
|
||||
activationPromise
|
||||
|
||||
deprecationCopView = null
|
||||
waitsFor ->
|
||||
deprecationCopView = atom.workspace.getActivePane().getActiveItem()
|
||||
|
||||
runs ->
|
||||
expect(deprecationCopView instanceof DeprecationCopView).toBeTruthy()
|
||||
|
||||
describe "deactivating the package", ->
|
||||
it "removes the deprecation cop pane item", ->
|
||||
atom.commands.dispatch workspaceElement, 'deprecation-cop:view'
|
||||
|
||||
waitsForPromise ->
|
||||
activationPromise
|
||||
|
||||
waitsForPromise ->
|
||||
Promise.resolve(atom.packages.deactivatePackage('deprecation-cop')) # Wrapped for Promise & non-Promise deactivate
|
||||
|
||||
runs ->
|
||||
expect(atom.workspace.getActivePane().getActiveItem()).not.toExist()
|
||||
@@ -0,0 +1,72 @@
|
||||
path = require 'path'
|
||||
Grim = require 'grim'
|
||||
DeprecationCopView = require '../lib/deprecation-cop-view'
|
||||
_ = require 'underscore-plus'
|
||||
|
||||
describe "DeprecationCopStatusBarView", ->
|
||||
[deprecatedMethod, statusBarView, workspaceElement] = []
|
||||
|
||||
beforeEach ->
|
||||
# jasmine.Clock.useMock() cannot mock _.debounce
|
||||
# http://stackoverflow.com/questions/13707047/spec-for-async-functions-using-jasmine
|
||||
spyOn(_, 'debounce').andCallFake (func) ->
|
||||
-> func.apply(this, arguments)
|
||||
|
||||
jasmine.snapshotDeprecations()
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
waitsForPromise -> atom.packages.activatePackage('status-bar')
|
||||
waitsForPromise -> atom.packages.activatePackage('deprecation-cop')
|
||||
|
||||
waitsFor ->
|
||||
statusBarView = workspaceElement.querySelector('.deprecation-cop-status')
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "adds the status bar view when activated", ->
|
||||
expect(statusBarView).toExist()
|
||||
expect(statusBarView.textContent).toBe '0 deprecations'
|
||||
expect(statusBarView).not.toShow()
|
||||
|
||||
it "increments when there are deprecated methods", ->
|
||||
deprecatedMethod = -> Grim.deprecate("This isn't used")
|
||||
anotherDeprecatedMethod = -> Grim.deprecate("This either")
|
||||
expect(statusBarView.style.display).toBe 'none'
|
||||
expect(statusBarView.offsetHeight).toBe(0)
|
||||
|
||||
deprecatedMethod()
|
||||
expect(statusBarView.textContent).toBe '1 deprecation'
|
||||
expect(statusBarView.offsetHeight).toBeGreaterThan(0)
|
||||
|
||||
deprecatedMethod()
|
||||
expect(statusBarView.textContent).toBe '2 deprecations'
|
||||
expect(statusBarView.offsetHeight).toBeGreaterThan(0)
|
||||
|
||||
anotherDeprecatedMethod()
|
||||
expect(statusBarView.textContent).toBe '3 deprecations'
|
||||
expect(statusBarView.offsetHeight).toBeGreaterThan(0)
|
||||
|
||||
# TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
|
||||
if atom.styles.getDeprecations?
|
||||
it "increments when there are deprecated selectors", ->
|
||||
atom.styles.addStyleSheet("""
|
||||
atom-text-editor::shadow { color: red; }
|
||||
""", sourcePath: 'file-1')
|
||||
expect(statusBarView.textContent).toBe '1 deprecation'
|
||||
expect(statusBarView).toBeVisible()
|
||||
atom.styles.addStyleSheet("""
|
||||
atom-text-editor::shadow { color: blue; }
|
||||
""", sourcePath: 'file-2')
|
||||
expect(statusBarView.textContent).toBe '2 deprecations'
|
||||
expect(statusBarView).toBeVisible()
|
||||
|
||||
it 'opens deprecation cop tab when clicked', ->
|
||||
expect(atom.workspace.getActivePane().getActiveItem()).not.toExist()
|
||||
|
||||
waitsFor (done) ->
|
||||
atom.workspace.onDidOpen ({item}) ->
|
||||
expect(item instanceof DeprecationCopView).toBe true
|
||||
done()
|
||||
statusBarView.click()
|
||||
@@ -0,0 +1,93 @@
|
||||
Grim = require 'grim'
|
||||
path = require 'path'
|
||||
_ = require 'underscore-plus'
|
||||
etch = require 'etch'
|
||||
|
||||
describe "DeprecationCopView", ->
|
||||
[deprecationCopView, workspaceElement] = []
|
||||
|
||||
beforeEach ->
|
||||
spyOn(_, 'debounce').andCallFake (func) ->
|
||||
-> func.apply(this, arguments)
|
||||
|
||||
workspaceElement = atom.views.getView(atom.workspace)
|
||||
jasmine.attachToDOM(workspaceElement)
|
||||
|
||||
jasmine.snapshotDeprecations()
|
||||
Grim.clearDeprecations()
|
||||
deprecatedMethod = -> Grim.deprecate("A test deprecation. This isn't used")
|
||||
deprecatedMethod()
|
||||
|
||||
spyOn(Grim, 'deprecate') # Don't fail tests if when using deprecated APIs in deprecation cop's activation
|
||||
activationPromise = atom.packages.activatePackage('deprecation-cop')
|
||||
|
||||
atom.commands.dispatch workspaceElement, 'deprecation-cop:view'
|
||||
|
||||
waitsForPromise ->
|
||||
activationPromise
|
||||
|
||||
waitsFor -> deprecationCopView = atom.workspace.getActivePane().getActiveItem()
|
||||
|
||||
runs ->
|
||||
jasmine.unspy(Grim, 'deprecate')
|
||||
|
||||
afterEach ->
|
||||
jasmine.restoreDeprecationsSnapshot()
|
||||
|
||||
it "displays deprecated methods", ->
|
||||
expect(deprecationCopView.element.textContent).toMatch /Deprecated calls/
|
||||
expect(deprecationCopView.element.textContent).toMatch /This isn't used/
|
||||
|
||||
# TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
|
||||
if atom.styles.getDeprecations?
|
||||
it "displays deprecated selectors", ->
|
||||
atom.styles.addStyleSheet("atom-text-editor::shadow { color: red }", sourcePath: path.join('some-dir', 'packages', 'package-1', 'file-1.css'))
|
||||
atom.styles.addStyleSheet("atom-text-editor::shadow { color: yellow }", context: 'atom-text-editor', sourcePath: path.join('some-dir', 'packages', 'package-1', 'file-2.css'))
|
||||
atom.styles.addStyleSheet('atom-text-editor::shadow { color: blue }', sourcePath: path.join('another-dir', 'packages', 'package-2', 'file-3.css'))
|
||||
atom.styles.addStyleSheet('atom-text-editor::shadow { color: gray }', sourcePath: path.join('another-dir', 'node_modules', 'package-3', 'file-4.css'))
|
||||
|
||||
promise = etch.getScheduler().getNextUpdatePromise()
|
||||
waitsForPromise -> promise
|
||||
|
||||
runs ->
|
||||
packageItems = deprecationCopView.element.querySelectorAll("ul.selectors > li")
|
||||
expect(packageItems.length).toBe(3)
|
||||
expect(packageItems[0].textContent).toMatch /package-1/
|
||||
expect(packageItems[1].textContent).toMatch /package-2/
|
||||
expect(packageItems[2].textContent).toMatch /Other/
|
||||
|
||||
packageDeprecationItems = packageItems[0].querySelectorAll("li.source-file")
|
||||
expect(packageDeprecationItems.length).toBe(2)
|
||||
expect(packageDeprecationItems[0].textContent).toMatch /atom-text-editor/
|
||||
expect(packageDeprecationItems[0].querySelector("a").href).toMatch('some-dir/packages/package-1/file-1.css')
|
||||
expect(packageDeprecationItems[1].textContent).toMatch /:host/
|
||||
expect(packageDeprecationItems[1].querySelector("a").href).toMatch('some-dir/packages/package-1/file-2.css')
|
||||
|
||||
it 'skips stack entries which go through node_modules/ files when determining package name', ->
|
||||
stack = [
|
||||
{
|
||||
"functionName": "function0"
|
||||
"location": path.normalize "/Users/user/.atom/packages/package1/node_modules/atom-space-pen-viewslib/space-pen.js:55:66"
|
||||
"fileName": path.normalize "/Users/user/.atom/packages/package1/node_modules/atom-space-pen-views/lib/space-pen.js"
|
||||
}
|
||||
{
|
||||
"functionName": "function1"
|
||||
"location": path.normalize "/Users/user/.atom/packages/package1/node_modules/atom-space-pen-viewslib/space-pen.js:15:16"
|
||||
"fileName": path.normalize "/Users/user/.atom/packages/package1/node_modules/atom-space-pen-views/lib/space-pen.js"
|
||||
}
|
||||
{
|
||||
"functionName": "function2"
|
||||
"location": path.normalize "/Users/user/.atom/packages/package2/lib/module.js:13:14"
|
||||
"fileName": path.normalize "/Users/user/.atom/packages/package2/lib/module.js"
|
||||
}
|
||||
]
|
||||
|
||||
packagePathsByPackageName = new Map([
|
||||
['package1', path.normalize("/Users/user/.atom/packages/package1")],
|
||||
['package2', path.normalize("/Users/user/.atom/packages/package2")]
|
||||
])
|
||||
|
||||
spyOn(deprecationCopView, 'getPackagePathsByPackageName').andReturn(packagePathsByPackageName)
|
||||
|
||||
packageName = deprecationCopView.getPackageName(stack)
|
||||
expect(packageName).toBe("package2")
|
||||
72
packages/deprecation-cop/styles/deprecation-cop.less
Normal file
72
packages/deprecation-cop/styles/deprecation-cop.less
Normal file
@@ -0,0 +1,72 @@
|
||||
// The ui-variables file is provided by base themes provided by Atom.
|
||||
//
|
||||
// See https://github.com/atom/atom-dark-ui/blob/master/stylesheets/ui-variables.less
|
||||
// for a full listing of what's available.
|
||||
@import "ui-variables";
|
||||
|
||||
.deprecation-cop-status {
|
||||
.icon.icon-alert:before {
|
||||
// It's a really big icon...
|
||||
width: 17px;
|
||||
}
|
||||
}
|
||||
.deprecation-cop {
|
||||
overflow: auto;
|
||||
-webkit-flex: 1;
|
||||
background-color: @app-background-color !important;
|
||||
|
||||
.deprecation-overview {
|
||||
&:after {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.deprecation-info {
|
||||
padding: 0 @component-padding;
|
||||
}
|
||||
|
||||
.deprecation-info:hover {
|
||||
background-color: @background-color-selected !important;
|
||||
}
|
||||
|
||||
.deprecation-detail.list-item {
|
||||
white-space: normal;
|
||||
clear: both;
|
||||
|
||||
.deprecation-message {
|
||||
padding: 5px 0 5px 28px;
|
||||
line-height: 1.4;
|
||||
font-size: @font-size;
|
||||
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-alert {
|
||||
margin-top: 5px;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed > ul {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.list {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.stack-trace {
|
||||
background-color: @tool-panel-background-color;
|
||||
padding: @component-padding;
|
||||
margin-bottom: @component-padding;
|
||||
}
|
||||
|
||||
a {
|
||||
color: @text-color-highlight;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user