create-react-native-library
Advanced tools
Comparing version 0.32.0 to 0.33.0
126
lib/index.js
"use strict"; | ||
var _path = _interopRequireDefault(require("path")); | ||
var _fsExtra = _interopRequireDefault(require("fs-extra")); | ||
var _ejs = _interopRequireDefault(require("ejs")); | ||
var _dedent = _interopRequireDefault(require("dedent")); | ||
var _kleur = _interopRequireDefault(require("kleur")); | ||
var _yargs = _interopRequireDefault(require("yargs")); | ||
var _ora = _interopRequireDefault(require("ora")); | ||
var _validateNpmPackageName = _interopRequireDefault(require("validate-npm-package-name")); | ||
var _githubUsername = _interopRequireDefault(require("github-username")); | ||
var _prompts = _interopRequireDefault(require("./utils/prompts")); | ||
var _generateExampleApp = _interopRequireDefault(require("./utils/generateExampleApp")); | ||
var _spawn = require("./utils/spawn"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const FALLBACK_BOB_VERSION = '0.20.0'; | ||
const BINARIES = /(gradlew|\.(jar|keystore|png|jpg|gif))$/; | ||
const BINARIES = [/(gradlew|\.(jar|keystore|png|jpg|gif))$/, /\$\.yarn(?![a-z])/]; | ||
const COMMON_FILES = _path.default.resolve(__dirname, '../templates/common'); | ||
const JS_FILES = _path.default.resolve(__dirname, '../templates/js-library'); | ||
const EXPO_FILES = _path.default.resolve(__dirname, '../templates/expo-library'); | ||
const CPP_FILES = _path.default.resolve(__dirname, '../templates/cpp-library'); | ||
const EXAMPLE_FILES = _path.default.resolve(__dirname, '../templates/example-legacy'); | ||
const NATIVE_COMMON_FILES = _path.default.resolve(__dirname, '../templates/native-common'); | ||
const NATIVE_FILES = { | ||
@@ -181,6 +161,4 @@ module_legacy: _path.default.resolve(__dirname, '../templates/native-library-legacy'), | ||
}; | ||
async function create(argv) { | ||
const folder = _path.default.join(process.cwd(), argv.name); | ||
if (await _fsExtra.default.pathExists(folder)) { | ||
@@ -190,3 +168,2 @@ console.log(`A folder already exists at ${_kleur.default.blue(folder)}! Please specify another folder name or delete the existing one.`); | ||
} | ||
try { | ||
@@ -203,13 +180,10 @@ await (0, _spawn.spawn)('npx', ['--help']); | ||
} | ||
let name, email; | ||
try { | ||
name = await (0, _spawn.spawn)('git', ['config', '--get', 'user.name']); | ||
email = await (0, _spawn.spawn)('git', ['config', '--get', 'user.email']); | ||
} catch (e) {// Ignore error | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
const basename = _path.default.basename(argv.name); | ||
const questions = { | ||
@@ -252,5 +226,5 @@ 'slug': { | ||
return `https://github.com/${username}`; | ||
} catch (e) {// Ignore error | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
return undefined; | ||
@@ -269,3 +243,2 @@ }, | ||
} | ||
return ''; | ||
@@ -290,3 +263,2 @@ }, | ||
} | ||
return true; | ||
@@ -296,4 +268,5 @@ }); | ||
} | ||
}; // Validate arguments passed to the CLI | ||
}; | ||
// Validate arguments passed to the CLI | ||
for (const [key, value] of Object.entries(argv)) { | ||
@@ -303,15 +276,12 @@ if (value == null) { | ||
} | ||
const question = questions[key]; | ||
if (question == null) { | ||
continue; | ||
} | ||
let valid = question.validate ? question.validate(String(value)) : true; | ||
let valid = question.validate ? question.validate(String(value)) : true; // We also need to guard against invalid choices | ||
// We also need to guard against invalid choices | ||
// If we don't already have a validation message to provide a better error | ||
if (typeof valid !== 'string' && 'choices' in question) { | ||
const choices = typeof question.choices === 'function' ? question.choices(undefined, argv, question) : question.choices; | ||
if (choices && !choices.some(choice => choice.value === value)) { | ||
@@ -321,10 +291,7 @@ valid = `Supported values are - ${choices.map(c => _kleur.default.green(c.value))}`; | ||
} | ||
if (valid !== true) { | ||
let message = `Invalid value ${_kleur.default.red(String(value))} passed for ${_kleur.default.blue(key)}`; | ||
if (typeof valid === 'string') { | ||
message += `: ${valid}`; | ||
} | ||
console.log(message); | ||
@@ -334,3 +301,2 @@ process.exit(1); | ||
} | ||
const { | ||
@@ -346,3 +312,4 @@ slug, | ||
reactNativeVersion | ||
} = { ...argv, | ||
} = { | ||
...argv, | ||
...(await (0, _prompts.default)(Object.entries(questions).filter(([k, v]) => { | ||
@@ -352,9 +319,8 @@ // Skip questions which are passed as parameter and pass validation | ||
return false; | ||
} // Skip questions with a single choice | ||
} | ||
// Skip questions with a single choice | ||
if (Array.isArray(v.choices) && v.choices.length === 1) { | ||
return false; | ||
} | ||
return true; | ||
@@ -365,15 +331,16 @@ }).map(([, v]) => { | ||
choices | ||
} = v; // Skip dynamic questions with a single choice | ||
} = v; | ||
// Skip dynamic questions with a single choice | ||
if (type === 'select' && typeof choices === 'function') { | ||
return { ...v, | ||
return { | ||
...v, | ||
type: (prev, values, prompt) => { | ||
const result = choices(prev, { ...argv, | ||
const result = choices(prev, { | ||
...argv, | ||
...values | ||
}, prompt); | ||
if (result && result.length === 1) { | ||
return null; | ||
} | ||
return type; | ||
@@ -383,9 +350,8 @@ } | ||
} | ||
return v; | ||
}))) | ||
}; // Get latest version of Bob from NPM | ||
}; | ||
// Get latest version of Bob from NPM | ||
let version; | ||
try { | ||
@@ -397,3 +363,2 @@ version = await Promise.race([new Promise(resolve => setTimeout(() => resolve(FALLBACK_BOB_VERSION), 1000)), (0, _spawn.spawn)('npm', ['view', 'react-native-builder-bob', 'dist-tags.latest'])]); | ||
} | ||
const moduleType = type.startsWith('view-') ? 'view' : 'module'; | ||
@@ -404,8 +369,7 @@ const arch = type === 'module-new' || type === 'view-new' ? 'new' : type === 'module-mixed' || type === 'view-mixed' ? 'mixed' : 'legacy'; | ||
let namespace; | ||
if (slug.startsWith('@') && slug.includes('/')) { | ||
namespace = slug.split('/')[0]?.replace(/[^a-z0-9]/g, '').toLowerCase(); | ||
} // Create a package identifier with specified namespace when possible | ||
} | ||
// Create a package identifier with specified namespace when possible | ||
const pack = `${namespace ? `${namespace}.` : ''}${project.replace(/[^a-z0-9]/g, '').toLowerCase()}`; | ||
@@ -419,4 +383,6 @@ const options = { | ||
description, | ||
name: /^[A-Z]/.test(argv.name) && /^[a-z0-9]+$/i.test(argv.name) ? // If the project name is already in PascalCase, use it as-is | ||
argv.name : // Otherwise, convert it to PascalCase and remove any non-alphanumeric characters | ||
name: /^[A-Z]/.test(argv.name) && /^[a-z0-9]+$/i.test(argv.name) ? | ||
// If the project name is already in PascalCase, use it as-is | ||
argv.name : | ||
// Otherwise, convert it to PascalCase and remove any non-alphanumeric characters | ||
`${project.charAt(0).toUpperCase()}${project.replace(/[^a-z0-9](\w)/g, (_, $1) => $1.toUpperCase()).slice(1)}`, | ||
@@ -444,7 +410,5 @@ package: pack, | ||
}; | ||
const copyDir = async (source, dest) => { | ||
await _fsExtra.default.mkdirp(dest); | ||
const files = await _fsExtra.default.readdir(source); | ||
for (const f of files) { | ||
@@ -455,10 +419,7 @@ const target = _path.default.join(dest, _ejs.default.render(f.replace(/^\$/, ''), options, { | ||
})); | ||
const file = _path.default.join(source, f); | ||
const stats = await _fsExtra.default.stat(file); | ||
if (stats.isDirectory()) { | ||
await copyDir(file, target); | ||
} else if (!file.match(BINARIES)) { | ||
} else if (!BINARIES.some(r => r.test(file))) { | ||
const content = await _fsExtra.default.readFile(file, 'utf8'); | ||
@@ -471,5 +432,3 @@ await _fsExtra.default.writeFile(target, _ejs.default.render(content, options)); | ||
}; | ||
await _fsExtra.default.mkdirp(folder); | ||
if (reactNativeVersion != null) { | ||
@@ -482,3 +441,2 @@ if (example === 'expo') { | ||
} | ||
const spinner = (0, _ora.default)('Generating example').start(); | ||
@@ -488,2 +446,3 @@ await (0, _generateExampleApp.default)({ | ||
dest: folder, | ||
slug: options.project.slug, | ||
projectName: options.project.name, | ||
@@ -495,3 +454,2 @@ arch, | ||
await copyDir(COMMON_FILES, folder); | ||
if (languages === 'js') { | ||
@@ -503,3 +461,2 @@ await copyDir(JS_FILES, folder); | ||
await copyDir(NATIVE_COMMON_FILES, folder); | ||
if (moduleType === 'module') { | ||
@@ -510,3 +467,2 @@ await copyDir(NATIVE_FILES[`${moduleType}_${arch}`], folder); | ||
} | ||
if (options.project.swift) { | ||
@@ -521,5 +477,3 @@ await copyDir(SWIFT_FILES[`${moduleType}_legacy`], folder); | ||
} | ||
const templateType = `${moduleType}_${arch}`; | ||
if (options.project.kotlin) { | ||
@@ -530,3 +484,2 @@ await copyDir(KOTLIN_FILES[templateType], folder); | ||
} | ||
if (options.project.cpp) { | ||
@@ -536,3 +489,2 @@ await copyDir(CPP_FILES, folder); | ||
} | ||
if (moduleType === 'view') { | ||
@@ -543,16 +495,12 @@ if (arch === 'new' || arch === 'mixed') { | ||
} | ||
} // Set `react` and `react-native` versions of root `package.json` from example `package.json` | ||
} | ||
// Set `react` and `react-native` versions of root `package.json` from example `package.json` | ||
const examplePackageJson = _fsExtra.default.readJSONSync(_path.default.join(folder, 'example', 'package.json')); | ||
const rootPackageJson = _fsExtra.default.readJSONSync(_path.default.join(folder, 'package.json')); | ||
rootPackageJson.devDependencies.react = examplePackageJson.dependencies.react; | ||
rootPackageJson.devDependencies['react-native'] = examplePackageJson.dependencies['react-native']; | ||
_fsExtra.default.writeJSONSync(_path.default.join(folder, 'package.json'), rootPackageJson, { | ||
spaces: 2 | ||
}); | ||
try { | ||
@@ -571,5 +519,5 @@ await (0, _spawn.spawn)('git', ['init'], { | ||
}); | ||
} catch (e) {// Ignore error | ||
} catch (e) { | ||
// Ignore error | ||
} | ||
spinner.succeed(`Project created successfully at ${_kleur.default.yellow(argv.name)}!\n`); | ||
@@ -606,8 +554,6 @@ const platforms = { | ||
`)); | ||
} // eslint-disable-next-line babel/no-unused-expressions | ||
} | ||
// eslint-disable-next-line babel/no-unused-expressions | ||
_yargs.default.command('$0 <name>', 'create a react native library', args, create).demandCommand().recommendCommands().fail((message, error) => { | ||
console.log('\n'); | ||
if (error) { | ||
@@ -617,3 +563,2 @@ console.log(_kleur.default.red(error.message)); | ||
} | ||
if (message) { | ||
@@ -624,5 +569,4 @@ console.log(_kleur.default.red(message)); | ||
} | ||
process.exit(1); | ||
}).strict().argv; | ||
//# sourceMappingURL=index.js.map |
@@ -7,13 +7,7 @@ "use strict"; | ||
exports.default = generateExampleApp; | ||
var _fsExtra = _interopRequireDefault(require("fs-extra")); | ||
var _path = _interopRequireDefault(require("path")); | ||
var _https = _interopRequireDefault(require("https")); | ||
var _spawn = require("./spawn"); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const FILES_TO_DELETE = ['__tests__', '.buckconfig', '.eslintrc.js', '.flowconfig', '.git', '.gitignore', '.prettierrc.js', 'App.js', 'App.tsx', 'index.js', 'tsconfig.json']; | ||
@@ -32,6 +26,6 @@ const PACKAGES_TO_REMOVE = ['@react-native/eslint-config', '@tsconfig/react-native', '@types/jest', '@types/react', '@types/react-test-renderer', '@typescript-eslint/eslint-plugin', '@typescript-eslint/parser', 'babel-jest', 'eslint', 'jest', 'prettier', 'react-test-renderer', 'typescript']; | ||
}; | ||
async function generateExampleApp({ | ||
type, | ||
dest, | ||
slug, | ||
projectName, | ||
@@ -42,20 +36,25 @@ arch, | ||
const directory = _path.default.join(dest, 'example'); | ||
const args = type === 'native' ? // `npx react-native init <projectName> --directory example --skip-install` | ||
['react-native@latest', 'init', `${projectName}Example`, '--directory', directory, '--version', reactNativeVersion, '--skip-install', '--npm'] : // `npx create-expo-app example --no-install` | ||
const args = type === 'native' ? | ||
// `npx react-native init <projectName> --directory example --skip-install` | ||
['react-native@latest', 'init', `${projectName}Example`, '--directory', directory, '--version', reactNativeVersion, '--skip-install', '--npm'] : | ||
// `npx create-expo-app example --no-install` | ||
['create-expo-app@latest', directory, '--no-install']; | ||
await (0, _spawn.spawn)('npx', args, { | ||
cwd: dest, | ||
env: { ...process.env, | ||
env: { | ||
...process.env, | ||
npm_config_yes: 'true' | ||
} | ||
}); // Remove unnecessary files and folders | ||
}); | ||
// Remove unnecessary files and folders | ||
for (const file of FILES_TO_DELETE) { | ||
await _fsExtra.default.remove(_path.default.join(directory, file)); | ||
} // Patch the example app's package.json | ||
} | ||
// Patch the example app's package.json | ||
const pkg = JSON.parse(await _fsExtra.default.readFile(_path.default.join(directory, 'package.json'), 'utf8')); | ||
pkg.name = `${slug}-example`; | ||
const pkg = JSON.parse(await _fsExtra.default.readFile(_path.default.join(directory, 'package.json'), 'utf8')); // Remove Jest config for now | ||
// Remove Jest config for now | ||
delete pkg.jest; | ||
@@ -69,7 +68,9 @@ const { | ||
delete scripts.lint; | ||
const SCRIPTS_TO_ADD = { | ||
'build:android': 'cd android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a', | ||
'build:ios': `cd ios && xcodebuild -workspace ${projectName}Example.xcworkspace -scheme ${projectName}Example -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO` | ||
}; | ||
if (type === 'native') { | ||
scripts.pods = 'pod-install --quiet'; | ||
Object.assign(scripts, SCRIPTS_TO_ADD); | ||
} | ||
PACKAGES_TO_REMOVE.forEach(name => { | ||
@@ -80,7 +81,5 @@ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete | ||
Object.assign(devDependencies, PACKAGES_TO_ADD_DEV); | ||
if (type === 'expo') { | ||
const sdkVersion = dependencies.expo.split('.')[0].replace(/[^\d]/, ''); | ||
let bundledNativeModules; | ||
try { | ||
@@ -103,3 +102,2 @@ bundledNativeModules = await new Promise((resolve, reject) => { | ||
} | ||
Object.entries(PACKAGES_TO_ADD_WEB).forEach(([name, version]) => { | ||
@@ -113,5 +111,5 @@ dependencies[name] = bundledNativeModules[name] || version; | ||
} | ||
await _fsExtra.default.writeFile(_path.default.join(directory, 'package.json'), JSON.stringify(pkg, null, 2)); | ||
await _fsExtra.default.writeFile(_path.default.join(directory, 'package.json'), JSON.stringify(pkg, null, 2)); // If the library is on new architecture, enable new arch for iOS and Android | ||
// If the library is on new architecture, enable new arch for iOS and Android | ||
if (arch === 'new') { | ||
@@ -121,5 +119,6 @@ // Android | ||
const gradleProperties = await _fsExtra.default.readFile(_path.default.join(directory, 'android', 'gradle.properties'), 'utf8'); | ||
await _fsExtra.default.writeFile(_path.default.join(directory, 'android', 'gradle.properties'), gradleProperties.replace('newArchEnabled=false', 'newArchEnabled=true')); // iOS | ||
await _fsExtra.default.writeFile(_path.default.join(directory, 'android', 'gradle.properties'), gradleProperties.replace('newArchEnabled=false', 'newArchEnabled=true')); | ||
// iOS | ||
// Add ENV['RCT_NEW_ARCH_ENABLED'] = 1 on top of example/ios/Podfile | ||
const podfile = await _fsExtra.default.readFile(_path.default.join(directory, 'ios', 'Podfile'), 'utf8'); | ||
@@ -126,0 +125,0 @@ await _fsExtra.default.writeFile(_path.default.join(directory, 'ios', 'Podfile'), "ENV['RCT_NEW_ARCH_ENABLED'] = '1'\n\n" + podfile); |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = prompts; | ||
var _prompts = _interopRequireDefault(require("prompts")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function prompts(args, options) { | ||
@@ -18,3 +15,2 @@ return (0, _prompts.default)(args, { | ||
}, | ||
...options | ||
@@ -21,0 +17,0 @@ }); |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.spawn = void 0; | ||
var _crossSpawn = _interopRequireDefault(require("cross-spawn")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
const spawn = async (...args) => { | ||
@@ -36,4 +33,3 @@ return new Promise((resolve, reject) => { | ||
}; | ||
exports.spawn = spawn; | ||
//# sourceMappingURL=spawn.js.map |
{ | ||
"name": "create-react-native-library", | ||
"version": "0.32.0", | ||
"version": "0.33.0", | ||
"description": "CLI to scaffold React Native libraries", | ||
@@ -27,5 +27,3 @@ "keywords": [ | ||
"main": "lib/index.js", | ||
"bin": { | ||
"create-react-native-library": "bin/create-react-native-library" | ||
}, | ||
"bin": "bin/create-react-native-library", | ||
"files": [ | ||
@@ -71,3 +69,3 @@ "lib", | ||
}, | ||
"gitHead": "2a92f26b642637b853c0dfe7f59e2d561d6394af" | ||
"gitHead": "93f29070b303a1681431c2eeee46c27bcf703186" | ||
} |
@@ -33,13 +33,10 @@ { | ||
"lint": "eslint \"**/*.{js,ts,tsx}\"", | ||
"prepack": "bob build", | ||
"release": "release-it", | ||
"example": "yarn --cwd example", | ||
<% if (example === 'native') { -%> | ||
"build:android": "cd example/android && ./gradlew assembleDebug --no-daemon --console=plain -PreactNativeArchitectures=arm64-v8a", | ||
"build:ios": "cd example/ios && xcodebuild -workspace <%- project.name %>Example.xcworkspace -scheme <%- project.name %>Example -configuration Debug -sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO", | ||
"bootstrap": "yarn example && yarn install && yarn example pods", | ||
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build" | ||
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib", | ||
<% } else { -%> | ||
"bootstrap": "yarn example && yarn install" | ||
"clean": "del-cli lib", | ||
<% } -%> | ||
"prepack": "bob build", | ||
"release": "release-it", | ||
"example": "yarn workspace <%- project.slug -%>-example" | ||
}, | ||
@@ -93,6 +90,9 @@ "keywords": [ | ||
}, | ||
"workspaces": [ | ||
"example" | ||
], | ||
"packageManager": "yarn@3.6.1", | ||
"engines": { | ||
"node": ">= 18.0.0" | ||
}, | ||
"packageManager": "^yarn@1.22.15", | ||
"jest": { | ||
@@ -99,0 +99,0 @@ "preset": "react-native", |
@@ -9,2 +9,7 @@ # Contributing | ||
This project is a monorepo managed using [Yarn workspaces](https://yarnpkg.com/features/workspaces). It contains the following packages: | ||
- The library package in the root directory. | ||
- An example app in the `example/` directory. | ||
To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: | ||
@@ -16,6 +21,16 @@ | ||
> While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development. | ||
> Since the project relies on Yarn workspaces, you cannot use [`npm`](https://github.com/npm/cli) for development. | ||
While developing, you can run the [example app](/example/) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app. | ||
The [example app](/example/) demonstrates usage of the library. You need to run it to test any changes you make. | ||
It is configured to use the local version of the library, so any changes you make to the library's source code will be reflected in the example app. Changes to the library's JavaScript code will be reflected in the example app without a rebuild, but native code changes will require a rebuild of the example app. | ||
<% if (project.native) { -%> | ||
If you want to use Android Studio or XCode to edit the native code, you can open the `example/android` or `example/ios` directories respectively in those editors. To edit the Objective-C or Swift files, open `example/ios/<%- project.name -%>Example.xcworkspace` in XCode and find the source files at `Pods > Development Pods > <%- project.slug -%>`. | ||
To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `<%- project.identifier -%>` under `Android`. | ||
<% } -%> | ||
You can use various commands from the root directory to work with the project. | ||
To start the packager: | ||
@@ -51,3 +66,3 @@ | ||
```sh | ||
RCT_NEW_ARCH_ENABLED=1 yarn example pods | ||
RCT_NEW_ARCH_ENABLED=1 yarn pod-install example/ios | ||
yarn example ios | ||
@@ -100,9 +115,2 @@ ``` | ||
<% if (project.native) { -%> | ||
To edit the Objective-C or Swift files, open `example/ios/<%- project.name -%>Example.xcworkspace` in XCode and find the source files at `Pods > Development Pods > <%- project.slug -%>`. | ||
To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `<%- project.identifier -%>` under `Android`. | ||
<% } -%> | ||
### Commit message convention | ||
@@ -143,3 +151,3 @@ | ||
- `yarn bootstrap`: setup project by installing all dependencies and pods. | ||
- `yarn`: setup project by installing dependencies and pods - run with `POD_INSTALL=0` to skip installing pods. | ||
- `yarn typecheck`: type-check files with TypeScript. | ||
@@ -146,0 +154,0 @@ - `yarn lint`: lint files with ESLint. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
3543529
127
15282
2
10
3