-
Notifications
You must be signed in to change notification settings - Fork 181
/
Copy pathaddNamedComponentExports.js
132 lines (107 loc) · 4.33 KB
/
addNamedComponentExports.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
/**
* This script aims to add named exports to index.js file,
* which will persist Vue2 solution to import selected components from the @carbon/vue package
* instead of installing all components
*/
const fs = require('fs');
const path = require('path');
const NEW_LINE_ENTITY = '\n';
const COMPONENTS_PATH = path.join(__dirname, './src/components/');
const FILE_ENCODING = 'utf8';
const INDEX_FILE_PATH = path.join(__dirname, './src/index.js');
const INDEX_EXPORT_MARKER = '// AUTO-GENERATED EXPORTS - DO NOT EDIT BELOW';
/**
* regex from index.js extended by: not starting from underscore
* It matches file names that:
* - do not start from underscore
* - do not contain '.stories.vue', '.test.vue', '.spec.vue' in it
* - ends with .vue extension
*/
const VUE_COMPONENT_FILENAME_REGEX =
/^[^_](?!.*(?:\/_|\.stories\.vue|\.test\.vue|\.spec\.vue)).*\.vue$/;
const NON_CHECK_PATHS = /(?:\/|\\)__test__/;
const FORBIDDEN_COMPONENT_NAME_CHARACTERS_REGEX = /[_-]/g;
let componentsExports = [];
function addNamedComponentExports(dir) {
readFilesFromPath(dir);
let indexFileContent = fs.readFileSync(INDEX_FILE_PATH, FILE_ENCODING);
const exportsContent = componentsExports.join(NEW_LINE_ENTITY);
if (exportsWereAddedToIndex(indexFileContent, exportsContent)) return;
// remove existing exports
const automaticExports = indexFileContent.indexOf(INDEX_EXPORT_MARKER);
if (automaticExports > -1) {
indexFileContent = indexFileContent.substring(
0,
automaticExports + INDEX_EXPORT_MARKER.length + NEW_LINE_ENTITY.length
);
}
const fileContentToSave = indexFileContent + exportsContent + NEW_LINE_ENTITY;
fs.writeFileSync(INDEX_FILE_PATH, fileContentToSave, FILE_ENCODING);
}
function exportsWereAddedToIndex(indexFileContent, exportsContent) {
return indexFileContent.includes(exportsContent);
}
function readFilesFromPath(dirPath) {
const files = fs.readdirSync(dirPath);
files.forEach(itemName => {
const itemPath = path.join(dirPath, itemName);
const itemPathMetaData = fs.statSync(itemPath);
const isDirectory = itemPathMetaData.isDirectory();
// exclude NON_CHECK_PATHS paths to not to lookup for .vue files inside of them
if (NON_CHECK_PATHS.test(itemPath)) return;
if (isDirectory) {
readFilesFromPath(itemPath);
return;
}
if (!isVueComponentFile(itemName)) return;
const { componentExportChunk, exportPathChunk } =
getFileExportStatement(itemPath);
if (
!componentExportChunk ||
!exportPathChunk ||
isComponentExported(componentsExports, componentExportChunk)
) {
return;
}
componentsExports.push(`${componentExportChunk} ${exportPathChunk}`);
});
}
function isVueComponentFile(fileName) {
return VUE_COMPONENT_FILENAME_REGEX.test(fileName);
}
function getFileExportStatement(filePath) {
const fileName = getFileNameWithoutExtension(filePath);
const fileNameFormatted = formatComponentNameForExport(fileName);
const filePathRelativeToIndex = convertToImportPathRelativeToIndex(filePath);
if (!filePathRelativeToIndex || !fileNameFormatted) return '';
const componentExportChunk = `export { default as ${fileNameFormatted} }`;
const exportPathChunk = `from '${filePathRelativeToIndex}';`;
return {
componentExportChunk,
exportPathChunk,
};
}
function getFileNameWithoutExtension(filePath) {
return path.basename(filePath, path.extname(filePath));
}
function formatComponentNameForExport(fileName) {
// remove problematic component names characters
// example 1: CvToggle-Skeleton becomes CvToggleSkeleton
// example 2: _CvAccordionItemSkeleton becomes CvAccordionItemSkeleton
return fileName.replace(FORBIDDEN_COMPONENT_NAME_CHARACTERS_REGEX, '');
}
function convertToImportPathRelativeToIndex(systemPath) {
const indexDir = path.dirname(INDEX_FILE_PATH);
const importPath = './' + path.relative(indexDir, systemPath);
return normalizePathPerSystem(importPath);
}
function normalizePathPerSystem(string) {
// ensure it will always return expected separators in path e.g. './components/CvAccordion/CvAccordion.vue'
return typeof string === 'string' && path.sep === '\\'
? string.replace(/\\/g, '/')
: string;
}
function isComponentExported(componentsExports, componentExportChunk) {
return componentsExports.find(el => el.startsWith(componentExportChunk));
}
addNamedComponentExports(COMPONENTS_PATH);