novaui-cli 1.1.2 → 1.1.3

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/src/constants.js CHANGED
@@ -1,15 +1,22 @@
1
- export const BASE_URL = 'https://raw.githubusercontent.com/KaloyanBehov/novaui/main'
1
+ // Allow overriding branch via environment variable (useful for testing)
2
+ const BRANCH = process.env.NOVAUI_BRANCH || 'main';
2
3
 
3
- export const CONFIG_FILENAME = 'components.json'
4
+ export const BASE_URL = `https://raw.githubusercontent.com/KaloyanBehov/novaui/${BRANCH}`;
4
5
 
5
- export const FETCH_TIMEOUT_MS = 15000
6
+ export const REGISTRY_URL = `${BASE_URL}/packages/registry/registry.json`;
7
+
8
+ export const THEMES_BASE_URL = `${BASE_URL}/packages/themes`;
9
+
10
+ export const CONFIG_FILENAME = 'components.json';
11
+
12
+ export const FETCH_TIMEOUT_MS = 15000;
6
13
 
7
14
  export const DEFAULT_CONFIG = {
8
15
  globalCss: 'global.css',
9
16
  componentsUi: 'components/ui',
10
17
  lib: 'lib',
11
18
  theme: 'default',
12
- }
19
+ };
13
20
 
