Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .release-it.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const createReleaseConfig = () => {

github: {
release: true,
releaseName: "v${version}",
releaseName: "Addon Bone v${version}",
autoGenerate: false,
releaseNotes: ({changelog}) => changelog,
},
Expand Down Expand Up @@ -226,8 +226,7 @@ const createReleaseConfig = () => {

whatBump,
writerOpts: {
headerPartial:
"## 🚀 Release {{#if name}}`{{name}}` {{else}}{{#if @root.pkg}}`{{@root.pkg.name}}` {{/if}}{{/if}}v{{version}} ({{date}})\n\n",
headerPartial: "## 🚀 Release Addon Bone v{{version}} ({{date}})\n\n",
footerPartial: `{{#if @root.contributors.length}}\n### 🙌 Contributors\n\n{{#each @root.contributors}}- {{#if url}}{{#if name}}[{{name}}]({{url}}){{#if login}} (@{{login}}){{/if}}{{else}}[@{{login}}]({{url}}){{/if}}{{else}}{{#if email}}{{#if name}}[{{name}}](mailto:{{email}}){{else}}{{email}}{{/if}}{{else}}{{name}}{{/if}}{{/if}} — commits: {{count}}\n{{/each}}{{/if}}`,
mainTemplate:
"{{> header}}\n" +
Expand Down
38 changes: 19 additions & 19 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@
"prepublishOnly": "npm run build",
"build": "tsup && tsc -p tsconfig.build.json && node ./scripts/copy-dts.js && tsc-alias -p tsconfig.build.json -f -fe .js",
"format": "prettier --write .",
"typecheck": "tsc -p tsconfig.json --noEmit",
"typecheck": "tsc -p tsconfig.json --noEmit && npm run typecheck:tests",
"typecheck:tests": "tsc -p tsconfig.tests.json --noEmit",
"check:node-version": "node ./scripts/check-node-version.js",
"test": "npm run build && jest",
"test:ci": "npm run test -- --ci --passWithNoTests --coverage",
Expand All @@ -126,8 +127,8 @@
"release:preview": "release-it --no-github.release --no-npm.publish --no-git.tag --ci"
},
"dependencies": {
"@addon-core/browser": "^0.7.1",
"@addon-core/inject-script": "^0.3.1",
"@addon-core/browser": "^0.7.2",
"@addon-core/inject-script": "^0.5.0",
"@addon-core/storage": "^0.7.0",
"@rsdoctor/rspack-plugin": "^1.5.1",
"@rspack/cli": "^1.7.5",
Expand Down
25 changes: 25 additions & 0 deletions src/cli/builders/locale/LocaleStructureValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,31 @@ describe("LocaleStructureValidator", () => {
);
});

test("rejects an omitted plural key before default-locale completion", () => {
const builders = makeBuilders([
[Language.English, {cart: {items: ["{{count}} item", "{{count}} items"]}}],
[Language.French, {title: "Panier"}],
]);

const validator = new LocaleStructureValidator(Language.English);

expect(() => validator.validate(builders)).toThrow(
'Locale "fr" is missing plural key "cart.items" required by default locale "en"'
);
expect(validator.isValid(builders)).toBe(false);
});

test("accepts a target-language plural supplied by an earlier merge", () => {
const builders = makeBuilders([
[Language.English, {cart: {items: ["item", "items"]}}],
[Language.French, {cart: {items: ["article", "articles"]}}],
]);

builders.get(Language.French)!.merge({title: "Panier"});

expect(new LocaleStructureValidator(Language.English).isValid(builders)).toBe(true);
});

test("warns about keys outside the default locale contract", () => {
const builders = makeBuilders([
[Language.English, {app: {name: "My App"}}],
Expand Down
8 changes: 8 additions & 0 deletions src/cli/builders/locale/LocaleStructureValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ export default class implements LocaleContractValidator {

const structure = builder.structure();

for (const [key, expected] of Object.entries(defaultStructure)) {
if (expected.plural && !Object.hasOwn(structure, key)) {
throw new Error(
`Locale "${language}" is missing plural key "${key}" required by default locale "${this.defaultLanguage}"`
);
}
}

for (const [key, locale] of Object.entries(structure)) {
const expected = defaultStructure[key];

Expand Down
31 changes: 31 additions & 0 deletions src/cli/bundler/plugins/GenerateJsonPlugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {rspack, Compiler} from "@rspack/core";
import GenerateJsonPlugin from "./GenerateJsonPlugin";

describe("GenerateJsonPlugin watch updates", () => {
let compiler: Compiler;

afterEach(async () => {
await new Promise<void>((resolve, reject) => compiler.close(error => (error ? reject(error) : resolve())));
});

test("propagates validation failures to the compiler and allows a later valid update", async () => {
const error = new Error('Locale "fr" is missing plural key "cart.items" required by default locale "en"');
const update = jest.fn(async () => ({"messages.json": {title: "Updated"}}));
update.mockRejectedValueOnce(error);
compiler = rspack({
mode: "none",
entry: {},
plugins: [new GenerateJsonPlugin({}).watch(update)],
});

await expect(compiler.hooks.watchRun.promise(compiler)).rejects.toThrow(error);
await expect(compiler.hooks.watchRun.promise(compiler)).resolves.toBeUndefined();
expect(update).toHaveBeenCalledTimes(2);
});

test("allows watch builds without an update callback", async () => {
compiler = rspack({mode: "none", entry: {}, plugins: [new GenerateJsonPlugin({})]});

await expect(compiler.hooks.watchRun.promise(compiler)).resolves.toBeUndefined();
});
});
13 changes: 5 additions & 8 deletions src/cli/bundler/plugins/GenerateJsonPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,11 @@ export default class GenerateJsonPlugin {

public apply(compiler: Compiler): void {
compiler.hooks.watchRun.tapPromise(this.pluginName, async () => {
try {
const update = this.update;

if (update) {
this.data = await update();
}
} catch (e) {
console.error("GenerateJsonPlugin: Error updating data", e);
const update = this.update;

if (update) {
// Let the compiler fail this rebuild rather than emit stale JSON.
this.data = await update();
}
});

Expand Down
11 changes: 10 additions & 1 deletion src/cli/entrypoint/file/injectors/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Command, Mode, PackageName} from "@typing/app";
import {Browser} from "@typing/browser";
import {RelayMethod} from "@typing/relay";
import {RelayAllFrames, RelayMethod} from "@typing/relay";
import {ContentScriptAppend, ContentScriptDeclarative, ContentScriptMarker} from "@typing/content";
import {OffscreenReason} from "@typing/offscreen";
import {SandboxAllow, SandboxSource} from "@typing/sandbox";
Expand Down Expand Up @@ -83,6 +83,15 @@ export default (): Injector[] => {
});
});

Object.entries(RelayAllFrames).forEach(([key, value]) => {
resolvers.push({
from: PackageName,
target: "RelayAllFrames",
name: key,
value,
});
});

Object.entries(OffscreenReason).forEach(([key, value]) => {
resolvers.push({
from: PackageName,
Expand Down
28 changes: 7 additions & 21 deletions src/cli/entrypoint/finder/LocaleFinder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import path from "path";
import LocaleFinder from "./LocaleFinder";

import {ReadonlyConfig} from "@typing/config";
import {Command} from "@typing/app";
import {Command, Mode} from "@typing/app";
import {Browser} from "@typing/browser";
import {Language} from "@typing/locale";

Expand All @@ -27,7 +27,7 @@ const makeFinder = (fixture: string, config: Partial<ReadonlyConfig> = {}): Test
lang: Language.English,
localeDir: "locales",
mergeLocales: true,
mode: "production",
mode: Mode.Production,
plugins: [
{
name: root,
Expand All @@ -52,7 +52,7 @@ const makeLayeredFinder = (config: Partial<ReadonlyConfig> = {}): TestLocaleFind
lang: Language.English,
localeDir: "locales",
mergeLocales: true,
mode: "production",
mode: Mode.Production,
plugins: [],
rootDir: path.join(root, "project"),
sharedDir: "shared",
Expand Down Expand Up @@ -256,24 +256,10 @@ describe("LocaleFinder", () => {

test("rejects ambiguous locale files in the same layer", async () => {
const root = path.join(fixtures, "duplicate-layer");
const config = {
app: "app",
appSrcDir: ".",
appsDir: "apps",
browser: Browser.Chrome,
command: Command.Build,
lang: Language.English,
localeDir: "locales",
mergeLocales: true,
mode: "production",
plugins: [],
rootDir: root,
sharedDir: "shared",
srcDir: "src",
} as ReadonlyConfig;
const finder = new TestLocaleFinder(config);

config.plugins.push({
const plugins: ReadonlyConfig["plugins"] = [];
const finder = makeFinder("duplicate-layer", {plugins});

plugins.push({
name: "adnbn:locale",
locale: () => finder.files(),
});
Expand Down
6 changes: 2 additions & 4 deletions src/cli/entrypoint/parser/ContentParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ import {
ContentScriptMarker,
ContentScriptMatches,
} from "@typing/content";
import {EntrypointFile} from "@typing/entrypoint";
import {EntrypointFile, EntrypointOptions} from "@typing/entrypoint";

export default class<
O extends ContentScriptEntrypointOptions = ContentScriptEntrypointOptions,
> extends AbstractParser<O> {
export default class<O extends EntrypointOptions = ContentScriptEntrypointOptions> extends AbstractParser<O> {
protected definition(): string | string[] {
return ["defineContentScript", "defineContentScriptAppend"];
}
Expand Down
30 changes: 30 additions & 0 deletions src/cli/entrypoint/parser/RelayParser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import path from "path";

import RelayParser from "./RelayParser";

import type {ReadonlyConfig} from "@typing/config";

const rootDir = path.resolve(__dirname, "../../../..");
const fixtures = path.resolve(__dirname, "tests", "fixtures", "relay");

const parser = new RelayParser({rootDir} as ReadonlyConfig);

const file = (...parts: string[]) => {
const filename = path.join(fixtures, ...parts);

return {
file: filename,
import: filename,
};
};

describe("RelayParser", () => {
test("parses the all-frame response capability from a real entrypoint file", () => {
expect(parser.options(file("options", "all-frames", "relay.ts"))).toEqual(
expect.objectContaining({
method: "messaging",
allFrames: "all",
})
);
});
});
3 changes: 2 additions & 1 deletion src/cli/entrypoint/parser/RelayParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import z from "zod";

import ContentParser from "./ContentParser";

import {RelayEntrypointOptions, RelayMethod} from "@typing/relay";
import {RelayAllFrames, RelayEntrypointOptions, RelayMethod} from "@typing/relay";
import {EntrypointFile} from "@typing/entrypoint";
import {ContentScriptDeclarative} from "@typing/content";

Expand All @@ -17,6 +17,7 @@ export default class extends ContentParser<RelayEntrypointOptions> {

protected schema(): typeof this.CommonPropertiesSchema {
return super.schema().extend({
allFrames: z.union([z.boolean(), z.nativeEnum(RelayAllFrames)]).optional(),
name: z
.string()
.trim()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {defineRelay, RelayAllFrames, RelayMethod} from "adnbn";

export default defineRelay({
method: RelayMethod.Messaging,
allFrames: RelayAllFrames.All,
init() {
return {
scan: () => true,
};
},
});
Loading
Loading