Merge branch 'master' into add-markdown-tree-sitter-grammar

This commit is contained in:
Andrew Dupont 2023-08-14 14:01:02 -07:00
commit e293df1ab1
54 changed files with 2582 additions and 385 deletions

View File

@ -1,6 +1,6 @@
env:
PYTHON_VERSION: 3.10
GITHUB_TOKEN: ENCRYPTED[13da504dc34d1608564d891fb7f456b546019d07d1abb059f9ab4296c56ccc0e6e32c7b313629776eda40ab74a54e95c]
GITHUB_TOKEN: ENCRYPTED[!b0ff4671044672be50914a3a10b49af642bd8e0e681a6f4e5855ec5230a5cf9afbc53d9e90239b8d2c79455f014f383f!]
# The above token, is a GitHub API Token, that allows us to download RipGrep without concern of API limits
linux_task:

View File

@ -104,6 +104,7 @@ jobs:
- package: "notifications"
- package: "open-on-github"
- package: "package-generator"
- package: "pulsar-updater"
- package: "settings-view"
- package: "snippets"
- package: "spell-check"

View File

@ -145,6 +145,7 @@
"postcss": "8.2.13",
"postcss-selector-parser": "6.0.4",
"property-accessors": "^1.1.3",
"pulsar-updater": "file:packages/pulsar-updater",
"resolve": "1.18.1",
"scandal": "^3.2.0",
"scoped-property-store": "^0.17.0",
@ -226,6 +227,7 @@
"notifications": "file:./packages/notifications",
"open-on-github": "file:./packages/open-on-github",
"package-generator": "file:./packages/package-generator",
"pulsar-updater": "file:./packages/pulsar-updater",
"settings-view": "file:./packages/settings-view",
"snippets": "1.6.1",
"spell-check": "file:./packages/spell-check",

View File

@ -85,6 +85,7 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
| **open-on-github** | [`./open-on-github`](./open-on-github) | |
| **settings-view** | [`./settings-view`](./settings-view) | |
| **package-generator** | [`./package-generator`](./package-generator) | |
| **pulsar-updater** | [`./pulsar-updater`](./pulsar-updater) | |
| **snippets** | [`pulsar-edit/snippets`][snippets] | |
| **solarized-dark-syntax** | [`./solarized-dark-syntax`](./solarized-dark-syntax) | |
| **solarized-light-syntax** | [`./solarized-light-syntax`](./solarized-light-syntax) | |

View File

@ -1,6 +0,0 @@
provider = require './provider'
module.exports =
activate: -> provider.load()
getProvider: -> provider

View File

@ -0,0 +1,7 @@
const provider = require('./provider');
module.exports = {
activate() { return provider.load(); },
getProvider() { return provider; }
};

View File

@ -1,97 +0,0 @@
fs = require 'fs'
path = require 'path'
CLASSES = require('../completions.json')
propertyPrefixPattern = /(?:^|\[|\(|,|=|:|\s)\s*(atom\.(?:[a-zA-Z]+\.?){0,2})$/
module.exports =
selector: '.source.coffee, .source.js'
filterSuggestions: true
getSuggestions: ({bufferPosition, editor}) ->
return unless @isEditingAnAtomPackageFile(editor)
line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition])
@getCompletions(line)
load: ->
@loadCompletions()
atom.project.onDidChangePaths => @scanProjectDirectories()
@scanProjectDirectories()
scanProjectDirectories: ->
@packageDirectories = []
atom.project.getDirectories().forEach (directory) =>
return unless directory?
@readMetadata directory, (error, metadata) =>
if @isAtomPackage(metadata) or @isAtomCore(metadata)
@packageDirectories.push(directory)
readMetadata: (directory, callback) ->
fs.readFile path.join(directory.getPath(), 'package.json'), (error, contents) ->
unless error?
try
metadata = JSON.parse(contents)
catch parseError
error = parseError
callback(error, metadata)
isAtomPackage: (metadata) ->
metadata?.engines?.atom?.length > 0
isAtomCore: (metadata) ->
metadata?.name is 'atom'
isEditingAnAtomPackageFile: (editor) ->
editorPath = editor.getPath()
if editorPath?
parsedPath = path.parse(editorPath)
basename = path.basename(parsedPath.dir)
if basename is '.atom' or basename is '.pulsar'
if parsedPath.base is 'init.coffee' or parsedPath.base is 'init.js'
return true
for directory in @packageDirectories ? []
return true if directory.contains(editorPath)
false
loadCompletions: ->
@completions ?= {}
@loadProperty('atom', 'AtomEnvironment', CLASSES)
getCompletions: (line) ->
completions = []
match = propertyPrefixPattern.exec(line)?[1]
return completions unless match
segments = match.split('.')
prefix = segments.pop() ? ''
segments = segments.filter (segment) -> segment
property = segments[segments.length - 1]
propertyCompletions = @completions[property]?.completions ? []
for completion in propertyCompletions when not prefix or firstCharsEqual(completion.name, prefix)
completions.push(clone(completion))
completions
getPropertyClass: (name) ->
atom[name]?.constructor?.name
loadProperty: (propertyName, className, classes, parent) ->
classCompletions = classes[className]
return unless classCompletions?
@completions[propertyName] = completions: []
for completion in classCompletions
@completions[propertyName].completions.push(completion)
if completion.type is 'property'
propertyClass = @getPropertyClass(completion.name)
@loadProperty(completion.name, propertyClass, classes)
return
clone = (obj) ->
newObj = {}
newObj[k] = v for k, v of obj
newObj
firstCharsEqual = (str1, str2) ->
str1[0].toLowerCase() is str2[0].toLowerCase()

View File