14
21
  export const UTILS_CONTENT = `import { type ClassValue, clsx } from "clsx"
15
22
  import { twMerge } from "tailwind-merge"
@@ -17,4 +24,78 @@ import { twMerge } from "tailwind-merge"
17
24
  export function cn(...inputs: ClassValue[]) {
18
25
  return twMerge(clsx(inputs))
19
26
  }
20
- `
27
+ `;
28
+
29
+ // Default theme bundled as fallback (always available, no network required)
30
+ export const DEFAULT_THEME_CSS = `@tailwind base;
31
+ @tailwind components;
32
+ @tailwind utilities;
33
+
34
+ @layer base {
35
+ :root {
36
+ --background: 0 0% 100%;
37
+ --foreground: 240 10% 3.9%;
38
+ --card: 0 0% 100%;
39
+ --card-foreground: 240 10% 3.9%;
40
+ --popover: 0 0% 100%;
41
+ --popover-foreground: 240 10% 3.9%;
42
+ --primary: 240 5.9% 10%;
43
+ --primary-foreground: 0 0% 98%;
44
+ --secondary: 240 4.8% 95.9%;
45
+ --secondary-foreground: 240 5.9% 10%;
46
+ --muted: 240 4.8% 95.9%;
47
+ --muted-foreground: 240 3.8% 46.1%;
48
+ --accent: 240 4.8% 95.9%;
49
+ --accent-foreground: 240 5.9% 10%;
50
+ --destructive: 0 84.2% 60.2%;
51
+ --destructive-foreground: 0 0% 98%;
52
+ --border: 240 5.9% 90%;
53
+ --input: 240 5.9% 90%;
54
+ --ring: 240 5.9% 10%;
55
+ --radius: 0.5rem;
56
+ }
57
+
58
+ .dark {
59
+ --background: 240 10% 3.9%;
60
+ --foreground: 0 0% 98%;
61
+ --card: 240 10% 3.9%;
62
+ --card-foreground: 0 0% 98%;
63
+ --popover: 240 10% 3.9%;
64
+ --popover-foreground: 0 0% 98%;
65
+ --primary: 0 0% 98%;
66
+ --primary-foreground: 240 5.9% 10%;
67
+ --secondary: 240 3.7% 15.9%;
68
+ --secondary-foreground: 0 0% 98%;
69
+ --muted: 240 3.7% 15.9%;
70
+ --muted-foreground: 240 5% 64.9%;
71
+ --accent: 240 3.7% 15.9%;
72
+ --accent-foreground: 0 0% 98%;
73
+ --destructive: 0 62.8% 30.6%;
74
+ --destructive-foreground: 0 0% 98%;
75
+ --border: 240 3.7% 15.9%;
76
+ --input: 240 3.7% 15.9%;
77
+ --ring: 240 4.9% 83.9%;
78
+ }
79
+ }
80
+ `;
81
+
82
+ export const BABEL_CONFIG_CONTENT = `module.exports = function (api) {
83
+ api.cache(true);
84
+ return {
85
+ presets: [
86
+ ["babel-preset-expo", { jsxImportSource: "nativewind" }],
87
+ "nativewind/babel",
88
+ ],
89
+ };
90
+ };
91
+ `;
92
+
93
+ export const METRO_CONFIG_CONTENT = (
94
+ globalCssPath
95
+ ) => `const { getDefaultConfig } = require("expo/metro-config");
96
+ const { withNativeWind } = require('nativewind/metro');
97
+
98
+ const config = getDefaultConfig(__dirname)
99
+
100
+ module.exports = withNativeWind(config, { input: './${globalCssPath}' })
101
+ `;
@@ -1,17 +1,48 @@
1
- import { DEFAULT_THEME_CSS } from './default.js'
2
- import { OCEAN_THEME_CSS } from './ocean.js'
3
- import { SUNSET_THEME_CSS } from './sunset.js'
1
+ import { THEMES_BASE_URL, DEFAULT_THEME_CSS } from '../constants.js'
2
+ import { fetchWithTimeout } from '../utils/fetch.js'
4
3
 
5
- export const THEMES = {
6
- default: DEFAULT_THEME_CSS,
7
- ocean: OCEAN_THEME_CSS,
8
- sunset: SUNSET_THEME_CSS,
9
- }
10
-
11
- export const THEME_KEYS = Object.keys(THEMES)
4
+ // Available theme names (fetched from GitHub)
5
+ export const THEME_KEYS = ['default', 'ocean', 'sunset']
12
6
 
13
- export function getThemeCssContent(themeName) {
14
- if (typeof themeName !== 'string') return THEMES.default
15
- const normalized = themeName.trim().toLowerCase()
16
- return THEMES[normalized] || THEMES.default
7
+ /**
8
+ * Fetch theme CSS content from GitHub.
9
+ * Falls back to bundled default theme if fetch fails or theme is 'default'.
10
+ *
11
+ * @param {string} themeName - The theme name (default, ocean, sunset)
12
+ * @returns {Promise<string>} The theme CSS content
13
+ */
14
+ export async function getThemeCssContent(themeName) {
15
+ const normalized = (typeof themeName === 'string' ? themeName : 'default').trim().toLowerCase()
16
+ const theme = THEME_KEYS.includes(normalized) ? normalized : 'default'
17
+
18
+ // Use bundled default theme (no network call needed)
19
+ if (theme === 'default') {
20
+ return DEFAULT_THEME_CSS
21
+ }
22
+
23
+ // Fetch other themes from GitHub
24
+ const themeUrl = `${THEMES_BASE_URL}/${theme}.js`
25
+
26
+ try {
27
+ const response = await fetchWithTimeout(themeUrl)
28
+
29
+ if (!response.ok) {
30
+ throw new Error(`Failed to fetch theme: ${response.status}`)
31
+ }
32
+
33
+ const content = await response.text()
34
+
35
+ // Extract the CSS content from the export statement
36
+ // Example: export const OCEAN_THEME_CSS = `...`
37
+ const match = content.match(/export const \w+_THEME_CSS = `([^`]*)`/s)
38
+ if (match && match[1]) {
39
+ return match[1]
40
+ }
41
+
42
+ throw new Error('Invalid theme format')
43
+ } catch (error) {
44
+ // Fallback to default theme on error
45
+ console.warn(`Warning: Could not fetch "${theme}" theme, using default. ${error.message}`)
46
+ return DEFAULT_THEME_CSS
47
+ }
17
48
  }
@@ -1,22 +1,22 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
- import { CONFIG_FILENAME, DEFAULT_CONFIG } from '../constants.js'
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { CONFIG_FILENAME, DEFAULT_CONFIG } from '../constants.js';
4
4
 
5
5
  /** Load components.json from cwd; returns null if missing or invalid. */
