ic-mops 1.8.1 → 1.9.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.
Files changed (47) hide show
  1. package/.DS_Store +0 -0
  2. package/.dockerignore +3 -0
  3. package/CHANGELOG.md +4 -0
  4. package/bun.lock +1278 -0
  5. package/bundle/bench/bench-canister.mo +109 -101
  6. package/bundle/bench/user-bench.mo +6 -6
  7. package/bundle/cli.js +1793 -909
  8. package/bundle/cli.tgz +0 -0
  9. package/bundle/declarations/main/main.did +6 -0
  10. package/bundle/declarations/main/main.did.d.ts +6 -0
  11. package/bundle/declarations/main/main.did.js +6 -0
  12. package/bundle/package.json +1 -1
  13. package/bundle/templates/src/lib.mo +13 -13
  14. package/bundle/templates/test/lib.test.mo +2 -2
  15. package/bundle/xhr-sync-worker.js +59 -0
  16. package/cli.ts +28 -0
  17. package/commands/docs-coverage.ts +110 -0
  18. package/commands/docs.ts +47 -20
  19. package/commands/publish.ts +11 -1
  20. package/declarations/main/main.did +6 -0
  21. package/declarations/main/main.did.d.ts +6 -0
  22. package/declarations/main/main.did.js +6 -0
  23. package/dist/cli.js +25 -0
  24. package/dist/commands/bench-replica.js +5 -2
  25. package/dist/commands/docs-coverage.d.ts +8 -0
  26. package/dist/commands/docs-coverage.js +86 -0
  27. package/dist/commands/docs.d.ts +9 -3
  28. package/dist/commands/docs.js +34 -17
  29. package/dist/commands/publish.js +10 -1
  30. package/dist/commands/replica.js +8 -7
  31. package/dist/commands/test/mmf1.js +14 -12
  32. package/dist/commands/test/reporters/compact-reporter.js +50 -63
  33. package/dist/commands/test/reporters/files-reporter.js +5 -14
  34. package/dist/commands/test/reporters/silent-reporter.js +10 -10
  35. package/dist/commands/test/reporters/verbose-reporter.js +7 -23
  36. package/dist/commands/watch/deployer.js +10 -7
  37. package/dist/commands/watch/error-checker.js +4 -4
  38. package/dist/commands/watch/formatter.js +7 -4
  39. package/dist/commands/watch/generator.js +9 -7
  40. package/dist/commands/watch/tester.js +7 -5
  41. package/dist/commands/watch/warning-checker.js +8 -6
  42. package/dist/declarations/main/main.did +6 -0
  43. package/dist/declarations/main/main.did.d.ts +6 -0
  44. package/dist/declarations/main/main.did.js +6 -0
  45. package/dist/package.json +13 -11
  46. package/package.json +15 -13
  47. package/tsconfig.json +2 -1
package/bundle/cli.tgz CHANGED
Binary file
@@ -218,6 +218,7 @@ type PackageSummary =
218
218
  type PackageQuality =
