@liangmi/mo 1.0.0 → 1.0.2
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 +13 -0
- package/dist/mo.mjs +75 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,8 +47,21 @@ mo setup
|
|
|
47
47
|
|
|
48
48
|
`mo cd`, `mo edit`, and `mo open` open an interactive selector when called without arguments.
|
|
49
49
|
|
|
50
|
+
> [!TIP]
|
|
51
|
+
> If you are using `mo` with VS Code based editors, you can add this line to your editor config to prevent `mo edit` popping up a new separated window.
|
|
52
|
+
>
|
|
53
|
+
> ```json
|
|
54
|
+
> "window.openFoldersInNewWindow": "off"
|
|
55
|
+
> ```
|
|
56
|
+
>
|
|
57
|
+
> Setting `code -r` as your editor in `mo setup` have the same effect as well.
|
|
58
|
+
|
|
50
59
|
## Config
|
|
51
60
|
|
|
61
|
+
The config file should be generated by running `mo setup`. Modifying `~/.config/morc.json` manually is not recommended.
|
|
62
|
+
|
|
63
|
+
Please follow the [config_schema.json](./config_schema.json) if you are developing `mo`.
|
|
64
|
+
|
|
52
65
|
`~/.config/morc.json`:
|
|
53
66
|
|
|
54
67
|
```json
|
package/dist/mo.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __require, r as __toESM, t as __commonJSMin } from "./chunk-CBBoxR_p.mjs";
|
|
2
2
|
import { C as untildify, S as parseAliasInput, _ as require_picocolors, a as ensureToolReady, b as defaultAliases, c as getDefaultConfigPath, d as error, f as icons, g as toTildePath, h as success, i as preventRunning, l as loadConfig, m as stopSpinner, n as getRestartFlagPath, o as runCommand, p as startSpinner, r as innerBinName, s as R, t as checkRestartRequired, u as supportedShells, v as aliasCommands, w as cac, x as getAliasPromptLabel } from "./runner-DW0Q4OMK.mjs";
|
|
3
3
|
import * as fs$1 from "node:fs";
|
|
4
|
-
import fs, { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
+
import fs, { existsSync, mkdirSync, readdirSync, rmSync, rmdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import os, { tmpdir } from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
@@ -13,7 +13,7 @@ import { Buffer as Buffer$1 } from "node:buffer";
|
|
|
13
13
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
14
14
|
import prompts from "prompts";
|
|
15
15
|
//#region package.json
|
|
16
|
-
var version = "1.0.
|
|
16
|
+
var version = "1.0.2";
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region src/commands/clone.ts
|
|
19
19
|
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
@@ -21,8 +21,9 @@ async function runCloneCommand(repo, config) {
|
|
|
21
21
|
const parsedRepo = parseRepo(repo);
|
|
22
22
|
const ownerDir = path.join(config.root, parsedRepo.owner);
|
|
23
23
|
const targetDir = path.join(ownerDir, parsedRepo.name);
|
|
24
|
+
const ownerExisted = existsSync(ownerDir);
|
|
24
25
|
if (existsSync(targetDir)) error(`Repository already exists at ${import_picocolors.default.cyan(toTildePath(targetDir))}`);
|
|
25
|
-
mkdirSync(ownerDir, { recursive: true });
|
|
26
|
+
if (!ownerExisted) mkdirSync(ownerDir, { recursive: true });
|
|
26
27
|
const cloneUrl = `https://github.com/${parsedRepo.owner}/${parsedRepo.name}.git`;
|
|
27
28
|
const spinner = startSpinner(`Cloning ${import_picocolors.default.bold(`${parsedRepo.owner}/${parsedRepo.name}`)}...`);
|
|
28
29
|
try {
|
|
@@ -32,10 +33,20 @@ async function runCloneCommand(repo, config) {
|
|
|
32
33
|
console.log(` ${import_picocolors.default.dim("→")} ${import_picocolors.default.cyan(toTildePath(targetDir))}`);
|
|
33
34
|
} catch (err) {
|
|
34
35
|
stopSpinner(spinner);
|
|
36
|
+
cleanupFailedClone(targetDir, ownerDir, ownerExisted);
|
|
35
37
|
const details = err instanceof Error ? `: ${err.message}` : "";
|
|
36
38
|
error(`Git clone failed for ${parsedRepo.owner}/${parsedRepo.name}${details}`);
|
|
37
39
|
}
|
|
38
40
|
}
|
|
41
|
+
function cleanupFailedClone(targetDir, ownerDir, ownerExisted) {
|
|
42
|
+
try {
|
|
43
|
+
if (existsSync(targetDir)) rmSync(targetDir, {
|
|
44
|
+
recursive: true,
|
|
45
|
+
force: true
|
|
46
|
+
});
|
|
47
|
+
if (!ownerExisted && existsSync(ownerDir) && readdirSync(ownerDir).length === 0) rmdirSync(ownerDir);
|
|
48
|
+
} catch {}
|
|
49
|
+
}
|
|
39
50
|
async function runGitClone(url, targetDir) {
|
|
40
51
|
const result = await R("git", [
|
|
41
52
|
"clone",
|
|
@@ -25187,6 +25198,53 @@ const useInput = (inputHandler, options = {}) => {
|
|
|
25187
25198
|
]);
|
|
25188
25199
|
};
|
|
25189
25200
|
//#endregion
|
|
25201
|
+
//#region src/utils/search.ts
|
|
25202
|
+
function getMatchScore(text, query) {
|
|
25203
|
+
const normalizedText = text.toLowerCase();
|
|
25204
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
25205
|
+
if (!normalizedQuery) return null;
|
|
25206
|
+
if (!normalizedText.includes(normalizedQuery)) return null;
|
|
25207
|
+
if (normalizedText === normalizedQuery) return 0;
|
|
25208
|
+
if (normalizedText.startsWith(normalizedQuery)) return 1;
|
|
25209
|
+
return 2;
|
|
25210
|
+
}
|
|
25211
|
+
function searchReposByName(query, groups) {
|
|
25212
|
+
const matches = [];
|
|
25213
|
+
for (const group of groups) for (const repo of group.repos) {
|
|
25214
|
+
const score = getMatchScore(repo.name, query);
|
|
25215
|
+
if (score === null) continue;
|
|
25216
|
+
matches.push({
|
|
25217
|
+
repo,
|
|
25218
|
+
score
|
|
25219
|
+
});
|
|
25220
|
+
}
|
|
25221
|
+
matches.sort((a, b) => {
|
|
25222
|
+
if (a.score !== b.score) return a.score - b.score;
|
|
25223
|
+
if (a.repo.name.length !== b.repo.name.length) return a.repo.name.length - b.repo.name.length;
|
|
25224
|
+
const byName = a.repo.name.localeCompare(b.repo.name);
|
|
25225
|
+
if (byName !== 0) return byName;
|
|
25226
|
+
return a.repo.owner.localeCompare(b.repo.owner);
|
|
25227
|
+
});
|
|
25228
|
+
return matches;
|
|
25229
|
+
}
|
|
25230
|
+
function searchOwnerGroupsByName(query, groups) {
|
|
25231
|
+
const matches = [];
|
|
25232
|
+
for (const group of groups) {
|
|
25233
|
+
const score = getMatchScore(group.owner, query);
|
|
25234
|
+
if (score === null) continue;
|
|
25235
|
+
matches.push({
|
|
25236
|
+
group,
|
|
25237
|
+
score
|
|
25238
|
+
});
|
|
25239
|
+
}
|
|
25240
|
+
matches.sort((a, b) => {
|
|
25241
|
+
if (a.score !== b.score) return a.score - b.score;
|
|
25242
|
+
if (a.group.owner.length !== b.group.owner.length) return a.group.owner.length - b.group.owner.length;
|
|
25243
|
+
return a.group.owner.localeCompare(b.group.owner);
|
|
25244
|
+
});
|
|
25245
|
+
return matches.map((match) => match.group);
|
|
25246
|
+
}
|
|
25247
|
+
//#endregion
|
|
25190
25248
|
//#region node_modules/.pnpm/react@19.2.4/node_modules/react/cjs/react-jsx-runtime.production.js
|
|
25191
25249
|
/**
|
|
25192
25250
|
* @license React
|
|
@@ -25464,28 +25522,17 @@ function buildListItems(root, groups) {
|
|
|
25464
25522
|
function searchItems(query, groups, root) {
|
|
25465
25523
|
const q = query.toLowerCase();
|
|
25466
25524
|
const items = [];
|
|
25467
|
-
const
|
|
25468
|
-
const
|
|
25469
|
-
|
|
25470
|
-
|
|
25471
|
-
|
|
25472
|
-
|
|
25473
|
-
|
|
25474
|
-
|
|
25475
|
-
|
|
25476
|
-
type: "project",
|
|
25477
|
-
label: repo.name,
|
|
25478
|
-
owner: repo.owner,
|
|
25479
|
-
path: repo.path,
|
|
25480
|
-
selectable: true
|
|
25481
|
-
}
|
|
25482
|
-
});
|
|
25483
|
-
matchedOwners.add(repo.owner);
|
|
25484
|
-
}
|
|
25485
|
-
projectMatches.sort((a, b) => a.score - b.score || a.item.label.length - b.item.label.length);
|
|
25486
|
-
const sortedProjects = projectMatches.map((m) => m.item);
|
|
25525
|
+
const projectMatches = searchReposByName(query, groups);
|
|
25526
|
+
const sortedProjects = projectMatches.map((match) => ({
|
|
25527
|
+
type: "project",
|
|
25528
|
+
label: match.repo.name,
|
|
25529
|
+
owner: match.repo.owner,
|
|
25530
|
+
path: match.repo.path,
|
|
25531
|
+
selectable: true
|
|
25532
|
+
}));
|
|
25533
|
+
const matchedOwners = new Set(projectMatches.map((match) => match.repo.owner));
|
|
25487
25534
|
if ("<root>".includes(q)) {
|
|
25488
|
-
const rootScore = "<root>"
|
|
25535
|
+
const rootScore = getMatchScore("<root>", query) ?? 3;
|
|
25489
25536
|
const rootItem = {
|
|
25490
25537
|
type: "project",
|
|
25491
25538
|
label: "<root>",
|
|
@@ -25824,9 +25871,10 @@ function resolveTarget(root, target, groups) {
|
|
|
25824
25871
|
const candidate = path.join(root, ...segments);
|
|
25825
25872
|
if (existsSync(candidate) && statSync(candidate).isDirectory()) return candidate;
|
|
25826
25873
|
}
|
|
25827
|
-
const
|
|
25828
|
-
|
|
25829
|
-
|
|
25874
|
+
const repoMatches = searchReposByName(target, groups);
|
|
25875
|
+
if (repoMatches.length) return repoMatches[0].repo.path;
|
|
25876
|
+
const ownerMatches = searchOwnerGroupsByName(target, groups);
|
|
25877
|
+
if (ownerMatches.length) return ownerMatches[0].path;
|
|
25830
25878
|
return null;
|
|
25831
25879
|
}
|
|
25832
25880
|
//#endregion
|