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
2 changes: 1 addition & 1 deletion src/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export abstract class Adapter {
}

async createSlice(model: SharedSlice, library?: URL): Promise<void> {
library ??= await this.getDefaultSliceLibrary();
library ??= (await this.getSliceLibraries())[0];
const sliceDirectoryName = pascalCase(model.name);
const sliceDirectory = new URL(sliceDirectoryName, appendTrailingSlash(library));
const modelPath = new URL("model.json", appendTrailingSlash(sliceDirectory));
Expand Down
29 changes: 22 additions & 7 deletions test/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,15 @@ export async function readLocalCustomTypes(project: URL): Promise<CustomType[]>
return result;
}

export async function getSliceLibraries(project: URL): Promise<URL[]> {
const { libraries = [] } = await getConfig(project);
if (libraries.length < 1) return [new URL("slices/", project)];
return libraries.map((library) => new URL(library.replace(/^\//, "") + "/", project));
}

export async function writeLocalSlice(project: URL, model: SharedSlice): Promise<void> {
const path = new URL(`slices/${pascalCase(model.name)}/model.json`, project);
const [library] = await getSliceLibraries(project);
const path = new URL(`${pascalCase(model.name)}/model.json`, library);
await mkdir(new URL(".", path), { recursive: true });
await writeFile(path, JSON.stringify(model, null, 2));
}
Expand All @@ -209,13 +216,21 @@ export async function readLocalSlice(project: URL, id: string): Promise<SharedSl
}

export async function readLocalSlices(project: URL): Promise<SharedSlice[]> {
const dir = new URL("slices/", project);
const entries = await readdir(dir).catch(() => [] as string[]);
const libraries = await getSliceLibraries(project);
const result: SharedSlice[] = [];
for (const name of entries) {
try {
result.push(JSON.parse(await readFile(new URL(`${name}/model.json`, dir), "utf8")));
} catch {}
for (const library of libraries) {
const entries = await readdir(library).catch(() => []);
for (const name of entries) {
try {
result.push(JSON.parse(await readFile(new URL(`${name}/model.json`, library), "utf8")));
} catch {}
}
}
return result;
}

async function getConfig(project: URL): Promise<{ libraries?: string[] }> {
const path = new URL("prismic.config.json", project);
const raw = await readFile(path, "utf8");
return JSON.parse(raw);
}
30 changes: 30 additions & 0 deletions test/pull.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { writeFile, mkdir } from "node:fs/promises";
import { sep } from "node:path";
import { fileURLToPath } from "node:url";
import { pascalCase } from "change-case";
import { x } from "tinyexec";

import { buildCustomType, buildSlice, it } from "./it";
Expand Down Expand Up @@ -101,6 +102,35 @@ it.sequential("adds new slice to existing library on re-pull", async ({
await expect(project).toContainSlice(sliceB);
});

it.sequential("pulls new slices into the first configured library", async ({
expect,
project,
prismic,
repo,
token,
host,
}) => {
const slice = buildSlice();

await writeFile(
new URL("prismic.config.json", project),
JSON.stringify({
repositoryName: repo,
libraries: ["./slices/blog", "./slices/features"],
}),
);

await insertSlice(slice, { repo, token, host });

const { exitCode } = await prismic("pull", ["--repo", repo]);
expect(exitCode).toBe(0);

const sliceDirectoryName = pascalCase(slice.name);
await expect(project).toContainSlice(slice);
await expect(project).toHaveFile(`slices/blog/${sliceDirectoryName}/model.json`);
await expect(project).not.toHaveFile(`slices/${sliceDirectoryName}/model.json`);
});

it.sequential("removes deleted slice and updates index on re-pull", async ({
expect,
project,
Expand Down
61 changes: 37 additions & 24 deletions test/setup.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { CustomType, SharedSlice } from "@prismicio/types-internal/lib/customtypes";

import { readFile } from "node:fs/promises";
import { pathToFileURL } from "node:url";
import { glob } from "tinyglobby";
import { expect } from "vitest";

import { getSliceLibraries } from "./it";

declare module "vitest" {
// oxlint-disable-next-line no-explicit-any
interface Matchers<T = any> {
Expand Down Expand Up @@ -39,36 +43,45 @@ expect.extend({
async toContainSlice(project, slice) {
const problems: string[] = [];

const sliceIndexPath = new URL("slices/index.js", project);
try {
const sliceIndex = await readFile(sliceIndexPath, "utf8");
if (!new RegExp(`\\b${slice.id}: `).test(sliceIndex)) {
problems.push(
`slice "${slice.id}" not found in slice library index (${sliceIndexPath.href})`,
);
const libraries = await getSliceLibraries(project);
let sliceDirectory;
for (const library of libraries) {
const sliceModelPaths = Array.from(
await glob("*/model.json", { absolute: true, cwd: library }),
(path) => pathToFileURL(path),
);
for (const sliceModelPath of sliceModelPaths) {
const model: SharedSlice = JSON.parse(await readFile(sliceModelPath, "utf8"));
if (model.id === slice.id) {
sliceDirectory = new URL(".", sliceModelPath);
}
}
} catch {
problems.push(`slice library index (${sliceIndexPath.href}) does not exist`);
}

const modelPath = new URL(`slices/${slice.name}/model.json`, project);
try {
const model: SharedSlice = JSON.parse(await readFile(modelPath, "utf8"));
if (model.id !== slice.id) {
problems.push(`slice model file (${modelPath.href}) has wrong ID`);
if (!sliceDirectory) {
problems.push(`slice model file does not exist`);
} else {
const sliceIndexPath = new URL("../index.js", sliceDirectory);
try {
const sliceIndex = await readFile(sliceIndexPath, "utf8");
if (!new RegExp(`\\b${slice.id}: `).test(sliceIndex)) {
problems.push(
`slice "${slice.id}" not found in slice library index (${sliceIndexPath.href})`,
);
}
} catch {
problems.push(`slice library index (${sliceIndexPath.href}) does not exist`);
}
} catch {
problems.push(`slice model file (${modelPath.href}) does not exist`);
}

const componentPath = new URL(`slices/${slice.name}/index.jsx`, project);
try {
const componentFile = await readFile(componentPath, "utf-8");
if (!componentFile.includes(slice.name)) {
problems.push(`slice component file (${componentPath.href}) does not contain slice name`);
const componentPath = new URL("index.jsx", sliceDirectory);
try {
const componentFile = await readFile(componentPath, "utf-8");
if (!componentFile.includes(slice.name)) {
problems.push(`slice component file (${componentPath.href}) does not contain slice name`);
}
} catch {
problems.push(`slice component file (${componentPath.href}) does not exist`);
}
} catch {
problems.push(`slice component file (${componentPath.href}) does not exist`);
}

return {
Expand Down
22 changes: 22 additions & 0 deletions test/slice-create.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { snakeCase } from "change-case";
import { writeFile } from "node:fs/promises";

import { buildSlice, it, readLocalSlice } from "./it";

Expand Down Expand Up @@ -32,3 +33,24 @@ it("creates a slice with a custom id", async ({ expect, prismic, project }) => {
const created = await readLocalSlice(project, id);
expect(created).toBeDefined();
});

it("creates a slice in the first configured library", async ({ expect, prismic, project, repo }) => {
await writeFile(
new URL("prismic.config.json", project),
JSON.stringify({
repositoryName: repo,
libraries: ["./slices/blog", "./slices/features"],
}),
);

const { name } = buildSlice();
const id = snakeCase(name);

const { exitCode } = await prismic("slice", ["create", name]);
expect(exitCode).toBe(0);

const created = await readLocalSlice(project, id);
expect(created).toBeDefined();
await expect(project).toHaveFile(`slices/blog/${name}/model.json`);
await expect(project).not.toHaveFile(`slices/${name}/model.json`);
});
Loading