@lakutata/cli 2.17.1 → 3.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +455 -28
- package/dist/esm/CLIApp.js +6 -0
- package/dist/esm/Config.js +53 -0
- package/dist/esm/controllers/CommandLineController.js +180 -0
- package/dist/esm/controllers/I18nController.js +67 -0
- package/dist/esm/controllers/MigrationController.js +66 -0
- package/dist/esm/controllers/NativeController.js +41 -0
- package/dist/esm/controllers/PackController.js +88 -0
- package/dist/esm/controllers/WorkspaceController.js +91 -0
- package/dist/esm/dtos/AddPackageDTO.js +25 -0
- package/dist/esm/dtos/BundleDTO.js +29 -0
- package/dist/esm/dtos/CleanDTO.js +17 -0
- package/dist/esm/dtos/CreateProjectDTO.js +61 -0
- package/dist/esm/dtos/ExecutableDTO.js +37 -0
- package/dist/esm/dtos/I18nDTO.js +41 -0
- package/dist/esm/dtos/InstallerDTO.js +33 -0
- package/dist/{options/ListTemplatesOptions.js → esm/dtos/ListTemplatesDTO.js} +5 -14
- package/dist/esm/dtos/MigrationDTO.js +45 -0
- package/dist/esm/dtos/NativeDTO.js +41 -0
- package/dist/esm/dtos/RunScriptDTO.js +33 -0
- package/dist/esm/dtos/VersionDTO.js +29 -0
- package/dist/esm/lib/AddPackage.js +487 -0
- package/dist/esm/lib/Builder.js +21 -0
- package/dist/esm/lib/Clean.js +146 -0
- package/dist/esm/lib/Environment.js +11 -0
- package/dist/esm/lib/I18n.js +67 -0
- package/dist/esm/lib/Language.js +24 -0
- package/dist/esm/lib/Migration.js +94 -0
- package/dist/esm/lib/Output.js +40 -0
- package/dist/esm/lib/Processes.js +54 -0
- package/dist/esm/lib/ProjectCreator.js +191 -0
- package/dist/esm/lib/Registry.js +152 -0
- package/dist/esm/lib/Settings.js +25 -0
- package/dist/esm/lib/Tar.js +145 -0
- package/dist/esm/lib/TemplateCatalog.js +195 -0
- package/dist/esm/lib/TemplateFeatures.js +141 -0
- package/dist/esm/lib/Versions.js +58 -0
- package/dist/esm/lib/native/CMake.js +357 -0
- package/dist/esm/lib/native/Gyp.js +398 -0
- package/dist/esm/lib/native/NativeProject.js +370 -0
- package/dist/esm/lib/native/TextEdits.js +68 -0
- package/dist/esm/lib/native/Toml.js +325 -0
- package/dist/esm/lib/workspace/Run.js +111 -0
- package/dist/esm/lib/workspace/Version.js +144 -0
- package/dist/esm/lib/workspace/Workspace.js +231 -0
- package/dist/esm/locales/zh-CN.json +194 -0
- package/dist/esm/locales/zh-TW.json +194 -0
- package/dist/esm/types/ProcessResult.js +1 -0
- package/package.json +32 -43
- package/CHANGELOG.md +0 -460
- package/dist/CLIApp.d.ts +0 -3
- package/dist/CLIApp.d.ts.map +0 -1
- package/dist/CLIApp.js +0 -45
- package/dist/config/Config.d.ts +0 -3
- package/dist/config/Config.d.ts.map +0 -1
- package/dist/config/Config.js +0 -63
- package/dist/config/SetupCLIEntrypoint.d.ts +0 -3
- package/dist/config/SetupCLIEntrypoint.d.ts.map +0 -1
- package/dist/config/SetupCLIEntrypoint.js +0 -31
- package/dist/controllers/CommandLineController.d.ts +0 -25
- package/dist/controllers/CommandLineController.d.ts.map +0 -1
- package/dist/controllers/CommandLineController.js +0 -78
- package/dist/lib/ConvertDTO2Inquirer.d.ts +0 -3
- package/dist/lib/ConvertDTO2Inquirer.d.ts.map +0 -1
- package/dist/lib/ConvertDTO2Inquirer.js +0 -61
- package/dist/lib/GetDataDirectory.d.ts +0 -2
- package/dist/lib/GetDataDirectory.d.ts.map +0 -1
- package/dist/lib/GetDataDirectory.js +0 -11
- package/dist/lib/GetLocalDataFilename.d.ts +0 -2
- package/dist/lib/GetLocalDataFilename.d.ts.map +0 -1
- package/dist/lib/GetLocalDataFilename.js +0 -12
- package/dist/lib/ListTemplateNames.d.ts +0 -2
- package/dist/lib/ListTemplateNames.d.ts.map +0 -1
- package/dist/lib/ListTemplateNames.js +0 -44
- package/dist/lib/SpecialChar.d.ts +0 -9
- package/dist/lib/SpecialChar.d.ts.map +0 -1
- package/dist/lib/SpecialChar.js +0 -11
- package/dist/lib/components/DeGitPuller.d.ts +0 -19
- package/dist/lib/components/DeGitPuller.d.ts.map +0 -1
- package/dist/lib/components/DeGitPuller.js +0 -65
- package/dist/lib/components/Spinner.d.ts +0 -23
- package/dist/lib/components/Spinner.d.ts.map +0 -1
- package/dist/lib/components/Spinner.js +0 -61
- package/dist/lib/providers/Creator.d.ts +0 -46
- package/dist/lib/providers/Creator.d.ts.map +0 -1
- package/dist/lib/providers/Creator.js +0 -179
- package/dist/lib/providers/Information.d.ts +0 -91
- package/dist/lib/providers/Information.d.ts.map +0 -1
- package/dist/lib/providers/Information.js +0 -225
- package/dist/lib/providers/OnlineLatestVersion.d.ts +0 -14
- package/dist/lib/providers/OnlineLatestVersion.d.ts.map +0 -1
- package/dist/lib/providers/OnlineLatestVersion.js +0 -47
- package/dist/lib/providers/TemplateManager.d.ts +0 -36
- package/dist/lib/providers/TemplateManager.d.ts.map +0 -1
- package/dist/lib/providers/TemplateManager.js +0 -164
- package/dist/options/CreateProjectOptions.d.ts +0 -15
- package/dist/options/CreateProjectOptions.d.ts.map +0 -1
- package/dist/options/CreateProjectOptions.js +0 -94
- package/dist/options/ListTemplatesOptions.d.ts +0 -5
- package/dist/options/ListTemplatesOptions.d.ts.map +0 -1
- package/tsconfig.json +0 -7
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { Workspace } from './workspace/Workspace.js';
|
|
5
|
+
/**
|
|
6
|
+
* The versions of the dependencies of the native addons
|
|
7
|
+
*/
|
|
8
|
+
const NATIVE_VERSIONS = {
|
|
9
|
+
'node-addon-api': '^8.9.2',
|
|
10
|
+
'node-gyp-build': '^4.8.4',
|
|
11
|
+
'node-gyp': '^12.4.0',
|
|
12
|
+
'cmake-js': '^8.0.0',
|
|
13
|
+
'@napi-rs/cli': '^3.10.6'
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The compiler options of the packages (as the ones of the templates), their declarations emitted for the packages
|
|
17
|
+
* depending on them
|
|
18
|
+
* @param outDir
|
|
19
|
+
*/
|
|
20
|
+
function tsConfig(outDir) {
|
|
21
|
+
return `${JSON.stringify({
|
|
22
|
+
compilerOptions: {
|
|
23
|
+
target: 'ES2022',
|
|
24
|
+
lib: ['ES2022'],
|
|
25
|
+
module: 'NodeNext',
|
|
26
|
+
moduleResolution: 'NodeNext',
|
|
27
|
+
rootDir: 'src',
|
|
28
|
+
outDir: outDir,
|
|
29
|
+
declaration: true,
|
|
30
|
+
types: ['node'],
|
|
31
|
+
strict: true,
|
|
32
|
+
esModuleInterop: true,
|
|
33
|
+
skipLibCheck: true
|
|
34
|
+
},
|
|
35
|
+
include: ['src']
|
|
36
|
+
}, null, 2)}\n`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The files of a TypeScript package
|
|
40
|
+
* @param name
|
|
41
|
+
* @param version
|
|
42
|
+
*/
|
|
43
|
+
function libraryFiles(name, version) {
|
|
44
|
+
return {
|
|
45
|
+
'package.json': `${JSON.stringify({
|
|
46
|
+
name: name,
|
|
47
|
+
version: version,
|
|
48
|
+
private: true,
|
|
49
|
+
type: 'module',
|
|
50
|
+
main: 'build/index.js',
|
|
51
|
+
types: 'build/index.d.ts',
|
|
52
|
+
exports: { '.': { types: './build/index.d.ts', default: './build/index.js' } },
|
|
53
|
+
files: ['build', '!build/tests'],
|
|
54
|
+
scripts: {
|
|
55
|
+
clean: 'lakutata clean',
|
|
56
|
+
build: 'tsc',
|
|
57
|
+
rebuild: 'npm run clean && npm run build',
|
|
58
|
+
test: 'node --test "build/tests/**/*.spec.js"'
|
|
59
|
+
}
|
|
60
|
+
}, null, 2)}\n`,
|
|
61
|
+
'tsconfig.json': tsConfig('build'),
|
|
62
|
+
'src/index.ts': `/**
|
|
63
|
+
* Greet someone
|
|
64
|
+
* @param name
|
|
65
|
+
*/
|
|
66
|
+
export function Greet(name: string): string {
|
|
67
|
+
return \`Hello, \${name}\`
|
|
68
|
+
}
|
|
69
|
+
`,
|
|
70
|
+
'src/tests/index.spec.ts': `import {describe, it} from 'node:test'
|
|
71
|
+
import assert from 'node:assert'
|
|
72
|
+
import {Greet} from '../index.js'
|
|
73
|
+
|
|
74
|
+
describe('${name}', (): void => {
|
|
75
|
+
it('greets', (): void => {
|
|
76
|
+
assert.strictEqual(Greet('lakutata'), 'Hello, lakutata')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
`,
|
|
80
|
+
'README.md': `# ${name}\n\n\`\`\`bash\nnpm run rebuild # compile\nnpm test # run the tests\n\`\`\`\n`
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The build files of an addon built by node-gyp: binding.gyp, its options commented
|
|
85
|
+
* @param target
|
|
86
|
+
*/
|
|
87
|
+
function gypFiles(target) {
|
|
88
|
+
return {
|
|
89
|
+
'binding.gyp': `# The build of the addon by node-gyp (gyp: a Python literal, its comments start with #)
|
|
90
|
+
{
|
|
91
|
+
'targets': [
|
|
92
|
+
{
|
|
93
|
+
'target_name': '${target}',
|
|
94
|
+
'sources': ['cpp/binding.cc'],
|
|
95
|
+
# The C++ exceptions of node-addon-api (thrown in JavaScript as errors) on every platform
|
|
96
|
+
'dependencies': ["<!(node -p \\"require('node-addon-api').targets\\"):node_addon_api_except"],
|
|
97
|
+
'defines': ['NAPI_VERSION=8'],
|
|
98
|
+
'include_dirs': [
|
|
99
|
+
# The headers of the addon and of its libraries: 'deps/include'
|
|
100
|
+
],
|
|
101
|
+
'libraries': [
|
|
102
|
+
# The libraries of the addon (lakutata native link writes them, or by hand):
|
|
103
|
+
# A library of the system: '-lpcap' (Linux, macOS), 'ws2_32.lib' (Windows, in its condition below)
|
|
104
|
+
# A static library of the package: '<(module_root_dir)/deps/lib/libfoo.a'
|
|
105
|
+
# A library found by pkg-config: '<!@(pkg-config --libs libpcap)' (its headers in include_dirs:
|
|
106
|
+
# '<!@(pkg-config --cflags-only-I libpcap | sed s/-I//g)')
|
|
107
|
+
# A dynamic library shipped with the addon (deps/lib/libfoo.so, .dylib): '-L<(module_root_dir)/deps/lib', '-lfoo',
|
|
108
|
+
# copied next to the addon (copies below) and found there at run time (the rpath of the conditions below)
|
|
109
|
+
],
|
|
110
|
+
# 'copies': [{'destination': '<(PRODUCT_DIR)', 'files': ['<(module_root_dir)/deps/lib/libfoo.so']}],
|
|
111
|
+
'conditions': [
|
|
112
|
+
['OS=="mac"', {
|
|
113
|
+
'xcode_settings': {
|
|
114
|
+
'MACOSX_DEPLOYMENT_TARGET': '11.0',
|
|
115
|
+
# One addon for the Macs with Intel and with Apple silicon
|
|
116
|
+
'OTHER_CFLAGS': ['-arch x86_64', '-arch arm64'],
|
|
117
|
+
'OTHER_LDFLAGS': [
|
|
118
|
+
'-arch x86_64', '-arch arm64',
|
|
119
|
+
# The dynamic libraries shipped with the addon, found next to it: '-Wl,-rpath,@loader_path'
|
|
120
|
+
# A framework of the system: '-framework CoreFoundation'
|
|
121
|
+
],
|
|
122
|
+
# The standard of C++: 'CLANG_CXX_LANGUAGE_STANDARD': 'c++20'
|
|
123
|
+
}
|
|
124
|
+
}],
|
|
125
|
+
['OS=="linux"', {
|
|
126
|
+
'ldflags': [
|
|
127
|
+
# The dynamic libraries shipped with the addon, found next to it: "-Wl,-rpath,'$$ORIGIN'"
|
|
128
|
+
],
|
|
129
|
+
# The standard of C++: 'cflags_cc': ['-std=c++20']
|
|
130
|
+
}],
|
|
131
|
+
['OS=="win"', {
|
|
132
|
+
'msvs_settings': {
|
|
133
|
+
'VCCLCompilerTool': {
|
|
134
|
+
'AdditionalOptions': ['/utf-8']
|
|
135
|
+
# The standard of C++: '/std:c++20'
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
'libraries': [
|
|
139
|
+
# A library of the system: 'ws2_32.lib', 'iphlpapi.lib'
|
|
140
|
+
# A static library of the package: '<(module_root_dir)/deps/lib/foo.lib'
|
|
141
|
+
# A DLL shipped with the addon (deps/lib/foo.dll): its import library '<(module_root_dir)/deps/lib/foo.lib',
|
|
142
|
+
# the DLL copied next to the addon (copies below), where Windows finds it at run time
|
|
143
|
+
],
|
|
144
|
+
# 'copies': [{'destination': '<(PRODUCT_DIR)', 'files': ['<(module_root_dir)/deps/lib/foo.dll']}]
|
|
145
|
+
}]
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
`,
|
|
151
|
+
'cpp/binding.cc': cppBinding(target)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The build files of an addon built by cmake-js: CMakeLists.txt, its options commented
|
|
156
|
+
* @param target
|
|
157
|
+
*/
|
|
158
|
+
function cMakeFiles(target) {
|
|
159
|
+
return {
|
|
160
|
+
'CMakeLists.txt': `# The build of the addon by cmake-js (npm run build:native)
|
|
161
|
+
cmake_minimum_required(VERSION 3.15)
|
|
162
|
+
cmake_policy(SET CMP0091 NEW)
|
|
163
|
+
cmake_policy(SET CMP0042 NEW)
|
|
164
|
+
|
|
165
|
+
# One addon for the Macs with Intel and with Apple silicon (forced: cmake-js gives the architecture of the machine)
|
|
166
|
+
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "The architectures of macOS" FORCE)
|
|
167
|
+
set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
|
|
168
|
+
|
|
169
|
+
project(${target})
|
|
170
|
+
|
|
171
|
+
# The standard of C++: the headers of Node.js (and node-addon-api) need C++20, as node-gyp gives it
|
|
172
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
173
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
174
|
+
|
|
175
|
+
add_library(\${PROJECT_NAME} SHARED cpp/binding.cc \${CMAKE_JS_SRC})
|
|
176
|
+
set_target_properties(\${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
|
|
177
|
+
|
|
178
|
+
# The headers of Node.js and of node-addon-api; the C++ exceptions thrown in JavaScript as errors
|
|
179
|
+
execute_process(COMMAND node -p "require('node-addon-api').include" WORKING_DIRECTORY \${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE NODE_ADDON_API_DIR)
|
|
180
|
+
string(REGEX REPLACE "[\\r\\n\\"]" "" NODE_ADDON_API_DIR \${NODE_ADDON_API_DIR})
|
|
181
|
+
target_include_directories(\${PROJECT_NAME} PRIVATE \${CMAKE_JS_INC} \${NODE_ADDON_API_DIR})
|
|
182
|
+
target_compile_definitions(\${PROJECT_NAME} PRIVATE NAPI_VERSION=8 NAPI_CPP_EXCEPTIONS)
|
|
183
|
+
if(MSVC)
|
|
184
|
+
target_compile_options(\${PROJECT_NAME} PRIVATE /utf-8 /EHsc)
|
|
185
|
+
endif()
|
|
186
|
+
target_link_libraries(\${PROJECT_NAME} \${CMAKE_JS_LIB})
|
|
187
|
+
|
|
188
|
+
# The libraries of the addon (lakutata native link writes them, or by hand):
|
|
189
|
+
# - a library of the system: target_link_libraries(\${PROJECT_NAME} pcap) (Windows: ws2_32)
|
|
190
|
+
# - a library found by pkg-config:
|
|
191
|
+
# find_package(PkgConfig REQUIRED)
|
|
192
|
+
# pkg_check_modules(PCAP REQUIRED libpcap)
|
|
193
|
+
# target_include_directories(\${PROJECT_NAME} PRIVATE \${PCAP_INCLUDE_DIRS})
|
|
194
|
+
# target_link_libraries(\${PROJECT_NAME} \${PCAP_LIBRARIES})
|
|
195
|
+
# - a package of CMake: find_package(ZLIB REQUIRED) then target_link_libraries(\${PROJECT_NAME} ZLIB::ZLIB)
|
|
196
|
+
# - a static library of the package: target_link_libraries(\${PROJECT_NAME} \${CMAKE_SOURCE_DIR}/deps/lib/libfoo.a)
|
|
197
|
+
# (Windows: deps/lib/foo.lib)
|
|
198
|
+
# - a library built from its sources (its own CMakeLists.txt): add_subdirectory(deps/foo) then
|
|
199
|
+
# target_link_libraries(\${PROJECT_NAME} foo)
|
|
200
|
+
# - a dynamic library shipped with the addon (deps/lib), copied next to it and found there at run time:
|
|
201
|
+
# target_link_libraries(\${PROJECT_NAME} \${CMAKE_SOURCE_DIR}/deps/lib/libfoo.so)
|
|
202
|
+
# set_target_properties(\${PROJECT_NAME} PROPERTIES BUILD_RPATH "$<IF:$<PLATFORM_ID:Darwin>,@loader_path,$ORIGIN>")
|
|
203
|
+
# add_custom_command(TARGET \${PROJECT_NAME} POST_BUILD COMMAND \${CMAKE_COMMAND} -E copy \${CMAKE_SOURCE_DIR}/deps/lib/libfoo.so $<TARGET_FILE_DIR:\${PROJECT_NAME}>)
|
|
204
|
+
# (Windows: the DLL linked by its import library, deps/lib/foo.lib, and copied next to the addon, where Windows finds
|
|
205
|
+
# it; no rpath)
|
|
206
|
+
|
|
207
|
+
# The import library of Node.js on Windows
|
|
208
|
+
if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
|
|
209
|
+
execute_process(COMMAND \${CMAKE_AR} /def:\${CMAKE_JS_NODELIB_DEF} /out:\${CMAKE_JS_NODELIB_TARGET} \${CMAKE_STATIC_LINKER_FLAGS})
|
|
210
|
+
endif()
|
|
211
|
+
`,
|
|
212
|
+
'cpp/binding.cc': cppBinding(target)
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The build files of an addon of Rust built by napi-rs: Cargo.toml, build.rs and rust/lib.rs
|
|
217
|
+
* @param target
|
|
218
|
+
* @param version
|
|
219
|
+
*/
|
|
220
|
+
function rustFiles(target, version) {
|
|
221
|
+
return {
|
|
222
|
+
'Cargo.toml': `[package]
|
|
223
|
+
name = "${target}"
|
|
224
|
+
version = "${version.replace(/[-+].*$/, '')}"
|
|
225
|
+
edition = "2021"
|
|
226
|
+
|
|
227
|
+
[lib]
|
|
228
|
+
crate-type = ["cdylib"]
|
|
229
|
+
path = "rust/lib.rs"
|
|
230
|
+
|
|
231
|
+
[dependencies]
|
|
232
|
+
# Node-API: the same addon runs in Node.js and Electron
|
|
233
|
+
napi = { version = "3", default-features = false, features = ["napi8"] }
|
|
234
|
+
napi-derive = "3"
|
|
235
|
+
# The crates of the addon: their native libraries are built and linked by cargo (their build.rs)
|
|
236
|
+
|
|
237
|
+
[build-dependencies]
|
|
238
|
+
napi-build = "2"
|
|
239
|
+
|
|
240
|
+
[profile.release]
|
|
241
|
+
lto = true
|
|
242
|
+
strip = "symbols"
|
|
243
|
+
`,
|
|
244
|
+
'build.rs': `use std::env;
|
|
245
|
+
use std::path::Path;
|
|
246
|
+
|
|
247
|
+
fn main() {
|
|
248
|
+
napi_build::setup();
|
|
249
|
+
// The native libraries of the addon (beside its crates), given by lakutata native link in .cargo/config.toml: the
|
|
250
|
+
// directives of cargo of every platform (LAKUTATA_NATIVE) and of one (LAKUTATA_NATIVE_MACOS, LAKUTATA_NATIVE_LINUX,
|
|
251
|
+
// LAKUTATA_NATIVE_WINDOWS, LAKUTATA_NATIVE_UNIX), separated by ";", their directories relative to the package
|
|
252
|
+
let root = env::var("CARGO_MANIFEST_DIR").unwrap();
|
|
253
|
+
let mut keys = vec![String::from("LAKUTATA_NATIVE")];
|
|
254
|
+
for cfg in ["CARGO_CFG_TARGET_OS", "CARGO_CFG_TARGET_FAMILY"] {
|
|
255
|
+
for value in env::var(cfg).unwrap_or_default().split(',').filter(|value| !value.is_empty()) {
|
|
256
|
+
let key = format!("LAKUTATA_NATIVE_{}", value.to_uppercase());
|
|
257
|
+
if !keys.contains(&key) {
|
|
258
|
+
keys.push(key);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
for key in keys {
|
|
263
|
+
println!("cargo:rerun-if-env-changed={}", key);
|
|
264
|
+
for directive in env::var(&key).unwrap_or_default().split(';').map(str::trim).filter(|directive| !directive.is_empty()) {
|
|
265
|
+
match directive.strip_prefix("rustc-link-search=") {
|
|
266
|
+
Some(search) => {
|
|
267
|
+
let (kind, directory) = search.split_once('=').unwrap_or(("all", search));
|
|
268
|
+
println!("cargo:rustc-link-search={}={}", kind, Path::new(&root).join(directory).display());
|
|
269
|
+
}
|
|
270
|
+
None => println!("cargo:{}", directive),
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
`,
|
|
276
|
+
'rust/lib.rs': `use napi_derive::napi;
|
|
277
|
+
|
|
278
|
+
/// Greet someone: greet(name)
|
|
279
|
+
#[napi]
|
|
280
|
+
pub fn greet(name: String) -> String {
|
|
281
|
+
format!("Hello, {} (native)", name)
|
|
282
|
+
}
|
|
283
|
+
`
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The C++ of an addon (node-addon-api)
|
|
288
|
+
* @param target
|
|
289
|
+
*/
|
|
290
|
+
function cppBinding(target) {
|
|
291
|
+
return `#include <napi.h>
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Greet someone: greet(name)
|
|
295
|
+
*/
|
|
296
|
+
static Napi::Value Greet(const Napi::CallbackInfo &info) {
|
|
297
|
+
Napi::Env env = info.Env();
|
|
298
|
+
if (info.Length() < 1 || !info[0].IsString()) {
|
|
299
|
+
throw Napi::TypeError::New(env, "The name must be a string");
|
|
300
|
+
}
|
|
301
|
+
return Napi::String::New(env, "Hello, " + info[0].As<Napi::String>().Utf8Value() + " (native)");
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
|
305
|
+
exports.Set("greet", Napi::Function::New(env, Greet));
|
|
306
|
+
return exports;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
NODE_API_MODULE(${target}, Init)
|
|
310
|
+
`;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* How the libraries and the options of the build are given, by build system
|
|
314
|
+
*/
|
|
315
|
+
const NATIVE_GUIDES = {
|
|
316
|
+
gyp: `C++ with [node-addon-api](https://github.com/nodejs/node-addon-api), built by node-gyp from \`binding.gyp\`.
|
|
317
|
+
|
|
318
|
+
The libraries and the options of the build are given in \`binding.gyp\`, whose comments show them: the libraries of
|
|
319
|
+
the system (\`-lpcap\`, \`ws2_32.lib\`, the frameworks of macOS), the ones found by pkg-config, the static libraries
|
|
320
|
+
of the package, the dynamic libraries shipped with the addon (copied next to it, found there at run time by its rpath:
|
|
321
|
+
\`$ORIGIN\` on Linux, \`@loader_path\` on macOS), the standard of C++, the options of each platform (\`conditions\`).`,
|
|
322
|
+
cmake: `C++ with [node-addon-api](https://github.com/nodejs/node-addon-api), built by [cmake-js](https://github.com/cmake-js/cmake-js)
|
|
323
|
+
from \`CMakeLists.txt\`.
|
|
324
|
+
|
|
325
|
+
The libraries and the options of the build are given in \`CMakeLists.txt\`, whose comments show them: the libraries of
|
|
326
|
+
the system, the ones found by pkg-config or by \`find_package\`, the static libraries of the package, the libraries built
|
|
327
|
+
from their sources (\`add_subdirectory\`), the dynamic libraries shipped with the addon (copied next to it, found there
|
|
328
|
+
at run time by its rpath). The headers of Node.js need C++20 (\`CMAKE_CXX_STANDARD\`).`,
|
|
329
|
+
rust: `Rust with [napi-rs](https://napi.rs), built by cargo (\`Cargo.toml\`, \`build.rs\`, \`rust/lib.rs\`).
|
|
330
|
+
|
|
331
|
+
The libraries of the addon are crates (\`Cargo.toml\`), their native libraries built and linked by cargo; the other
|
|
332
|
+
native libraries are linked by \`build.rs\`, given by \`lakutata native link\`. The addon is built for the platform and the
|
|
333
|
+
architecture of the machine (\`rustup target add\` builds the other ones).`
|
|
334
|
+
};
|
|
335
|
+
/**
|
|
336
|
+
* The files of a native addon: built into build/Release (gyp, cmake-js, napi-rs), loaded by node-gyp-build from the
|
|
337
|
+
* TypeScript compiled into dist (the build systems own build)
|
|
338
|
+
* @param name
|
|
339
|
+
* @param version
|
|
340
|
+
* @param build
|
|
341
|
+
*/
|
|
342
|
+
function nativeFiles(name, version, build) {
|
|
343
|
+
const target = name.replace(/^@[^/]+\//, '').replace(/[^A-Za-z0-9_]/g, '_');
|
|
344
|
+
const builds = {
|
|
345
|
+
gyp: {
|
|
346
|
+
files: gypFiles(target),
|
|
347
|
+
buildNative: 'node-gyp rebuild',
|
|
348
|
+
//Built when installed (node-gyp-build builds it without prebuilt binaries)
|
|
349
|
+
install: 'node-gyp-build',
|
|
350
|
+
sources: ['cpp', 'binding.gyp'],
|
|
351
|
+
dependencies: { 'node-addon-api': NATIVE_VERSIONS['node-addon-api'], 'node-gyp-build': NATIVE_VERSIONS['node-gyp-build'] },
|
|
352
|
+
devDependencies: { 'node-gyp': NATIVE_VERSIONS['node-gyp'] },
|
|
353
|
+
toolchain: 'Python and a C++ toolchain (the Xcode command line tools on macOS, build-essential on Linux, the Visual Studio Build Tools on Windows)'
|
|
354
|
+
},
|
|
355
|
+
cmake: {
|
|
356
|
+
files: cMakeFiles(target),
|
|
357
|
+
buildNative: 'cmake-js rebuild',
|
|
358
|
+
install: 'cmake-js compile',
|
|
359
|
+
sources: ['cpp', 'CMakeLists.txt'],
|
|
360
|
+
dependencies: { 'node-addon-api': NATIVE_VERSIONS['node-addon-api'], 'node-gyp-build': NATIVE_VERSIONS['node-gyp-build'], 'cmake-js': NATIVE_VERSIONS['cmake-js'] },
|
|
361
|
+
devDependencies: {},
|
|
362
|
+
toolchain: 'CMake and a C++ toolchain (the Xcode command line tools on macOS, build-essential on Linux, the Visual Studio Build Tools on Windows)'
|
|
363
|
+
},
|
|
364
|
+
rust: {
|
|
365
|
+
files: rustFiles(target, version),
|
|
366
|
+
buildNative: 'napi build --release --output-dir build/Release',
|
|
367
|
+
install: 'napi build --release --output-dir build/Release',
|
|
368
|
+
sources: ['rust', 'Cargo.toml', 'build.rs'],
|
|
369
|
+
dependencies: { 'node-gyp-build': NATIVE_VERSIONS['node-gyp-build'], '@napi-rs/cli': NATIVE_VERSIONS['@napi-rs/cli'] },
|
|
370
|
+
devDependencies: {},
|
|
371
|
+
toolchain: 'Rust (rustup, or the package manager of the system)'
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
const chosen = builds[build];
|
|
375
|
+
return {
|
|
376
|
+
'package.json': `${JSON.stringify({
|
|
377
|
+
name: name,
|
|
378
|
+
version: version,
|
|
379
|
+
private: true,
|
|
380
|
+
type: 'module',
|
|
381
|
+
main: 'dist/index.js',
|
|
382
|
+
types: 'dist/index.d.ts',
|
|
383
|
+
exports: { '.': { types: './dist/index.d.ts', default: './dist/index.js' } },
|
|
384
|
+
...(build === 'gyp' ? { gypfile: true } : {}),
|
|
385
|
+
...(build === 'rust' ? { napi: { binaryName: target } } : {}),
|
|
386
|
+
files: ['dist', '!dist/tests', ...chosen.sources],
|
|
387
|
+
scripts: {
|
|
388
|
+
//The addon is built when the package is installed (from its sources, without prebuilt binaries)
|
|
389
|
+
install: chosen.install,
|
|
390
|
+
clean: 'lakutata clean',
|
|
391
|
+
'clean:native': build === 'rust' ? 'lakutata clean build target' : 'lakutata clean build',
|
|
392
|
+
'build:native': chosen.buildNative,
|
|
393
|
+
build: 'tsc',
|
|
394
|
+
rebuild: 'npm run clean && npm run build:native && npm run build',
|
|
395
|
+
test: 'node --test "dist/tests/**/*.spec.js"'
|
|
396
|
+
},
|
|
397
|
+
dependencies: chosen.dependencies,
|
|
398
|
+
...(Object.keys(chosen.devDependencies).length ? { devDependencies: chosen.devDependencies } : {})
|
|
399
|
+
}, null, 2)}\n`,
|
|
400
|
+
...chosen.files,
|
|
401
|
+
'src/index.ts': `import {createRequire} from 'node:module'
|
|
402
|
+
import path from 'node:path'
|
|
403
|
+
import {fileURLToPath} from 'node:url'
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* The functions of the addon
|
|
407
|
+
*/
|
|
408
|
+
type Binding = {
|
|
409
|
+
greet(name: string): string
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* The addon built into build/Release, loaded from the directory of the package
|
|
414
|
+
*/
|
|
415
|
+
const binding: Binding = createRequire(import.meta.url)('node-gyp-build')(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'))
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Greet someone, in ${build === 'rust' ? 'Rust' : 'C++'}
|
|
419
|
+
* @param name
|
|
420
|
+
*/
|
|
421
|
+
export function Greet(name: string): string {
|
|
422
|
+
return binding.greet(name)
|
|
423
|
+
}
|
|
424
|
+
`,
|
|
425
|
+
'src/tests/index.spec.ts': `import {describe, it} from 'node:test'
|
|
426
|
+
import assert from 'node:assert'
|
|
427
|
+
import {Greet} from '../index.js'
|
|
428
|
+
|
|
429
|
+
describe('${name}', (): void => {
|
|
430
|
+
it('greets in ${build === 'rust' ? 'Rust' : 'C++'}', (): void => {
|
|
431
|
+
assert.strictEqual(Greet('lakutata'), 'Hello, lakutata (native)')
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
it('throws the errors of the addon as JavaScript errors', (): void => {
|
|
435
|
+
assert.throws((): unknown => Greet(42 as unknown as string), ${build === 'rust' ? '/String/' : "{name: 'TypeError', message: 'The name must be a string'}"})
|
|
436
|
+
})
|
|
437
|
+
})
|
|
438
|
+
`,
|
|
439
|
+
'tsconfig.json': tsConfig('dist'),
|
|
440
|
+
'README.md': `# ${name}
|
|
441
|
+
|
|
442
|
+
A native addon: ${NATIVE_GUIDES[build]}
|
|
443
|
+
|
|
444
|
+
Node-API is stable across the versions of Node.js and Electron: the same addon runs in both without being rebuilt.
|
|
445
|
+
\`lakutata package bundle\` and \`lakutata package exe\` ship it with the application.
|
|
446
|
+
|
|
447
|
+
\`\`\`bash
|
|
448
|
+
npm run rebuild # build the addon (build/Release) and compile the TypeScript (dist)
|
|
449
|
+
npm test # run the tests
|
|
450
|
+
\`\`\`
|
|
451
|
+
|
|
452
|
+
A library built by its own Makefile (or its own build) is built before the addon by a script, then linked by it:
|
|
453
|
+
\`"build:deps": "make -C deps/foo"\`, \`"build:native": "npm run build:deps && ${chosen.buildNative}"\`.
|
|
454
|
+
|
|
455
|
+
Building the addon needs ${chosen.toolchain}.
|
|
456
|
+
`
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Add a package to the workspace of the current directory: packages/<name> (without its scope), of the version of the
|
|
461
|
+
* workspace; a package of the workspace may depend on it
|
|
462
|
+
* @param options
|
|
463
|
+
*/
|
|
464
|
+
export async function addPackage(options) {
|
|
465
|
+
if (!/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(options.name))
|
|
466
|
+
throw new Error(`"${options.name}" is not a name of package (lower case, digits, - . _ ~, an optional @scope/)`);
|
|
467
|
+
const workspace = await Workspace.find();
|
|
468
|
+
if (workspace.packages.some((pkg) => pkg.name === options.name))
|
|
469
|
+
throw new Error(`The workspace has already a package ${options.name}`);
|
|
470
|
+
const dependent = options.to === undefined ? undefined : workspace.packages.find((pkg) => pkg.name === options.to);
|
|
471
|
+
if (options.to !== undefined && !dependent)
|
|
472
|
+
throw new Error(`The workspace has no package ${options.to} (${workspace.packages.map((pkg) => pkg.name).join(', ')})`);
|
|
473
|
+
const directory = path.join(workspace.root, 'packages', options.name.replace(/^@[^/]+\//, ''));
|
|
474
|
+
if (existsSync(directory))
|
|
475
|
+
throw new Error(`${path.relative(process.cwd(), directory) || directory} exists already`);
|
|
476
|
+
const version = workspace.lerna?.data.version ?? workspace.manifest.data.version ?? '0.0.1';
|
|
477
|
+
const files = options.native ? nativeFiles(options.name, version, options.native) : libraryFiles(options.name, version);
|
|
478
|
+
for (const [file, content] of Object.entries(files)) {
|
|
479
|
+
await mkdir(path.dirname(path.join(directory, file)), { recursive: true });
|
|
480
|
+
await writeFile(path.join(directory, file), content);
|
|
481
|
+
}
|
|
482
|
+
if (dependent) {
|
|
483
|
+
dependent.manifest.data.dependencies = { ...(dependent.manifest.data.dependencies ?? {}), [options.name]: `^${version}` };
|
|
484
|
+
await dependent.manifest.write();
|
|
485
|
+
}
|
|
486
|
+
return { directory: directory, files: Object.keys(files), version: version, to: dependent?.name };
|
|
487
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
/**
|
|
5
|
+
* The builder of a project: the one installed in the project (its node_modules, the ones of its workspace), else the one
|
|
6
|
+
* installed with the tool
|
|
7
|
+
* @param project
|
|
8
|
+
*/
|
|
9
|
+
export async function loadBuilder(project) {
|
|
10
|
+
for (const base of [path.join(project, 'package.json'), import.meta.url]) {
|
|
11
|
+
let entry;
|
|
12
|
+
try {
|
|
13
|
+
entry = createRequire(base).resolve('@lakutata/builder');
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
return await import(pathToFileURL(entry).href);
|
|
19
|
+
}
|
|
20
|
+
throw new Error('The builder of the applications is not installed: install it in the project (npm install --save-dev @lakutata/builder)');
|
|
21
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* The paths a clean never removes: the package itself, its sources, its dependencies and its manifest
|
|
7
|
+
*/
|
|
8
|
+
const PROTECTED = ['node_modules', 'src', 'package.json', '.git'];
|
|
9
|
+
/**
|
|
10
|
+
* The text of a JSON with comments and trailing commas (a tsconfig.json) as JSON: the comments and the commas before a
|
|
11
|
+
* closing bracket are removed outside of the strings
|
|
12
|
+
* @param text
|
|
13
|
+
*/
|
|
14
|
+
function stripJSONC(text) {
|
|
15
|
+
let output = '';
|
|
16
|
+
for (let index = 0; index < text.length; index++) {
|
|
17
|
+
const char = text[index];
|
|
18
|
+
if (char === '"') {
|
|
19
|
+
//A string, its escaped quotes included
|
|
20
|
+
let end = index + 1;
|
|
21
|
+
while (end < text.length && text[end] !== '"')
|
|
22
|
+
end += text[end] === '\\' ? 2 : 1;
|
|
23
|
+
output += text.slice(index, end + 1);
|
|
24
|
+
index = end;
|
|
25
|
+
}
|
|
26
|
+
else if (char === '/' && text[index + 1] === '/') {
|
|
27
|
+
while (index < text.length && text[index] !== '\n')
|
|
28
|
+
index++;
|
|
29
|
+
output += '\n';
|
|
30
|
+
}
|
|
31
|
+
else if (char === '/' && text[index + 1] === '*') {
|
|
32
|
+
index = text.indexOf('*/', index + 2);
|
|
33
|
+
if (index < 0)
|
|
34
|
+
break;
|
|
35
|
+
index++;
|
|
36
|
+
}
|
|
37
|
+
else if (char === ',') {
|
|
38
|
+
//A trailing comma: the next character, whitespaces and comments skipped, closes an object or an array
|
|
39
|
+
let next = index + 1;
|
|
40
|
+
for (;;) {
|
|
41
|
+
while (next < text.length && /\s/.test(text[next]))
|
|
42
|
+
next++;
|
|
43
|
+
if (text[next] === '/' && text[next + 1] === '/')
|
|
44
|
+
next = text.indexOf('\n', next) < 0 ? text.length : text.indexOf('\n', next);
|
|
45
|
+
else if (text[next] === '/' && text[next + 1] === '*')
|
|
46
|
+
next = text.indexOf('*/', next + 2) < 0 ? text.length : text.indexOf('*/', next + 2) + 2;
|
|
47
|
+
else
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
if (text[next] !== '}' && text[next] !== ']')
|
|
51
|
+
output += char;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
output += char;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return output;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The file of a configuration extended: a path relative to the configuration, or a module (lakutata/tsconfig.json)
|
|
61
|
+
* @param from the configuration extending it
|
|
62
|
+
* @param specifier
|
|
63
|
+
*/
|
|
64
|
+
function extendedConfiguration(from, specifier) {
|
|
65
|
+
if (specifier.startsWith('.') || path.isAbsolute(specifier)) {
|
|
66
|
+
const file = path.resolve(path.dirname(from), specifier);
|
|
67
|
+
return [file, `${file}.json`].find((candidate) => existsSync(candidate) && !candidate.endsWith(path.sep));
|
|
68
|
+
}
|
|
69
|
+
const require = createRequire(from);
|
|
70
|
+
for (const candidate of [specifier, `${specifier}.json`, `${specifier}/tsconfig.json`]) {
|
|
71
|
+
try {
|
|
72
|
+
return require.resolve(candidate);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
//The next form of the specifier
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The output directories of a TypeScript configuration and of the ones it extends (outDir, declarationDir), absolute:
|
|
82
|
+
* each one relative to the configuration giving it, the closest configuration winning
|
|
83
|
+
* @param file
|
|
84
|
+
* @param depth
|
|
85
|
+
*/
|
|
86
|
+
async function configurationOutputs(file, depth = 0) {
|
|
87
|
+
const configuration = JSON.parse(stripJSONC(await readFile(file, 'utf8')));
|
|
88
|
+
let outputs = {};
|
|
89
|
+
const extended = configuration.extends === undefined ? [] : Array.isArray(configuration.extends) ? configuration.extends : [configuration.extends];
|
|
90
|
+
if (depth < 8) {
|
|
91
|
+
for (const specifier of extended) {
|
|
92
|
+
const parent = extendedConfiguration(file, specifier);
|
|
93
|
+
if (parent)
|
|
94
|
+
outputs = { ...outputs, ...await configurationOutputs(parent, depth + 1) };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const option of ['outDir', 'declarationDir']) {
|
|
98
|
+
const value = configuration.compilerOptions?.[option];
|
|
99
|
+
if (typeof value === 'string')
|
|
100
|
+
outputs[option] = path.resolve(path.dirname(file), value);
|
|
101
|
+
}
|
|
102
|
+
return outputs;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The output directories of the TypeScript configuration of a package (its tsconfig.json): outDir and declarationDir
|
|
106
|
+
* @param directory
|
|
107
|
+
* @return the directories, relative to the package
|
|
108
|
+
*/
|
|
109
|
+
export async function outputDirectories(directory) {
|
|
110
|
+
const file = path.join(directory, 'tsconfig.json');
|
|
111
|
+
if (!existsSync(file))
|
|
112
|
+
throw new Error(`${directory} has no tsconfig.json: give the paths removed (lakutata clean <paths...>)`);
|
|
113
|
+
const outputs = await configurationOutputs(file);
|
|
114
|
+
const directories = [...new Set([outputs.outDir, outputs.declarationDir].filter((output) => !!output))];
|
|
115
|
+
if (!directories.length)
|
|
116
|
+
throw new Error(`The tsconfig.json of ${directory} gives no outDir: give the paths removed (lakutata clean <paths...>)`);
|
|
117
|
+
return directories.map((output) => path.relative(directory, output));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Remove paths of a package (as rm -rf, on every platform): only the paths inside the package, never the package itself,
|
|
121
|
+
* its sources, its dependencies nor its manifest
|
|
122
|
+
* @param directory the directory of the package
|
|
123
|
+
* @param paths relative to the package
|
|
124
|
+
*/
|
|
125
|
+
export async function clean(directory, paths) {
|
|
126
|
+
const root = path.resolve(directory);
|
|
127
|
+
const targets = paths.map((target) => {
|
|
128
|
+
const absolute = path.resolve(root, target);
|
|
129
|
+
const relative = path.relative(root, absolute);
|
|
130
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
|
|
131
|
+
throw new Error(`${target} is not inside the package ${root}: it is not removed`);
|
|
132
|
+
if (PROTECTED.includes(relative.split(path.sep)[0]))
|
|
133
|
+
throw new Error(`${target} is protected (${PROTECTED.join(', ')}): it is not removed`);
|
|
134
|
+
return { relative: relative, absolute: absolute };
|
|
135
|
+
});
|
|
136
|
+
const result = { removed: [], missing: [] };
|
|
137
|
+
for (const target of targets) {
|
|
138
|
+
if (!existsSync(target.absolute)) {
|
|
139
|
+
result.missing.push(target.relative);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
await rm(target.absolute, { recursive: true, force: true });
|
|
143
|
+
result.removed.push(target.relative);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The environment the tool was started with: the application of the tool sets some variables (NODE_ENV from its mode…),
|
|
3
|
+
* the commands it runs (the scripts of the packages, the installations) are given the environment of the user
|
|
4
|
+
*/
|
|
5
|
+
export const LaunchEnvironment = { ...process.env };
|
|
6
|
+
//The commands of the migrations (MIGRATION_GENERATE, MIGRATION_RUN…) are given to the applications of the projects, not
|
|
7
|
+
//to the tool, an application of lakutata too: the tool run by a script of an application started by a migration command
|
|
8
|
+
//(lakutata clean in its build) does its own command; the commands it runs are still given them (LaunchEnvironment)
|
|
9
|
+
for (const name of Object.keys(process.env))
|
|
10
|
+
if (name.toUpperCase().startsWith('MIGRATION_'))
|
|
11
|
+
delete process.env[name];
|