@digigov/cli-build 2.0.0-b4cd6916 → 2.0.0-d0adc9fb

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.
@@ -1,16 +1,17 @@
1
1
  {
2
- "../../tooling/cli-build": "../../tooling/cli-build:qTUBqXD27dl7fc7zPWxUDuD2EUBBs/CeE75+ZZm39l4=:",
3
- "/@babel/cli@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
2
+ "../../tooling/cli-build": "../../tooling/cli-build:02YjlK6+1qui1+paVKGwEISZBfTmSHa5jCm7uK5t+7I=:",
3
+ "/@babel/cli@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
4
4
  "/@babel/compat-data@7.12.5": "Missing shrinkwrap entry!",
5
- "/@babel/core@7.12.13": "Missing shrinkwrap entry!",
5
+ "/@babel/core@7.26.0": "Missing shrinkwrap entry!",
6
6
  "/@babel/helper-validator-identifier@7.9.5": "Missing shrinkwrap entry!",
7
- "/@babel/plugin-proposal-class-properties@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
8
- "/@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
9
- "/@babel/plugin-transform-object-assign@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
10
- "/@babel/plugin-transform-runtime@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
11
- "/@babel/preset-env@7.12.13(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
12
- "/@babel/preset-react@7.12.13(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
13
- "/@babel/preset-typescript@7.12.1(@babel/core@7.12.13)": "Missing shrinkwrap entry!",
7
+ "/@babel/plugin-proposal-class-properties@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
8
+ "/@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
9
+ "/@babel/plugin-transform-object-assign@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
10
+ "/@babel/plugin-transform-runtime@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
11
+ "/@babel/preset-env@7.12.13(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
12
+ "/@babel/preset-react@7.12.13(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
13
+ "/@babel/preset-typescript@7.12.1(@babel/core@7.26.0)": "Missing shrinkwrap entry!",
14
+ "/@types/fs-extra@11.0.4": "Missing shrinkwrap entry!",
14
15
  "/@types/node@18.19.0": "Missing shrinkwrap entry!",
15
16
  "/babel-plugin-inline-import-data-uri@1.0.1": "Missing shrinkwrap entry!",
16
17
  "/babel-plugin-istanbul@7.0.0": "Missing shrinkwrap entry!",
@@ -20,11 +21,14 @@
20
21
  "/babel-plugin-transform-dev-warning@0.1.1": "Missing shrinkwrap entry!",
21
22
  "/babel-plugin-transform-react-constant-elements@6.23.0": "Missing shrinkwrap entry!",
22
23
  "/babel-plugin-transform-react-remove-prop-types@0.4.24": "Missing shrinkwrap entry!",
24
+ "/commander@12.1.0": "Missing shrinkwrap entry!",
23
25
  "/esbuild@0.23.0": "Missing shrinkwrap entry!",
24
26
  "/fs-extra@11.2.0": "Missing shrinkwrap entry!",
25
- "/glob@7.1.6": "Missing shrinkwrap entry!",
26
- "/next@13.1.1(@babel/core@7.12.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": "Missing shrinkwrap entry!",
27
+ "/globby@11.0.0": "Missing shrinkwrap entry!",
28
+ "/next@13.1.1(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)": "Missing shrinkwrap entry!",
27
29
  "/publint@0.1.8": "Missing shrinkwrap entry!",
28
30
  "/rimraf@3.0.2": "Missing shrinkwrap entry!",
29
- "/typescript@5.6.2": "Missing shrinkwrap entry!"
31
+ "/ts-morph@25.0.0": "Missing shrinkwrap entry!",
32
+ "/typescript@5.6.2": "Missing shrinkwrap entry!",
33
+ "/vitest@2.1.3(@types/node@18.19.0)(happy-dom@15.11.0)(jsdom@20.0.3)(lightningcss@1.22.0)(sass-embedded@1.81.0)(terser@5.33.0)": "Missing shrinkwrap entry!"
30
34
  }
@@ -4,7 +4,7 @@ const lib = require("@digigov/cli/lib");
4
4
 
