@create-mastery/cli 0.1.0 → 0.1.2

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/cli.ts CHANGED
@@ -1,21 +1,32 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
+ import { execSync } from 'node:child_process'
4
+ import { readFileSync } from 'node:fs'
5
+ import path from 'node:path'
6
+ import chalk from 'chalk'
3
7
  import { program } from 'commander'
4
8
  import gradient from 'gradient-string'
9
+ import type { PackageJson } from 'type-fest'
5
10
  import addComponent from './commands/add/component'
6
11
  import addLanguage from './commands/add/language'
7
12
  import { genSchema } from './commands/generate-schema'
8
13
  import printScripts from './commands/scripts'
9
14
  import printVersion from './commands/version'
10
- import cliInfo from './package.json'
11
15
  import { createMasteryASCIIArtBig } from './utils/arts'
12
- import { execSync } from 'node:child_process'
13
- import chalk from 'chalk'
16
+ import { requireProjectRoot } from './utils/require-project-root'
17
+ import { fileURLToPath } from 'node:url'
18
+
19
+ const __filename = fileURLToPath(import.meta.url)
20
+ const __dirname = path.dirname(__filename)
14
21
 
15
22
  const add = program.command('add').description('add a language or component')
16
23
  const gen = program.command('gen').description('generate the dictionary schema')
17
24
 
18
- program.version(cliInfo.version)
25
+ const cliPackagePath = path.resolve(__dirname, './package.json')
26
+
27
+ const cliInfo: PackageJson = JSON.parse(readFileSync(cliPackagePath, 'utf-8'))
28
+
29
+ program.version(cliInfo.version ?? '')
19
30
  program.name('cm')
20
31
 