6
6
  export function loadConfig(cwd) {
7
- const configPath = path.join(cwd, CONFIG_FILENAME)
8
- if (!fs.existsSync(configPath)) return null
7
+ const configPath = path.join(cwd, CONFIG_FILENAME);
8
+ if (!fs.existsSync(configPath)) return null;
9
9
  try {
10
- const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'))
11
- if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null
12
- return { ...DEFAULT_CONFIG, ...raw }
10
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
11
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;
12
+ return { ...DEFAULT_CONFIG, ...raw };
13
13
  } catch {
14
- return null
14
+ return null;
15
15
  }
16
16
  }
17
17
 
18
18
  /** Write components.json to cwd. */
19
19
  export function writeConfig(cwd, config) {
20
- const configPath = path.join(cwd, CONFIG_FILENAME)
21
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8')
20
+ const configPath = path.join(cwd, CONFIG_FILENAME);
21
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
22
22
  }
package/src/utils/deps.js CHANGED
@@ -1,36 +1,40 @@
1
- import { execFileSync } from 'node:child_process'
2
- import fs from 'node:fs'
3
- import path from 'node:path'
1
+ import { execFileSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
4
 
5
5
  export function detectPackageManager() {
6
- const userAgent = process.env.npm_config_user_agent || ''
7
- if (userAgent.startsWith('yarn')) return { command: 'yarn', baseArgs: ['add'] }
8
- if (userAgent.startsWith('pnpm')) return { command: 'pnpm', baseArgs: ['add'] }
9
- if (userAgent.startsWith('bun')) return { command: 'bun', baseArgs: ['add'] }
10
- return { command: 'npm', baseArgs: ['install'] }
6
+ const userAgent = process.env.npm_config_user_agent || '';
7
+ if (userAgent.startsWith('yarn')) return { command: 'yarn', baseArgs: ['add'], devFlag: '--dev' };
8
+ if (userAgent.startsWith('pnpm')) return { command: 'pnpm', baseArgs: ['add'], devFlag: '--save-dev' };
9
+ if (userAgent.startsWith('bun')) return { command: 'bun', baseArgs: ['add'], devFlag: '--dev' };
10
+ return { command: 'npm', baseArgs: ['install'], devFlag: '--save-dev' };
11
11
  }
12
12
 
13
- export function installPackages(packages) {
14
- if (!Array.isArray(packages) || packages.length === 0) return
15
- const { command, baseArgs } = detectPackageManager()
16
- execFileSync(command, [...baseArgs, ...packages], { stdio: 'inherit' })
13
+ export function installPackages(packages, options = {}) {
14
+ if (!Array.isArray(packages) || packages.length === 0) return;
15
+ const { dev = false } = options;
16
+ const { command, baseArgs, devFlag } = detectPackageManager();
17
+ const args = dev ? [...baseArgs, devFlag, ...packages] : [...baseArgs, ...packages];
18
+ execFileSync(command, args, { stdio: 'inherit' });
17
19
  }
18
20
 
19
- export function getInstallHint(packages) {
20
- const { command, baseArgs } = detectPackageManager()
21
- return `${command} ${[...baseArgs, ...packages].join(' ')}`
21
+ export function getInstallHint(packages, options = {}) {
22
+ const { dev = false } = options;
23
+ const { command, baseArgs, devFlag } = detectPackageManager();
24
+ const args = dev ? [...baseArgs, devFlag, ...packages] : [...baseArgs, ...packages];
25
+ return `${command} ${args.join(' ')}`;
22
26
  }
23
27
 
24
28
  /** Returns which of the requested deps are not listed in package.json (dependencies or devDependencies). */
25
29
  export function getMissingDeps(cwd, deps) {
26
- const pkgPath = path.join(cwd, 'package.json')
30
+ const pkgPath = path.join(cwd, 'package.json');
27
31
  if (!fs.existsSync(pkgPath)) {
28
- return [...deps]
32
+ return [...deps];
29
33
  }
30
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
34
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
31
35
  const installed = new Set([
32
36
  ...Object.keys(pkg.dependencies || {}),
33
37
  ...Object.keys(pkg.devDependencies || {}),
34
- ])
35
- return deps.filter(d => !installed.has(d))
38
+ ]);
39
+ return deps.filter((d) => !installed.has(d));
36
40
  }
@@ -1,21 +1,21 @@
1
- import { FETCH_TIMEOUT_MS } from '../constants.js'
1
+ import { FETCH_TIMEOUT_MS } from '../constants.js';
2
2
 
3
3
  export async function fetchWithTimeout(url) {
4
- const controller = new AbortController()
5
- const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS)
4
+ const controller = new AbortController();
5
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
6
6
  try {
7
- return await fetch(url, { signal: controller.signal })
7
+ return await fetch(url, { signal: controller.signal });
8
8
  } catch (error) {
9
9
  if (error && error.name === 'AbortError') {
10
- throw new Error(`Request timed out after ${FETCH_TIMEOUT_MS}ms: ${url}`)
10
+ throw new Error(`Request timed out after ${FETCH_TIMEOUT_MS}ms: ${url}`);
11
11
  }
12
- throw error
12
+ throw error;
13
13
  } finally {
14
- clearTimeout(timeout)
14
+ clearTimeout(timeout);
15
15
  }
16
16
  }
