commit
18932f4a5f
4
.commitlintrc.json
Normal file
4
.commitlintrc.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-conventional"],
|
||||
"rules": {}
|
||||
}
|
4
.devcontainer/Dockerfile
Normal file
4
.devcontainer/Dockerfile
Normal file
@ -0,0 +1,4 @@
|
||||
FROM mcr.microsoft.com/devcontainers/base:ubuntu
|
||||
|
||||
RUN apt update
|
||||
RUN apt install -y pkg-config
|
50
.devcontainer/devcontainer.json
Normal file
50
.devcontainer/devcontainer.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "loafle.nx.plugin",
|
||||
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspace",
|
||||
"shutdownAction": "stopCompose",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/node:1": {},
|
||||
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
|
||||
},
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"terminal.integrated.defaultProfile.linux": "zsh",
|
||||
"terminal.integrated.profiles.linux": {
|
||||
"zsh": {
|
||||
"path": "/bin/zsh"
|
||||
}
|
||||
},
|
||||
"scss.validate": false,
|
||||
"css.validate": false,
|
||||
"css.lint.unknownAtRules": "ignore",
|
||||
"scss.lint.unknownAtRules": "ignore"
|
||||
},
|
||||
"extensions": [
|
||||
"bradlc.vscode-tailwindcss",
|
||||
"csstools.postcss",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"donjayamanne.githistory",
|
||||
"eamodio.gitlens",
|
||||
"esbenp.prettier-vscode",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"ms-azuretools.vscode-docker"
|
||||
]
|
||||
}
|
||||
},
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
// Use 'postCreateCommand' to run commands after the container is created.
|
||||
"postCreateCommand": "/bin/sh ./.devcontainer/postCreateCommand.sh",
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached",
|
||||
"source=${localEnv:HOME}/.netrc,target=/home/vscode/.netrc,type=bind,consistency=cached",
|
||||
"source=${localEnv:HOME}/.config/pypoetry,target=/home/vscode/.config/pypoetry,type=bind,consistency=cached",
|
||||
"source=${localEnv:HOME}/.ssh/id_rsa,target=/home/vscode/.ssh/id_rsa,type=bind,consistency=cached"
|
||||
]
|
||||
}
|
48
.devcontainer/docker-compose.yml
Normal file
48
.devcontainer/docker-compose.yml
Normal file
@ -0,0 +1,48 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
# Using a Dockerfile is optional, but included for completeness.
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
# [Optional] You can use build args to set options. e.g. 'VARIANT' below affects the image in the Dockerfile
|
||||
# args:
|
||||
# VARIANT: buster
|
||||
# environment:
|
||||
# PORT: 3000
|
||||
# ports:
|
||||
# - 3000:3000
|
||||
|
||||
volumes:
|
||||
# This is where VS Code should expect to find your project's source code and the value of "workspaceFolder" in .devcontainer/devcontainer.json
|
||||
- ..:/workspace:cached
|
||||
|
||||
# Uncomment the next line to use Docker from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker-compose for details.
|
||||
# - /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
# command: /bin/sh -c "while sleep 1000; do :; done"
|
||||
command: sleep infinity
|
||||
|
||||
# Runs app on the same network as the service container, allows "forwardPorts" in devcontainer.json function.
|
||||
# network_mode: service:another-service
|
||||
|
||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
|
||||
# Uncomment the next line to use a non-root user for all processes - See https://aka.ms/vscode-remote/containers/non-root for details.
|
||||
# user: vscode
|
||||
|
||||
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
|
||||
# cap_add:
|
||||
# - SYS_PTRACE
|
||||
# security_opt:
|
||||
# - seccomp:unconfined
|
||||
|
||||
# You can include other services not opened by VS Code as well
|
||||
# another-service:
|
||||
# image: mongo:latest
|
||||
# restart: unless-stopped
|
||||
|
||||
# As in the "app" service, use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
3
.devcontainer/postCreateCommand.sh
Normal file
3
.devcontainer/postCreateCommand.sh
Normal file
@ -0,0 +1,3 @@
|
||||
npm install -g npm
|
||||
|
||||
npm add --global nx@latest
|
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Editor configuration, see http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
4
.env
Normal file
4
.env
Normal file
@ -0,0 +1,4 @@
|
||||
# Nx 18 enables using plugins to infer targets by default
|
||||
# This is disabled for existing workspaces to maintain compatibility
|
||||
# For more info, see: https://nx.dev/concepts/inferred-tasks
|
||||
NX_ADD_PLUGINS=false
|
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
node_modules
|
48
.eslintrc.json
Normal file
48
.eslintrc.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": ["**/*"],
|
||||
"plugins": ["@nx"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {
|
||||
"@nx/enforce-module-boundaries": [
|
||||
"error",
|
||||
{
|
||||
"enforceBuildableLibDependency": true,
|
||||
"allow": [],
|
||||
"depConstraints": [
|
||||
{
|
||||
"sourceTag": "*",
|
||||
"onlyDependOnLibsWithTags": ["*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"extends": ["plugin:@nx/typescript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"@typescript-eslint/no-extra-semi": "error",
|
||||
"no-extra-semi": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"extends": ["plugin:@nx/javascript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-extra-semi": "error",
|
||||
"no-extra-semi": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.json",
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
24
.github/workflows/ci.yml
vendored
Normal file
24
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
env:
|
||||
node_version: 20
|
||||
|
||||
jobs:
|
||||
checks:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: ./.github/workflows/setup
|
||||
with:
|
||||
node_version: ${{ env.node_version }}
|
||||
- run: yarn nx run-many --target=build,test,lint --exclude loafle --parallel --max-parallel=3
|
||||
- run: yarn nx run-many --target=e2e --exclude loafle --parallel
|
||||
- run: yarn nx-cloud stop-all-agents
|
27
.github/workflows/setup/action.yml
vendored
Normal file
27
.github/workflows/setup/action.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Setup
|
||||
description: Setup tasks
|
||||
inputs:
|
||||
node_version: # id of input
|
||||
description: 'Version of node to use'
|
||||
required: true
|
||||
default: '20'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Derive appropriate SHAs for base and head for `nx affected` commands
|
||||
uses: nrwl/nx-set-shas@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node_version}}
|
||||
- name: Install
|
||||
uses: dtolnay/rust-toolchain@1.79.0
|
||||
- uses: actions/cache@v4
|
||||
id: workspace-cache
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-${{ inputs.node_version }}-workspace-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ inputs.node_version }}-workspace-
|
||||
- run: yarn install --frozen-lockfile
|
||||
shell: bash
|
47
.gitignore
vendored
Normal file
47
.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
||||
.nx/cache
|
||||
.nx/workspace-data
|
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit $1
|
7
.prettierignore
Normal file
7
.prettierignore
Normal file
@ -0,0 +1,7 @@
|
||||
# Add files here to ignore them from prettier formatting
|
||||
|
||||
/dist
|
||||
/coverage
|
||||
|
||||
/.nx/cache
|
||||
/.nx/workspace-data
|
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"singleQuote": true
|
||||
}
|
47
.verdaccio/config.yml
Normal file
47
.verdaccio/config.yml
Normal file
@ -0,0 +1,47 @@
|
||||
# path to a directory with all packages
|
||||
storage: ../tmp/local-registry/storage
|
||||
|
||||
auth:
|
||||
htpasswd:
|
||||
file: ./htpasswd
|
||||
algorithm: bcrypt
|
||||
|
||||
# a list of other known repositories we can talk to
|
||||
uplinks:
|
||||
npmjs:
|
||||
url: https://registry.npmjs.org/
|
||||
maxage: 60m
|
||||
max_fails: 20
|
||||
fail_timeout: 2m
|
||||
yarn:
|
||||
url: https://registry.yarnpkg.com
|
||||
maxage: 60m
|
||||
max_fails: 20
|
||||
fail_timeout: 2
|
||||
|
||||
packages:
|
||||
'@*/*':
|
||||
# scoped packages
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: $all
|
||||
proxy: npmjs
|
||||
|
||||
'**':
|
||||
# give all users (including non-authenticated users) full access
|
||||
# because it is a local registry
|
||||
access: $all
|
||||
publish: $all
|
||||
unpublish: $all
|
||||
|
||||
# if package is not available locally, proxy requests to npm registry
|
||||
proxy: npmjs
|
||||
|
||||
# log settings
|
||||
logs:
|
||||
type: stdout
|
||||
format: pretty
|
||||
level: warn
|
||||
|
||||
publish:
|
||||
allow_offline: true # set offline to true to allow publish offline
|
1
.verdaccio/htpasswd
Normal file
1
.verdaccio/htpasswd
Normal file
@ -0,0 +1 @@
|
||||
test:$2y$10$lVWrhBqHffH6dnroJWR.0ug.Zgehrsxdh0dRcrFSqdktWqf/sRk9S
|
8
.vscode/extensions.json
vendored
Normal file
8
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"nrwl.angular-console",
|
||||
"esbenp.prettier-vscode",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"firsttris.vscode-jest-runner"
|
||||
]
|
||||
}
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.validate": [
|
||||
"json"
|
||||
]
|
||||
}
|
14
README.md
Normal file
14
README.md
Normal file
@ -0,0 +1,14 @@
|
||||
<p align="center">
|
||||
<img width="256px" src="./assets/monodon.png" />
|
||||
</p>
|
||||
<div align="center">
|
||||
|
||||
# Monodon
|
||||
|
||||
**A collection of utilities and plugins for the Nx ecosystem**
|
||||
|
||||
</div>
|
||||
|
||||
[](./packages/rust/README.md)
|
||||
[](https://www.npmjs.com/package/@loafle/nx-rust)<br/>
|
||||
[](./packages/rust/README.md)
|
BIN
assets/monodon.png
Normal file
BIN
assets/monodon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 451 KiB |
18
e2e/rust-e2e/.eslintrc.json
Normal file
18
e2e/rust-e2e/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
12
e2e/rust-e2e/jest.config.ts
Normal file
12
e2e/rust-e2e/jest.config.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'rust-e2e',
|
||||
preset: '../../jest.preset.js',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/e2e/rust-e2e',
|
||||
globalSetup: '../../tools/scripts/start-local-registry.ts',
|
||||
globalTeardown: '../../tools/scripts/stop-local-registry.ts',
|
||||
};
|
22
e2e/rust-e2e/project.json
Normal file
22
e2e/rust-e2e/project.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "rust-e2e",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"sourceRoot": "e2e/rust-e2e/src",
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "e2e/rust-e2e/jest.config.ts",
|
||||
"runInBand": true
|
||||
},
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": ["{options.outputFile}"]
|
||||
}
|
||||
},
|
||||
"implicitDependencies": ["rust"]
|
||||
}
|
69
e2e/rust-e2e/src/napi.spec.ts
Normal file
69
e2e/rust-e2e/src/napi.spec.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { execSync } from 'child_process';
|
||||
import { createTestProject, runNxCommand } from './utils';
|
||||
import { rmSync } from 'fs';
|
||||
import { listFiles, readFile, updateFile } from '@nx/plugin/testing';
|
||||
|
||||
describe('napi', () => {
|
||||
let projectDirectory: string;
|
||||
beforeAll(() => {
|
||||
projectDirectory = createTestProject('napi');
|
||||
|
||||
// The plugin has been built and published to a local registry in the jest globalSetup
|
||||
// Install the plugin built with the latest source code into the test repo
|
||||
execSync(`yarn add -D @loafle/nx-rust@e2e`, {
|
||||
cwd: projectDirectory,
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Cleanup the test project
|
||||
rmSync(projectDirectory, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a napi project', () => {
|
||||
runNxCommand(
|
||||
`generate @loafle/nx-rust:lib napi-proj --napi`,
|
||||
projectDirectory
|
||||
);
|
||||
|
||||
const projectConfigPath = `test-project-napi/napi_proj/project.json`;
|
||||
const projectFile = JSON.parse(readFile(projectConfigPath));
|
||||
projectFile['targets']['build']['options'] = {
|
||||
...projectFile['targets']['build']['options'],
|
||||
jsFile: 'native.js',
|
||||
dts: 'native.d.ts',
|
||||
};
|
||||
updateFile(projectConfigPath, JSON.stringify(projectFile, null, 2));
|
||||
|
||||
expect(listFiles(`test-project-napi/napi_proj/npm`).length).toBeGreaterThan(
|
||||
0
|
||||
);
|
||||
|
||||
expect(() =>
|
||||
runNxCommand(`build napi_proj`, projectDirectory)
|
||||
).not.toThrow();
|
||||
|
||||
const files = listFiles(`test-project-napi/napi_proj`);
|
||||
expect(files.some((file) => file.endsWith('native.js'))).toBeTruthy();
|
||||
expect(files.some((file) => file.endsWith('native.d.ts'))).toBeTruthy();
|
||||
expect(files.some((file) => file.endsWith('.node'))).toBeTruthy();
|
||||
|
||||
expect(() =>
|
||||
runNxCommand(
|
||||
`build napi_proj -- --target wasm32-wasip1-threads`,
|
||||
projectDirectory
|
||||
)
|
||||
).not.toThrow();
|
||||
const files2 = listFiles(`test-project-napi/napi_proj`);
|
||||
expect(
|
||||
files2.some((file) => file.endsWith('wasm32-wasi.wasm'))
|
||||
).toBeTruthy();
|
||||
expect(files2).toContain('wasi-worker.mjs');
|
||||
expect(files2).toContain('wasi-worker-browser.mjs');
|
||||
});
|
||||
});
|
75
e2e/rust-e2e/src/rust.spec.ts
Normal file
75
e2e/rust-e2e/src/rust.spec.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { ProjectGraph } from '@nx/devkit';
|
||||
import { execSync } from 'child_process';
|
||||
import { readFileSync, rmSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { createTestProject, runNxCommand } from './utils';
|
||||
|
||||
describe('rust', () => {
|
||||
let projectDirectory: string;
|
||||
|
||||
beforeAll(() => {
|
||||
projectDirectory = createTestProject();
|
||||
|
||||
// The plugin has been built and published to a local registry in the jest globalSetup
|
||||
// Install the plugin built with the latest source code into the test repo
|
||||
execSync(`yarn add -D @loafle/nx-rust@e2e`, {
|
||||
cwd: projectDirectory,
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// Cleanup the test project
|
||||
rmSync(projectDirectory, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should be installed', () => {
|
||||
// npm ls will fail if the package is not installed properly
|
||||
execSync('npm ls @loafle/nx-rust', {
|
||||
cwd: projectDirectory,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate a cargo project and update the project graph', () => {
|
||||
runNxCommand(`generate @loafle/nx-rust:bin hello-world`, projectDirectory);
|
||||
runNxCommand(`generate @loafle/nx-rust:lib lib1`, projectDirectory);
|
||||
|
||||
execSync('cargo add itertools -p lib1', { cwd: projectDirectory });
|
||||
execSync(`cargo add lib1 --path ./lib1 -p hello_world`, {
|
||||
cwd: projectDirectory,
|
||||
});
|
||||
expect(() =>
|
||||
runNxCommand(`build hello_world`, projectDirectory)
|
||||
).not.toThrow();
|
||||
|
||||
const projectGraph: ProjectGraph = JSON.parse(
|
||||
readFileSync(
|
||||
join(projectDirectory, '.nx/workspace-data/project-graph.json')
|
||||
).toString()
|
||||
);
|
||||
|
||||
expect(projectGraph.dependencies['hello_world']).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"source": "hello_world",
|
||||
"target": "lib1",
|
||||
"type": "static",
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(projectGraph.dependencies['lib1']).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"source": "lib1",
|
||||
"target": "cargo:itertools",
|
||||
"type": "static",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
38
e2e/rust-e2e/src/utils.ts
Normal file
38
e2e/rust-e2e/src/utils.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { dirname, join } from 'path';
|
||||
import { mkdirSync, rmSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import { tmpProjPath } from '@nx/plugin/testing';
|
||||
|
||||
/**
|
||||
* Creates a test project with create-nx-workspace and installs the plugin
|
||||
* @returns The directory where the test project was created
|
||||
*/
|
||||
export function createTestProject(testId = '') {
|
||||
const projectName = 'test-project-' + testId;
|
||||
const projectDirectory = tmpProjPath(projectName);
|
||||
|
||||
// Ensure projectDirectory is empty
|
||||
rmSync(projectDirectory, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
mkdirSync(dirname(projectDirectory), {
|
||||
recursive: true,
|
||||
});
|
||||
|
||||
execSync(
|
||||
`npx --yes create-nx-workspace@latest ${projectName} --preset apps --nxCloud=skip --no-interactive --packageManager yarn`,
|
||||
{
|
||||
cwd: dirname(projectDirectory),
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
}
|
||||
);
|
||||
console.log(`Created test project in "${projectDirectory}"`);
|
||||
|
||||
return projectDirectory;
|
||||
}
|
||||
|
||||
export function runNxCommand(command: string, projectDir: string) {
|
||||
execSync(`npx nx ${command}`, { cwd: projectDir, stdio: 'inherit' });
|
||||
}
|
10
e2e/rust-e2e/tsconfig.json
Normal file
10
e2e/rust-e2e/tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
14
e2e/rust-e2e/tsconfig.spec.json
Normal file
14
e2e/rust-e2e/tsconfig.spec.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
5
jest.config.ts
Normal file
5
jest.config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { getJestProjectsAsync } from '@nx/jest';
|
||||
|
||||
export default async () => ({
|
||||
projects: await getJestProjectsAsync(),
|
||||
});
|
15
jest.preset.js
Normal file
15
jest.preset.js
Normal file
@ -0,0 +1,15 @@
|
||||
const nxPreset = require('@nx/jest/preset').default;
|
||||
|
||||
module.exports = {
|
||||
...nxPreset,
|
||||
/* TODO: Update to latest Jest snapshotFormat
|
||||
* By default Nx has kept the older style of Jest Snapshot formats
|
||||
* to prevent breaking of any existing tests with snapshots.
|
||||
* It's recommend you update to the latest format.
|
||||
* You can do this by removing snapshotFormat property
|
||||
* and running tests with --update-snapshot flag.
|
||||
* Example: "nx affected --targets=e2e --update-snapshot"
|
||||
* More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
|
||||
*/
|
||||
snapshotFormat: { escapeString: true, printBasicPrototype: true },
|
||||
};
|
27
migrations.json
Normal file
27
migrations.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"version": "20.0.0-beta.7",
|
||||
"description": "Migration for v20.0.0-beta.7",
|
||||
"implementation": "./src/migrations/update-20-0-0/move-use-daemon-process",
|
||||
"package": "nx",
|
||||
"name": "move-use-daemon-process"
|
||||
},
|
||||
{
|
||||
"version": "20.0.1",
|
||||
"description": "Set `useLegacyCache` to true for migrating workspaces",
|
||||
"implementation": "./src/migrations/update-20-0-1/use-legacy-cache",
|
||||
"x-repair-skip": true,
|
||||
"package": "nx",
|
||||
"name": "use-legacy-cache"
|
||||
},
|
||||
{
|
||||
"cli": "nx",
|
||||
"version": "20.0.0-beta.5",
|
||||
"description": "replace getJestProjects with getJestProjectsAsync",
|
||||
"implementation": "./src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync",
|
||||
"package": "@nx/jest",
|
||||
"name": "replace-getJestProjects-with-getJestProjectsAsync"
|
||||
}
|
||||
]
|
||||
}
|
67
nx.json
Normal file
67
nx.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"$schema": "./node_modules/nx/schemas/nx-schema.json",
|
||||
"nxCloudAccessToken": "NzcyM2FlMTMtMjU2MS00NTE0LWFjNzQtNmU0OGU5YjExNzVlfHJlYWQ=",
|
||||
"workspaceLayout": {
|
||||
"appsDir": "e2e",
|
||||
"libsDir": "packages"
|
||||
},
|
||||
"release": {
|
||||
"projects": ["rust"],
|
||||
"projectsRelationship": "independent",
|
||||
"releaseTagPattern": "{projectName}-{version}",
|
||||
"version": {
|
||||
"conventionalCommits": true,
|
||||
"generatorOptions": {
|
||||
"packageRoot": "dist/packages/{projectName}"
|
||||
}
|
||||
},
|
||||
"changelog": {
|
||||
"projectChangelogs": {
|
||||
"file": "{projectRoot}/CHANGELOG.md",
|
||||
"createRelease": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"targetDefaults": {
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/packages/{projectName}"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["production", "^production"],
|
||||
"cache": true
|
||||
},
|
||||
"@nx/jest:jest": {
|
||||
"cache": true,
|
||||
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
|
||||
"options": {
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@nx/eslint:lint": {
|
||||
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
|
||||
"cache": true
|
||||
}
|
||||
},
|
||||
"namedInputs": {
|
||||
"default": ["{projectRoot}/**/*", "sharedGlobals"],
|
||||
"sharedGlobals": [],
|
||||
"production": [
|
||||
"default",
|
||||
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
|
||||
"!{projectRoot}/tsconfig.spec.json",
|
||||
"!{projectRoot}/jest.config.[jt]s",
|
||||
"!{projectRoot}/.eslintrc.json",
|
||||
"!{projectRoot}/src/test-setup.[jt]s"
|
||||
]
|
||||
},
|
||||
"useLegacyCache": false
|
||||
}
|
64
package.json
Normal file
64
package.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "loafle",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"nx": "nx",
|
||||
"prepare": "husky install",
|
||||
"local-registry": "nx run loafle:local-registry",
|
||||
"build": "nx run rust:build",
|
||||
"test": "nx run rust:test",
|
||||
"e2e": "nx run rust-e2e:e2e",
|
||||
"release": "node tools/scripts/release.js"
|
||||
},
|
||||
"private": true,
|
||||
"packageManager": "yarn@1.22.19",
|
||||
"dependencies": {
|
||||
"@ltd/j-toml": "1.38.0",
|
||||
"@napi-rs/cli": "3.0.0-alpha.63",
|
||||
"@nx/devkit": "20.0.1",
|
||||
"@nx/js": "20.0.1",
|
||||
"@swc/helpers": "0.5.13",
|
||||
"chalk": "^4.1.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "17.3.0",
|
||||
"@commitlint/config-conventional": "17.3.0",
|
||||
"@nx/eslint": "20.0.1",
|
||||
"@nx/eslint-plugin": "20.0.1",
|
||||
"@nx/jest": "20.0.1",
|
||||
"@nx/node": "20.0.1",
|
||||
"@nx/plugin": "20.0.1",
|
||||
"@nx/workspace": "20.0.1",
|
||||
"@swc-node/register": "1.9.2",
|
||||
"@swc/cli": "0.3.14",
|
||||
"@swc/core": "1.5.7",
|
||||
"@types/jest": "29.5.13",
|
||||
"@types/node": "18.19.11",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/eslint-plugin": "7.18.0",
|
||||
"@typescript-eslint/parser": "7.18.0",
|
||||
"dotenv": "~10.0.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"husky": "^8.0.0",
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"jsonc-eslint-parser": "^2.1.0",
|
||||
"nx": "20.0.1",
|
||||
"prettier": "2.8.0",
|
||||
"semver": "7.5.4",
|
||||
"ts-jest": "29.1.0",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.5.4",
|
||||
"verdaccio": "^5.25.0"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.11.1",
|
||||
"yarn": "1.22.19"
|
||||
},
|
||||
"nx": {
|
||||
"includedScripts": []
|
||||
}
|
||||
}
|
31
packages/rust/.eslintrc.json
Normal file
31
packages/rust/.eslintrc.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"./package.json",
|
||||
"./generators.json",
|
||||
"./executors.json",
|
||||
"./migrations.json"
|
||||
],
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {
|
||||
"@nx/nx-plugin-checks": "error",
|
||||
"@nx/dependency-checks": "warn"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
0
packages/rust/CHANGELOG.md
Normal file
0
packages/rust/CHANGELOG.md
Normal file
122
packages/rust/README.md
Normal file
122
packages/rust/README.md
Normal file
@ -0,0 +1,122 @@
|
||||
# @loafle/nx-rust
|
||||
|
||||
A Nx plugin that adds support for Cargo and Rust in your Nx workspace.
|
||||
|
||||
## Compatibility Chart
|
||||
|
||||
| @loafle/nx-rust | nx |
|
||||
| --------------- | -------- |
|
||||
| <=1.2.1 | <=17.1.0 |
|
||||
| >=1.3.0 | >=17.1.0 |
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
The following tools need to be installed on your system to take full advantage of `@loafle/nx-rust`
|
||||
|
||||
- Node (LTS)
|
||||
- Rust / Cargo via [https://rustup.rs](https://rustup.rs)
|
||||
|
||||
### Install with `npx create-nx-workspace` preset
|
||||
|
||||
To bootstrap a new workspace with `@loafle/nx-rust` installed and ready, run:
|
||||
|
||||
```shell
|
||||
npx create-nx-workspace --preset=@loafle/nx-rust
|
||||
```
|
||||
|
||||
### Installation in already set up workspace
|
||||
|
||||
Use your favourite package manager to install in your project:
|
||||
|
||||
```shell
|
||||
yarn add -D @loafle/nx-rust
|
||||
```
|
||||
|
||||
```shell
|
||||
npm install -D @loafle/nx-rust
|
||||
```
|
||||
|
||||
```shell
|
||||
pnpm add -D @loafle/nx-rust
|
||||
```
|
||||
|
||||
#### Initialization
|
||||
|
||||
After installing, you can run any of the project generators (binary, library) to have @loafle/nx-rust set up Cargo in your workspace.
|
||||
|
||||
## Generators
|
||||
|
||||
Use Nx Console to see the full list of options for each generator.
|
||||
|
||||
### `@loafle/nx-rust:binary`
|
||||
|
||||
Creates a Rust binary application to be run independently.
|
||||
|
||||
> Create a new binary:
|
||||
>
|
||||
> ```shell
|
||||
> nx generate @loafle/nx-rust:binary my-rust-app
|
||||
> ```
|
||||
|
||||
### `@loafle/nx-rust:library`
|
||||
|
||||
Creates a Rust library that can be used in binaries, or compiled to be used for napi.
|
||||
|
||||
> Create a new library:
|
||||
>
|
||||
> ```shell
|
||||
> nx generate @loafle/nx-rust:library my-rust-lib
|
||||
> ```
|
||||
|
||||
> Create a new library with napi:
|
||||
>
|
||||
> ```shell
|
||||
> nx generate @loafle/nx-rust:library my-rust-node-lib --napi
|
||||
> ```
|
||||
|
||||
#### Napi
|
||||
|
||||
Generating a library with the `--napi` flag will set up the project to be built with it.
|
||||
|
||||
## Executors
|
||||
|
||||
All the executors support these additional properties:
|
||||
|
||||
- toolchain: (e.g. `--toolchain='stable' | 'beta' | 'nightly'`);
|
||||
- Uses `stable` by default
|
||||
- target (e.g. `--target=aarch64-apple-darwin`);
|
||||
- profile (e.g. `--profile=dev`)
|
||||
- [Cargo profiles](https://doc.rust-lang.org/cargo/reference/profiles.html)
|
||||
- release
|
||||
- target-dir
|
||||
- features (e.g. `--features=bmp`)
|
||||
- [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html)
|
||||
- all-features
|
||||
- args
|
||||
- [Arguments forwarding](https://nx.dev/nx-api/nx/executors/run-commands#args) to the executor.
|
||||
|
||||
### `@loafle/nx-rust:build`
|
||||
|
||||
Runs cargo to build the project
|
||||
|
||||
> Not supported with napi
|
||||
|
||||
### `@loafle/nx-rust:lint`
|
||||
|
||||
Runs cargo clippy to lint the project
|
||||
|
||||
### `@loafle/nx-rust:napi`
|
||||
|
||||
Runs the napi cli to build the project
|
||||
|
||||
### `@loafle/nx-rust:run`
|
||||
|
||||
Runs `cargo run` for the project
|
||||
|
||||
> Not supported with napi
|
||||
|
||||
### `@loafle/nx-rust:test`
|
||||
|
||||
Runs `cargo test` for the project
|
46
packages/rust/executors.json
Normal file
46
packages/rust/executors.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"executors": {
|
||||
"build": {
|
||||
"implementation": "./src/executors/build/executor",
|
||||
"schema": "./src/executors/build/schema.json",
|
||||
"description": "Build a Rust project with Cargo"
|
||||
},
|
||||
"check": {
|
||||
"implementation": "./src/executors/check/executor",
|
||||
"schema": "./src/executors/check/schema.json",
|
||||
"description": "Check a Rust project with Cargo"
|
||||
},
|
||||
"lint": {
|
||||
"implementation": "./src/executors/lint/executor",
|
||||
"schema": "./src/executors/lint/schema.json",
|
||||
"description": "Lint a Rust project with Cargo clippy"
|
||||
},
|
||||
"run": {
|
||||
"implementation": "./src/executors/run/executor",
|
||||
"schema": "./src/executors/run/schema.json",
|
||||
"description": "Run a Rust project with Cargo"
|
||||
},
|
||||
"test": {
|
||||
"implementation": "./src/executors/test/executor",
|
||||
"schema": "./src/executors/test/schema.json",
|
||||
"description": "Test a Rust project with Cargo"
|
||||
},
|
||||
"wasm-pack": {
|
||||
"implementation": "./src/executors/wasm-pack/executor",
|
||||
"schema": "./src/executors/wasm-pack/schema.json",
|
||||
"description": "Builds a Cargo project using wasm-pack"
|
||||
},
|
||||
"napi": {
|
||||
"implementation": "./src/executors/napi/executor",
|
||||
"schema": "./src/executors/napi/schema.json",
|
||||
"description": "Wrapper to run the napi-cli"
|
||||
},
|
||||
"release-publish": {
|
||||
"implementation": "./src/executors/release-publish/executor",
|
||||
"schema": "./src/executors/release-publish/schema.json",
|
||||
"description": "DO NOT INVOKE DIRECTLY WITH `nx run`. Use `nx release publish` instead.",
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
}
|
65
packages/rust/generators.json
Normal file
65
packages/rust/generators.json
Normal file
@ -0,0 +1,65 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"name": "rust",
|
||||
"version": "0.0.1",
|
||||
"generators": {
|
||||
"binary": {
|
||||
"factory": "./src/generators/binary/generator",
|
||||
"schema": "./src/generators/binary/schema.json",
|
||||
"description": "Generate a Rust bin with Cargo",
|
||||
"x-type": "application",
|
||||
"aliases": [
|
||||
"bin"
|
||||
]
|
||||
},
|
||||
"init": {
|
||||
"factory": "./src/generators/init/generator",
|
||||
"schema": "./src/generators/init/schema.json",
|
||||
"description": "initializes a Cargo workspace within a Nx workspace",
|
||||
"hidden": true
|
||||
},
|
||||
"library": {
|
||||
"factory": "./src/generators/library/generator",
|
||||
"schema": "./src/generators/library/schema.json",
|
||||
"description": "Generate a Rust library with Cargo",
|
||||
"x-type": "library",
|
||||
"aliases": [
|
||||
"lib"
|
||||
]
|
||||
},
|
||||
"add-wasm": {
|
||||
"factory": "./src/generators/add-wasm/generator",
|
||||
"schema": "./src/generators/add-wasm/schema.json",
|
||||
"description": "Adds wasm support to a Cargo project",
|
||||
"hidden": true
|
||||
},
|
||||
"add-wasm-reference": {
|
||||
"factory": "./src/generators/add-wasm-reference/generator",
|
||||
"schema": "./src/generators/add-wasm-reference/schema.json",
|
||||
"description": "Adds wasm support to an existing JavaScript/TypeScript project",
|
||||
"hidden": true
|
||||
},
|
||||
"preset": {
|
||||
"factory": "./src/generators/preset/generator",
|
||||
"schema": "./src/generators/preset/schema.json",
|
||||
"description": "preset generator",
|
||||
"hidden": true
|
||||
},
|
||||
"add-napi": {
|
||||
"factory": "./src/generators/add-napi/generator",
|
||||
"schema": "./src/generators/add-napi/schema.json",
|
||||
"description": "Generates support for napi-rs"
|
||||
},
|
||||
"create-napi-npm-dirs": {
|
||||
"factory": "./src/generators/create-napi-npm-dirs/generator",
|
||||
"schema": "./src/generators/create-napi-npm-dirs/schema.json",
|
||||
"description": "Generates npm package directories for a NAPI project"
|
||||
},
|
||||
"release-version": {
|
||||
"factory": "./src/generators/release-version/release-version#releaseVersionGenerator",
|
||||
"schema": "./src/generators/release-version/schema.json",
|
||||
"description": "DO NOT INVOKE DIRECTLY WITH `nx generate`. Use `nx release version` instead.",
|
||||
"hidden": true
|
||||
}
|
||||
}
|
||||
}
|
17
packages/rust/jest.config.ts
Normal file
17
packages/rust/jest.config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'rust',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {},
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': [
|
||||
'ts-jest',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/packages/rust',
|
||||
};
|
25
packages/rust/migrations.json
Normal file
25
packages/rust/migrations.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"generators": {},
|
||||
"packageJsonUpdates": {
|
||||
"2.0.0": {
|
||||
"version": "2.0.0-beta.1",
|
||||
"requires": {
|
||||
"@napi-rs/cli": "<3.0.0"
|
||||
},
|
||||
"packages": {
|
||||
"@napi-rs/cli": {
|
||||
"version": "3.0.0-alpha.63",
|
||||
"alwaysAddToPackageJson": false
|
||||
},
|
||||
"@napi-rs/wasm-runtime": {
|
||||
"version": "^0.2.4",
|
||||
"alwaysAddToPackageJson": true
|
||||
},
|
||||
"emnapi": {
|
||||
"version": "^1.1.0",
|
||||
"alwaysAddToPackageJson": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
packages/rust/package.json
Normal file
27
packages/rust/package.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "@loafle/nx-rust",
|
||||
"version": "0.0.0-updated-during-release",
|
||||
"main": "src/index.js",
|
||||
"repository": {
|
||||
"url": "https://git.loafle.net/loafle/nx",
|
||||
"type": "git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"private": false,
|
||||
"generators": "./generators.json",
|
||||
"executors": "./executors.json",
|
||||
"dependencies": {
|
||||
"@nx/devkit": ">= 19 < 21",
|
||||
"@ltd/j-toml": "1.38.0",
|
||||
"chalk": "^4.1.2",
|
||||
"npm-run-path": "^4.0.1",
|
||||
"semver": "7.5.4",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@napi-rs/cli": "^3.0.0-alpha.55"
|
||||
},
|
||||
"nx-migrations": {
|
||||
"migrations": "./migrations.json"
|
||||
}
|
||||
}
|
58
packages/rust/project.json
Normal file
58
packages/rust/project.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "rust",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/rust/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": ["{options.outputFile}"]
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/packages/rust"],
|
||||
"options": {
|
||||
"jestConfig": "packages/rust/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/rust",
|
||||
"tsConfig": "packages/rust/tsconfig.lib.json",
|
||||
"packageJson": "packages/rust/package.json",
|
||||
"main": "packages/rust/src/index.ts",
|
||||
"assets": [
|
||||
"packages/rust/*.md",
|
||||
{
|
||||
"input": "./packages/rust/src",
|
||||
"glob": "**/!(*.ts)",
|
||||
"output": "./src"
|
||||
},
|
||||
{
|
||||
"input": "./packages/rust/src",
|
||||
"glob": "**/*.d.ts",
|
||||
"output": "./src"
|
||||
},
|
||||
{
|
||||
"input": "./packages/rust",
|
||||
"glob": "generators.json",
|
||||
"output": "."
|
||||
},
|
||||
{
|
||||
"input": "./packages/rust",
|
||||
"glob": "executors.json",
|
||||
"output": "."
|
||||
},
|
||||
{
|
||||
"input": "./packages/rust",
|
||||
"glob": "migrations.json",
|
||||
"output": "."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
packages/rust/src/executors/build/executor.spec.ts
Normal file
15
packages/rust/src/executors/build/executor.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// import * as cargoUtils from '../../utils/cargo';
|
||||
// jest.mock('../../utils/cargo', (): Partial<typeof cargoUtils> => {
|
||||
// return { runCargoSync: jest.fn(() => ({ output: 'output', success: true })) };
|
||||
// });
|
||||
|
||||
import {} from '@nx/devkit/testing';
|
||||
import { BuildExecutorSchema } from './schema';
|
||||
|
||||
const options: BuildExecutorSchema = {};
|
||||
|
||||
describe('Build Executor', () => {
|
||||
it('can run', async () => {
|
||||
// e2es should cover this
|
||||
});
|
||||
});
|
16
packages/rust/src/executors/build/executor.ts
Normal file
16
packages/rust/src/executors/build/executor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { cargoCommand } from '../../utils/cargo';
|
||||
import { BuildExecutorSchema } from './schema';
|
||||
|
||||
export default async function* runExecutor(
|
||||
options: BuildExecutorSchema,
|
||||
context: ExecutorContext
|
||||
): AsyncGenerator<{ success: boolean }> {
|
||||
const command = buildCommand('build', options, context);
|
||||
|
||||
const { success } = await cargoCommand(...command);
|
||||
yield {
|
||||
success,
|
||||
};
|
||||
}
|
4
packages/rust/src/executors/build/schema.d.ts
vendored
Normal file
4
packages/rust/src/executors/build/schema.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import { BaseOptions } from '../../models/base-options';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface BuildExecutorSchema extends BaseOptions {}
|
138
packages/rust/src/executors/build/schema.json
Normal file
138
packages/rust/src/executors/build/schema.json
Normal file
@ -0,0 +1,138 @@
|
||||
{
|
||||
"version": 2,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Build executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile": {
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stable",
|
||||
"beta",
|
||||
"nightly"
|
||||
],
|
||||
"default": "stable"
|
||||
},
|
||||
"features": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Features of workspace members may be enabled with package-name/feature-name syntax. Array of names is supported"
|
||||
},
|
||||
"all-features": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all binary targets"
|
||||
},
|
||||
"lib": {
|
||||
"type": "boolean",
|
||||
"description": "Build the package's library",
|
||||
"default": false
|
||||
},
|
||||
"bin": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified binary. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"bins": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all binary targets"
|
||||
},
|
||||
"example": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified example. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"examples": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all example targets"
|
||||
},
|
||||
"test": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified test. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"tests": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all test targets"
|
||||
},
|
||||
"bench": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified bench. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"benches": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all targets in benchmark mode that have the bench = true manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the bench flag in the manifest settings for the target."
|
||||
},
|
||||
"all-targets": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all test targets"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
15
packages/rust/src/executors/check/executor.spec.ts
Normal file
15
packages/rust/src/executors/check/executor.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// import * as cargoUtils from '../../utils/cargo';
|
||||
// jest.mock('../../utils/cargo', (): Partial<typeof cargoUtils> => {
|
||||
// return { runCargoSync: jest.fn(() => ({ output: 'output', success: true })) };
|
||||
// });
|
||||
|
||||
import {} from '@nx/devkit/testing';
|
||||
import { CheckExecutorSchema } from './schema';
|
||||
|
||||
const options: CheckExecutorSchema = {};
|
||||
|
||||
describe('Build Executor', () => {
|
||||
it('can run', async () => {
|
||||
// e2es should cover this
|
||||
});
|
||||
});
|
16
packages/rust/src/executors/check/executor.ts
Normal file
16
packages/rust/src/executors/check/executor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { cargoCommand } from '../../utils/cargo';
|
||||
import { CheckExecutorSchema } from './schema';
|
||||
|
||||
export default async function* runExecutor(
|
||||
options: CheckExecutorSchema,
|
||||
context: ExecutorContext
|
||||
): AsyncGenerator<{ success: boolean }> {
|
||||
const command = buildCommand('check', options, context);
|
||||
|
||||
const { success } = await cargoCommand(...command);
|
||||
yield {
|
||||
success,
|
||||
};
|
||||
}
|
4
packages/rust/src/executors/check/schema.d.ts
vendored
Normal file
4
packages/rust/src/executors/check/schema.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import { BaseOptions } from '../../models/base-options';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface CheckExecutorSchema extends BaseOptions {}
|
138
packages/rust/src/executors/check/schema.json
Normal file
138
packages/rust/src/executors/check/schema.json
Normal file
@ -0,0 +1,138 @@
|
||||
{
|
||||
"version": 2,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Check executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile": {
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stable",
|
||||
"beta",
|
||||
"nightly"
|
||||
],
|
||||
"default": "stable"
|
||||
},
|
||||
"features": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Features of workspace members may be enabled with package-name/feature-name syntax. Array of names is supported"
|
||||
},
|
||||
"all-features": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all binary targets"
|
||||
},
|
||||
"lib": {
|
||||
"type": "boolean",
|
||||
"description": "Check the package's library",
|
||||
"default": false
|
||||
},
|
||||
"bin": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Check the specified binary. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"bins": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all binary targets"
|
||||
},
|
||||
"example": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Check the specified example. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"examples": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all example targets"
|
||||
},
|
||||
"test": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Check the specified test. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"tests": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all test targets"
|
||||
},
|
||||
"bench": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Check the specified bench. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"benches": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all targets in benchmark mode that have the bench = true manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the bench flag in the manifest settings for the target."
|
||||
},
|
||||
"all-targets": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Check all test targets"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
10
packages/rust/src/executors/lint/executor.spec.ts
Normal file
10
packages/rust/src/executors/lint/executor.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { LintExecutorSchema } from './schema';
|
||||
import executor from './executor';
|
||||
|
||||
const options: LintExecutorSchema = {};
|
||||
|
||||
describe('Lint Executor', () => {
|
||||
it('can run', async () => {
|
||||
// e2es should cover this
|
||||
});
|
||||
});
|
16
packages/rust/src/executors/lint/executor.ts
Normal file
16
packages/rust/src/executors/lint/executor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { cargoCommand } from '../../utils/cargo';
|
||||
import { LintExecutorSchema } from './schema';
|
||||
|
||||
export default async function* runExecutor(
|
||||
options: LintExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const command = buildCommand('clippy', options, context);
|
||||
|
||||
const { success } = await cargoCommand(...command);
|
||||
yield {
|
||||
success,
|
||||
};
|
||||
}
|
5
packages/rust/src/executors/lint/schema.d.ts
vendored
Normal file
5
packages/rust/src/executors/lint/schema.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
import { BaseOptions } from '../../models/base-options';
|
||||
|
||||
export interface LintExecutorSchema extends BaseOptions {
|
||||
fix?: boolean;
|
||||
} // eslint-disable-line
|
37
packages/rust/src/executors/lint/schema.json
Normal file
37
packages/rust/src/executors/lint/schema.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": 2,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Lint executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile": {
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stable",
|
||||
"beta",
|
||||
"nightly"
|
||||
],
|
||||
"default": "stable"
|
||||
},
|
||||
"fix": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
54
packages/rust/src/executors/napi/executor.ts
Normal file
54
packages/rust/src/executors/napi/executor.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { ExecutorContext, joinPathFragments, workspaceRoot } from '@nx/devkit';
|
||||
import { NapiExecutorSchema } from './schema.js';
|
||||
import { join } from 'path';
|
||||
import { fileExists } from 'nx/src/utils/fileutils.js';
|
||||
import { cargoMetadata } from '../../utils/cargo';
|
||||
|
||||
export default async function runExecutor(
|
||||
options: NapiExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const { NapiCli } = await import('@napi-rs/cli');
|
||||
const projectRoot =
|
||||
context.projectGraph?.nodes[context.projectName ?? ''].data.root;
|
||||
const packageJson = join(projectRoot ?? '.', 'package.json');
|
||||
if (!fileExists(packageJson)) {
|
||||
throw new Error(`Could not find package.json at ${packageJson}`);
|
||||
}
|
||||
|
||||
const napi = new NapiCli();
|
||||
|
||||
const buildOptions: Parameters<typeof napi.build>[0] = {};
|
||||
|
||||
buildOptions.platform = true;
|
||||
buildOptions.jsBinding = options.jsFile;
|
||||
buildOptions.dts = options.dts;
|
||||
buildOptions.outputDir = options.dist;
|
||||
buildOptions.manifestPath = join(projectRoot ?? '.', 'Cargo.toml');
|
||||
buildOptions.packageJsonPath = packageJson;
|
||||
if (options.release) {
|
||||
buildOptions.release = true;
|
||||
}
|
||||
|
||||
if (options.target) {
|
||||
buildOptions.target = options.target;
|
||||
}
|
||||
|
||||
if (options.zig) {
|
||||
buildOptions.crossCompile = true;
|
||||
}
|
||||
|
||||
const metadata = cargoMetadata();
|
||||
buildOptions.targetDir =
|
||||
metadata?.target_directory ??
|
||||
joinPathFragments(workspaceRoot, 'dist', 'cargo');
|
||||
|
||||
if (process.env.VERCEL) {
|
||||
// Vercel doesnt have support for cargo atm, so auto success builds
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
const { task } = await napi.build(buildOptions);
|
||||
const output = await task;
|
||||
return { success: true, terminalOutput: output };
|
||||
}
|
8
packages/rust/src/executors/napi/schema.d.ts
vendored
Normal file
8
packages/rust/src/executors/napi/schema.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export interface NapiExecutorSchema {
|
||||
dist: string;
|
||||
jsFile: string;
|
||||
dts?: string;
|
||||
release?: boolean;
|
||||
target?: string;
|
||||
zig?: boolean;
|
||||
}
|
31
packages/rust/src/executors/napi/schema.json
Normal file
31
packages/rust/src/executors/napi/schema.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"version": 2,
|
||||
"title": "Napi executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"dist": {
|
||||
"type": "string"
|
||||
},
|
||||
"jsFile": {
|
||||
"type": "string"
|
||||
},
|
||||
"dts": {
|
||||
"type": "string",
|
||||
"default": "index.d.ts"
|
||||
},
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"zig": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": ["dist", "jsFile"]
|
||||
}
|
87
packages/rust/src/executors/release-publish/executor.ts
Normal file
87
packages/rust/src/executors/release-publish/executor.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { ExecutorContext, joinPathFragments, output } from '@nx/devkit';
|
||||
import { execSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { relative } from 'node:path';
|
||||
import { env as appendLocalEnv } from 'npm-run-path';
|
||||
import { parseCargoToml } from '../../utils/toml';
|
||||
import { PublishExecutorSchema } from './schema';
|
||||
import chalk = require('chalk');
|
||||
|
||||
const LARGE_BUFFER = 1024 * 1000000;
|
||||
|
||||
function processEnv(color: boolean) {
|
||||
const env = {
|
||||
...process.env,
|
||||
...appendLocalEnv(),
|
||||
};
|
||||
|
||||
if (color) {
|
||||
env.FORCE_COLOR = `${color}`;
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
export default async function runExecutor(
|
||||
options: PublishExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
/**
|
||||
* We need to check both the env var and the option because the executor may have been triggered
|
||||
* indirectly via dependsOn, in which case the env var will be set, but the option will not.
|
||||
*/
|
||||
const isDryRun = process.env.NX_DRY_RUN === 'true' || options.dryRun || false;
|
||||
|
||||
const projectConfig =
|
||||
context.projectsConfigurations!.projects[context.projectName!]!;
|
||||
|
||||
const packageRoot = joinPathFragments(
|
||||
context.root,
|
||||
options.packageRoot ?? projectConfig.root
|
||||
);
|
||||
const workspaceRelativePackageRoot = relative(context.root, packageRoot);
|
||||
|
||||
const cargoTomlPath = joinPathFragments(packageRoot, 'Cargo.toml');
|
||||
const cargoTomlContents = readFileSync(cargoTomlPath, 'utf-8');
|
||||
const cargoToml = parseCargoToml(cargoTomlContents);
|
||||
const crateName = cargoToml.package.name;
|
||||
|
||||
const cargoPublishCommandSegments = [
|
||||
`cargo publish --allow-dirty -p ${crateName}`,
|
||||
];
|
||||
|
||||
if (isDryRun) {
|
||||
cargoPublishCommandSegments.push(`--dry-run`);
|
||||
}
|
||||
|
||||
try {
|
||||
const command = cargoPublishCommandSegments.join(' ');
|
||||
output.logSingleLine(`Running "${command}"...`);
|
||||
|
||||
execSync(command, {
|
||||
maxBuffer: LARGE_BUFFER,
|
||||
env: processEnv(true),
|
||||
cwd: packageRoot,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
console.log('');
|
||||
|
||||
if (isDryRun) {
|
||||
console.log(
|
||||
`Would publish to https://crates.io, but ${chalk.keyword('orange')(
|
||||
'[dry-run]'
|
||||
)} was set`
|
||||
);
|
||||
} else {
|
||||
console.log(`Published to https://crates.io`);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
} catch (err: any) {
|
||||
return {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
4
packages/rust/src/executors/release-publish/schema.d.ts
vendored
Normal file
4
packages/rust/src/executors/release-publish/schema.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export interface PublishExecutorSchema {
|
||||
packageRoot?: string;
|
||||
dryRun?: boolean;
|
||||
}
|
18
packages/rust/src/executors/release-publish/schema.json
Normal file
18
packages/rust/src/executors/release-publish/schema.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/schema",
|
||||
"version": 2,
|
||||
"title": "Implementation details of `nx release publish`",
|
||||
"description": "DO NOT INVOKE DIRECTLY WITH `nx run`. Use `nx release publish` instead.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"packageRoot": {
|
||||
"type": "string",
|
||||
"description": "The root directory of the directory (containing a manifest file at its root) to publish. Defaults to the project root."
|
||||
},
|
||||
"dryRun": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to run the command without actually publishing the package to the registry."
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
10
packages/rust/src/executors/run/executor.spec.ts
Normal file
10
packages/rust/src/executors/run/executor.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { RunExecutorSchema } from './schema';
|
||||
import executor from './executor';
|
||||
|
||||
const options: RunExecutorSchema = {};
|
||||
|
||||
describe('Run Executor', () => {
|
||||
it('can run', async () => {
|
||||
// e2es should cover this
|
||||
});
|
||||
});
|
16
packages/rust/src/executors/run/executor.ts
Normal file
16
packages/rust/src/executors/run/executor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { cargoRunCommand } from '../../utils/cargo';
|
||||
import { RunExecutorSchema } from './schema';
|
||||
|
||||
export default async function* runExecutor(
|
||||
options: RunExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const command = buildCommand('run', options, context);
|
||||
|
||||
const { success } = await cargoRunCommand(...command);
|
||||
yield {
|
||||
success,
|
||||
};
|
||||
}
|
3
packages/rust/src/executors/run/schema.d.ts
vendored
Normal file
3
packages/rust/src/executors/run/schema.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
import { BaseOptions } from '../../models/base-options';
|
||||
|
||||
export interface RunExecutorSchema extends BaseOptions {} // eslint-disable-line
|
77
packages/rust/src/executors/run/schema.json
Normal file
77
packages/rust/src/executors/run/schema.json
Normal file
@ -0,0 +1,77 @@
|
||||
{
|
||||
"version": 2,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Run executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile": {
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stable",
|
||||
"beta",
|
||||
"nightly"
|
||||
],
|
||||
"default": "stable"
|
||||
},
|
||||
"features": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Features of workspace members may be enabled with package-name/feature-name syntax. Array of names is supported"
|
||||
},
|
||||
"all-features": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all binary targets"
|
||||
},
|
||||
"bin": {
|
||||
"type": "string",
|
||||
"description": "Run the specified binary"
|
||||
},
|
||||
"example": {
|
||||
"type": "string",
|
||||
"description": "Run the specified example"
|
||||
},
|
||||
"args": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "Extra arguments. You can pass them as follows: nx run project:run --args='--wait=100'."
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
10
packages/rust/src/executors/test/executor.spec.ts
Normal file
10
packages/rust/src/executors/test/executor.spec.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { TestExecutorSchema } from './schema';
|
||||
import executor from './executor';
|
||||
|
||||
const options: TestExecutorSchema = {};
|
||||
|
||||
describe('Test Executor', () => {
|
||||
it('can run', async () => {
|
||||
// e2es should cover this
|
||||
});
|
||||
});
|
16
packages/rust/src/executors/test/executor.ts
Normal file
16
packages/rust/src/executors/test/executor.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { cargoCommand } from '../../utils/cargo';
|
||||
import { TestExecutorSchema } from './schema';
|
||||
|
||||
export default async function* runExecutor(
|
||||
options: TestExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const command = buildCommand('test', options, context);
|
||||
|
||||
const { success } = await cargoCommand(...command);
|
||||
yield {
|
||||
success,
|
||||
};
|
||||
}
|
7
packages/rust/src/executors/test/schema.d.ts
vendored
Normal file
7
packages/rust/src/executors/test/schema.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { BaseOptions } from '../../models/base-options';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface TestExecutorSchema extends BaseOptions {
|
||||
'no-run'?: boolean;
|
||||
'no-fail-fast'?: boolean;
|
||||
}
|
160
packages/rust/src/executors/test/schema.json
Normal file
160
packages/rust/src/executors/test/schema.json
Normal file
@ -0,0 +1,160 @@
|
||||
{
|
||||
"version": 2,
|
||||
"outputCapture": "pipe",
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Test executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"no-run": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"no-fail-fast": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile": {
|
||||
"type": "string"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"toolchain": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stable",
|
||||
"beta",
|
||||
"nightly"
|
||||
],
|
||||
"default": "stable"
|
||||
},
|
||||
"features": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Features of workspace members may be enabled with package-name/feature-name syntax. Array of names is supported"
|
||||
},
|
||||
"all-features": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all binary targets"
|
||||
},
|
||||
"lib": {
|
||||
"type": "boolean",
|
||||
"description": "Build the package's library",
|
||||
"default": false
|
||||
},
|
||||
"bin": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified binary. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"bins": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all binary targets"
|
||||
},
|
||||
"example": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified example. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"examples": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all example targets"
|
||||
},
|
||||
"test": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified test. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"tests": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all test targets"
|
||||
},
|
||||
"bench": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "Build the specified bench. Array of names or common Unix glob patterns is supported"
|
||||
},
|
||||
"benches": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all targets in benchmark mode that have the bench = true manifest flag set. By default this includes the library and binaries built as benchmarks, and bench targets. Be aware that this will also build any required dependencies, so the lib target may be built twice (once as a benchmark, and once as a dependency for binaries, benchmarks, etc.). Targets may be enabled or disabled by setting the bench flag in the manifest settings for the target."
|
||||
},
|
||||
"all-targets": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Build all test targets"
|
||||
},
|
||||
"args": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "Extra arguments. You can pass them as follows: nx run project:run --args='--wait=100'."
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
11
packages/rust/src/executors/wasm-pack/executor.spec.ts
Normal file
11
packages/rust/src/executors/wasm-pack/executor.spec.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { WasmPackExecutorSchema } from './schema';
|
||||
import executor from './executor';
|
||||
|
||||
|
||||
|
||||
xdescribe('Wasm Executor', () => {
|
||||
it('can run', async () => {
|
||||
// const output = await executor(options);
|
||||
// expect(output.success).toBe(true);
|
||||
});
|
||||
});
|
29
packages/rust/src/executors/wasm-pack/executor.ts
Normal file
29
packages/rust/src/executors/wasm-pack/executor.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import { buildCommand } from '../../utils/build-command';
|
||||
import { runProcess } from '../../utils/run-process';
|
||||
import { WasmPackExecutorSchema } from './schema';
|
||||
|
||||
interface WasmPackOptions extends Omit<WasmPackExecutorSchema, 'target-dir'> {
|
||||
'out-dir': string;
|
||||
}
|
||||
|
||||
export default async function runExecutor(
|
||||
options: WasmPackExecutorSchema,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const wasmPackOptions = wasmPackArgs(options);
|
||||
const args = buildCommand('build', wasmPackOptions, context);
|
||||
return runWasmPack(...args);
|
||||
}
|
||||
|
||||
function runWasmPack(...args: string[]) {
|
||||
return runProcess('wasm-pack', ...args);
|
||||
}
|
||||
|
||||
function wasmPackArgs(options: WasmPackExecutorSchema): WasmPackOptions {
|
||||
return {
|
||||
release: options.release,
|
||||
target: options.target,
|
||||
'out-dir': options['target-dir'],
|
||||
};
|
||||
}
|
5
packages/rust/src/executors/wasm-pack/schema.d.ts
vendored
Normal file
5
packages/rust/src/executors/wasm-pack/schema.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export interface WasmPackExecutorSchema {
|
||||
['target-dir']: string;
|
||||
target: 'bundler' | 'nodejs' | 'web' | 'no-module';
|
||||
release: boolean;
|
||||
}
|
27
packages/rust/src/executors/wasm-pack/schema.json
Normal file
27
packages/rust/src/executors/wasm-pack/schema.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"title": "Wasm Pack executor",
|
||||
"description": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"release": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"target": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bundler",
|
||||
"nodejs",
|
||||
"web",
|
||||
"no-module"
|
||||
],
|
||||
"default": "bundler"
|
||||
},
|
||||
"target-dir": {
|
||||
"type": "string",
|
||||
"default": "pkg"
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
extern crate napi_build;
|
||||
|
||||
fn main() {
|
||||
napi_build::setup();
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/* auto-generated by NAPI-RS */
|
||||
|
||||
export function sum(a: number, b: number): number
|
251
packages/rust/src/generators/add-napi/files/index.js__template__
Normal file
251
packages/rust/src/generators/add-napi/files/index.js__template__
Normal file
@ -0,0 +1,251 @@
|
||||
const { existsSync, readFileSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
|
||||
const { platform, arch } = process
|
||||
|
||||
let nativeBinding = null
|
||||
let localFileExisted = false
|
||||
let loadError = null
|
||||
|
||||
function isMusl() {
|
||||
// For Node 10
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
try {
|
||||
const lddPath = require('child_process').execSync('which ldd').toString().trim();
|
||||
return readFileSync(lddPath, 'utf8').includes('musl')
|
||||
} catch (e) {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
return !glibcVersionRuntime
|
||||
}
|
||||
}
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
switch (arch) {
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, '<%= projectName %>.android-arm64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.android-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-android-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(join(__dirname, '<%= projectName %>.android-arm-eabi.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.android-arm-eabi.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-android-arm-eabi')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Android ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.win32-x64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.win32-x64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-win32-x64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.win32-ia32-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.win32-ia32-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-win32-ia32-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.win32-arm64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.win32-arm64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-win32-arm64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'darwin':
|
||||
localFileExisted = existsSync(join(__dirname, '<%= projectName %>.darwin-universal.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.darwin-universal.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-darwin-universal')
|
||||
}
|
||||
break
|
||||
} catch {}
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, '<%= projectName %>.darwin-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.darwin-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-darwin-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.darwin-arm64.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.darwin-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-darwin-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, '<%= projectName %>.freebsd-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.freebsd-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-freebsd-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.linux-x64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.linux-x64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-linux-x64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.linux-x64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.linux-x64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-linux-x64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.linux-arm64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.linux-arm64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-linux-arm64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.linux-arm64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.linux-arm64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-linux-arm64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, '<%= projectName %>.linux-arm-gnueabihf.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./<%= projectName %>.linux-arm-gnueabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('<%= packageName %>-linux-arm-gnueabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
||||
}
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError
|
||||
}
|
||||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { sum } = nativeBinding
|
||||
|
||||
module.exports.sum = sum
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "<%= packageName %>",
|
||||
"version": "0.0.0",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"napi": {
|
||||
"binaryName": "<%= projectName %>",
|
||||
"packageName": "<%= packageName %>",
|
||||
"targets": [
|
||||
"aarch64-apple-darwin",
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"aarch64-pc-windows-msvc",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-apple-darwin",
|
||||
"i686-pc-windows-msvc",
|
||||
"wasm32-wasip1-threads"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate napi_derive;
|
||||
|
||||
#[napi]
|
||||
pub fn sum(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
91
packages/rust/src/generators/add-napi/generator.spec.ts
Normal file
91
packages/rust/src/generators/add-napi/generator.spec.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { Tree, readProjectConfiguration } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
|
||||
import libraryGenerator from '../library/generator';
|
||||
import generator from './generator';
|
||||
import { AddNapiGeneratorSchema } from './schema';
|
||||
|
||||
jest.mock('@nx/devkit', (): typeof import('@nx/devkit') => {
|
||||
const originalModule = jest.requireActual('@nx/devkit');
|
||||
return {
|
||||
...originalModule,
|
||||
ensurePackage: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('add-napi generator', () => {
|
||||
let appTree: Tree;
|
||||
const options: AddNapiGeneratorSchema = { project: 'test' };
|
||||
|
||||
beforeEach(async () => {
|
||||
appTree = createTreeWithEmptyWorkspace();
|
||||
await libraryGenerator(appTree, { name: 'test' });
|
||||
});
|
||||
|
||||
it('should update the Cargo.toml file', async () => {
|
||||
await generator(appTree, options);
|
||||
const cargoString = appTree.read('./test/Cargo.toml')?.toString() ?? '';
|
||||
expect(cargoString).toMatchInlineSnapshot(`
|
||||
"
|
||||
[package]
|
||||
name = 'test'
|
||||
version = '0.1.0'
|
||||
edition = '2021'
|
||||
|
||||
[dependencies]
|
||||
napi = { version = '2.10.2', default-features = false, features = [
|
||||
'napi4',
|
||||
] }
|
||||
napi-derive = '2.9.3'
|
||||
|
||||
[lib]
|
||||
crate-type = [
|
||||
'cdylib',
|
||||
]
|
||||
|
||||
[build-dependencies]
|
||||
napi-build = '2.0.1'
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should update the base tsconfig file', async () => {
|
||||
await generator(appTree, options);
|
||||
expect(JSON.parse(appTree.read('tsconfig.base.json')?.toString() ?? ''))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"compilerOptions": Object {
|
||||
"paths": Object {
|
||||
"@proj/test": Array [
|
||||
"test/index.d.ts",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should update a project', async () => {
|
||||
await generator(appTree, options);
|
||||
const project = readProjectConfiguration(appTree, 'test');
|
||||
expect(project.targets?.build).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"cache": true,
|
||||
"configurations": Object {
|
||||
"production": Object {
|
||||
"dist": "dist/test",
|
||||
"release": true,
|
||||
},
|
||||
},
|
||||
"executor": "@loafle/nx-rust:napi",
|
||||
"options": Object {
|
||||
"dist": "test",
|
||||
"jsFile": "index.js",
|
||||
},
|
||||
"outputs": Array [
|
||||
"{workspaceRoot}/test",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
205
packages/rust/src/generators/add-napi/generator.ts
Normal file
205
packages/rust/src/generators/add-napi/generator.ts
Normal file
@ -0,0 +1,205 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
ProjectConfiguration,
|
||||
readJson,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
modifyCargoTable,
|
||||
parseCargoTomlWithTree,
|
||||
stringifyCargoToml,
|
||||
} from '../../utils/toml';
|
||||
import {
|
||||
NAPI_EMNAPI,
|
||||
NAPI_VERSION,
|
||||
NAPI_WASM_RUNTIME,
|
||||
} from '../../utils/versions';
|
||||
import { AddNapiGeneratorSchema } from './schema';
|
||||
|
||||
interface NormalizedSchema extends AddNapiGeneratorSchema {
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
packageName: string;
|
||||
offsetFromRoot: string;
|
||||
dryRun?: boolean;
|
||||
}
|
||||
|
||||
export default async function (tree: Tree, options: AddNapiGeneratorSchema) {
|
||||
const project = getProjects(tree).get(options.project);
|
||||
if (!project) {
|
||||
throw 'Project not found';
|
||||
}
|
||||
|
||||
const normalizedOptions = normalizeOptions(tree, options, project);
|
||||
addFiles(tree, normalizedOptions);
|
||||
updateCargo(tree, normalizedOptions);
|
||||
const addPackage = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@napi-rs/cli': NAPI_VERSION,
|
||||
'@napi-rs/wasm-runtime': NAPI_WASM_RUNTIME,
|
||||
emnapi: NAPI_EMNAPI,
|
||||
}
|
||||
);
|
||||
updateGitIgnore(tree);
|
||||
updateTsConfig(tree, normalizedOptions);
|
||||
updateProjectConfiguration(tree, normalizedOptions.projectName, {
|
||||
...project,
|
||||
targets: {
|
||||
...project.targets,
|
||||
build: {
|
||||
cache: true,
|
||||
outputs: [`{workspaceRoot}/${normalizedOptions.projectRoot}`],
|
||||
executor: '@loafle/nx-rust:napi',
|
||||
options: {
|
||||
dist: normalizedOptions.projectRoot,
|
||||
jsFile: 'index.js',
|
||||
},
|
||||
configurations: {
|
||||
production: {
|
||||
dist: `dist/${normalizedOptions.projectName}`,
|
||||
release: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await formatFiles(tree);
|
||||
|
||||
return async () => {
|
||||
await addPackage();
|
||||
const { NapiCli } = await import('@napi-rs/cli');
|
||||
const napi = new NapiCli();
|
||||
|
||||
await napi.createNpmDirs({
|
||||
npmDir: `${normalizedOptions.projectRoot}/npm`,
|
||||
packageJsonPath: `${normalizedOptions.projectRoot}/package.json`,
|
||||
dryRun: normalizedOptions.dryRun,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: AddNapiGeneratorSchema,
|
||||
project: ProjectConfiguration
|
||||
): NormalizedSchema {
|
||||
const npmScope = getNpmScope(tree);
|
||||
const projectName = project.name ?? options.project;
|
||||
const packageName = npmScope
|
||||
? `@${npmScope}/${names(projectName).fileName}`
|
||||
: projectName;
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
projectRoot: project.root,
|
||||
packageName,
|
||||
offsetFromRoot: offsetFromRoot(project.root),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the npm scope that a workspace should use by default
|
||||
*/
|
||||
function getNpmScope(tree: Tree) {
|
||||
const { name } = tree.exists('package.json')
|
||||
? readJson(tree, 'package.json')
|
||||
: { name: null };
|
||||
if (name?.startsWith('@')) {
|
||||
return name.split('/')[0].substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
function getRootTsConfigPathInTree(tree: Tree) {
|
||||
for (const path of ['tsconfig.base.json', 'tsconfig.json']) {
|
||||
if (tree.exists(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return 'tsconfig.base.json';
|
||||
}
|
||||
|
||||
function addFiles(tree: Tree, options: NormalizedSchema) {
|
||||
const templateOptions = {
|
||||
...options,
|
||||
...names(options.project),
|
||||
template: '',
|
||||
};
|
||||
generateFiles(
|
||||
tree,
|
||||
path.join(__dirname, 'files'),
|
||||
options.projectRoot,
|
||||
templateOptions
|
||||
);
|
||||
}
|
||||
|
||||
function updateCargo(tree: Tree, options: NormalizedSchema) {
|
||||
const cargoToml = parseCargoTomlWithTree(
|
||||
tree,
|
||||
options.projectRoot,
|
||||
options.projectName
|
||||
);
|
||||
|
||||
modifyCargoTable(cargoToml, 'lib', 'crate-type', ['cdylib']);
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'napi', {
|
||||
version: '2.10.2',
|
||||
'default-features': false,
|
||||
features: ['napi4'],
|
||||
});
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'napi-derive', '2.9.3');
|
||||
modifyCargoTable(cargoToml, 'build-dependencies', 'napi-build', '2.0.1');
|
||||
|
||||
tree.write(
|
||||
options.projectRoot + '/Cargo.toml',
|
||||
stringifyCargoToml(cargoToml)
|
||||
);
|
||||
}
|
||||
|
||||
function updateGitIgnore(tree: Tree) {
|
||||
if (!tree.exists('.gitignore')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let gitIgnore = tree.read('.gitignore')?.toString() ?? '';
|
||||
gitIgnore += '\n*.node';
|
||||
tree.write('.gitignore', gitIgnore);
|
||||
}
|
||||
|
||||
function updateTsConfig(tree: Tree, options: NormalizedSchema) {
|
||||
if (!tree.exists('tsconfig.base.json')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tsConfig = getRootTsConfigPathInTree(tree);
|
||||
|
||||
if (!tsConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateJson(tree, tsConfig, (json) => {
|
||||
const c = json.compilerOptions;
|
||||
c.paths = c.paths || {};
|
||||
|
||||
if (c.paths[options.packageName]) {
|
||||
throw new Error(
|
||||
`You already have a library using the import path "${options.packageName}". Make sure to specify a unique one.`
|
||||
);
|
||||
}
|
||||
|
||||
c.paths[options.packageName] = [
|
||||
joinPathFragments(options.projectRoot, 'index.d.ts'),
|
||||
];
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
3
packages/rust/src/generators/add-napi/schema.d.ts
vendored
Normal file
3
packages/rust/src/generators/add-napi/schema.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export interface AddNapiGeneratorSchema {
|
||||
project: string;
|
||||
}
|
16
packages/rust/src/generators/add-napi/schema.json
Normal file
16
packages/rust/src/generators/add-napi/schema.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "AddNapi",
|
||||
"title": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project": {
|
||||
"description": "The name of the project",
|
||||
"$default": {
|
||||
"$source": "projectName",
|
||||
"index": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
@ -0,0 +1 @@
|
||||
const variable = "<%= projectName %>";
|
@ -0,0 +1,20 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Tree, readProjectConfiguration } from '@nx/devkit';
|
||||
|
||||
import generator from './generator';
|
||||
import { AddWasmReferenceGeneratorSchema } from './schema';
|
||||
|
||||
describe('add-wasm-reference generator', () => {
|
||||
let appTree: Tree;
|
||||
const options: AddWasmReferenceGeneratorSchema = { name: 'test' };
|
||||
|
||||
beforeEach(() => {
|
||||
appTree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should run successfully', async () => {
|
||||
await generator(appTree, options);
|
||||
const config = readProjectConfiguration(appTree, 'test');
|
||||
expect(config).toBeDefined();
|
||||
});
|
||||
});
|
76
packages/rust/src/generators/add-wasm-reference/generator.ts
Normal file
76
packages/rust/src/generators/add-wasm-reference/generator.ts
Normal file
@ -0,0 +1,76 @@
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
getWorkspaceLayout,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import * as path from 'path';
|
||||
import { AddWasmReferenceGeneratorSchema } from './schema';
|
||||
|
||||
interface NormalizedSchema extends AddWasmReferenceGeneratorSchema {
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
}
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: AddWasmReferenceGeneratorSchema
|
||||
): NormalizedSchema {
|
||||
const name = names(options.name).fileName;
|
||||
const projectDirectory = options.directory
|
||||
? `${names(options.directory).fileName}/${name}`
|
||||
: name;
|
||||
const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
const projectRoot = `${getWorkspaceLayout(tree).libsDir}/${projectDirectory}`;
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
projectRoot,
|
||||
projectDirectory,
|
||||
parsedTags,
|
||||
};
|
||||
}
|
||||
|
||||
function addFiles(tree: Tree, options: NormalizedSchema) {
|
||||
const templateOptions = {
|
||||
...options,
|
||||
...names(options.name),
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
template: '',
|
||||
};
|
||||
generateFiles(
|
||||
tree,
|
||||
path.join(__dirname, 'files'),
|
||||
options.projectRoot,
|
||||
templateOptions
|
||||
);
|
||||
}
|
||||
|
||||
export default async function (
|
||||
tree: Tree,
|
||||
options: AddWasmReferenceGeneratorSchema
|
||||
) {
|
||||
const normalizedOptions = normalizeOptions(tree, options);
|
||||
addProjectConfiguration(tree, normalizedOptions.projectName, {
|
||||
root: normalizedOptions.projectRoot,
|
||||
projectType: 'library',
|
||||
sourceRoot: `${normalizedOptions.projectRoot}/src`,
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@loafle/nx-rust:build',
|
||||
},
|
||||
},
|
||||
tags: normalizedOptions.parsedTags,
|
||||
});
|
||||
addFiles(tree, normalizedOptions);
|
||||
await formatFiles(tree);
|
||||
}
|
5
packages/rust/src/generators/add-wasm-reference/schema.d.ts
vendored
Normal file
5
packages/rust/src/generators/add-wasm-reference/schema.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export interface AddWasmReferenceGeneratorSchema {
|
||||
name: string;
|
||||
tags?: string;
|
||||
directory?: string;
|
||||
}
|
30
packages/rust/src/generators/add-wasm-reference/schema.json
Normal file
30
packages/rust/src/generators/add-wasm-reference/schema.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "AddWasmReference",
|
||||
"title": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use?"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
"description": "Add tags to the project (used for linting)",
|
||||
"alias": "t"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string",
|
||||
"description": "A directory where the project is placed",
|
||||
"alias": "d"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
mod utils;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
<%_ if (useWebSys) { _%>
|
||||
use web_sys::window;
|
||||
<%_ } _%>
|
||||
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = "wee_alloc")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
<%_ if (!useWebSys) { _%>
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn alert(s: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn greet() {
|
||||
alert("Hello, <%= projectName %>!");
|
||||
}
|
||||
<%_ } _%>
|
||||
<%_ if (useWebSys) { _%>
|
||||
#[wasm_bindgen]
|
||||
pub fn greet() -> Result<(), JsValue> {
|
||||
window()
|
||||
.ok_or("no window")?
|
||||
.alert_with_message("Hello, world!")
|
||||
}
|
||||
<%_ } _%>
|
@ -0,0 +1,10 @@
|
||||
pub fn set_panic_hook() {
|
||||
// When the `console_error_panic_hook` feature is enabled, we can call the
|
||||
// `set_panic_hook` function at least once during initialization, and then
|
||||
// we will get better error messages if our code ever panics.
|
||||
//
|
||||
// For more details see
|
||||
// https://github.com/rustwasm/console_error_panic_hook#readme
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
141
packages/rust/src/generators/add-wasm/generator.spec.ts
Normal file
141
packages/rust/src/generators/add-wasm/generator.spec.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import { Tree } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import libraryGenerator from '../library/generator';
|
||||
import generator from './generator';
|
||||
import { AddWasmGeneratorSchema } from './schema';
|
||||
|
||||
describe('add-wasm generator', () => {
|
||||
let appTree: Tree;
|
||||
const options: AddWasmGeneratorSchema = {
|
||||
project: 'test_lib',
|
||||
generateDefaultLib: true,
|
||||
useWebSys: false,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
appTree = createTreeWithEmptyWorkspace();
|
||||
await libraryGenerator(appTree, {
|
||||
name: 'test_lib',
|
||||
});
|
||||
});
|
||||
|
||||
it('should add wasm to an existing library', async () => {
|
||||
await generator(appTree, options);
|
||||
const lib = appTree.read('./test_lib/src/lib.rs')?.toString();
|
||||
expect(lib).toMatchInlineSnapshot(`
|
||||
"mod utils;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// When the \`wee_alloc\` feature is enabled, use \`wee_alloc\` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = \\"wee_alloc\\")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern {
|
||||
fn alert(s: &str);
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn greet() {
|
||||
alert(\\"Hello, test_lib!\\");
|
||||
}
|
||||
"
|
||||
`);
|
||||
|
||||
const cargoString = appTree.read('./test_lib/Cargo.toml')?.toString() ?? '';
|
||||
expect(cargoString).toMatchInlineSnapshot(`
|
||||
"
|
||||
[package]
|
||||
name = 'test_lib'
|
||||
version = '0.1.0'
|
||||
edition = '2021'
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = '0.2'
|
||||
console_error_panic_hook = { version = '0.1.6', optional = true }
|
||||
wee_alloc = { version = '0.4', optional = true }
|
||||
|
||||
[lib]
|
||||
crate-type = [
|
||||
'cdylib',
|
||||
'rlib',
|
||||
]
|
||||
|
||||
[feature]
|
||||
default = [
|
||||
'console_error_panic_hook',
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = '0.3'
|
||||
|
||||
[profile.release]
|
||||
opt-level = 's' #Tell \`rustc\` to optimize for small code size.
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add wasm to an existing library with webSys', async () => {
|
||||
await generator(appTree, { ...options, useWebSys: true });
|
||||
const lib = appTree.read('./test_lib/src/lib.rs')?.toString();
|
||||
expect(lib).toMatchInlineSnapshot(`
|
||||
"mod utils;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::window;
|
||||
|
||||
// When the \`wee_alloc\` feature is enabled, use \`wee_alloc\` as the global
|
||||
// allocator.
|
||||
#[cfg(feature = \\"wee_alloc\\")]
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn greet() -> Result<(), JsValue> {
|
||||
window()
|
||||
.ok_or(\\"no window\\")?
|
||||
.alert_with_message(\\"Hello, world!\\")
|
||||
}
|
||||
"
|
||||
`);
|
||||
|
||||
const cargoString = appTree.read('./test_lib/Cargo.toml')?.toString() ?? '';
|
||||
expect(cargoString).toMatchInlineSnapshot(`
|
||||
"
|
||||
[package]
|
||||
name = 'test_lib'
|
||||
version = '0.1.0'
|
||||
edition = '2021'
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = '0.2'
|
||||
js-sys = '0.3'
|
||||
web-sys = { version = '0.3', features = [
|
||||
'Window',
|
||||
] }
|
||||
console_error_panic_hook = { version = '0.1.6', optional = true }
|
||||
wee_alloc = { version = '0.4', optional = true }
|
||||
|
||||
[lib]
|
||||
crate-type = [
|
||||
'cdylib',
|
||||
'rlib',
|
||||
]
|
||||
|
||||
[feature]
|
||||
default = [
|
||||
'console_error_panic_hook',
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = '0.3'
|
||||
|
||||
[profile.release]
|
||||
opt-level = 's' #Tell \`rustc\` to optimize for small code size.
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
126
packages/rust/src/generators/add-wasm/generator.ts
Normal file
126
packages/rust/src/generators/add-wasm/generator.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import TOML from '@ltd/j-toml';
|
||||
import {
|
||||
Tree,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
offsetFromRoot,
|
||||
readProjectConfiguration,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import * as path from 'path';
|
||||
import { addWasmPackExecutor } from '../../utils/add-executors';
|
||||
import {
|
||||
modifyCargoNestedTable,
|
||||
modifyCargoTable,
|
||||
parseCargoTomlWithTree,
|
||||
stringifyCargoToml,
|
||||
} from '../../utils/toml';
|
||||
import { AddWasmGeneratorSchema } from './schema';
|
||||
|
||||
interface NormalizedSchema extends AddWasmGeneratorSchema {
|
||||
projectName: string;
|
||||
projectRoot: string;
|
||||
}
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
options: AddWasmGeneratorSchema
|
||||
): NormalizedSchema {
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
|
||||
const projectName = project.name ?? options.project ?? '';
|
||||
const projectRoot = project.root;
|
||||
|
||||
return {
|
||||
...options,
|
||||
projectName,
|
||||
projectRoot,
|
||||
};
|
||||
}
|
||||
|
||||
function addFiles(tree: Tree, options: NormalizedSchema) {
|
||||
if (!options.generateDefaultLib) {
|
||||
return;
|
||||
}
|
||||
|
||||
const templateOptions = {
|
||||
...options,
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
template: '',
|
||||
};
|
||||
generateFiles(
|
||||
tree,
|
||||
path.join(__dirname, 'files'),
|
||||
options.projectRoot,
|
||||
templateOptions
|
||||
);
|
||||
}
|
||||
|
||||
function updateCargo(tree: Tree, options: NormalizedSchema) {
|
||||
const cargoToml = parseCargoTomlWithTree(
|
||||
tree,
|
||||
options.projectRoot,
|
||||
options.projectName
|
||||
);
|
||||
|
||||
modifyCargoTable(cargoToml, 'lib', 'crate-type', ['cdylib', 'rlib']);
|
||||
|
||||
modifyCargoTable(cargoToml, 'feature', 'default', [
|
||||
'console_error_panic_hook',
|
||||
]);
|
||||
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'wasm-bindgen', '0.2');
|
||||
|
||||
if (options.useWebSys) {
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'js-sys', '0.3');
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'web-sys', {
|
||||
version: '0.3',
|
||||
features: ['Window'],
|
||||
});
|
||||
}
|
||||
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'console_error_panic_hook', {
|
||||
version: '0.1.6',
|
||||
optional: true,
|
||||
});
|
||||
|
||||
modifyCargoTable(cargoToml, 'dependencies', 'wee_alloc', {
|
||||
version: '0.4',
|
||||
optional: true,
|
||||
});
|
||||
|
||||
modifyCargoTable(cargoToml, 'dev-dependencies', 'wasm-bindgen-test', '0.3');
|
||||
|
||||
modifyCargoNestedTable(cargoToml, 'profile', 'release', {
|
||||
[TOML.commentFor('opt-level')]:
|
||||
'Tell `rustc` to optimize for small code size.',
|
||||
'opt-level': 's',
|
||||
});
|
||||
|
||||
tree.write(
|
||||
options.projectRoot + '/Cargo.toml',
|
||||
stringifyCargoToml(cargoToml)
|
||||
);
|
||||
}
|
||||
|
||||
function updateBuildTarget(tree: Tree, options: NormalizedSchema) {
|
||||
const configuration = readProjectConfiguration(tree, options.projectName);
|
||||
configuration.targets ??= {};
|
||||
configuration.targets.build = addWasmPackExecutor({
|
||||
'target-dir': `dist/target/wasm/${options.projectName}`,
|
||||
release: false,
|
||||
target: 'bundler',
|
||||
});
|
||||
updateProjectConfiguration(tree, options.projectName, configuration);
|
||||
}
|
||||
|
||||
export default async function wasmGenerator(
|
||||
tree: Tree,
|
||||
options: AddWasmGeneratorSchema
|
||||
) {
|
||||
const normalizedOptions = normalizeOptions(tree, options);
|
||||
addFiles(tree, normalizedOptions);
|
||||
updateCargo(tree, normalizedOptions);
|
||||
updateBuildTarget(tree, normalizedOptions);
|
||||
await formatFiles(tree);
|
||||
}
|
5
packages/rust/src/generators/add-wasm/schema.d.ts
vendored
Normal file
5
packages/rust/src/generators/add-wasm/schema.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export interface AddWasmGeneratorSchema {
|
||||
project: string;
|
||||
useWebSys: boolean;
|
||||
generateDefaultLib: boolean;
|
||||
}
|
29
packages/rust/src/generators/add-wasm/schema.json
Normal file
29
packages/rust/src/generators/add-wasm/schema.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "AddWasm",
|
||||
"title": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The name of the project",
|
||||
"$default": {
|
||||
"$source": "projectName",
|
||||
"index": 0
|
||||
}
|
||||
},
|
||||
"useWebSys": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Use the web sys package"
|
||||
},
|
||||
"generateDefaultLib": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Generates a default lib that contains wasm code. This will over write the existing lib.rs file."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"project"
|
||||
]
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "<%= projectName %>"
|
||||
version = "0.1.0"
|
||||
edition = "<%= edition %>"
|
||||
|
||||
|
||||
[dependencies]
|
||||
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
87
packages/rust/src/generators/binary/generator.spec.ts
Normal file
87
packages/rust/src/generators/binary/generator.spec.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Tree, readProjectConfiguration } from '@nx/devkit';
|
||||
import TOML from '@ltd/j-toml';
|
||||
import generator from './generator';
|
||||
import { RustBinaryGeneratorSchema } from './schema';
|
||||
|
||||
describe('rust generator', () => {
|
||||
let appTree: Tree;
|
||||
const options: RustBinaryGeneratorSchema = { name: 'test-name' };
|
||||
|
||||
beforeEach(() => {
|
||||
appTree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should run successfully', async () => {
|
||||
await generator(appTree, options);
|
||||
const config = readProjectConfiguration(appTree, 'test_name');
|
||||
expect(config).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a Cargo.toml project', async () => {
|
||||
await generator(appTree, { ...options });
|
||||
const cargoToml = appTree.read('./test_name/Cargo.toml')?.toString() ?? '';
|
||||
expect(cargoToml.length).toBeGreaterThan(0);
|
||||
expect(TOML.parse(cargoToml)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"dependencies": Object {},
|
||||
"package": Object {
|
||||
"edition": "2021",
|
||||
"name": "test_name",
|
||||
"version": "0.1.0",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create a project with a specified edition', async () => {
|
||||
await generator(appTree, { ...options, edition: '2018' });
|
||||
const cargoToml = appTree.read('./test_name/Cargo.toml')?.toString() ?? '';
|
||||
expect(TOML.parse(cargoToml)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"dependencies": Object {},
|
||||
"package": Object {
|
||||
"edition": "2018",
|
||||
"name": "test_name",
|
||||
"version": "0.1.0",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add a project to the main Cargo.toml workspace members', async () => {
|
||||
await generator(appTree, options);
|
||||
const cargoToml = appTree.read('Cargo.toml')?.toString() ?? '';
|
||||
expect(TOML.parse(cargoToml)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"profile": Object {
|
||||
"release": Object {
|
||||
"lto": true,
|
||||
},
|
||||
},
|
||||
"workspace": Object {
|
||||
"members": Array [
|
||||
"test_name",
|
||||
],
|
||||
"resolver": "2",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate into a directory', async () => {
|
||||
await generator(appTree, { ...options, directory: 'test-dir' });
|
||||
const cargoToml =
|
||||
appTree.read('./test_dir/test_name/Cargo.toml')?.toString() ?? '';
|
||||
expect(TOML.parse(cargoToml)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"dependencies": Object {},
|
||||
"package": Object {
|
||||
"edition": "2021",
|
||||
"name": "test_dir_test_name",
|
||||
"version": "0.1.0",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
63
packages/rust/src/generators/binary/generator.ts
Normal file
63
packages/rust/src/generators/binary/generator.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
names,
|
||||
offsetFromRoot,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
addBuildExecutor,
|
||||
addTestExecutor,
|
||||
addLintExecutor,
|
||||
addRunExecutor,
|
||||
} from '../../utils/add-executors';
|
||||
import { addToCargoWorkspace } from '../../utils/add-to-workspace';
|
||||
import {
|
||||
NormalizedSchema,
|
||||
normalizeOptions,
|
||||
} from '../../utils/normalize-options';
|
||||
import init from '../init/generator';
|
||||
import { RustBinaryGeneratorSchema } from './schema';
|
||||
|
||||
function addFiles(
|
||||
tree: Tree,
|
||||
options: NormalizedSchema & RustBinaryGeneratorSchema
|
||||
) {
|
||||
const templateOptions = {
|
||||
...options,
|
||||
...names(options.name),
|
||||
offsetFromRoot: offsetFromRoot(options.projectRoot),
|
||||
template: '',
|
||||
};
|
||||
generateFiles(
|
||||
tree,
|
||||
path.join(__dirname, 'files'),
|
||||
options.projectRoot,
|
||||
templateOptions
|
||||
);
|
||||
}
|
||||
|
||||
export default async function binaryGenerator(
|
||||
tree: Tree,
|
||||
options: RustBinaryGeneratorSchema
|
||||
) {
|
||||
await init(tree);
|
||||
const normalizedOptions = normalizeOptions(tree, 'app', options);
|
||||
addProjectConfiguration(tree, normalizedOptions.projectName, {
|
||||
root: normalizedOptions.projectRoot,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${normalizedOptions.projectRoot}/src`,
|
||||
targets: {
|
||||
build: addBuildExecutor({ 'target-dir': normalizedOptions.targetDir }),
|
||||
test: addTestExecutor({ 'target-dir': normalizedOptions.targetDir }),
|
||||
lint: addLintExecutor({ 'target-dir': normalizedOptions.targetDir }),
|
||||
run: addRunExecutor({ 'target-dir': normalizedOptions.targetDir }),
|
||||
},
|
||||
tags: normalizedOptions.parsedTags,
|
||||
});
|
||||
addFiles(tree, normalizedOptions);
|
||||
addToCargoWorkspace(tree, normalizedOptions.projectRoot);
|
||||
await formatFiles(tree);
|
||||
}
|
6
packages/rust/src/generators/binary/schema.d.ts
vendored
Normal file
6
packages/rust/src/generators/binary/schema.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export interface RustBinaryGeneratorSchema {
|
||||
name: string;
|
||||
edition?: '2015' | '2018' | '2021';
|
||||
tags?: string;
|
||||
directory?: string;
|
||||
}
|
40
packages/rust/src/generators/binary/schema.json
Normal file
40
packages/rust/src/generators/binary/schema.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "Rust",
|
||||
"title": "",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use?"
|
||||
},
|
||||
"edition": {
|
||||
"type": "string",
|
||||
"description": "The edition of Rust to use for this binary (default is 2021)",
|
||||
"default": "2021",
|
||||
"enum": [
|
||||
"2015",
|
||||
"2018",
|
||||
"2021"
|
||||
]
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
"description": "Add tags to the project (used for linting)",
|
||||
"alias": "t"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string",
|
||||
"description": "A directory where the project is placed",
|
||||
"alias": "d"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
Tree,
|
||||
formatFiles,
|
||||
getPackageManagerCommand,
|
||||
getProjects,
|
||||
joinPathFragments,
|
||||
} from '@nx/devkit';
|
||||
import { CreateNapiNpmDirsGeneratorSchema } from './schema';
|
||||
import { runProcess } from '../../utils/run-process';
|
||||
|
||||
export default async function (
|
||||
tree: Tree,
|
||||
options: CreateNapiNpmDirsGeneratorSchema
|
||||
) {
|
||||
const project = getProjects(tree).get(options.project);
|
||||
if (!project) {
|
||||
throw 'Project not found';
|
||||
}
|
||||
|
||||
addNpmFiles(project);
|
||||
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
function addNpmFiles(project: ProjectConfiguration) {
|
||||
const { exec } = getPackageManagerCommand();
|
||||
const command = `${exec} napi create-npm-dir`;
|
||||
runProcess(
|
||||
command,
|
||||
'-c',
|
||||
joinPathFragments(project.root, 'package.json'),
|
||||
'-t',
|
||||
project.root
|
||||
);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user