chore: disable delete confirmation in VS Code explorer

Disable the confirmation dialog when deleting files in the VS Code explorer to streamline the development workflow and reduce friction during file management operations.
This commit is contained in:
Falck
2026-04-25 15:56:37 +08:00
parent c998f8beda
commit e5d578a849
947 changed files with 114025 additions and 1 deletions

View File

@@ -0,0 +1,12 @@
const borderedText = (text: string) => {
const lines = text.split('\n');
const width = Math.max(...lines.map((l) => l.length));
const res = [`${'─'.repeat(width + 2)}`];
for (const line of lines) {
res.push(`${line.padEnd(width)}`);
}
res.push(`${'─'.repeat(width + 2)}`);
return res.join('\n');
};
export default borderedText;

View File

@@ -0,0 +1,17 @@
import { createConfigDir, getLastUpdate, saveLastUpdate } from './cache';
createConfigDir();
jest.useFakeTimers().setSystemTime(new Date('2022-01-01'));
const fakeTime = new Date('2022-01-01').getTime();
test('can save update then get the update details', () => {
saveLastUpdate('test');
expect(getLastUpdate('test')).toBe(fakeTime);
});
test('prefixed module can save update then get the update details', () => {
saveLastUpdate('@alexbrazier/test');
expect(getLastUpdate('@alexbrazier/test')).toBe(fakeTime);
});

View File

@@ -0,0 +1,44 @@
import os from 'os';
import path from 'path';
import fs from 'fs';
const homeDirectory = os.homedir();
const configDir =
process.env.XDG_CONFIG_HOME ||
path.join(homeDirectory, '.config', 'simple-update-notifier');
const getConfigFile = (packageName: string) => {
return path.join(
configDir,
`${packageName.replace('@', '').replace('/', '__')}.json`
);
};
export const createConfigDir = () => {
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
};
export const getLastUpdate = (packageName: string) => {
const configFile = getConfigFile(packageName);
try {
if (!fs.existsSync(configFile)) {
return undefined;
}
const file = JSON.parse(fs.readFileSync(configFile, 'utf8'));
return file.lastUpdateCheck as number;
} catch {
return undefined;
}
};
export const saveLastUpdate = (packageName: string) => {
const configFile = getConfigFile(packageName);
fs.writeFileSync(
configFile,
JSON.stringify({ lastUpdateCheck: new Date().getTime() })
);
};

View File

@@ -0,0 +1,35 @@
import Stream from 'stream';
import https from 'https';
import getDistVersion from './getDistVersion';
jest.mock('https', () => ({
get: jest.fn(),
}));
test('Valid response returns version', async () => {
const st = new Stream();
(https.get as jest.Mock).mockImplementation((url, cb) => {
cb(st);
st.emit('data', '{"latest":"1.0.0"}');
st.emit('end');
});
const version = await getDistVersion('test', 'latest');
expect(version).toEqual('1.0.0');
});
test('Invalid response throws error', async () => {
const st = new Stream();
(https.get as jest.Mock).mockImplementation((url, cb) => {
cb(st);
st.emit('data', 'some invalid json');
st.emit('end');
});
expect(getDistVersion('test', 'latest')).rejects.toThrow(
'Could not parse version response'
);
});

View File

@@ -0,0 +1,29 @@
import https from 'https';
const getDistVersion = async (packageName: string, distTag: string) => {
const url = `https://registry.npmjs.org/-/package/${packageName}/dist-tags`;
return new Promise<string>((resolve, reject) => {
https
.get(url, (res) => {
let body = '';
res.on('data', (chunk) => (body += chunk));
res.on('end', () => {
try {
const json = JSON.parse(body);
const version = json[distTag];
if (!version) {
reject(new Error('Error getting version'));
}
resolve(version);
} catch {
reject(new Error('Could not parse version response'));
}
});
})
.on('error', (err) => reject(err));
});
};
export default getDistVersion;

View File

@@ -0,0 +1,82 @@
import hasNewVersion from './hasNewVersion';
import { getLastUpdate } from './cache';
import getDistVersion from './getDistVersion';
jest.mock('./getDistVersion', () => jest.fn().mockReturnValue('1.0.0'));
jest.mock('./cache', () => ({
getLastUpdate: jest.fn().mockReturnValue(undefined),
createConfigDir: jest.fn(),
saveLastUpdate: jest.fn(),
}));
const pkg = { name: 'test', version: '1.0.0' };
afterEach(() => jest.clearAllMocks());
const defaultArgs = {
pkg,
shouldNotifyInNpmScript: true,
alwaysRun: true,
};
test('it should not trigger update for same version', async () => {
const newVersion = await hasNewVersion(defaultArgs);
expect(newVersion).toBe(false);
});
test('it should trigger update for patch version bump', async () => {
(getDistVersion as jest.Mock).mockReturnValue('1.0.1');
const newVersion = await hasNewVersion(defaultArgs);
expect(newVersion).toBe('1.0.1');
});
test('it should trigger update for minor version bump', async () => {
(getDistVersion as jest.Mock).mockReturnValue('1.1.0');
const newVersion = await hasNewVersion(defaultArgs);
expect(newVersion).toBe('1.1.0');
});
test('it should trigger update for major version bump', async () => {
(getDistVersion as jest.Mock).mockReturnValue('2.0.0');
const newVersion = await hasNewVersion(defaultArgs);
expect(newVersion).toBe('2.0.0');
});
test('it should not trigger update if version is lower', async () => {
(getDistVersion as jest.Mock).mockReturnValue('0.0.9');
const newVersion = await hasNewVersion(defaultArgs);
expect(newVersion).toBe(false);
});
it('should trigger update check if last update older than config', async () => {
const TWO_WEEKS = new Date().getTime() - 1000 * 60 * 60 * 24 * 14;
(getLastUpdate as jest.Mock).mockReturnValue(TWO_WEEKS);
const newVersion = await hasNewVersion({
pkg,
shouldNotifyInNpmScript: true,
});
expect(newVersion).toBe(false);
expect(getDistVersion).toHaveBeenCalled();
});
it('should not trigger update check if last update is too recent', async () => {
const TWELVE_HOURS = new Date().getTime() - 1000 * 60 * 60 * 12;
(getLastUpdate as jest.Mock).mockReturnValue(TWELVE_HOURS);
const newVersion = await hasNewVersion({
pkg,
shouldNotifyInNpmScript: true,
});
expect(newVersion).toBe(false);
expect(getDistVersion).not.toHaveBeenCalled();
});