21
32
  program.addHelpText(
@@ -29,7 +40,7 @@ program.addHelpText(
29
40
  // I know this may look silly, but it's for creating space between the prompt and the help message
30
41
  program.addHelpText('afterAll', ' ')
31
42
 
32
- program.description(cliInfo.description)
43
+ program.description(cliInfo.description ?? '')
33
44
 
34
45
  program
35
46
  .command('version')
@@ -37,12 +48,21 @@ program
37
48
  'display the version of the Create Mastery website and some other useful information'
38
49
  )
39
50
  .option('-v, --verbose', 'verbose output of version command', false)
40
- .action((options) => printVersion(options.verbose))
51
+ .action((options) => {
52
+ const projectRoot = requireProjectRoot()
53
+ printVersion(options.verbose, cliInfo, projectRoot)
54
+ })
41
55
 
42
56
  program
43
57
  .command('scripts')
44
58
  .description('display all the available scripts in package.json')
45
- .action(() => printScripts())
59
+ .action(() => {
60
+ const projectRoot = requireProjectRoot()
61
+ const siteInfo: PackageJson = JSON.parse(
62
+ readFileSync(path.join(projectRoot, 'package.json'), 'utf-8')
63
+ )
64
+ printScripts(siteInfo)
65
+ })
46
66
 
47
67
  program
48
68
  .command('clone')
@@ -66,7 +86,10 @@ program
66
86
  gen
67
87
  .command('schema')
68
88
  .description('generates the schema for the dictionaries')
69
- .action(() => genSchema())
89
+ .action(() => {
90
+ const projectRoot = requireProjectRoot()
91
+ genSchema(projectRoot)
92
+ })
70
93
 
71
94
  add
72
95
  .command('component')
@@ -74,7 +97,10 @@ add
74
97
  .argument('<name>', 'component to add')
75
98
  .option('-p, --props', 'the component is generated with props', false)
76
99
  .option('-c, --client', 'the component is a client component', false)
77
- .action((name, options) => addComponent(name, options.props, options.client))
100
+ .action((name, options) => {
101
+ const projectRoot = requireProjectRoot()
102
+ addComponent(name, options.props, options.client, projectRoot)
103
+ })
78
104
 
79
105
  add
80
106
  .command('language')
@@ -1,17 +1,15 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
3
  import chalk from 'chalk'
5
4
 
6
- const __filename = fileURLToPath(import.meta.url)
7
- const __dirname = path.dirname(__filename)
8
- const componentsDir = path.resolve(__dirname, '../../../src/components/')
9
-
10
5
  export default function addComponent(
11
6
  componentName: string,
12
7
  props: boolean,
13
- client: boolean
8
+ client: boolean,
9
+ projectRoot: string
14
10
  ) {
11
+ const componentsDir = path.resolve(projectRoot, 'src/components/')
12
+
15
13
  const filePath = path.resolve(componentsDir, `${componentName}.tsx`)
16
14
  const dirPath = path.dirname(filePath)
17
15
 
@@ -1,11 +1,9 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
3
  import chalk from 'chalk'
4
+ import { findProjectRoot } from '../../utils/find-project-root'
5
5
 
6
- const __filename = fileURLToPath(import.meta.url)
7
- const __dirname = path.dirname(__filename)
8
- const dictionarieDir = path.resolve(__dirname, '../../../src/i18n/dictionaries')
6
+ const projectRoot = findProjectRoot()
9
7
 
10
8
  type Json =
11
9
  | string
@@ -37,7 +35,7 @@ function genLocales(files: string[]) {
37
35
  const content = `export type locales = ${locales}\n`
38
36
 
39
37
  fs.writeFileSync(
40
- path.resolve(__dirname, '../../../src/i18n/types/locales.ts'),
38
+ path.resolve(projectRoot ?? '', '../../../src/i18n/types/locales.ts'),
41
39
  content
42
40
  )
43
41
  }
@@ -54,7 +52,7 @@ function genI18n(files: string[]) {
54
52
  }`
55
53
 
56
54
  fs.writeFileSync(
57
- path.resolve(__dirname, '../../../src/i18n/i18n.ts'),
55
+ path.resolve(projectRoot ?? '', '../../../src/i18n/i18n.ts'),
58
56
  content
59
57
  )
60
58
  }
@@ -72,7 +70,7 @@ function genDictionaryLoaders(files: string[]) {
72
70
 
73
71
  fs.writeFileSync(
74
72
  path.resolve(
75
- __dirname,
73
+ projectRoot ?? '',
76
74
  '../../../src/i18n/dictionaries/dictionaries-loaders.ts'
77
75
  ),
78
76
  dictionariesLoaders
@@ -80,6 +78,11 @@ function genDictionaryLoaders(files: string[]) {
80
78
  }
81
79
 
82
80
  export default function addLanguage(language: string) {
81
+ const dictionarieDir = path.resolve(
82
+ projectRoot ?? '',
83
+ '../../../src/i18n/dictionaries'
84
+ )
85
+
83
86
  const input = JSON.parse(fs.readFileSync(`${dictionarieDir}/en.json`, 'utf8'))
84
87
  const output = stripValues(input)
85
88
 
@@ -1,20 +1,7 @@
1
- import * as GenerateSchema from 'generate-schema'
2
-
3
1
  import fs from 'node:fs'
4
2
  import path from 'node:path'
5
- import { fileURLToPath } from 'node:url'
6
3
  import chalk from 'chalk'
7
-
8
- const __filename = fileURLToPath(import.meta.url)
9
- const __dirname = path.dirname(__filename)
10
- const dictionarieDir = path.resolve(__dirname, '../../src/i18n/dictionaries/')
11
- const dictionary = JSON.parse(
12
- fs.readFileSync(`${dictionarieDir}/en.json`, 'utf8')
13
- )
14
- const schemaPath = path.resolve(
15
- __dirname,
16
- `${dictionarieDir}/schema.schema.json`
17
- )
4
+ import * as GenerateSchema from 'generate-schema'
18
5
 
19
6
  interface JsonSchema {
20
7
  type: string
@@ -45,7 +32,21 @@ function addRequiredRecursively(
45
32
  }
46
33
  }
47
34
 
48
- export function genSchema() {
35
+ export function genSchema(projectRoot: string) {
36
+ const dictionarieDir = path.resolve(
37
+ projectRoot ?? '',
38
+ 'src/i18n/dictionaries/'
39
+ )
40
+
41
+ const dictionary = JSON.parse(
42
+ fs.readFileSync(`${dictionarieDir}/en.json`, 'utf8')
43
+ )
44
+
45
+ const schemaPath = path.resolve(
46
+ projectRoot ?? '',
47
+ `${dictionarieDir}/schema.schema.json`
48
+ )
49
+
49
50
  const schema = GenerateSchema.json('dictionary schema', dictionary)
50
51
 
51
52
  addRequiredRecursively(schema, dictionary)
@@ -1,12 +1,12 @@
1
1
  import chalk from 'chalk'
2
- import siteInfo from '../../package.json'
2
+ import type { PackageJson } from 'type-fest'
3
3
  import { createMasteryASCIIArtSmall } from '../utils/arts'
4
4
 
5
- export default function printScripts() {
5
+ export default function printScripts(siteInfo: PackageJson) {
6
6
  console.log(chalk.blue(createMasteryASCIIArtSmall))
7
7
  console.log(chalk.blue('Available scripts:'))
8
8
  console.log(chalk.blue('──────────────────────────────────────────'))
9
- Object.entries(siteInfo.scripts).forEach(([key, value]) => {
9
+ Object.entries(siteInfo.scripts ?? '').forEach(([key, value]) => {
10
10
  console.log(
11
11
  `${chalk.blue(key.padEnd(10))} ${chalk.blue('─')} ${chalk.reset(value)}`
12
12
  )
@@ -1,30 +1,30 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
3
  import chalk from 'chalk'
5
4
  import { globSync } from 'glob'
6
- import siteInfo from '../../package.json'
5
+ import type { PackageJson } from 'type-fest'
7
6
  import { createMasteryASCIIArtSmall } from '../utils/arts'
8
7
 
9
- const __filename = fileURLToPath(import.meta.url)
10
- const __dirname = path.dirname(__filename)
11
-
12
- export default function printVersion(verbose: boolean) {
13
- const dictionarieDir = path.resolve(__dirname, '../../src/i18n/dictionaries')
14
- const guideDirectory = path.resolve(__dirname, '../../src/app/**/guide')
8
+ export default function printVersion(
9
+ verbose: boolean,
10
+ cliInfo: PackageJson,
11
+ projectRoot: string
12
+ ) {
13
+ const dictionarieDir = path.resolve(projectRoot, 'src/i18n/dictionaries')
14
+ const guideDirectory = path.resolve(projectRoot, 'src/app/**/guide')
15
15
 
16
16
  // since schema.schema.json is also counted we decrement the value by 1 to get the actual number of languages
17
17
  const getLanguages = () =>
18
18
  fs.readdirSync(dictionarieDir).filter((f) => f.endsWith('.json')).length - 1
19
19
 
20
- const deps = Object.keys(siteInfo.dependencies).length
21
- const devDeps = Object.keys(siteInfo.devDependencies).length
20
+ const deps = Object.keys(cliInfo.dependencies ?? '').length
21
+ const devDeps = Object.keys(cliInfo.devDependencies ?? '').length
22
22
 
23
23
  const languages: number = getLanguages()
24
24
  const guides: number = globSync(`${guideDirectory}/**/*.tsx`).length
25
25
 
26
26
  console.log(chalk.blue(createMasteryASCIIArtSmall))
27
- console.log(chalk.blue('VERSION ─'), chalk.reset(siteInfo.version))
27
+ console.log(chalk.blue('VERSION ─'), chalk.reset(cliInfo.version))
28
28
  console.log(chalk.blue('GUIDES ─'), chalk.reset(guides))
29
29
  console.log(chalk.blue('LANGUAGES ─'), chalk.reset(languages))
30
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@create-mastery/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The official Create Website CLI, created to enhance the DX",
5
5
  "homepage": "https://github.com/Create-Mastery/website/tree/main/cli#readme",
6
6
  "repository": {
@@ -15,12 +15,13 @@
15
15
  "cm": "cli.ts"
16
16
  },
17
17
  "dependencies": {
18
- "gradient-string": "^3.0.0",
19
18
  "chalk": "^5.6.2",
20
19
  "commander": "^14.0.2",
21
20
  "generate-schema": "^2.6.0",
22
21
  "glob": "^13.0.0",
23
- "tsx": "^4.21.0"
22
+ "gradient-string": "^3.0.0",
23
+ "tsx": "^4.21.0",
24
+ "type-fest": "^5.4.3"
24
25
  },
25
26
  "devDependencies": {
26
27
  "@biomejs/biome": "^2.3.11"
@@ -0,0 +1,15 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ export function findProjectRoot(startDir = process.cwd()): string | null {
5
+ let dir = startDir
6
+
7
+ while (dir !== path.parse(dir).root) {
8
+ if (fs.existsSync(path.join(dir, '.create-mastery-root'))) {
9
+ return dir
10
+ }
11
+ dir = path.dirname(dir)
12
+ }
13
+
14
+ return null
15
+ }
@@ -0,0 +1,17 @@
1
+ import chalk from 'chalk'
2
+ import { findProjectRoot } from './find-project-root'
3
+
4
+ export function requireProjectRoot(): string {
5
+ const root = findProjectRoot()
6
+
7
+ if (!root) {
8
+ console.error(
9
+ chalk.red(
10
+ 'Not inside a Create Mastery project. Run this command inside a project.'
11
+ )
12
+ )
13
+ process.exit(1)
14
+ }
15
+
16
+ return root
17
+ }