5
5
  function makeBabelConfig(dir, opts = { docs: false, proptypes: false }) {
6
6
  const project = lib.resolveProject(dir);
7
- const aliases = !project.externalLockFile ? lib.aliases(null, true) : {};
7
+ const aliases = !project.externalLockFile ? lib.aliases(true) : {};
8
8
 
9
9
  const BABEL_ENV = process.env.BABEL_ENV || "esm";
10
10
  const BABEL_PUBLISH = process.env.BABEL_PUBLISH || false;
@@ -0,0 +1 @@
1
+ module.exports = require("./babel.common.cjs").config;
package/build.js ADDED
@@ -0,0 +1,85 @@
1
+ import { DigigovCommand, logger } from "@digigov/cli/lib";
2
+
3
+ import assert from "assert";
4
+ import path from "path";
5
+ import fs from "fs-extra";
6
+ import baseEsbuild from "esbuild";
7
+
8
+ /**
9
+ * Generate TypeScript declaration files
10
+ *
11
+ * @param {object} project - The project object
12
+ * @param {string} project.root - The project root directory
13
+ * @param {string} project.src - The project source directory
14
+ * @param {string} project.distDir - The project build directory
15
+ * @param {string} tsconfig - The tsconfig path
16
+ * @param {DigigovCommand} ctx - The command context
17
+ */
18
+ export async function generateTypeDeclarationFiles(project, tsconfig, ctx) {
19
+ logger.debug("Building types...");
20
+
21
+ const distDir = path.resolve(project.root, project.distDir);
22
+ const projectBasename = path.basename(project.root);
23
+
24
+ await ctx.exec("tsc", [
25
+ "--emitDeclarationOnly",
26
+ "--outDir",
27
+ "dist",
28
+ "--project",
29
+ tsconfig,
30
+ ]);
31
+
32
+ const projectBasePath = path.join(distDir, projectBasename);
33
+ logger.debug("Project base path", projectBasePath);
34
+ if (await fs.exists(projectBasePath)) {
35
+ const typesIncluded = await fs.readdir(path.join(distDir));
36
+ const srcPath = path.join(distDir, projectBasename, project.src);
37
+ const paths = await fs.readdir(srcPath);
38
+
39
+ await Promise.all([
40
+ // Move src files to dist
41
+ ...paths.map((p) => {
42
+ logger.debug("Moving types file", p);
43
+ fs.move(path.join(srcPath, p), path.join(distDir, p));
44
+ }),
45
+ // Remove dirs
46
+ ...typesIncluded.map((typesDir) => {
47
+ logger.debug("Removing types directory", typesDir);
48
+ fs.rm(path.join(distDir, typesDir), { recursive: true });
49
+ }),
50
+ ]).catch((err) => {
51
+ logger.error("Error while building types", err);
52
+ });
53
+ }
54
+ logger.debug("Types built.");
55
+ }
56
+
57
+ /**
58
+ * Run esbuild for the given options
59
+ *
60
+ * @param {object} options - The build options
61
+ * @param {string[]} options.files - The files to build
62
+ * @param {string | undefined} options.tsconfig - The tsconfig path
63
+ * @param {"esm" | "cjs"} options.format - The module format
64
+ * @param {string} options.outdir - The output directory
65
+ */
66
+ export function buildFormat({ files: entryPoints, tsconfig, format, outdir }) {
67
+ assert(format === "esm" || format === "cjs", "Invalid format");
68
+
69
+ logger.log(`Running: esbuild for ${format.toUpperCase()} format`);
70
+ return baseEsbuild.build({
71
+ ...BASE_OPTIONS,
72
+ entryPoints,
73
+ tsconfig,
74
+ format,
75
+ outdir,
76
+ });
77
+ }
78
+
79
+ /** @type {baseEsbuild.BuildOptions} */
80
+ export const BASE_OPTIONS = {
81
+ logLevel: "error",
82
+ platform: "node",
83
+ sourcemap: true,
84
+ target: ["esnext"],
85
+ };
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,23 +1,40 @@
1
- /* eslint-disable no-console */
2
- const path = require("path");
3
- const fs = require("fs");
4
- const fse = require("fs-extra");
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
- async function includeFileInBuild(file) {
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
- await fse.copy(sourcePath, targetPath);
16
- console.log(`Copied ${sourcePath} to ${targetPath}`);
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
- async function createRootPackageFile() {
20
- const packageData = await fse.readFile(
33
+ /**
34
+ * Create a package.json file in the build directory
35
+ */
36
+ function createRootPackageFile() {
37
+ const packageData = fs.readFileSync(
21
38
  path.resolve(packagePath, "./package.json"),
22
39
  "utf8",
23
40
  );
@@ -32,18 +49,20 @@ async function createRootPackageFile() {
32
49
  };
33
50
  const targetPath = path.resolve(buildPath, "./package.json");
34
51
 
35
- await fse.writeFile(
36
- targetPath,
37
- JSON.stringify(newPackageData, null, 2),
38
- "utf8",
39
- );
40
- console.log(`Created package.json in ${targetPath}`);
52
+ fs.writeFileSync(targetPath, JSON.stringify(newPackageData, null, 2), "utf8");
53
+ logger.debug(`Created package.json in build directory`);
41
54
 
42
55
  return newPackageData;
43
56
  }
44
57
 
58
+ /**
59
+ * Create nested package.json files in the build directory
60
+ *
61
+ */
45
62
  function createNestedPackageFiles() {
46
- const indexPaths = glob.sync(path.join(buildPath, "!(cjs)/**/index.js"));
63
+ const indexPaths = glob.sync(path.join(buildPath, "**/index.js"), {
64
+ ignore: [path.join(buildPath, "cjs/**")],
65
+ });
47
66
 
48
67
  indexPaths.forEach((indexPath) => {
49
68
  if (indexPath === path.join(buildPath, "index.js")) return;
@@ -63,63 +82,78 @@ function createNestedPackageFiles() {
63
82
  });
64
83
  }
65
84
 
66
- async function prepend(file, string) {
67
- const data = await fse.readFile(file, "utf8");
68
- await fse.writeFile(file, string + data, "utf8");
85
+ /**
86
+ * Prepend a string to a file
87
+ *
88
+ * @param {string} file - The file to prepend to
89
+ * @param {string} string - The string to prepend
90
+ */
91
+ function prepend(file, string) {
92
+ const data = fs.readFileSync(file, "utf8");
93
+ fs.writeFileSync(file, string + data, "utf8");
94
+ logger.debug(`Prepended license to ${file}`);
69
95
  }
70
96
 
71
- async function addLicense(packageData) {
72
- const license = `/** @license Digigov v${packageData.version}
97
+ /**
98
+ * Add license to the top of the files
99
+ *
100
+ * @param {object} packageData - The package data
101
+ */
102
+ function addLicense(packageData) {
103
+ const license = `/** @license Digigov v${packageData["version"]}
73
104
  *
74
105
  * This source code is licensed under the BSD-2-Clause license found in the
75
106
  * LICENSE file in the root directory of this source tree.
76
107
  */
77
108
  `;
78
- await Promise.all(
79
- ["./index.js", "./index.mjs"].map(async (file) => {
80
- try {
81
- await prepend(path.resolve(buildPath, file), license);
82
- } catch (err) {
83
- if (err.code === "ENOENT") {
84
- console.log(`Skipped license for ${file}`);
85
- } else {
86
- throw err;
87
- }
109
+ ["./index.js", "./index.mjs"].map(async (file) => {
110
+ try {
111
+ prepend(path.resolve(buildPath, file), license);
112
+ } catch (err) {
113
+ if (
114
+ typeof err === "object" &&
115
+ err &&
116
+ "code" in err &&
117
+ err.code === "ENOENT"
118
+ ) {
119
+ logger.debug(`Skipped license for ${file}`);
120
+ } else {
121
+ throw err;
88
122
  }
89
- }),
90
- );
123
+ }
124
+ });
91
125
  }
92
126
 
127
+ /**
128
+ * Create separate index modules for each directory
129
+ */
93
130
  function createSeparateIndexModules() {
94
- const files = glob.sync(path.join(buildPath, "**/!(index).js"));
131
+ const files = glob.sync(path.join(buildPath, "**/*.js"), {
132
+ ignore: [path.join(buildPath, "**/index.js")],
133
+ });
95
134
 
96
135
  files.forEach((file) => {
97
- fs.mkdirSync(file.replace(".js", ""));
98
- fs.renameSync(file, file.replace(".js", "/index.js"));
136
+ fs.mkdirSync(file.replace(/\.js$/, ""));
137
+ fs.renameSync(file, file.replace(/\.js$/, "/index.js"));
99
138
  });
100
139
  }
101
140
 
102
- async function run() {
103
- try {
104
- const packageData = await createRootPackageFile();
105
- createSeparateIndexModules();
106
- createNestedPackageFiles();
107
-
108
- await Promise.all(
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
- );
141
+ /**
142
+ * Run the copy files script
143
+ */
144
+ export default function run() {
145
+ const packageData = createRootPackageFile();
146
+ createSeparateIndexModules();
147
+ createNestedPackageFiles();
148
+ copyRegistryFilesToSrc();
118
149
 
119
- await addLicense(packageData);
120
- } catch (err) {
121
- console.error(err);
122
- }
150
+ [
151
+ // use enhanced readme from workspace root for `@digigov/ui`
152
+ // packageData.name === '@digigov/ui' ? '../../README.md' : './README.md',
153
+ "./src",
154
+ "./README.md",
155
+ "./CHANGELOG.md",
156
+ "../../LICENSE",
157
+ ].map((file) => includeFileInBuild(file)),
158
+ addLicense(packageData);
123
159
  }
124
-
125
- run();
@@ -0,0 +1,268 @@
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
+ /**
10
+ * Generate registry files for the given project
11
+ *
12
+ * @param {object} project - The project object
13
+ * @param {string} project.root - The project root directory
14
+ * @param {string} project.distDir - The project build directory
15
+ * @param {string} project.name - The project name as in package.json
16
+ * @param {string[]} filePaths - The paths of the files to include in the registry
17
+ * @param {boolean} shouldGenerateStoriesRegistry - Whether to export stories in the registry
18
+ * @returns {Promise<[string, string]>} - The paths of the generated registry files
19
+ */
20
+ export async function generateRegistryFiles(
21
+ project,
22
+ filePaths,
23
+ shouldGenerateStoriesRegistry = false,
24
+ ) {
25
+ const registryPath = ensureRegistryPath(project, "registry.js");
26
+ const lazyRegistryPath = ensureRegistryPath(project, "lazy.js");
27
+
28
+ const registry = generateRegistryFileContent(
29
+ project,
30
+ filePaths,
31
+ shouldGenerateStoriesRegistry,
32
+ );
33
+
34
+ const componentPathsOnly = filePaths.filter(
35
+ (path) => !path.includes("stories"),
36
+ );
37
+ const lazyRegistry = generateLazyFileContent(project, componentPathsOnly);
38
+
39
+ await Promise.all([
40
+ fs.writeFile(registryPath, registry),
41
+ fs.writeFile(lazyRegistryPath, lazyRegistry),
42
+ ]);
43
+
44
+ return [registryPath, lazyRegistryPath];
45
+ }
46
+
47
+ /**
48
+ * Ensure that the registry file does not already exist at the given path
49
+ *
50
+ * @param {object} project - The project object
51
+ * @param {string} project.root - The project root directory
52
+ * @param {string} project.distDir - The project build directory
53
+ * @param {string} fileName - The name of the registry file
54
+ */
55
+ function ensureRegistryPath(project, fileName) {
56
+ const registryPath = path.join(project.root, project.distDir, fileName);
57
+ if (fs.existsSync(registryPath))
58
+ throw new Error(`A "${fileName}" file already exists at ${registryPath}.`);
59
+ return registryPath;
60
+ }
61
+
62
+ /**
63
+ * Generate registry file content for the given files
64
+ *
65
+ * @param {object} project - The project object
66
+ * @param {string} project.root - The project root directory
67
+ * @param {string} project.name - The project name as in package.json
68
+ * @param {string[]} absoluteFilePaths - The absolute paths of the files to include in the registry
69
+ * @param {boolean} includeStories - Whether to include stories in the registry
70
+ * @returns {string} - The registry file content or null if no components are found
71
+ */
72
+ export function generateRegistryFileContent(
73
+ project,
74
+ absoluteFilePaths,
75
+ includeStories = false,
76
+ ) {
77
+ const relativePaths = absoluteFilePaths.map((path) => {
78
+ assert(
79
+ path.startsWith(project.root),
80
+ "Expected path to be in project root",
81
+ );
82
+ return toNodeResolvablePath(
83
+ path.replace(`${project.root}/src/`, `${project.name}/`),
84
+ );
85
+ });
86
+ let registryPaths = relativePaths.map((path) => ({
87
+ path,
88
+ uid: createUid(path),
89
+ }));
90
+
91
+ if (registryPaths.length === 0)
92
+ throw new Error(
93
+ "Could not generate registry. No exportable modules found.",
94
+ );
95
+
96
+ const importStatements = registryPaths.map(
97
+ (file) => `import * as ${file.uid} from "${file.path}";`,
98
+ );
99
+ const exportStatements = registryPaths.map(
100
+ (file) => ` '${file.path}': lazyImport(${file.uid})`,
101
+ );
102
+
103
+ const [components, stories] = splitStoriesExports(exportStatements);
104
+ logger.debug(`Including ${components.length} component modules in registry`);
105
+
106
+ if (includeStories) {
107
+ logger.debug(`Including ${stories.length} stories in registry`);
108
+ }
109
+
110
+ let out = `
111
+ ${importStatements.join("\n")}
112
+ function lazyImport(pkgImport) {
113
+ return new Proxy(
114
+ {},
115
+ {
116
+ get: (_target, name) => {
117
+ if (name === '__esModule' || name === 'default') {
118
+ return pkgImport.default;
119
+ } else if(
120
+ name === '*'
121
+ ) {
122
+ return pkgImport;
123
+ } else {
124
+ return pkgImport[name];
125
+ }
126
+ },
127
+ }
128
+ )
129
+ }
130
+ export default {
131
+ ${components.join(",\n")}
132
+ };
133
+ `;
134
+
135
+ if (includeStories) {
136
+ out += `
137
+
138
+ export const stories = {
139
+ ${stories.join(",\n")}
140
+ };
141
+ `;
142
+ }
143
+ return out;
144
+ }
145
+
146
+ /**
147
+ * Extract a node-resolvable path
148
+ *
149
+ * @param {string} inputPath - The file path
150
+ * @returns {string} - The node-resolvable path
151
+ */
152
+ export function toNodeResolvablePath(inputPath) {
153
+ const dir = path.dirname(inputPath);
154
+ const base = path.basename(inputPath, path.extname(inputPath));
155
+
156
+ return base === "index" ? dir : path.join(dir, base);
157
+ }
158
+
159
+ /**
160
+ * Create a UID from a path
161
+ *
162
+ * @param {string} inputPath - The path
163
+ * @returns {string} - The UID
164
+ */
165
+ export function createUid(inputPath) {
166
+ return inputPath.replace(/[\/@\-.]/g, "_");
167
+ }
168
+
169
+ /**
170
+ * Split the given files into components and stories
171
+ *
172
+ * @param {string[]} exportStatements - The export statements
173
+ * @returns {[string[], string[]]} - The split components and stories exports
174
+ */
175
+ export function splitStoriesExports(exportStatements) {
176
+ const stories = [];
177
+ const components = [];
178
+ for (const exportStatement of exportStatements) {
179
+ if (exportStatement.includes("_stories")) {
180
+ stories.push(exportStatement);
181
+ } else {
182
+ components.push(exportStatement);
183
+ }
184
+ }
185
+ return [components, stories];
186
+ }
187
+
188
+ /**
189
+ * Generate lazy component registry file content for the given project
190
+ *
191
+ * @param {object} project - The project object
192
+ * @param {string} project.root - The project root directory
193
+ * @param {string} project.name - The project name as in package.json
194
+ * @param {string[]} filePaths - The files whose exports will be included in the lazy registry
195
+ * @returns {string} - The lazy component registry file content or null if no components are found
196
+ */
197
+ export function generateLazyFileContent(project, filePaths) {
198
+ const tsMorphProject = new TsMorphProject({
199
+ tsConfigFilePath: getProjectTsconfig(project.root),
200
+ });
201
+
202
+ /** @type {Record<string, string>} */
203
+ let allComponents = {};
204
+
205
+ for (const filePath of filePaths) {
206
+ const sourceFile = tsMorphProject.addSourceFileAtPath(filePath);
207
+ const exports = sourceFile
208
+ .getExportSymbols()
209
+ .filter(isJsExport)
210
+ .map((symbol) => symbol.getName());
211
+
212
+ for (const exportedComponent of exports) {
213
+ if (
214
+ exportedComponent !== "default" &&
215
+ exportedComponent.match(/^[A-Z]/)
216
+ ) {
217
+ if (
218
+ !allComponents[exportedComponent] ||
219
+ allComponents[exportedComponent].length < filePath.length // Make import path more specific
220
+ ) {
221
+ allComponents[exportedComponent] = toNodeResolvablePath(
222
+ filePath.replace(`${project.root}/src/`, `${project.name}/`),
223
+ );
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ const componentCount = Object.keys(allComponents).length;
230
+
231
+ if (componentCount === 0)
232
+ throw new Error(
233
+ "Could not generate lazy registry. No exportable components found.",
234
+ );
235
+
236
+ logger.debug(`Including ${componentCount} components in lazy registry`);
237
+
238
+ const content = Object.entries(allComponents)
239
+ .map(
240
+ ([component, filePath]) =>
241
+ ` '${component}': lazy(() => import('${filePath}').then((module) => ({ default: module['${component}'] })))`,
242
+ )
243
+ .join(",\n");
244
+
245
+ return `import { lazy } from 'react';
246
+ export default {
247
+ ${content}
248
+ };
249
+ `;
250
+ }
251
+
252
+ /**
253
+ * Check if a symbol is a JS export
254
+ *
255
+ * @param {import("ts-morph").Symbol} symbol - The symbol to check
256
+ */
257
+ function isJsExport(symbol) {
258
+ const declarations = symbol.getDeclarations();
259
+ return declarations.some((declaration) => {
260
+ const kind = declaration.getKind();
261
+ return (
262
+ kind === SyntaxKind.FunctionDeclaration ||
263
+ kind === SyntaxKind.ClassDeclaration ||
264
+ kind === SyntaxKind.VariableDeclaration ||
265
+ kind === SyntaxKind.ExportSpecifier
266
+ );
267
+ });
268
+ }
package/index.js CHANGED
@@ -1,107 +1,106 @@
1
- const { Command } = require("@oclif/command");
2
- const execa = require("execa");
3
- const { resolveProject, DigigovCommand } = require("@digigov/cli/lib");
4
- const path = require("path");
5
- const fs = require("fs");
6
- const esbuild = require("esbuild");
7
- const glob = require("glob");
1
+ import { DigigovCommand, resolveProject, logger } from "@digigov/cli/lib";
2
+ import { buildFormat, generateTypeDeclarationFiles } from "./build.js";
3
+ import { generateRegistryFiles } from "./generate-registry.js";
4
+ import copyFiles from "./copy-files.js";
8
5
 
9
- module.exports = class Build extends DigigovCommand {
10
- static description = "build digigov libraries";
11
- static id = "build";
12
- dirname = __dirname;
13
- static examples = [`$ digigov build`];
14
- static strict = false;
15
- static load() {
16
- return Build;
17
- }
18
- script = "babel";
19
- async run() {
20
- const { argv } = this.parse(Build);
21
- try {
22
- await this.exec("rimraf", ["dist"]);
23
- const project = resolveProject();
24
- const babelArgs = [
25
- "--config-file",
26
- path.join(__dirname, "babel.config.js"),
27
- project.src,
28
- "--extensions",
29
- ".tsx,.ts,.js,.jsx",
30
- "--copy-files",
31
- "--out-dir",
32
- ];
33
- const distDir = path.resolve(project.root, project.distDir);
34
- const basename = path.basename(project.root);
6
+ import { Option } from "commander";
7
+ import path from "path";
8
+ import glob from "globby";
9
+ import assert from "assert";
10
+ import { getProjectTsconfig } from "./common.js";
11
+
12
+ const command = new DigigovCommand("build", import.meta.url)
13
+ .option(
14
+ "--generate-registry",
15
+ "Generate a registry file for the build output",
16
+ )
17
+ .addOption(
18
+ new Option("--include-stories", "Include stories in the output").implies({
19
+ generateRegistry: true,
20
+ }),
21
+ )
22
+ .action(main);
23
+ export default command;
24
+
25
+ const SRC_GLOB = "src/**/*.{tsx,ts,js,jsx}";
26
+ const TEST_GLOBS = [
27
+ "**/*.test.{js,jsx,ts,tsx}",
28
+ "**/*.spec.{js,jsx,ts,tsx}",
29
+ "**/__tests__/**/*.{js,jsx,ts,tsx}",
30
+ ];
31
+ const STORIES_GLOBS = [
32
+ "**/*.stories.{js,jsx,ts,tsx}",
33
+ "**/__stories__/**/*.{js,jsxts,tsx}",
34
+ ];
35
+
36
+ /**
37
+ * @param {object} options - The command options
38
+ * @param {boolean} options.generateRegistry - Generate a registry file for the build output
39
+ * @param {boolean} options.includeStories - Include stories in the generated registry file
40
+ * @param {DigigovCommand} ctx
41
+ */
42
+ async function main(options, ctx) {
43
+ const project = resolveProject();
35
44
 
36
- if (project.isTs) {
37
- const tsconfigProduction = path.join(
38
- project.root,
39
- "tsconfig.production.json",
40
- );
41
- const tsArgs = [];
42
- if (fs.existsSync(tsconfigProduction)) {
43
- tsArgs.push("--project", tsconfigProduction);
44
- }
45
- await this.exec("tsc", [
46
- "--emitDeclarationOnly",
47
- "--outDir",
48
- "dist",
49
- ...tsArgs,
50
- ]);
51
- if (fs.existsSync(path.join(distDir, basename))) {
52
- const typesIncluded = fs.readdirSync(path.join(distDir));
53
- const paths = fs.readdirSync(
54
- path.join(distDir, basename, project.src),
55
- );
56
- paths.forEach((p) => {
57
- fs.renameSync(
58
- path.join(distDir, basename, project.src, p),
59
- path.join(distDir, p),
60
- );
61
- });
62
- typesIncluded.forEach((typesDir) => {
63
- fs.rmSync(path.join(distDir, typesDir), { recursive: true });
64
- });
65
- }
66
- }
45
+ await ctx.exec("rimraf", [project.distDir]);
67
46
 
68
- const files = glob.sync(
69
- path.join(project.root, "src", "**/*.{tsx,ts,js,jsx}"),
70
- {
71
- ignore: "**/*.{spec,test}.{ts,tsx,js,jsx}",
72
- },
73
- );
74
- const commonBuildOptions = {
75
- entryPoints: files,
76
- platform: "node",
77
- sourcemap: true,
78
- target: ["esnext"],
79
- logLevel: "error",
80
- };
81
- if (fs.existsSync(path.join(project.root, "tsconfig.production.json"))) {
82
- commonBuildOptions["tsconfig"] = "tsconfig.production.json";
83
- } else if (fs.existsSync(path.join(project.root, "tsconfig.json"))) {
84
- commonBuildOptions["tsconfig"] = "tsconfig.json";
85
- }
47
+ /**
48
+ * The project tsconfig, or undefined if the project is not using TypeScript
49
+ * @type {string | undefined}
50
+ */
51
+ let tsconfig;
52
+ if (project.isTs) {
53
+ tsconfig = getProjectTsconfig(project.root);
54
+ assert(tsconfig, "Expected tsconfig to be in project");
55
+ await generateTypeDeclarationFiles(project, tsconfig, ctx);
56
+ }
57
+
58
+ const ignore = [...TEST_GLOBS];
59
+ if (options.includeStories) {
60
+ logger.debug("Including stories in the build");
61
+ } else {
62
+ ignore.push(...STORIES_GLOBS);
63
+ }
64
+ const filesToBuild = await glob(path.join(project.root, SRC_GLOB), {
65
+ ignore,
66
+ });
67
+ logger.debug("Bundling ESM and CJS...");
68
+ await Promise.all([
69
+ buildFormat({
70
+ files: filesToBuild,
71
+ tsconfig: tsconfig,
72
+ format: "cjs",
73
+ outdir: project.distDir + "/cjs",
74
+ }),
75
+ buildFormat({
76
+ files: filesToBuild,
77
+ tsconfig,
78
+ format: "esm",
79
+ outdir: project.distDir,
80
+ }),
81
+ ]);
82
+ logger.debug("Bundling done.");
86
83
 
87
- await Promise.all([
88
- esbuild.build({
89
- ...commonBuildOptions,
90
- format: "esm",
91
- outdir: `dist`,
92
- }),
93
- esbuild.build({
94
- ...commonBuildOptions,
95
- format: "cjs",
96
- outdir: `dist/cjs`,
97
- }),
98
- ]);
99
- await execa("node", [path.join(__dirname, "copy-files.js")], {
100
- env: {},
101
- stdio: "inherit",
102
- });
103
- } catch (err) {
104
- console.error(err);
105
- }
84
+ if (options.generateRegistry) {
85
+ const registryFiles = filesToBuild.filter(
86
+ (file) => !(file.includes("native") || file.endsWith(".d.ts")),
87
+ );
88
+ logger.debug("Generating registry files...");
89
+ const registryFilePaths = await generateRegistryFiles(
90
+ project,
91
+ registryFiles,
92
+ options.includeStories,
93
+ );
94
+ await buildFormat({
95
+ files: registryFilePaths,
96
+ tsconfig: tsconfig,
97
+ format: "cjs",
98
+ outdir: project.distDir + "/cjs",
99
+ });
100
+ logger.log("Generated registry files");
106
101
  }
107
- };
102
+
103
+ logger.debug("Copying files to build directory...");
104
+ copyFiles();
105
+ logger.debug("Files copied.");
106
+ }
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@digigov/cli-build",
3
- "version": "2.0.0-b4cd6916",
3
+ "version": "2.0.0-d0adc9fb",
4
4
  "description": "Build plugin for Digigov CLI",
5
5
  "main": "./index.js",
6
+ "type": "module",
6
7
  "author": "GRNET Devs <devs@lists.grnet.gr>",
7
8
  "license": "BSD-2-Clause",
8
9
  "private": false,
9
10
  "dependencies": {
10
11
  "@babel/cli": "7.12.1",
11
12
  "@babel/compat-data": "7.12.5",
12
- "@babel/core": "7.12.13",
13
+ "@babel/core": "7.26.0",
13
14
  "@babel/helper-validator-identifier": "7.9.5",
14
15
  "@babel/plugin-proposal-class-properties": "7.12.1",
15
16
  "@babel/plugin-proposal-object-rest-spread": "7.12.1",
@@ -26,22 +27,31 @@
26
27
  "babel-plugin-transform-react-constant-elements": "6.23.0",
27
28
  "babel-plugin-transform-react-remove-prop-types": "0.4.24",
28
29
  "fs-extra": "11.2.0",
29
- "glob": "7.1.6",
30
- "typescript": "5.6.2",
31
- "@types/node": "18.19.0",
30
+ "globby": "11.0.0",
32
31
  "babel-plugin-istanbul": "7.0.0",
33
32
  "publint": "0.1.8",
33
+ "rimraf": "3.0.2",
34
34
  "esbuild": "0.23.0",
35
- "@digigov/babel-ts-to-proptypes": "1.1.0"
35
+ "commander": "12.1.0",
36
+ "ts-morph": "25.0.0"
36
37
  },
37
38
  "devDependencies": {
38
- "publint": "0.1.8"
39
+ "publint": "0.1.8",
40
+ "vitest": "2.1.3",
41
+ "@digigov/cli-test": "2.0.0-d0adc9fb",
42
+ "@types/fs-extra": "11.0.4",
43
+ "@types/node": "18.19.0",
44
+ "typescript": "5.6.2"
39
45
  },
40
46
  "peerDependencies": {
41
- "@digigov/cli": "1.1.2-b4cd6916",
42
- "rimraf": "3.0.2",
47
+ "@digigov/cli": "2.0.0-d0adc9fb",
43
48
  "next": "13.1.1"
44
49
  },
50
+ "peerDependenciesMeta": {
51
+ "next": {
52
+ "optional": true
53
+ }
54
+ },
45
55
  "scripts": {
46
56
  "publint": "publint"
47
57
  }
@@ -12,9 +12,6 @@
12
12
  "@digigov/auth/*": ["./auth/src/*"],
13
13
  "@digigov/auth/": ["./auth/src"],
14
14
  "@digigov/auth": ["./auth/src"],
15
- "@digigov/benchmark/*": ["./benchmark/src/*"],
16
- "@digigov/benchmark/": ["./benchmark/src"],
17
- "@digigov/benchmark": ["./benchmark/src"],
18
15
  "@digigov/text-search/*": ["./text-search/src/*"],
19
16
  "@digigov/text-search/": ["./text-search/src"],
20
17
  "@digigov/text-search": ["./text-search/src"],
@@ -36,14 +33,15 @@
36
33
  "@digigov/react-experimental/*": ["../libs-ui/react-experimental/src/*"],
37
34
  "@digigov/react-experimental/": ["../libs-ui/react-experimental/src"],
38
35
  "@digigov/react-experimental": ["../libs-ui/react-experimental/src"],
39
- "@digigov/storybook/*": ["../examples/storybook/stories/*"]
36
+ "@digigov/storybook/*": ["../examples/storybook/stories/*"],
37
+ "@uides/stepwise/*": ["./stepwise/src/*"],
38
+ "@uides/stepwise/": ["./stepwise/src"],
39
+ "@uides/stepwise": ["./stepwise/src"]
40
40
  }
41
41
  },
42
42
  "include": [
43
43
  "../../libs/auth/src/**/*.tsx",
44
44
  "../../libs/auth/src/*.tsx",
45
- "../../libs/benchmark/src/**/*.tsx",
46
- "../../libs/benchmark/src/*.tsx",
47
45
  "../../libs/text-search/src/**/*.tsx",
48
46
  "../../libs/text-search/src/*.tsx",
49
47
  "../../libs/text-search/src/**/*.ts",
package/tsconfig.json CHANGED
@@ -1,45 +1,12 @@
1
1
  {
2
- "extends": "./tsconfig.base.json",
2
+ "extends": "@digigov/cli/tsconfig.cli",
3
3
  "compilerOptions": {
4
4
  "types": [
5
- "node"
6
- ],
7
- "outDir": "dist",
8
- "paths": {
9
- "@digigov/babel-ts-to-proptypes": [
10
- "node_modules/@digigov/babel-ts-to-proptypes/src"
11
- ],
12
- "@digigov/babel-ts-to-proptypes/": [
13
- "node_modules/@digigov/babel-ts-to-proptypes/src/"
14
- ],
15
- "@digigov/babel-ts-to-proptypes/*": [
16
- "node_modules/@digigov/babel-ts-to-proptypes/src/*"
17
- ],
18
- "@digigov/cli": [
19
- "node_modules/@digigov/cli/src"
20
- ],
21
- "@digigov/cli/": [
22
- "node_modules/@digigov/cli/src/"
23
- ],
24
- "@digigov/cli/*": [
25
- "node_modules/@digigov/cli/src/*"
26
- ],
27
- "@digigov/cli-build": [
28
- "./src"
29
- ],
30
- "@digigov/cli-build/": [
31
- "./src/"
32
- ],
33
- "@digigov/cli-build/*": [
34
- "./src/*"
35
- ]
36
- },
37
- "baseUrl": "./"
5
+ "vitest/globals"
6
+ ]
38
7
  },
39
8
  "include": [
40
- "index.js"
41
- ],
42
- "exclude": [
43
- "node_modules"
9
+ "./*.js",
10
+ "__tests__"
44
11
  ]
45
12
  }
package/babel.config.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./babel.common').config