View File

@@ -0,0 +1,40 @@
import semver from 'semver';
import { createConfigDir, getLastUpdate, saveLastUpdate } from './cache';
import getDistVersion from './getDistVersion';
import { IUpdate } from './types';
const hasNewVersion = async ({
pkg,
updateCheckInterval = 1000 * 60 * 60 * 24,
distTag = 'latest',
alwaysRun,
debug,
}: IUpdate) => {
createConfigDir();
const lastUpdateCheck = getLastUpdate(pkg.name);
if (
alwaysRun ||
!lastUpdateCheck ||
lastUpdateCheck < new Date().getTime() - updateCheckInterval
) {
const latestVersion = await getDistVersion(pkg.name, distTag);
saveLastUpdate(pkg.name);
if (semver.gt(latestVersion, pkg.version)) {
return latestVersion;
} else if (debug) {
console.error(
`Latest version (${latestVersion}) not newer than current version (${pkg.version})`
);
}
} else if (debug) {
console.error(
`Too recent to check for a new update. simpleUpdateNotifier() interval set to ${updateCheckInterval}ms but only ${
new Date().getTime() - lastUpdateCheck
}ms since last check.`
);
}
return false;
};
export default hasNewVersion;

View File

@@ -0,0 +1,27 @@
import simpleUpdateNotifier from '.';
import hasNewVersion from './hasNewVersion';
const consoleSpy = jest.spyOn(console, 'error');
jest.mock('./hasNewVersion', () => jest.fn().mockResolvedValue('2.0.0'));
beforeEach(jest.clearAllMocks);
test('it logs message if update is available', async () => {
await simpleUpdateNotifier({
pkg: { name: 'test', version: '1.0.0' },
alwaysRun: true,
});
expect(consoleSpy).toHaveBeenCalledTimes(1);
});
test('it does not log message if update is not available', async () => {
(hasNewVersion as jest.Mock).mockResolvedValue(false);
await simpleUpdateNotifier({
pkg: { name: 'test', version: '2.0.0' },
alwaysRun: true,
});
expect(consoleSpy).toHaveBeenCalledTimes(0);
});

View File

@@ -0,0 +1,34 @@
import isNpmOrYarn from './isNpmOrYarn';
import hasNewVersion from './hasNewVersion';
import { IUpdate } from './types';
import borderedText from './borderedText';
const simpleUpdateNotifier = async (args: IUpdate) => {
if (
!args.alwaysRun &&
(!process.stdout.isTTY || (isNpmOrYarn && !args.shouldNotifyInNpmScript))
) {
if (args.debug) {
console.error('Opting out of running simpleUpdateNotifier()');
}
return;
}
try {
const latestVersion = await hasNewVersion(args);
if (latestVersion) {
console.error(
borderedText(`New version of ${args.pkg.name} available!
Current Version: ${args.pkg.version}
Latest Version: ${latestVersion}`)
);
}
} catch (err) {
// Catch any network errors or cache writing errors so module doesn't cause a crash
if (args.debug && err instanceof Error) {
console.error('Unexpected error in simpleUpdateNotifier():', err);
}
}
};
export default simpleUpdateNotifier;

View File

@@ -0,0 +1,12 @@
import process from 'process';
const packageJson = process.env.npm_package_json;
const userAgent = process.env.npm_config_user_agent;
const isNpm6 = Boolean(userAgent && userAgent.startsWith('npm'));
const isNpm7 = Boolean(packageJson && packageJson.endsWith('package.json'));
const isNpm = isNpm6 || isNpm7;
const isYarn = Boolean(userAgent && userAgent.startsWith('yarn'));
const isNpmOrYarn = isNpm || isYarn;
export default isNpmOrYarn;

View File

@@ -0,0 +1,8 @@
export interface IUpdate {
pkg: { name: string; version: string };
updateCheckInterval?: number;
shouldNotifyInNpmScript?: boolean;
distTag?: string;
alwaysRun?: boolean;
debug?: boolean;
}