@digigov/cli-build 2.0.0-daaf7bdf → 2.0.0-e7d30530
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/.prettierrc.cjs +1 -0
- package/.rush/temp/shrinkwrap-deps.json +413 -28
- package/build.js +93 -0
- package/common.js +20 -0
- package/copy-files.js +109 -73
- package/eslint.config.js +3 -0
- package/generate-registry.js +214 -0
- package/index.js +110 -99
- package/package.json +25 -28
- package/tsconfig.base.json +4 -6
- package/tsconfig.json +4 -41
- package/babel.common.js +0 -119
- package/babel.config.js +0 -1
package/common.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
const POSSIBLE_TS_CONFIGS = ['tsconfig.production.json', 'tsconfig.json'];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the tsconfig path for the given project
|
|
8
|
+
*
|
|
9
|
+
* @param {string} projectRoot - The project root
|
|
10
|
+
* @returns {string | undefined} - The tsconfig path or undefined if not found
|
|
11
|
+
*/
|
|
12
|
+
export function getProjectTsconfig(projectRoot) {
|
|
13
|
+
for (const tsconfig of POSSIBLE_TS_CONFIGS) {
|
|
14
|
+
const tsconfigPath = path.join(projectRoot, tsconfig);
|
|
15
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
16
|
+
return tsconfigPath;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return;
|
|
20
|
+
}
|
package/copy-files.js
CHANGED
|
@@ -1,125 +1,161 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const glob = require("glob");
|
|
6
|
-
const { resolveProject } = require("@digigov/cli/lib");
|
|
1
|
+
import { logger, resolveProject } from '@digigov/cli/lib';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import glob from 'globby';
|
|
7
5
|
|
|
8
|
-
const project = resolveProject();
|
|
9
6
|
const packagePath = process.cwd();
|
|
7
|
+
const project = resolveProject();
|
|
10
8
|
const buildPath = path.join(project.root, project.distDir);
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Copy a file from the package to the build directory
|
|
12
|
+
*
|
|
13
|
+
* @param {string} file - The file to include in the build
|
|
14
|
+
*/
|
|
15
|
+
function includeFileInBuild(file) {
|
|
13
16
|
const sourcePath = path.resolve(packagePath, file);
|
|
14
17
|
const targetPath = path.resolve(buildPath, path.basename(file));
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
fs.copySync(sourcePath, targetPath);
|
|
19
|
+
logger.debug(`Copied ${sourcePath} to build directory`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function copyRegistryFilesToSrc() {
|
|
23
|
+
const registryPath = path.resolve(buildPath, 'registry/index.js');
|
|
24
|
+
const lazyPath = path.resolve(buildPath, 'lazy/index.js');
|
|
25
|
+
if (!fs.existsSync(registryPath) || !fs.existsSync(lazyPath)) return;
|
|
26
|
+
|
|
27
|
+
const srcPath = path.resolve(buildPath, 'src');
|
|
28
|
+
logger.debug(`Copying registry and lazy files to ${srcPath}`);
|
|
29
|
+
fs.copySync(registryPath, path.resolve(srcPath, 'registry.js'));
|
|
30
|
+
fs.copySync(lazyPath, path.resolve(srcPath, 'lazy.js'));
|
|
17
31
|
}
|
|
18
32
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Create a package.json file in the build directory
|
|
35
|
+
*/
|
|
36
|
+
function createRootPackageFile() {
|
|
37
|
+
const packageData = fs.readFileSync(
|
|
38
|
+
path.resolve(packagePath, './package.json'),
|
|
39
|
+
'utf8'
|
|
23
40
|
);
|
|
41
|
+
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
24
43
|
const { nyc, scripts, devDependencies, workspaces, ...packageDataOther } =
|
|
25
44
|
JSON.parse(packageData);
|
|
26
45
|
const newPackageData = {
|
|
27
46
|
...packageDataOther,
|
|
28
47
|
private: false,
|
|
29
|
-
main:
|
|
30
|
-
module:
|
|
31
|
-
typings:
|
|
48
|
+
main: './cjs/index.js',
|
|
49
|
+
module: './index.js',
|
|
50
|
+
typings: './index.d.ts',
|
|
32
51
|
};
|
|
33
|
-
const targetPath = path.resolve(buildPath,
|
|
52
|
+
const targetPath = path.resolve(buildPath, './package.json');
|
|
34
53
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
JSON.stringify(newPackageData, null, 2),
|
|
38
|
-
"utf8",
|
|
39
|
-
);
|
|
40
|
-
console.log(`Created package.json in ${targetPath}`);
|
|
54
|
+
fs.writeFileSync(targetPath, JSON.stringify(newPackageData, null, 2), 'utf8');
|
|
55
|
+
logger.debug(`Created package.json in build directory`);
|
|
41
56
|
|
|
42
57
|
return newPackageData;
|
|
43
58
|
}
|
|
44
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Create nested package.json files in the build directory
|
|
62
|
+
*
|
|
63
|
+
*/
|
|
45
64
|
function createNestedPackageFiles() {
|
|
46
|
-
const indexPaths = glob.sync(path.join(buildPath,
|
|
65
|
+
const indexPaths = glob.sync(path.join(buildPath, '**/index.js'), {
|
|
66
|
+
ignore: [path.join(buildPath, 'cjs/**')],
|
|
67
|
+
});
|
|
47
68
|
|
|
48
69
|
indexPaths.forEach((indexPath) => {
|
|
49
|
-
if (indexPath === path.join(buildPath,
|
|
70
|
+
if (indexPath === path.join(buildPath, 'index.js')) return;
|
|
50
71
|
const packageData = {
|
|
51
72
|
sideEffects: false,
|
|
52
|
-
module:
|
|
53
|
-
types:
|
|
73
|
+
module: './index.js',
|
|
74
|
+
types: './index.d.ts',
|
|
54
75
|
main: path.relative(
|
|
55
76
|
path.dirname(indexPath),
|
|
56
|
-
indexPath.replace(buildPath, path.join(buildPath,
|
|
77
|
+
indexPath.replace(buildPath, path.join(buildPath, '/cjs'))
|
|
57
78
|
),
|
|
58
79
|
};
|
|
59
80
|
fs.writeFileSync(
|
|
60
|
-
path.join(path.dirname(indexPath),
|
|
61
|
-
JSON.stringify(packageData, null, 2)
|
|
81
|
+
path.join(path.dirname(indexPath), 'package.json'),
|
|
82
|
+
JSON.stringify(packageData, null, 2)
|
|
62
83
|
);
|
|
63
84
|
});
|
|
64
85
|
}
|
|
65
86
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Prepend a string to a file
|
|
89
|
+
*
|
|
90
|
+
* @param {string} file - The file to prepend to
|
|
91
|
+
* @param {string} string - The string to prepend
|
|
92
|
+
*/
|
|
93
|
+
function prepend(file, string) {
|
|
94
|
+
const data = fs.readFileSync(file, 'utf8');
|
|
95
|
+
fs.writeFileSync(file, string + data, 'utf8');
|
|
96
|
+
logger.debug(`Prepended license to ${file}`);
|
|
69
97
|
}
|
|
70
98
|
|
|
71
|
-
|
|
72
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Add license to the top of the files
|
|
101
|
+
*
|
|
102
|
+
* @param {object} packageData - The package data
|
|
103
|
+
*/
|
|
104
|
+
function addLicense(packageData) {
|
|
105
|
+
const license = `/** @license Digigov v${packageData['version']}
|
|
73
106
|
*
|
|
74
107
|
* This source code is licensed under the BSD-2-Clause license found in the
|
|
75
108
|
* LICENSE file in the root directory of this source tree.
|
|
76
109
|
*/
|
|
77
110
|
`;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
111
|
+
['./index.js', './index.mjs'].map(async (file) => {
|
|
112
|
+
try {
|
|
113
|
+
prepend(path.resolve(buildPath, file), license);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (
|
|
116
|
+
typeof err === 'object' &&
|
|
117
|
+
err &&
|
|
118
|
+
'code' in err &&
|
|
119
|
+
err.code === 'ENOENT'
|
|
120
|
+
) {
|
|
121
|
+
logger.debug(`Skipped license for ${file}`);
|
|
122
|
+
} else {
|
|
123
|
+
throw err;
|
|
88
124
|
}
|
|
89
|
-
}
|
|
90
|
-
);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
91
127
|
}
|
|
92
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Create separate index modules for each directory
|
|
131
|
+
*/
|
|
93
132
|
function createSeparateIndexModules() {
|
|
94
|
-
const files = glob.sync(path.join(buildPath,
|
|
133
|
+
const files = glob.sync(path.join(buildPath, '**/*.js'), {
|
|
134
|
+
ignore: [path.join(buildPath, '**/index.js')],
|
|
135
|
+
});
|
|
95
136
|
|
|
96
137
|
files.forEach((file) => {
|
|
97
|
-
fs.mkdirSync(file.replace(
|
|
98
|
-
fs.renameSync(file, file.replace(
|
|
138
|
+
fs.mkdirSync(file.replace(/\.js$/, ''));
|
|
139
|
+
fs.renameSync(file, file.replace(/\.js$/, '/index.js'));
|
|
99
140
|
});
|
|
100
141
|
}
|
|
101
142
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// use enhanced readme from workspace root for `@digigov/ui`
|
|
111
|
-
// packageData.name === '@digigov/ui' ? '../../README.md' : './README.md',
|
|
112
|
-
"./src",
|
|
113
|
-
"./README.md",
|
|
114
|
-
"./CHANGELOG.md",
|
|
115
|
-
"../../LICENSE",
|
|
116
|
-
].map((file) => includeFileInBuild(file)),
|
|
117
|
-
);
|
|
143
|
+
/**
|
|
144
|
+
* Run the copy files script
|
|
145
|
+
*/
|
|
146
|
+
export default function run() {
|
|
147
|
+
const packageData = createRootPackageFile();
|
|
148
|
+
createSeparateIndexModules();
|
|
149
|
+
createNestedPackageFiles();
|
|
150
|
+
copyRegistryFilesToSrc();
|
|
118
151
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
[
|
|
153
|
+
// use enhanced readme from workspace root for `@digigov/ui`
|
|
154
|
+
// packageData.name === '@digigov/ui' ? '../../README.md' : './README.md',
|
|
155
|
+
'./src',
|
|
156
|
+
'./README.md',
|
|
157
|
+
'./CHANGELOG.md',
|
|
158
|
+
'../../LICENSE',
|
|
159
|
+
].map((file) => includeFileInBuild(file));
|
|
160
|
+
addLicense(packageData);
|
|
123
161
|
}
|
|
124
|
-
|
|
125
|
-
run();
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { logger } from '@digigov/cli/lib';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { SyntaxKind, Project as TsMorphProject } from 'ts-morph';
|
|
5
|
+
import assert from 'assert';
|
|
6
|
+
|
|
7
|
+
import { getProjectTsconfig } from './common.js';
|
|
8
|
+
|
|
9
|
+
/** @typedef {Object} Project - Represents the project to be built
|
|
10
|
+
* @property {string} root - The project root directory
|
|
11
|
+
* @property {string} name - The project name as in package.json
|
|
12
|
+
* @property {string} distDir - The project build directory
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Generate registry file for the given project
|
|
17
|
+
*
|
|
18
|
+
* @param {Project} project - The project object
|
|
19
|
+
* @param {string} [registryFilename="registry.js"] - The name of the registry file
|
|
20
|
+
* @param {string[]} absoluteFilePaths - The absolute paths of the files to include in the registry
|
|
21
|
+
* @returns {Promise<string>} - The path to the generated registry file
|
|
22
|
+
*/
|
|
23
|
+
export async function generateRegistry(
|
|
24
|
+
project,
|
|
25
|
+
absoluteFilePaths,
|
|
26
|
+
registryFilename = 'registry.js'
|
|
27
|
+
) {
|
|
28
|
+
const registryPath = ensureRegistryPath(project, registryFilename);
|
|
29
|
+
|
|
30
|
+
const relativePaths = absoluteFilePaths.map((path) => {
|
|
31
|
+
assert(
|
|
32
|
+
path.startsWith(project.root),
|
|
33
|
+
'Expected path to be in project root'
|
|
34
|
+
);
|
|
35
|
+
return toNodeResolvablePath(
|
|
36
|
+
path.replace(`${project.root}/src/`, `${project.name}/`)
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
let registryPaths = relativePaths.map((path) => ({
|
|
40
|
+
path,
|
|
41
|
+
uid: createUid(path),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
if (registryPaths.length === 0)
|
|
45
|
+
throw new Error(
|
|
46
|
+
'Could not generate registry. No exportable modules found.'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const importStatements = registryPaths.map(
|
|
50
|
+
(file) => `import * as ${file.uid} from "${file.path}";`
|
|
51
|
+
);
|
|
52
|
+
const componentsToExport = registryPaths.map(
|
|
53
|
+
(file) => ` '${file.path}': lazyImport(${file.uid})`
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
logger.debug(
|
|
57
|
+
`Including ${componentsToExport.length} items in ${registryPath}`
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
let registryFileContent = `
|
|
61
|
+
${importStatements.join('\n')}
|
|
62
|
+
function lazyImport(pkgImport) {
|
|
63
|
+
return new Proxy(
|
|
64
|
+
{},
|
|
65
|
+
{
|
|
66
|
+
get: (_target, name) => {
|
|
67
|
+
if (name === '__esModule' || name === 'default') {
|
|
68
|
+
return pkgImport.default;
|
|
69
|
+
} else if(
|
|
70
|
+
name === '*'
|
|
71
|
+
) {
|
|
72
|
+
return pkgImport;
|
|
73
|
+
} else {
|
|
74
|
+
return pkgImport[name];
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
export default {
|
|
81
|
+
${componentsToExport.join(',\n')}
|
|
82
|
+
};
|
|
83
|
+
`;
|
|
84
|
+
await fs.writeFile(registryPath, registryFileContent);
|
|
85
|
+
|
|
86
|
+
return registryPath;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate a lazy registry file for the given project
|
|
91
|
+
*
|
|
92
|
+
* @param {Project} project - The project object
|
|
93
|
+
* @param {string[]} filePaths - The files whose exports will be included in the lazy registry
|
|
94
|
+
* @param {string} [lazyFilename="lazy.js"] - The name of the registry file
|
|
95
|
+
* @returns {Promise<string>} - The path to the generated lazy registry file
|
|
96
|
+
*/
|
|
97
|
+
export async function generateLazyRegistry(
|
|
98
|
+
project,
|
|
99
|
+
filePaths,
|
|
100
|
+
lazyFilename = 'lazy.js'
|
|
101
|
+
) {
|
|
102
|
+
const lazyPath = ensureRegistryPath(project, lazyFilename);
|
|
103
|
+
|
|
104
|
+
const tsMorphProject = new TsMorphProject({
|
|
105
|
+
tsConfigFilePath: getProjectTsconfig(project.root),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/** @type {Record<string, string>} */
|
|
109
|
+
let allComponents = {};
|
|
110
|
+
|
|
111
|
+
for (const filePath of filePaths) {
|
|
112
|
+
const sourceFile = tsMorphProject.addSourceFileAtPath(filePath);
|
|
113
|
+
const exports = sourceFile
|
|
114
|
+
.getExportSymbols()
|
|
115
|
+
.filter(isJsExport)
|
|
116
|
+
.map((symbol) => symbol.getName());
|
|
117
|
+
|
|
118
|
+
for (const exportedComponent of exports) {
|
|
119
|
+
if (
|
|
120
|
+
exportedComponent !== 'default' &&
|
|
121
|
+
exportedComponent.match(/^[A-Z]/)
|
|
122
|
+
) {
|
|
123
|
+
if (
|
|
124
|
+
!allComponents[exportedComponent] ||
|
|
125
|
+
allComponents[exportedComponent].length < filePath.length // Make import path more specific
|
|
126
|
+
) {
|
|
127
|
+
allComponents[exportedComponent] = toNodeResolvablePath(
|
|
128
|
+
filePath.replace(`${project.root}/src/`, `${project.name}/`)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const componentCount = Object.keys(allComponents).length;
|
|
136
|
+
|
|
137
|
+
if (componentCount === 0)
|
|
138
|
+
throw new Error(
|
|
139
|
+
'Could not generate lazy registry. No exportable components found.'
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
logger.debug(`Including ${componentCount} components in ${lazyPath}`);
|
|
143
|
+
|
|
144
|
+
const componentsToExport = Object.entries(allComponents)
|
|
145
|
+
.map(
|
|
146
|
+
([component, filePath]) =>
|
|
147
|
+
` '${component}': lazy(() => import('${filePath}').then((module) => ({ default: module['${component}'] })))`
|
|
148
|
+
)
|
|
149
|
+
.join(',\n');
|
|
150
|
+
|
|
151
|
+
const lazyFileContent = `import { lazy } from 'react';
|
|
152
|
+
export default {
|
|
153
|
+
${componentsToExport}
|
|
154
|
+
};
|
|
155
|
+
`;
|
|
156
|
+
|
|
157
|
+
await fs.writeFile(lazyPath, lazyFileContent);
|
|
158
|
+
|
|
159
|
+
return lazyPath;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Ensure that the registry file does not already exist at the given path
|
|
164
|
+
*
|
|
165
|
+
* @param {Project} project - The project object
|
|
166
|
+
* @param {string} fileName - The name of the registry file
|
|
167
|
+
*/
|
|
168
|
+
function ensureRegistryPath(project, fileName) {
|
|
169
|
+
const registryPath = path.join(project.root, project.distDir, fileName);
|
|
170
|
+
if (fs.existsSync(registryPath))
|
|
171
|
+
throw new Error(`A "${fileName}" file already exists at ${registryPath}.`);
|
|
172
|
+
return registryPath;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Extract a node-resolvable path
|
|
177
|
+
*
|
|
178
|
+
* @param {string} inputPath - The file path
|
|
179
|
+
* @returns {string} - The node-resolvable path
|
|
180
|
+
*/
|
|
181
|
+
function toNodeResolvablePath(inputPath) {
|
|
182
|
+
const dir = path.dirname(inputPath);
|
|
183
|
+
const base = path.basename(inputPath, path.extname(inputPath));
|
|
184
|
+
|
|
185
|
+
return base === 'index' ? dir : path.join(dir, base);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Create a UID from a path
|
|
190
|
+
*
|
|
191
|
+
* @param {string} inputPath - The path
|
|
192
|
+
* @returns {string} - The UID
|
|
193
|
+
*/
|
|
194
|
+
function createUid(inputPath) {
|
|
195
|
+
return inputPath.replace(/[/@\-.]/g, '_');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Check if a symbol is a JS export
|
|
200
|
+
*
|
|
201
|
+
* @param {import("ts-morph").Symbol} symbol - The symbol to check
|
|
202
|
+
*/
|
|
203
|
+
function isJsExport(symbol) {
|
|
204
|
+
const declarations = symbol.getDeclarations();
|
|
205
|
+
return declarations.some((declaration) => {
|
|
206
|
+
const kind = declaration.getKind();
|
|
207
|
+
return (
|
|
208
|
+
kind === SyntaxKind.FunctionDeclaration ||
|
|
209
|
+
kind === SyntaxKind.ClassDeclaration ||
|
|
210
|
+
kind === SyntaxKind.VariableDeclaration ||
|
|
211
|
+
kind === SyntaxKind.ExportSpecifier
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
}
|