From 60ef631b358029737a5763577ed414ff1dc7acb2 Mon Sep 17 00:00:00 2001 From: Jakub Andrysek Date: Thu, 9 Apr 2026 13:25:32 +0200 Subject: [PATCH 1/3] refactor: update Jaculus schema to encapsulate registry under jaculus key --- packages/project/src/package.ts | 46 ++++++++++++++++----------------- test/project/package.test.ts | 34 ++++++++++++++++++------ test/project/testHelpers.ts | 9 ++++--- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/packages/project/src/package.ts b/packages/project/src/package.ts index 5b5f376..7618021 100644 --- a/packages/project/src/package.ts +++ b/packages/project/src/package.ts @@ -23,34 +23,34 @@ const DependenciesSchema = z.record(NameSchema, VersionFormat); const RegistryUrisSchema = z.array(z.string()); export const JaculusProjectTypeSchema = z.enum(["code", "jacly"]); -const JaculusSchema = z.object({ - registry: RegistryUrisSchema.optional(), - blocks: z.string().optional(), - projectType: JaculusProjectTypeSchema.optional(), - template: z.boolean().optional(), - projectFormatVersion: z.number().optional(), - jaclyVersion: VersionFormat.optional(), -}); +const JaculusSchema = z + .object({ + registry: RegistryUrisSchema.optional(), + blocks: z.string().optional(), + projectType: JaculusProjectTypeSchema.optional(), + template: z.boolean().optional(), + projectFormatVersion: z.number().optional(), + jaclyVersion: VersionFormat.optional(), + }) + .catchall(z.unknown()); const ExportKeyValueSchema = z.record(z.string(), z.string()); const ExportsSchema = z.union([z.string(), ExportKeyValueSchema]); -const PackageJsonSchema = z - .object({ - name: NameSchema, - version: VersionFormat, - description: DescriptionSchema.optional(), - dependencies: DependenciesSchema.default({}), - files: z.array(z.string()).optional(), - type: z.enum(["module"]).optional(), - main: z.string().optional(), - scripts: z.record(z.string(), z.string()).optional(), - exports: ExportsSchema.optional(), - types: z.string().optional(), - jaculus: JaculusSchema.optional(), - }) - .catchall(z.unknown()); +const PackageJsonSchema = z.object({ + name: NameSchema, + version: VersionFormat, + description: DescriptionSchema.optional(), + dependencies: DependenciesSchema.default({}), + files: z.array(z.string()).optional(), + type: z.enum(["module"]).optional(), + main: z.string().optional(), + scripts: z.record(z.string(), z.string()).optional(), + exports: ExportsSchema.optional(), + types: z.string().optional(), + jaculus: JaculusSchema.optional(), +}); export type DependencyObject = { name: string; diff --git a/test/project/package.test.ts b/test/project/package.test.ts index aae2bd4..d776eee 100644 --- a/test/project/package.test.ts +++ b/test/project/package.test.ts @@ -32,7 +32,9 @@ describe("Package JSON", () => { core: "0.0.24", "led-strip": "1.2.3", }, - registry: ["https://registry.example.com", "https://backup.registry.com"], + jaculus: { + registry: ["https://registry.example.com", "https://backup.registry.com"], + }, }; const packagePath = path.join(tempDir, "package.json"); @@ -46,7 +48,9 @@ describe("Package JSON", () => { expect(loaded.description).to.equal("A test package"); expect(loaded.dependencies).to.have.property("core", "0.0.24"); expect(loaded.dependencies).to.have.property("led-strip", "1.2.3"); - expect(loaded.registry).to.be.an("array").that.includes("https://registry.example.com"); + expect(loaded.jaculus?.registry) + .to.be.an("array") + .that.includes("https://registry.example.com"); }); it("should load minimal valid package.json with only dependencies", async () => { @@ -68,7 +72,7 @@ describe("Package JSON", () => { expect(loaded.name).to.equal("minimal-package"); expect(loaded.version).to.equal("1.0.0"); expect(loaded.description).to.be.undefined; - expect(loaded.registry).to.be.undefined; + expect(loaded.jaculus).to.be.undefined; }); it("should load package.json with empty dependencies", async () => { @@ -87,7 +91,7 @@ describe("Package JSON", () => { expect(loaded.dependencies).to.be.an("object").that.is.empty; }); - it("should preserve unknown top-level package.json fields", async () => { + it("should strip unknown top-level package.json fields", async () => { const packageData = { name: "metadata-package", version: "1.0.0", @@ -108,8 +112,18 @@ describe("Package JSON", () => { await savePackageJson(mockFs, packagePath, loaded); const roundTripped = JSON.parse(fs.readFileSync(packagePath, "utf-8")); - expect(loaded).to.deep.equal(packageData); - expect(roundTripped).to.deep.equal(packageData); + expect(loaded).to.deep.equal({ + name: "metadata-package", + version: "1.0.0", + dependencies: {}, + files: ["dist"], + }); + expect(roundTripped).to.deep.equal({ + name: "metadata-package", + version: "1.0.0", + dependencies: {}, + files: ["dist"], + }); }); it("should throw error for invalid JSON format", async () => { @@ -263,7 +277,9 @@ describe("Package JSON", () => { core: "0.0.24", "led-strip": "1.2.3", }, - registry: ["https://registry.example.com"], + jaculus: { + registry: ["https://registry.example.com"], + }, }; await savePackageJson(mockFs, path.join(tempDir, "package.json"), packageData); @@ -384,7 +400,9 @@ describe("Package JSON", () => { core: "0.0.24", "test-lib": "2.1.0-beta", }, - registry: ["https://test.registry.com", "https://backup.registry.com"], + jaculus: { + registry: ["https://test.registry.com", "https://backup.registry.com"], + }, }; await savePackageJson(mockFs, path.join(tempDir, "roundtrip.json"), originalData); diff --git a/test/project/testHelpers.ts b/test/project/testHelpers.ts index 4c25802..cd1ad6d 100644 --- a/test/project/testHelpers.ts +++ b/test/project/testHelpers.ts @@ -155,8 +155,11 @@ export function createPackageJson( name: "test-project", version: "0.0.1", dependencies, - registry, ...additionalFields, + jaculus: { + registry, + ...(additionalFields.jaculus || {}), + }, }; fs.mkdirSync(projectPath, { recursive: true }); @@ -176,7 +179,7 @@ export async function createMockRegistry( logger: Logger = createMockLogger() ): Promise { const pkg = await loadPackageJson(fs, path.join(projectPath, "package.json")); - return new Registry(pkg.registry, getRequest, logger); + return new Registry(pkg.jaculus?.registry, getRequest, logger); } export function createTestDir(prefix: string = "jaculus-test-"): string { @@ -200,7 +203,7 @@ export function createProjectStructure( createPackageJson( projectPath, packageData.dependencies || {}, - packageData.registry || [registryBasePath], + packageData.jaculus?.registry || [registryBasePath], packageData ); } else { From 28d6da82b3d36b9f24a8784da16e1fad362eafad Mon Sep 17 00:00:00 2001 From: Jakub Andrysek Date: Thu, 9 Apr 2026 13:34:18 +0200 Subject: [PATCH 2/3] refactor: revert back unknown type --- packages/project/src/package.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/project/src/package.ts b/packages/project/src/package.ts index 7618021..252a8d6 100644 --- a/packages/project/src/package.ts +++ b/packages/project/src/package.ts @@ -38,19 +38,21 @@ const ExportKeyValueSchema = z.record(z.string(), z.string()); const ExportsSchema = z.union([z.string(), ExportKeyValueSchema]); -const PackageJsonSchema = z.object({ - name: NameSchema, - version: VersionFormat, - description: DescriptionSchema.optional(), - dependencies: DependenciesSchema.default({}), - files: z.array(z.string()).optional(), - type: z.enum(["module"]).optional(), - main: z.string().optional(), - scripts: z.record(z.string(), z.string()).optional(), - exports: ExportsSchema.optional(), - types: z.string().optional(), - jaculus: JaculusSchema.optional(), -}); +const PackageJsonSchema = z + .object({ + name: NameSchema, + version: VersionFormat, + description: DescriptionSchema.optional(), + dependencies: DependenciesSchema.default({}), + files: z.array(z.string()).optional(), + type: z.enum(["module"]).optional(), + main: z.string().optional(), + scripts: z.record(z.string(), z.string()).optional(), + exports: ExportsSchema.optional(), + types: z.string().optional(), + jaculus: JaculusSchema.optional(), + }) + .catchall(z.unknown()); export type DependencyObject = { name: string; From 65f6532b4224ce0926cccef37dee6e080e1c9b71 Mon Sep 17 00:00:00 2001 From: Jakub Andrysek Date: Thu, 9 Apr 2026 13:38:57 +0200 Subject: [PATCH 3/3] refactor: update test to preserve unknown top-level package.json fields --- test/project/package.test.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/test/project/package.test.ts b/test/project/package.test.ts index d776eee..20ce65c 100644 --- a/test/project/package.test.ts +++ b/test/project/package.test.ts @@ -91,7 +91,7 @@ describe("Package JSON", () => { expect(loaded.dependencies).to.be.an("object").that.is.empty; }); - it("should strip unknown top-level package.json fields", async () => { + it("should preserve unknown top-level package.json fields", async () => { const packageData = { name: "metadata-package", version: "1.0.0", @@ -112,18 +112,8 @@ describe("Package JSON", () => { await savePackageJson(mockFs, packagePath, loaded); const roundTripped = JSON.parse(fs.readFileSync(packagePath, "utf-8")); - expect(loaded).to.deep.equal({ - name: "metadata-package", - version: "1.0.0", - dependencies: {}, - files: ["dist"], - }); - expect(roundTripped).to.deep.equal({ - name: "metadata-package", - version: "1.0.0", - dependencies: {}, - files: ["dist"], - }); + expect(loaded).to.deep.equal(packageData); + expect(roundTripped).to.deep.equal(packageData); }); it("should throw error for invalid JSON format", async () => {