1
1
#!/usr/bin/env node
2
2
3
- import os from 'node:os' ;
4
- import path from 'node:path' ;
5
- import { fileURLToPath } from 'node:url' ;
6
- import { Command } from 'commander' ;
7
- import fse from 'fs-extra' ;
8
- import logSymbols from 'log-symbols' ;
9
- import ora from 'ora' ;
10
- import { tree } from './tree.js' ;
3
+ import path from "node:path" ;
4
+ import { fileURLToPath } from "node:url" ;
5
+ import { Command } from "commander" ;
6
+ import fse from "fs-extra" ;
7
+ import logSymbols from "log-symbols" ;
8
+ import ora from "ora" ;
9
+ import { tree } from "./tree.js" ;
11
10
12
11
const filename = fileURLToPath ( import . meta. url ) ;
13
12
const dirname = path . dirname ( filename ) ;
14
13
15
14
const packageJson = JSON . parse (
16
- fse . readFileSync ( path . resolve ( dirname , ' ../package.json' ) , ' utf8' ) ,
15
+ fse . readFileSync ( path . resolve ( dirname , " ../package.json" ) , " utf8" ) ,
17
16
) ;
18
17
19
18
const getLatestVersionOfTag = async ( packageName , tag ) => {
20
- const cachePath = path . resolve (
21
- os . tmpdir ( ) ,
22
- `${ packageName . replaceAll ( '/' , '-' ) } -${ tag } .json` ,
23
- ) ;
19
+ const cacheFilename = `${ packageName . replaceAll ( "/" , "-" ) } -${ tag } .json` ;
20
+
21
+ const cacheDir = path . join ( path . dirname ( fileURLToPath ( import . meta. url ) ) , '..' , '.cache' ) ;
22
+
23
+ if ( ! fse . existsSync ( cacheDir ) ) {
24
+ fse . mkdirSync ( cacheDir , { recursive : true , mode : 0o700 } ) ;
25
+ }
26
+
27
+ const cachePath = path . join ( cacheDir , cacheFilename ) ;
28
+
24
29
let data ;
25
30
try {
26
31
const response = await fetch (
27
32
`https://registry.npmjs.org/${ packageName } /${ tag } ` ,
28
33
) ;
29
34
data = await response . json ( ) ;
30
- await fse . writeFile ( cachePath , JSON . stringify ( data ) ) ;
35
+
36
+ fse . writeFileSync ( cachePath , JSON . stringify ( data ) , { mode : 0o600 } ) ;
31
37
} catch ( exception ) {
32
38
if ( fse . existsSync ( cachePath ) ) {
33
39
console . warn (
34
40
`${ logSymbols . warning } Failed to fetch the latest version from npm, using a cache` ,
35
41
) ;
36
- data = await fse . readJson ( cachePath ) ;
42
+ data = fse . readJSONSync ( cachePath ) ;
37
43
} else {
38
44
throw exception ;
39
45
}
40
46
}
41
47
42
- if ( typeof data === ' string' && data . startsWith ( ' version not found' ) ) {
48
+ if ( typeof data === " string" && data . startsWith ( " version not found" ) ) {
43
49
console . error ( `Tag ${ tag } does not exist for ${ packageName } .` ) ;
44
50
process . exit ( 1 ) ;
45
51
}
46
52
47
53
const { version } = data ;
48
54
49
55
if ( ! / ^ \d + \. \d + \. \d + .* $ / . test ( version ) ) {
50
- console . error ( ' Invalid version received, something has gone very wrong.' ) ;
56
+ console . error ( " Invalid version received, something has gone very wrong." ) ;
51
57
}
52
-
58
+
53
59
return version ;
54
60
} ;
55
61
56
62
const init = async ( name , { tag } ) => {
57
63
let projectPath = name ;
58
64
59
65
if ( ! projectPath ) {
60
- projectPath = path . join ( process . cwd ( ) , ' react-email-starter' ) ;
66
+ projectPath = path . join ( process . cwd ( ) , " react-email-starter" ) ;
61
67
}
62
68
63
- if ( typeof projectPath === ' string' ) {
69
+ if ( typeof projectPath === " string" ) {
64
70
projectPath = projectPath . trim ( ) ;
65
71
}
66
72
67
- const templatePath = path . resolve ( dirname , ' ../template' ) ;
73
+ const templatePath = path . resolve ( dirname , " ../template" ) ;
68
74
const resolvedProjectPath = path . resolve ( projectPath ) ;
69
75
70
76
if ( fse . existsSync ( resolvedProjectPath ) ) {
@@ -73,51 +79,51 @@ const init = async (name, { tag }) => {
73
79
}
74
80
75
81
const spinner = ora ( {
76
- text : ' Preparing files...\n' ,
82
+ text : " Preparing files...\n" ,
77
83
} ) . start ( ) ;
78
84
79
85
fse . copySync ( templatePath , resolvedProjectPath , {
80
86
recursive : true ,
81
87
} ) ;
82
88
const templatePackageJsonPath = path . resolve (
83
89
resolvedProjectPath ,
84
- ' ./package.json' ,
90
+ " ./package.json" ,
85
91
) ;
86
- const templatePackageJson = fse . readFileSync ( templatePackageJsonPath , ' utf8' ) ;
92
+ const templatePackageJson = fse . readFileSync ( templatePackageJsonPath , " utf8" ) ;
87
93
fse . writeFileSync (
88
94
templatePackageJsonPath ,
89
95
templatePackageJson
90
96
. replace (
91
- ' INSERT_COMPONENTS_VERSION' ,
92
- await getLatestVersionOfTag ( ' @react-email/components' , tag ) ,
97
+ " INSERT_COMPONENTS_VERSION" ,
98
+ await getLatestVersionOfTag ( " @react-email/components" , tag ) ,
93
99
)
94
100
. replace (
95
- ' INSERT_REACT_EMAIL_VERSION' ,
96
- await getLatestVersionOfTag ( ' react-email' , tag ) ,
101
+ " INSERT_REACT_EMAIL_VERSION" ,
102
+ await getLatestVersionOfTag ( " react-email" , tag ) ,
97
103
) ,
98
- ' utf8' ,
104
+ " utf8" ,
99
105
) ;
100
106
101
107
spinner . stopAndPersist ( {
102
108
symbol : logSymbols . success ,
103
- text : ' React Email Starter files ready' ,
109
+ text : " React Email Starter files ready" ,
104
110
} ) ;
105
111
106
112
// eslint-disable-next-line no-console
107
113
console . info (
108
114
await tree ( resolvedProjectPath , 4 , ( dirent ) => {
109
115
return ! path
110
116
. join ( dirent . parentPath , dirent . name )
111
- . includes ( ' node_modules' ) ;
117
+ . includes ( " node_modules" ) ;
112
118
} ) ,
113
119
) ;
114
120
} ;
115
121
116
122
new Command ( )
117
123
. name ( packageJson . name )
118
124
. version ( packageJson . version )
119
- . description ( ' The easiest way to get started with React Email' )
120
- . arguments ( ' [dir]' , ' Path to initialize the project' )
121
- . option ( ' -t, --tag <tag>' , ' Tag of React Email versions to use' , ' latest' )
125
+ . description ( " The easiest way to get started with React Email" )
126
+ . arguments ( " [dir]" , " Path to initialize the project" )
127
+ . option ( " -t, --tag <tag>" , " Tag of React Email versions to use" , " latest" )
122
128
. action ( init )
123
129
. parse ( process . argv ) ;
0 commit comments