@tbsten/mir-core 0.0.2-alpha02 → 0.0.2-alpha03
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/dist/__tests__/errors.test.d.ts +1 -0
- package/dist/__tests__/errors.test.js +51 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/helpers/string-helpers.test.d.ts +1 -0
- package/dist/__tests__/helpers/string-helpers.test.js +61 -0
- package/dist/__tests__/helpers/string-helpers.test.js.map +1 -0
- package/dist/__tests__/hooks.test.d.ts +1 -0
- package/dist/__tests__/hooks.test.js +125 -0
- package/dist/__tests__/hooks.test.js.map +1 -0
- package/dist/__tests__/i18n.test.d.ts +1 -0
- package/dist/__tests__/i18n.test.js +51 -0
- package/dist/__tests__/i18n.test.js.map +1 -0
- package/dist/__tests__/remote-registry.test.d.ts +1 -0
- package/dist/__tests__/remote-registry.test.js +194 -0
- package/dist/__tests__/remote-registry.test.js.map +1 -0
- package/dist/__tests__/safe-yaml-parser.test.d.ts +1 -0
- package/dist/__tests__/safe-yaml-parser.test.js +159 -0
- package/dist/__tests__/safe-yaml-parser.test.js.map +1 -0
- package/dist/__tests__/snapshots/error-messages.snapshot.test.d.ts +1 -0
- package/dist/__tests__/snapshots/error-messages.snapshot.test.js +52 -0
- package/dist/__tests__/snapshots/error-messages.snapshot.test.js.map +1 -0
- package/dist/__tests__/snapshots/snippet-schema-output.snapshot.test.d.ts +1 -0
- package/dist/__tests__/snapshots/snippet-schema-output.snapshot.test.js +93 -0
- package/dist/__tests__/snapshots/snippet-schema-output.snapshot.test.js.map +1 -0
- package/dist/__tests__/snapshots/template-output.snapshot.test.d.ts +1 -0
- package/dist/__tests__/snapshots/template-output.snapshot.test.js +60 -0
- package/dist/__tests__/snapshots/template-output.snapshot.test.js.map +1 -0
- package/dist/__tests__/snippet-schema.test.d.ts +1 -0
- package/dist/__tests__/snippet-schema.test.js +137 -0
- package/dist/__tests__/snippet-schema.test.js.map +1 -0
- package/dist/__tests__/symlink-checker.test.d.ts +1 -0
- package/dist/__tests__/symlink-checker.test.js +81 -0
- package/dist/__tests__/symlink-checker.test.js.map +1 -0
- package/dist/__tests__/template-engine.test.d.ts +1 -0
- package/dist/__tests__/template-engine.test.js +175 -0
- package/dist/__tests__/template-engine.test.js.map +1 -0
- package/dist/__tests__/validate-name.test.d.ts +1 -0
- package/dist/__tests__/validate-name.test.js +49 -0
- package/dist/__tests__/validate-name.test.js.map +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +68 -0
- package/dist/errors.js.map +1 -0
- package/dist/helpers/index.d.ts +5 -0
- package/dist/helpers/index.js +28 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/string-helpers.d.ts +15 -0
- package/dist/helpers/string-helpers.js +63 -0
- package/dist/helpers/string-helpers.js.map +1 -0
- package/dist/hooks.d.ts +9 -0
- package/dist/hooks.js +48 -0
- package/dist/hooks.js.map +1 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.js +20 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/locales/en.d.ts +2 -0
- package/dist/i18n/locales/en.js +84 -0
- package/dist/i18n/locales/en.js.map +1 -0
- package/dist/i18n/locales/ja.d.ts +2 -0
- package/dist/i18n/locales/ja.js +84 -0
- package/dist/i18n/locales/ja.js.map +1 -0
- package/dist/i18n/types.d.ts +72 -0
- package/dist/i18n/types.js +2 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/symlink-checker.d.ts +15 -0
- package/dist/lib/symlink-checker.js +54 -0
- package/dist/lib/symlink-checker.js.map +1 -0
- package/dist/registry.d.ts +8 -0
- package/dist/registry.js +86 -0
- package/dist/registry.js.map +1 -0
- package/dist/remote-registry.d.ts +51 -0
- package/dist/remote-registry.js +181 -0
- package/dist/remote-registry.js.map +1 -0
- package/dist/safe-yaml-parser.d.ts +26 -0
- package/{src/safe-yaml-parser.ts → dist/safe-yaml-parser.js} +28 -34
- package/dist/safe-yaml-parser.js.map +1 -0
- package/dist/snippet-schema.d.ts +38 -0
- package/dist/snippet-schema.js +63 -0
- package/dist/snippet-schema.js.map +1 -0
- package/dist/template-engine.d.ts +5 -0
- package/dist/template-engine.js +130 -0
- package/dist/template-engine.js.map +1 -0
- package/dist/validate-name.d.ts +1 -0
- package/dist/validate-name.js +9 -0
- package/dist/validate-name.js.map +1 -0
- package/package.json +6 -1
- package/src/__tests__/errors.test.ts +0 -71
- package/src/__tests__/helpers/string-helpers.test.ts +0 -100
- package/src/__tests__/hooks.test.ts +0 -145
- package/src/__tests__/i18n.test.ts +0 -60
- package/src/__tests__/remote-registry.test.ts +0 -265
- package/src/__tests__/safe-yaml-parser.test.ts +0 -187
- package/src/__tests__/snapshots/__snapshots__/error-messages.snapshot.test.ts.snap +0 -27
- package/src/__tests__/snapshots/__snapshots__/snippet-schema-output.snapshot.test.ts.snap +0 -78
- package/src/__tests__/snapshots/__snapshots__/template-output.snapshot.test.ts.snap +0 -45
- package/src/__tests__/snapshots/error-messages.snapshot.test.ts +0 -76
- package/src/__tests__/snapshots/snippet-schema-output.snapshot.test.ts +0 -98
- package/src/__tests__/snapshots/template-output.snapshot.test.ts +0 -73
- package/src/__tests__/snippet-schema.test.ts +0 -180
- package/src/__tests__/symlink-checker.test.ts +0 -95
- package/src/__tests__/template-engine.test.ts +0 -240
- package/src/__tests__/validate-name.test.ts +0 -61
- package/src/errors.ts +0 -82
- package/src/helpers/index.ts +0 -34
- package/src/helpers/string-helpers.ts +0 -76
- package/src/hooks.ts +0 -63
- package/src/i18n/index.ts +0 -32
- package/src/i18n/locales/en.ts +0 -96
- package/src/i18n/locales/ja.ts +0 -96
- package/src/i18n/types.ts +0 -96
- package/src/index.ts +0 -86
- package/src/lib/symlink-checker.ts +0 -62
- package/src/registry.ts +0 -120
- package/src/remote-registry.ts +0 -260
- package/src/snippet-schema.ts +0 -117
- package/src/template-engine.ts +0 -147
- package/src/validate-name.ts +0 -12
- package/tsconfig.json +0 -17
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handlebars カスタムヘルパー用の純粋関数群
|
|
3
|
-
* 外部ライブラリ不使用
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/** 単語分割: `-`, `_`, `.`, スペース, camelCase 境界で分割 */
|
|
7
|
-
function splitWords(value: string): string[] {
|
|
8
|
-
return value
|
|
9
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1\0$2")
|
|
10
|
-
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1\0$2")
|
|
11
|
-
.split(/[-_.\s\0]+/)
|
|
12
|
-
.filter((w) => w.length > 0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function lowercase(value: unknown): string {
|
|
16
|
-
return String(value).toLowerCase();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function uppercase(value: unknown): string {
|
|
20
|
-
return String(value).toUpperCase();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function capitalize(value: unknown): string {
|
|
24
|
-
const s = String(value);
|
|
25
|
-
if (s.length === 0) return s;
|
|
26
|
-
return s[0].toUpperCase() + s.slice(1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function uncapitalize(value: unknown): string {
|
|
30
|
-
const s = String(value);
|
|
31
|
-
if (s.length === 0) return s;
|
|
32
|
-
return s[0].toLowerCase() + s.slice(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** リテラル文字列置換(replaceAll)。正規表現は受け付けない(ReDoS 防止) */
|
|
36
|
-
export function replace(
|
|
37
|
-
value: unknown,
|
|
38
|
-
search: unknown,
|
|
39
|
-
replacement: unknown,
|
|
40
|
-
): string {
|
|
41
|
-
const s = String(value);
|
|
42
|
-
const searchStr = String(search);
|
|
43
|
-
const replaceStr = String(replacement);
|
|
44
|
-
if (searchStr === "") return s;
|
|
45
|
-
return s.split(searchStr).join(replaceStr);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function camelCase(value: unknown): string {
|
|
49
|
-
const words = splitWords(String(value));
|
|
50
|
-
return words
|
|
51
|
-
.map((w, i) =>
|
|
52
|
-
i === 0 ? w.toLowerCase() : w[0].toUpperCase() + w.slice(1).toLowerCase(),
|
|
53
|
-
)
|
|
54
|
-
.join("");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function pascalCase(value: unknown): string {
|
|
58
|
-
const words = splitWords(String(value));
|
|
59
|
-
return words.map((w) => w[0].toUpperCase() + w.slice(1).toLowerCase()).join("");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function snakeCase(value: unknown): string {
|
|
63
|
-
return splitWords(String(value))
|
|
64
|
-
.map((w) => w.toLowerCase())
|
|
65
|
-
.join("_");
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function kebabCase(value: unknown): string {
|
|
69
|
-
return splitWords(String(value))
|
|
70
|
-
.map((w) => w.toLowerCase())
|
|
71
|
-
.join("-");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function trim(value: unknown): string {
|
|
75
|
-
return String(value).trim();
|
|
76
|
-
}
|
package/src/hooks.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { MirError } from "./errors.js";
|
|
2
|
-
import { expandTemplate } from "./template-engine.js";
|
|
3
|
-
import { t } from "./i18n/index.js";
|
|
4
|
-
import type { Action } from "./snippet-schema.js";
|
|
5
|
-
|
|
6
|
-
export class ExitHookError extends MirError {
|
|
7
|
-
constructor() {
|
|
8
|
-
super(t("error.exit-hook"));
|
|
9
|
-
this.name = "ExitHookError";
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface HookExecutionOptions {
|
|
14
|
-
onEcho?: (message: string) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function executeHooks(
|
|
18
|
-
actions: Action[],
|
|
19
|
-
variables: Record<string, unknown>,
|
|
20
|
-
options?: HookExecutionOptions,
|
|
21
|
-
): Record<string, unknown> {
|
|
22
|
-
const vars = { ...variables };
|
|
23
|
-
|
|
24
|
-
for (const action of actions) {
|
|
25
|
-
if (action.echo !== undefined) {
|
|
26
|
-
const message = expandTemplate(action.echo, vars);
|
|
27
|
-
options?.onEcho?.(message);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (action.exit !== undefined) {
|
|
31
|
-
if (action.if !== undefined) {
|
|
32
|
-
const condition = expandTemplate(action.if, vars);
|
|
33
|
-
if (isTruthy(condition)) {
|
|
34
|
-
throw new ExitHookError();
|
|
35
|
-
}
|
|
36
|
-
} else if (action.exit) {
|
|
37
|
-
throw new ExitHookError();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (action.input !== undefined) {
|
|
42
|
-
for (const [, inputDef] of Object.entries(action.input)) {
|
|
43
|
-
const answerTo = inputDef["answer-to"];
|
|
44
|
-
if (!answerTo) continue;
|
|
45
|
-
|
|
46
|
-
if (inputDef.schema?.default !== undefined) {
|
|
47
|
-
vars[answerTo] = inputDef.schema.default;
|
|
48
|
-
} else {
|
|
49
|
-
throw new MirError(
|
|
50
|
-
t("error.hook-input-required", { key: answerTo }),
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return vars;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function isTruthy(value: string): boolean {
|
|
61
|
-
const trimmed = value.trim();
|
|
62
|
-
return trimmed !== "" && trimmed !== "false" && trimmed !== "0";
|
|
63
|
-
}
|
package/src/i18n/index.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { MessageKey, MessageCatalog } from "./types.js";
|
|
2
|
-
import { ja } from "./locales/ja.js";
|
|
3
|
-
import { en } from "./locales/en.js";
|
|
4
|
-
|
|
5
|
-
export type Locale = "ja" | "en";
|
|
6
|
-
|
|
7
|
-
const catalogs: Record<Locale, MessageCatalog> = { ja, en };
|
|
8
|
-
|
|
9
|
-
let currentLocale: Locale = "ja";
|
|
10
|
-
|
|
11
|
-
export function setLocale(locale: Locale): void {
|
|
12
|
-
currentLocale = locale;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function getLocale(): Locale {
|
|
16
|
-
return currentLocale;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function t(
|
|
20
|
-
key: MessageKey,
|
|
21
|
-
params?: Record<string, string | number>,
|
|
22
|
-
): string {
|
|
23
|
-
let message = catalogs[currentLocale][key];
|
|
24
|
-
if (params) {
|
|
25
|
-
for (const [k, v] of Object.entries(params)) {
|
|
26
|
-
message = message.replaceAll(`{${k}}`, String(v));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
return message;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export type { MessageKey, MessageCatalog };
|
package/src/i18n/locales/en.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { MessageCatalog } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export const en: MessageCatalog = {
|
|
4
|
-
// errors
|
|
5
|
-
"error.snippet-not-found": "Snippet \"{name}\" not found. Use `mir list` to see available snippets or specify `--registry` for another registry",
|
|
6
|
-
"error.snippet-already-exists": "Snippet \"{name}\" already exists. Use `--force` to overwrite or specify a different name",
|
|
7
|
-
"error.registry-not-found": "Registry \"{name}\" not found. Configure registries in `~/.mir/mirconfig.yaml`",
|
|
8
|
-
"error.registry-remote": "Cannot publish to remote registry",
|
|
9
|
-
"error.registry-remote-named": "Cannot publish to registry \"{name}\" because it is a remote registry",
|
|
10
|
-
"error.path-traversal": "Security error: File path \"{path}\" references outside the output directory. Check your template files",
|
|
11
|
-
"error.file-conflict": "File \"{path}\" already exists. Use `--no-interactive` to overwrite all files or `--out-dir` to specify another directory",
|
|
12
|
-
"error.validation": "Validation error",
|
|
13
|
-
"error.invalid-snippet-name": "Invalid snippet name \"{name}\". Only alphanumeric characters and hyphens are allowed, and must start with an alphanumeric character",
|
|
14
|
-
"error.variable-empty": "No value provided for variable \"{key}\"",
|
|
15
|
-
"error.variable-required": "Variable \"{key}\" is required. Specify it with {hint}",
|
|
16
|
-
"error.exit-hook": "Installation was cancelled",
|
|
17
|
-
"error.hook-input-required": "Variable \"{key}\" requires input, but interactive mode is not yet supported. Please specify a default value",
|
|
18
|
-
"error.no-snippets": "No snippets available to select",
|
|
19
|
-
"error.remote-fetch": "Failed to fetch from remote registry: {url}",
|
|
20
|
-
"error.remote-fetch-status": "Failed to fetch from remote registry: {url} (HTTP {status})",
|
|
21
|
-
"error.invalid-manifest": "Invalid manifest from remote registry: {url}",
|
|
22
|
-
"error.fetch-timeout": "Timeout: Connection to {url} did not complete within {timeout} seconds",
|
|
23
|
-
"error.symlink-detected": "Symbolic link detected: {path}",
|
|
24
|
-
"error.symlink-in-snippet": "Snippet contains symbolic links: {paths}",
|
|
25
|
-
"error.safe-mode-overwrite": "Overwriting existing files is not allowed in safe mode: {path}",
|
|
26
|
-
"error.file-not-found": "File \"{path}\" not found",
|
|
27
|
-
"error.file-read-failed": "Failed to read file \"{path}\"",
|
|
28
|
-
"error.snippet-not-found-details": "\nPossible causes:\n1. Typo in snippet name\n2. Snippet not registered in registry\n3. No access permission to registry\n\nWays to check:\n• mir list - Show available snippets\n• mir search <keyword> - Search by keyword\n• mir info <name> - Show snippet details",
|
|
29
|
-
|
|
30
|
-
// create
|
|
31
|
-
"create.success": "Created snippet \"{name}\"",
|
|
32
|
-
|
|
33
|
-
// publish
|
|
34
|
-
"publish.success": "Published snippet \"{name}\" to registry",
|
|
35
|
-
"publish.cancelled": "Publish cancelled",
|
|
36
|
-
"publish.confirm-overwrite": "Snippet \"{name}\" already exists. Overwrite?",
|
|
37
|
-
|
|
38
|
-
// install
|
|
39
|
-
"install.success": "Installed snippet \"{name}\"",
|
|
40
|
-
"install.skip": "Skipped: {path}",
|
|
41
|
-
"install.confirm-overwrite": "File \"{path}\" already exists. Overwrite? (y/n/a): ",
|
|
42
|
-
"install.dry-run-files": "[dry-run] Files to be generated:",
|
|
43
|
-
"install.dry-run-complete": "[dry-run] No actual file writes were performed.",
|
|
44
|
-
"install.multiple-snippets": "Installing multiple snippets...",
|
|
45
|
-
"install.snippet-n-of-m": "{current} / {total}: {name}",
|
|
46
|
-
"install.completed-multiple": "Installed {count} snippet(s)",
|
|
47
|
-
"install.failed-multiple": "Failed to install {count} snippet(s)",
|
|
48
|
-
"install.safe-mode-hooks-skipped": "[safe] Skipped hooks execution",
|
|
49
|
-
"install.symlink-warning": "Symbolic link detected: {path}",
|
|
50
|
-
|
|
51
|
-
// sync
|
|
52
|
-
"sync.no-new-vars": "No new variables to add",
|
|
53
|
-
"sync.success": "Added {count} variable(s)",
|
|
54
|
-
|
|
55
|
-
// search
|
|
56
|
-
"search.query-required": "Search query is required",
|
|
57
|
-
"search.no-results": "No snippets found matching \"{query}\"",
|
|
58
|
-
|
|
59
|
-
// error specific
|
|
60
|
-
"error.no-failed-snippets": "No failed snippet history",
|
|
61
|
-
"error.publish-token-required": "publish_token is required to publish to remote registry. Configure it in ~/.mir/mirconfig.yaml",
|
|
62
|
-
"error.publish-auth-failed": "Publish authentication failed. Please verify your publish_token",
|
|
63
|
-
"error.publish-token-invalid": "Invalid publish_token. Check your registry configuration",
|
|
64
|
-
"error.publish-failed": "Failed to publish snippet: {error}",
|
|
65
|
-
"error.publish-network-error": "Network error: {message}",
|
|
66
|
-
|
|
67
|
-
// clone
|
|
68
|
-
"clone.success": "Cloned snippet \"{name}\" to \"{alias}\"",
|
|
69
|
-
|
|
70
|
-
// preview
|
|
71
|
-
"preview.title": "Preview: {name}",
|
|
72
|
-
"preview.confirm": "Do you want to install this snippet?",
|
|
73
|
-
|
|
74
|
-
// prompt
|
|
75
|
-
"prompt.snippet-name": "Snippet name: ",
|
|
76
|
-
"prompt.select-snippet": "Select a snippet",
|
|
77
|
-
"prompt.select": "Select: ",
|
|
78
|
-
"prompt.enter-number": "Please enter a number",
|
|
79
|
-
"prompt.other-manual": "Other (manual input)",
|
|
80
|
-
"prompt.use-default": "Press Enter to use {value}",
|
|
81
|
-
"prompt.use-default-value": "Press Enter to use default \"{value}\"",
|
|
82
|
-
"prompt.yes-no-all": "(y/n/a): ",
|
|
83
|
-
"prompt.yes-no": "(y/N): ",
|
|
84
|
-
|
|
85
|
-
// batch-summary
|
|
86
|
-
"batch-summary.results": "Installation results:",
|
|
87
|
-
"batch-summary.success": "Success",
|
|
88
|
-
"batch-summary.failure": "Failed",
|
|
89
|
-
"batch-summary.skipped": "Skipped",
|
|
90
|
-
"batch-summary.counts": "Success: {success}/{total}, Failed: {failure}/{total}, Skipped: {skipped}/{total}",
|
|
91
|
-
"batch-summary.retry-hint": "💡 To retry failed snippets: mir install --retry-failed",
|
|
92
|
-
|
|
93
|
-
// general
|
|
94
|
-
"general.variables": "Variables:",
|
|
95
|
-
"general.default": "(default)",
|
|
96
|
-
};
|
package/src/i18n/locales/ja.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { MessageCatalog } from "../types.js";
|
|
2
|
-
|
|
3
|
-
export const ja: MessageCatalog = {
|
|
4
|
-
// errors
|
|
5
|
-
"error.snippet-not-found": "Snippet \"{name}\" が見つかりません。`mir list` で利用可能な snippet を確認するか、`--registry` で別の registry を指定してください",
|
|
6
|
-
"error.snippet-already-exists": "Snippet \"{name}\" は既に存在します。`--force` で上書きするか、別の名前を指定してください",
|
|
7
|
-
"error.registry-not-found": "Registry \"{name}\" が見つかりません。`~/.mir/mirconfig.yaml` で registry を設定してください",
|
|
8
|
-
"error.registry-remote": "リモート registry には publish できません",
|
|
9
|
-
"error.registry-remote-named": "Registry \"{name}\" はリモート registry のため publish できません",
|
|
10
|
-
"error.path-traversal": "セキュリティエラー: ファイルパス \"{path}\" が出力範囲外を参照しています。テンプレートファイルを確認してください",
|
|
11
|
-
"error.file-conflict": "ファイル \"{path}\" は既に存在します。`--no-interactive` で全て上書きするか、`--out-dir` で別ディレクトリを指定してください",
|
|
12
|
-
"error.validation": "バリデーションエラー",
|
|
13
|
-
"error.invalid-snippet-name": "不正な snippet 名 \"{name}\" です。英数字とハイフンのみ使用可能で、先頭は英数字にしてください",
|
|
14
|
-
"error.variable-empty": "変数 \"{key}\" の値が入力されませんでした",
|
|
15
|
-
"error.variable-required": "変数 \"{key}\" の値が必要です。{hint} で指定してください",
|
|
16
|
-
"error.exit-hook": "install が中止されました",
|
|
17
|
-
"error.hook-input-required": "変数 \"{key}\" の入力が必要ですが、interactive mode は未対応です。default 値を指定してください",
|
|
18
|
-
"error.no-snippets": "選択可能な snippet がありません",
|
|
19
|
-
"error.remote-fetch": "リモート registry の取得に失敗しました: {url}",
|
|
20
|
-
"error.remote-fetch-status": "リモート registry の取得に失敗しました: {url} (HTTP {status})",
|
|
21
|
-
"error.invalid-manifest": "リモート registry のマニフェストが不正です: {url}",
|
|
22
|
-
"error.fetch-timeout": "タイムアウト: {url} への接続が {timeout} 秒以内に完了しませんでした",
|
|
23
|
-
"error.symlink-detected": "シンボリックリンクが検出されました: {path}",
|
|
24
|
-
"error.symlink-in-snippet": "Snippet にシンボリックリンクが含まれています: {paths}",
|
|
25
|
-
"error.safe-mode-overwrite": "safe モードでは既存ファイルの上書きは許可されていません: {path}",
|
|
26
|
-
"error.file-not-found": "ファイル \"{path}\" が見つかりません",
|
|
27
|
-
"error.file-read-failed": "ファイル \"{path}\" の読み込みに失敗しました",
|
|
28
|
-
"error.snippet-not-found-details": "\n可能な原因:\n1. Snippet 名の入力ミス\n2. Registry に登録されていない\n3. Registry へのアクセス権限がない\n\n確認方法:\n• mir list - 利用可能な snippet を表示\n• mir search <keyword> - キーワードで検索\n• mir info <name> - snippet の詳細情報を表示",
|
|
29
|
-
|
|
30
|
-
// create
|
|
31
|
-
"create.success": "Snippet \"{name}\" を作成しました",
|
|
32
|
-
|
|
33
|
-
// publish
|
|
34
|
-
"publish.success": "Snippet \"{name}\" を registry に登録しました",
|
|
35
|
-
"publish.cancelled": "publish をキャンセルしました",
|
|
36
|
-
"publish.confirm-overwrite": "Snippet \"{name}\" は既に存在します。上書きしますか?",
|
|
37
|
-
|
|
38
|
-
// install
|
|
39
|
-
"install.success": "Snippet \"{name}\" をインストールしました",
|
|
40
|
-
"install.skip": "スキップ: {path}",
|
|
41
|
-
"install.confirm-overwrite": "ファイル \"{path}\" は既に存在します。上書きしますか? (y/n/a): ",
|
|
42
|
-
"install.dry-run-files": "[dry-run] 生成されるファイル:",
|
|
43
|
-
"install.dry-run-complete": "[dry-run] 実際のファイル書き込みは実行されていません。",
|
|
44
|
-
"install.multiple-snippets": "複数の snippet をインストール中...",
|
|
45
|
-
"install.snippet-n-of-m": "{current} / {total}: {name}",
|
|
46
|
-
"install.completed-multiple": "{count} 個の snippet をインストールしました",
|
|
47
|
-
"install.failed-multiple": "{count} 個の snippet のインストールに失敗しました",
|
|
48
|
-
"install.safe-mode-hooks-skipped": "[safe] hooks の実行をスキップしました",
|
|
49
|
-
"install.symlink-warning": "シンボリックリンクが検出されました: {path}",
|
|
50
|
-
|
|
51
|
-
// sync
|
|
52
|
-
"sync.no-new-vars": "追加する変数はありません",
|
|
53
|
-
"sync.success": "{count} 件の変数を追加しました",
|
|
54
|
-
|
|
55
|
-
// search
|
|
56
|
-
"search.query-required": "検索キーワードが必要です",
|
|
57
|
-
"search.no-results": "\"{query}\" に一致する snippet が見つかりません",
|
|
58
|
-
|
|
59
|
-
// error specific
|
|
60
|
-
"error.no-failed-snippets": "失敗した snippet の履歴がありません",
|
|
61
|
-
"error.publish-token-required": "リモート registry への publish には publish_token が必要です。~/.mir/mirconfig.yaml で設定してください",
|
|
62
|
-
"error.publish-auth-failed": "publish 認証に失敗しました。publish_token を確認してください",
|
|
63
|
-
"error.publish-token-invalid": "publish_token が無効です。registry の設定を確認してください",
|
|
64
|
-
"error.publish-failed": "Snippet の publish に失敗しました: {error}",
|
|
65
|
-
"error.publish-network-error": "ネットワークエラー: {message}",
|
|
66
|
-
|
|
67
|
-
// clone
|
|
68
|
-
"clone.success": "Snippet \"{name}\" を \"{alias}\" として複製しました",
|
|
69
|
-
|
|
70
|
-
// preview
|
|
71
|
-
"preview.title": "プレビュー: {name}",
|
|
72
|
-
"preview.confirm": "この snippet をインストールしますか?",
|
|
73
|
-
|
|
74
|
-
// prompt
|
|
75
|
-
"prompt.snippet-name": "snippet 名: ",
|
|
76
|
-
"prompt.select-snippet": "snippet を選択してください",
|
|
77
|
-
"prompt.select": "選択: ",
|
|
78
|
-
"prompt.enter-number": "番号を入力してください",
|
|
79
|
-
"prompt.other-manual": "その他 (手動入力)",
|
|
80
|
-
"prompt.use-default": "Enter で {value} を使用",
|
|
81
|
-
"prompt.use-default-value": "Enter でデフォルト値 \"{value}\" を使用",
|
|
82
|
-
"prompt.yes-no-all": "(y/n/a): ",
|
|
83
|
-
"prompt.yes-no": "(y/N): ",
|
|
84
|
-
|
|
85
|
-
// batch-summary
|
|
86
|
-
"batch-summary.results": "インストール結果:",
|
|
87
|
-
"batch-summary.success": "成功",
|
|
88
|
-
"batch-summary.failure": "失敗",
|
|
89
|
-
"batch-summary.skipped": "スキップ",
|
|
90
|
-
"batch-summary.counts": "成功: {success}/{total}, 失敗: {failure}/{total}, スキップ: {skipped}/{total}",
|
|
91
|
-
"batch-summary.retry-hint": "💡 失敗した snippet をもう一度インストールするには: mir install --retry-failed",
|
|
92
|
-
|
|
93
|
-
// general
|
|
94
|
-
"general.variables": "Variables:",
|
|
95
|
-
"general.default": "(default)",
|
|
96
|
-
};
|
package/src/i18n/types.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
export interface MessageCatalog {
|
|
2
|
-
// errors
|
|
3
|
-
"error.snippet-not-found": string;
|
|
4
|
-
"error.snippet-already-exists": string;
|
|
5
|
-
"error.registry-not-found": string;
|
|
6
|
-
"error.registry-remote": string;
|
|
7
|
-
"error.registry-remote-named": string;
|
|
8
|
-
"error.path-traversal": string;
|
|
9
|
-
"error.file-conflict": string;
|
|
10
|
-
"error.validation": string;
|
|
11
|
-
"error.invalid-snippet-name": string;
|
|
12
|
-
"error.variable-empty": string;
|
|
13
|
-
"error.variable-required": string;
|
|
14
|
-
"error.exit-hook": string;
|
|
15
|
-
"error.hook-input-required": string;
|
|
16
|
-
"error.no-snippets": string;
|
|
17
|
-
"error.remote-fetch": string;
|
|
18
|
-
"error.remote-fetch-status": string;
|
|
19
|
-
"error.invalid-manifest": string;
|
|
20
|
-
"error.fetch-timeout": string;
|
|
21
|
-
"error.symlink-detected": string;
|
|
22
|
-
"error.symlink-in-snippet": string;
|
|
23
|
-
"error.safe-mode-overwrite": string;
|
|
24
|
-
"error.file-not-found": string;
|
|
25
|
-
"error.file-read-failed": string;
|
|
26
|
-
"error.snippet-not-found-details": string;
|
|
27
|
-
|
|
28
|
-
// create
|
|
29
|
-
"create.success": string;
|
|
30
|
-
|
|
31
|
-
// publish
|
|
32
|
-
"publish.success": string;
|
|
33
|
-
"publish.cancelled": string;
|
|
34
|
-
"publish.confirm-overwrite": string;
|
|
35
|
-
|
|
36
|
-
// install
|
|
37
|
-
"install.success": string;
|
|
38
|
-
"install.skip": string;
|
|
39
|
-
"install.confirm-overwrite": string;
|
|
40
|
-
"install.dry-run-files": string;
|
|
41
|
-
"install.dry-run-complete": string;
|
|
42
|
-
"install.multiple-snippets": string;
|
|
43
|
-
"install.snippet-n-of-m": string;
|
|
44
|
-
"install.completed-multiple": string;
|
|
45
|
-
"install.failed-multiple": string;
|
|
46
|
-
"install.safe-mode-hooks-skipped": string;
|
|
47
|
-
"install.symlink-warning": string;
|
|
48
|
-
|
|
49
|
-
// sync
|
|
50
|
-
"sync.no-new-vars": string;
|
|
51
|
-
"sync.success": string;
|
|
52
|
-
|
|
53
|
-
// search
|
|
54
|
-
"search.query-required": string;
|
|
55
|
-
"search.no-results": string;
|
|
56
|
-
|
|
57
|
-
// error specific
|
|
58
|
-
"error.no-failed-snippets": string;
|
|
59
|
-
"error.publish-token-required": string;
|
|
60
|
-
"error.publish-auth-failed": string;
|
|
61
|
-
"error.publish-token-invalid": string;
|
|
62
|
-
"error.publish-failed": string;
|
|
63
|
-
"error.publish-network-error": string;
|
|
64
|
-
|
|
65
|
-
// clone
|
|
66
|
-
"clone.success": string;
|
|
67
|
-
|
|
68
|
-
// preview
|
|
69
|
-
"preview.title": string;
|
|
70
|
-
"preview.confirm": string;
|
|
71
|
-
|
|
72
|
-
// prompt
|
|
73
|
-
"prompt.snippet-name": string;
|
|
74
|
-
"prompt.select-snippet": string;
|
|
75
|
-
"prompt.select": string;
|
|
76
|
-
"prompt.enter-number": string;
|
|
77
|
-
"prompt.other-manual": string;
|
|
78
|
-
"prompt.use-default": string;
|
|
79
|
-
"prompt.use-default-value": string;
|
|
80
|
-
"prompt.yes-no-all": string;
|
|
81
|
-
"prompt.yes-no": string;
|
|
82
|
-
|
|
83
|
-
// batch-summary
|
|
84
|
-
"batch-summary.results": string;
|
|
85
|
-
"batch-summary.success": string;
|
|
86
|
-
"batch-summary.failure": string;
|
|
87
|
-
"batch-summary.skipped": string;
|
|
88
|
-
"batch-summary.counts": string;
|
|
89
|
-
"batch-summary.retry-hint": string;
|
|
90
|
-
|
|
91
|
-
// general
|
|
92
|
-
"general.variables": string;
|
|
93
|
-
"general.default": string;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export type MessageKey = keyof MessageCatalog;
|
package/src/index.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
// errors
|
|
2
|
-
export {
|
|
3
|
-
MirError,
|
|
4
|
-
ValidationError,
|
|
5
|
-
SnippetNotFoundError,
|
|
6
|
-
SnippetAlreadyExistsError,
|
|
7
|
-
RegistryNotFoundError,
|
|
8
|
-
RegistryRemoteError,
|
|
9
|
-
PathTraversalError,
|
|
10
|
-
FileConflictError,
|
|
11
|
-
RemoteRegistryFetchError,
|
|
12
|
-
InvalidManifestError,
|
|
13
|
-
} from "./errors.js";
|
|
14
|
-
|
|
15
|
-
// snippet-schema
|
|
16
|
-
export {
|
|
17
|
-
parseSnippetYaml,
|
|
18
|
-
serializeSnippetYaml,
|
|
19
|
-
validateSnippetDefinition,
|
|
20
|
-
} from "./snippet-schema.js";
|
|
21
|
-
export type {
|
|
22
|
-
VariableSchema,
|
|
23
|
-
VariableDefinition,
|
|
24
|
-
Action,
|
|
25
|
-
SnippetDefinition,
|
|
26
|
-
} from "./snippet-schema.js";
|
|
27
|
-
|
|
28
|
-
// validate-name
|
|
29
|
-
export { validateSnippetName } from "./validate-name.js";
|
|
30
|
-
|
|
31
|
-
// safe-yaml-parser
|
|
32
|
-
export {
|
|
33
|
-
safeParseYaml,
|
|
34
|
-
checkNoRefInSchema,
|
|
35
|
-
YAML_MAX_SIZE_BYTES,
|
|
36
|
-
} from "./safe-yaml-parser.js";
|
|
37
|
-
|
|
38
|
-
// template-engine
|
|
39
|
-
export {
|
|
40
|
-
expandTemplate,
|
|
41
|
-
expandPath,
|
|
42
|
-
extractVariables,
|
|
43
|
-
extractVariablesFromDirectory,
|
|
44
|
-
expandTemplateDirectory,
|
|
45
|
-
} from "./template-engine.js";
|
|
46
|
-
|
|
47
|
-
// helpers
|
|
48
|
-
export { HELPER_NAMES } from "./helpers/index.js";
|
|
49
|
-
|
|
50
|
-
// hooks
|
|
51
|
-
export { ExitHookError, executeHooks } from "./hooks.js";
|
|
52
|
-
export type { HookExecutionOptions } from "./hooks.js";
|
|
53
|
-
|
|
54
|
-
// registry
|
|
55
|
-
export {
|
|
56
|
-
listRegistrySnippets,
|
|
57
|
-
snippetExistsInRegistry,
|
|
58
|
-
readSnippetFromRegistry,
|
|
59
|
-
listTemplateFiles,
|
|
60
|
-
readTemplateFile,
|
|
61
|
-
copySnippetToRegistry,
|
|
62
|
-
removeSnippetFromRegistry,
|
|
63
|
-
} from "./registry.js";
|
|
64
|
-
|
|
65
|
-
// remote-registry
|
|
66
|
-
export {
|
|
67
|
-
fetchRegistryManifest,
|
|
68
|
-
listRemoteSnippets,
|
|
69
|
-
fetchSnippetDefinition,
|
|
70
|
-
fetchRemoteFiles,
|
|
71
|
-
fetchRemoteSnippet,
|
|
72
|
-
expandRemoteTemplateFiles,
|
|
73
|
-
} from "./remote-registry.js";
|
|
74
|
-
export type { RegistryManifest, RemoteSnippet, FetchOptions } from "./remote-registry.js";
|
|
75
|
-
|
|
76
|
-
// symlink-checker
|
|
77
|
-
export {
|
|
78
|
-
isSymbolicLink,
|
|
79
|
-
findSymlinksInDirectory,
|
|
80
|
-
} from "./lib/symlink-checker.js";
|
|
81
|
-
export type { SymlinkCheckResult } from "./lib/symlink-checker.js";
|
|
82
|
-
|
|
83
|
-
// i18n
|
|
84
|
-
export { setLocale, getLocale, t } from "./i18n/index.js";
|
|
85
|
-
export type { Locale } from "./i18n/index.js";
|
|
86
|
-
export type { MessageKey, MessageCatalog } from "./i18n/types.js";
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
export interface SymlinkCheckResult {
|
|
5
|
-
hasSymlinks: boolean;
|
|
6
|
-
symlinkPaths: string[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 指定ファイルがシンボリックリンクかどうかを確認する
|
|
11
|
-
* lstat を使用することで、リンク先ではなくリンク自体の情報を取得する
|
|
12
|
-
*/
|
|
13
|
-
export function isSymbolicLink(filePath: string): boolean {
|
|
14
|
-
try {
|
|
15
|
-
const stat = fs.lstatSync(filePath);
|
|
16
|
-
return stat.isSymbolicLink();
|
|
17
|
-
} catch {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* ディレクトリ内のシンボリックリンクを再帰的に検索する
|
|
24
|
-
* @param dirPath 検索対象ディレクトリ
|
|
25
|
-
* @returns シンボリックリンクの有無と、見つかったシンボリックリンクのパス一覧
|
|
26
|
-
*/
|
|
27
|
-
export function findSymlinksInDirectory(dirPath: string): SymlinkCheckResult {
|
|
28
|
-
const symlinkPaths: string[] = [];
|
|
29
|
-
|
|
30
|
-
function walkDir(currentPath: string, relativePath: string): void {
|
|
31
|
-
let entries: fs.Dirent[];
|
|
32
|
-
try {
|
|
33
|
-
entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
34
|
-
} catch {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (const entry of entries) {
|
|
39
|
-
const fullPath = path.join(currentPath, entry.name);
|
|
40
|
-
const relPath = relativePath
|
|
41
|
-
? path.join(relativePath, entry.name)
|
|
42
|
-
: entry.name;
|
|
43
|
-
|
|
44
|
-
// isSymbolicLink() は entry レベルで確認可能だが、
|
|
45
|
-
// lstat で確実に判定するため個別確認
|
|
46
|
-
if (isSymbolicLink(fullPath)) {
|
|
47
|
-
symlinkPaths.push(relPath);
|
|
48
|
-
} else if (entry.isDirectory()) {
|
|
49
|
-
walkDir(fullPath, relPath);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (fs.existsSync(dirPath)) {
|
|
55
|
-
walkDir(dirPath, "");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
hasSymlinks: symlinkPaths.length > 0,
|
|
60
|
-
symlinkPaths,
|
|
61
|
-
};
|
|
62
|
-
}
|