cognite-create 0.1.7 → 0.2.0

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