219
219
  record {
220
220
  depsStatus: DepsStatus;
221
+ docsCoverage: float64;
221
222
  hasDescription: bool;
222
223
  hasDocumentation: bool;
223
224
  hasKeywords: bool;
@@ -249,6 +250,7 @@ type PackageDetails =
249
250
  dependents: vec PackageSummary__1;
250
251
  deps: vec PackageSummary__1;
251
252
  devDeps: vec PackageSummary__1;
253
+ docsCoverage: float64;
252
254
  downloadTrend: vec DownloadsSnapshot;
253
255
  downloadsInLast30Days: nat;
254
256
  downloadsInLast7Days: nat;
@@ -308,10 +310,12 @@ type PackageConfigV3 =
308
310
  type PackageChanges =
309
311
  record {
310
312
  curBenchmarks: Benchmarks__1;
313
+ curDocsCoverage: float64;
311
314
  deps: vec DepChange;
312
315
  devDeps: vec DepChange;
313
316
  notes: text;
314
317
  prevBenchmarks: Benchmarks__1;
318
+ prevDocsCoverage: float64;
315
319
  tests: TestsChanges;
316
320
  };
317
321
  type Main =
@@ -379,11 +383,13 @@ type Main =
379
383
  removeOwner: (PackageName__1, principal) -> (Result_3);
380
384
  restore: (nat) -> ();
381
385
  search: (Text, opt nat, opt nat) -> (vec PackageSummary, PageCount) query;
386
+ setStorageControllers: () -> ();
382
387
  setUserProp: (text, text) -> (Result_3);
383
388
  startFileUpload: (PublishingId, Text, nat, blob) -> (Result_2);
384
389
  startPublish: (PackageConfigV3_Publishing) -> (Result_1);
385
390
  transformRequest: (HttpTransformArg) -> (HttpResponse) query;
386
391
  uploadBenchmarks: (PublishingId, Benchmarks) -> (Result);
392
+ uploadDocsCoverage: (PublishingId, float64) -> (Result);
387
393
  uploadFileChunk: (PublishingId, FileId, nat, blob) -> (Result);
388
394
  uploadNotes: (PublishingId, text) -> (Result);
389
395
  uploadTestStats: (PublishingId, TestStats) -> (Result);
@@ -124,6 +124,7 @@ export interface Main {
124
124
  [Text, [] | [bigint], [] | [bigint]],
125
125
  [Array<PackageSummary>, PageCount]
126
126
  >,
127
+ 'setStorageControllers' : ActorMethod<[], undefined>,
127
128
  'setUserProp' : ActorMethod<[string, string], Result_3>,
128
129
  'startFileUpload' : ActorMethod<
129
130
  [PublishingId, Text, bigint, Uint8Array | number[]],
@@ -132,6 +133,7 @@ export interface Main {
132
133
  'startPublish' : ActorMethod<[PackageConfigV3_Publishing], Result_1>,
133
134
  'transformRequest' : ActorMethod<[HttpTransformArg], HttpResponse>,
134
135
  'uploadBenchmarks' : ActorMethod<[PublishingId, Benchmarks], Result>,
136
+ 'uploadDocsCoverage' : ActorMethod<[PublishingId, number], Result>,
135
137
  'uploadFileChunk' : ActorMethod<
136
138
  [PublishingId, FileId, bigint, Uint8Array | number[]],
137
139
  Result
@@ -143,8 +145,10 @@ export interface PackageChanges {
143
145
  'tests' : TestsChanges,
144
146
  'deps' : Array<DepChange>,
145
147
  'curBenchmarks' : Benchmarks__1,
148
+ 'prevDocsCoverage' : number,
146
149
  'prevBenchmarks' : Benchmarks__1,
147
150
  'notes' : string,
151
+ 'curDocsCoverage' : number,
148
152
  'devDeps' : Array<DepChange>,
149
153
  }
150
154
  export interface PackageConfigV3 {
@@ -196,6 +200,7 @@ export interface PackageDetails {
196
200
  'quality' : PackageQuality,
197
201
  'publisher' : User,
198
202
  'testStats' : TestStats__1,
203
+ 'docsCoverage' : number,
199
204
  'highestVersion' : PackageVersion,
200
205
  'downloadsTotal' : bigint,
201
206
  'downloadsInLast30Days' : bigint,
@@ -223,6 +228,7 @@ export interface PackagePublication {
223
228
  }
224
229
  export interface PackageQuality {
225
230
  'depsStatus' : DepsStatus,
231
+ 'docsCoverage' : number,
226
232
  'hasDescription' : boolean,
227
233
  'hasKeywords' : boolean,
228
234
  'hasLicense' : boolean,
@@ -48,6 +48,7 @@ export const idlFactory = ({ IDL }) => {
48
48
  });
49
49
  const PackageQuality = IDL.Record({
50
50
  'depsStatus' : DepsStatus,
51
+ 'docsCoverage' : IDL.Float64,
51
52
  'hasDescription' : IDL.Bool,
52
53
  'hasKeywords' : IDL.Bool,
53
54
  'hasLicense' : IDL.Bool,
@@ -161,8 +162,10 @@ export const idlFactory = ({ IDL }) => {
161
162
  'tests' : TestsChanges,
162
163
  'deps' : IDL.Vec(DepChange),
163
164
  'curBenchmarks' : Benchmarks__1,
165
+ 'prevDocsCoverage' : IDL.Float64,
164
166
  'prevBenchmarks' : Benchmarks__1,
165
167
  'notes' : IDL.Text,
168
+ 'curDocsCoverage' : IDL.Float64,
166
169
  'devDeps' : IDL.Vec(DepChange),
167
170
  });
168
171
  const PackageSummaryWithChanges__1 = IDL.Record({
@@ -192,6 +195,7 @@ export const idlFactory = ({ IDL }) => {
192
195
  'quality' : PackageQuality,
193
196
  'publisher' : User,
194
197
  'testStats' : TestStats__1,
198
+ 'docsCoverage' : IDL.Float64,
195
199
  'highestVersion' : PackageVersion,
196
200
  'downloadsTotal' : IDL.Nat,
197
201
  'downloadsInLast30Days' : IDL.Nat,
@@ -428,6 +432,7 @@ export const idlFactory = ({ IDL }) => {
428
432
  [IDL.Vec(PackageSummary), PageCount],
429
433
  ['query'],
430
434
  ),
435
+ 'setStorageControllers' : IDL.Func([], [], []),
431
436
  'setUserProp' : IDL.Func([IDL.Text, IDL.Text], [Result_3], []),
432
437
  'startFileUpload' : IDL.Func(
433
438
  [PublishingId, Text, IDL.Nat, IDL.Vec(IDL.Nat8)],
@@ -441,6 +446,7 @@ export const idlFactory = ({ IDL }) => {
441
446
  ['query'],
442
447
  ),
443
448
  'uploadBenchmarks' : IDL.Func([PublishingId, Benchmarks], [Result], []),
449
+ 'uploadDocsCoverage' : IDL.Func([PublishingId, IDL.Float64], [Result], []),
444
450
  'uploadFileChunk' : IDL.Func(
445
451
  [PublishingId, FileId, IDL.Nat, IDL.Vec(IDL.Nat8)],
446
452
  [Result],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ic-mops",
3
- "version": "1.7.2",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mops": "bin/mops.js",
@@ -1,15 +1,15 @@
1
1
  module {
2
- // This comment will not be included in the documentation
3
- // Use triple slash for documentation
2
+ // This comment will not be included in the documentation
3
+ // Use triple slash for documentation
4
4
 
5
- /// Add two natural numbers
6
- ///
7
- /// Example:
8
- /// ```motoko
9
- /// assert add(1, 2) == 3;
10
- /// assert add(7, 3) == 10;
11
- /// ```
12
- public func add(x : Nat, y : Nat) : Nat {
13
- return x + y;
14
- };
15
- };
5
+ /// Add two natural numbers
6
+ ///
7
+ /// Example:
8
+ /// ```motoko
9
+ /// assert add(1, 2) == 3;
10
+ /// assert add(7, 3) == 10;
11
+ /// ```
12
+ public func add(x : Nat, y : Nat) : Nat {
13
+ return x + y;
14
+ };
15
+ };
@@ -1,4 +1,4 @@
1
- import {add} "../src";
1
+ import { add } "../src";
2
2
 
3
3
  assert add(1, 2) == 3;
4
- assert add(3, 22) == 25;
4
+ assert add(3, 22) == 25;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ const util = require("util");
3
+ const { JSDOM } = require("../../../..");
4
+ const { READY_STATES } = require("./xhr-utils");
5
+ const idlUtils = require("../generated/utils");
6
+ const tough = require("tough-cookie");
7
+
8
+ const dom = new JSDOM();
9
+ const xhr = new dom.window.XMLHttpRequest();
10
+ const xhrImpl = idlUtils.implForWrapper(xhr);
11
+
12
+ const chunks = [];
13
+
14
+ process.stdin.on("data", chunk => {
15
+ chunks.push(chunk);
16
+ });
17
+
18
+ process.stdin.on("end", () => {
19
+ const buffer = Buffer.concat(chunks);
20
+
21
+ const flag = JSON.parse(buffer.toString());
22
+ if (flag.body && flag.body.type === "Buffer" && flag.body.data) {
23
+ flag.body = Buffer.from(flag.body.data);
24
+ }
25
+ if (flag.cookieJar) {
26
+ flag.cookieJar = tough.CookieJar.fromJSON(flag.cookieJar);
27
+ }
28
+
29
+ flag.synchronous = false;
30
+ Object.assign(xhrImpl.flag, flag);
31
+ const { properties } = xhrImpl;
32
+ xhrImpl.readyState = READY_STATES.OPENED;
33
+ try {
34
+ xhr.addEventListener("loadend", () => {
35
+ if (properties.error) {
36
+ properties.error = properties.error.stack || util.inspect(properties.error);
37
+ }
38
+ process.stdout.write(JSON.stringify({
39
+ responseURL: xhrImpl.responseURL,
40
+ status: xhrImpl.status,
41
+ statusText: xhrImpl.statusText,
42
+ properties
43
+ }), () => {
44
+ process.exit(0);
45
+ });
46
+ }, false);
47
+ xhr.send(flag.body);
48
+ } catch (error) {
49
+ properties.error += error.stack || util.inspect(error);
50
+ process.stdout.write(JSON.stringify({
51
+ responseURL: xhrImpl.responseURL,
52
+ status: xhrImpl.status,
53
+ statusText: xhrImpl.statusText,
54
+ properties
55
+ }), () => {
56
+ process.exit(0);
57
+ });
58
+ }
59
+ });
package/cli.ts CHANGED
@@ -30,6 +30,8 @@ import {watch} from './commands/watch/watch.js';
30
30
  import {addOwner, printOwners, removeOwner} from './commands/owner.js';
31
31
  import {addMaintainer, printMaintainers, removeMaintainer} from './commands/maintainer.js';
32
32
  import {format} from './commands/format.js';
33
+ import {docs} from './commands/docs.js';
34
+ import {docsCoverage} from './commands/docs-coverage.js';
33
35
 
34
36
  declare global {
35
37
  // eslint-disable-next-line no-var
@@ -494,4 +496,30 @@ program
494
496
  }
495
497
  });
496
498
 
499
+ // docs
500
+ const docsCommand = new Command('docs').description('Documentation management');
501
+
502
+ docsCommand
503
+ .command('generate')
504
+ .description('Generate documentation for Motoko code')
505
+ .addOption(new Option('--source <source>', 'Source directory').default('src'))
506
+ .addOption(new Option('--output <output>', 'Output directory').default('docs'))
507
+ .addOption(new Option('--format <format>', 'Output format').default('md').choices(['md', 'adoc', 'html']))
508
+ .action(async (options) => {
509
+ checkConfigFile(true);
510
+ await docs(options);
511
+ });
512
+
513
+ docsCommand
514
+ .command('coverage')
515
+ .description('Documentation coverage report')
516
+ .addOption(new Option('-s, --source <source>', 'Source directory (with .mo files)').default('src'))
517
+ .addOption(new Option('-r, --reporter <reporter>', 'Coverage reporter').choices(['files', 'compact', 'missing', 'verbose']).default('files'))
518
+ .addOption(new Option('-t, --threshold <threshold>', 'Coverage threshold (0-100). If total coverage is below threshold, exit with error code 1').default(70))
519
+ .action(async (options) => {
520
+ checkConfigFile(true);
521
+ await docsCoverage(options);
522
+ });
523
+ program.addCommand(docsCommand);
524
+
497
525
  program.parse();
@@ -0,0 +1,110 @@
1
+ import {readFileSync} from 'node:fs';
2
+ import chalk from 'chalk';
3
+ import {globSync} from 'glob';
4
+ import {JSDOM} from 'jsdom';
5
+ import {docs} from './docs.js';
6
+
7
+ export type DocsCoverageReporter = 'compact' | 'files' | 'missing' | 'verbose' | 'silent';
8
+
9
+ type DocsCoverageOptions = {
10
+ source : string,
11
+ reporter : DocsCoverageReporter,
12
+ threshold : number,
13
+ };
14
+
15
+ export async function docsCoverage(options : Partial<DocsCoverageOptions> = {}) {
16
+ let docsDir = '.mops/.docs';
17
+
18
+ let {source, reporter, threshold} = {
19
+ source: 'src',
20
+ reporter: 'files',
21
+ threshold: 0,
22
+ ...options,
23
+ };
24
+
25
+ await docs({
26
+ source,
27
+ output: docsDir,
28
+ format: 'html',
29
+ silent: true,
30
+ });
31
+
32
+ let files = globSync(`${docsDir}/**/*.html`, {ignore: [`${docsDir}/**/index.html`]});
33
+ let coverages = [];
34
+
35
+ for (let file of files) {
36
+ let coverage = docFileCoverage(file);
37
+ coverages.push(coverage);
38
+
39
+ if (reporter === 'silent') {
40
+ continue;
41
+ }
42
+ if (reporter !== 'compact' && (reporter !== 'missing' || coverage.coverage < 100)) {
43
+ console.log(`• ${coverage.file} ${colorizeCoverage(coverage.coverage)}`);
44
+ }
45
+ if (reporter === 'missing' && coverage.coverage < 100) {
46
+ for (let item of coverage.items) {
47
+ if (!item.covered) {
48
+ console.log(` ${item.covered ? chalk.green('✓') : chalk.red('✖')} ${item.id} ${chalk.gray(item.type)}`);
49
+ }
50
+ }
51
+ }
52
+ else if (reporter === 'verbose') {
53
+ for (let item of coverage.items) {
54
+ console.log(` ${item.covered ? chalk.green('✓') : chalk.red('✖')} ${item.id} ${chalk.gray(item.type)}`);
55
+ }
56
+ }
57
+ }
58
+
59
+ if (reporter !== 'compact' && reporter !== 'silent') {
60
+ console.log('-'.repeat(50));
61
+ }
62
+
63
+ let totalCoverage = coverages.reduce((acc, coverage) => acc + coverage.coverage, 0) / (coverages.length || 1);
64
+ if (reporter !== 'silent') {
65
+ console.log(`Documentation coverage: ${colorizeCoverage(totalCoverage)}`);
66
+ }
67
+
68
+ if (threshold > 0 && totalCoverage < threshold) {
69
+ process.exit(1);
70
+ }
71
+
72
+ return totalCoverage;
73
+ }
74
+
75
+ function docFileCoverage(file : string) {
76
+ let dom = new JSDOM(readFileSync(file, 'utf-8'));
77
+
78
+ let module = dom.window.document.querySelector('h1')?.textContent || '';
79
+ let moduleFile = `${module}.mo`;
80
+
81
+ let items = [...dom.window.document.querySelectorAll('h4')].map(h4 => {
82
+ let id = h4.getAttribute('id')?.replace('type.', '');
83
+ let type = h4.className.replace('-declaration', '').replace('function', 'func');
84
+ let definition = h4.textContent;
85
+ let comment = h4.parentElement?.querySelector('p + p')?.textContent;
86
+ return {file: moduleFile, id, type, definition, comment, covered: (comment || '').length >= 5};
87
+ });
88
+
89
+ let coverage = 0;
90
+ if (!items.length) {
91
+ coverage = 100;
92
+ }
93
+ else {
94
+ coverage = items.filter(item => item.covered).length / items.length * 100;
95
+ }
96
+
97
+ return {file: moduleFile, coverage, items};
98
+ }
99
+
100
+ function colorizeCoverage(coverage : number) {
101
+ if (coverage >= 90) {
102
+ return chalk.green(coverage.toFixed(2) + '%');
103
+ }
104
+ else if (coverage >= 50) {
105
+ return chalk.yellow(coverage.toFixed(2) + '%');
106
+ }
107
+ else {
108
+ return chalk.red(coverage.toFixed(2) + '%');
109
+ }
110
+ }
package/commands/docs.ts CHANGED
@@ -13,9 +13,30 @@ import {toolchain} from './toolchain/index.js';
13
13
 
14
14
  let moDocPath : string;
15
15
 
16
- export async function docs({silent = false} = {}) {
16
+ type DocsOptions = {
17
+ source : string,
18
+ output : string,
19
+ format : 'md' | 'adoc' | 'html',
20
+ silent : boolean,
21
+ archive : boolean,
22
+ };
23
+
24
+ export async function docs(options : Partial<DocsOptions> = {}) {
25
+ let {source, output, format, silent, archive} = {
26
+ source: 'src',
27
+ output: '.mops/.docs',
28
+ format: 'adoc',
29
+ silent: false,
30
+ archive: false,
31
+ ...options,
32
+ };
33
+
34
+ if (format === 'md') {
35
+ format = 'plain';
36
+ }
37
+
17
38
  let rootDir = getRootDir();
18
- let docsDir = path.join(rootDir, '.mops/.docs');
39
+ let docsDir = path.join(rootDir, output);
19
40
  let docsDirRelative = path.relative(process.cwd(), docsDir);
20
41
 
21
42
  deleteSync([docsDir], {force: true});
@@ -32,14 +53,18 @@ export async function docs({silent = false} = {}) {
32
53
 
33
54
  // generate docs
34
55
  await new Promise<void>((resolve) => {
35
- let proc = spawn(moDocPath, [`--source=${path.join(rootDir, 'src')}`, `--output=${docsDirRelative}`, '--format=adoc']);
56
+ let proc = spawn(moDocPath, [
57
+ `--source=${path.join(rootDir, source)}`,
58
+ `--output=${docsDirRelative}`,
59
+ `--format=${format}`,
60
+ ]);
36
61
 
37
62
  // stdout
38
63
  proc.stdout.on('data', (data) => {
39
64
  let text = data.toString().trim();
40
65
  let failedText = 'Failed to extract documentation';
41
66
  if (text.includes(failedText)) {
42
- console.log(text.replaceAll(failedText, chalk.yellow('Warning: ') + failedText));
67
+ silent ||console.log(text.replaceAll(failedText, chalk.yellow('Warning: ') + failedText));
43
68
  }
44
69
  silent || console.log('stdout', text);
45
70
  });
@@ -75,22 +100,24 @@ export async function docs({silent = false} = {}) {
75
100
  });
76
101
 
77
102
  // create archive
78
- let ignore = [
79
- `${docsDir}/**/*.test.adoc`,
80
- `${docsDir}/test/**/*`,
81
- ];
82
- let files = globSync(`${docsDir}/**/*.adoc`, {ignore}).map(f => path.relative(docsDir, f));
83
- files.sort();
84
- if (files.length) {
85
- let stream = createTar(
86
- {
87
- cwd: docsDir,
88
- gzip: true,
89
- portable: true,
90
- },
91
- files
92
- ).pipe(fs.createWriteStream(path.join(docsDir, 'docs.tgz')));
93
- await streamToPromise(stream);
103
+ if (archive) {
104
+ let ignore = [
105
+ `${docsDir}/**/*.test.adoc`,
106
+ `${docsDir}/test/**/*`,
107
+ ];
108
+ let files = globSync(`${docsDir}/**/*.adoc`, {ignore}).map(f => path.relative(docsDir, f));
109
+ files.sort();
110
+ if (files.length) {
111
+ let stream = createTar(
112
+ {
113
+ cwd: docsDir,
114
+ gzip: true,
115
+ portable: true,
116
+ },
117
+ files
118
+ ).pipe(fs.createWriteStream(path.join(docsDir, 'docs.tgz')));
119
+ await streamToPromise(stream);
120
+ }
94
121
  }
95
122
 
96
123
  silent || console.log(`${chalk.green('Documentation generated')} at ${docsDirRelative}`);
@@ -17,6 +17,7 @@ import {testWithReporter} from './test/test.js';
17
17
  import {SilentReporter} from './test/reporters/silent-reporter.js';
18
18
  import {findChangelogEntry} from '../helpers/find-changelog-entry.js';
19
19
  import {bench} from './bench.js';
20
+ import {docsCoverage} from './docs-coverage.js';
20
21
 
21
22
  export async function publish(options : {docs ?: boolean, test ?: boolean, bench ?: boolean, verbose ?: boolean} = {}) {
22
23
  if (!checkConfigFile()) {
@@ -230,9 +231,13 @@ export async function publish(options : {docs ?: boolean, test ?: boolean, bench
230
231
 
231
232
  // generate docs
232
233
  let docsFile = path.join(rootDir, '.mops/.docs/docs.tgz');
234
+ let docsCov = 0;
233
235
  if (options.docs) {
234
236
  console.log('Generating documentation...');
235
- await docs({silent: true});
237
+ docsCov = await docsCoverage({
238
+ reporter: 'silent',
239
+ });
240
+ await docs({silent: true, archive: true});
236
241
  if (fs.existsSync(docsFile)) {
237
242
  files.unshift(docsFile);
238
243
  }
@@ -336,6 +341,11 @@ export async function publish(options : {docs ?: boolean, test ?: boolean, bench
336
341
  await actor.uploadNotes(puiblishingId, changelog);
337
342
  }
338
343
 
344
+ // upload docs coverage
345
+ if (options.docs) {
346
+ await actor.uploadDocsCoverage(puiblishingId, docsCov);
347
+ }
348
+
339
349
  // upload files
340
350
  await parallel(8, files, async (file : string) => {
341
351
  progress();
@@ -218,6 +218,7 @@ type PackageSummary =
218
218
  type PackageQuality =
219
219
  record {
220
220
  depsStatus: DepsStatus;
221
+ docsCoverage: float64;
221
222
  hasDescription: bool;
222
223
  hasDocumentation: bool;
223
224
  hasKeywords: bool;
@@ -249,6 +250,7 @@ type PackageDetails =
249
250
  dependents: vec PackageSummary__1;
250
251
  deps: vec PackageSummary__1;
251
252
  devDeps: vec PackageSummary__1;
253
+ docsCoverage: float64;
252
254
  downloadTrend: vec DownloadsSnapshot;
253
255
  downloadsInLast30Days: nat;
254
256
  downloadsInLast7Days: nat;
@@ -308,10 +310,12 @@ type PackageConfigV3 =
308
310
  type PackageChanges =
309
311
  record {
310
312
  curBenchmarks: Benchmarks__1;
313
+ curDocsCoverage: float64;
311
314
  deps: vec DepChange;
312
315
  devDeps: vec DepChange;
313
316
  notes: text;
314
317
  prevBenchmarks: Benchmarks__1;
318
+ prevDocsCoverage: float64;
315
319
  tests: TestsChanges;
316
320
  };
317
321
  type Main =
@@ -379,11 +383,13 @@ type Main =
379
383
  removeOwner: (PackageName__1, principal) -> (Result_3);
380
384
  restore: (nat) -> ();
381
385
  search: (Text, opt nat, opt nat) -> (vec PackageSummary, PageCount) query;
386
+ setStorageControllers: () -> ();
382
387
  setUserProp: (text, text) -> (Result_3);
383
388
  startFileUpload: (PublishingId, Text, nat, blob) -> (Result_2);
384
389
  startPublish: (PackageConfigV3_Publishing) -> (Result_1);
385
390
  transformRequest: (HttpTransformArg) -> (HttpResponse) query;
386
391
  uploadBenchmarks: (PublishingId, Benchmarks) -> (Result);
392
+ uploadDocsCoverage: (PublishingId, float64) -> (Result);
387
393
  uploadFileChunk: (PublishingId, FileId, nat, blob) -> (Result);
388
394
  uploadNotes: (PublishingId, text) -> (Result);
389
395
  uploadTestStats: (PublishingId, TestStats) -> (Result);
@@ -124,6 +124,7 @@ export interface Main {
124
124
  [Text, [] | [bigint], [] | [bigint]],
125
125
  [Array<PackageSummary>, PageCount]
126
126
  >,
127
+ 'setStorageControllers' : ActorMethod<[], undefined>,
127
128
  'setUserProp' : ActorMethod<[string, string], Result_3>,
128
129
  'startFileUpload' : ActorMethod<
129
130
  [PublishingId, Text, bigint, Uint8Array | number[]],
@@ -132,6 +133,7 @@ export interface Main {
132
133
  'startPublish' : ActorMethod<[PackageConfigV3_Publishing], Result_1>,
133
134
  'transformRequest' : ActorMethod<[HttpTransformArg], HttpResponse>,
134
135
  'uploadBenchmarks' : ActorMethod<[PublishingId, Benchmarks], Result>,
136
+ 'uploadDocsCoverage' : ActorMethod<[PublishingId, number], Result>,
135
137
  'uploadFileChunk' : ActorMethod<
136
138
  [PublishingId, FileId, bigint, Uint8Array | number[]],
137
139
  Result
@@ -143,8 +145,10 @@ export interface PackageChanges {
143
145
  'tests' : TestsChanges,
144
146
  'deps' : Array<DepChange>,
145
147
  'curBenchmarks' : Benchmarks__1,
148
+ 'prevDocsCoverage' : number,
146
149
  'prevBenchmarks' : Benchmarks__1,
147
150
  'notes' : string,
151
+ 'curDocsCoverage' : number,
148
152
  'devDeps' : Array<DepChange>,
149
153
  }
150
154
  export interface PackageConfigV3 {
@@ -196,6 +200,7 @@ export interface PackageDetails {
196
200
  'quality' : PackageQuality,
197
201
  'publisher' : User,
198
202
  'testStats' : TestStats__1,
203
+ 'docsCoverage' : number,
199
204
  'highestVersion' : PackageVersion,
200
205
  'downloadsTotal' : bigint,
201
206
  'downloadsInLast30Days' : bigint,
@@ -223,6 +228,7 @@ export interface PackagePublication {
223
228
  }
224
229
  export interface PackageQuality {
225
230
  'depsStatus' : DepsStatus,
231
+ 'docsCoverage' : number,
226
232
  'hasDescription' : boolean,
227
233
  'hasKeywords' : boolean,
228
234
  'hasLicense' : boolean,
@@ -48,6 +48,7 @@ export const idlFactory = ({ IDL }) => {
48
48
  });
49
49
  const PackageQuality = IDL.Record({
50
50
  'depsStatus' : DepsStatus,
51
+ 'docsCoverage' : IDL.Float64,
51
52
  'hasDescription' : IDL.Bool,
52
53
  'hasKeywords' : IDL.Bool,
53
54
  'hasLicense' : IDL.Bool,
@@ -161,8 +162,10 @@ export const idlFactory = ({ IDL }) => {
161
162
  'tests' : TestsChanges,
162
163
  'deps' : IDL.Vec(DepChange),
163
164
  'curBenchmarks' : Benchmarks__1,
165
+ 'prevDocsCoverage' : IDL.Float64,
164
166
  'prevBenchmarks' : Benchmarks__1,
165
167
  'notes' : IDL.Text,
168
+ 'curDocsCoverage' : IDL.Float64,
166
169
  'devDeps' : IDL.Vec(DepChange),
167
170
  });
168
171
  const PackageSummaryWithChanges__1 = IDL.Record({
@@ -192,6 +195,7 @@ export const idlFactory = ({ IDL }) => {
192
195
  'quality' : PackageQuality,
193
196
  'publisher' : User,
194
197
  'testStats' : TestStats__1,
198
+ 'docsCoverage' : IDL.Float64,
195
199
  'highestVersion' : PackageVersion,
196
200
  'downloadsTotal' : IDL.Nat,
197
201
  'downloadsInLast30Days' : IDL.Nat,
@@ -428,6 +432,7 @@ export const idlFactory = ({ IDL }) => {
428
432
  [IDL.Vec(PackageSummary), PageCount],
429
433
  ['query'],
430
434
  ),
435
+ 'setStorageControllers' : IDL.Func([], [], []),
431
436
  'setUserProp' : IDL.Func([IDL.Text, IDL.Text], [Result_3], []),
432
437
  'startFileUpload' : IDL.Func(
433
438
  [PublishingId, Text, IDL.Nat, IDL.Vec(IDL.Nat8)],
@@ -441,6 +446,7 @@ export const idlFactory = ({ IDL }) => {
441
446
  ['query'],
442
447
  ),
443
448
  'uploadBenchmarks' : IDL.Func([PublishingId, Benchmarks], [Result], []),
449
+ 'uploadDocsCoverage' : IDL.Func([PublishingId, IDL.Float64], [Result], []),
444
450
  'uploadFileChunk' : IDL.Func(
445
451
  [PublishingId, FileId, IDL.Nat, IDL.Vec(IDL.Nat8)],
446
452
  [Result],
package/dist/cli.js CHANGED
@@ -28,6 +28,8 @@ import { watch } from './commands/watch/watch.js';
28
28
  import { addOwner, printOwners, removeOwner } from './commands/owner.js';
29
29
  import { addMaintainer, printMaintainers, removeMaintainer } from './commands/maintainer.js';
30
30
  import { format } from './commands/format.js';
31
+ import { docs } from './commands/docs.js';
32
+ import { docsCoverage } from './commands/docs-coverage.js';
31
33
  events.setMaxListeners(20);
32
34
  let networkFile = getNetworkFile();
33
35
  if (fs.existsSync(networkFile)) {
@@ -426,4 +428,27 @@ program
426
428
  process.exit(1);
427
429
  }
428
430
  });
431
+ // docs
432
+ const docsCommand = new Command('docs').description('Documentation management');
433
+ docsCommand
434
+ .command('generate')
435
+ .description('Generate documentation for Motoko code')
436
+ .addOption(new Option('--source <source>', 'Source directory').default('src'))
437
+ .addOption(new Option('--output <output>', 'Output directory').default('docs'))
438
+ .addOption(new Option('--format <format>', 'Output format').default('md').choices(['md', 'adoc', 'html']))
439
+ .action(async (options) => {
440
+ checkConfigFile(true);
441
+ await docs(options);
442
+ });
443
+ docsCommand
444
+ .command('coverage')
445
+ .description('Documentation coverage report')
446
+ .addOption(new Option('-s, --source <source>', 'Source directory (with .mo files)').default('src'))
447
+ .addOption(new Option('-r, --reporter <reporter>', 'Coverage reporter').choices(['files', 'compact', 'missing', 'verbose']).default('files'))
448
+ .addOption(new Option('-t, --threshold <threshold>', 'Coverage threshold (0-100). If total coverage is below threshold, exit with error code 1').default(70))
449
+ .action(async (options) => {
450
+ checkConfigFile(true);
451
+ await docsCoverage(options);
452
+ });
453
+ program.addCommand(docsCommand);
429
454
  program.parse();