feat(cli): start new cli
This commit is contained in:
parent
8df107f380
commit
2073f23a91
11 changed files with 1742 additions and 123 deletions
14
.eslintignore
Normal file
14
.eslintignore
Normal file
|
@ -0,0 +1,14 @@
|
|||
node_modules
|
||||
dist
|
||||
lib
|
||||
esm
|
||||
next
|
||||
coverage
|
||||
output
|
||||
static
|
||||
temp
|
||||
.nyc_output
|
||||
*.d.ts
|
||||
__mock__
|
||||
target
|
||||
scripts
|
214
.eslintrc.yml
Normal file
214
.eslintrc.yml
Normal file
|
@ -0,0 +1,214 @@
|
|||
parser: '@typescript-eslint/parser'
|
||||
|
||||
parserOptions:
|
||||
ecmaFeatures:
|
||||
jsx: true
|
||||
ecmaVersion: 2020
|
||||
sourceType: module
|
||||
project: ./tsconfig.json
|
||||
|
||||
env:
|
||||
browser: true
|
||||
es6: true
|
||||
node: true
|
||||
|
||||
plugins:
|
||||
- import
|
||||
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- plugin:prettier/recommended
|
||||
|
||||
rules:
|
||||
# 0 = off, 1 = warn, 2 = error
|
||||
'space-before-function-paren': 0
|
||||
'no-useless-constructor': 0
|
||||
'no-undef': 2
|
||||
'no-console': [2, { allow: ['error', 'warn', 'info', 'assert'] }]
|
||||
'comma-dangle': ['error', 'only-multiline']
|
||||
'no-unused-vars': 0
|
||||
'no-var': 2
|
||||
'one-var-declaration-per-line': 2
|
||||
'prefer-const': 2
|
||||
'no-const-assign': 2
|
||||
'no-duplicate-imports': 2
|
||||
'no-use-before-define': [2, { 'functions': false, 'classes': false }]
|
||||
'eqeqeq': [2, 'always', { 'null': 'ignore' }]
|
||||
'no-case-declarations': 0
|
||||
'no-dupe-class-members': 0
|
||||
|
||||
'import/first': 2
|
||||
'import/newline-after-import': 2
|
||||
'import/order':
|
||||
[
|
||||
2,
|
||||
{
|
||||
'newlines-between': 'always',
|
||||
'alphabetize': { 'order': 'asc', 'caseInsensitive': true },
|
||||
'pathGroups':
|
||||
[
|
||||
{
|
||||
'pattern': '@slardar/**',
|
||||
'group': 'internal',
|
||||
'position': 'before',
|
||||
},
|
||||
{
|
||||
'pattern': '@perfkit/**',
|
||||
'group': 'internal',
|
||||
'position': 'before',
|
||||
},
|
||||
{
|
||||
'pattern': '@maiev/**',
|
||||
'group': 'internal',
|
||||
'position': 'before',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
'@typescript-eslint/adjacent-overload-signatures': 2
|
||||
|
||||
'@typescript-eslint/await-thenable': 2
|
||||
|
||||
'@typescript-eslint/consistent-type-assertions': 2
|
||||
|
||||
'@typescript-eslint/ban-types':
|
||||
[
|
||||
'error',
|
||||
{
|
||||
'types':
|
||||
{
|
||||
'String': { 'message': 'Use string instead', 'fixWith': 'string' },
|
||||
'Number': { 'message': 'Use number instead', 'fixWith': 'number' },
|
||||
'Boolean':
|
||||
{ 'message': 'Use boolean instead', 'fixWith': 'boolean' },
|
||||
'Function': { 'message': 'Use explicit type instead' },
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
'@typescript-eslint/explicit-member-accessibility':
|
||||
[
|
||||
'error',
|
||||
{
|
||||
accessibility: 'explicit',
|
||||
overrides:
|
||||
{
|
||||
accessors: 'no-public',
|
||||
constructors: 'no-public',
|
||||
methods: 'no-public',
|
||||
properties: 'no-public',
|
||||
parameterProperties: 'explicit',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
'@typescript-eslint/method-signature-style': 2
|
||||
|
||||
'@typescript-eslint/no-floating-promises': 2
|
||||
|
||||
'@typescript-eslint/no-implied-eval': 2
|
||||
|
||||
'@typescript-eslint/no-for-in-array': 2
|
||||
|
||||
'@typescript-eslint/no-inferrable-types': 2
|
||||
|
||||
'@typescript-eslint/no-invalid-void-type': 2
|
||||
|
||||
'@typescript-eslint/no-misused-new': 2
|
||||
|
||||
'@typescript-eslint/no-misused-promises': 2
|
||||
|
||||
'@typescript-eslint/no-namespace': 2
|
||||
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 2
|
||||
|
||||
'@typescript-eslint/no-throw-literal': 2
|
||||
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 2
|
||||
|
||||
'@typescript-eslint/prefer-for-of': 2
|
||||
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 2
|
||||
|
||||
'@typescript-eslint/switch-exhaustiveness-check': 2
|
||||
|
||||
'@typescript-eslint/prefer-optional-chain': 2
|
||||
|
||||
'@typescript-eslint/prefer-readonly': 2
|
||||
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 0
|
||||
|
||||
'@typescript-eslint/no-array-constructor': 2
|
||||
|
||||
'@typescript-eslint/require-await': 2
|
||||
|
||||
'@typescript-eslint/return-await': 2
|
||||
|
||||
'@typescript-eslint/ban-ts-comment':
|
||||
[
|
||||
2,
|
||||
{
|
||||
'ts-expect-error': false,
|
||||
'ts-ignore': true,
|
||||
'ts-nocheck': true,
|
||||
'ts-check': false,
|
||||
},
|
||||
]
|
||||
|
||||
'@typescript-eslint/naming-convention':
|
||||
[
|
||||
2,
|
||||
{
|
||||
selector: 'memberLike',
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
modifiers: ['private'],
|
||||
leadingUnderscore: 'forbid',
|
||||
},
|
||||
]
|
||||
|
||||
'@typescript-eslint/no-unused-vars':
|
||||
[
|
||||
2,
|
||||
{
|
||||
varsIgnorePattern: '^_',
|
||||
argsIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
]
|
||||
'@typescript-eslint/member-ordering':
|
||||
[
|
||||
2,
|
||||
{
|
||||
default:
|
||||
[
|
||||
'public-static-field',
|
||||
'protected-static-field',
|
||||
'private-static-field',
|
||||
'public-static-method',
|
||||
'protected-static-method',
|
||||
'private-static-method',
|
||||
'public-instance-field',
|
||||
'protected-instance-field',
|
||||
'private-instance-field',
|
||||
'public-constructor',
|
||||
'protected-constructor',
|
||||
'private-constructor',
|
||||
'public-instance-method',
|
||||
'protected-instance-method',
|
||||
'private-instance-method',
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
overrides:
|
||||
- files:
|
||||
- ./**/*.js
|
||||
plugins:
|
||||
- '@typescript-eslint'
|
||||
parserOptions:
|
||||
project: ./tsconfig.json
|
||||
rules:
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 0
|
||||
'@typescript-eslint/prefer-optional-chain': 0
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 0
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -154,3 +154,4 @@ Temporary Items
|
|||
.apdisk
|
||||
|
||||
# End of https://www.gitignore.io/api/macos
|
||||
scripts
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
target
|
||||
build
|
||||
sys
|
||||
napi
|
||||
napi-derive
|
||||
napi-derive-example
|
||||
|
@ -7,3 +8,10 @@ test_module
|
|||
.yarnrc
|
||||
Cargo.lock
|
||||
rustfmt.toml
|
||||
.github
|
||||
.dockerignore
|
||||
.eslintignore
|
||||
.eslintrc.yml
|
||||
Cargo.toml
|
||||
Dockerfile.alpine
|
||||
yarn.lock
|
||||
|
|
21
package.json
21
package.json
|
@ -31,6 +31,8 @@
|
|||
},
|
||||
"homepage": "https://github.com/napi-rs/napi-rs#readme",
|
||||
"dependencies": {
|
||||
"clipanion": "^2.4.2",
|
||||
"inquirer": "^7.3.3",
|
||||
"minimist": "^1.2.5",
|
||||
"toml": "^3.0.0"
|
||||
},
|
||||
|
@ -57,11 +59,26 @@
|
|||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.27",
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.1",
|
||||
"@types/inquirer": "^7.3.0",
|
||||
"@types/node": "^14.0.26",
|
||||
"@typescript-eslint/eslint-plugin": "^3.7.0",
|
||||
"@typescript-eslint/parser": "^3.7.0",
|
||||
"ava": "^3.11.0",
|
||||
"eslint": "^7.5.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.22.0",
|
||||
"eslint-plugin-prettier": "^3.1.4",
|
||||
"husky": "^4.2.5",
|
||||
"lint-staged": "^10.2.11",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.0.5"
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.0.5",
|
||||
"source-map-support": "^0.5.19",
|
||||
"ts-node": "^8.10.2",
|
||||
"typescript": "^3.9.7"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const parseArgs = require('minimist')
|
||||
const path = require('path')
|
||||
const os = require('os')
|
||||
const toml = require('toml')
|
||||
const fs = require('fs')
|
||||
|
||||
let tomlContentString
|
||||
let tomlContent
|
||||
let moduleName
|
||||
|
||||
try {
|
||||
tomlContentString = fs.readFileSync(
|
||||
path.join(process.cwd(), 'Cargo.toml'),
|
||||
'utf-8',
|
||||
)
|
||||
} catch {
|
||||
throw new TypeError('Can not find Cargo.toml in process.cwd')
|
||||
}
|
||||
|
||||
try {
|
||||
tomlContent = toml.parse(tomlContentString)
|
||||
} catch {
|
||||
throw new TypeError('Can not parse the Cargo.toml')
|
||||
}
|
||||
|
||||
if (tomlContent.package && tomlContent.package.name) {
|
||||
moduleName = tomlContent.package.name.replace(/-/g, '_')
|
||||
} else {
|
||||
throw new TypeError('No package.name field in Cargo.toml')
|
||||
}
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2), {
|
||||
boolean: ['release', 'platform', 'musl'],
|
||||
})
|
||||
|
||||
const platform = os.platform()
|
||||
let libExt
|
||||
let dylibName = moduleName
|
||||
|
||||
// Platform based massaging for build commands
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
libExt = '.dylib'
|
||||
dylibName = `lib${moduleName}`
|
||||
break
|
||||
case 'win32':
|
||||
libExt = '.dll'
|
||||
break
|
||||
case 'linux':
|
||||
dylibName = `lib${moduleName}`
|
||||
libExt = '.so'
|
||||
break
|
||||
default:
|
||||
console.error(
|
||||
'Operating system not currently supported or recognized by the build script',
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const targetDir = argv.release ? 'release' : 'debug'
|
||||
|
||||
const platformName = argv.musl ? '.musl' : argv.platform ? `.${platform}` : ''
|
||||
|
||||
let distModulePath =
|
||||
argv._[0] ||
|
||||
path.join('target', targetDir, `${moduleName}${platformName}.node`)
|
||||
const parsedDist = path.parse(distModulePath)
|
||||
|
||||
if (!parsedDist.name || parsedDist.name === '.') {
|
||||
distModulePath = moduleName
|
||||
}
|
||||
|
||||
if (!parsedDist.ext) {
|
||||
distModulePath = `${distModulePath}${platformName}.node`
|
||||
}
|
||||
|
||||
const pos = __dirname.indexOf('node_modules')
|
||||
|
||||
const dylibContent = fs.readFileSync(
|
||||
path.join(
|
||||
__dirname.substring(0, pos),
|
||||
'target',
|
||||
targetDir,
|
||||
`${dylibName}${libExt}`,
|
||||
),
|
||||
)
|
||||
|
||||
fs.writeFileSync(distModulePath, dylibContent)
|
117
src/build.ts
Normal file
117
src/build.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import { readFile, writeFile } from 'fs'
|
||||
import os from 'os'
|
||||
import { join, parse } from 'path'
|
||||
import { promisify } from 'util'
|
||||
|
||||
import { Command } from 'clipanion'
|
||||
import toml from 'toml'
|
||||
|
||||
const readFileAsync = promisify(readFile)
|
||||
const writeFileAsync = promisify(writeFile)
|
||||
|
||||
export class BuildCommand extends Command {
|
||||
static usage = Command.Usage({
|
||||
description: 'Copy native module into specified dir',
|
||||
})
|
||||
|
||||
@Command.String(`--name`)
|
||||
name!: string
|
||||
|
||||
@Command.String(`--platform`)
|
||||
appendPlatformToFilename!: string
|
||||
|
||||
@Command.Boolean(`--release`)
|
||||
isRelease = false
|
||||
|
||||
@Command.Boolean('--musl')
|
||||
isMusl = false
|
||||
|
||||
@Command.String()
|
||||
target?: string
|
||||
|
||||
@Command.Path('build')
|
||||
async execute() {
|
||||
let tomlContentString: string
|
||||
let tomlContent: any
|
||||
let moduleName: string
|
||||
|
||||
try {
|
||||
tomlContentString = await readFileAsync(
|
||||
join(process.cwd(), 'Cargo.toml'),
|
||||
'utf-8',
|
||||
)
|
||||
} catch {
|
||||
throw new TypeError(`Could not find Cargo.toml in ${process.cwd()}`)
|
||||
}
|
||||
|
||||
try {
|
||||
tomlContent = toml.parse(tomlContentString)
|
||||
} catch {
|
||||
throw new TypeError('Could not parse the Cargo.toml')
|
||||
}
|
||||
|
||||
if (tomlContent.package ?? tomlContent.package.name) {
|
||||
moduleName = tomlContent.package.name.replace(/-/g, '_')
|
||||
} else {
|
||||
throw new TypeError('No package.name field in Cargo.toml')
|
||||
}
|
||||
|
||||
const platform = os.platform()
|
||||
let libExt
|
||||
let dylibName = moduleName
|
||||
|
||||
// Platform based massaging for build commands
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
libExt = '.dylib'
|
||||
dylibName = `lib${moduleName}`
|
||||
break
|
||||
case 'win32':
|
||||
libExt = '.dll'
|
||||
break
|
||||
case 'linux':
|
||||
dylibName = `lib${moduleName}`
|
||||
libExt = '.so'
|
||||
break
|
||||
default:
|
||||
console.error(
|
||||
'Operating system not currently supported or recognized by the build script',
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const targetDir = this.isRelease ? 'release' : 'debug'
|
||||
|
||||
const platformName = this.isMusl
|
||||
? '.musl'
|
||||
: this.appendPlatformToFilename
|
||||
? `.${platform}`
|
||||
: ''
|
||||
|
||||
let distModulePath =
|
||||
this.target ??
|
||||
join('target', targetDir, `${moduleName}${platformName}.node`)
|
||||
const parsedDist = parse(distModulePath)
|
||||
|
||||
if (!parsedDist.name || parsedDist.name === '.') {
|
||||
distModulePath = moduleName
|
||||
}
|
||||
|
||||
if (!parsedDist.ext) {
|
||||
distModulePath = `${distModulePath}${platformName}.node`
|
||||
}
|
||||
|
||||
const pos = __dirname.indexOf('node_modules')
|
||||
|
||||
const dylibContent = await readFileAsync(
|
||||
join(
|
||||
__dirname.substring(0, pos),
|
||||
'target',
|
||||
targetDir,
|
||||
`${dylibName}${libExt}`,
|
||||
),
|
||||
)
|
||||
|
||||
await writeFileAsync(distModulePath, dylibContent)
|
||||
}
|
||||
}
|
19
src/index.ts
Normal file
19
src/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { Cli } from 'clipanion'
|
||||
|
||||
import { BuildCommand } from './build'
|
||||
|
||||
const cli = new Cli({
|
||||
binaryName: 'bin',
|
||||
binaryVersion: require('../package.json').version,
|
||||
})
|
||||
|
||||
cli.register(BuildCommand)
|
||||
|
||||
cli
|
||||
.run(process.argv.slice(2), {
|
||||
...Cli.defaultContext,
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
process.exit(1)
|
||||
})
|
|
@ -2,8 +2,8 @@
|
|||
"name": "test-module",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "cargo build && node ../scripts/napi.js ./index",
|
||||
"build-release": "cargo build --release && node ../scripts/napi.js --release ./index",
|
||||
"build": "cargo build && node ../scripts/index.js build ./index",
|
||||
"build-release": "cargo build --release && node ../scripts/napi.js build --release ./index",
|
||||
"test": "node ./index.js"
|
||||
}
|
||||
}
|
||||
|
|
44
tsconfig.json
Normal file
44
tsconfig.json
Normal file
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"declaration": true,
|
||||
"downlevelIteration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"importHelpers": true,
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"noEmitHelpers": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"suppressExcessPropertyErrors": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"preserveSymlinks": true,
|
||||
"target": "ES2015",
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"stripInternal": true,
|
||||
"resolveJsonModule": true,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"outDir": "./scripts",
|
||||
"lib": [
|
||||
"dom",
|
||||
"DOM.Iterable",
|
||||
"ES5",
|
||||
"ES2015",
|
||||
"ES2016",
|
||||
"ES2017",
|
||||
"ES2018",
|
||||
"ES2019",
|
||||
"ES2020",
|
||||
"esnext"
|
||||
]
|
||||
},
|
||||
"include": ["./src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
Loading…
Reference in a new issue