@modern-js/utils 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @modern-js/utils
2
2
 
3
+ ## 1.2.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 83166714: change .npmignore
8
+
3
9
  ## 1.2.1
4
10
 
5
11
  ### Patch Changes
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.2.1",
14
+ "version": "1.2.2",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -1,181 +0,0 @@
1
- /* eslint-disable eslint-comments/no-unlimited-disable */
2
- /* eslint-disable */
3
- /**
4
- * Copyright (c) 2015-present, Facebook, Inc.
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file at
8
- * https://github.com/facebook/create-react-app/blob/master/LICENSE
9
- */
10
-
11
- // Modified by Chao Xu (xuchaobei)
12
- 'use strict';
13
-
14
- import fs from 'fs';
15
- import path from 'path';
16
- import chalk from 'chalk';
17
- import filesize from 'filesize';
18
- import recursive from 'recursive-readdir';
19
- import stripAnsi from 'strip-ansi';
20
- import gzipSize from 'gzip-size';
21
- import { logger } from './logger';
22
-
23
-
24
- function canReadAsset(asset:string) {
25
- return (
26
- /\.(js|css)$/.test(asset) &&
27
- !/service-worker\.js/.test(asset) &&
28
- !/precache-manifest\.[0-9a-f]+\.js/.test(asset)
29
- );
30
- }
31
-
32
- // Prints a detailed summary of build files.
33
- function printFileSizesAfterBuild(
34
- webpackStats:any,
35
- previousSizeMap:{root:string, sizes:Record<string, number[]>},
36
- buildFolder:string,
37
- maxBundleGzipSize:number,
38
- maxChunkGzipSize:number
39
- ) {
40
- var root = previousSizeMap.root;
41
- var sizes = previousSizeMap.sizes;
42
- var assets = (webpackStats.stats || [webpackStats])
43
- .map((stats:any) =>
44
- stats
45
- .toJson({ all: false, assets: true })
46
- .assets.filter((asset:any) => canReadAsset(asset.name))
47
- .map((asset:any) => {
48
- var fileContents = fs.readFileSync(path.join(root, asset.name));
49
- var size = fileContents.length;
50
- var gzippedSize = gzipSize.sync(fileContents);
51
- var [previousSize, previousGzipSize] = sizes[removeFileNameHash(root, asset.name)] || [];
52
- var sizeDifference = getDifferenceLabel(size, previousSize);
53
- var gzipSizeDifference = getDifferenceLabel(gzippedSize, previousGzipSize);
54
- return {
55
- folder: path.join(
56
- path.basename(buildFolder),
57
- path.dirname(asset.name)
58
- ),
59
- name: path.basename(asset.name),
60
- gzippedSize: gzippedSize,
61
- sizeLabel: filesize(size) + (sizeDifference ? ' (' + sizeDifference + ')' : ''),
62
- gzipSizeLabel: filesize(gzippedSize) + (gzipSizeDifference ? ' (' + gzipSizeDifference + ')' : ''),
63
- };
64
- })
65
- )
66
- .reduce((single:any, all:any) => all.concat(single), []);
67
- assets.sort((a:any, b:any) => b.size - a.size);
68
- var longestSizeLabelLength = Math.max.apply(
69
- null,
70
- assets.map((a:any) => stripAnsi(a.sizeLabel).length)
71
- );
72
- var longestFileNameLength = Math.max.apply(
73
- null,
74
- assets.map((a:any) => stripAnsi(a.folder + path.sep + a.name).length)
75
- );
76
-
77
- printFileSizesHeader(longestFileNameLength, longestSizeLabelLength);
78
-
79
- var suggestBundleSplitting = false;
80
- assets.forEach((asset:any) => {
81
- var {folder, name, sizeLabel, gzipSizeLabel, gzippedSize} = asset;
82
- var fileNameLength = stripAnsi(folder + path.sep + name).length;
83
- var sizeLength = stripAnsi(sizeLabel).length;
84
- if (sizeLength < longestSizeLabelLength) {
85
- var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
86
- sizeLabel += rightPadding;
87
- }
88
- var fileNameLabel = chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name);
89
- if (fileNameLength < longestFileNameLength) {
90
- var rightPadding = ' '.repeat(longestFileNameLength - fileNameLength);
91
- fileNameLabel += rightPadding;
92
- }
93
- var isMainBundle = asset.name.indexOf('main.') === 0;
94
- var maxRecommendedSize = isMainBundle
95
- ? maxBundleGzipSize
96
- : maxChunkGzipSize;
97
- var isLarge = maxRecommendedSize && gzippedSize > maxRecommendedSize;
98
- if (isLarge && path.extname(asset.name) === '.js') {
99
- suggestBundleSplitting = true;
100
- }
101
- logger.log(
102
- ' ' + fileNameLabel +
103
- ' ' + sizeLabel +
104
- ' ' + (isLarge ? chalk.yellow(gzipSizeLabel) : gzipSizeLabel)
105
- );
106
- });
107
- if (suggestBundleSplitting) {
108
- logger.log();
109
- logger.warn(
110
- 'The bundle size is significantly larger than recommended.'
111
- );
112
- }
113
- }
114
-
115
- function printFileSizesHeader(longestFileNameLength:number, longestSizeLabelLength:number){
116
- const longestLengths = [longestFileNameLength, longestSizeLabelLength]
117
- const headerRow = ['File', 'Size', 'Gzipped'].reduce((prev, cur, index) => {
118
- const length = longestLengths[index];
119
- let curLabel = cur;
120
- if(length){
121
- curLabel = cur.length < length ? cur + ' '.repeat(length - cur.length) : cur;
122
- }
123
- return prev + curLabel + ' ';
124
- }, ' ')
125
-
126
- logger.log(chalk.bold(chalk.blue(headerRow)))
127
- }
128
-
129
- function removeFileNameHash(buildFolder:string, fileName:string) {
130
- return fileName
131
- .replace(buildFolder, '')
132
- .replace(/\\/g, '/')
133
- .replace(
134
- /\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/,
135
- (match, p1, p2, p3, p4) => p1 + p4
136
- );
137
- }
138
-
139
- // Input: 1024, 2048
140
- // Output: "(+1 KB)"
141
- function getDifferenceLabel(currentSize:number, previousSize:number) {
142
- var FIFTY_KILOBYTES = 1024 * 50;
143
- var difference = currentSize - previousSize;
144
- var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
145
- if (difference >= FIFTY_KILOBYTES) {
146
- return chalk.red('+' + fileSize);
147
- } else if (difference < FIFTY_KILOBYTES && difference > 0) {
148
- return chalk.yellow('+' + fileSize);
149
- } else if (difference < 0) {
150
- return chalk.green(fileSize);
151
- } else {
152
- return '';
153
- }
154
- }
155
-
156
- function measureFileSizesBeforeBuild(buildFolder:string):Promise<{root:string; sizes: Record<string, number[]>}> {
157
- return new Promise(resolve => {
158
- recursive(buildFolder, (err, fileNames) => {
159
- var sizes;
160
- if (!err && fileNames) {
161
- sizes = fileNames.filter(canReadAsset).reduce<Record<string, [number,number]>>((memo, fileName) => {
162
- var contents = fs.readFileSync(fileName);
163
- var key = removeFileNameHash(buildFolder, fileName);
164
- // save both the original size and gzip size
165
- memo[key] = [contents.length, gzipSize.sync(contents)]
166
- return memo;
167
- }, {});
168
- }
169
- resolve({
170
- root: buildFolder,
171
- sizes: sizes || {},
172
- });
173
- });
174
- });
175
- }
176
-
177
- export {
178
- measureFileSizesBeforeBuild,
179
- printFileSizesAfterBuild,
180
- };
181
- /* eslint-enable */
package/src/alias.ts DELETED
@@ -1,90 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import chalk from 'chalk';
4
- import { readTsConfigByFile } from './readTsConfig';
5
- import { applyOptionsChain } from './applyOptionsChain';
6
-
7
- type AliasOption =
8
- | Record<string, string>
9
- | ((aliases: Record<string, string>) => Record<string, unknown>)
10
- | Record<string, string>
11
- | undefined;
12
-
13
- interface NormalizedConfig {
14
- source: {
15
- alias?: AliasOption | Array<AliasOption>;
16
- };
17
- }
18
-
19
- interface IAliasConfig {
20
- absoluteBaseUrl: string;
21
- paths?: Record<string, string | string[]>;
22
- isTsPath?: boolean;
23
- isTsProject?: boolean;
24
- }
25
-
26
- export const validAlias = <T extends NormalizedConfig>(
27
- modernConfig: T,
28
- { tsconfigPath }: { tsconfigPath: string },
29
- ) => {
30
- const {
31
- source: { alias },
32
- } = modernConfig;
33
- if (!alias) {
34
- return null;
35
- }
36
-
37
- const isTsProject = fs.existsSync(tsconfigPath);
38
- if (!isTsProject) {
39
- return null;
40
- }
41
-
42
- const userAlias = getUserAlias(alias as Record<string, string>);
43
- if (Object.keys(userAlias).length > 0) {
44
- return chalk.red(
45
- 'Note: Please use `compilerOptions.paths` in "tsconfig.json" file replace `source.alias` config in "modern.config.js/ts" when project is typescript',
46
- );
47
- }
48
-
49
- return null;
50
- };
51
-
52
- export const getAlias = (
53
- aliasOption: AliasOption | Array<AliasOption>,
54
- option: { appDirectory: string; tsconfigPath: string },
55
- ) => {
56
- const isTsProject = fs.existsSync(option.tsconfigPath);
57
- let aliasConfig: IAliasConfig;
58
- if (!isTsProject) {
59
- aliasConfig = {
60
- absoluteBaseUrl: option.appDirectory,
61
- paths: applyOptionsChain({ '@': ['./src'] }, aliasOption as any),
62
- isTsPath: false,
63
- isTsProject,
64
- };
65
- } else {
66
- const tsconfig = readTsConfigByFile(option.tsconfigPath);
67
- const baseUrl = tsconfig?.compilerOptions?.baseUrl;
68
- aliasConfig = {
69
- absoluteBaseUrl: baseUrl
70
- ? path.join(option.appDirectory, baseUrl)
71
- : option.appDirectory,
72
- paths: {
73
- ...(aliasOption || {}),
74
- ...tsconfig?.compilerOptions?.paths,
75
- },
76
- isTsPath: true,
77
- isTsProject,
78
- };
79
- }
80
- return aliasConfig;
81
- };
82
-
83
- // filter invalid ts paths that are not array
84
- export const getUserAlias = (alias: Record<string, string | string[]> = {}) =>
85
- Object.keys(alias).reduce((o, k) => {
86
- if (Array.isArray(alias[k])) {
87
- o[k] = alias[k];
88
- }
89
- return o;
90
- }, {} as Record<string, string | string[]>);
@@ -1,44 +0,0 @@
1
- // eslint-disable-next-line import/no-useless-path-segments
2
- import { isFunction, logger, isPlainObject } from './index';
3
-
4
- export const applyOptionsChain = <T, U>(
5
- defaults: T,
6
- /* eslint-disable @typescript-eslint/no-invalid-void-type */
7
- options?:
8
- | T
9
- | ((config: T, utils?: U) => T | void)
10
- | Array<T | ((config: T, utils?: U) => T | void)>,
11
- /* eslint-enable @typescript-eslint/no-invalid-void-type */
12
- utils?: U,
13
- mergeFn = Object.assign,
14
- ): T => {
15
- if (!options) {
16
- return defaults;
17
- }
18
-
19
- if (isPlainObject(options) as any) {
20
- return mergeFn(defaults, options);
21
- } else if (isFunction(options)) {
22
- const ret = options(defaults, utils);
23
- if (ret) {
24
- if (!isPlainObject(ret)) {
25
- logger.warn(
26
- `${options.name}: Function should mutate the config and return nothing, Or return a cloned or merged version of config object.`,
27
- );
28
- }
29
- return ret;
30
- }
31
- } else if (Array.isArray(options)) {
32
- return options.reduce<T>(
33
- (memo, cur) => applyOptionsChain(memo, cur, utils, mergeFn),
34
- defaults,
35
- );
36
- } else {
37
- throw new Error(
38
- `applyOptionsChain error:\ndefault options is: ${JSON.stringify(
39
- defaults,
40
- )}`,
41
- );
42
- }
43
- return defaults;
44
- };
package/src/chalk.ts DELETED
@@ -1,3 +0,0 @@
1
- import chalk from 'chalk';
2
-
3
- export { chalk };
@@ -1,5 +0,0 @@
1
- export const clearConsole = () => {
2
- if (process.stdout.isTTY) {
3
- process.stdout.write('\x1B[H\x1B[2J');
4
- }
5
- };
@@ -1,25 +0,0 @@
1
- import { findExists } from './findExists';
2
-
3
- /**
4
- * Require function compatible with esm and cjs module.
5
- * @param filePath - File to required.
6
- * @returns module export object.
7
- */
8
- export const compatRequire = (filePath: string) => {
9
- const mod = require(filePath);
10
-
11
- return mod?.__esModule ? mod.default : mod;
12
- };
13
-
14
- export const requireExistModule = (
15
- filename: string,
16
- extensions = ['.ts', '.js'],
17
- ) => {
18
- const exist = findExists(extensions.map(ext => `${filename}${ext}`));
19
-
20
- if (!exist) {
21
- return null;
22
- }
23
-
24
- return compatRequire(exist);
25
- };
package/src/constants.ts DELETED
@@ -1,265 +0,0 @@
1
- /**
2
- * alias to src directory
3
- */
4
- export const INTERNAL_SRC_ALIAS = '@_modern_js_src';
5
-
6
- /**
7
- * alias to node_modules/.modern-js
8
- */
9
- export const INTERNAL_DIR_ALAIS = '@_modern_js_internal';
10
-
11
- /**
12
- * hmr socket connect path
13
- */
14
- export const HMR_SOCK_PATH = '/_modern_js_hmr_ws';
15
-
16
- /**
17
- * route specification file
18
- */
19
- export const ROUTE_SPEC_FILE = 'route.json';
20
-
21
- /**
22
- * main entry name
23
- */
24
- export const MAIN_ENTRY_NAME = 'main';
25
-
26
- /**
27
- * open editor request path
28
- */
29
- export const LAUNCH_EDITOR_ENDPOINT = '/__open-stack-frame-in-editor';
30
-
31
- /**
32
- * server side bundles directory, which relative to dist.
33
- */
34
- export const SERVER_BUNDLE_DIRECTORY = 'bundles';
35
-
36
- /**
37
- * entry name pattern used for ajv pattern properties.
38
- */
39
- export const ENTRY_NAME_PATTERN = '^[a-zA-Z0-9_-]+$';
40
-
41
- /**
42
- * SSR server render function name
43
- */
44
- export const SERVER_RENDER_FUNCTION_NAME = 'serverRender';
45
-
46
- /**
47
- * loadbale manifest json file
48
- */
49
- export const LOADABLE_STATS_FILE = 'loadable-stats.json';
50
-
51
- /**
52
- * real entry generate by modern.js
53
- */
54
- export const HIDE_MODERN_JS_DIR = './node_modules/.modern-js';
55
-
56
- /**
57
- * internal specified folder
58
- */
59
- export const API_DIR = 'api';
60
-
61
- export const SERVER_DIR = 'server';
62
-
63
- export const SHARED_DIR = 'shared';
64
-
65
- /**
66
- * Internal plugins that work as soon as they are installed.
67
- */
68
- export const INTERNAL_PLUGINS: {
69
- [name: string]: { cli?: string; server?: string };
70
- } = {
71
- '@modern-js/app-tools': { cli: '@modern-js/app-tools/cli' },
72
- '@modern-js/monorepo-tools': { cli: '@modern-js/monorepo-tools/cli' },
73
- '@modern-js/module-tools': { cli: '@modern-js/module-tools/cli' },
74
- '@modern-js/runtime': { cli: '@modern-js/runtime/cli' },
75
- '@modern-js/plugin-less': { cli: '@modern-js/plugin-less/cli' },
76
- '@modern-js/plugin-sass': { cli: '@modern-js/plugin-sass/cli' },
77
- '@modern-js/plugin-esbuild': { cli: '@modern-js/plugin-esbuild/cli' },
78
- '@modern-js/plugin-proxy': { cli: '@modern-js/plugin-proxy/cli' },
79
- '@modern-js/plugin-ssg': { cli: '@modern-js/plugin-ssg/cli' },
80
- '@modern-js/plugin-bff': {
81
- cli: '@modern-js/plugin-bff/cli',
82
- server: '@modern-js/plugin-bff/server',
83
- },
84
- '@modern-js/plugin-electron': { cli: '@modern-js/plugin-electron/cli' },
85
- '@modern-js/plugin-testing': { cli: '@modern-js/plugin-testing/cli' },
86
- '@modern-js/plugin-storybook': { cli: '@modern-js/plugin-storybook/cli' },
87
- '@modern-js/plugin-docsite': { cli: '@modern-js/plugin-docsite/cli' },
88
- '@modern-js/plugin-express': {
89
- cli: '@modern-js/plugin-express/cli',
90
- server: '@modern-js/plugin-express',
91
- },
92
- '@modern-js/plugin-egg': {
93
- cli: '@modern-js/plugin-egg/cli',
94
- server: '@modern-js/plugin-egg',
95
- },
96
- '@modern-js/plugin-koa': {
97
- cli: '@modern-js/plugin-koa/cli',
98
- server: '@modern-js/plugin-koa',
99
- },
100
- '@modern-js/plugin-nest': {
101
- cli: '@modern-js/plugin-nest/cli',
102
- server: '@modern-js/plugin-nest/server',
103
- },
104
- '@modern-js/plugin-unbundle': { cli: '@modern-js/plugin-unbundle' },
105
- '@modern-js/plugin-server-build': { cli: '@modern-js/plugin-server-build' },
106
- '@modern-js/plugin-server': {
107
- cli: '@modern-js/plugin-server/cli',
108
- server: '@modern-js/plugin-server/server',
109
- },
110
- '@modern-js/plugin-micro-frontend': {
111
- cli: '@modern-js/plugin-micro-frontend/cli',
112
- },
113
- '@modern-js/plugin-jarvis': { cli: '@modern-js/plugin-jarvis/cli' },
114
- '@modern-js/plugin-tailwindcss': { cli: '@modern-js/plugin-tailwindcss/cli' },
115
- '@modern-js/plugin-lambda-fc': { cli: '@modern-js/plugin-lambda-fc/cli' },
116
- '@modern-js/plugin-lambda-scf': { cli: '@modern-js/plugin-lambda-scf/cli' },
117
- '@modern-js/plugin-cdn-oss': { cli: '@modern-js/plugin-cdn-oss/cli' },
118
- '@modern-js/plugin-cdn-cos': { cli: '@modern-js/plugin-cdn-cos/cli' },
119
- '@modern-js/plugin-static-hosting': {
120
- cli: '@modern-js/plugin-static-hosting/cli',
121
- },
122
- '@modern-js/plugin-polyfill': {
123
- cli: '@modern-js/plugin-polyfill/cli',
124
- server: '@modern-js/plugin-polyfill',
125
- },
126
- '@modern-js/plugin-multiprocess': {
127
- cli: '@modern-js/plugin-multiprocess/cli',
128
- },
129
- '@modern-js/plugin-nocode': { cli: '@modern-js/plugin-nocode/cli' },
130
- };
131
-
132
- /**
133
- * The schema registered in the plugin.
134
- */
135
- export const PLUGIN_SCHEMAS = {
136
- '@modern-js/runtime': [
137
- {
138
- target: 'runtime',
139
- schema: {
140
- type: 'object',
141
- additionalProperties: false,
142
- },
143
- },
144
- {
145
- target: 'runtimeByEntries',
146
- schema: {
147
- type: 'object',
148
- patternProperties: { [ENTRY_NAME_PATTERN]: { type: 'object' } },
149
- additionalProperties: false,
150
- },
151
- },
152
- ],
153
- '@modern-js/plugin-bff': [
154
- {
155
- target: 'bff',
156
- schema: {
157
- type: 'object',
158
- properties: {
159
- prefix: {
160
- type: ['string', 'array'],
161
- items: { type: 'string' },
162
- },
163
- fetcher: { type: 'string' },
164
- proxy: { type: 'object' },
165
- requestCreator: { type: 'string' },
166
- },
167
- },
168
- },
169
- ],
170
- '@modern-js/plugin-esbuild': [
171
- {
172
- target: 'tools.esbuild',
173
- schema: { typeof: ['object'] },
174
- },
175
- ],
176
- '@modern-js/plugin-less': [
177
- {
178
- target: 'tools.less',
179
- schema: { typeof: ['object', 'function'] },
180
- },
181
- ],
182
- '@modern-js/plugin-sass': [
183
- {
184
- target: 'tools.sass',
185
- schema: { typeof: ['object', 'function'] },
186
- },
187
- ],
188
- '@modern-js/plugin-tailwindcss': [
189
- {
190
- target: 'tools.tailwindcss',
191
- schema: { typeof: ['object', 'function'] },
192
- },
193
- {
194
- target: 'source.designSystem',
195
- schema: { typeof: ['object'] },
196
- },
197
- ],
198
- '@modern-js/plugin-proxy': [
199
- {
200
- target: 'dev.proxy',
201
- schema: { typeof: ['string', 'object'] },
202
- },
203
- ],
204
- '@modern-js/plugin-unbundle': [
205
- {
206
- target: 'source.disableAutoImportStyle',
207
- schema: { type: 'boolean' },
208
- },
209
- {
210
- target: 'server.https',
211
- schema: { type: 'boolean' },
212
- },
213
- ],
214
- '@modern-js/plugin-ssg': [
215
- {
216
- target: 'output.ssg',
217
- schema: {
218
- oneOf: [
219
- { type: 'boolean' },
220
- { type: 'object' },
221
- { instanceof: 'Function' },
222
- ],
223
- },
224
- },
225
- ],
226
- '@modern-js/plugin-ssr': [
227
- {
228
- target: 'runtime.ssr',
229
- schema: { type: ['boolean', 'object'] },
230
- },
231
- ],
232
- '@modern-js/plugin-state': [
233
- {
234
- target: 'runtime.state',
235
- schema: { type: ['boolean', 'object'] },
236
- },
237
- ],
238
- '@modern-js/plugin-router': [
239
- {
240
- target: 'runtime.router',
241
- schema: { type: ['boolean', 'object'] },
242
- },
243
- ],
244
- '@modern-js/plugin-testing': [
245
- {
246
- target: 'testing',
247
- schema: { typeof: ['object'] },
248
- },
249
- {
250
- target: 'tools.jest',
251
- schema: { typeof: ['object', 'function'] },
252
- },
253
- ],
254
- '@modern-js/plugin-micro-frontend': [
255
- {
256
- target: 'runtime.masterApp',
257
- schema: { type: ['object'] },
258
- },
259
- {
260
- target: 'dev.withMasterApp',
261
- schema: { type: ['object'] },
262
- },
263
- ],
264
- '@modern-js/plugin-nocode': [],
265
- };
package/src/debug.ts DELETED
@@ -1,8 +0,0 @@
1
- import debug from 'debug';
2
-
3
- /**
4
- * Create debug function with unified namespace prefix.
5
- * @param scope - Custom module name of your debug function.
6
- * @returns Debug function which namespace start with modern-js:.
7
- */
8
- export const createDebugger = (scope: string) => debug(`modern-js:${scope}`);
@@ -1,10 +0,0 @@
1
- import path from 'path';
2
-
3
- /**
4
- * ensure absolute file path.
5
- * @param base - Base path to resolve relative from.
6
- * @param filePath - Aboluste or relative file path.
7
- * @returns Resolved absolute file path.
8
- */
9
- export const ensureAbsolutePath = (base: string, filePath: string): string =>
10
- path.isAbsolute(filePath) ? filePath : path.resolve(base, filePath);
package/src/findExists.ts DELETED
@@ -1,15 +0,0 @@
1
- import fs from 'fs';
2
-
3
- /**
4
- * Find first already exists file.
5
- * @param files - Asbolute file paths with extension.
6
- * @returns The file path if exists, or false if no file exists.
7
- */
8
- export const findExists = (files: string[]): string | false => {
9
- for (const file of files) {
10
- if (fs.existsSync(file) && fs.statSync(file).isFile()) {
11
- return file;
12
- }
13
- }
14
- return false;
15
- };