17
17
 
18
18
  export function formatError(error) {
19
- if (error instanceof Error && error.message) return error.message
20
- return String(error)
19
+ if (error instanceof Error && error.message) return error.message;
20
+ return String(error);
21
21
  }
@@ -1,18 +1,18 @@
1
- import fs from 'node:fs'
2
- import pc from 'picocolors'
1
+ import fs from 'node:fs';
2
+ import pc from 'picocolors';
3
3
 
4
4
  export function ensureDir(dir) {
5
5
  if (!fs.existsSync(dir)) {
6
- fs.mkdirSync(dir, { recursive: true })
6
+ fs.mkdirSync(dir, { recursive: true });
7
7
  }
8
8
  }
9
9
 
10
10
  export function writeIfNotExists(filePath, content, label) {
11
11
  if (fs.existsSync(filePath)) {
12
- console.log(pc.dim(` ℹ ${label} already exists, skipping.`))
13
- return false
12
+ console.log(pc.dim(` ℹ ${label} already exists, skipping.`));
13
+ return false;
14
14
  }
15
- fs.writeFileSync(filePath, content, 'utf8')
16
- console.log(pc.green(` ✓ Created ${label}`))
17
- return true
15
+ fs.writeFileSync(filePath, content, 'utf8');
16
+ console.log(pc.green(` ✓ Created ${label}`));
17
+ return true;
18
18
  }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Fuzzy matching utilities for better error messages
