kaddidlehopper 0.6.0 → 0.7.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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolve, basename } from 'node:path';
2
- import { existsSync, readdirSync } from 'node:fs';
2
+ import { existsSync } from 'node:fs';
3
3
  import { cp, rm, mkdtemp, readFile, writeFile } from 'node:fs/promises';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { join } from 'node:path';
@@ -7,8 +7,8 @@ import { execSync } from 'node:child_process';
7
7
  import { Command } from 'commander';
8
8
  import chalk from 'chalk';
9
9
  import validatePackageName from 'validate-npm-package-name';
10
- const GITHUB_REPO = 'https://github.com/jherr/kdh-templates.git';
11
- const MANIFEST_URL = 'https://raw.githubusercontent.com/jherr/kdh-templates/main/manifest.json';
10
+ const GITHUB_REPO = 'https://github.com/netlify/swar-templates.git';
11
+ const MANIFEST_URL = 'https://raw.githubusercontent.com/netlify/swar-templates/main/manifest.json';
12
12
  function sanitizePackageName(name) {
13
13
  return name
14
14
  .toLowerCase()
@@ -51,8 +51,7 @@ export function cli() {
51
51
  .option('--add-ons [id]', 'starter ID to use from the template repo')
52
52
  .option('--list-addons-json', 'list all available starters as JSON', false)
53
53
  .option('--no-git', 'do not create a git repository')
54
- .option('--target-dir <path>', 'the target directory for the application root')
55
- .option('-f, --force', 'force project creation even if the target directory is not empty');
54
+ .option('--target-dir <path>', 'the target directory for the application root');
56
55
  program.action(async (projectName, options) => {
57
56
  // Handle --list-addons-json
58
57
  if (options.listAddonsJson) {
@@ -77,22 +76,23 @@ export function cli() {
77
76
  console.error(chalk.red(error));
78
77
  process.exit(1);
79
78
  }
80
- // Check if target directory exists and is non-empty
81
- if (existsSync(targetDir)) {
82
- const contents = readdirSync(targetDir);
83
- if (contents.length > 0 && !options.force) {
84
- console.error(chalk.red(`Target directory "${targetDir}" is not empty. Use --force to overwrite.`));
85
- process.exit(1);
86
- }
79
+ // Delete index.html if it exists in the target directory
80
+ const indexHtmlPath = join(targetDir, 'index.html');
81
+ if (existsSync(indexHtmlPath)) {
82
+ await rm(indexHtmlPath);
87
83
  }
88
84
  console.log(chalk.bold.cyan(`Creating a new Netlify TanStack Start app in ${chalk.white(targetDir)}...`));
89
85
  console.log(chalk.gray(`Using starter: ${starterId}`));
86
+ const manifest = await fetch(MANIFEST_URL).then((r) => r.json());
87
+ const starterEntry = manifest.starters.find((s) => s.id === starterId);
88
+ const frameworkId = starterEntry?.framework;
90
89
  // Sparse clone the template repo into a temp directory
91
90
  const tmpDir = await mkdtemp(join(tmpdir(), 'netlify-cta-'));
92
91
  try {
93
92
  console.log(chalk.gray('⟳ Fetching template...'));
93
+ const sparsePaths = [`starters/${starterId}`, ...(frameworkId ? [`frameworks/${frameworkId}`] : [])];
94
94
  execSync(`git clone --depth=1 --filter=blob:none --sparse ${GITHUB_REPO} ${tmpDir}`, { stdio: 'pipe' });
95
- execSync(`git -C ${tmpDir} sparse-checkout set starters/${starterId}`, { stdio: 'pipe' });
95
+ execSync(`git -C ${tmpDir} sparse-checkout set ${sparsePaths.join(' ')}`, { stdio: 'pipe' });
96
96
  const starterPath = join(tmpDir, 'starters', starterId);
97
97
  if (!existsSync(starterPath)) {
98
98
  console.error(chalk.red(`Starter "${starterId}" not found in the template repo. Run --list-addons-json to see available starters.`));
@@ -100,6 +100,18 @@ export function cli() {
100
100
  }
101
101
  // Copy starter files to target directory
102
102
  await cp(starterPath, targetDir, { recursive: true });
103
+ // Copy framework overlay files if they exist
104
+ if (frameworkId) {
105
+ const frameworkPath = join(tmpDir, 'frameworks', frameworkId);
106
+ if (existsSync(frameworkPath)) {
107
+ console.log(chalk.gray(`⟳ Applying framework overlay (${frameworkId})...`));
108
+ await cp(frameworkPath, targetDir, { recursive: true });
109
+ console.log(chalk.green(`✓ Framework overlay applied (${frameworkId})`));
110
+ }
111
+ else {
112
+ console.log(chalk.yellow(`⚠ Framework overlay "${frameworkId}" not found in repo, skipping`));
113
+ }
114
+ }
103
115
  // Update package.json name if a project name was provided
104
116
  if (projectName && projectName !== '.') {
105
117
  const pkgPath = join(targetDir, 'package.json');
@@ -4,6 +4,5 @@ export interface CliOptions {
4
4
  addOns: string | boolean | undefined;
5
5
  listAddonsJson: boolean;
6
6
  git: boolean;
7
- force: boolean | undefined;
8
7
  targetDir: string | undefined;
9
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kaddidlehopper",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Create TanStack Start applications for Netlify",
5
5
  "bin": "./dist/index.js",
6
6
  "type": "module",
package/src/cli.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { resolve, basename } from 'node:path'
2
- import { existsSync, readdirSync } from 'node:fs'
2
+ import { existsSync } from 'node:fs'
3
3
  import { cp, rm, mkdtemp, readFile, writeFile } from 'node:fs/promises'
4
4
  import { tmpdir } from 'node:os'
5
5
  import { join } from 'node:path'
@@ -10,9 +10,9 @@ import validatePackageName from 'validate-npm-package-name'
10
10
 
11
11
  import type { CliOptions } from './types.js'
12
12
 
13
- const GITHUB_REPO = 'https://github.com/jherr/kdh-templates.git'
13
+ const GITHUB_REPO = 'https://github.com/netlify/swar-templates.git'
14
14
  const MANIFEST_URL =
15
- 'https://raw.githubusercontent.com/jherr/kdh-templates/main/manifest.json'
15
+ 'https://raw.githubusercontent.com/netlify/swar-templates/main/manifest.json'
16
16
 
17
17
  function sanitizePackageName(name: string): string {
18
18
  return name
@@ -72,10 +72,6 @@ export function cli() {
72
72
  '--target-dir <path>',
73
73
  'the target directory for the application root',
74
74
  )
75
- .option(
76
- '-f, --force',
77
- 'force project creation even if the target directory is not empty',
78
- )
79
75
 
80
76
  program.action(async (projectName: string | undefined, options: CliOptions) => {
81
77
  // Handle --list-addons-json
@@ -106,17 +102,10 @@ export function cli() {
106
102
  process.exit(1)
107
103
  }
108
104
 
109
- // Check if target directory exists and is non-empty
110
- if (existsSync(targetDir)) {
111
- const contents = readdirSync(targetDir)
112
- if (contents.length > 0 && !options.force) {
113
- console.error(
114
- chalk.red(
115
- `Target directory "${targetDir}" is not empty. Use --force to overwrite.`,
116
- ),
117
- )
118
- process.exit(1)
119
- }
105
+ // Delete index.html if it exists in the target directory
106
+ const indexHtmlPath = join(targetDir, 'index.html')
107
+ if (existsSync(indexHtmlPath)) {
108
+ await rm(indexHtmlPath)
120
109
  }
121
110
 
122
111
  console.log(
@@ -126,16 +115,23 @@ export function cli() {
126
115
  )
127
116
  console.log(chalk.gray(`Using starter: ${starterId}`))
128
117
 
118
+ // Fetch manifest to resolve frameworkId for this starter
119
+ type StarterEntry = { id: string; framework?: string }
120
+ const manifest = await fetch(MANIFEST_URL).then((r) => r.json()) as { starters: StarterEntry[] }
121
+ const starterEntry = manifest.starters.find((s) => s.id === starterId)
122
+ const frameworkId = starterEntry?.framework
123
+
129
124
  // Sparse clone the template repo into a temp directory
130
125
  const tmpDir = await mkdtemp(join(tmpdir(), 'netlify-cta-'))
131
126
  try {
132
127
  console.log(chalk.gray('⟳ Fetching template...'))
128
+ const sparsePaths = [`starters/${starterId}`, ...(frameworkId ? [`frameworks/${frameworkId}`] : [])]
133
129
  execSync(
134
130
  `git clone --depth=1 --filter=blob:none --sparse ${GITHUB_REPO} ${tmpDir}`,
135
131
  { stdio: 'pipe' },
136
132
  )
137
133
  execSync(
138
- `git -C ${tmpDir} sparse-checkout set starters/${starterId}`,
134
+ `git -C ${tmpDir} sparse-checkout set ${sparsePaths.join(' ')}`,
139
135
  { stdio: 'pipe' },
140
136
  )
141
137
 
@@ -152,6 +148,18 @@ export function cli() {
152
148
  // Copy starter files to target directory
153
149
  await cp(starterPath, targetDir, { recursive: true })
154
150
 
151
+ // Copy framework overlay files if they exist
152
+ if (frameworkId) {
153
+ const frameworkPath = join(tmpDir, 'frameworks', frameworkId)
154
+ if (existsSync(frameworkPath)) {
155
+ console.log(chalk.gray(`⟳ Applying framework overlay (${frameworkId})...`))
156
+ await cp(frameworkPath, targetDir, { recursive: true })
157
+ console.log(chalk.green(`✓ Framework overlay applied (${frameworkId})`))
158
+ } else {
159
+ console.log(chalk.yellow(`⚠ Framework overlay "${frameworkId}" not found in repo, skipping`))
160
+ }
161
+ }
162
+
155
163
  // Update package.json name if a project name was provided
156
164
  if (projectName && projectName !== '.') {
157
165
  const pkgPath = join(targetDir, 'package.json')
package/src/types.ts CHANGED
@@ -4,6 +4,5 @@ export interface CliOptions {
4
4
  addOns: string | boolean | undefined
5
5
  listAddonsJson: boolean
6
6
  git: boolean
7
- force: boolean | undefined
8
7
  targetDir: string | undefined
9
8
  }