@ -0,0 +1,125 @@
const fs = require('fs');
const path = require('path');
const CLASSES = require('../completions.json');
const propertyPrefixPattern = /(?:^|\[|\(|,|=|:|\s)\s*(atom\.(?:[a-zA-Z]+\.?){0,2})$/;
module.exports = {
selector: '.source.coffee, .source.js',
filterSuggestions: true,
getSuggestions({bufferPosition, editor}) {
if (!this.isEditingAnAtomPackageFile(editor)) { return; }
const line = editor.getTextInRange([[bufferPosition.row, 0], bufferPosition]);
return this.getCompletions(line);
},
load() {
this.loadCompletions();
atom.project.onDidChangePaths(() => this.scanProjectDirectories());
return this.scanProjectDirectories();
},
scanProjectDirectories() {
this.packageDirectories = [];
atom.project.getDirectories().forEach(directory => {
if (directory == null) { return; }
this.readMetadata(directory, (error, metadata) => {
if (this.isAtomPackage(metadata) || this.isAtomCore(metadata)) {
this.packageDirectories.push(directory);
}
});
});
},
readMetadata(directory, callback) {
fs.readFile(path.join(directory.getPath(), 'package.json'), function(error, contents) {
let metadata;
if (error == null) {
try {
metadata = JSON.parse(contents);
} catch (parseError) {
error = parseError;
}
}
return callback(error, metadata);
});
},
isAtomPackage(metadata) {
return metadata?.engines?.atom?.length > 0;
},
isAtomCore(metadata) {
return metadata?.name === 'atom';
},
isEditingAnAtomPackageFile(editor) {
const editorPath = editor.getPath();
if (editorPath != null) {
const parsedPath = path.parse(editorPath);
const basename = path.basename(parsedPath.dir);
if ((basename === '.atom') || (basename === '.pulsar')) {
if ((parsedPath.base === 'init.coffee') || (parsedPath.base === 'init.js')) {
return true;
}
}
}
for (let directory of (this.packageDirectories != null ? this.packageDirectories : [])) {
if (directory.contains(editorPath)) { return true; }
}
return false;
},
loadCompletions() {
if (this.completions == null) { this.completions = {}; }
return this.loadProperty('atom', 'AtomEnvironment', CLASSES);
},
getCompletions(line) {
const completions = [];
const match = propertyPrefixPattern.exec(line)?.[1];
if (!match) { return completions; }
let segments = match.split('.');
const prefix = segments.pop() ?? '';
segments = segments.filter(segment => segment);
const property = segments[segments.length - 1];
const propertyCompletions = this.completions[property]?.completions != null ? this.completions[property]?.completions : [];
for (let completion of propertyCompletions) {
if (!prefix || firstCharsEqual(completion.name, prefix)) {
completions.push(clone(completion));
}
}
return completions;
},
getPropertyClass(name) {
return atom[name]?.constructor?.name;
},
loadProperty(propertyName, className, classes, parent) {
const classCompletions = classes[className];
if (classCompletions == null) { return; }
this.completions[propertyName] = {completions: []};
for (let completion of classCompletions) {
this.completions[propertyName].completions.push(completion);
if (completion.type === 'property') {
const propertyClass = this.getPropertyClass(completion.name);
this.loadProperty(completion.name, propertyClass, classes);
}
}
}
};
const clone = function(obj) {
const newObj = {};
for (let k in obj) { const v = obj[k]; newObj[k] = v; }
return newObj;
};
const firstCharsEqual = (str1, str2) => str1[0].toLowerCase() === str2[0].toLowerCase();

View File

@ -1,142 +0,0 @@
_ = require 'underscore-plus'
CharacterPattern = ///
[
^\s
]
///
module.exports =
activate: ->
@commandDisposable = atom.commands.add 'atom-text-editor',
'autoflow:reflow-selection': (event) =>
@reflowSelection(event.currentTarget.getModel())
deactivate: ->
@commandDisposable?.dispose()
@commandDisposable = null
reflowSelection: (editor) ->
range = editor.getSelectedBufferRange()
range = editor.getCurrentParagraphBufferRange() if range.isEmpty()
return unless range?
reflowOptions =
wrapColumn: @getPreferredLineLength(editor)
tabLength: @getTabLength(editor)
reflowedText = @reflow(editor.getTextInRange(range), reflowOptions)
editor.getBuffer().setTextInRange(range, reflowedText)
reflow: (text, {wrapColumn, tabLength}) ->
paragraphs = []
# Convert all \r\n and \r to \n. The text buffer will normalize them later
text = text.replace(/\r\n?/g, '\n')
leadingVerticalSpace = text.match(/^\s*\n/)
if leadingVerticalSpace
text = text.substr(leadingVerticalSpace.length)
else
leadingVerticalSpace = ''
trailingVerticalSpace = text.match(/\n\s*$/)
if trailingVerticalSpace
text = text.substr(0, text.length - trailingVerticalSpace.length)
else
trailingVerticalSpace = ''
paragraphBlocks = text.split(/\n\s*\n/g)
if tabLength
tabLengthInSpaces = Array(tabLength + 1).join(' ')
else
tabLengthInSpaces = ''
for block in paragraphBlocks
blockLines = block.split('\n')
# For LaTeX tags surrounding the text, we simply ignore them, and
# reproduce them verbatim in the wrapped text.
beginningLinesToIgnore = []
endingLinesToIgnore = []
latexTagRegex = /^\s*\\\w+(\[.*\])?\{\w+\}(\[.*\])?\s*$/g # e.g. \begin{verbatim}
latexTagStartRegex = /^\s*\\\w+\s*\{\s*$/g # e.g. \item{
latexTagEndRegex = /^\s*\}\s*$/g # e.g. }
while blockLines.length > 0 and (
blockLines[0].match(latexTagRegex) or
blockLines[0].match(latexTagStartRegex))
beginningLinesToIgnore.push(blockLines[0])
blockLines.shift()
while blockLines.length > 0 and (
blockLines[blockLines.length - 1].match(latexTagRegex) or
blockLines[blockLines.length - 1].match(latexTagEndRegex))
endingLinesToIgnore.unshift(blockLines[blockLines.length - 1])
blockLines.pop()
# The paragraph might be a LaTeX section with no text, only tags:
# \documentclass{article}
# In that case, we have nothing to reflow.
# Push the tags verbatim and continue to the next paragraph.
unless blockLines.length > 0
paragraphs.push(block)
continue
# TODO: this could be more language specific. Use the actual comment char.
# Remember that `-` has to be the last character in the character class.
linePrefix = blockLines[0].match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0]
linePrefixTabExpanded = linePrefix
if tabLengthInSpaces
linePrefixTabExpanded = linePrefix.replace(/\t/g, tabLengthInSpaces)
if linePrefix
escapedLinePrefix = _.escapeRegExp(linePrefix)
blockLines = blockLines.map (blockLine) ->
blockLine.replace(///^#{escapedLinePrefix}///, '')
blockLines = blockLines.map (blockLine) ->
blockLine.replace(/^\s+/, '')
lines = []
currentLine = []
currentLineLength = linePrefixTabExpanded.length
wrappedLinePrefix = linePrefix
.replace(/^(\s*)\/\*/, '$1 ')
.replace(/^(\s*)-(?!-)/, '$1 ')
firstLine = true
for segment in @segmentText(blockLines.join(' '))
if @wrapSegment(segment, currentLineLength, wrapColumn)
# Independent of line prefix don't mess with it on the first line
if firstLine isnt true
# Handle C comments
if linePrefix.search(/^\s*\/\*/) isnt -1 or linePrefix.search(/^\s*-(?!-)/) isnt -1
linePrefix = wrappedLinePrefix
lines.push(linePrefix + currentLine.join(''))
currentLine = []
currentLineLength = linePrefixTabExpanded.length
firstLine = false
currentLine.push(segment)
currentLineLength += segment.length
lines.push(linePrefix + currentLine.join(''))
wrappedLines = beginningLinesToIgnore.concat(lines.concat(endingLinesToIgnore))
paragraphs.push(wrappedLines.join('\n').replace(/\s+\n/g, '\n'))
return leadingVerticalSpace + paragraphs.join('\n\n') + trailingVerticalSpace
getTabLength: (editor) ->
atom.config.get('editor.tabLength', scope: editor.getRootScopeDescriptor()) ? 2
getPreferredLineLength: (editor) ->
atom.config.get('editor.preferredLineLength', scope: editor.getRootScopeDescriptor())
wrapSegment: (segment, currentLineLength, wrapColumn) ->
CharacterPattern.test(segment) and
(currentLineLength + segment.length > wrapColumn) and
(currentLineLength > 0 or segment.length < wrapColumn)
segmentText: (text) ->
segments = []
re = /[\s]+|[^\s]+/g
segments.push(match[0]) while match = re.exec(text)
segments

View File

@ -0,0 +1,165 @@
const _ = require('underscore-plus');
const CharacterPattern = new RegExp(/[^\s]/);
module.exports = {
activate() {
this.commandDisposable = atom.commands.add('atom-text-editor', {
'autoflow:reflow-selection': event => {
this.reflowSelection(event.currentTarget.getModel());
}
}
);
},
deactivate() {
this.commandDisposable?.dispose();
this.commandDisposable = null;
},
reflowSelection(editor) {
let range = editor.getSelectedBufferRange();
if (range.isEmpty()) { range = editor.getCurrentParagraphBufferRange(); }
if (range == null) { return; }
const reflowOptions = {
wrapColumn: this.getPreferredLineLength(editor),
tabLength: this.getTabLength(editor)
};
const reflowedText = this.reflow(editor.getTextInRange(range), reflowOptions);
return editor.getBuffer().setTextInRange(range, reflowedText);
},
reflow(text, {wrapColumn, tabLength}) {
let tabLengthInSpaces;
const paragraphs = [];
// Convert all \r\n and \r to \n. The text buffer will normalize them later
text = text.replace(/\r\n?/g, '\n');
let leadingVerticalSpace = text.match(/^\s*\n/);
if (leadingVerticalSpace) {
text = text.substr(leadingVerticalSpace.length);
} else {
leadingVerticalSpace = '';
}
let trailingVerticalSpace = text.match(/\n\s*$/);
if (trailingVerticalSpace) {
text = text.substr(0, text.length - trailingVerticalSpace.length);
} else {
trailingVerticalSpace = '';
}
const paragraphBlocks = text.split(/\n\s*\n/g);
if (tabLength) {
tabLengthInSpaces = Array(tabLength + 1).join(' ');
} else {
tabLengthInSpaces = '';
}
for (let block of paragraphBlocks) {
let blockLines = block.split('\n');
// For LaTeX tags surrounding the text, we simply ignore them, and
// reproduce them verbatim in the wrapped text.
const beginningLinesToIgnore = [];
const endingLinesToIgnore = [];
const latexTagRegex = /^\s*\\\w+(\[.*\])?\{\w+\}(\[.*\])?\s*$/g; // e.g. \begin{verbatim}
const latexTagStartRegex = /^\s*\\\w+\s*\{\s*$/g; // e.g. \item{
const latexTagEndRegex = /^\s*\}\s*$/g; // e.g. }
while ((blockLines.length > 0) && (
blockLines[0].match(latexTagRegex) ||
blockLines[0].match(latexTagStartRegex))) {
beginningLinesToIgnore.push(blockLines[0]);
blockLines.shift();
}
while ((blockLines.length > 0) && (
blockLines[blockLines.length - 1].match(latexTagRegex) ||
blockLines[blockLines.length - 1].match(latexTagEndRegex))) {
endingLinesToIgnore.unshift(blockLines[blockLines.length - 1]);
blockLines.pop();
}
// The paragraph might be a LaTeX section with no text, only tags:
// \documentclass{article}
// In that case, we have nothing to reflow.
// Push the tags verbatim and continue to the next paragraph.
if (!(blockLines.length > 0)) {
paragraphs.push(block);
continue;
}
// TODO: this could be more language specific. Use the actual comment char.
// Remember that `-` has to be the last character in the character class.
let linePrefix = blockLines[0].match(/^\s*(\/\/|\/\*|;;|#'|\|\|\||--|[#%*>-])?\s*/g)[0];
let linePrefixTabExpanded = linePrefix;
if (tabLengthInSpaces) {
linePrefixTabExpanded = linePrefix.replace(/\t/g, tabLengthInSpaces);
}
if (linePrefix) {
var escapedLinePrefix = _.escapeRegExp(linePrefix);
blockLines = blockLines.map(blockLine => blockLine.replace(new RegExp(`^${escapedLinePrefix}`), ''));
}
blockLines = blockLines.map(blockLine => blockLine.replace(/^\s+/, ''));
const lines = [];
let currentLine = [];
let currentLineLength = linePrefixTabExpanded.length;
const wrappedLinePrefix = linePrefix
.replace(/^(\s*)\/\*/, '$1 ')
.replace(/^(\s*)-(?!-)/, '$1 ');
let firstLine = true;
for (let segment of this.segmentText(blockLines.join(' '))) {
if (this.wrapSegment(segment, currentLineLength, wrapColumn)) {
// Independent of line prefix don't mess with it on the first line
if (firstLine !== true) {
// Handle C comments
if ((linePrefix.search(/^\s*\/\*/) !== -1) || (linePrefix.search(/^\s*-(?!-)/) !== -1)) {
linePrefix = wrappedLinePrefix;
}
}
lines.push(linePrefix + currentLine.join(''));
currentLine = [];
currentLineLength = linePrefixTabExpanded.length;
firstLine = false;
}
currentLine.push(segment);
currentLineLength += segment.length;
}
lines.push(linePrefix + currentLine.join(''));
const wrappedLines = beginningLinesToIgnore.concat(lines.concat(endingLinesToIgnore));
paragraphs.push(wrappedLines.join('\n').replace(/\s+\n/g, '\n'));
}
return leadingVerticalSpace + paragraphs.join('\n\n') + trailingVerticalSpace;
},
getTabLength(editor) {
return atom.config.get('editor.tabLength', { scope: editor.getRootScopeDescriptor() }) ?? 2;
},
getPreferredLineLength(editor) {
return atom.config.get('editor.preferredLineLength', {scope: editor.getRootScopeDescriptor()});
},
wrapSegment(segment, currentLineLength, wrapColumn) {
return CharacterPattern.test(segment) &&
((currentLineLength + segment.length) > wrapColumn) &&
((currentLineLength > 0) || (segment.length < wrapColumn));
},
segmentText(text) {
let match;
const segments = [];
const re = /[\s]+|[^\s]+/g;
while ((match = re.exec(text))) { segments.push(match[0]); }
return segments;
}
};

View File

@ -1,68 +0,0 @@
{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 = ''

View File

@ -0,0 +1,104 @@
const { CompositeDisposable, Disposable } = require("atom");
const _ = require("underscore-plus");
const Grim = require("grim");
module.exports = class DeprecationCopStatusBarView {
static lastLength = null;
static toolTipDisposable = null;
constructor() {
this.update = this.update.bind(this);
this.subscriptions = new CompositeDisposable();
this.element = document.createElement("div");
this.element.classList.add(
"deprecation-cop-status",
"inline-block",
"text-warning"
);
this.element.setAttribute("tabindex", -1);
this.icon = document.createElement("span");
this.icon.classList.add("icon", "icon-alert");
this.element.appendChild(this.icon);
this.deprecationNumber = document.createElement("span");
this.deprecationNumber.classList.add("deprecation-number");
this.deprecationNumber.textContent = "0";
this.element.appendChild(this.deprecationNumber);
const clickHandler = function () {
const workspaceElement = atom.views.getView(atom.workspace);
atom.commands.dispatch(workspaceElement, "deprecation-cop:view");
};
this.element.addEventListener("click", clickHandler);
this.subscriptions.add(
new Disposable(() =>
this.element.removeEventListener("click", clickHandler)
)
);
this.update();
const debouncedUpdateDeprecatedSelectorCount = _.debounce(
this.update,
1000
);
this.subscriptions.add(Grim.on("updated", this.update));
// TODO: Remove conditional when the new StyleManager deprecation APIs reach stable.
if (atom.styles.onDidUpdateDeprecations != null) {
this.subscriptions.add(
atom.styles.onDidUpdateDeprecations(
debouncedUpdateDeprecatedSelectorCount
)
);
}
}
destroy() {
this.subscriptions.dispose();
this.element.remove();
}
getDeprecatedCallCount() {
return 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 != null) {
return Object.keys(atom.styles.getDeprecations()).length;
} else {
return 0;
}
}
update() {
const length =
this.getDeprecatedCallCount() + this.getDeprecatedStyleSheetsCount();
if (this.lastLength === length) {
return;
}
this.lastLength = length;
this.deprecationNumber.textContent = `${_.pluralize(
length,
"deprecation"
)}`;
this.toolTipDisposable?.dispose();
this.toolTipDisposable = atom.tooltips.add(this.element, {
title: `${_.pluralize(length, "call")} to deprecated methods`,
});
if (length === 0) {
return (this.element.style.display = "none");
} else {
return (this.element.style.display = "");
}
}
};

View File

@ -8,6 +8,12 @@ injectionRegex: '^(c|C)$'
treeSitter:
grammar: 'tree-sitter-c/tree-sitter-c.wasm'
highlightsQuery: 'tree-sitter-c/highlights.scm'
localsQuery: 'tree-sitter-c/locals.scm'
tagsQuery: 'tree-sitter-c/tags.scm'
foldsQuery: 'tree-sitter-c/folds.scm'
indentsQuery: 'tree-sitter-c/indents.scm'
fileTypes: [
'h'
'c'
'h.in'
]

View File

@ -3,11 +3,33 @@ scopeName: 'source.cpp'
type: 'modern-tree-sitter'
parser: 'tree-sitter-cpp'
injectionRegex: '^(cpp|CPP|cc|CC)$'
injectionRegex: '^(c|C)(\\+\\+|pp|PP)$'
treeSitter:
grammar: 'tree-sitter-cpp/tree-sitter-cpp.wasm'
highlightsQuery: 'tree-sitter-cpp/highlights.scm'
localsQuery: 'tree-sitter-cpp/locals.scm'
tagsQuery: 'tree-sitter-cpp/tags.scm'
foldsQuery: 'tree-sitter-cpp/folds.scm'
indentsQuery: 'tree-sitter-cpp/indents.scm'
fileTypes: [
'cc'
'cpp'
'cp'
'cxx'
'c++'
'cu'
'cuh'
'h'
'hh'
'hpp'
'hxx'
'h++'
'inl'
'ino'
'ipp'
'tcc'
'tpp'
]
contentRegex: '\n\\s*(namespace|class|template)\\s+'

View File

@ -0,0 +1,2 @@
((function_declarator (identifier) @name))

View File

@ -0,0 +1,2 @@
((function_declarator (identifier) @name))

View File

@ -11,6 +11,7 @@ treeSitter:
grammar: 'tree-sitter/tree-sitter-css.wasm'
highlightsQuery: 'tree-sitter/queries/highlights.scm'
foldsQuery: 'tree-sitter/queries/folds.scm'
tagsQuery: 'tree-sitter/queries/tags.scm'
indentsQuery: 'tree-sitter/queries/indents.scm'
injectionRegex: '^(css|CSS)$'

View File

@ -0,0 +1 @@
(selectors) @name

View File

@ -13,5 +13,6 @@ comments:
treeSitter:
grammar: 'tree-sitter-java/tree-sitter-java.wasm'
highlightsQuery: 'tree-sitter-java/highlights.scm'
tagsQuery: 'tree-sitter-java/tags.scm'
indentsQuery: 'tree-sitter-java/indents.scm'
foldsQuery: 'tree-sitter-java/folds.scm'

View File

@ -0,0 +1,21 @@
(class_declaration
name: (identifier) @name) @definition.class
(method_declaration
name: (identifier) @name) @definition.method
(method_invocation
name: (identifier) @name
arguments: (argument_list) @reference.call)
(interface_declaration
name: (identifier) @name) @definition.interface
; TODO: Update parser
; (type_list
; (type_identifier) @name) @reference.implementation
(object_creation_expression
type: (type_identifier) @name) @reference.class
(superclass (type_identifier) @name) @reference.class

View File

@ -3,7 +3,7 @@ scopeName: 'source.js'
type: 'modern-tree-sitter'
parser: 'tree-sitter-javascript'
injectionRegex: '^(js|javascript)$'
injectionRegex: '^(js|javascript|JS|JAVASCRIPT)$'
treeSitter:
grammar: 'ts/grammar.wasm'
highlightsQuery: 'ts/highlights.scm'

View File

@ -11,16 +11,30 @@
(
(comment)* @doc
.
[
(class
name: (_) @name)
(class_declaration
name: (_) @name)
] @definition.class
(#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
(#select-adjacent! @doc @definition.class)
(class_declaration
name: (_) @name) @definition.class
)
(
(comment)* @doc
.
(class
name: (_) @name) @definition.class
)
; (
; (comment)* @doc
; .
; [
; (class
; name: (_) @name)
; (class_declaration
; name: (_) @name)
; ] @definition.class
; (#strip! @doc "^[\\s\\*/]+|^[\\s\\*/]$")
; (#select-adjacent! @doc @definition.class)
; )
(
(comment)* @doc
.

View File

@ -70,7 +70,7 @@ exports.activate = function() {
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
const HYPERLINK_PATTERN = /\bhttps?:/
for (const scopeName of ['source.js', 'source.flow', 'source.ts']) {
for (const scopeName of ['source.js', 'source.ts', 'source.ts.tsx']) {
atom.grammars.addInjectionPoint(scopeName, {
type: 'comment',
language(comment) {
@ -105,27 +105,6 @@ exports.activate = function() {
});
}
// atom.grammars.addInjectionPoint(scopeName, {
// type: 'program',
// language: () => 'todo',
// content: (node) => {
// return node.descendantsOfType('comment');
// },
// languageScope: null
// });
//
// atom.grammars.addInjectionPoint(scopeName, {
// type: 'program',
// language: () => 'hyperlink',
// content: (node) => {
// return node.descendantsOfType([
// 'template_string',
// 'string_fragment',
// 'comment'
// ]);
// },
// languageScope: null
// });
}
};

View File

@ -10,6 +10,7 @@ treeSitter:
highlightsQuery: 'tree-sitter/queries/highlights.scm'
indentsQuery: 'tree-sitter/queries/indents.scm'
foldsQuery: 'tree-sitter/queries/folds.scm'
tagsQuery: 'tree-sitter/queries/tags.scm'
fileTypes: [
'avsc'

View File

@ -0,0 +1,9 @@
; All JSON keys are symbols as long as they descend from a chain of objects.
; Nested keys try to prepend the symbol name of their parent's key.
(pair key: (string (string_content) @name
(#is-not? test.descendantOfType "array")
(#set! symbol.prependSymbolForNode parent.parent.parent.previousNamedSibling.firstNamedChild)
(#set! symbol.contextNode parent.parent.parent.previousNamedSibling.firstNamedChild)
(#set! symbol.joiner ".")))

View File

@ -31,6 +31,6 @@ treeSitter:
# to add support for `match` statements.
grammar: 'ts/tree-sitter-python.wasm'
highlightsQuery: 'ts/highlights.scm'
localsQuery: 'ts/locals.scm'
tagsQuery: 'ts/tags.scm'
foldsQuery: 'ts/folds.scm'
indentsQuery: 'ts/indents.scm'

View File

@ -0,0 +1,12 @@
(class_definition
name: (identifier) @name) @definition.class
(function_definition
name: (identifier) @name) @definition.function
(call
function: [
(identifier) @name
(attribute
attribute: (identifier) @name)
]) @reference.call

View File

@ -1,17 +1,29 @@
exports.activate = function () {
if (!atom.grammars.addInjectionPoint) return;
// TODO: Uncomment when performance is acceptable.
const TODO_PATTERN = /\b(TODO|FIXME|CHANGED|XXX|IDEA|HACK|NOTE|REVIEW|NB|BUG|QUESTION|COMBAK|TEMP|DEBUG|OPTIMIZE|WARNING)\b/;
const HYPERLINK_PATTERN = /\bhttps?:/
// atom.grammars.addInjectionPoint('source.python', {
// type: 'string',
// language() {
// return 'hyperlink';
// },
// content(node) {
// return node;
// }
// });
atom.grammars.addInjectionPoint('source.python', {
type: 'comment',
language: (node) => {
return TODO_PATTERN.test(node.text) ? 'todo' : undefined;
},
content: (node) => node,
languageScope: null
});
for (let type of ['comment', 'string']) {
atom.grammars.addInjectionPoint('source.python', {
type,
language(node) {
return HYPERLINK_PATTERN.test(node.text) ?
'hyperlink' : undefined;
},
content: (node) => node,
languageScope: null
});
}
// TODO: There's no regex literal in Python. The TM-style grammar has a
// very obscure option that, when enabled, assumes all raw strings are

View File

@ -3,13 +3,13 @@
name: [
(constant) @name
(scope_resolution name: (_) @name)
])
]) @definition.class
(singleton_class
value: [
(constant) @name
(scope_resolution name: (_) @name)
])
]) @definition.class
; Module names
(module
@ -17,11 +17,11 @@
(constant) @name
(scope_resolution
name: (_) @name)
])
]) @definition.module
; Method names
(method name: (_) @name)
(singleton_method name: (_) @name)
(method name: (_) @name) @definition.method
(singleton_method name: (_) @name) @definition.method
; Aliased methods
(alias name: (_) @name)
(alias name: (_) @name) @definition.method

View File

@ -9,7 +9,6 @@ exports.activate = function() {
content(node) {
return node.descendantsOfType('heredoc_content')
},
// coverShallowerScopes: true
});
atom.grammars.addInjectionPoint('source.ruby', {

View File

@ -15,5 +15,6 @@ comments:
treeSitter:
grammar: 'tree-sitter-rust/tree-sitter-rust.wasm'
highlightsQuery: 'tree-sitter-rust/queries/highlights.scm'
tagsQuery: 'tree-sitter-rust/queries/tags.scm'
foldsQuery: 'tree-sitter-rust/queries/folds.scm'
indentsQuery: 'tree-sitter-rust/queries/indents.scm'

View File

@ -0,0 +1,68 @@
; ADT definitions
(struct_item
name: (type_identifier) @name) @definition.class
(enum_item
name: (type_identifier) @name) @definition.class
(union_item
name: (type_identifier) @name) @definition.class
; type aliases
(type_item
name: (type_identifier) @name) @definition.class
(impl_item
(declaration_list
(function_item
name: (identifier) @name)
(#set! capture.final true)
(#set! symbol.prependTextForNode parent.parent.parent.firstNamedChild)
(#set! symbol.joiner " ")))
; method definitions
((declaration_list
(function_item
name: (identifier) @name)) @definition.method
(#set! capture.final true))
; function definitions
(function_item
name: (identifier) @name) @definition.function
; trait definitions
(trait_item
name: (type_identifier) @name) @definition.interface
; module definitions
(mod_item
name: (identifier) @name) @definition.module
; macro definitions
(macro_definition
name: (identifier) @name) @definition.macro
; references
; (call_expression
; function: (identifier) @name) @reference.call
;
; (call_expression
; function: (field_expression
; field: (field_identifier) @name)) @reference.call
;
; (macro_invocation
; macro: (identifier) @name) @reference.call
; implementations
(impl_item
trait: (type_identifier) @name) @reference.implementation
(impl_item
type: (type_identifier) @name
!trait) @reference.implementation

View File

@ -23,6 +23,7 @@ injectionRegex: '(^(bash|BASH)$|sh^|SH^)'
treeSitter:
grammar: 'tree-sitter/tree-sitter-bash.wasm'
highlightsQuery: 'tree-sitter/highlights.scm'
tagsQuery: 'tree-sitter/tags.scm'
foldsQuery: 'tree-sitter/folds.scm'
indentsQuery: 'tree-sitter/indents.scm'

View File

@ -0,0 +1,2 @@
(function_definition name: (_) @name)

View File

@ -1,20 +1,31 @@
(function_declaration
name: (identifier) @name) @definition.function
name: (identifier) @name
(#set! symbol.tag "function")) @definition.function
(function
name: (identifier) @name) @definition.function
name: (identifier) @name
(#set! symbol.tag "function")) @definition.function
(method_definition
name: (property_identifier) @name) @definition.method
name: (property_identifier) @name
(#set! symbol.tag "method")) @definition.method
(abstract_method_signature
name: (property_identifier) @name) @definition.method
name: (property_identifier) @name
(#set! symbol.tag "method")) @definition.method
(class_declaration
name: (type_identifier) @name) @definition.class
name: (type_identifier) @name
(#set! symbol.tag "class")) @definition.class
(module
name: (identifier) @name) @definition.module
name: (identifier) @name
(#set! symbol.tag "module")) @definition.module
(interface_declaration
name: (type_identifier) @name) @definition.interface
name: (type_identifier) @name
(#set! symbol.tag "interface")) @definition.interface
(function_signature
name: (identifier) @name
(#set! symbol.tag "function")) @definition.function

View File

@ -1,5 +1,5 @@
exports.activate = function() {
for (const scopeName of ['source.ts', 'source.flow']) {
for (const scopeName of ['source.ts', 'source.tsx', 'source.flow']) {
atom.grammars.addInjectionPoint(scopeName, {
type: 'call_expression',

View File

@ -154,7 +154,8 @@
}
.syntax--support {
&.syntax--class {
&.syntax--class,
&.syntax--module {
color: @hue-6-2;
}

View File

@ -154,7 +154,8 @@
}
.syntax--support {
&.syntax--class {
&.syntax--class,
&.syntax--module {
color: @hue-6-2;
}

1
packages/pulsar-updater/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

View File

@ -0,0 +1,48 @@
# Pulsar Updater
Update utility for Pulsar. On launch of Pulsar, `pulsar-updater` will check for any new releases available via GitHub APIs. And if one is available will display a notification for the user to be able to install the new version.
If the user seems to have installed Pulsar manually, a link will be opened directly to the resource on GitHub, allowing the user to then download the correct file as needed, and install it. Otherwise if it seems the user has installed Pulsar via various recognized package managers, then Pulsar Updater will present a notification that an update is available, and provide the commands needed to preform the update themselves if they so wish.
This package is made to be minimally invasive, while still allowing users to be aware of new Pulsar versions without any manual effort.
Additionally, since the entire process of actually installation is done by the user, there is no need for complex Squirrel logic, or expensive certifications to allow Squirrel to work.
## Command Palette
If a user would prefer to manually check for any updates available then the following commands are exposed from Pulsar Updater to do so:
* `pulsar-updater:check-for-update`: Performs an update check and shows a notification if a newer version of Pulsar is available.
* `pulsar-updater:clear-cache`: Clears the package's cache and forgets any requests to suppress update checking.
## The Update Notification
If an update is available, the notification that is shown is intended to be as non-invasive as possible, providing a few possible options:
* Dismiss this Version: This will remove the notification, and prevent an additional notification ever appearing for this version again. Bypassing any cache expirations.
* Dismiss until next launch: This will remove the notification, but only until the next update check. Which happens automatically at launch, or otherwise can be invoked manually.
* Download from GitHub: This option is only shown if the installation method was determined to be manually. And clicking it will open the GitHub page containing the specific version to update to.
## Supported/Checked/Recognized for Installation Methods
Since a major part of the functionality of this package is attempting to determine the installation method, it's important to list them all here:
* Universal: Developer Mode
* Universal: Safe Mode
* Universal: Spec Mode
* Windows: Chocolatey Installation
* Windows: winget Installation
* Windows: User Installation
* Windows: Machine Installation
* Windows: Portable Installation
* Linux: Flatpak Installation
* Linux: Deb-Get Installation
* Linux: Nix Installation
* Linux: Home Brew Installation
* Linux: Manual Installation
* macOS: Home Brew Installation
* macOS: Manual Installation
## Known Issues
It's important to remember that this update system is in no way integrated with the rest of Pulsar. The toggles within Pulsar to update automatically are ignored. The About view will still be unable to alert of new versions, nor track progress on installation. Those systems should eventually be removed, or mothballed, in favour of this.

847
packages/pulsar-updater/package-lock.json generated Normal file
View File

@ -0,0 +1,847 @@
{
"name": "pulsar-updater",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "pulsar-updater",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"event-kit": "github:pulsar-edit/event-kit",
"shelljs": "^0.8.5",
"superagent": "^8.0.9",
"winreg": "^1.2.4"
},
"engines": {
"atom": ">=1.106.0 <2.0.0"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/cookiejar": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
"integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/event-kit": {
"version": "2.5.3",
"resolved": "git+ssh://git@github.com/pulsar-edit/event-kit.git#80b551c1d03dd05795500f0c71dcf15be3a23c63",
"license": "MIT"
},
"node_modules/fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/formidable": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
"integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
"dependencies": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
},
"funding": {
"url": "https://ko-fi.com/tunnckoCore/commissions"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/get-intrinsic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/interpret": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/is-core-module": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
"dependencies": {
"has": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/qs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
"dependencies": {
"resolve": "^1.1.6"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"dependencies": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/shelljs": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
"dependencies": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
},
"bin": {
"shjs": "bin/shjs"
},
"engines": {
"node": ">=4"
}
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/superagent": {
"version": "8.0.9",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
"integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
"dependencies": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.4",
"debug": "^4.3.4",
"fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.0",
"formidable": "^2.1.2",
"methods": "^1.1.2",
"mime": "2.6.0",
"qs": "^6.11.0",
"semver": "^7.3.8"
},
"engines": {
"node": ">=6.4.0 <13 || >=14"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/winreg": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz",
"integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA=="
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
},
"dependencies": {
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"requires": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"cookiejar": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
"integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"requires": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"event-kit": {
"version": "git+ssh://git@github.com/pulsar-edit/event-kit.git#80b551c1d03dd05795500f0c71dcf15be3a23c63",
"from": "event-kit@pulsar-edit/event-kit"
},
"fast-safe-stringify": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"formidable": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz",
"integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==",
"requires": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-intrinsic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
"requires": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3"
}
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"requires": {
"function-bind": "^1.1.1"
}
},
"has-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
},
"has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
},
"hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"interpret": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
},
"is-core-module": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
"integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
"requires": {
"has": "^1.0.3"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
},
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"requires": {
"wrappy": "1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"qs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
"requires": {
"side-channel": "^1.0.4"
}
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
"requires": {
"resolve": "^1.1.6"
}
},
"resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"requires": {
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
"requires": {
"lru-cache": "^6.0.0"
}
},
"shelljs": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
"requires": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
}
},
"side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"requires": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
}
},
"superagent": {
"version": "8.0.9",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz",
"integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==",
"requires": {
"component-emitter": "^1.3.0",
"cookiejar": "^2.1.4",
"debug": "^4.3.4",
"fast-safe-stringify": "^2.1.1",
"form-data": "^4.0.0",
"formidable": "^2.1.2",
"methods": "^1.1.2",
"mime": "2.6.0",
"qs": "^6.11.0",
"semver": "^7.3.8"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"winreg": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz",
"integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}

View File

@ -0,0 +1,28 @@
{
"name": "pulsar-updater",
"version": "1.0.0",
"description": "Detect Pulsar updates on Launch.",
"main": "./src/main.js",
"scripts": {
"test": "pulsar --test spec"
},
"engines": {
"atom": ">=1.106.0 <2.0.0"
},
"author": "confused-Techie",
"license": "MIT",
"repository": "https://github.com/pulsar-edit/pulsar",
"dependencies": {
"event-kit": "github:pulsar-edit/event-kit",
"shelljs": "^0.8.5",
"superagent": "^8.0.9",
"winreg": "^1.2.4"
},
"configSchema": {
"checkForUpdatesOnLaunch": {
"type": "boolean",
"default": true,
"description": "If Pulsar Updater should check for an update to Pulsar as soon as Pulsar launches."
}
}
}

View File

@ -0,0 +1,20 @@
const cache = require("../src/cache.js");
describe("pulsar-updater cache", () => {
it("returns key for path", () => {
let key = cache.cacheKeyForPath("test");
expect(key).toBe("pulsar-updater:test");
});
it("returns expired properly according to date", () => {
let expiry = cache.isItemExpired({ createdOn: Date.now() });
expect(expiry).toBe(false);
});
it("returns not expired if offline", () => {
spyOn(cache, "online").andReturn(true);
let expiry = cache.isItemExpired({ createdOn: 0 });
expect(expiry).toBe(false);
})
});

View File

@ -0,0 +1,137 @@
const findInstallChannel = require("../src/find-install-channel.js");
const shell = require("shelljs");
describe("pulsar-updater findInstallChannel", () => {
describe("windows choco install", () => {
it("fails if 'choco' isn't found", () => {
spyOn(shell, "which").andReturn(false);
let installCheck = findInstallChannel.windows_chocoInstalled();
expect(installCheck).toBe(false);
});
it("fails if pulsar isn't included in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "not -pu-l-sar" });
let installCheck = findInstallChannel.windows_chocoInstalled();
expect(installCheck).toBe(false);
});
it("fails if exit code is not 0", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 1, stdout: "" });
let installCheck = findInstallChannel.windows_chocoInstalled();
expect(installCheck).toBe(false);
});
it("succeeds if pulsar is included in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "pulsar" });
let installCheck = findInstallChannel.windows_chocoInstalled();
expect(installCheck).toBe(true);
});
});
describe("windows winget install", () => {
it("fails if winget isn't found", () => {
spyOn(shell, "which").andReturn(false);
let installCheck = findInstallChannel.windows_wingetInstalled();
expect(installCheck).toBe(false);
});
it("fails if pulsar isn't found in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "not -pu-l-sar" });
let installCheck = findInstallChannel.windows_wingetInstalled();
expect(installCheck).toBe(false);
});
it("fails if exit code is not 0", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 1, stdout: "" });
let installCheck = findInstallChannel.windows_wingetInstalled();
expect(installCheck).toBe(false);
});
it("succeeds if pulsar is included in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "Pulsar" });
let installCheck = findInstallChannel.windows_wingetInstalled();
expect(installCheck).toBe(true);
});
});
describe("linux/macos homebrew install", () => {
it("fails if brew isn't found", () => {
spyOn(shell, "which").andReturn(false);
let installCheck = findInstallChannel.linux_macos_homebrewInstalled();
expect(installCheck).toBe(false);
});
it("fails if pulsar isn't found in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "not -pu-l-sar" });
let installCheck = findInstallChannel.linux_macos_homebrewInstalled();
expect(installCheck).toBe(false);
});
it("fails if exit code is not 0", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 1, stdout: "" });
let installCheck = findInstallChannel.linux_macos_homebrewInstalled();
expect(installCheck).toBe(false);
});
it("succeeds if pulsar is included in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "pulsar" });
let installCheck = findInstallChannel.linux_macos_homebrewInstalled();
expect(installCheck).toBe(true);
});
});
describe("linux debget install", () => {
it("fails if deb-get isn't found", () => {
spyOn(shell, "which").andReturn(false);
let installCheck = findInstallChannel.linux_debGetInstalled();
expect(installCheck).toBe(false);
});
it("fails if pulsar isn't found in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "not -pu-l-sar" });
let installCheck = findInstallChannel.linux_debGetInstalled();
expect(installCheck).toBe(false);
});
it("fails if exit code is not 0", () => {
spyOn(shell, "which").andReturn(false);
spyOn(shell, "exec").andReturn({ code: 1, stdout: "" });
let installCheck = findInstallChannel.linux_debGetInstalled();
expect(installCheck).toBe(false);
});
it("succeeds if pulsar is included in stdout", () => {
spyOn(shell, "which").andReturn(true);
spyOn(shell, "exec").andReturn({ code: 0, stdout: "pulsar" });
let installCheck = findInstallChannel.linux_debGetInstalled();
expect(installCheck).toBe(true);
});
});
describe("linux flatpak install", () => {
it("fails if flatpak_id is not pulsar", () => {
process.env.FLATPAK_ID = "not-pulsar";
let installCheck = findInstallChannel.linux_flatpakInstalled();
expect(installCheck).toBe(false);
});
it("succeeds if flatpak_id is pulsar", () => {
process.env.FLATPAK_ID = "dev.pulsar_edit.Pulsar";
let installCheck = findInstallChannel.linux_flatpakInstalled();
expect(installCheck).toBe(true);
});
});
});

View File

@ -0,0 +1,18 @@
const findInstallMethod = require("../src/find-install-method.js");
describe("find-install-method main", async () => {
const platform = process.platform;
const arch = process.arch;
it("Returns spec mode if applicable", async () => {
// We can't mock the atom api return from a package,
// So we will just know that if tests are running, it's in the Atom SpecMode
let method = await findInstallMethod();
expect(method.installMethod).toBe("Spec Mode");
expect(method.platform).toBe(platform);
expect(method.arch).toBe(arch);
});
});

View File

@ -0,0 +1,111 @@
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms, true));
}
describe('PulsarUpdater', () => {
let pack, workspaceElement;
beforeEach(async () => {
atom.config.set("pulsar-updater.checkForUpdatesOnLaunch", false);
workspaceElement = atom.views.getView(atom.workspace);
pack = await atom.packages.activatePackage('pulsar-updater');
pack.mainModule.cache?.empty("last-update-check");
});
afterEach(async () => {
pack.mainModule.cache?.empty("last-update-check");
await atom.packages.deactivatePackage('pulsar-updater');
});
describe('when pulsar-updater:check-for-updates is triggered', () => {
beforeEach(async () => {
spyOn(pack.mainModule, 'checkForUpdates');
})
it('triggers an update check', () => {
atom.commands.dispatch(workspaceElement, 'pulsar-updater:check-for-update');
expect(pack.mainModule.checkForUpdates).toHaveBeenCalled();
});
});
describe("when the remote version is greater than ours", () => {
beforeEach(() => {
spyOn(atom, "getVersion").andReturn("1.0.0");
spyOn(pack.mainModule, 'findNewestRelease').andCallFake(() => {
return "2.0.0";
})
spyOn(pack.mainModule, 'notifyAboutUpdate').andCallThrough();
spyOn(pack.mainModule, 'notifyAboutCurrent').andCallThrough();
});
afterEach(() => {
pack.mainModule.notifyAboutUpdate.reset();
pack.mainModule.notifyAboutCurrent.reset();
})
it("signals that the user should update", async () => {
jasmine.useRealClock();
atom.commands.dispatch(workspaceElement, 'pulsar-updater:check-for-update');
await wait(200);
expect(pack.mainModule.notifyAboutUpdate).toHaveBeenCalledWith("2.0.0");
expect(pack.mainModule.notifyAboutCurrent).not.toHaveBeenCalled();
});
});
describe("when the remote version is equal to ours", () => {
beforeEach(() => {
spyOn(atom, "getVersion").andReturn("1.0.5");
spyOn(pack.mainModule, 'findNewestRelease').andCallFake(() => {
return "1.0.5";
})
spyOn(pack.mainModule, 'notifyAboutUpdate');
spyOn(pack.mainModule, 'notifyAboutCurrent');
});
it("takes no action", async () => {
jasmine.useRealClock();
atom.commands.dispatch(workspaceElement, 'pulsar-updater:check-for-update');
await wait(200);
expect(pack.mainModule.notifyAboutUpdate).not.toHaveBeenCalled();
expect(pack.mainModule.notifyAboutCurrent).toHaveBeenCalledWith("1.0.5", true);
});
});
describe("when the user tells us to ignore until the next version", () => {
let latestVersion = "1.0.6";
beforeEach(() => {
spyOn(atom, "getVersion").andReturn("1.0.5");
spyOn(pack.mainModule, 'findNewestRelease').andCallFake(() => {
return latestVersion;
});
spyOn(pack.mainModule, 'notifyAboutUpdate').andCallThrough();
spyOn(pack.mainModule, 'notifyAboutCurrent').andCallThrough();
});
it("subsequent checks do not result in notifications", async () => {
jasmine.useRealClock();
atom.commands.dispatch(workspaceElement, 'pulsar-updater:check-for-update');
await wait(200);
expect(pack.mainModule.notifyAboutUpdate).toHaveBeenCalledWith("1.0.6");
expect(pack.mainModule.notifyAboutCurrent).not.toHaveBeenCalled();
pack.mainModule.ignoreForThisVersion("1.0.6");
// Calling the method directly here because eventually we'll want a
// user-initiated check for updates to ignore this cache.
pack.mainModule.checkForUpdates();
await wait(200);
expect(pack.mainModule.notifyAboutUpdate.callCount).toBe(1);
expect(pack.mainModule.notifyAboutCurrent).not.toHaveBeenCalled();
latestVersion = "1.0.7";
pack.mainModule.checkForUpdates();
await wait(200);
expect(pack.mainModule.notifyAboutUpdate).toHaveBeenCalledWith("1.0.7");
expect(pack.mainModule.notifyAboutCurrent).not.toHaveBeenCalled();
});
});
});

View File

@ -0,0 +1,73 @@
// Simple caching utilities
// The rough shape of an object will be: (This matches the cache in settings-view)
// {
// "createdOn": "epoch time",
// "data": "cache object"
// }
function setCacheItem(key, item) {
let obj = {
createdOn: Date.now(),
data: JSON.stringify(item),
};
localStorage.setItem(cacheKeyForPath(key), JSON.stringify(obj));
}
function getCacheItem(key) {
let obj = localStorage.getItem(cacheKeyForPath(key));
if (!obj) {
return null;
}
let cached = JSON.parse(obj);
if (typeof cached === "object" && !isItemExpired(cached)) {
return JSON.parse(cached.data);
}
return null;
}
function empty(key) {
localStorage.removeItem(cacheKeyForPath(key));
}
function isItemExpired(item, key) {
if (key === "last-update-check") {
// the last update check item never expires, to ensure skipping version
// preferences are permanent
return false;
}
if (!online() || Date.now() - item.createdOn < expiry()) {
return false;
} else {
return true;
}
}
function online() {
return navigator.onLine;
}
function cacheKeyForPath(path) {
return `pulsar-updater:${path}`;
}
function expiry() {
// TODO get this from the package's config
// 5 hour expiry by default
return 1000 * 60 * 60 * 5;
}
module.exports = {
setCacheItem,
getCacheItem,
isItemExpired,
empty,
cacheKeyForPath,
online,
};

View File

@ -0,0 +1,135 @@
const Registry = require("winreg");
const shell = require("shelljs");
const fs = require("fs");
// https://github.com/shelljs/shelljs/wiki/Electron-compatibility
// ShellJS is not totally compatible within Electron.
// We may need to look at running this within a task, but otherwise this should be
// sufficient to get `exec` working
shell.config.execPath = shell.which("node").toString();
function windows_isUserInstalled() {
return new Promise((resolve, reject) => {
let userInstallReg = new Registry({
hive: "HKCU",
key: "\\SOFTWARE\\0949b555-c22c-56b7-873a-a960bdefa81f",
});
userInstallReg.keyExists((err, exists) => {
if (err) {
reject(err);
}
resolve(exists);
});
});
}
function windows_isMachineInstalled() {
return new Promise((resolve, reject) => {
let machineInstallReg = new Registry({
hive: "HKLM",
key: "\\SOFTWARE\\0949b555-c22c-56b7-873a-a960bdefa81f",
});
machineInstallReg.keyExists((err, exists) => {
if (err) {
reject(err);
}
resolve(exists);
});
});
}
function windows_chocoInstalled() {
if (!shell.which("choco")) {
return false;
}
let chocoCheck = shell.exec("choco list --local-only");
if (chocoCheck.code !== 0) {
return false;
}
return chocoCheck.stdout.includes("pulsar");
}
function windows_wingetInstalled() {
if (!shell.which("winget")) {
return false;
}
let wingetCheck = shell.exec("winget show Pulsar");
if (wingetCheck.code !== 0) {
return false;
}
return wingetCheck.stdout.includes("Pulsar");
}
function linux_macos_homebrewInstalled() {
if (!shell.which("brew")) {
return false;
}
let homebrewCheck = shell.exec("brew list 'pulsar'");
if (homebrewCheck.code !== 0) {
return false;
}
return homebrewCheck.stdout.includes("pulsar");
}
function linux_nixInstalled() {
if (!fs.existsSync("/nix/store")) {
return false;
}
if (!shell.which("find")) {
// A little dishonest, but we need this to check if it exists so..
return false;
}
shell.cd("/nix/store");
let nixCheck = shell.exec('find -maxdepth 1 -name "*pulsar.nemo_action"');
if (nixCheck.code !== 0) {
return false;
}
return nixCheck.stdout.includes("pulsar.nemo_action");
}
function linux_debGetInstalled() {
if (!shell.which("deb-get")) {
return false;
}
let debGetCheck = shell.exec("deb-get list --installed");
if (debGetCheck.code !== 0) {
return false;
}
return debGetCheck.stdout.includes("pulsar");
}
function linux_flatpakInstalled() {
return process.env.FLATPAK_ID === "dev.pulsar_edit.Pulsar";
}
module.exports = {
windows_isUserInstalled,
windows_isMachineInstalled,
windows_chocoInstalled,
windows_wingetInstalled,
linux_macos_homebrewInstalled,
linux_nixInstalled,
linux_debGetInstalled,
linux_flatpakInstalled,
};

View File

@ -0,0 +1,134 @@
const findInstallChannel = require("./find-install-channel.js");
const INSTALL_CHANNELS = {
macos: {
fallback: "Manual Installation",
channels: [
{
string: "Homebrew Installation",
func: findInstallChannel.linux_macos_homebrewInstalled,
},
],
},
linux: {
fallback: "Manual Installation",
channels: [
{
string: "Flatpak Installation",
func: findInstallChannel.linux_flatpakInstalled,
},
{
string: "Deb-Get Installation",
func: findInstallChannel.linux_debGetInstalled,
},
{
string: "Nix Installation",
func: findInstallChannel.linux_nixInstalled,
},
{
string: "Homebrew Installation",
func: findInstallChannel.linux_macos_homebrewInstalled,
},
// TODO AUR
],
},
windows: {
fallback: "Portable Installation",
channels: [
{
string: "Chocolatey Installation",
func: findInstallChannel.windows_chocoInstalled,
},
{
string: "winget Installation",
func: findInstallChannel.windows_wingetInstalled,
},
// We must check for package installs on windows before, user & machine
// Since package installs trigger either a user or machine install
{
string: "User Installation",
func: findInstallChannel.windows_isUserInstalled,
},
{
string: "Machine Installation",
func: findInstallChannel.windows_isMachineInstalled,
},
],
},
};
// This module will do whatever it can to determine the installation method.
// This doesn't just mean to determine what platform Pulsar is installed on
// this also means to determine what program installed it, and what variant
// of the Pulsar binary is in use.
async function main() {
let returnValue = "";
if (atom.inDevMode()) {
returnValue = "Developer Mode";
}
if (atom.inSafeMode()) {
returnValue = "Safe Mode";
}
if (atom.inSpecMode()) {
returnValue = "Spec Mode";
}
if (returnValue.length > 0) {
// Return early
return {
platform: process.platform,
arch: process.arch,
installMethod: returnValue,
};
}
if (process.platform === "win32") {
returnValue = await determineChannel(
INSTALL_CHANNELS.windows.channels,
INSTALL_CHANNELS.windows.fallback
);
} else if (process.platform === "darwin") {
returnValue = await determineChannel(
INSTALL_CHANNELS.macos.channels,
INSTALL_CHANNELS.macos.fallback
);
} else if (process.platform === "linux") {
returnValue = await determineChannel(
INSTALL_CHANNELS.linux.channels,
INSTALL_CHANNELS.linux.fallback
);
}
// Unused aix, freebsd, openbsd, sunos, android
return {
platform: process.platform,
arch: process.arch,
installMethod: returnValue,
};
}
async function determineChannel(channels, fallback) {
for (let i = 0; i < channels.length; i++) {
let channel = channels[i];
let install = await channel.func();
if (
typeof install === "boolean" &&
install &&
typeof channel.string === "string"
) {
return channel.string;
}
}
// Since we know that Pulsar hasn't been installed via an above method,
// we should assume the fallback method
return fallback;
}
module.exports = main;

View File

@ -0,0 +1,20 @@
let superagent;
module.exports =
async function findNewestRelease() {
superagent ??= require("superagent");
let res = await superagent
.get("https://api.github.com/repos/pulsar-edit/pulsar/releases")
.set("Accept", "application/vnd.github+json")
.set("User-Agent", "Pulsar.Pulsar-Updater");
if (res.status !== 200) {
// Lie and say it's something that will never update
return "0.0.0";
}
// We can be fast and simply check if the top of the array is newer than our
// current version. Since the return is ordered.
return res.body[0].tag_name;
}

View File

@ -0,0 +1,231 @@
const { CompositeDisposable } = require("atom");
let shell;
let superagent;
let findInstallMethod;
class PulsarUpdater {
activate() {
this.disposables = new CompositeDisposable();
this.cache = require("./cache.js");
this.disposables.add(
atom.commands.add("atom-workspace", {
"pulsar-updater:check-for-update": () => {
this.checkForUpdates({ manual: true });
},
"pulsar-updater:clear-cache": () => {
this.cache.empty("last-update-check");
this.cache.empty(`installMethod.${atom.getVersion()}`);
},
})
);
if (atom.config.get("pulsar-updater.checkForUpdatesOnLaunch")) {
this.checkForUpdates();
}
}
deactivate() {
this.disposables.dispose();
this.cache = null;
}
async findNewestRelease() {
superagent ??= require("superagent");
let res = await superagent
.get("https://api.github.com/repos/pulsar-edit/pulsar/releases")
.set("Accept", "application/vnd.github+json")
.set("User-Agent", "Pulsar.Pulsar-Updater");
if (res.status !== 200) {
// Lie and say it's something that will never update
return "0.0.0";
}
// We get the results ordered by newest tag first, so we can just check the
// first item.
return res.body[0].tag_name;
}
async checkForUpdates({ manual = false } = {}) {
let cachedUpdateCheck = this.cache.getCacheItem("last-update-check");
// Null means that there is no previous check, or the last check expired
let latestVersion = await this.findNewestRelease();
let shouldUpdate = !atom.versionSatisfies(`>= ${latestVersion}`);
if (
cachedUpdateCheck?.latestVersion === latestVersion &&
!cachedUpdateCheck?.shouldUpdate
) {
// The user has already been notified about this version and told us not
// to notify them again until the next release.
if (manual) {
await this.notifyAboutUpdate(latestVersion);
}
return;
}
if (shouldUpdate) {
await this.notifyAboutUpdate(latestVersion);
} else {
// This can be a no-op or something that generates an actual notification
// based on how the update check was invoked.
await this.notifyAboutCurrent(latestVersion, manual);
}
}
notifyAboutCurrent(latestVersion, manual) {
if (!manual) return;
atom.notifications.addInfo(
"Pulsar is already up to date.",
{ dismissable: true }
);
}
async notifyAboutUpdate(latestVersion) {
this.cache.setCacheItem("last-update-check", {
latestVersion: latestVersion,
shouldUpdate: true
});
findInstallMethod ??= require("./find-install-method.js");
let installMethod =
this.cache.getCacheItem(`installMethod.${atom.getVersion()}`) ??
(await findInstallMethod());
this.cache.setCacheItem(
`installMethod.${atom.getVersion()}`,
installMethod
);
let objButtonForInstallMethod = this.getObjButtonForInstallMethod(installMethod);
let notificationDetailText = this.getNotificationText(installMethod, latestVersion);
// Notification text of `null` means that we shouldn't show a notification
// after all.
if (notificationDetailText === null) {
return;
}
const notification = atom.notifications.addInfo(
"An update for Pulsar is available.",
{
description: notificationDetailText,
dismissable: true,
buttons: [
{
text: "Dismiss this Version",
onDidClick: () => {
this.ignoreForThisVersion(latestVersion);
notification.dismiss();
},
},
{
text: "Dismiss until next launch",
onDidClick: () => {
this.ignoreUntilNextLaunch();
notification.dismiss();
},
},
// Below we optionally add a button for the install method. That may
// open to a pulsar download URL, if available for installation method
typeof objButtonForInstallMethod === "object" &&
objButtonForInstallMethod
],
}
);
}
ignoreForThisVersion(version) {
this.cache.setCacheItem("last-update-check", {
latestVersion: version,
shouldUpdate: false
});
}
ignoreUntilNextLaunch() {
// emptying the cache, will cause the next check to succeed
this.cache.empty("last-update-check");
}
getNotificationText(installMethod, latestVersion) {
let returnText = `Pulsar ${latestVersion} is available.\n`;
switch (installMethod.installMethod) {
case "Developer Mode":
returnText +=
"Since you're in developer mode, Pulsy trusts you know how to update. :)";
break;
case "Safe Mode":
return null;
break;
case "Spec Mode":
return null;
break;
case "Flatpak Installation":
returnText += "Install the latest version by running `flatpak update`.";
break;
case "Deb-Get Installation":
returnText +=
"Install the latest version by running `sudo deb-get update`.";
break;
case "Nix Installation":
// TODO find nix update command
returnText += "Install the latest version via Nix.";
break;
case "Homebrew Installation":
returnText +=
"Install the latest version by running `brew upgrade pulsar`.";
break;
case "winget Installation":
returnText +=
"Install the latest version by running `winget upgrade pulsar`.";
break;
case "Chocolatey Installation":
returnText +=
"Install the latest version by running `choco upgrade pulsar`.";
break;
case "User Installation":
case "Machine Installation":
case "Portable Installation":
case "Manual Installation":
default:
returnText +=
"Download the latest version from the Pulsar Website or GitHub.";
break;
}
return returnText;
}
getObjButtonForInstallMethod(installMethod) {
let returnObj = null;
const openWebGitHub = (e) => {
e.preventDefault();
shell ??= shell || require("electron").shell;
let latestVersion = this.cache.getCacheItem("last-update-check")?.latestVersion;
let tagSegment = latestVersion ? `tag/${latestVersion}` : "";
shell.openExternal(`https://github.com/pulsar-edit/pulsar/releases/${tagSegment}`);
};
switch (installMethod.installMethod) {
case "User Installation":
case "Machine Installation":
default:
returnObj = {
text: "Download from GitHub",
onDidClick: openWebGitHub,
};
break;
}
return returnObj;
}
}
module.exports = new PulsarUpdater();

View File

@ -225,6 +225,26 @@ describe('StyleManager', () => {
);
});
it('recognizes valid less variables: right side', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
"p { padding: @size + 12px; }",
{}
);
expect(upgradedSheet.source).toEqual(
"p { padding: calc(@size + 12px); }"
);
});
it('recognizes valid less variables: left side', () => {
let upgradedSheet = mathStyleManager.upgradeDeprecatedMathUsageForStyleSheet(
"p { padding: 12px + @size; }",
{}
);
expect(upgradedSheet.source).toEqual(
"p { padding: calc(12px + @size); }"
);
});
});
describe('when a sourcePath parameter is specified', () => {

View File

@ -437,7 +437,7 @@ function transformDeprecatedMathUsage(css, context) {
const cssValueIgnoreList = /hsl|abs|acos|asin|atan|atan2|cos|mod|rem|sign|sin|tan|url/g;
const mathExpressionRegex =
/-*(\d(\.\d)?)+(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|rlh|vw|vh|vmin|vmax|vb|vi|svw|svh|lvw|lvh|dvw|dvh|%)?(\s*([\/\+\*]|(\-\s+))\s*(\d(\.\d)*)+(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|rlh|vw|vh|vmin|vmax|vb|vi|svw|svh|lvw|lvh|dvw|dvh|%)?)+/g;
/(-*(\d(\.\d)?)+(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|rlh|vw|vh|vmin|vmax|vb|vi|svw|svh|lvw|lvh|dvw|dvh|%)?|@?[\w-]+)(\s*([\/\+\*]|(\-\s+))\s*((\d(\.\d)*)+(cm|mm|Q|in|pc|pt|px|em|ex|ch|rem|lh|rlh|vw|vh|vmin|vmax|vb|vi|svw|svh|lvw|lvh|dvw|dvh|%)?|@?[\w-]+))+/g;
try {
transformedSource = postcss.parse(css);

131
yarn.lock
View File

@ -2198,7 +2198,7 @@ array.prototype.reduce@^1.0.5:
es-array-method-boxes-properly "^1.0.0"
is-string "^1.0.7"
asap@~2.0.3:
asap@^2.0.0, asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
@ -3237,6 +3237,11 @@ compare-version@^0.1.2:
resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080"
integrity sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==
component-emitter@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
compress-commons@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d"
@ -3299,6 +3304,11 @@ convert-source-map@^1.1.0, convert-source-map@^1.7.0:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
cookiejar@^2.1.4:
version "2.1.4"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
copy-anything@^2.0.1:
version "2.0.6"
resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
@ -3676,6 +3686,14 @@ devtools@7.20.8:
ua-parser-js "^1.0.1"
uuid "^8.0.0"
dezalgo@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
dependencies:
asap "^2.0.0"
wrappy "1"
diff@3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@ -4365,6 +4383,10 @@ event-kit@^1.0.0, event-kit@^1.0.2:
dependencies:
grim "^1.2.1"
"event-kit@github:pulsar-edit/event-kit":
version "2.5.3"
resolved "https://codeload.github.com/pulsar-edit/event-kit/tar.gz/80b551c1d03dd05795500f0c71dcf15be3a23c63"
event-stream@~3.1.0:
version "3.1.7"
resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.1.7.tgz#b4c540012d0fe1498420f3d8946008db6393c37a"
@ -4453,6 +4475,11 @@ fast-levenshtein@^2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
fast-safe-stringify@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
fastq@^1.6.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
@ -4624,6 +4651,16 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
formidable@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89"
integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==
dependencies:
dezalgo "^1.0.4"
hexoid "^1.0.0"
once "^1.4.0"
qs "^6.11.0"
from@~0:
version "0.1.7"
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
@ -4992,7 +5029,7 @@ glob@7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0:
glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@ -5234,6 +5271,11 @@ he@1.2.0:
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hexoid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
hosted-git-info@^2.8.9:
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
@ -5437,6 +5479,11 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
interpret@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
invert-kv@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
@ -5523,6 +5570,13 @@ is-core-module@^2.0.0, is-core-module@^2.9.0:
dependencies:
has "^1.0.3"
is-core-module@^2.11.0:
version "2.12.1"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
dependencies:
has "^1.0.3"
is-date-object@^1.0.1, is-date-object@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
@ -6652,6 +6706,11 @@ mdurl@^1.0.1:
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
methods@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@ -6664,16 +6723,16 @@ mime-types@^2.1.12, mime-types@~2.1.19:
dependencies:
mime-db "1.52.0"
mime@2.6.0, mime@^2.5.2:
version "2.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.5.2:
version "2.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@ -7792,6 +7851,14 @@ psl@^1.1.28:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
"pulsar-updater@file:packages/pulsar-updater":
version "1.0.0"
dependencies:
event-kit "github:pulsar-edit/event-kit"
shelljs "^0.8.5"
superagent "^8.0.9"
winreg "^1.2.4"
pump@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
@ -7846,6 +7913,13 @@ puppeteer-core@^13.1.3:
unbzip2-stream "1.4.3"
ws "8.5.0"
qs@^6.11.0:
version "6.11.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9"
integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==
dependencies:
side-channel "^1.0.4"
qs@~6.5.2:
version "6.5.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
@ -7993,6 +8067,13 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
rechoir@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
dependencies:
resolve "^1.1.6"
reduce-extract@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/reduce-extract/-/reduce-extract-1.0.0.tgz#67f2385beda65061b5f5f4312662e8b080ca1525"
@ -8177,6 +8258,15 @@ resolve@1.18.1:
is-core-module "^2.0.0"
path-parse "^1.0.6"
resolve@^1.1.6:
version "1.22.2"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.2:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
@ -8495,6 +8585,15 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shelljs@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
@ -8928,6 +9027,22 @@ sumchecker@^3.0.1:
dependencies:
debug "^4.1.0"
superagent@^8.0.9:
version "8.0.9"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.0.9.tgz#2c6fda6fadb40516515f93e9098c0eb1602e0535"
integrity sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==
dependencies:
component-emitter "^1.3.0"
cookiejar "^2.1.4"
debug "^4.3.4"
fast-safe-stringify "^2.1.1"
form-data "^4.0.0"
formidable "^2.1.2"
methods "^1.1.2"
mime "2.6.0"
qs "^6.11.0"
semver "^7.3.8"
superstring@^2.4.4:
version "2.4.4"
resolved "https://registry.yarnpkg.com/superstring/-/superstring-2.4.4.tgz#d5df5b080deb5605ffd88b6cdbaf17a0b30d5f0e"
@ -9912,7 +10027,7 @@ window-size@^0.1.4:
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
integrity sha512-2thx4pB0cV3h+Bw7QmMXcEbdmOzv9t0HFplJH/Lz6yu60hXYy5RT8rUu+wlIreVxWsGN20mo+MHeCSfUpQBwPw==
winreg@^1.2.1:
winreg@^1.2.1, winreg@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
integrity sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA==