@prismicio/cli 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/prismic.js +47 -0
- package/dist/_node_modules/meow/build/dependencies.js +9040 -0
- package/dist/_node_modules/meow/build/dependencies.js.map +1 -0
- package/dist/_node_modules/meow/build/index.js +80 -0
- package/dist/_node_modules/meow/build/index.js.map +1 -0
- package/dist/_node_modules/meow/build/options.js +86 -0
- package/dist/_node_modules/meow/build/options.js.map +1 -0
- package/dist/_node_modules/meow/build/parser.js +61 -0
- package/dist/_node_modules/meow/build/parser.js.map +1 -0
- package/dist/_node_modules/meow/build/utils.js +8 -0
- package/dist/_node_modules/meow/build/utils.js.map +1 -0
- package/dist/_node_modules/meow/build/validate.js +102 -0
- package/dist/_node_modules/meow/build/validate.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.js +147 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +34 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.js +32 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/core/auth.d.ts +2 -0
- package/dist/core/auth.js +72 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/customType.d.ts +6 -0
- package/dist/core/customType.js +43 -0
- package/dist/core/customType.js.map +1 -0
- package/dist/core/framework.d.ts +41 -0
- package/dist/core/framework.js +128 -0
- package/dist/core/framework.js.map +1 -0
- package/dist/core/project.d.ts +19 -0
- package/dist/core/project.js +92 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/repository.d.ts +6 -0
- package/dist/core/repository.js +33 -0
- package/dist/core/repository.js.map +1 -0
- package/dist/core/slices.d.ts +6 -0
- package/dist/core/slices.js +47 -0
- package/dist/core/slices.js.map +1 -0
- package/dist/core/version.d.ts +15 -0
- package/dist/core/version.js +27 -0
- package/dist/core/version.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/packages/cli/package.json.js +63 -0
- package/dist/packages/cli/package.json.js.map +1 -0
- package/dist/utils/error.d.ts +8 -0
- package/dist/utils/error.js +18 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/listr.d.ts +5 -0
- package/dist/utils/listr.js +12 -0
- package/dist/utils/listr.js.map +1 -0
- package/dist/utils/output.d.ts +3 -0
- package/dist/utils/output.js +34 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/package.d.ts +10 -0
- package/dist/utils/package.js +20 -0
- package/dist/utils/package.js.map +1 -0
- package/dist/utils/sentry.d.ts +10 -0
- package/dist/utils/sentry.js +62 -0
- package/dist/utils/sentry.js.map +1 -0
- package/dist/utils/telemetry.d.ts +14 -0
- package/dist/utils/telemetry.js +42 -0
- package/dist/utils/telemetry.js.map +1 -0
- package/package.json +84 -0
- package/src/cli.ts +186 -0
- package/src/commands/init.ts +68 -0
- package/src/commands/sync.ts +58 -0
- package/src/core/auth.ts +98 -0
- package/src/core/customType.ts +64 -0
- package/src/core/framework.ts +180 -0
- package/src/core/project.ts +148 -0
- package/src/core/repository.ts +51 -0
- package/src/core/slices.ts +67 -0
- package/src/core/version.ts +50 -0
- package/src/index.ts +1 -0
- package/src/utils/error.ts +40 -0
- package/src/utils/listr.ts +13 -0
- package/src/utils/output.ts +45 -0
- package/src/utils/package.ts +29 -0
- package/src/utils/sentry.ts +104 -0
- package/src/utils/telemetry.ts +70 -0
package/src/cli.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createPrismicManager } from "@prismicio/manager";
|
|
2
|
+
import meow from "meow";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
|
|
5
|
+
import { name as pkgName, version as pkgVersion } from "../package.json";
|
|
6
|
+
|
|
7
|
+
import { init } from "./commands/init";
|
|
8
|
+
import { sync } from "./commands/sync";
|
|
9
|
+
import { FRAMEWORK_PLUGINS } from "./core/framework";
|
|
10
|
+
import { handleSilentError } from "./utils/error";
|
|
11
|
+
import { displayError, displayHeader } from "./utils/output";
|
|
12
|
+
import { setupSentry, trackSentryError } from "./utils/sentry";
|
|
13
|
+
import { initTelemetry, trackErrorTelemetry } from "./utils/telemetry";
|
|
14
|
+
|
|
15
|
+
const cli = meow(
|
|
16
|
+
`
|
|
17
|
+
DOCUMENTATION
|
|
18
|
+
https://prismic.io/docs
|
|
19
|
+
|
|
20
|
+
VERSION
|
|
21
|
+
${pkgName}@${pkgVersion}
|
|
22
|
+
|
|
23
|
+
USAGE
|
|
24
|
+
$ npx prismic@latest init --repository <repository-id>
|
|
25
|
+
$ npx prismic@latest sync
|
|
26
|
+
|
|
27
|
+
OPTIONS
|
|
28
|
+
--repository, -r Specify a Prismic repository to use when initializing a project
|
|
29
|
+
|
|
30
|
+
--help, -h Display CLI help
|
|
31
|
+
--version, -v Display CLI version
|
|
32
|
+
`,
|
|
33
|
+
{
|
|
34
|
+
importMeta: import.meta,
|
|
35
|
+
flags: {
|
|
36
|
+
repository: {
|
|
37
|
+
type: "string",
|
|
38
|
+
shortFlag: "r",
|
|
39
|
+
},
|
|
40
|
+
help: {
|
|
41
|
+
type: "boolean",
|
|
42
|
+
shortFlag: "h",
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
45
|
+
version: {
|
|
46
|
+
type: "boolean",
|
|
47
|
+
shortFlag: "v",
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
description: false,
|
|
52
|
+
autoHelp: false,
|
|
53
|
+
autoVersion: false,
|
|
54
|
+
allowUnknownFlags: false,
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export const CLIArgs = z.discriminatedUnion("commandType", [
|
|
59
|
+
z.object({
|
|
60
|
+
commandType: z.literal("init"),
|
|
61
|
+
help: z.boolean().optional(),
|
|
62
|
+
version: z.boolean().optional(),
|
|
63
|
+
repository: z
|
|
64
|
+
.string()
|
|
65
|
+
.min(1, "Repository name is required to initialize a project"),
|
|
66
|
+
}),
|
|
67
|
+
z.object({
|
|
68
|
+
commandType: z.literal("sync"),
|
|
69
|
+
help: z.boolean().optional(),
|
|
70
|
+
version: z.boolean().optional(),
|
|
71
|
+
}),
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
export async function run(): Promise<void> {
|
|
75
|
+
// Display header immediately so user sees something is happening
|
|
76
|
+
displayHeader();
|
|
77
|
+
|
|
78
|
+
// Setup Sentry as early as possible to track ALL errors
|
|
79
|
+
setupSentry();
|
|
80
|
+
|
|
81
|
+
// Handle help flag (exit early, no telemetry needed)
|
|
82
|
+
if (cli.flags.help) {
|
|
83
|
+
cli.showHelp(0);
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Handle version flag (exit early, no telemetry needed)
|
|
88
|
+
if (cli.flags.version) {
|
|
89
|
+
console.info(`${pkgName}@${pkgVersion}`);
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Validate CLI arguments first (before any operations that might fail)
|
|
94
|
+
const cliArgs = CLIArgs.safeParse({
|
|
95
|
+
...cli.flags,
|
|
96
|
+
commandType: cli.input[0],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Invalid arguments - track with Sentry even though it's a user error
|
|
100
|
+
if (!cliArgs.success) {
|
|
101
|
+
const error = new Error(cliArgs.error.message);
|
|
102
|
+
displayError(error);
|
|
103
|
+
await trackSentryError(error);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Too many arguments - track with Sentry
|
|
108
|
+
if (cli.input.length > 1) {
|
|
109
|
+
const error = new Error("Too many arguments. Expected 'init' or 'sync'.");
|
|
110
|
+
displayError(error);
|
|
111
|
+
await trackSentryError(error);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Create manager - wrap in try-catch to track failures
|
|
116
|
+
let manager;
|
|
117
|
+
try {
|
|
118
|
+
manager = createPrismicManager({
|
|
119
|
+
cwd: process.cwd(),
|
|
120
|
+
nativePlugins: FRAMEWORK_PLUGINS,
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
// Manager creation failed - track with Sentry (telemetry not available yet)
|
|
124
|
+
displayError(error);
|
|
125
|
+
await trackSentryError(error);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const commandType = cliArgs.data.commandType;
|
|
130
|
+
const repositoryName =
|
|
131
|
+
commandType === "init" ? cliArgs.data.repository : undefined;
|
|
132
|
+
|
|
133
|
+
// Initialize telemetry as early as possible (after manager creation)
|
|
134
|
+
// Track initialization failures with Sentry
|
|
135
|
+
try {
|
|
136
|
+
await initTelemetry({
|
|
137
|
+
manager,
|
|
138
|
+
commandType,
|
|
139
|
+
repositoryName,
|
|
140
|
+
});
|
|
141
|
+
} catch (telemetryError) {
|
|
142
|
+
// Telemetry initialization failed - track with Sentry but continue execution
|
|
143
|
+
// This prevents telemetry issues from breaking the CLI
|
|
144
|
+
await trackSentryError(telemetryError);
|
|
145
|
+
handleSilentError(telemetryError, "Telemetry initialization error");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Execute command - all errors here will be tracked
|
|
149
|
+
try {
|
|
150
|
+
if (commandType === "init") {
|
|
151
|
+
await init({
|
|
152
|
+
manager,
|
|
153
|
+
repositoryName: cliArgs.data.repository,
|
|
154
|
+
});
|
|
155
|
+
process.exit(0);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (commandType === "sync") {
|
|
159
|
+
await sync({ manager });
|
|
160
|
+
process.exit(0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw new Error("Unknown command type.");
|
|
164
|
+
} catch (error) {
|
|
165
|
+
displayError(error);
|
|
166
|
+
|
|
167
|
+
// Always track with Sentry first (most reliable)
|
|
168
|
+
await trackSentryError(error);
|
|
169
|
+
|
|
170
|
+
// Try to track with telemetry if it was initialized
|
|
171
|
+
// If telemetry wasn't initialized or tracking fails, Sentry already has it
|
|
172
|
+
try {
|
|
173
|
+
await trackErrorTelemetry({
|
|
174
|
+
manager,
|
|
175
|
+
error,
|
|
176
|
+
commandType,
|
|
177
|
+
});
|
|
178
|
+
} catch (telemetryError) {
|
|
179
|
+
handleSilentError(telemetryError, "Telemetry tracking error");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
void run();
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { PrismicManager } from "@prismicio/manager";
|
|
2
|
+
|
|
3
|
+
import { version as pkgVersion } from "../../package.json";
|
|
4
|
+
import { login } from "../core/auth";
|
|
5
|
+
import { saveCustomTypes } from "../core/customType";
|
|
6
|
+
import { initFramework } from "../core/framework";
|
|
7
|
+
import {
|
|
8
|
+
createPrismicConfig,
|
|
9
|
+
detectProjectContext,
|
|
10
|
+
detectProjectState,
|
|
11
|
+
} from "../core/project";
|
|
12
|
+
import { validateRepository } from "../core/repository";
|
|
13
|
+
import { saveSlices } from "../core/slices";
|
|
14
|
+
import { checkCLIVersion } from "../core/version";
|
|
15
|
+
import { displaySuccess } from "../utils/output";
|
|
16
|
+
|
|
17
|
+
type InitArgs = {
|
|
18
|
+
manager: PrismicManager;
|
|
19
|
+
repositoryName: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export async function init(args: InitArgs): Promise<void> {
|
|
23
|
+
const { manager, repositoryName } = args;
|
|
24
|
+
|
|
25
|
+
// Authentication - Also updates Sentry context
|
|
26
|
+
await login(manager);
|
|
27
|
+
|
|
28
|
+
// Ensure the project is not already initialized
|
|
29
|
+
await detectProjectState({ manager, commandType: "init" });
|
|
30
|
+
|
|
31
|
+
// Ensure the repository exists and the user has write access
|
|
32
|
+
await validateRepository({ manager, repository: repositoryName });
|
|
33
|
+
|
|
34
|
+
// Get project framework and package manager - Also updates Sentry context
|
|
35
|
+
const projectContext = await detectProjectContext(manager);
|
|
36
|
+
|
|
37
|
+
// Check CLI version - Voluntarily late so Sentry context is updated
|
|
38
|
+
await checkCLIVersion({ manager, currentVersion: pkgVersion });
|
|
39
|
+
|
|
40
|
+
// Create Prismic configuration file
|
|
41
|
+
await createPrismicConfig({ manager, projectContext, repositoryName });
|
|
42
|
+
|
|
43
|
+
// Initialize the plugin system
|
|
44
|
+
await manager.plugins.initPlugins();
|
|
45
|
+
|
|
46
|
+
// Initialize the framework specific dependencies and files
|
|
47
|
+
await initFramework({ manager, projectContext });
|
|
48
|
+
|
|
49
|
+
// Save Prismic slices locally
|
|
50
|
+
await saveSlices({ manager });
|
|
51
|
+
|
|
52
|
+
// Save Prismic custom types locally
|
|
53
|
+
await saveCustomTypes({ manager });
|
|
54
|
+
|
|
55
|
+
// Track the end of the init command
|
|
56
|
+
await manager.telemetry.track({
|
|
57
|
+
event: "prismic-cli:end",
|
|
58
|
+
commandType: "init",
|
|
59
|
+
repository: repositoryName,
|
|
60
|
+
fullCommand: process.argv.join(" "),
|
|
61
|
+
success: true,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
displaySuccess(
|
|
65
|
+
"Project initialized successfully!",
|
|
66
|
+
"You're all set to start building with Prismic.",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { PrismicManager } from "@prismicio/manager";
|
|
2
|
+
|
|
3
|
+
import { version as pkgVersion } from "../../package.json";
|
|
4
|
+
import { login } from "../core/auth";
|
|
5
|
+
import { saveCustomTypes } from "../core/customType";
|
|
6
|
+
import { detectProjectContext, detectProjectState } from "../core/project";
|
|
7
|
+
import { validateRepository } from "../core/repository";
|
|
8
|
+
import { saveSlices } from "../core/slices";
|
|
9
|
+
import { checkCLIVersion } from "../core/version";
|
|
10
|
+
import { displaySuccess } from "../utils/output";
|
|
11
|
+
|
|
12
|
+
type SyncArgs = {
|
|
13
|
+
manager: PrismicManager;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export async function sync(args: SyncArgs): Promise<void> {
|
|
17
|
+
const { manager } = args;
|
|
18
|
+
|
|
19
|
+
// Authentication - Also updates Sentry context
|
|
20
|
+
await login(manager);
|
|
21
|
+
|
|
22
|
+
// Ensure the project is already initialized
|
|
23
|
+
await detectProjectState({ manager, commandType: "sync" });
|
|
24
|
+
|
|
25
|
+
// Get repository from Prismic config file
|
|
26
|
+
const repositoryName = await manager.project.getRepositoryName();
|
|
27
|
+
|
|
28
|
+
// Ensure the repository exists and the user has write access
|
|
29
|
+
await validateRepository({ manager, repository: repositoryName });
|
|
30
|
+
|
|
31
|
+
// Ensure validity of the framework and package manager - Also updates Sentry context
|
|
32
|
+
await detectProjectContext(manager);
|
|
33
|
+
|
|
34
|
+
// Check CLI version - Voluntarily late so Sentry context is updated
|
|
35
|
+
await checkCLIVersion({ manager, currentVersion: pkgVersion });
|
|
36
|
+
|
|
37
|
+
// Initialize the plugin system
|
|
38
|
+
await manager.plugins.initPlugins();
|
|
39
|
+
|
|
40
|
+
// Save Prismic slices locally
|
|
41
|
+
await saveSlices({ manager });
|
|
42
|
+
|
|
43
|
+
// Save Prismic custom types locally
|
|
44
|
+
await saveCustomTypes({ manager });
|
|
45
|
+
|
|
46
|
+
await manager.telemetry.track({
|
|
47
|
+
event: "prismic-cli:end",
|
|
48
|
+
commandType: "sync",
|
|
49
|
+
repository: repositoryName,
|
|
50
|
+
fullCommand: process.argv.join(" "),
|
|
51
|
+
success: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
displaySuccess(
|
|
55
|
+
"Sync completed successfully!",
|
|
56
|
+
"Your local types are up to date.",
|
|
57
|
+
);
|
|
58
|
+
}
|
package/src/core/auth.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { PrismicManager } from "@prismicio/manager";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import open from "open";
|
|
4
|
+
|
|
5
|
+
import { listr, listrRun } from "../utils/listr";
|
|
6
|
+
import { updateSentryContext } from "../utils/sentry";
|
|
7
|
+
|
|
8
|
+
export async function login(manager: PrismicManager): Promise<void> {
|
|
9
|
+
return listrRun([
|
|
10
|
+
{
|
|
11
|
+
title: "Logging in to Prismic...",
|
|
12
|
+
task: async (_, parentTask) => {
|
|
13
|
+
const isLoggedIn = await manager.user.checkIsLoggedIn();
|
|
14
|
+
|
|
15
|
+
if (!isLoggedIn) {
|
|
16
|
+
parentTask.title = getLoggingInTitle(
|
|
17
|
+
chalk.cyan("Press any key to open the browser to login..."),
|
|
18
|
+
);
|
|
19
|
+
await pressKeyToLogin();
|
|
20
|
+
await waitingForLogin(manager, ({ url }) => {
|
|
21
|
+
parentTask.title = getLoggingInTitle(
|
|
22
|
+
chalk.cyan("Opening browser, waiting for you to login..."),
|
|
23
|
+
chalk.yellow(
|
|
24
|
+
"If your browser did not open automatically, please use the url below:",
|
|
25
|
+
),
|
|
26
|
+
url,
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
parentTask.title = `Logged in`;
|
|
32
|
+
|
|
33
|
+
return listr(
|
|
34
|
+
[
|
|
35
|
+
{
|
|
36
|
+
title: "Fetching user profile...",
|
|
37
|
+
task: async (_, task) => {
|
|
38
|
+
const userProfile = await manager.user.getProfile();
|
|
39
|
+
|
|
40
|
+
// Identify the user for Amplitude
|
|
41
|
+
await manager.telemetry.identify(userProfile);
|
|
42
|
+
|
|
43
|
+
// Update Sentry context for the current user
|
|
44
|
+
updateSentryContext({ userProfile });
|
|
45
|
+
|
|
46
|
+
parentTask.title = `Logged in as ${chalk.cyan(
|
|
47
|
+
userProfile?.email,
|
|
48
|
+
)}`;
|
|
49
|
+
task.title = "Fetched user profile";
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
{ concurrent: true },
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getLoggingInTitle(subtitle?: string, ...extra: string[]): string {
|
|
61
|
+
return `Logging in to Prismic...
|
|
62
|
+
|
|
63
|
+
███████████████████████████████████████████████████████████████████████████
|
|
64
|
+
|
|
65
|
+
${subtitle ? `* * ${subtitle}` : ""}
|
|
66
|
+
${extra.length ? `\n${extra.map((line) => ` ${line}`).join("\n")}\n` : ""}
|
|
67
|
+
███████████████████████████████████████████████████████████████████████████
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function pressKeyToLogin(): Promise<void> {
|
|
72
|
+
await new Promise((resolve) => {
|
|
73
|
+
const initialRawMode = !!process.stdin.isRaw;
|
|
74
|
+
process.stdin.setRawMode?.(true);
|
|
75
|
+
process.stdin.resume();
|
|
76
|
+
process.stdin.once("data", (data: Buffer) => {
|
|
77
|
+
process.stdin.setRawMode?.(initialRawMode);
|
|
78
|
+
process.stdin.pause();
|
|
79
|
+
resolve(data.toString("utf-8"));
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function waitingForLogin(
|
|
85
|
+
manager: PrismicManager,
|
|
86
|
+
onListenCallback?: (
|
|
87
|
+
sessionInfo: Awaited<ReturnType<typeof manager.user.getLoginSessionInfo>>,
|
|
88
|
+
) => void,
|
|
89
|
+
): Promise<void> {
|
|
90
|
+
const sessionInfo = await manager.user.getLoginSessionInfo();
|
|
91
|
+
await manager.user.nodeLoginSession({
|
|
92
|
+
port: sessionInfo.port,
|
|
93
|
+
onListenCallback() {
|
|
94
|
+
open(sessionInfo.url);
|
|
95
|
+
onListenCallback?.(sessionInfo);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { PrismicManager } from "@prismicio/manager";
|
|
2
|
+
|
|
3
|
+
import { listrRun } from "../utils/listr";
|
|
4
|
+
|
|
5
|
+
type SaveCustomTypesArgs = {
|
|
6
|
+
manager: PrismicManager;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export async function saveCustomTypes(
|
|
10
|
+
args: SaveCustomTypesArgs,
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
const { manager } = args;
|
|
13
|
+
|
|
14
|
+
await listrRun([
|
|
15
|
+
{
|
|
16
|
+
title: "Fetching Prismic custom types...",
|
|
17
|
+
task: async (_, parentTask) => {
|
|
18
|
+
const customTypes = await manager.customTypes.fetchRemoteCustomTypes();
|
|
19
|
+
|
|
20
|
+
parentTask.title = "Saving Prismic custom types changes...";
|
|
21
|
+
|
|
22
|
+
const localCustomTypes = await manager.customTypes.readAllCustomTypes();
|
|
23
|
+
|
|
24
|
+
// Handle custom types update
|
|
25
|
+
for (const remoteCustomType of customTypes) {
|
|
26
|
+
const existsLocally = localCustomTypes.models.some(
|
|
27
|
+
(local) => local.model.id === remoteCustomType.id,
|
|
28
|
+
);
|
|
29
|
+
if (existsLocally) {
|
|
30
|
+
await manager.customTypes.updateCustomType({
|
|
31
|
+
model: remoteCustomType,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Handle custom types deletion
|
|
37
|
+
for (const localCustomType of localCustomTypes.models) {
|
|
38
|
+
const existsRemotely = customTypes.some(
|
|
39
|
+
(remote) => remote.id === localCustomType.model.id,
|
|
40
|
+
);
|
|
41
|
+
if (!existsRemotely) {
|
|
42
|
+
await manager.customTypes.deleteCustomType({
|
|
43
|
+
id: localCustomType.model.id,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Handle custom types creation
|
|
49
|
+
for (const remoteCustomType of customTypes) {
|
|
50
|
+
const existsLocally = localCustomTypes.models.some(
|
|
51
|
+
(local) => local.model.id === remoteCustomType.id,
|
|
52
|
+
);
|
|
53
|
+
if (!existsLocally) {
|
|
54
|
+
await manager.customTypes.createCustomType({
|
|
55
|
+
model: remoteCustomType,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
parentTask.title = "Prismic custom types changes saved";
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { readFile, readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import adapterNextPlugin from "@prismicio/adapter-next";
|
|
5
|
+
import adapterNuxtPlugin from "@prismicio/adapter-nuxt";
|
|
6
|
+
import adapterNuxt2Plugin from "@prismicio/adapter-nuxt2";
|
|
7
|
+
import adapterSveltekitPlugin from "@prismicio/adapter-sveltekit";
|
|
8
|
+
import { type PrismicManager } from "@prismicio/manager";
|
|
9
|
+
import semver from "semver";
|
|
10
|
+
|
|
11
|
+
import { listrRun } from "../utils/listr";
|
|
12
|
+
|
|
13
|
+
import { type ProjectContext } from "./project";
|
|
14
|
+
|
|
15
|
+
export type Framework = {
|
|
16
|
+
/**
|
|
17
|
+
* Framework's human readable name.
|
|
18
|
+
*/
|
|
19
|
+
name: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Framework 's id sent to Segment from Slice Machine
|
|
23
|
+
*/
|
|
24
|
+
telemetryID: "next" | "nuxt-2" | "nuxt" | "sveltekit-1" | "sveltekit-2";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Package name of the adapter responsible for this framework
|
|
28
|
+
*/
|
|
29
|
+
adapterName: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A package name/semver range map defining framework compatibility
|
|
33
|
+
* requirements.
|
|
34
|
+
*
|
|
35
|
+
* Project should match all entries to be considered compatible.
|
|
36
|
+
*/
|
|
37
|
+
compatibility: Record<string, string>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Frameworks we support, orders shouldn't matter much but is respected (the
|
|
42
|
+
* higher it is the more priority it has in case multiple matches)
|
|
43
|
+
*/
|
|
44
|
+
export const FRAMEWORKS: Record<string, Framework> = {
|
|
45
|
+
"nuxt-2": {
|
|
46
|
+
name: "Nuxt 2",
|
|
47
|
+
telemetryID: "nuxt-2",
|
|
48
|
+
adapterName: "@prismicio/adapter-nuxt2",
|
|
49
|
+
compatibility: {
|
|
50
|
+
nuxt: "^2.0.0",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
nuxt: {
|
|
54
|
+
name: "Nuxt",
|
|
55
|
+
telemetryID: "nuxt",
|
|
56
|
+
adapterName: "@prismicio/adapter-nuxt",
|
|
57
|
+
compatibility: {
|
|
58
|
+
nuxt: "^3.0.0 || ^4.0.0",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
next: {
|
|
62
|
+
name: "Next.js",
|
|
63
|
+
telemetryID: "next",
|
|
64
|
+
adapterName: "@prismicio/adapter-next",
|
|
65
|
+
compatibility: {
|
|
66
|
+
next: "^11 || ^12 || ^13 || ^14 || ^15 || ^16.0.0-beta.0",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
"sveltekit-1": {
|
|
70
|
+
name: "SvelteKit",
|
|
71
|
+
telemetryID: "sveltekit-1",
|
|
72
|
+
adapterName: "@prismicio/adapter-sveltekit",
|
|
73
|
+
compatibility: {
|
|
74
|
+
"@sveltejs/kit": "^1.0.0",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"sveltekit-2": {
|
|
78
|
+
name: "SvelteKit",
|
|
79
|
+
telemetryID: "sveltekit-2",
|
|
80
|
+
adapterName: "@prismicio/adapter-sveltekit",
|
|
81
|
+
compatibility: {
|
|
82
|
+
"@sveltejs/kit": "^2.0.0",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
} as const;
|
|
86
|
+
|
|
87
|
+
export const detectFramework = async (cwd: string): Promise<Framework> => {
|
|
88
|
+
const path = join(cwd, "package.json");
|
|
89
|
+
|
|
90
|
+
let allDependencies: Record<string, string>;
|
|
91
|
+
try {
|
|
92
|
+
const pkg = JSON.parse(await readFile(path, "utf-8"));
|
|
93
|
+
|
|
94
|
+
allDependencies = {
|
|
95
|
+
...pkg.dependencies,
|
|
96
|
+
...pkg.devDependencies,
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Failed to read project's \`package.json\` at \`${path}\``,
|
|
101
|
+
{ cause: error },
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const framework = Object.values(FRAMEWORKS).find((framework) => {
|
|
106
|
+
return Object.entries(framework.compatibility).every(([pkg, range]) => {
|
|
107
|
+
if (pkg in allDependencies) {
|
|
108
|
+
try {
|
|
109
|
+
// Determine lowest version possibly in use
|
|
110
|
+
const minimumVersion = semver.minVersion(allDependencies[pkg]);
|
|
111
|
+
|
|
112
|
+
return semver.satisfies(minimumVersion!, range);
|
|
113
|
+
} catch {
|
|
114
|
+
// We assume unconventional tags, `latest`, `beta`, `dev` matches the framework
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return false;
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (!framework) {
|
|
124
|
+
throw new Error("No framework compatible with Prismic was found.");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return framework;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
type InitFrameworkArgs = {
|
|
131
|
+
manager: PrismicManager;
|
|
132
|
+
projectContext: ProjectContext;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export async function initFramework(args: InitFrameworkArgs): Promise<void> {
|
|
136
|
+
const { manager, projectContext } = args;
|
|
137
|
+
const { framework } = projectContext;
|
|
138
|
+
|
|
139
|
+
await listrRun([
|
|
140
|
+
{
|
|
141
|
+
title: `Initializing project for ${framework.name}...`,
|
|
142
|
+
task: async (_, parentTask) => {
|
|
143
|
+
const updateOutput = (data: Buffer | string | null) => {
|
|
144
|
+
if (data instanceof Buffer) {
|
|
145
|
+
parentTask.output = data.toString();
|
|
146
|
+
} else if (typeof data === "string") {
|
|
147
|
+
parentTask.output = data;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
await manager.project.initProject({
|
|
151
|
+
log: updateOutput,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// TODO: Export simulator management out of adapter and remove this code
|
|
155
|
+
const projectRoot = await manager.project.getRoot();
|
|
156
|
+
const entries = await readdir(projectRoot, {
|
|
157
|
+
recursive: true,
|
|
158
|
+
withFileTypes: true,
|
|
159
|
+
});
|
|
160
|
+
for (const entry of entries) {
|
|
161
|
+
if (entry.isDirectory() && entry.name === "slice-simulator") {
|
|
162
|
+
await rm(join(entry.path, entry.name), {
|
|
163
|
+
recursive: true,
|
|
164
|
+
force: true,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
parentTask.title = `Updated project for ${framework.name}`;
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
]);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const FRAMEWORK_PLUGINS = {
|
|
176
|
+
"@prismicio/adapter-next": adapterNextPlugin,
|
|
177
|
+
"@prismicio/adapter-nuxt": adapterNuxtPlugin,
|
|
178
|
+
"@prismicio/adapter-nuxt2": adapterNuxt2Plugin,
|
|
179
|
+
"@prismicio/adapter-sveltekit": adapterSveltekitPlugin,
|
|
180
|
+
};
|