-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathindex.js
149 lines (120 loc) · 4.19 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
const fs = require('fs');
const path = require('path');
const package = require(path.resolve('./', 'package.json'));
const { tori } = package;
exports.generate = async function generate(cmds) {
try {
const [componentType, componentPath] = cmds.slice(2);
// If we don't pass in a component type, the first param is the actual path
const typeSetInConfig = tori && tori.hasOwnProperty(componentType);
const actualComponentPath = typeSetInConfig
? safePath(componentPath)
: safePath(componentType);
// The last directory name can be used as the component name
const componentName = actualComponentPath.split('/')[
actualComponentPath.split('/').length - 1
];
// Map tori config to actual paths
const toriPaths = mapToriPaths(tori, componentName);
// Choose the proper path to use for generation based on if the type exists in the config.
// If it doesn't exist, we should use the basePath in config or the current directory instead.
// NOTE: mapToriPaths defaults to creating 'base' path, but it's not guaranteed since tori config might not exist
const realPath = typeSetInConfig
? toriPaths[componentType]
: path.join(toriPaths.base || './', actualComponentPath);
const targetPath = normalizedPath(realPath);
if (!directoryExists(targetPath)) {
createDirectory(targetPath);
}
copyFilesToTarget(targetPath, componentName);
replaceContentWithComponentName(targetPath, componentName);
console.log(`Generated '${componentName}' component in '${targetPath}'`);
} catch (err) {
console.error(err);
return err;
}
};
function mapToriPaths(toriConfig, componentName) {
if (!toriConfig) return {};
try {
const base = normalizedPath(path.resolve('./', safePath(toriConfig.basePath) || ''));
const paths = Object.keys(toriConfig).reduce((object, key) => {
if (key === 'basePath') return object;
const baseDir = toriConfig.basePath ? base : './';
const pathForKey = path.resolve(baseDir, safePath(toriConfig[key]));
return {
...object,
[key]: normalizedPath(path.join(pathForKey, componentName)),
};
}, {});
return {
base,
...paths,
};
} catch (err) {
console.error(err);
return err;
}
}
function normalizedPath(targetPath) {
return path.normalize(path.resolve('./', safePath(targetPath)));
}
function directoryExists(targetPath) {
return fs.existsSync(safePath(targetPath));
}
function createDirectory(targetPath) {
try {
return fs.mkdirSync(safePath(targetPath), { recursive: true });
} catch (err) {
console.error(err);
return err;
}
}
function copyFilesToTarget(targetPath, componentName) {
const templatesPath = path.resolve(__dirname, safePath('./templates'));
try {
fs.readdirSync(templatesPath).forEach((file) => {
const templateNameToComponentName = file.replace('component', componentName);
fs.copyFileSync(
path.join(templatesPath, file),
path.join(safePath(targetPath), templateNameToComponentName)
);
});
} catch (err) {
console.error(err);
return err;
}
}
function replaceContentWithComponentName(targetPath, componentName) {
const safeTargetPath = safePath(targetPath);
try {
fs.readdirSync(safeTargetPath).forEach(function replaceFileContent(file) {
const content = fs.readFileSync(path.join(safeTargetPath, file), {
encoding: 'utf8',
});
const componentNameInPascalCase = toPascalCase(componentName);
const replacedContent = content
.replace(/ComponentName/g, componentNameInPascalCase)
.replace(/[c|C]omponent/g, componentName);
fs.writeFileSync(path.join(safeTargetPath, file), replacedContent);
});
} catch (err) {
console.error(err);
return err;
}
}
function toPascalCase(text) {
return text.replace(/(^\w|-\w)/g, clearAndUpper);
}
function clearAndUpper(text) {
return text.replace(/-/, '').toUpperCase();
}
/**
* Replaces possible /../.. values in paths to avoid working outside the current work dir
*
* @param {string} possiblyUnsafePath
*/
function safePath(possiblyUnsafePath) {
if (!possiblyUnsafePath) return '';
return possiblyUnsafePath.replace('..', '');
}