@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/src/logger.ts DELETED
@@ -1,184 +0,0 @@
1
- import chalk, { Color } from 'chalk';
2
-
3
- type LogLevel = 'debug' | 'info' | 'warn' | 'error';
4
-
5
- type LogMsg = number | string | Error;
6
-
7
- interface LoggerConfiguration {
8
- color?: typeof Color;
9
- label?: string;
10
- level?: LogLevel;
11
- }
12
-
13
- interface InstanceConfiguration {
14
- displayLabel?: boolean;
15
- underlineLabel?: boolean;
16
- uppercaseLabel?: boolean;
17
- }
18
-
19
- interface ConstructorOptions {
20
- config?: InstanceConfiguration;
21
- types?: Record<string, LoggerConfiguration>;
22
- }
23
-
24
- type LoggerFunction = (
25
- message?: number | string | Error,
26
- ...args: any[]
27
- ) => void;
28
-
29
- const { grey, underline } = chalk;
30
-
31
- const LOG_TYPES = {
32
- error: {
33
- color: 'red',
34
- label: 'error',
35
- level: 'error',
36
- },
37
- info: {
38
- color: 'blue',
39
- label: 'info',
40
- level: 'info',
41
- },
42
- warn: {
43
- color: 'yellow',
44
- label: 'warning',
45
- level: 'warn',
46
- },
47
- debug: {
48
- color: 'red',
49
- label: 'debug',
50
- level: 'debug',
51
- },
52
- log: { level: 'info' },
53
- };
54
-
55
- const DEFAULT_CONFIG = {
56
- displayLabel: true,
57
- underlineLabel: true,
58
- uppercaseLabel: false,
59
- };
60
-
61
- class Logger {
62
- private readonly logCount: number = 200;
63
-
64
- private history: Partial<Record<string, Array<string>>> = {};
65
-
66
- private readonly config: InstanceConfiguration;
67
-
68
- private readonly types: Record<string, LoggerConfiguration>;
69
-
70
- private readonly longestLabel: string;
71
-
72
- [key: string]: any;
73
-
74
- constructor(options: ConstructorOptions = {}) {
75
- this.config = { ...DEFAULT_CONFIG, ...(options.config || {}) };
76
- this.types = {
77
- ...(LOG_TYPES as Record<string, LoggerConfiguration>),
78
- ...(options.types || {}),
79
- };
80
- this.longestLabel = this.getLongestLabel();
81
-
82
- Object.keys(this.types).forEach(type => {
83
- this[type] = this._log.bind(this, type);
84
- });
85
- }
86
-
87
- private retainLog(type: string, message: string) {
88
- if (!this.history[type]) {
89
- this.history[type] = [];
90
- }
91
- this.history[type]!.push(message);
92
- while (this.history[type]!.length > this.logCount) {
93
- this.history[type]!.shift();
94
- }
95
- }
96
-
97
- // eslint-disable-next-line max-statements
98
- private _log(type: string, message?: LogMsg) {
99
- if (message === undefined) {
100
- // eslint-disable-next-line no-console
101
- console.log();
102
- return;
103
- }
104
-
105
- let label = '';
106
- let text = '';
107
- const logType = this.types[type];
108
-
109
- if (this.config.displayLabel && logType.label) {
110
- label = this.config.uppercaseLabel
111
- ? logType.label.toUpperCase()
112
- : logType.label;
113
-
114
- if (this.config.underlineLabel) {
115
- label = underline(label).padEnd(this.longestUnderlinedLabel.length + 1);
116
- } else {
117
- label = label.padEnd(this.longestLabel.length + 1);
118
- }
119
-
120
- label = logType.color ? chalk[logType.color](label) : label;
121
- }
122
-
123
- if (message instanceof Error) {
124
- if (message.stack) {
125
- const [name, ...rest] = message.stack.split('\n');
126
- text = `${name}\n${grey(rest.join('\n'))}`;
127
- } else {
128
- text = message.message;
129
- }
130
- } else {
131
- text = `${message}`;
132
- }
133
-
134
- // only retain logs of warn/error level
135
- if (logType.level === 'warn' || logType.level === 'error') {
136
- // retain log text without label
137
- this.retainLog(type, text);
138
- }
139
-
140
- const log = label.length > 0 ? `${label} ${text}` : text;
141
- // eslint-disable-next-line no-console
142
- console.log(log);
143
- }
144
-
145
- private getLongestLabel() {
146
- let longestLabel = '';
147
- Object.keys(this.types).forEach(type => {
148
- const { label = '' } = this.types[type];
149
- if (label.length > longestLabel.length) {
150
- longestLabel = label;
151
- }
152
- });
153
- return longestLabel;
154
- }
155
-
156
- private get longestUnderlinedLabel() {
157
- return underline(this.longestLabel);
158
- }
159
-
160
- getRetainedLogs(type: string) {
161
- return this.history[type] || [];
162
- }
163
-
164
- clearRetainedLogs(type: string) {
165
- if (type) {
166
- if (this.history[type]) {
167
- this.history[type] = [];
168
- }
169
- } else {
170
- this.history = {};
171
- }
172
- }
173
- }
174
-
175
- type LoggerInterface = {
176
- [key in keyof typeof LOG_TYPES]: LoggerFunction;
177
- };
178
-
179
- const logger = new Logger() as Logger & LoggerInterface;
180
-
181
- logger.Logger = Logger;
182
-
183
- export { logger };
184
- export type { LoggerInterface };
package/src/monorepo.ts DELETED
@@ -1,106 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import glob from 'glob';
4
- import yaml from 'yaml';
5
-
6
- const PACKAGE_MAX_DEPTH = 5;
7
-
8
- const WOKRSPACES_FILES = {
9
- YARN: 'package.json',
10
- PNPM: 'pnpm-workspaces.yaml',
11
- LERNA: 'lerna.json',
12
- };
13
-
14
- export const isLerna = (root: string) =>
15
- fs.existsSync(path.join(root, WOKRSPACES_FILES.LERNA));
16
-
17
- export const isYarnWorkspaces = (root: string) => {
18
- const pkg = path.join(root, WOKRSPACES_FILES.YARN);
19
-
20
- if (!fs.existsSync(pkg)) {
21
- return false;
22
- }
23
-
24
- const json = JSON.parse(fs.readFileSync(pkg, 'utf8'));
25
-
26
- return Boolean(json.workspaces?.packages);
27
- };
28
-
29
- export const isPnpmWorkspaces = (root: string) =>
30
- fs.existsSync(path.join(root, WOKRSPACES_FILES.PNPM));
31
-
32
- export const isMonorepo = (root: string) =>
33
- isLerna(root) || isYarnWorkspaces(root) || isPnpmWorkspaces(root);
34
-
35
- export const isModernjsMonorepo = (root: string) => {
36
- const json = JSON.parse(
37
- fs.readFileSync(path.join(root, 'package.json'), 'utf8'),
38
- );
39
-
40
- const deps = {
41
- ...(json.dependencies || {}),
42
- ...(json.devDependencies || {}),
43
- };
44
-
45
- return Boolean(deps['@modern-js/monorepo-tools']);
46
- };
47
-
48
- export const findMonorepoRoot = (
49
- appDirectory: string,
50
- maxDepth: number = PACKAGE_MAX_DEPTH,
51
- ) => {
52
- let inMonorepo = false;
53
-
54
- for (let depth = 0; depth < maxDepth; depth++) {
55
- if (isMonorepo(appDirectory)) {
56
- inMonorepo = true;
57
- break;
58
- }
59
- // eslint-disable-next-line no-param-reassign
60
- appDirectory = path.dirname(appDirectory);
61
- }
62
-
63
- return inMonorepo ? appDirectory : undefined;
64
- };
65
-
66
- export const getMonorepoPackages = (
67
- root: string,
68
- ): { name: string; path: string }[] => {
69
- let packages: string[] = [];
70
-
71
- if (isYarnWorkspaces(root)) {
72
- const json = JSON.parse(
73
- fs.readFileSync(path.join(root, 'package.json'), 'utf8'),
74
- );
75
- ({ packages } = json.workspaces);
76
- } else if (isLerna(root)) {
77
- const json = JSON.parse(
78
- fs.readFileSync(path.resolve(root, 'lerna.json'), 'utf8'),
79
- );
80
- ({ packages } = json);
81
- } else {
82
- ({ packages } = yaml.parse(
83
- fs.readFileSync(path.join(root, WOKRSPACES_FILES.PNPM), 'utf8'),
84
- ));
85
- }
86
-
87
- if (packages) {
88
- return packages
89
- .map(name =>
90
- // The trailing / ensures only dirs are picked up
91
- glob.sync(path.join(root, `${name}/`), {
92
- ignore: ['**/node_modules/**'],
93
- }),
94
- )
95
- .flat()
96
- .filter(filepath => fs.existsSync(path.resolve(filepath, 'package.json')))
97
- .map(filepath => ({
98
- path: filepath,
99
- name: JSON.parse(
100
- fs.readFileSync(path.resolve(filepath, 'package.json'), 'utf8'),
101
- ).name,
102
- }));
103
- }
104
-
105
- return [];
106
- };
package/src/nodeEnv.ts DELETED
@@ -1,28 +0,0 @@
1
- import execa from 'execa';
2
-
3
- export async function canUseNpm() {
4
- try {
5
- await execa('npm', ['--version'], { env: process.env });
6
- return true;
7
- } catch (e) {
8
- return false;
9
- }
10
- }
11
-
12
- export async function canUseYarn() {
13
- try {
14
- await execa('yarn', ['--version'], { env: process.env });
15
- return true;
16
- } catch (e) {
17
- return false;
18
- }
19
- }
20
-
21
- export async function canUsePnpm() {
22
- try {
23
- await execa('pnpm', ['--version'], { env: process.env });
24
- return true;
25
- } catch (e) {
26
- return false;
27
- }
28
- }
package/src/path.ts DELETED
@@ -1,9 +0,0 @@
1
- import path from 'path';
2
- import upath from 'upath';
3
-
4
- export const isRelativePath = (test: string): boolean =>
5
- /^\.\.?($|[\\/])/.test(test);
6
-
7
- export const normalizeOutputPath = (s: string) => s.replace(/\\/g, '\\\\');
8
- export const normalizeToPosixPath = (p: string) =>
9
- upath.normalizeSafe(path.normalize(p));
package/src/pkgUp.ts DELETED
@@ -1,3 +0,0 @@
1
- import pkgUp from 'pkg-up';
2
-
3
- export { pkgUp };
@@ -1,88 +0,0 @@
1
- import os from 'os';
2
- import chalk from 'chalk';
3
- import { isDev } from './is';
4
-
5
- // TODO: type
6
- interface EntryPoint {
7
- entryName: string;
8
- }
9
-
10
- interface ServerRoute {
11
- entryName: string;
12
- isSSR: boolean;
13
- urlPath: string;
14
- }
15
-
16
- // TODO: remove hard code 'main'
17
- export const isSingleEntry = (entrypoints: EntryPoint[]) =>
18
- entrypoints.length === 1 && entrypoints[0].entryName === 'main';
19
-
20
- const normalizeUrl = (url: string) => url.replace(/([^:]\/)\/+/g, '$1');
21
-
22
- const getAddressUrls = (protocol = 'http', port: number) => {
23
- const interfaces = os.networkInterfaces();
24
- const ipv4Interfaces: os.NetworkInterfaceInfo[] = [];
25
- Object.keys(interfaces).forEach(key => {
26
- interfaces[key]!.forEach(detail => {
27
- if (detail.family === 'IPv4') {
28
- ipv4Interfaces.push(detail);
29
- }
30
- });
31
- });
32
-
33
- return ipv4Interfaces.reduce(
34
- (memo: { type: string; url: string }[], detail) => {
35
- let type = 'Network: ';
36
- let url = `${protocol}://${detail.address}:${port}`;
37
- if (detail.address.includes(`localhost`)) {
38
- type = 'Local: ';
39
- url = `${protocol}://localhost:${port}`;
40
- }
41
-
42
- memo.push({ type, url });
43
- return memo;
44
- },
45
- [],
46
- );
47
- };
48
-
49
- export const prettyInstructions = (appContext: any, config: any) => {
50
- const { entrypoints, serverRoutes, port } = appContext as {
51
- entrypoints: EntryPoint[];
52
- serverRoutes: ServerRoute[];
53
- port: number;
54
- };
55
-
56
- const urls = getAddressUrls(
57
- config.dev.https && isDev() ? 'https' : 'http',
58
- port,
59
- );
60
-
61
- const routes = serverRoutes.filter(route => route.entryName);
62
-
63
- let message = 'App running at:\n\n';
64
-
65
- if (isSingleEntry(entrypoints)) {
66
- message += urls
67
- .map(
68
- ({ type, url }) =>
69
- ` ${chalk.bold(`> ${type.padEnd(10)}`)}${chalk.cyanBright(
70
- normalizeUrl(`${url}/${routes[0].urlPath}`),
71
- )}\n`,
72
- )
73
- .join('');
74
- } else {
75
- const maxNameLength = Math.max(...routes.map(r => r.entryName.length));
76
-
77
- urls.forEach(({ type, url }) => {
78
- message += ` ${chalk.bold(`> ${type}`)}\n`;
79
- routes.forEach(({ entryName, urlPath }) => {
80
- message += ` ${chalk.yellowBright(
81
- entryName.padEnd(maxNameLength + 8),
82
- )}${chalk.cyanBright(normalizeUrl(`${url}/${urlPath}`))}\n`;
83
- });
84
- });
85
- }
86
-
87
- return message;
88
- };
@@ -1,47 +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
-
13
- import chalk from 'chalk';
14
- import { logger } from './logger';
15
-
16
- export function printBuildError(err: Error) {
17
- const message = err != null && err.message;
18
- const stack = err != null && err.stack;
19
-
20
- // Add more helpful message for Terser error
21
- if (
22
- stack &&
23
- typeof message === 'string' &&
24
- message.indexOf('from Terser') !== -1
25
- ) {
26
- try {
27
- const matched = /(.+)\[(.+):(.+),(.+)\]\[.+\]/.exec(stack);
28
- if (!matched) {
29
- throw new Error('Using errors for control flow is bad.');
30
- }
31
- const problemPath = matched[2];
32
- const line = matched[3];
33
- const column = matched[4];
34
- logger.error(
35
- `Failed to minify the code from this file: \n\n ${chalk.yellow(
36
- `\t${problemPath}:${line}${column !== '0' ? ':' + column : ''}`
37
- )}\n`
38
- );
39
- } catch (ignored) {
40
- logger.error(`Failed to minify the bundle. ${err}\n`);
41
- }
42
- } else {
43
- logger.error((message || err) + '\n');
44
- }
45
- logger.log();
46
- };
47
- /* eslint-enable */
@@ -1,21 +0,0 @@
1
- import path from 'path';
2
-
3
- export const readTsConfig = (root: string) => {
4
- // import typescript from 'typescript' cause eslint fromat error.
5
- const typescript = require('typescript');
6
-
7
- return typescript.readConfigFile(
8
- path.resolve(root, './tsconfig.json'),
9
- typescript.sys.readFile,
10
- ).config;
11
- };
12
-
13
- export const readTsConfigByFile = (filename: string) => {
14
- // import typescript from 'typescript' cause eslint fromat error.
15
- const typescript = require('typescript');
16
-
17
- return typescript.readConfigFile(
18
- path.resolve(filename),
19
- typescript.sys.readFile,
20
- ).config;
21
- };
@@ -1,6 +0,0 @@
1
- export const removeLeadingSlash = (s: string): string => s.replace(/^\/+/, '');
2
-
3
- export const removeTailSlash = (s: string): string => s.replace(/\/+$/, '');
4
-
5
- export const removeSlash = (s: string): string =>
6
- removeLeadingSlash(removeTailSlash(s));
@@ -1,68 +0,0 @@
1
- import path from 'path';
2
- import fs from 'fs-extra';
3
- import { normalizeOutputPath } from './path';
4
-
5
- const memo = <T extends (...args: any[]) => any>(fn: T) => {
6
- const cache = new Map();
7
-
8
- return (...params: Parameters<T>): ReturnType<T> => {
9
- const stringifiedParams = JSON.stringify(params);
10
- const cachedResult = cache.get(stringifiedParams);
11
-
12
- if (cachedResult) {
13
- return cachedResult;
14
- }
15
-
16
- const res = fn(...params);
17
- cache.set(stringifiedParams, res);
18
-
19
- return res;
20
- };
21
- };
22
-
23
- export const createRuntimeExportsUtils = memo(
24
- (pwd = '', namespace: string, ts = false) => {
25
- const entryExportFile = path.join(
26
- pwd,
27
- `.runtime-exports/${namespace ? `${namespace}.js` : 'index.js'}`,
28
- );
29
- const entryExportTsFile = path.join(
30
- pwd,
31
- `.runtime-exports/${namespace ? `${namespace}.d.ts` : 'index.d.ts'}`,
32
- );
33
-
34
- // const ensure = () => {
35
- // if (!fs.existsSync(entryExportFile)) {
36
- // fs.outputFileSync(entryExportFile, '');
37
- // }
38
- // fs.ensureFileSync(entryExportFile);
39
- // };
40
-
41
- const addExport = (statement: string) => {
42
- // eslint-disable-next-line no-param-reassign
43
- statement = normalizeOutputPath(statement);
44
- try {
45
- fs.ensureFileSync(entryExportFile);
46
- fs.ensureFileSync(entryExportTsFile);
47
-
48
- if (!fs.readFileSync(entryExportFile, 'utf8').includes(statement)) {
49
- fs.appendFileSync(entryExportFile, `${statement}\n`);
50
- ts &&
51
- fs.appendFileSync(
52
- entryExportTsFile,
53
- `${statement.replace('.js', '.d')}\n`,
54
- );
55
- }
56
- } catch {
57
- // FIXME:
58
- }
59
- };
60
-
61
- const getPath = () => entryExportFile;
62
-
63
- return {
64
- addExport,
65
- getPath,
66
- };
67
- },
68
- );
package/src/types.d.ts DELETED
@@ -1 +0,0 @@
1
- declare module 'browserslist/node';
package/src/watch.ts DELETED
@@ -1,56 +0,0 @@
1
- import * as path from 'path';
2
- import { Import } from './import';
3
-
4
- const chokidar: typeof import('chokidar') = Import.lazy('chokidar', require);
5
-
6
- export type WatchChangeTypeValueT = 'add' | 'unlink' | 'change';
7
-
8
- export const WatchChangeType: Record<
9
- 'ADD' | 'UNLINK' | 'CHANGE',
10
- WatchChangeTypeValueT
11
- > = {
12
- ADD: 'add',
13
- UNLINK: 'unlink',
14
- CHANGE: 'change',
15
- };
16
-
17
- type RunTaskType = (option: {
18
- changedFilePath: string;
19
- changeType: WatchChangeTypeValueT;
20
- }) => void | Promise<void>;
21
-
22
- export const watch = (
23
- watchDir: string | string[],
24
- runTask: RunTaskType,
25
- ignored: string[] = [],
26
- ) => {
27
- let ready = false;
28
- const watcher = chokidar.watch(watchDir, {
29
- ignored,
30
- });
31
-
32
- watcher.on('ready', () => (ready = true));
33
-
34
- watcher.on('change', async filePath => {
35
- const changedFilePath = path.resolve(filePath);
36
- await runTask({ changedFilePath, changeType: WatchChangeType.CHANGE });
37
- });
38
-
39
- watcher.on('add', async filePath => {
40
- const changedFilePath = path.resolve(filePath);
41
- if (ready) {
42
- await runTask({ changedFilePath, changeType: WatchChangeType.ADD });
43
- }
44
- });
45
-
46
- watcher.on('unlink', async filePath => {
47
- const changedFilePath = path.resolve(filePath);
48
- await runTask({ changedFilePath, changeType: WatchChangeType.UNLINK });
49
- });
50
-
51
- watcher.on('error', err => {
52
- throw err;
53
- });
54
-
55
- return watcher;
56
- };