@magland/mochi 0.3.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.
Files changed (116) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +108 -0
  3. package/dist/ansi.js +174 -0
  4. package/dist/api/admin.js +416 -0
  5. package/dist/api/auth.js +166 -0
  6. package/dist/api/backup.js +598 -0
  7. package/dist/api/ci.js +336 -0
  8. package/dist/api/contents.js +339 -0
  9. package/dist/api/issues.js +165 -0
  10. package/dist/api/pulls.js +244 -0
  11. package/dist/api/releases.js +83 -0
  12. package/dist/api/repos.js +156 -0
  13. package/dist/api/write.js +518 -0
  14. package/dist/api.js +326 -0
  15. package/dist/assets.js +29 -0
  16. package/dist/atom.js +32 -0
  17. package/dist/atomic.js +171 -0
  18. package/dist/avatar.js +81 -0
  19. package/dist/browse.js +630 -0
  20. package/dist/build-info.json +4 -0
  21. package/dist/ci/actionref.js +86 -0
  22. package/dist/ci/api.js +829 -0
  23. package/dist/ci/artifacts.js +201 -0
  24. package/dist/ci/dispatch.js +30 -0
  25. package/dist/ci/engine.js +1321 -0
  26. package/dist/ci/expr.js +526 -0
  27. package/dist/ci/manual.js +199 -0
  28. package/dist/ci/present.js +82 -0
  29. package/dist/ci/protocol.js +6 -0
  30. package/dist/ci/runners.js +256 -0
  31. package/dist/ci/runs.js +208 -0
  32. package/dist/ci/trigger.js +28 -0
  33. package/dist/ci/views.js +441 -0
  34. package/dist/ci/wake.js +194 -0
  35. package/dist/ci/web.js +617 -0
  36. package/dist/ci/workflow.js +436 -0
  37. package/dist/cli/admin-cmd.js +324 -0
  38. package/dist/cli/api-cmd.js +128 -0
  39. package/dist/cli/backup-cmd.js +1500 -0
  40. package/dist/cli/exit.js +69 -0
  41. package/dist/cli/input.js +64 -0
  42. package/dist/cli/issue-cmd.js +243 -0
  43. package/dist/cli/output.js +93 -0
  44. package/dist/cli/parse.js +317 -0
  45. package/dist/cli/pr-cmd.js +289 -0
  46. package/dist/cli/release-cmd.js +171 -0
  47. package/dist/cli/repo-cmd.js +763 -0
  48. package/dist/cli/repo.js +101 -0
  49. package/dist/cli/run-cmd.js +438 -0
  50. package/dist/cli/target.js +54 -0
  51. package/dist/cli-api.js +84 -0
  52. package/dist/compare.js +111 -0
  53. package/dist/config.js +212 -0
  54. package/dist/credentials.js +235 -0
  55. package/dist/deploy-cli.js +859 -0
  56. package/dist/deploy-runner-cli.js +592 -0
  57. package/dist/diff.js +171 -0
  58. package/dist/discussion.js +253 -0
  59. package/dist/egress.js +559 -0
  60. package/dist/filecache.js +68 -0
  61. package/dist/find.js +162 -0
  62. package/dist/forms.js +737 -0
  63. package/dist/git.js +547 -0
  64. package/dist/githttp.js +428 -0
  65. package/dist/html.js +87 -0
  66. package/dist/icons.js +101 -0
  67. package/dist/import-cli.js +316 -0
  68. package/dist/index.js +752 -0
  69. package/dist/issues.js +308 -0
  70. package/dist/issueweb.js +447 -0
  71. package/dist/job-cli.js +197 -0
  72. package/dist/jobtoken.js +96 -0
  73. package/dist/languages.js +383 -0
  74. package/dist/layout.js +100 -0
  75. package/dist/lfs.js +438 -0
  76. package/dist/lfsstore.js +425 -0
  77. package/dist/limit.js +259 -0
  78. package/dist/logo.js +61 -0
  79. package/dist/markdown.js +382 -0
  80. package/dist/migrate.js +334 -0
  81. package/dist/multipart.js +90 -0
  82. package/dist/ops.js +869 -0
  83. package/dist/pagescript.js +465 -0
  84. package/dist/perms.js +370 -0
  85. package/dist/pointer.js +55 -0
  86. package/dist/profile.js +106 -0
  87. package/dist/pulls.js +320 -0
  88. package/dist/pullweb.js +461 -0
  89. package/dist/redirects.js +455 -0
  90. package/dist/releases.js +435 -0
  91. package/dist/render.js +233 -0
  92. package/dist/runner/actions.js +448 -0
  93. package/dist/runner/client.js +428 -0
  94. package/dist/runner/context.js +247 -0
  95. package/dist/runner/docker.js +197 -0
  96. package/dist/runner/externals.js +175 -0
  97. package/dist/runner/job.js +290 -0
  98. package/dist/runner/manual-run.js +272 -0
  99. package/dist/runner/overrides.js +554 -0
  100. package/dist/runner/steps.js +571 -0
  101. package/dist/runner/wake.js +84 -0
  102. package/dist/runner-cli.js +405 -0
  103. package/dist/scan.js +231 -0
  104. package/dist/server.js +424 -0
  105. package/dist/session.js +267 -0
  106. package/dist/site.js +259 -0
  107. package/dist/siteshost.js +94 -0
  108. package/dist/source.js +90 -0
  109. package/dist/style.js +1295 -0
  110. package/dist/themes.js +369 -0
  111. package/dist/vault.js +442 -0
  112. package/dist/version.js +88 -0
  113. package/dist/views.js +1007 -0
  114. package/dist/web.js +182 -0
  115. package/dist/webops.js +1402 -0
  116. package/package.json +71 -0
