ic-mops 0.22.0 → 0.24.0
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 +6 -18
- package/cli.ts +22 -14
- package/commands/init.ts +197 -31
- package/commands/remove.ts +1 -1
- package/commands/sync.ts +98 -0
- package/commands/template.ts +83 -15
- package/declarations/main/main.did +10 -10
- package/declarations/main/main.did.d.ts +6 -7
- package/declarations/main/main.did.js +14 -7
- package/dist/cli.js +21 -14
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.js +174 -29
- package/dist/commands/remove.js +1 -1
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +84 -0
- package/dist/commands/template.d.ts +1 -1
- package/dist/commands/template.js +78 -15
- package/dist/declarations/main/main.did +10 -10
- package/dist/declarations/main/main.did.d.ts +6 -7
- package/dist/declarations/main/main.did.js +14 -7
- package/dist/package.json +2 -1
- package/dist/templates/README.md +13 -0
- package/dist/templates/licenses/Apache-2.0 +202 -0
- package/dist/templates/licenses/Apache-2.0-NOTICE +13 -0
- package/dist/templates/licenses/MIT +21 -0
- package/dist/templates/src/lib.mo +15 -0
- package/dist/templates/test/lib.test.mo +4 -0
- package/package.json +2 -1
- package/templates/README.md +13 -0
- package/templates/licenses/Apache-2.0 +202 -0
- package/templates/licenses/Apache-2.0-NOTICE +13 -0
- package/templates/licenses/MIT +21 -0
- package/templates/src/lib.mo +15 -0
- package/templates/test/lib.test.mo +4 -0
package/README.md
CHANGED
|
@@ -17,28 +17,16 @@ npm i -g ic-mops
|
|
|
17
17
|
|
|
18
18
|
## Install Packages
|
|
19
19
|
|
|
20
|
-
### 1.
|
|
21
|
-
Add `mops` as a packtool to your `dfx.json`
|
|
22
|
-
|
|
23
|
-
```json
|
|
24
|
-
{
|
|
25
|
-
"defaults": {
|
|
26
|
-
"build": {
|
|
27
|
-
"packtool": "mops sources"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### 2. Initialize
|
|
20
|
+
### 1. Initialize
|
|
34
21
|
Run this command in the root directory of your project (where is `dfx.json` placed)
|
|
22
|
+
|
|
35
23
|
If there are Vessel config files, mops will migrate packages from `vessel.dhall` to `mops.toml`
|
|
36
24
|
|
|
37
25
|
```
|
|
38
26
|
mops init
|
|
39
27
|
```
|
|
40
28
|
|
|
41
|
-
###
|
|
29
|
+
### 2. Install Motoko Packages
|
|
42
30
|
Use `mops add <package_name>` to install a specific package and save it to `mops.toml`
|
|
43
31
|
|
|
44
32
|
```
|
|
@@ -65,7 +53,7 @@ Use `mops install` to install all packages specified in `mops.toml`
|
|
|
65
53
|
mops install
|
|
66
54
|
```
|
|
67
55
|
|
|
68
|
-
###
|
|
56
|
+
### 3. Import Package
|
|
69
57
|
Now you can import installed packages in your Motoko code
|
|
70
58
|
|
|
71
59
|
```motoko
|
|
@@ -92,10 +80,10 @@ mops import-identity -- "$(dfx identity export mops)"
|
|
|
92
80
|
```
|
|
93
81
|
|
|
94
82
|
### 2. Initialize
|
|
95
|
-
Run this command in your package root
|
|
83
|
+
Run this command in your package root and select type "Package"
|
|
96
84
|
|
|
97
85
|
```
|
|
98
|
-
mops init
|
|
86
|
+
mops init
|
|
99
87
|
```
|
|
100
88
|
|
|
101
89
|
Edit `description` and `repository` fields in `mops.toml` file.
|
package/cli.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
|
-
import {program} from 'commander';
|
|
4
|
+
import {program, Argument} from 'commander';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import {Principal} from '@dfinity/principal';
|
|
7
7
|
|
|
@@ -21,6 +21,7 @@ import {selfUpdate} from './commands/self-update.js';
|
|
|
21
21
|
import {remove} from './commands/remove.js';
|
|
22
22
|
import {getUserProp, setUserProp} from './commands/user.js';
|
|
23
23
|
import {bump} from './commands/bump.js';
|
|
24
|
+
import {sync} from './commands/sync.js';
|
|
24
25
|
// import {docs} from './commands/docs.js';
|
|
25
26
|
|
|
26
27
|
program.name('mops');
|
|
@@ -31,10 +32,11 @@ program.version(`CLI ${packageJson.version}\nAPI ${apiVersion}`, '-v --version')
|
|
|
31
32
|
|
|
32
33
|
// init
|
|
33
34
|
program
|
|
34
|
-
.command('init
|
|
35
|
-
.description('
|
|
36
|
-
.
|
|
37
|
-
|
|
35
|
+
.command('init')
|
|
36
|
+
.description('Initialize a new project or package in the current directory')
|
|
37
|
+
.option('-y, --yes', 'Accept all defaults')
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
await init(options);
|
|
38
40
|
});
|
|
39
41
|
|
|
40
42
|
// add
|
|
@@ -110,7 +112,7 @@ program
|
|
|
110
112
|
program
|
|
111
113
|
.command('set-network <network>')
|
|
112
114
|
.alias('sn')
|
|
113
|
-
.description('Set network local|
|
|
115
|
+
.description('Set network local|staging|ic')
|
|
114
116
|
.action(async (network) => {
|
|
115
117
|
await setNetwork(network);
|
|
116
118
|
console.log(`Selected '${network}' network`);
|
|
@@ -166,8 +168,9 @@ program
|
|
|
166
168
|
|
|
167
169
|
// cache
|
|
168
170
|
program
|
|
169
|
-
.command('cache
|
|
171
|
+
.command('cache')
|
|
170
172
|
.description('Manage cache')
|
|
173
|
+
.addArgument(new Argument('<sub>').choices(['size', 'clean']))
|
|
171
174
|
.action(async (sub) => {
|
|
172
175
|
if (sub == 'clean') {
|
|
173
176
|
await cleanCache();
|
|
@@ -177,9 +180,6 @@ program
|
|
|
177
180
|
let size = await cacheSize();
|
|
178
181
|
console.log('Cache size is ' + size);
|
|
179
182
|
}
|
|
180
|
-
else {
|
|
181
|
-
console.log('Unknown sub command. Available sub commands: clean, size');
|
|
182
|
-
}
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
// test
|
|
@@ -236,7 +236,10 @@ program
|
|
|
236
236
|
|
|
237
237
|
// user
|
|
238
238
|
program
|
|
239
|
-
.command('user
|
|
239
|
+
.command('user')
|
|
240
|
+
.addArgument(new Argument('<sub>').choices(['set', 'get']))
|
|
241
|
+
.addArgument(new Argument('<prop>').choices(['name', 'site', 'email', 'github', 'twitter']))
|
|
242
|
+
.addArgument(new Argument('[value]'))
|
|
240
243
|
.description('User settings')
|
|
241
244
|
.action(async (sub, prop, value) => {
|
|
242
245
|
if (sub == 'get') {
|
|
@@ -249,9 +252,6 @@ program
|
|
|
249
252
|
}
|
|
250
253
|
await setUserProp(prop, value);
|
|
251
254
|
}
|
|
252
|
-
else {
|
|
253
|
-
console.log('Unknown sub command. Available sub commands: set, get');
|
|
254
|
-
}
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
// airdrop
|
|
@@ -294,4 +294,12 @@ program
|
|
|
294
294
|
bump(part);
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
+
// sync
|
|
298
|
+
program
|
|
299
|
+
.command('sync')
|
|
300
|
+
.description('Add missing packages and remove unused packages')
|
|
301
|
+
.action(async () => {
|
|
302
|
+
await sync();
|
|
303
|
+
});
|
|
304
|
+
|
|
297
305
|
program.parse();
|
package/commands/init.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {execSync} from 'node:child_process';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import
|
|
3
|
+
import {existsSync, readFileSync, writeFileSync} from 'node:fs';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import
|
|
5
|
+
import prompts from 'prompts';
|
|
6
|
+
|
|
7
|
+
import {checkApiCompatibility, mainActor, writeConfig} from '../mops.js';
|
|
6
8
|
import {installAll} from './install-all.js';
|
|
7
9
|
import {VesselConfig, readVesselConfig} from '../vessel.js';
|
|
8
10
|
import {Config, Dependencies} from '../types.js';
|
|
11
|
+
import {template} from './template.js';
|
|
9
12
|
|
|
10
|
-
export async function init(
|
|
13
|
+
export async function init({yes = false} = {}) {
|
|
11
14
|
let configFile = path.join(process.cwd(), 'mops.toml');
|
|
12
|
-
let exists =
|
|
15
|
+
let exists = existsSync(configFile);
|
|
13
16
|
if (exists) {
|
|
14
17
|
console.log(chalk.yellow('mops.toml already exists'));
|
|
15
18
|
return;
|
|
@@ -18,56 +21,179 @@ export async function init(name = '') {
|
|
|
18
21
|
console.log('Initializing...');
|
|
19
22
|
|
|
20
23
|
let config: Config = {};
|
|
21
|
-
let vesselConfig: VesselConfig = {dependencies: [], 'dev-dependencies': []};
|
|
22
|
-
let deps: Dependencies = {};
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
if (yes) {
|
|
26
|
+
await applyInit({
|
|
27
|
+
type: 'project',
|
|
28
|
+
config,
|
|
29
|
+
setupWorkflow: true,
|
|
30
|
+
addTest: false,
|
|
31
|
+
copyrightOwner: '',
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// migrate from vessel
|
|
37
|
+
let vesselFile = path.join(process.cwd(), 'vessel.dhall');
|
|
38
|
+
let vesselConfig: VesselConfig = {dependencies: [], 'dev-dependencies': []};
|
|
25
39
|
|
|
26
|
-
if (
|
|
40
|
+
if (existsSync(vesselFile)) {
|
|
27
41
|
console.log('Reading vessel.dhall file');
|
|
28
|
-
|
|
42
|
+
let res = await readVesselConfig(process.cwd(), {cache: false});
|
|
29
43
|
if (res) {
|
|
30
44
|
vesselConfig = {...res};
|
|
31
45
|
}
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
if (vesselConfig.dependencies) {
|
|
49
|
+
let deps: Dependencies = {};
|
|
35
50
|
deps = {};
|
|
36
51
|
|
|
37
52
|
for (const dep of (vesselConfig.dependencies || [])) {
|
|
38
53
|
deps[dep.name] = dep;
|
|
39
54
|
}
|
|
55
|
+
|
|
56
|
+
if (Object.keys(deps).length) {
|
|
57
|
+
config.dependencies = deps;
|
|
58
|
+
}
|
|
40
59
|
}
|
|
41
60
|
|
|
42
|
-
|
|
43
|
-
|
|
61
|
+
let promptsConfig = {
|
|
62
|
+
onCancel() {
|
|
63
|
+
console.log('aborted');
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// type
|
|
69
|
+
let {type} = await prompts({
|
|
70
|
+
type: 'select',
|
|
71
|
+
name: 'type',
|
|
72
|
+
message: 'Select type:',
|
|
73
|
+
choices: [
|
|
74
|
+
{title: `Project ${chalk.dim('(I just want to use mops packages in my project)')}`, value: 'project'},
|
|
75
|
+
{title: `Package ${chalk.dim('(I plan to publish this package on mops)')}`, value: 'package'},
|
|
76
|
+
],
|
|
77
|
+
}, promptsConfig);
|
|
78
|
+
|
|
79
|
+
let addTest = false;
|
|
80
|
+
let copyrightOwner = '';
|
|
81
|
+
|
|
82
|
+
// package details
|
|
83
|
+
if (type === 'package') {
|
|
84
|
+
let res = await prompts([
|
|
85
|
+
{
|
|
86
|
+
type: 'text',
|
|
87
|
+
name: 'name',
|
|
88
|
+
message: 'Enter package name:',
|
|
89
|
+
initial: '',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'text',
|
|
93
|
+
name: 'description',
|
|
94
|
+
message: 'Enter package description:',
|
|
95
|
+
initial: '',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'text',
|
|
99
|
+
name: 'repository',
|
|
100
|
+
message: 'Enter package repository url:',
|
|
101
|
+
initial: '',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: 'text',
|
|
105
|
+
name: 'keywords',
|
|
106
|
+
message: 'Enter keywords separated by spaces:',
|
|
107
|
+
initial: '',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'select',
|
|
111
|
+
name: 'license',
|
|
112
|
+
message: 'Choose a license:',
|
|
113
|
+
choices: [
|
|
114
|
+
{title: 'MIT', value: 'MIT'},
|
|
115
|
+
{title: 'Apache-2.0', value: 'Apache-2.0'},
|
|
116
|
+
],
|
|
117
|
+
initial: 0,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
type: 'text',
|
|
121
|
+
name: 'copyrightOwner',
|
|
122
|
+
message: 'Enter license copyright owner:',
|
|
123
|
+
initial: '',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'confirm',
|
|
127
|
+
name: 'addTest',
|
|
128
|
+
message: `Add example test file? ${chalk.dim('(test/lib.test.mo)')}`,
|
|
129
|
+
initial: true,
|
|
130
|
+
},
|
|
131
|
+
], promptsConfig);
|
|
132
|
+
|
|
44
133
|
config.package = {
|
|
45
|
-
name,
|
|
46
|
-
version: '
|
|
47
|
-
description: '',
|
|
48
|
-
repository: '',
|
|
134
|
+
name: (res.name || '').trim(),
|
|
135
|
+
version: '1.0.0',
|
|
136
|
+
description: (res.description || '').trim(),
|
|
137
|
+
repository: (res.repository || '').trim(),
|
|
138
|
+
keywords: [...new Set(res.keywords.split(' ').filter(Boolean))] as string[],
|
|
139
|
+
license: (res.license || '').trim(),
|
|
49
140
|
};
|
|
50
141
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
142
|
+
addTest = res.addTest;
|
|
143
|
+
copyrightOwner = res.copyrightOwner;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// GitHub workflow
|
|
147
|
+
let {setupWorkflow} = await prompts({
|
|
148
|
+
type: 'confirm',
|
|
149
|
+
name: 'setupWorkflow',
|
|
150
|
+
message: `Setup GitHub workflow? ${chalk.dim('(run `mops test` on push)')}`,
|
|
151
|
+
initial: true,
|
|
152
|
+
}, promptsConfig);
|
|
153
|
+
|
|
154
|
+
await applyInit({
|
|
155
|
+
type,
|
|
156
|
+
config,
|
|
157
|
+
setupWorkflow,
|
|
158
|
+
addTest,
|
|
159
|
+
copyrightOwner,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
54
162
|
|
|
55
|
-
|
|
163
|
+
type ApplyInitOptions = {
|
|
164
|
+
type: 'project' | 'package';
|
|
165
|
+
config: Config;
|
|
166
|
+
setupWorkflow: boolean;
|
|
167
|
+
addTest: boolean;
|
|
168
|
+
copyrightOwner: string;
|
|
169
|
+
}
|
|
56
170
|
|
|
57
|
-
|
|
58
|
-
|
|
171
|
+
async function applyInit({type, config, setupWorkflow, addTest, copyrightOwner} : ApplyInitOptions) {
|
|
172
|
+
// set packtool in dfx.json
|
|
173
|
+
let dfxJson = path.resolve(process.cwd(), 'dfx.json');
|
|
174
|
+
let dfxJsonData;
|
|
175
|
+
if (existsSync(dfxJson)) {
|
|
176
|
+
let dfxJsonText = readFileSync(dfxJson).toString();
|
|
177
|
+
dfxJsonData = JSON.parse(dfxJsonText);
|
|
178
|
+
console.log('Setting packtool in dfx.json...');
|
|
179
|
+
dfxJsonData.defaults = dfxJsonData.defaults || {};
|
|
180
|
+
dfxJsonData.defaults.build = dfxJsonData.defaults.build || {};
|
|
181
|
+
if (dfxJsonData.defaults.build.packtool !== 'mops sources') {
|
|
182
|
+
dfxJsonData.defaults.build.packtool = 'mops sources';
|
|
183
|
+
let indent = dfxJsonText.match(/([ \t]+)"/)?.[1] || ' ';
|
|
184
|
+
writeFileSync(path.join(process.cwd(), 'dfx.json'), JSON.stringify(dfxJsonData, null, indent));
|
|
185
|
+
console.log(chalk.green('packtool set to "mops sources"'));
|
|
59
186
|
}
|
|
60
187
|
}
|
|
61
188
|
|
|
62
|
-
//
|
|
63
|
-
if (
|
|
189
|
+
// get default packages
|
|
190
|
+
if (type === 'project') {
|
|
64
191
|
let compatible = await checkApiCompatibility();
|
|
65
192
|
if (!compatible) {
|
|
66
193
|
return;
|
|
67
194
|
}
|
|
68
195
|
|
|
69
|
-
let
|
|
70
|
-
let dfxVersion = dfxJson?.dfx || '';
|
|
196
|
+
let dfxVersion = dfxJsonData?.dfx || '';
|
|
71
197
|
if (!dfxVersion) {
|
|
72
198
|
try {
|
|
73
199
|
let res = execSync('dfx --version').toString();
|
|
@@ -79,6 +205,7 @@ export async function init(name = '') {
|
|
|
79
205
|
catch {}
|
|
80
206
|
}
|
|
81
207
|
|
|
208
|
+
console.log(`Fetching default packages for dfx ${dfxVersion}...`);
|
|
82
209
|
let actor = await mainActor();
|
|
83
210
|
let defaultPackages = await actor.getDefaultPackages(dfxVersion);
|
|
84
211
|
|
|
@@ -86,18 +213,57 @@ export async function init(name = '') {
|
|
|
86
213
|
config.dependencies = {};
|
|
87
214
|
}
|
|
88
215
|
|
|
89
|
-
if (deps) {
|
|
90
|
-
config.dependencies = deps;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
216
|
for (let [name, version] of defaultPackages) {
|
|
94
217
|
config.dependencies[name] = {name, version};
|
|
95
218
|
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// save config
|
|
222
|
+
let configFile = path.join(process.cwd(), 'mops.toml');
|
|
223
|
+
writeConfig(config, configFile);
|
|
224
|
+
console.log(chalk.green('Created'), 'mops.toml');
|
|
225
|
+
|
|
226
|
+
// add src/lib.mo
|
|
227
|
+
if (type === 'package' && !existsSync(path.join(process.cwd(), 'src'))) {
|
|
228
|
+
await template('lib.mo');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// add src/lib.test.mo
|
|
232
|
+
if (addTest && !existsSync(path.join(process.cwd(), 'test'))) {
|
|
233
|
+
await template('lib.test.mo');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// add license
|
|
237
|
+
if (config.package?.license) {
|
|
238
|
+
await template(`license:${config.package.license}`, {copyrightOwner});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// add readme
|
|
242
|
+
if (type === 'package') {
|
|
243
|
+
await template('readme');
|
|
244
|
+
}
|
|
96
245
|
|
|
97
|
-
|
|
246
|
+
// add GitHub workflow
|
|
247
|
+
if (setupWorkflow) {
|
|
248
|
+
await template('github-workflow:mops-test');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// add .mops to .gitignore
|
|
252
|
+
{
|
|
253
|
+
let gitignore = path.join(process.cwd(), '.gitignore');
|
|
254
|
+
let gitignoreData = existsSync(gitignore) ? readFileSync(gitignore).toString() : '';
|
|
255
|
+
let lf = gitignoreData.endsWith('\n') ? '\n' : '';
|
|
256
|
+
if (!gitignoreData.includes('.mops')) {
|
|
257
|
+
writeFileSync(gitignore, `${gitignoreData}\n.mops${lf}`.trimStart());
|
|
258
|
+
console.log(chalk.green('Added'), '.mops to .gitignore');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
98
261
|
|
|
262
|
+
// install deps
|
|
263
|
+
if (Object.keys(config.dependencies || {}).length) {
|
|
264
|
+
console.log('Installing dependencies...');
|
|
99
265
|
await installAll({verbose: true});
|
|
100
266
|
}
|
|
101
267
|
|
|
102
|
-
console.log(chalk.green('
|
|
268
|
+
console.log(chalk.green('Done!'));
|
|
103
269
|
}
|
package/commands/remove.ts
CHANGED
|
@@ -77,7 +77,7 @@ export async function remove(name: string, {dev = false, verbose = false, dryRun
|
|
|
77
77
|
pkgDir = formatDir(dep.name, dep.version);
|
|
78
78
|
}
|
|
79
79
|
if (pkgDir && fs.existsSync(pkgDir)) {
|
|
80
|
-
dryRun || deleteSync([`${pkgDir}`]);
|
|
80
|
+
dryRun || deleteSync([`${pkgDir}`], {force: true});
|
|
81
81
|
verbose && console.log(`Removed local cache ${pkgDir}`);
|
|
82
82
|
}
|
|
83
83
|
}
|
package/commands/sync.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {execSync} from 'node:child_process';
|
|
3
|
+
import {globSync} from 'glob';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import {checkConfigFile, getRootDir, readConfig} from '../mops.js';
|
|
6
|
+
import {add} from './add.js';
|
|
7
|
+
import {remove} from './remove.js';
|
|
8
|
+
|
|
9
|
+
let ignore = [
|
|
10
|
+
'**/node_modules/**',
|
|
11
|
+
'**/.vessel/**',
|
|
12
|
+
'**/.git/**',
|
|
13
|
+
'**/.mops/**',
|
|
14
|
+
'**/test/**',
|
|
15
|
+
'**/*.test.mo',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
let mocPath = '';
|
|
19
|
+
function getMocPath(): string {
|
|
20
|
+
if (!mocPath) {
|
|
21
|
+
mocPath = process.env.DFX_MOC_PATH || '';
|
|
22
|
+
}
|
|
23
|
+
if (!mocPath) {
|
|
24
|
+
try {
|
|
25
|
+
mocPath = execSync('dfx cache show').toString().trim() + '/moc';
|
|
26
|
+
}
|
|
27
|
+
catch {}
|
|
28
|
+
}
|
|
29
|
+
if (!mocPath) {
|
|
30
|
+
mocPath = 'moc';
|
|
31
|
+
}
|
|
32
|
+
return mocPath;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function getUsedPackages(): Promise<string[]> {
|
|
36
|
+
let rootDir = getRootDir();
|
|
37
|
+
let files = globSync('**/*.mo', {
|
|
38
|
+
cwd: rootDir,
|
|
39
|
+
nocase: true,
|
|
40
|
+
ignore: ignore,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
let packages: Set<string> = new Set;
|
|
44
|
+
|
|
45
|
+
for (let file of files) {
|
|
46
|
+
let deps: string[] = execSync(`${getMocPath()} --print-deps ${path.join(rootDir, file)}`).toString().trim().split('\n');
|
|
47
|
+
|
|
48
|
+
for (let dep of deps) {
|
|
49
|
+
if (dep.startsWith('mo:') && !dep.startsWith('mo:prim') && !dep.startsWith('mo:⛔')) {
|
|
50
|
+
packages.add(dep.replace(/^mo:([^/]+).*$/, '$1'));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return [...packages];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function getMissingPackages(): Promise<string[]> {
|
|
59
|
+
let config = readConfig();
|
|
60
|
+
let allDeps = [...Object.keys(config.dependencies || {}), ...Object.keys(config['dev-dependencies'] || {})];
|
|
61
|
+
let missing = new Set(await getUsedPackages());
|
|
62
|
+
for (let pkg of allDeps) {
|
|
63
|
+
missing.delete(pkg);
|
|
64
|
+
}
|
|
65
|
+
return [...missing];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function getUnusedPackages(): Promise<string[]> {
|
|
69
|
+
let config = readConfig();
|
|
70
|
+
let allDeps = new Set([...Object.keys(config.dependencies || {})]);
|
|
71
|
+
let used = await getUsedPackages();
|
|
72
|
+
for (let pkg of used) {
|
|
73
|
+
allDeps.delete(pkg);
|
|
74
|
+
}
|
|
75
|
+
return [...allDeps];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function sync() {
|
|
79
|
+
if (!checkConfigFile()) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let missing = await getMissingPackages();
|
|
84
|
+
let unused = await getUnusedPackages();
|
|
85
|
+
|
|
86
|
+
missing.length && console.log(`${chalk.yellow('Missing packages:')} ${missing.join(', ')}`);
|
|
87
|
+
unused.length && console.log(`${chalk.yellow('Unused packages:')} ${unused.join(', ')}`);
|
|
88
|
+
|
|
89
|
+
// add missing packages
|
|
90
|
+
for (let pkg of missing) {
|
|
91
|
+
await add(pkg);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// remove unused packages
|
|
95
|
+
for (let pkg of unused) {
|
|
96
|
+
await remove(pkg);
|
|
97
|
+
}
|
|
98
|
+
}
|
package/commands/template.ts
CHANGED
|
@@ -2,29 +2,97 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import prompts from 'prompts';
|
|
5
|
-
import
|
|
5
|
+
import camelCase from 'camelcase';
|
|
6
|
+
import {getRootDir, readConfig} from '../mops.js';
|
|
6
7
|
|
|
7
|
-
export async function template() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
export async function template(templateName?: string, options: any = {}) {
|
|
9
|
+
if (!templateName) {
|
|
10
|
+
let res = await prompts({
|
|
11
|
+
type: 'select',
|
|
12
|
+
name: 'value',
|
|
13
|
+
message: 'Select template:',
|
|
14
|
+
choices: [
|
|
15
|
+
{title: 'README.md', value: 'readme'},
|
|
16
|
+
{title: 'src/lib.mo', value: 'lib.mo'},
|
|
17
|
+
{title: 'test/lib.test.mo', value: 'lib.test.mo'},
|
|
18
|
+
{title: 'License MIT', value: 'license:MIT'},
|
|
19
|
+
{title: 'License Apache-2.0', value: 'license:Apache-2.0'},
|
|
20
|
+
{title: 'GitHub Workflow to run \'mops test\'', value: 'github-workflow:mops-test'},
|
|
21
|
+
{title: '× Cancel', value: ''},
|
|
22
|
+
],
|
|
23
|
+
initial: 0,
|
|
24
|
+
});
|
|
25
|
+
templateName = res.value;
|
|
26
|
+
}
|
|
18
27
|
|
|
19
|
-
if (
|
|
28
|
+
if (templateName === 'github-workflow:mops-test') {
|
|
20
29
|
let dest = path.resolve(getRootDir(), '.github/workflows/mops-test.yml');
|
|
21
30
|
if (fs.existsSync(dest)) {
|
|
22
|
-
console.log(chalk.yellow('Workflow already exists:'), dest);
|
|
31
|
+
console.log(chalk.yellow('Workflow already exists:'), path.relative(getRootDir(), dest));
|
|
23
32
|
return;
|
|
24
33
|
}
|
|
25
34
|
let mopsTestYml = new URL('../templates/mops-test.yml', import.meta.url);
|
|
26
35
|
fs.mkdirSync(path.resolve(getRootDir(), '.github/workflows'), {recursive: true});
|
|
27
36
|
fs.copyFileSync(mopsTestYml, dest);
|
|
28
|
-
console.log(chalk.green('
|
|
37
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), dest));
|
|
38
|
+
}
|
|
39
|
+
else if (templateName?.startsWith('license:')) {
|
|
40
|
+
let dest = path.resolve(getRootDir(), 'LICENSE');
|
|
41
|
+
if (fs.existsSync(dest)) {
|
|
42
|
+
console.log(chalk.yellow('LICENSE already exists'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let setYearAndOwner = (file: string) => {
|
|
47
|
+
let license = fs.readFileSync(file).toString();
|
|
48
|
+
license = license.replace(/<year>/g, new Date().getFullYear().toString());
|
|
49
|
+
if (options.copyrightOwner) {
|
|
50
|
+
license = license.replace(/<copyright-owner>/g, options.copyrightOwner);
|
|
51
|
+
}
|
|
52
|
+
fs.writeFileSync(file, license);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (templateName === 'license:MIT') {
|
|
56
|
+
fs.copyFileSync(new URL('../templates/licenses/MIT', import.meta.url), path.resolve(getRootDir(), 'LICENSE'));
|
|
57
|
+
setYearAndOwner(path.resolve(getRootDir(), 'LICENSE'));
|
|
58
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'LICENSE'));
|
|
59
|
+
}
|
|
60
|
+
else if (templateName === 'license:Apache-2.0') {
|
|
61
|
+
fs.copyFileSync(new URL('../templates/licenses/Apache-2.0', import.meta.url), path.resolve(getRootDir(), 'LICENSE'));
|
|
62
|
+
fs.copyFileSync(new URL('../templates/licenses/Apache-2.0-NOTICE', import.meta.url), path.resolve(getRootDir(), 'NOTICE'));
|
|
63
|
+
setYearAndOwner(path.resolve(getRootDir(), 'NOTICE'));
|
|
64
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'LICENSE'));
|
|
65
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'NOTICE'));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (templateName === 'lib.mo') {
|
|
69
|
+
fs.mkdirSync(path.join(getRootDir(), 'src'), {recursive: true});
|
|
70
|
+
fs.copyFileSync(new URL('../templates/src/lib.mo', import.meta.url), path.resolve(getRootDir(), 'src/lib.mo'));
|
|
71
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'src/lib.mo'));
|
|
72
|
+
}
|
|
73
|
+
else if (templateName === 'lib.test.mo') {
|
|
74
|
+
fs.mkdirSync(path.join(getRootDir(), 'test'), {recursive: true});
|
|
75
|
+
fs.copyFileSync(new URL('../templates/test/lib.test.mo', import.meta.url), path.resolve(getRootDir(), 'test/lib.test.mo'));
|
|
76
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'test/lib.test.mo'));
|
|
77
|
+
}
|
|
78
|
+
else if (templateName === 'readme') {
|
|
79
|
+
let dest = path.resolve(getRootDir(), 'README.md');
|
|
80
|
+
if (fs.existsSync(dest)) {
|
|
81
|
+
console.log(chalk.yellow('README.md already exists'));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
fs.copyFileSync(new URL('../templates/README.md', import.meta.url), dest);
|
|
85
|
+
|
|
86
|
+
let config = readConfig();
|
|
87
|
+
|
|
88
|
+
let data = fs.readFileSync(dest).toString();
|
|
89
|
+
data = data.replace(/<year>/g, new Date().getFullYear().toString());
|
|
90
|
+
if (config.package?.name) {
|
|
91
|
+
data = data.replace(/<name>/g, config.package.name);
|
|
92
|
+
data = data.replace(/<import-name>/g, camelCase(config.package.name, {pascalCase: true}));
|
|
93
|
+
}
|
|
94
|
+
fs.writeFileSync(dest, data);
|
|
95
|
+
|
|
96
|
+
console.log(chalk.green('Created'), path.relative(getRootDir(), 'README.md'));
|
|
29
97
|
}
|
|
30
98
|
}
|