3
+ * Helps users find components when they mistype names
4
+ */
5
+
6
+ /**
7
+ * Calculate Levenshtein distance between two strings
8
+ * Used for finding similar component names
9
+ */
10
+ function levenshteinDistance(str1, str2) {
11
+ const len1 = str1.length
12
+ const len2 = str2.length
13
+ const matrix = []
14
+
15
+ for (let i = 0; i <= len1; i++) {
16
+ matrix[i] = [i]
17
+ }
18
+
19
+ for (let j = 0; j <= len2; j++) {
20
+ matrix[0][j] = j
21
+ }
22
+
23
+ for (let i = 1; i <= len1; i++) {
24
+ for (let j = 1; j <= len2; j++) {
25
+ const cost = str1[i - 1] === str2[j - 1] ? 0 : 1
26
+ matrix[i][j] = Math.min(
27
+ matrix[i - 1][j] + 1,
28
+ matrix[i][j - 1] + 1,
29
+ matrix[i - 1][j - 1] + cost
30
+ )
31
+ }
32
+ }
33
+
34
+ return matrix[len1][len2]
35
+ }
36
+
37
+ /**
38
+ * Find similar component names based on typo distance
39
+ * Returns up to maxResults similar names, sorted by similarity
40
+ */
41
+ export function findSimilarComponents(input, availableComponents, maxResults = 5) {
42
+ const normalizedInput = input.toLowerCase().trim()
43
+
44
+ const scored = availableComponents
45
+ .map(name => ({
46
+ name,
47
+ distance: levenshteinDistance(normalizedInput, name.toLowerCase()),
48
+ startsWithSame: name.toLowerCase().startsWith(normalizedInput[0]),
49
+ }))
50
+ .filter(item => item.distance <= 4) // Only suggest if reasonably close
51
+ .sort((a, b) => {
52
+ if (a.distance !== b.distance) {
53
+ return a.distance - b.distance
54
+ }
55
+ if (a.startsWithSame !== b.startsWithSame) {
56
+ return a.startsWithSame ? -1 : 1
57
+ }
58
+ return a.name.localeCompare(b.name)
59
+ })
60
+ .slice(0, maxResults)
61
+ .map(item => item.name)
62
+
63
+ return scored
64
+ }
65
+
66
+ /**
67
+ * Format a helpful error message for missing components
68
+ */
69
+ export function formatComponentNotFoundError(componentName, availableComponents) {
70
+ const similar = findSimilarComponents(componentName, availableComponents)
71
+
72
+ let message = `Component "${componentName}" not found in registry.`
73
+
74
+ if (similar.length > 0) {
75
+ message += '\n\n Did you mean one of these?'
76
+ similar.forEach(name => {
77
+ message += `\n • ${name}`
78
+ })
79
+ }
80
+
81
+ message += '\n\n Available components:'
82
+
83
+ const sorted = [...availableComponents].sort()
84
+ const columns = 3
85
+ const itemsPerColumn = Math.ceil(sorted.length / columns)
86
+
87
+ for (let i = 0; i < itemsPerColumn; i++) {
88
+ let row = ' '
89
+ for (let col = 0; col < columns; col++) {
90
+ const idx = i + col * itemsPerColumn
91
+ if (idx < sorted.length) {
92
+ row += sorted[idx].padEnd(20)
93
+ }
94
+ }
95
+ message += '\n' + row.trimEnd()
96
+ }
97
+
98
+ return message
99
+ }
@@ -0,0 +1,172 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import pc from 'picocolors'
4
+
5
+ /**
6
+ * Pre-flight checks to ensure the project environment is ready for NovaUI
7
+ */
8
+
9
+ export function checkPackageJson(cwd) {
10
+ const pkgPath = path.join(cwd, 'package.json')
11
+ if (!fs.existsSync(pkgPath)) {
12
+ throw new Error('package.json not found. Please run this command in a valid Node.js project.')
13
+ }
14
+
15
+ try {
16
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
17
+ return pkg
18
+ } catch (error) {
19
+ throw new Error('package.json is invalid or cannot be parsed.')
20
+ }
21
+ }
22
+
23
+ export function checkReactNativeProject(pkg) {
24
+ const deps = {
25
+ ...pkg.dependencies,
26
+ ...pkg.devDependencies,
27
+ }
28
+
29
+ if (!deps['react-native'] && !deps['expo']) {
30
+ console.log('')
31
+ console.log(pc.yellow(' ⚠ Warning: react-native or expo not found in dependencies.'))
32
+ console.log(pc.dim(' NovaUI is designed for React Native projects.'))
33
+ console.log('')
34
+ }
35
+ }
36
+
37
+ export function checkBabelConfig(cwd) {
38
+ const babelPaths = [
39
+ path.join(cwd, 'babel.config.js'),
40
+ path.join(cwd, 'babel.config.json'),
41
+ path.join(cwd, '.babelrc'),
42
+ path.join(cwd, '.babelrc.js'),
43
+ ]
44
+
45
+ for (const babelPath of babelPaths) {
46
+ if (fs.existsSync(babelPath)) {
47
+ return babelPath
48
+ }
49
+ }
50
+
51
+ return null
52
+ }
53
+
54
+ export function checkNativeWindInBabel(cwd) {
55
+ const babelPath = checkBabelConfig(cwd)
56
+
57
+ if (!babelPath) {
58
+ console.log('')
59
+ console.log(pc.yellow(' ⚠ Warning: babel.config.js not found.'))
60
+ console.log(pc.dim(' NativeWind requires Babel configuration.'))
61
+ console.log('')
62
+ return false
63
+ }
64
+
65
+ try {
66
+ const content = fs.readFileSync(babelPath, 'utf-8')
67
+ const hasNativeWind = content.includes('nativewind/babel') || content.includes('"nativewind/babel"')
68
+
69
+ if (!hasNativeWind) {
70
+ console.log('')
71
+ console.log(pc.yellow(' ⚠ Warning: NativeWind not detected in Babel config.'))
72
+ console.log(pc.dim(' Add "nativewind/babel" to your Babel plugins:'))
73
+ console.log('')
74
+ console.log(pc.cyan(' module.exports = {'))
75
+ console.log(pc.cyan(' plugins: ["nativewind/babel"],'))
76
+ console.log(pc.cyan(' }'))
77
+ console.log('')
78
+ console.log(pc.dim(' See: https://www.nativewind.dev/docs/getting-started/installation'))
79
+ console.log('')
80
+ return false
81
+ }
82
+
83
+ return true
84
+ } catch (error) {
85
+ console.log('')
86
+ console.log(pc.yellow(' ⚠ Warning: Could not read babel.config.js'))
87
+ console.log('')
88
+ return false
89
+ }
90
+ }
91
+
92
+ export function checkReactNativeVersion(pkg) {
93
+ const deps = {
94
+ ...pkg.dependencies,
95
+ ...pkg.devDependencies,
96
+ }
97
+
98
+ const rnVersion = deps['react-native']
99
+ if (rnVersion) {
100
+ const versionMatch = rnVersion.match(/(\d+)\.(\d+)/)
101
+ if (versionMatch) {
102
+ const [, major, minor] = versionMatch
103
+ const majorNum = parseInt(major, 10)
104
+ const minorNum = parseInt(minor, 10)
105
+
106
+ if (majorNum < 0 || (majorNum === 0 && minorNum < 72)) {
107
+ console.log('')
108
+ console.log(pc.yellow(' ⚠ Warning: React Native version is below 0.72'))
109
+ console.log(pc.dim(' NovaUI requires React Native >= 0.72'))
110
+ console.log('')
111
+ return false
112
+ }
113
+ }
114
+ }
115
+
116
+ return true
117
+ }
118
+
119
+ export function checkNativeWindVersion(pkg) {
120
+ const deps = {
121
+ ...pkg.dependencies,
122
+ ...pkg.devDependencies,
123
+ }
124
+
125
+ const nwVersion = deps['nativewind']
126
+ if (!nwVersion) {
127
+ console.log('')
128
+ console.log(pc.yellow(' ⚠ Warning: NativeWind not found in package.json'))
129
+ console.log(pc.dim(' NovaUI requires NativeWind >= 4.0'))
130
+ console.log(pc.dim(' Install: npm install nativewind'))
131
+ console.log(pc.dim(' See: https://www.nativewind.dev/docs/getting-started/installation'))
132
+ console.log('')
133
+ return false
134
+ }
135
+
136
+ // Check if version 4 or higher
137
+ const versionMatch = nwVersion.match(/(\d+)/)
138
+ if (versionMatch) {
139
+ const [, major] = versionMatch
140
+ const majorNum = parseInt(major, 10)
141
+
142
+ if (majorNum < 4) {
143
+ console.log('')
144
+ console.log(pc.yellow(' ⚠ Warning: NativeWind version is below 4.0'))
145
+ console.log(pc.dim(' NovaUI requires NativeWind >= 4.0'))
146
+ console.log(pc.dim(' Upgrade: npm install nativewind@latest'))
147
+ console.log('')
148
+ return false
149
+ }
150
+ }
151
+
152
+ return true
153
+ }
154
+
155
+ /**
156
+ * Run all pre-flight checks before init command
157
+ */
158
+ export function runInitPreflightChecks(cwd) {
159
+ const pkg = checkPackageJson(cwd)
160
+ checkReactNativeProject(pkg)
161
+ checkNativeWindVersion(pkg)
162
+ checkNativeWindInBabel(cwd)
163
+ checkReactNativeVersion(pkg)
164
+ }
165
+
166
+ /**
167
+ * Run minimal pre-flight checks before add command
168
+ */
169
+ export function runAddPreflightChecks(cwd) {
170
+ const pkg = checkPackageJson(cwd)
171
+ return pkg
172
+ }