package/dist/diff.js ADDED
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderDiff = renderDiff;
4
+ const icons_1 = require("./icons");
5
+ const render_1 = require("./render");
6
+ // Unified diff to HTML. Two things a patch carries that a plain rendering
7
+ // throws away are recovered here: the line numbers each side of a hunk, and
8
+ // the shape of the change (how many lines each file gained and lost, and
9
+ // whether it was added, deleted, or renamed). Both are what a reader uses to
10
+ // orient in a diff, so both are rendered.
11
+ // Lines of a patch that describe the file rather than its content. The file
12
+ // header already says what these say - the path, the status, the counts - so
13
+ // they are dropped from the body, as GitHub drops them.
14
+ const HEADER_PREFIXES = [
15
+ '+++',
16
+ '---',
17
+ 'index ',
18
+ 'new file',
19
+ 'deleted file',
20
+ 'similarity',
21
+ 'dissimilarity',
22
+ 'rename ',
23
+ 'copy ',
24
+ 'old mode',
25
+ 'new mode',
26
+ ];
27
+ // These two do belong in the body: they say something about the content.
28
+ const NOTE_PREFIXES = ['Binary files', '\\'];
29
+ /** How many lines of one file's diff we render before offering the file instead. */
30
+ const MAX_FILE_LINES = 2000;
31
+ function parse(patch) {
32
+ const files = [];
33
+ let cur = null;
34
+ for (const line of patch.split('\n')) {
35
+ const start = line.match(/^diff --git a\/(.*) b\/(.*)$/);
36
+ if (line.startsWith('diff --git ')) {
37
+ cur = {
38
+ path: start ? start[2] : line.slice('diff --git '.length),
39
+ oldPath: start ? start[1] : '',
40
+ status: 'modified',
41
+ binary: false,
42
+ added: 0,
43
+ removed: 0,
44
+ lines: [],
45
+ };
46
+ files.push(cur);
47
+ continue;
48
+ }
49
+ if (!cur)
50
+ continue;
51
+ if (line.startsWith('new file'))
52
+ cur.status = 'added';
53
+ else if (line.startsWith('deleted file'))
54
+ cur.status = 'deleted';
55
+ else if (line.startsWith('rename to '))
56
+ cur.status = 'renamed';
57
+ else if (line.startsWith('Binary files'))
58
+ cur.binary = true;
59
+ else if (line.startsWith('+') && !line.startsWith('+++'))
60
+ cur.added++;
61
+ else if (line.startsWith('-') && !line.startsWith('---'))
62
+ cur.removed++;
63
+ cur.lines.push(line);
64
+ }
65
+ // A patch ends with a newline, which leaves an empty last line that is not
66
+ // part of anyone's file.
67
+ for (const f of files) {
68
+ while (f.lines.length > 0 && f.lines[f.lines.length - 1] === '')
69
+ f.lines.pop();
70
+ }
71
+ return files;
72
+ }
73
+ /**
74
+ * A bar beside a file's counts, in the proportion of the change: the share
75
+ * that was additions, then the share that was deletions, so a glance
76
+ * separates a rewrite from a one-line fix. A file that changed at all gets
77
+ * at least a tenth of the bar for each side it changed on, since a single
78
+ * deletion among four hundred additions should still be visible. The widths
79
+ * are inline because they are the datum; only the bar's shape is style.
80
+ */
81
+ function statBar(added, removed) {
82
+ const total = added + removed;
83
+ if (total === 0)
84
+ return '';
85
+ const add = added > 0 && removed > 0
86
+ ? Math.min(90, Math.max(10, Math.round((added / total) * 100)))
87
+ : added > 0
88
+ ? 100
89
+ : 0;
90
+ return `<span class="statbar" aria-hidden="true"><span class="add" style="width:${add}%"></span><span class="del" style="width:${100 - add}%"></span></span>`;
91
+ }
92
+ function counts(added, removed) {
93
+ return `<span class="stat-add">+${added}</span><span class="stat-del">&minus;${removed}</span>${statBar(added, removed)}`;
94
+ }
95
+ const STATUS_LABEL = {
96
+ added: 'added',
97
+ deleted: 'deleted',
98
+ renamed: 'renamed',
99
+ modified: 'modified',
100
+ };
101
+ function renderBody(file) {
102
+ if (file.binary)
103
+ return `<div class="diff-none muted">Binary file not shown.</div>`;
104
+ if (file.lines.length > MAX_FILE_LINES) {
105
+ return `<div class="diff-none muted">This diff is ${file.lines.length.toLocaleString('en-US')} lines long and is not shown.</div>`;
106
+ }
107
+ // Line numbers come from the hunk headers: a context line advances both
108
+ // sides, an addition only the new one, a removal only the old one.
109
+ let oldNo = 0;
110
+ let newNo = 0;
111
+ const rows = [];
112
+ for (const l of file.lines) {
113
+ let cls = 'ctx';
114
+ let left = '';
115
+ let right = '';
116
+ const hunk = l.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
117
+ if (HEADER_PREFIXES.some((p) => l.startsWith(p))) {
118
+ continue;
119
+ }
120
+ else if (hunk) {
121
+ oldNo = parseInt(hunk[1], 10);
122
+ newNo = parseInt(hunk[2], 10);
123
+ cls = 'hunk';
124
+ }
125
+ else if (NOTE_PREFIXES.some((p) => l.startsWith(p))) {
126
+ cls = 'meta';
127
+ }
128
+ else if (l.startsWith('+')) {
129
+ cls = 'add';
130
+ right = String(newNo++);
131
+ }
132
+ else if (l.startsWith('-')) {
133
+ cls = 'del';
134
+ left = String(oldNo++);
135
+ }
136
+ else if (l !== '') {
137
+ left = String(oldNo++);
138
+ right = String(newNo++);
139
+ }
140
+ rows.push(`<div class="dline ${cls}"><span class="dnum">${left}</span><span class="dnum">${right}</span><span class="dtext">${(0, render_1.esc)(l) || '&nbsp;'}</span></div>`);
141
+ }
142
+ if (rows.length === 0)
143
+ return `<div class="diff-none muted">No changes to the file's content.</div>`;
144
+ return `<div class="diff-body">${rows.join('')}</div>`;
145
+ }
146
+ function renderDiff(patch, opts = {}) {
147
+ const files = parse(patch);
148
+ if (files.length === 0)
149
+ return '<p class="muted">No changes.</p>';
150
+ const added = files.reduce((n, f) => n + f.added, 0);
151
+ const removed = files.reduce((n, f) => n + f.removed, 0);
152
+ const summary = `<div class="diff-summary"><b>${files.length} changed file${files.length === 1 ? '' : 's'}</b>${counts(added, removed)}</div>`;
153
+ const boxes = files
154
+ .map((f, i) => {
155
+ const view = opts.blobBase
156
+ ? `<a class="btn" href="${opts.blobBase}/${f.path
157
+ .split('/')
158
+ .map(encodeURIComponent)
159
+ .join('/')}" title="View the whole file at this revision">View file</a>`
160
+ : '';
161
+ const renamed = f.status === 'renamed' && f.oldPath ? `<span class="muted small">${(0, render_1.esc)(f.oldPath)} &rarr;</span>` : '';
162
+ // Each file is a <details>, so a reader can fold away what they have
163
+ // read; the summary keeps the name, the counts, and the way to the file.
164
+ return `<details class="diff-file" id="diff-${i}" open>
165
+ <summary class="diff-file-header">${(0, icons_1.icon)('chevron-down', 'fold')}${renamed}<span class="diff-path mono">${(0, render_1.esc)(f.path)}</span><span class="chip">${STATUS_LABEL[f.status]}</span><span class="diff-file-stat">${counts(f.added, f.removed)}</span>${view}</summary>
166
+ ${renderBody(f)}
167
+ </details>`;
168
+ })
169
+ .join('');
170
+ return `${summary}${boxes}`;
171
+ }
@@ -0,0 +1,253 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MAX_BODY = exports.MAX_TITLE = void 0;
37
+ exports.itemDir = itemDir;
38
+ exports.numericDirs = numericDirs;
39
+ exports.readDoc = readDoc;
40
+ exports.writeDoc = writeDoc;
41
+ exports.str = str;
42
+ exports.countComments = countComments;
43
+ exports.touch = touch;
44
+ exports.readComments = readComments;
45
+ exports.checkTitle = checkTitle;
46
+ exports.checkBody = checkBody;
47
+ exports.openFor = openFor;
48
+ exports.addComment = addComment;
49
+ exports.allocate = allocate;
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
52
+ const YAML = __importStar(require("yaml"));
53
+ const atomic_1 = require("./atomic");
54
+ const ops_1 = require("./ops");
55
+ // What issues and pull requests have in common.
56
+ //
57
+ // The two are stored the same way on purpose: a numbered directory holding a
58
+ // markdown file with a YAML frontmatter header, and a `comments/` directory of
59
+ // further markdown files beside it. A pull request is a discussion with a
60
+ // branch pair attached, so everything about the discussion half was written
61
+ // twice, and the copies had begun to drift in the small ways copies do. The
62
+ // bodies of `touch` differed only in a comment; `addComment` differed only in
63
+ // the noun in one message and the name of the header file.
64
+ //
65
+ // What is left in issues.ts and pulls.ts is what genuinely differs: labels and
66
+ // four sort orders on one side, base and head and merging on the other. What
67
+ // moved here is the storage shape, which neither owns.
68
+ //
69
+ // A `DiscussionKind` is how the caller says which of the two it is. It carries
70
+ // the header file's name, the directory the numbered ones sit in, and the noun
71
+ // to use in a message, because a person reading "That is longer than a
72
+ // discussion may be" would rightly wonder what a discussion is.
73
+ exports.MAX_TITLE = 200;
74
+ exports.MAX_BODY = 64 * 1024;
75
+ /** The directory for one numbered issue or pull request. */
76
+ function itemDir(kind, root, collection, repo, n) {
77
+ const dir = kind.dirFor(root, collection, repo);
78
+ if (!dir || !Number.isInteger(n) || n < 1)
79
+ return null;
80
+ return path.join(dir, String(n));
81
+ }
82
+ /** The numbered subdirectories of `dir`, in order. */
83
+ function numericDirs(dir) {
84
+ let entries;
85
+ try {
86
+ entries = fs.readdirSync(dir, { withFileTypes: true });
87
+ }
88
+ catch {
89
+ return [];
90
+ }
91
+ return entries
92
+ .filter((e) => e.isDirectory() && /^[1-9][0-9]*$/.test(e.name))
93
+ .map((e) => parseInt(e.name, 10))
94
+ .sort((a, b) => a - b);
95
+ }
96
+ /**
97
+ * A markdown file with a YAML frontmatter header, which is the shape of every
98
+ * file here. A file without a header is not one of ours and is skipped rather
99
+ * than guessed at.
100
+ */
101
+ function readDoc(file) {
102
+ let text;
103
+ try {
104
+ text = fs.readFileSync(file, 'utf8');
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ const m = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
110
+ if (!m)
111
+ return null;
112
+ let meta;
113
+ try {
114
+ meta = YAML.parse(m[1]);
115
+ }
116
+ catch {
117
+ return null;
118
+ }
119
+ if (typeof meta !== 'object' || meta === null)
120
+ return null;
121
+ return { meta: meta, body: m[2] };
122
+ }
123
+ function writeDoc(file, meta, body) {
124
+ const text = `---\n${YAML.stringify(meta).trimEnd()}\n---\n${body.replace(/\s+$/, '')}\n`;
125
+ (0, atomic_1.writeFileAtomic)(file, text, { mode: 0o600 });
126
+ }
127
+ function str(v, fallback = '') {
128
+ return typeof v === 'string' ? v : fallback;
129
+ }
130
+ function countComments(dir) {
131
+ try {
132
+ return fs.readdirSync(path.join(dir, 'comments')).filter((f) => /^[1-9][0-9]*\.md$/.test(f)).length;
133
+ }
134
+ catch {
135
+ return 0;
136
+ }
137
+ }
138
+ /**
139
+ * Move a directory's timestamp, which is what invalidates the memoized open and
140
+ * closed counts shown on every repository page. Every write calls it.
141
+ */
142
+ function touch(dir) {
143
+ const now = new Date();
144
+ try {
145
+ fs.utimesSync(dir, now, now);
146
+ }
147
+ catch {
148
+ // The directory may not exist yet; the next read simply misses the cache.
149
+ }
150
+ }
151
+ /** Every comment on one issue or pull request, oldest first. */
152
+ function readComments(dir) {
153
+ let files = [];
154
+ try {
155
+ files = fs.readdirSync(path.join(dir, 'comments'));
156
+ }
157
+ catch {
158
+ return [];
159
+ }
160
+ const out = [];
161
+ for (const f of files.filter((x) => /^[1-9][0-9]*\.md$/.test(x)).sort((a, b) => parseInt(a, 10) - parseInt(b, 10))) {
162
+ const c = readDoc(path.join(dir, 'comments', f));
163
+ if (!c)
164
+ continue;
165
+ out.push({
166
+ id: parseInt(f, 10),
167
+ author: str(c.meta.author, 'unknown'),
168
+ created: str(c.meta.created),
169
+ body: c.body,
170
+ });
171
+ }
172
+ return out;
173
+ }
174
+ function checkTitle(kind, title) {
175
+ const t = title.trim().replace(/\s+/g, ' ');
176
+ if (t === '')
177
+ throw new ops_1.OpError(`${kind.Indefinite} needs a title.`);
178
+ if (t.length > exports.MAX_TITLE)
179
+ throw new ops_1.OpError(`A title may be at most ${exports.MAX_TITLE} characters.`);
180
+ return t;
181
+ }
182
+ function checkBody(kind, body) {
183
+ const b = body.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
184
+ if (b.length > exports.MAX_BODY)
185
+ throw new ops_1.OpError(`That is longer than ${kind.indefinite} may be.`);
186
+ return b;
187
+ }
188
+ /** Read a header for a write, refusing if it is not there. */
189
+ function openFor(kind, root, collection, repo, n) {
190
+ const dir = itemDir(kind, root, collection, repo, n);
191
+ const doc = dir ? readDoc(path.join(dir, kind.doc)) : null;
192
+ if (!dir || !doc)
193
+ throw new ops_1.OpError(`${kind.Bare} ${n} does not exist.`, 'notfound');
194
+ return { dir, doc };
195
+ }
196
+ function addComment(kind, root, collection, repo, n, input) {
197
+ const { dir, doc } = openFor(kind, root, collection, repo, n);
198
+ const body = checkBody(kind, input.body);
199
+ if (body.trim() === '')
200
+ throw new ops_1.OpError('A comment needs something in it.');
201
+ const commentsDir = path.join(dir, 'comments');
202
+ fs.mkdirSync(commentsDir, { recursive: true });
203
+ const used = fs
204
+ .readdirSync(commentsDir)
205
+ .filter((f) => /^[1-9][0-9]*\.md$/.test(f))
206
+ .map((f) => parseInt(f, 10));
207
+ const now = new Date().toISOString();
208
+ let id = (used.length ? Math.max(...used) : 0) + 1;
209
+ for (let attempt = 0; attempt < 50; attempt++, id++) {
210
+ const file = path.join(commentsDir, `${id}.md`);
211
+ // Exclusive create is the allocation, as mkdir is for the numbers: an
212
+ // existsSync test leaves a window in which two writers pick the same id,
213
+ // and the second write would then replace the first comment outright.
214
+ try {
215
+ fs.closeSync(fs.openSync(file, 'wx'));
216
+ }
217
+ catch {
218
+ continue;
219
+ }
220
+ writeDoc(file, { author: input.author, created: now }, body);
221
+ writeDoc(path.join(dir, kind.doc), { ...doc.meta, updated: now }, doc.body);
222
+ const container = kind.dirFor(root, collection, repo);
223
+ if (container)
224
+ touch(container);
225
+ return { id, author: input.author, created: now, body };
226
+ }
227
+ throw new ops_1.OpError('Could not add the comment; try again.', 'conflict');
228
+ }
229
+ /**
230
+ * Allocate the next free number and build the directory for it.
231
+ *
232
+ * mkdir is the allocation: whoever creates the directory owns the number, and
233
+ * the filesystem decides that rather than a check that two writers could both
234
+ * pass. A racing writer gets EEXIST and tries the next one.
235
+ */
236
+ function allocate(kind, dir, write) {
237
+ fs.mkdirSync(dir, { recursive: true });
238
+ let n = (numericDirs(dir).pop() ?? 0) + 1;
239
+ for (let attempt = 0; attempt < 50; attempt++, n++) {
240
+ const sub = path.join(dir, String(n));
241
+ try {
242
+ fs.mkdirSync(sub);
243
+ }
244
+ catch {
245
+ continue;
246
+ }
247
+ fs.mkdirSync(path.join(sub, 'comments'), { recursive: true });
248
+ write(sub, n);
249
+ touch(dir);
250
+ return n;
251
+ }
252
+ throw new ops_1.OpError(`Could not allocate ${kind.indefinite} number; try again.`, 'conflict');
253
+ }