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

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/build.js CHANGED
@@ -1,9 +1,9 @@
1
- import { DigigovCommand, logger } from "@digigov/cli/lib";
1
+ import { logger } from '@digigov/cli/lib';
2
2
 
3
- import assert from "assert";
4
- import path from "path";
5
- import fs from "fs-extra";
6
- import baseEsbuild from "esbuild";
3
+ import assert from 'assert';
4
+ import path from 'path';
5
+ import fs from 'fs-extra';
6
+ import baseEsbuild from 'esbuild';
7
7
 
8
8
  /**
9
9
  * Generate TypeScript declaration files
@@ -13,24 +13,24 @@ import baseEsbuild from "esbuild";
13
13
  * @param {string} project.src - The project source directory
14
14
  * @param {string} project.distDir - The project build directory
15
15
  * @param {string} tsconfig - The tsconfig path
16
- * @param {DigigovCommand} ctx - The command context
16
+ * @param {import("@digigov/cli/lib").DigigovCommand} ctx - The command context
17
17
  */
18
18
  export async function generateTypeDeclarationFiles(project, tsconfig, ctx) {
19
- logger.debug("Building types...");
19
+ logger.debug('Building types...');
20
20
 
21
21
  const distDir = path.resolve(project.root, project.distDir);
22
22
  const projectBasename = path.basename(project.root);
23
23
 
24
- await ctx.exec("tsc", [
25
- "--emitDeclarationOnly",
26
- "--outDir",
27
- "dist",
28
- "--project",
24
+ await ctx.exec('tsc', [
25
+ '--emitDeclarationOnly',
26
+ '--outDir',
27
+ 'dist',
28
+ '--project',
29
29
  tsconfig,
30
30
  ]);
31
31
 
32
32
  const projectBasePath = path.join(distDir, projectBasename);
33
- logger.debug("Project base path", projectBasePath);
33
+ logger.debug('Project base path', projectBasePath);
34
34
  if (await fs.exists(projectBasePath)) {
35
35
  const typesIncluded = await fs.readdir(path.join(distDir));
36
36
  const srcPath = path.join(distDir, projectBasename, project.src);
@@ -39,19 +39,19 @@ export async function generateTypeDeclarationFiles(project, tsconfig, ctx) {
39
39
  await Promise.all([
40
40
  // Move src files to dist
41
41
  ...paths.map((p) => {
42
- logger.debug("Moving types file", p);
42
+ logger.debug('Moving types file', p);
43
43
  fs.move(path.join(srcPath, p), path.join(distDir, p));
44
44
  }),
45
45
  // Remove dirs
46
46
  ...typesIncluded.map((typesDir) => {
47
- logger.debug("Removing types directory", typesDir);
47
+ logger.debug('Removing types directory', typesDir);
48
48
  fs.rm(path.join(distDir, typesDir), { recursive: true });
49
49
  }),
50
50
  ]).catch((err) => {
51
- logger.error("Error while building types", err);
51
+ logger.error('Error while building types', err);
52
52
  });
53
53
  }
54
- logger.debug("Types built.");
54
+ logger.debug('Types built.');
55
55
  }
56
56
 
57
57
  /**
@@ -62,11 +62,19 @@ export async function generateTypeDeclarationFiles(project, tsconfig, ctx) {
62
62
  * @param {string | undefined} options.tsconfig - The tsconfig path
63
63
  * @param {"esm" | "cjs"} options.format - The module format
64
64
  * @param {string} options.outdir - The output directory
65
+ * @param {boolean | undefined} [options.noLogs] - Whether to log debug information
65
66
  */
66
- export function buildFormat({ files: entryPoints, tsconfig, format, outdir }) {
67
- assert(format === "esm" || format === "cjs", "Invalid format");
67
+ export function buildFormat({
68
+ files: entryPoints,
69
+ tsconfig,
70
+ format,
71
+ outdir,
72
+ noLogs,
73
+ }) {
74
+ assert(format === 'esm' || format === 'cjs', 'Invalid format');
68
75
 
69
- logger.log(`Running: esbuild for ${format.toUpperCase()} format`);
76
+ if (!noLogs)
77
+ logger.log(`Running: esbuild for ${format.toUpperCase()} format`);
70
78
  return baseEsbuild.build({
71
79
  ...BASE_OPTIONS,
72
80
  entryPoints,
@@ -78,8 +86,8 @@ export function buildFormat({ files: entryPoints, tsconfig, format, outdir }) {
78
86
 
79
87
  /** @type {baseEsbuild.BuildOptions} */
80
88
  export const BASE_OPTIONS = {
81
- logLevel: "error",
82
- platform: "node",
89
+ logLevel: 'error',
90
+ platform: 'node',
83
91
  sourcemap: true,
84
- target: ["esnext"],
92
+ target: ['esnext'],
85
93
  };
package/common.js CHANGED
@@ -1,7 +1,7 @@
1
- import fs from "fs-extra";
2
- import path from "path";
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
3
 
4
- const POSSIBLE_TS_CONFIGS = ["tsconfig.production.json", "tsconfig.json"];
4
+ const POSSIBLE_TS_CONFIGS = ['tsconfig.production.json', 'tsconfig.json'];
5
5
 
6
6
  /**
7
7
  * Get the tsconfig path for the given project
package/copy-files.js CHANGED
@@ -1,7 +1,7 @@
1
- import { logger, resolveProject } from "@digigov/cli/lib";
2
- import fs from "fs-extra";
3
- import path from "path";
4
- import glob from "globby";
1
+ import { logger, resolveProject } from '@digigov/cli/lib';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import glob from 'globby';
5
5
 
6
6
  const packagePath = process.cwd();
7
7
  const project = resolveProject();
@@ -20,14 +20,14 @@ function includeFileInBuild(file) {
20
20
  }
21
21
 
22
22
  function copyRegistryFilesToSrc() {
23
- const registryPath = path.resolve(buildPath, "registry/index.js");
24
- const lazyPath = path.resolve(buildPath, "lazy/index.js");
23
+ const registryPath = path.resolve(buildPath, 'registry/index.js');
24
+ const lazyPath = path.resolve(buildPath, 'lazy/index.js');
25
25
  if (!fs.existsSync(registryPath) || !fs.existsSync(lazyPath)) return;
26
26
 
27
- const srcPath = path.resolve(buildPath, "src");
27
+ const srcPath = path.resolve(buildPath, 'src');
28
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"));
29
+ fs.copySync(registryPath, path.resolve(srcPath, 'registry.js'));
30
+ fs.copySync(lazyPath, path.resolve(srcPath, 'lazy.js'));
31
31
  }
32
32
 
33
33
  /**
@@ -35,21 +35,23 @@ function copyRegistryFilesToSrc() {
35
35
  */
36
36
  function createRootPackageFile() {
37
37
  const packageData = fs.readFileSync(
38
- path.resolve(packagePath, "./package.json"),
39
- "utf8",
38
+ path.resolve(packagePath, './package.json'),
39
+ 'utf8'
40
40
  );
41
+
42
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
41
43
  const { nyc, scripts, devDependencies, workspaces, ...packageDataOther } =
42
44
  JSON.parse(packageData);
43
45
  const newPackageData = {
44
46
  ...packageDataOther,
45
47
  private: false,
46
- main: "./cjs/index.js",
47
- module: "./index.js",
48
- typings: "./index.d.ts",
48
+ main: './cjs/index.js',
49
+ module: './index.js',
50
+ typings: './index.d.ts',
49
51
  };
50
- const targetPath = path.resolve(buildPath, "./package.json");
52
+ const targetPath = path.resolve(buildPath, './package.json');
51
53
 
52
- fs.writeFileSync(targetPath, JSON.stringify(newPackageData, null, 2), "utf8");
54
+ fs.writeFileSync(targetPath, JSON.stringify(newPackageData, null, 2), 'utf8');
53
55
  logger.debug(`Created package.json in build directory`);
54
56
 
55
57
  return newPackageData;
@@ -60,24 +62,24 @@ function createRootPackageFile() {
60
62
  *
61
63
  */
62
64
  function createNestedPackageFiles() {
63
- const indexPaths = glob.sync(path.join(buildPath, "**/index.js"), {
64
- ignore: [path.join(buildPath, "cjs/**")],
65
+ const indexPaths = glob.sync(path.join(buildPath, '**/index.js'), {
66
+ ignore: [path.join(buildPath, 'cjs/**')],
65
67
  });
66
68
 
67
69
  indexPaths.forEach((indexPath) => {
68
- if (indexPath === path.join(buildPath, "index.js")) return;
70
+ if (indexPath === path.join(buildPath, 'index.js')) return;
69
71
  const packageData = {
70
72
  sideEffects: false,
71
- module: "./index.js",
72
- types: "./index.d.ts",
73
+ module: './index.js',
74
+ types: './index.d.ts',
73
75
  main: path.relative(
74
76
  path.dirname(indexPath),
75
- indexPath.replace(buildPath, path.join(buildPath, "/cjs")),
77
+ indexPath.replace(buildPath, path.join(buildPath, '/cjs'))
76
78
  ),
77
79
  };
78
80
  fs.writeFileSync(
79
- path.join(path.dirname(indexPath), "package.json"),
80
- JSON.stringify(packageData, null, 2),
81
+ path.join(path.dirname(indexPath), 'package.json'),
82
+ JSON.stringify(packageData, null, 2)
81
83
  );
82
84
  });
83
85
  }
@@ -89,8 +91,8 @@ function createNestedPackageFiles() {
89
91
  * @param {string} string - The string to prepend
90
92
  */
91
93
  function prepend(file, string) {
92
- const data = fs.readFileSync(file, "utf8");
93
- fs.writeFileSync(file, string + data, "utf8");
94
+ const data = fs.readFileSync(file, 'utf8');
95
+ fs.writeFileSync(file, string + data, 'utf8');
94
96
  logger.debug(`Prepended license to ${file}`);
95
97
  }
96
98
 
@@ -100,21 +102,21 @@ function prepend(file, string) {
100
102
  * @param {object} packageData - The package data
101
103
  */
102
104
  function addLicense(packageData) {
103
- const license = `/** @license Digigov v${packageData["version"]}
105
+ const license = `/** @license Digigov v${packageData['version']}
104
106
  *
105
107
  * This source code is licensed under the BSD-2-Clause license found in the
106
108
  * LICENSE file in the root directory of this source tree.
107
109
  */
108
110
  `;
109
- ["./index.js", "./index.mjs"].map(async (file) => {
111
+ ['./index.js', './index.mjs'].map(async (file) => {
110
112
  try {
111
113
  prepend(path.resolve(buildPath, file), license);
112
114
  } catch (err) {
113
115
  if (
114
- typeof err === "object" &&
116
+ typeof err === 'object' &&
115
117
  err &&
116
- "code" in err &&
117
- err.code === "ENOENT"
118
+ 'code' in err &&
119
+ err.code === 'ENOENT'
118
120
  ) {
119
121
  logger.debug(`Skipped license for ${file}`);
120
122
  } else {
@@ -128,13 +130,13 @@ function addLicense(packageData) {
128
130
  * Create separate index modules for each directory
129
131
  */
130
132
  function createSeparateIndexModules() {
131
- const files = glob.sync(path.join(buildPath, "**/*.js"), {
132
- ignore: [path.join(buildPath, "**/index.js")],
133
+ const files = glob.sync(path.join(buildPath, '**/*.js'), {
134
+ ignore: [path.join(buildPath, '**/index.js')],
133
135
  });
134
136
 
135
137
  files.forEach((file) => {
136
- fs.mkdirSync(file.replace(/\.js$/, ""));
137
- fs.renameSync(file, file.replace(/\.js$/, "/index.js"));
138
+ fs.mkdirSync(file.replace(/\.js$/, ''));
139
+ fs.renameSync(file, file.replace(/\.js$/, '/index.js'));
138
140
  });
139
141
  }
140
142
 
@@ -150,10 +152,10 @@ export default function run() {
150
152
  [
151
153
  // use enhanced readme from workspace root for `@digigov/ui`
152
154
  // 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);
155
+ './src',
156
+ './README.md',
157
+ './CHANGELOG.md',
158
+ '../../LICENSE',
159
+ ].map((file) => includeFileInBuild(file));
160
+ addLicense(packageData);
159
161
  }
@@ -0,0 +1,3 @@
1
+ import config from '@digigov/cli-lint/eslint.config';
2
+
3
+ export default [...config];
@@ -1,86 +1,39 @@
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
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
19
13
  */
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
14
 
47
15
  /**
48
- * Ensure that the registry file does not already exist at the given path
16
+ * Generate registry file for the given project
49
17
  *
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
18
+ * @param {Project} project - The project object
19
+ * @param {string} [registryFilename="registry.js"] - The name of the registry file
68
20
  * @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
21
+ * @returns {Promise<string>} - The path to the generated registry file
71
22
  */
72
- export function generateRegistryFileContent(
23
+ export async function generateRegistry(
73
24
  project,
74
25
  absoluteFilePaths,
75
- includeStories = false,
26
+ registryFilename = 'registry.js'
76
27
  ) {
28
+ const registryPath = ensureRegistryPath(project, registryFilename);
29
+
77
30
  const relativePaths = absoluteFilePaths.map((path) => {
78
31
  assert(
79
32
  path.startsWith(project.root),
80
- "Expected path to be in project root",
33
+ 'Expected path to be in project root'
81
34
  );
82
35
  return toNodeResolvablePath(
83
- path.replace(`${project.root}/src/`, `${project.name}/`),
36
+ path.replace(`${project.root}/src/`, `${project.name}/`)
84
37
  );
85
38
  });
86
39
  let registryPaths = relativePaths.map((path) => ({
@@ -90,25 +43,22 @@ export function generateRegistryFileContent(
90
43
 
91
44
  if (registryPaths.length === 0)
92
45
  throw new Error(
93
- "Could not generate registry. No exportable modules found.",
46
+ 'Could not generate registry. No exportable modules found.'
94
47
  );
95
48
 
96
49
  const importStatements = registryPaths.map(
97
- (file) => `import * as ${file.uid} from "${file.path}";`,
50
+ (file) => `import * as ${file.uid} from "${file.path}";`
98
51
  );
99
- const exportStatements = registryPaths.map(
100
- (file) => ` '${file.path}': lazyImport(${file.uid})`,
52
+ const componentsToExport = registryPaths.map(
53
+ (file) => ` '${file.path}': lazyImport(${file.uid})`
101
54
  );
102
55
 
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
- }
56
+ logger.debug(
57
+ `Including ${componentsToExport.length} items in ${registryPath}`
58
+ );
109
59
 
110
- let out = `
111
- ${importStatements.join("\n")}
60
+ let registryFileContent = `
61
+ ${importStatements.join('\n')}
112
62
  function lazyImport(pkgImport) {
113
63
  return new Proxy(
114
64
  {},
@@ -128,73 +78,29 @@ function lazyImport(pkgImport) {
128
78
  )
129
79
  }
130
80
  export default {
131
- ${components.join(",\n")}
132
- };
133
- `;
134
-
135
- if (includeStories) {
136
- out += `
137
-
138
- export const stories = {
139
- ${stories.join(",\n")}
81
+ ${componentsToExport.join(',\n')}
140
82
  };
141
83
  `;
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
- }
84
+ await fs.writeFile(registryPath, registryFileContent);
168
85
 
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];
86
+ return registryPath;
186
87
  }
187
88
 
188
89
  /**
189
- * Generate lazy component registry file content for the given project
90
+ * Generate a lazy registry file for the given project
190
91
  *
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
92
+ * @param {Project} project - The project object
194
93
  * @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
94
+ * @param {string} [lazyFilename="lazy.js"] - The name of the registry file
95
+ * @returns {Promise<string>} - The path to the generated lazy registry file
196
96
  */
197
- export function generateLazyFileContent(project, filePaths) {
97
+ export async function generateLazyRegistry(
98
+ project,
99
+ filePaths,
100
+ lazyFilename = 'lazy.js'
101
+ ) {
102
+ const lazyPath = ensureRegistryPath(project, lazyFilename);
103
+
198
104
  const tsMorphProject = new TsMorphProject({
199
105
  tsConfigFilePath: getProjectTsconfig(project.root),
200
106
  });
@@ -211,7 +117,7 @@ export function generateLazyFileContent(project, filePaths) {
211
117
 
212
118
  for (const exportedComponent of exports) {
213
119
  if (
214
- exportedComponent !== "default" &&
120
+ exportedComponent !== 'default' &&
215
121
  exportedComponent.match(/^[A-Z]/)
216
122
  ) {
217
123
  if (
@@ -219,7 +125,7 @@ export function generateLazyFileContent(project, filePaths) {
219
125
  allComponents[exportedComponent].length < filePath.length // Make import path more specific
220
126
  ) {
221
127
  allComponents[exportedComponent] = toNodeResolvablePath(
222
- filePath.replace(`${project.root}/src/`, `${project.name}/`),
128
+ filePath.replace(`${project.root}/src/`, `${project.name}/`)
223
129
  );
224
130
  }
225
131
  }
@@ -230,23 +136,63 @@ export function generateLazyFileContent(project, filePaths) {
230
136
 
231
137
  if (componentCount === 0)
232
138
  throw new Error(
233
- "Could not generate lazy registry. No exportable components found.",
139
+ 'Could not generate lazy registry. No exportable components found.'
234
140
  );
235
141
 
236
- logger.debug(`Including ${componentCount} components in lazy registry`);
142
+ logger.debug(`Including ${componentCount} components in ${lazyPath}`);
237
143
 
238
- const content = Object.entries(allComponents)
144
+ const componentsToExport = Object.entries(allComponents)
239
145
  .map(
240
146
  ([component, filePath]) =>
241
- ` '${component}': lazy(() => import('${filePath}').then((module) => ({ default: module['${component}'] })))`,
147
+ ` '${component}': lazy(() => import('${filePath}').then((module) => ({ default: module['${component}'] })))`
242
148
  )
243
- .join(",\n");
149
+ .join(',\n');
244
150
 
245
- return `import { lazy } from 'react';
151
+ const lazyFileContent = `import { lazy } from 'react';
246
152
  export default {
247
- ${content}
153
+ ${componentsToExport}
248
154
  };
249
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, '_');
250
196
  }
251
197
 
252
198
  /**