Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b5424cadb | |||
| 48571f5032 | |||
| c6c9f65040 | |||
| ace6c20164 | |||
| d64b64f39e | |||
| 41a687a63e | |||
| f4f6704510 | |||
| 65fc0fadb3 | |||
| 64b686713b | |||
| 9c6d3e37d4 | |||
| 37abe9db39 | |||
| 9ebef4a268 | |||
| e60f7c7e77 | |||
| 36aadd0604 |
@@ -121,6 +121,8 @@ const chromeExtensionIds = [
|
||||
'lapnciffpekdengooeolaienkeoilfeo', // All API Hub – AI Relay & New API Manager - https://github.com/qixing-jk/all-api-hub
|
||||
'bhgobenflkkhfcgkikejaaejenoddcmo', // Scrape Similar - Extract data from websites into spreadsheets - https://github.com/zizzfizzix/scrape-similar
|
||||
'kinlknncggaihnhdcalijdmpbhbflalm', // isTrust - https://github.com/Internet-Society-Belgium/isTrust/
|
||||
'ojpakgiekphppgkcdihbjpafobhnhlkp', // Dymo
|
||||
'pmgehhllikbjmadpenhabejhpemplhmd', // Extension Rank Checker - Extension Ranker
|
||||
];
|
||||
|
||||
const { data, err, isLoading } = useListExtensionDetails(chromeExtensionIds);
|
||||
|
||||
@@ -76,6 +76,28 @@ Alternatively, if you're trying to use similar APIs under different names (to su
|
||||
});
|
||||
```
|
||||
|
||||
### Augmenting the Browser Type
|
||||
|
||||
WXT's `browser` types are based on the `@types/chrome` package. That means some Firefox-specific APIs may not be typed, like `browser.sidebarAction`. If you want to add types for these APIs, you can augment the browser type to add them yourself:
|
||||
|
||||
```ts
|
||||
// <srcDir>/browser-types.d.ts
|
||||
import '@wxt-dev/browser';
|
||||
import type { SidebarAction } from 'webextension-polyfill';
|
||||
|
||||
declare module '@wxt-dev/browser' {
|
||||
namespace Browser {
|
||||
export const sidebarAction: SidebarAction.Static;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> For this to work, you may need to install `@wxt-dev/browser` as a direct dependency.
|
||||
>
|
||||
> ```sh
|
||||
> pnpm add @wxt-dev/browser
|
||||
> ```
|
||||
|
||||
## Entrypoint Limitations
|
||||
|
||||
Because WXT imports your entrypoint files into a NodeJS, non-extension environment, the `chrome`/`browser` variables provided to extensions by the browser **will not be available**.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@wxt-dev/browser",
|
||||
"description": "Provides a cross-browser API for using extension APIs and types based on @types/chrome",
|
||||
"version": "0.1.37",
|
||||
"version": "0.1.38",
|
||||
"type": "module",
|
||||
"main": "src/index.mjs",
|
||||
"types": "src/index.d.ts",
|
||||
@@ -23,7 +23,7 @@
|
||||
"src"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@types/chrome": "0.1.37",
|
||||
"@types/chrome": "0.1.38",
|
||||
"@types/node": "^20.0.0",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
+11
-8
@@ -4076,14 +4076,17 @@ export namespace Browser {
|
||||
id: string;
|
||||
/**
|
||||
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are hardware-backed.
|
||||
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 and RSA-OAEP (on Chrome versions 134+) with `modulusLength` up to 2048 and ECDSA with `namedCurve` P-256. Each RSASSA-PKCS1-V1_5 and ECDSA key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely. RSA-OAEP keys are supported since Chrome version 134 and can be used by extensions allowlisted through that same policy to unwrap other keys.
|
||||
*
|
||||
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 with `modulusLength` up to 2048 and ECDSA with `namedCurve` P-256. Each key can be used for signing data at most once, unless the extension is allowlisted by the KeyPermissions policy, in which case the key can be used indefinitely.
|
||||
*
|
||||
* Keys generated on a specific `Token` cannot be used with any other Tokens, nor can they be used with `window.crypto.subtle`. Equally, `Key` objects created with `window.crypto.subtle` cannot be used with this interface.
|
||||
*/
|
||||
subtleCrypto: SubtleCrypto;
|
||||
/**
|
||||
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are software-backed.
|
||||
* Protection of the keys, and thus implementation of the non-extractable property, is done in software, so the keys are less protected than hardware-backed keys.
|
||||
* Only non-extractable keys can be generated. The supported key types are RSASSA-PKCS1-V1_5 and RSA-OAEP (on Chrome versions 134+) with `modulusLength` up to 2048. Each RSASSA-PKCS1-V1_5 key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely. RSA-OAEP keys are supported since Chrome version 134 and can be used by extensions allowlisted through that same policy to unwrap other keys.
|
||||
* Implements the WebCrypto's SubtleCrypto interface. The cryptographic operations, including key generation, are software-backed. Protection of the keys, and thus implementation of the non-extractable property, is done in software, so the keys are less protected than hardware-backed keys.
|
||||
*
|
||||
* Only non-extractable keys can be generated. The only supported key type is RSASSA-PKCS1-V1_5 with `modulusLength` up to 2048. up to 2048. Each key can be used for signing data at most once, unless the extension is allowlisted through the KeyPermissions policy, in which case the key can be used indefinitely.
|
||||
*
|
||||
* Keys generated on a specific `Token` cannot be used with any other Tokens, nor can they be used with `window.crypto.subtle`. Equally, `Key` objects created with `window.crypto.subtle` cannot be used with this interface.
|
||||
* @since Chrome 97
|
||||
*/
|
||||
@@ -9692,7 +9695,7 @@ export namespace Browser {
|
||||
/** Sent after onSuspend to indicate that the app won't be unloaded after all. */
|
||||
export const onSuspendCanceled: events.Event<() => void>;
|
||||
|
||||
/** Fired when a message is sent from either an extension process (by {@link runtime.sendMessage}) or a content script (by {@link tabs.sendMessage}). */
|
||||
/** Fired when a message is sent from either {@link runtime.sendMessage} or {@link tabs.sendMessage}. */
|
||||
export const onMessage: events.Event<
|
||||
(message: any, sender: MessageSender, sendResponse: (response?: any) => void) => void
|
||||
>;
|
||||
@@ -11058,7 +11061,7 @@ export namespace Browser {
|
||||
sessionId?: string | undefined;
|
||||
/**
|
||||
* The ID of the Split View that the tab belongs to.
|
||||
* @since Chrome 145
|
||||
* @since Chrome 140
|
||||
*/
|
||||
splitViewId?: number | undefined;
|
||||
/**
|
||||
@@ -11134,7 +11137,7 @@ export namespace Browser {
|
||||
|
||||
/**
|
||||
* An ID that represents the absence of a split tab.
|
||||
* @since Chrome 145
|
||||
* @since Chrome 140
|
||||
*/
|
||||
export const SPLIT_VIEW_ID_NONE: -1;
|
||||
|
||||
@@ -11581,7 +11584,7 @@ export namespace Browser {
|
||||
export function duplicate(tabId: number, callback: (tab?: Tab) => void): void;
|
||||
|
||||
/**
|
||||
* Sends a single message to the content script(s) in the specified tab, with an optional callback to run when a response is sent back. The {@link runtime.onMessage} event is fired in each content script running in the specified tab for the current extension.
|
||||
* Sends a single message to the content script(s) in the specified tab. The {@link runtime.onMessage} event is fired in each content script running in the specified tab for the current extension.
|
||||
*
|
||||
* Can return its result via Promise in Manifest V3 or later since Chrome 99.
|
||||
*/
|
||||
|
||||
@@ -16,12 +16,25 @@ export { SUPPORTED_LOCALES } from './supported-locales';
|
||||
// TYPES
|
||||
//
|
||||
|
||||
export type SimpleMessage = string;
|
||||
|
||||
export type PluralMessage = Record<'n' | number, string>;
|
||||
|
||||
export interface ChromeMessage {
|
||||
message: string;
|
||||
description?: string;
|
||||
placeholders?: Record<string, { content: string; example?: string }>;
|
||||
}
|
||||
|
||||
export type Message =
|
||||
| SimpleMessage
|
||||
| PluralMessage
|
||||
| ChromeMessage
|
||||
| Message[]
|
||||
| { [key: string]: Message };
|
||||
|
||||
export type MessagesObject = Record<string, Message>;
|
||||
|
||||
export interface ParsedBaseMessage {
|
||||
key: string[];
|
||||
substitutions: number;
|
||||
@@ -95,7 +108,7 @@ const EXT_FORMATS_MAP: Record<string, MessageFormat> = {
|
||||
'.toml': 'TOML',
|
||||
};
|
||||
|
||||
const PARSERS: Record<MessageFormat, (text: string) => any> = {
|
||||
const PARSERS: Record<MessageFormat, (text: string) => MessagesObject> = {
|
||||
YAML: parseYAML,
|
||||
JSON5: parseJSON5,
|
||||
TOML: parseTOML,
|
||||
@@ -117,6 +130,7 @@ export async function parseMessagesFile(
|
||||
): Promise<ParsedMessage[]> {
|
||||
const text = await readFile(file, 'utf8');
|
||||
const ext = extname(file).toLowerCase();
|
||||
|
||||
return parseMessagesText(text, EXT_FORMATS_MAP[ext] ?? 'JSON5');
|
||||
}
|
||||
|
||||
@@ -129,7 +143,7 @@ export function parseMessagesText(
|
||||
}
|
||||
|
||||
/** Given the JS object form of a raw messages file, extract the messages. */
|
||||
export function parseMessagesObject(object: any): ParsedMessage[] {
|
||||
export function parseMessagesObject(object: MessagesObject): ParsedMessage[] {
|
||||
return _parseMessagesObject(
|
||||
[],
|
||||
{
|
||||
@@ -142,7 +156,7 @@ export function parseMessagesObject(object: any): ParsedMessage[] {
|
||||
|
||||
function _parseMessagesObject(
|
||||
path: string[],
|
||||
object: any,
|
||||
object: Message,
|
||||
depth: number,
|
||||
): ParsedMessage[] {
|
||||
switch (typeof object) {
|
||||
@@ -163,15 +177,17 @@ function _parseMessagesObject(
|
||||
];
|
||||
}
|
||||
case 'object':
|
||||
if ([null, undefined].includes(object)) {
|
||||
if (object == null) {
|
||||
throw new Error(
|
||||
`Messages file should not contain \`${object}\` (found at "${path.join('.')}")`,
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(object))
|
||||
return object.flatMap((item, i) =>
|
||||
_parseMessagesObject(path.concat(String(i)), item, depth + 1),
|
||||
);
|
||||
|
||||
if (isPluralMessage(object)) {
|
||||
const message = Object.values(object).join('|');
|
||||
const substitutions = getSubstitutionCount(message);
|
||||
@@ -184,6 +200,7 @@ function _parseMessagesObject(
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (depth === 1 && isChromeMessage(object)) {
|
||||
const message = applyChromeMessagePlaceholders(object);
|
||||
const substitutions = getSubstitutionCount(message);
|
||||
@@ -196,6 +213,7 @@ function _parseMessagesObject(
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return Object.entries(object).flatMap(([key, value]) =>
|
||||
_parseMessagesObject(path.concat(key), value, depth + 1),
|
||||
);
|
||||
@@ -204,13 +222,13 @@ function _parseMessagesObject(
|
||||
}
|
||||
}
|
||||
|
||||
function isPluralMessage(object: any): object is Record<number | 'n', string> {
|
||||
function isPluralMessage(object: Message): object is PluralMessage {
|
||||
return Object.keys(object).every(
|
||||
(key) => key === 'n' || isFinite(Number(key)),
|
||||
);
|
||||
}
|
||||
|
||||
function isChromeMessage(object: any): object is ChromeMessage {
|
||||
function isChromeMessage(object: Message): object is ChromeMessage {
|
||||
return Object.keys(object).every((key) =>
|
||||
ALLOWED_CHROME_MESSAGE_KEYS.has(key),
|
||||
);
|
||||
@@ -222,7 +240,7 @@ function isChromeMessage(object: any): object is ChromeMessage {
|
||||
|
||||
export function generateTypeText(messages: ParsedMessage[]): string {
|
||||
const renderMessageEntry = (message: ParsedMessage): string => {
|
||||
// Use . for deep keys at runtime and types
|
||||
// Use '.' for deep keys at runtime and types
|
||||
const key = message.key.join('.');
|
||||
|
||||
const features = [
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
## v2.0.5
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v2.0.4...module-svelte-v2.0.5)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Update `@sveltejs/vite-plugin-svelte` version range to support Vite 8 ([48571f50](https://github.com/wxt-dev/wxt/commit/48571f50))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- Upgrade dev and non-major prod dependencies ([#2000](https://github.com/wxt-dev/wxt/pull/2000))
|
||||
- Use `tsdown` to build packages ([#2006](https://github.com/wxt-dev/wxt/pull/2006))
|
||||
- Move script-only dev dependencies to top-level `package.json` ([#2007](https://github.com/wxt-dev/wxt/pull/2007))
|
||||
- Update dependencies ([#2069](https://github.com/wxt-dev/wxt/pull/2069))
|
||||
- **deps:** Upgrade deps ([#2175](https://github.com/wxt-dev/wxt/pull/2175))
|
||||
- Add prepack script to all packages ([032f7931](https://github.com/wxt-dev/wxt/commit/032f7931))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
|
||||
## v2.0.4
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/module-svelte-v2.0.3...module-svelte-v2.0.4)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/wxt-dev",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.5",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.mjs",
|
||||
@@ -48,7 +48,7 @@
|
||||
"svelte": ">=5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^4.0.0 || ^5.0.0 || ^6.0.0"
|
||||
"@sveltejs/vite-plugin-svelte": ">=4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"publint": "^0.3.18",
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# Changelog
|
||||
|
||||
## v0.20.20
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.19...wxt-v0.20.20)
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- Unlisted script return values broken with Vite 8 sourcemaps ([#2197](https://github.com/wxt-dev/wxt/pull/2197))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- Add Dymo extension ID to UsingWxtSection.vue ([#2187](https://github.com/wxt-dev/wxt/pull/2187))
|
||||
- Add Extension Rank Checker to the list of extensions ([#2193](https://github.com/wxt-dev/wxt/pull/2193))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **deps:** Add vite-node 6 support ([64b68671](https://github.com/wxt-dev/wxt/commit/64b68671))
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Aaron ([@aklinker1](https://github.com/aklinker1))
|
||||
- Joseph Hu ([@KiJO94GO](https://github.com/KiJO94GO))
|
||||
- FJRG2007 ツ ([@FJRG2007](https://github.com/FJRG2007))
|
||||
- Hampus Tågerud ([@hampustagerud](https://github.com/hampustagerud))
|
||||
|
||||
## v0.20.19
|
||||
|
||||
[compare changes](https://github.com/wxt-dev/wxt/compare/wxt-v0.20.18...wxt-v0.20.19)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wxt",
|
||||
"type": "module",
|
||||
"version": "0.20.19",
|
||||
"version": "0.20.20",
|
||||
"description": "⚡ Next-gen Web Extension Framework",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
@@ -30,7 +30,6 @@
|
||||
"ci-info": "^4.4.0",
|
||||
"consola": "^3.4.2",
|
||||
"defu": "^6.1.4",
|
||||
"dotenv": "^17.3.1",
|
||||
"dotenv-expand": "^12.0.3",
|
||||
"esbuild": "^0.27.1",
|
||||
"filesize": "^11.0.13",
|
||||
@@ -43,7 +42,6 @@
|
||||
"jszip": "^3.10.1",
|
||||
"linkedom": "^0.18.12",
|
||||
"magicast": "^0.5.2",
|
||||
"minimatch": "^10.2.4",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"nanospinner": "^1.2.2",
|
||||
"normalize-path": "^3.0.0",
|
||||
@@ -52,13 +50,14 @@
|
||||
"open": "^11.0.0",
|
||||
"perfect-debounce": "^2.1.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"picomatch": "^4.0.3",
|
||||
"prompts": "^2.4.2",
|
||||
"publish-browser-extension": "^2.3.0 || ^3.0.2 || ^4.0.4",
|
||||
"scule": "^1.3.0",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0",
|
||||
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0",
|
||||
"vite-node": "^3.2.4 || ^5.0.0",
|
||||
"vite-node": "^3.2.4 || ^5.0.0 || ^6.0.0",
|
||||
"web-ext-run": "^0.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -74,6 +73,7 @@
|
||||
"@types/lodash.merge": "^4.6.9",
|
||||
"@types/node": "^20.17.6",
|
||||
"@types/normalize-path": "^3.0.2",
|
||||
"@types/picomatch": "^4.0.2",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"eslint": "^10.0.0",
|
||||
"extract-zip": "^2.0.1",
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { iifeFooter } from '../iifeFooter';
|
||||
|
||||
interface OutputChunk {
|
||||
type: 'chunk';
|
||||
code: string;
|
||||
isEntry: boolean;
|
||||
}
|
||||
|
||||
interface OutputAsset {
|
||||
type: 'asset';
|
||||
source: string;
|
||||
}
|
||||
|
||||
type OutputBundle = Record<string, OutputChunk | OutputAsset>;
|
||||
|
||||
function dedent(code: string) {
|
||||
const lines = code.trim().split('\n');
|
||||
return lines.map((line) => line.trimStart()).join('\n');
|
||||
}
|
||||
|
||||
function createBundle(code: string): OutputBundle {
|
||||
return {
|
||||
'entry.js': {
|
||||
type: 'chunk',
|
||||
code: dedent(code),
|
||||
isEntry: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function getCode(bundle: OutputBundle): string {
|
||||
const entry = bundle['entry.js'];
|
||||
|
||||
if (entry.type !== 'chunk') {
|
||||
throw new Error('expected chunk');
|
||||
}
|
||||
|
||||
return entry.code;
|
||||
}
|
||||
|
||||
function runPlugin(name: string, bundle: OutputBundle) {
|
||||
const plugin = iifeFooter(name);
|
||||
// @ts-expect-error -- calling the hook directly
|
||||
plugin.generateBundle(undefined, bundle);
|
||||
}
|
||||
|
||||
describe('IIFE return value plugin', () => {
|
||||
it('should append return value when no sourcemap comment', () => {
|
||||
const bundle = createBundle(`
|
||||
var foo = (function(){return 1})();
|
||||
`);
|
||||
|
||||
runPlugin('foo', bundle);
|
||||
|
||||
expect(getCode(bundle)).toBe(
|
||||
dedent(`
|
||||
var foo = (function(){return 1})();
|
||||
foo;
|
||||
`),
|
||||
);
|
||||
});
|
||||
|
||||
it('should insert return value before sourcemap comment', () => {
|
||||
const bundle = createBundle(`
|
||||
var foo = (function(){return 1})();
|
||||
//# ${'sourceMappingURL'}=foo.js.map
|
||||
`);
|
||||
|
||||
runPlugin('foo', bundle);
|
||||
|
||||
expect(getCode(bundle)).toBe(
|
||||
dedent(`
|
||||
var foo = (function(){return 1})();
|
||||
foo;
|
||||
//# ${'sourceMappingURL'}=foo.js.map
|
||||
`),
|
||||
);
|
||||
});
|
||||
|
||||
it('should insert return value before inline sourcemap', () => {
|
||||
const bundle = createBundle(`
|
||||
var foo = (function(){return 1})();
|
||||
//# ${'sourceMappingURL'}=data:application/json;base64,abc123
|
||||
`);
|
||||
|
||||
runPlugin('foo', bundle);
|
||||
|
||||
expect(getCode(bundle)).toBe(
|
||||
dedent(`
|
||||
var foo = (function(){return 1})();
|
||||
foo;
|
||||
//# ${'sourceMappingURL'}=data:application/json;base64,abc123
|
||||
`),
|
||||
);
|
||||
});
|
||||
|
||||
it('should skip non-entry chunks', () => {
|
||||
const bundle = createBundle('var x = 1;');
|
||||
(bundle['entry.js'] as OutputChunk).isEntry = false;
|
||||
|
||||
runPlugin('x', bundle);
|
||||
|
||||
expect(getCode(bundle)).toBe('var x = 1;');
|
||||
});
|
||||
|
||||
it('should skip assets', () => {
|
||||
const bundle: OutputBundle = {
|
||||
'style.css': {
|
||||
type: 'asset',
|
||||
source: 'body {}',
|
||||
} satisfies OutputAsset,
|
||||
};
|
||||
|
||||
runPlugin('style', bundle);
|
||||
|
||||
expect((bundle['style.css'] as OutputAsset).source).toBe('body {}');
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,20 @@ export function iifeFooter(iifeReturnValueName: string): Plugin {
|
||||
generateBundle(_, bundle) {
|
||||
for (const chunk of Object.values(bundle)) {
|
||||
if (chunk.type === 'chunk' && chunk.isEntry) {
|
||||
chunk.code += `${iifeReturnValueName};`;
|
||||
const code = chunk.code;
|
||||
const marker = '\n//# sourceMappingURL=';
|
||||
const returnValue = `${iifeReturnValueName};`;
|
||||
|
||||
const index = code.indexOf(marker);
|
||||
|
||||
if (index >= 0) {
|
||||
chunk.code =
|
||||
code.slice(0, index + 1) +
|
||||
`${returnValue}\n` +
|
||||
code.slice(index + 1);
|
||||
} else {
|
||||
chunk.code += `\n${returnValue}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { minimatchMultiple } from '../minimatch-multiple';
|
||||
|
||||
describe('minimatchMultiple', () => {
|
||||
it('should return false if the pattern array is undefined', () => {
|
||||
const patterns = undefined;
|
||||
const search = 'test.json';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern array is empty', () => {
|
||||
const patterns: string[] = [];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if the pattern array contains a match', () => {
|
||||
const patterns = ['test.yml', 'test.json'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the pattern array does not contain a match', () => {
|
||||
const patterns = ['test.yml', 'test.json'];
|
||||
const search = 'test.txt';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern matches a negative pattern', () => {
|
||||
const patterns = ['test.*', '!test.json'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern matches a negative pattern, regardless of order', () => {
|
||||
const patterns = ['!test.json', 'test.*'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(minimatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { picomatchMultiple } from '../picomatch-multiple';
|
||||
|
||||
describe('picomatchMultiple', () => {
|
||||
it('should return false if the pattern array is undefined', () => {
|
||||
const patterns = undefined;
|
||||
const search = 'test.json';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern array is empty', () => {
|
||||
const patterns: string[] = [];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if the pattern array contains a match', () => {
|
||||
const patterns = ['test.yml', 'test.json'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the pattern array does not contain a match', () => {
|
||||
const patterns = ['test.yml', 'test.json'];
|
||||
const search = 'test.txt';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern matches a negative pattern', () => {
|
||||
const patterns = ['test.*', '!test.json'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the pattern matches a negative pattern, regardless of order', () => {
|
||||
const patterns = ['!test.json', 'test.*'];
|
||||
const search = 'test.json';
|
||||
|
||||
expect(picomatchMultiple(search, patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should support extglob-like extension matching', () => {
|
||||
const patterns = ['content.[jt]s?(x)'];
|
||||
|
||||
expect(picomatchMultiple('content.ts', patterns)).toBe(true);
|
||||
expect(picomatchMultiple('content.jsx', patterns)).toBe(true);
|
||||
expect(picomatchMultiple('content.css', patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should support nested paths', () => {
|
||||
const patterns = ['foo/**/*.ts'];
|
||||
|
||||
expect(picomatchMultiple('foo/bar/baz.ts', patterns)).toBe(true);
|
||||
expect(picomatchMultiple('foo/bar/baz.js', patterns)).toBe(false);
|
||||
});
|
||||
|
||||
it('should preserve include/exclude interaction used by zip filtering', () => {
|
||||
const include = ['special.txt'];
|
||||
const exclude = ['**/*.txt'];
|
||||
const search = 'special.txt';
|
||||
const shouldInclude =
|
||||
picomatchMultiple(search, include) || !picomatchMultiple(search, exclude);
|
||||
|
||||
expect(shouldInclude).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
UnlistedScriptEntrypoint,
|
||||
} from '../../../types';
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import { minimatch } from 'minimatch';
|
||||
import picomatch from 'picomatch';
|
||||
import { parseHTML } from 'linkedom';
|
||||
import JSON5 from 'json5';
|
||||
import { glob } from 'tinyglobby';
|
||||
@@ -61,7 +61,7 @@ export async function findEntrypoints(): Promise<Entrypoint[]> {
|
||||
const inputPath = resolve(wxt.config.entrypointsDir, relativePath);
|
||||
const name = getEntrypointName(wxt.config.entrypointsDir, inputPath);
|
||||
const matchingGlob = pathGlobs.find((glob) =>
|
||||
minimatch(relativePath, glob),
|
||||
picomatch(glob)(relativePath),
|
||||
);
|
||||
if (matchingGlob) {
|
||||
const type = PATH_GLOB_TO_TYPE_MAP[matchingGlob];
|
||||
|
||||
@@ -1,23 +1,45 @@
|
||||
import { config } from 'dotenv';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { parseEnv } from 'node:util';
|
||||
import { expand } from 'dotenv-expand';
|
||||
import type { TargetBrowser } from '../../types';
|
||||
|
||||
/** Load environment files based on the current mode and browser. */
|
||||
export function loadEnv(mode: string, browser: TargetBrowser) {
|
||||
return expand(
|
||||
config({
|
||||
quiet: true,
|
||||
// Files on top override files below
|
||||
path: [
|
||||
`.env.${mode}.${browser}.local`,
|
||||
`.env.${mode}.${browser}`,
|
||||
`.env.${browser}.local`,
|
||||
`.env.${browser}`,
|
||||
`.env.${mode}.local`,
|
||||
`.env.${mode}`,
|
||||
`.env.local`,
|
||||
`.env`,
|
||||
],
|
||||
const envFiles = [
|
||||
// List is ordered with general files first, specific ones last, so the more
|
||||
// specific files override the more general ones in the loop below.
|
||||
`.env`,
|
||||
`.env.local`,
|
||||
`.env.${mode}`,
|
||||
`.env.${mode}.local`,
|
||||
`.env.${browser}`,
|
||||
`.env.${browser}.local`,
|
||||
`.env.${mode}.${browser}`,
|
||||
`.env.${mode}.${browser}.local`,
|
||||
];
|
||||
|
||||
const parsed = Object.fromEntries<string>(
|
||||
envFiles.flatMap((filePath) => {
|
||||
if (!existsSync(filePath)) return [];
|
||||
|
||||
try {
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
const parsedEnv = parseEnv(content);
|
||||
return Object.entries(parsedEnv) as [string, string][];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// Make a copy of `process.env` so that `dotenv-expand` doesn't re-assign the
|
||||
// expanded values to the global `process.env`.
|
||||
const processEnv = { ...process.env } as Record<string, string>;
|
||||
|
||||
expand({
|
||||
parsed,
|
||||
processEnv,
|
||||
});
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,7 +1,7 @@
|
||||
import { minimatch, MinimatchOptions } from 'minimatch';
|
||||
import picomatch, { PicomatchOptions } from 'picomatch';
|
||||
|
||||
/**
|
||||
* Run [`minimatch`](https://npmjs.com/package/minimatch) against multiple
|
||||
* Run [`picomatch`](https://npmjs.com/package/picomatch) against multiple
|
||||
* patterns.
|
||||
*
|
||||
* Supports negated patterns, the order does not matter. If your `search` string
|
||||
@@ -9,14 +9,14 @@ import { minimatch, MinimatchOptions } from 'minimatch';
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* minimatchMultiple('a.json', ['*.json', '!b.json']); // => true
|
||||
* minimatchMultiple('b.json', ['*.json', '!b.json']); // => false
|
||||
* picomatchMultiple('a.json', ['*.json', '!b.json']); // => true
|
||||
* picomatchMultiple('b.json', ['*.json', '!b.json']); // => false
|
||||
* ```;
|
||||
*/
|
||||
export function minimatchMultiple(
|
||||
export function picomatchMultiple(
|
||||
search: string,
|
||||
patterns: string[] | undefined,
|
||||
options?: MinimatchOptions,
|
||||
options?: PicomatchOptions,
|
||||
): boolean {
|
||||
if (patterns == null) return false;
|
||||
|
||||
@@ -29,12 +29,12 @@ export function minimatchMultiple(
|
||||
|
||||
if (
|
||||
negatePatterns.some((negatePattern) =>
|
||||
minimatch(search, negatePattern, options),
|
||||
picomatch(negatePattern, options)(search),
|
||||
)
|
||||
)
|
||||
return false;
|
||||
|
||||
return positivePatterns.some((positivePattern) =>
|
||||
minimatch(search, positivePattern, options),
|
||||
picomatch(positivePattern, options)(search),
|
||||
);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { registerWxt, wxt } from './wxt';
|
||||
import JSZip from 'jszip';
|
||||
import { glob } from 'tinyglobby';
|
||||
import { normalizePath } from './utils';
|
||||
import { minimatchMultiple } from './utils/minimatch-multiple';
|
||||
import { picomatchMultiple } from './utils/picomatch-multiple';
|
||||
|
||||
/**
|
||||
* Build and zip the extension for distribution.
|
||||
@@ -125,8 +125,8 @@ async function zipDir(
|
||||
})
|
||||
).filter((relativePath) => {
|
||||
return (
|
||||
minimatchMultiple(relativePath, options?.include) ||
|
||||
!minimatchMultiple(relativePath, options?.exclude)
|
||||
picomatchMultiple(relativePath, options?.include) ||
|
||||
!picomatchMultiple(relativePath, options?.exclude)
|
||||
);
|
||||
});
|
||||
const filesToZip = [
|
||||
|
||||
@@ -212,7 +212,7 @@ export interface InlineConfig {
|
||||
*/
|
||||
sourcesRoot?: string;
|
||||
/**
|
||||
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
|
||||
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
|
||||
* include when creating a ZIP of all your source code for Firefox. Patterns
|
||||
* are relative to your `config.zip.sourcesRoot`.
|
||||
*
|
||||
@@ -226,7 +226,7 @@ export interface InlineConfig {
|
||||
*/
|
||||
includeSources?: string[];
|
||||
/**
|
||||
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
|
||||
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
|
||||
* exclude when creating a ZIP of all your source code for Firefox. Patterns
|
||||
* are relative to your `config.zip.sourcesRoot`.
|
||||
*
|
||||
@@ -239,7 +239,7 @@ export interface InlineConfig {
|
||||
*/
|
||||
excludeSources?: string[];
|
||||
/**
|
||||
* [Minimatch](https://www.npmjs.com/package/minimatch) patterns of files to
|
||||
* [Picomatch](https://www.npmjs.com/package/picomatch) patterns of files to
|
||||
* exclude when zipping the extension.
|
||||
*
|
||||
* @example
|
||||
|
||||
Generated
+18
-13
@@ -173,8 +173,8 @@ importers:
|
||||
version: 1.2.16
|
||||
devDependencies:
|
||||
'@types/chrome':
|
||||
specifier: 0.1.37
|
||||
version: 0.1.37
|
||||
specifier: 0.1.38
|
||||
version: 0.1.38
|
||||
'@types/node':
|
||||
specifier: ^20.0.0
|
||||
version: 20.19.32
|
||||
@@ -297,7 +297,7 @@ importers:
|
||||
packages/module-svelte:
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte':
|
||||
specifier: ^4.0.0 || ^5.0.0 || ^6.0.0
|
||||
specifier: '>=4'
|
||||
version: 6.2.4(vite@7.3.1(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))
|
||||
devDependencies:
|
||||
publint:
|
||||
@@ -456,9 +456,6 @@ importers:
|
||||
defu:
|
||||
specifier: ^6.1.4
|
||||
version: 6.1.4
|
||||
dotenv:
|
||||
specifier: ^17.3.1
|
||||
version: 17.3.1
|
||||
dotenv-expand:
|
||||
specifier: ^12.0.3
|
||||
version: 12.0.3
|
||||
@@ -495,9 +492,6 @@ importers:
|
||||
magicast:
|
||||
specifier: ^0.5.2
|
||||
version: 0.5.2
|
||||
minimatch:
|
||||
specifier: ^10.2.4
|
||||
version: 10.2.4
|
||||
nano-spawn:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
@@ -522,6 +516,9 @@ importers:
|
||||
picocolors:
|
||||
specifier: ^1.1.1
|
||||
version: 1.1.1
|
||||
picomatch:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3
|
||||
prompts:
|
||||
specifier: ^2.4.2
|
||||
version: 2.4.2
|
||||
@@ -541,7 +538,7 @@ importers:
|
||||
specifier: ^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0
|
||||
version: 7.3.1(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
|
||||
vite-node:
|
||||
specifier: ^3.2.4 || ^5.0.0
|
||||
specifier: ^3.2.4 || ^5.0.0 || ^6.0.0
|
||||
version: 5.3.0(@types/node@20.19.32)(jiti@2.6.1)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)
|
||||
web-ext-run:
|
||||
specifier: ^0.2.4
|
||||
@@ -559,6 +556,9 @@ importers:
|
||||
'@types/normalize-path':
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
'@types/picomatch':
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
'@types/prompts':
|
||||
specifier: ^2.4.9
|
||||
version: 2.4.9
|
||||
@@ -2129,8 +2129,8 @@ packages:
|
||||
'@types/chai@5.2.3':
|
||||
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
|
||||
|
||||
'@types/chrome@0.1.37':
|
||||
resolution: {integrity: sha512-IJE4ceuDO7lrEuua7Pow47zwNcI8E6qqkowRP7aFPaZ0lrjxh6y836OPqqkIZeTX64FTogbw+4RNH0+QrweCTQ==}
|
||||
'@types/chrome@0.1.38':
|
||||
resolution: {integrity: sha512-5aK4m9wZqoWAoB98aElESLm/5pXpqJnFWMNoiCs/XdPsXR6wNdVkJFSdQ9Wr4PnTuUrxD0SuNuDHh3EG5QeBzA==}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
@@ -2195,6 +2195,9 @@ packages:
|
||||
'@types/normalize-path@3.0.2':
|
||||
resolution: {integrity: sha512-DO++toKYPaFn0Z8hQ7Tx+3iT9t77IJo/nDiqTXilgEP+kPNIYdpS9kh3fXuc53ugqwp9pxC1PVjCpV1tQDyqMA==}
|
||||
|
||||
'@types/picomatch@4.0.2':
|
||||
resolution: {integrity: sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==}
|
||||
|
||||
'@types/prompts@2.4.9':
|
||||
resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==}
|
||||
|
||||
@@ -6237,7 +6240,7 @@ snapshots:
|
||||
'@types/deep-eql': 4.0.2
|
||||
assertion-error: 2.0.1
|
||||
|
||||
'@types/chrome@0.1.37':
|
||||
'@types/chrome@0.1.38':
|
||||
dependencies:
|
||||
'@types/filesystem': 0.0.36
|
||||
'@types/har-format': 1.2.16
|
||||
@@ -6299,6 +6302,8 @@ snapshots:
|
||||
|
||||
'@types/normalize-path@3.0.2': {}
|
||||
|
||||
'@types/picomatch@4.0.2': {}
|
||||
|
||||
'@types/prompts@2.4.9':
|
||||
dependencies:
|
||||
'@types/node': 20.19.32
|
||||
|
||||
Vendored
+1
-1
@@ -23,6 +23,6 @@
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@wxt-dev/module-react": "^1.1.5",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.19"
|
||||
"wxt": "^0.20.20"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -20,6 +20,6 @@
|
||||
"devDependencies": {
|
||||
"@wxt-dev/module-solid": "^1.1.4",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.19"
|
||||
"wxt": "^0.20.20"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -21,6 +21,6 @@
|
||||
"svelte-check": "^4.4.4",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.19"
|
||||
"wxt": "^0.20.20"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-4
@@ -1,6 +1,3 @@
|
||||
{
|
||||
"extends": "./.wxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"useDefineForClassFields": true
|
||||
}
|
||||
"extends": "./.wxt/tsconfig.json"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -16,6 +16,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
"wxt": "^0.20.19"
|
||||
"wxt": "^0.20.20"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -21,6 +21,6 @@
|
||||
"@wxt-dev/module-vue": "^1.0.3",
|
||||
"typescript": "^5.9.3",
|
||||
"vue-tsc": "^3.2.5",
|
||||
"wxt": "^0.20.19"
|
||||
"wxt": "^0.20.20"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user