cognite-create 0.1.6 → 0.1.8
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/index.js +184 -21
- package/package.json +1 -1
- package/templates/.cursor/rules/general.mdc +1 -1
package/bin/index.js
CHANGED
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
4
|
-
const { spawn } = require(
|
|
4
|
+
const { spawn } = require("node:child_process");
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
6
|
-
const fs = require(
|
|
6
|
+
const fs = require("node:fs/promises");
|
|
7
7
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
8
|
-
const path = require(
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
|
|
10
|
+
const REQUIRED_DEPENDENCIES = [
|
|
11
|
+
{ name: "tw-animate-css", version: "^1.3.8" },
|
|
12
|
+
{ name: "clsx", version: "^2.1.1" },
|
|
13
|
+
];
|
|
9
14
|
|
|
10
15
|
async function main() {
|
|
11
16
|
const args = process.argv.slice(2);
|
|
12
17
|
|
|
13
|
-
if (args.length === 0 || args[0].startsWith(
|
|
14
|
-
console.error(
|
|
18
|
+
if (args.length === 0 || args[0].startsWith("-")) {
|
|
19
|
+
console.error(
|
|
20
|
+
"Usage: cognite-create <project-name> [create-next-app options]"
|
|
21
|
+
);
|
|
15
22
|
process.exit(1);
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
const projectDir = args[0];
|
|
19
|
-
const createArgs = [
|
|
26
|
+
const createArgs = ["create-next-app@latest", ...args];
|
|
20
27
|
await runCreateNextApp(createArgs);
|
|
21
28
|
await addCogniteTemplates(projectDir);
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
function runCreateNextApp(cliArgs) {
|
|
25
|
-
const command = process.platform ===
|
|
32
|
+
const command = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
26
33
|
|
|
27
34
|
return new Promise((resolve, reject) => {
|
|
28
|
-
const child = spawn(command, cliArgs, { stdio:
|
|
35
|
+
const child = spawn(command, cliArgs, { stdio: "inherit" });
|
|
29
36
|
|
|
30
|
-
child.on(
|
|
31
|
-
child.on(
|
|
37
|
+
child.on("error", reject);
|
|
38
|
+
child.on("close", (code) => {
|
|
32
39
|
if (code !== 0) {
|
|
33
40
|
const error = new Error(`create-next-app exited with code ${code}`);
|
|
34
41
|
error.exitCode = code;
|
|
@@ -42,22 +49,24 @@ function runCreateNextApp(cliArgs) {
|
|
|
42
49
|
|
|
43
50
|
async function addCogniteTemplates(projectDir) {
|
|
44
51
|
const targetRoot = path.resolve(process.cwd(), projectDir);
|
|
45
|
-
const templateRoot = path.resolve(__dirname,
|
|
52
|
+
const templateRoot = path.resolve(__dirname, "..", "templates");
|
|
46
53
|
|
|
47
54
|
try {
|
|
48
55
|
await fs.access(targetRoot);
|
|
49
56
|
} catch (error) {
|
|
50
|
-
if (error.code ===
|
|
57
|
+
if (error.code === "ENOENT") {
|
|
51
58
|
throw new Error(
|
|
52
59
|
`Expected to find the newly created project at "${projectDir}", but it was not found. ` +
|
|
53
|
-
|
|
60
|
+
"Check the create-next-app output for more details."
|
|
54
61
|
);
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
throw error;
|
|
58
65
|
}
|
|
59
66
|
|
|
60
|
-
|
|
67
|
+
await ensureDependenciesInstalled(targetRoot);
|
|
68
|
+
|
|
69
|
+
const srcDirectory = path.join(targetRoot, "src");
|
|
61
70
|
const templateFiles = await collectTemplateFiles(templateRoot);
|
|
62
71
|
|
|
63
72
|
await fs.mkdir(srcDirectory, { recursive: true });
|
|
@@ -66,12 +75,14 @@ async function addCogniteTemplates(projectDir) {
|
|
|
66
75
|
const normalizedPath = normalizeRelativePath(relativePath);
|
|
67
76
|
const source = path.join(templateRoot, relativePath);
|
|
68
77
|
|
|
69
|
-
const pathSegments = normalizedPath.split(
|
|
78
|
+
const pathSegments = normalizedPath.split("/");
|
|
70
79
|
|
|
71
|
-
if (pathSegments[0] ===
|
|
80
|
+
if (pathSegments[0] === "app" || pathSegments[0] === "lib") {
|
|
72
81
|
const target = path.join(srcDirectory, ...pathSegments);
|
|
73
82
|
const isGlobalsCss =
|
|
74
|
-
pathSegments[0] ===
|
|
83
|
+
pathSegments[0] === "app" &&
|
|
84
|
+
pathSegments.length === 2 &&
|
|
85
|
+
pathSegments[1] === "globals.css";
|
|
75
86
|
|
|
76
87
|
if (isGlobalsCss) {
|
|
77
88
|
await copyFileWithOverwrite(source, target);
|
|
@@ -86,7 +97,7 @@ async function addCogniteTemplates(projectDir) {
|
|
|
86
97
|
await copyFileIfMissing(source, target);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
|
-
console.log(
|
|
100
|
+
console.log("\nCognite templates copied successfully.");
|
|
90
101
|
}
|
|
91
102
|
|
|
92
103
|
async function copyFileIfMissing(source, target) {
|
|
@@ -96,7 +107,7 @@ async function copyFileIfMissing(source, target) {
|
|
|
96
107
|
await fs.access(target);
|
|
97
108
|
console.warn(`Skipped existing ${path.relative(process.cwd(), target)}`);
|
|
98
109
|
} catch (error) {
|
|
99
|
-
if (error.code !==
|
|
110
|
+
if (error.code !== "ENOENT") {
|
|
100
111
|
throw error;
|
|
101
112
|
}
|
|
102
113
|
|
|
@@ -137,11 +148,163 @@ async function collectTemplateFiles(rootDir) {
|
|
|
137
148
|
}
|
|
138
149
|
|
|
139
150
|
function normalizeRelativePath(relativePath) {
|
|
140
|
-
return relativePath.split(path.sep).join(
|
|
151
|
+
return relativePath.split(path.sep).join("/");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function formatDependencySummary(dependencies) {
|
|
155
|
+
return dependencies
|
|
156
|
+
.map((dependency) =>
|
|
157
|
+
dependency.version ? `${dependency.name}@${dependency.version}` : dependency.name
|
|
158
|
+
)
|
|
159
|
+
.join(", ");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function ensureDependenciesInstalled(targetRoot) {
|
|
163
|
+
const packageJsonPath = path.join(targetRoot, "package.json");
|
|
164
|
+
let packageJson;
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, "utf8");
|
|
168
|
+
packageJson = JSON.parse(packageJsonContent);
|
|
169
|
+
} catch {
|
|
170
|
+
console.warn(
|
|
171
|
+
`\nUnable to read or parse ${path.relative(
|
|
172
|
+
process.cwd(),
|
|
173
|
+
packageJsonPath
|
|
174
|
+
)}. Install ${formatDependencySummary(REQUIRED_DEPENDENCIES)} manually.`
|
|
175
|
+
);
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const missingDependencies = REQUIRED_DEPENDENCIES.filter(
|
|
180
|
+
(dependency) =>
|
|
181
|
+
!(
|
|
182
|
+
(packageJson.dependencies && packageJson.dependencies[dependency.name]) ||
|
|
183
|
+
(packageJson.devDependencies && packageJson.devDependencies[dependency.name])
|
|
184
|
+
)
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
if (missingDependencies.length === 0) {
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const packageManager = await detectPackageManager(packageJson, targetRoot);
|
|
192
|
+
|
|
193
|
+
if (!packageManager) {
|
|
194
|
+
console.warn(
|
|
195
|
+
`\nCould not determine package manager for ${path.relative(
|
|
196
|
+
process.cwd(),
|
|
197
|
+
targetRoot
|
|
198
|
+
)}. Install ${formatDependencySummary(missingDependencies)} manually.`
|
|
199
|
+
);
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const dependencySummary = formatDependencySummary(missingDependencies);
|
|
204
|
+
console.log(`\nInstalling ${dependencySummary} using ${packageManager}...`);
|
|
205
|
+
await installDependencies(packageManager, targetRoot, missingDependencies);
|
|
206
|
+
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function detectPackageManager(packageJson, targetRoot) {
|
|
211
|
+
if (
|
|
212
|
+
packageJson.packageManager &&
|
|
213
|
+
typeof packageJson.packageManager === "string"
|
|
214
|
+
) {
|
|
215
|
+
const [name] = packageJson.packageManager.split("@");
|
|
216
|
+
|
|
217
|
+
if (name) {
|
|
218
|
+
return name;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const candidates = [
|
|
223
|
+
{ name: "pnpm", lockFile: "pnpm-lock.yaml" },
|
|
224
|
+
{ name: "yarn", lockFile: "yarn.lock" },
|
|
225
|
+
{ name: "bun", lockFile: "bun.lockb" },
|
|
226
|
+
{ name: "npm", lockFile: "package-lock.json" },
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
for (const candidate of candidates) {
|
|
230
|
+
const lockFilePath = path.join(targetRoot, candidate.lockFile);
|
|
231
|
+
|
|
232
|
+
if (await pathExists(lockFilePath)) {
|
|
233
|
+
return candidate.name;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function installDependencies(packageManager, cwd, dependencies) {
|
|
241
|
+
const dependencySpecs = dependencies.map((dependency) =>
|
|
242
|
+
dependency.version ? `${dependency.name}@${dependency.version}` : dependency.name
|
|
243
|
+
);
|
|
244
|
+
const { command, args } = getInstallCommand(packageManager, dependencySpecs);
|
|
245
|
+
|
|
246
|
+
if (!command) {
|
|
247
|
+
throw new Error(`Unsupported package manager: ${packageManager}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
const child = spawn(command, args, { stdio: "inherit", cwd });
|
|
252
|
+
|
|
253
|
+
child.on("error", reject);
|
|
254
|
+
child.on("close", (code) => {
|
|
255
|
+
if (code !== 0) {
|
|
256
|
+
const error = new Error(
|
|
257
|
+
`${packageManager} exited with code ${code} while installing ${dependencySpecs.join(", ")}`
|
|
258
|
+
);
|
|
259
|
+
error.exitCode = code;
|
|
260
|
+
return reject(error);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
resolve();
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function getInstallCommand(packageManager, dependencySpecs) {
|
|
269
|
+
const normalized = normalizeCommand(packageManager);
|
|
270
|
+
|
|
271
|
+
switch (packageManager) {
|
|
272
|
+
case "npm":
|
|
273
|
+
return { command: normalized, args: ["install", ...dependencySpecs] };
|
|
274
|
+
case "pnpm":
|
|
275
|
+
return { command: normalized, args: ["add", ...dependencySpecs] };
|
|
276
|
+
case "yarn":
|
|
277
|
+
return { command: normalized, args: ["add", ...dependencySpecs] };
|
|
278
|
+
case "bun":
|
|
279
|
+
return { command: normalized, args: ["add", ...dependencySpecs] };
|
|
280
|
+
default:
|
|
281
|
+
return { command: null, args: [] };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function normalizeCommand(command) {
|
|
286
|
+
if (process.platform === "win32" && command !== "bun") {
|
|
287
|
+
return `${command}.cmd`;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return command;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async function pathExists(filePath) {
|
|
294
|
+
try {
|
|
295
|
+
await fs.access(filePath);
|
|
296
|
+
return true;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
if (error && error.code === "ENOENT") {
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
141
304
|
}
|
|
142
305
|
|
|
143
306
|
main().catch((error) => {
|
|
144
|
-
if (error && typeof error.exitCode ===
|
|
307
|
+
if (error && typeof error.exitCode === "number") {
|
|
145
308
|
process.exit(error.exitCode);
|
|
146
309
|
}
|
|
147
310
|
|
package/package.json
CHANGED
|
@@ -4,4 +4,4 @@ globs:
|
|
|
4
4
|
alwaysApply: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Use the ShadCN MCP server to check the Cognite registry for components before making your own.
|
|
7
|
+
Use the ShadCN MCP server to check the Cognite registry for components you could use before making your own. If there are Cognite components available for what you are trying to do you must always use them over alternatives. We want to make sure our app aligns with the Cognite design system. Make sure to check the globals.css file for styling.
|