@dx-pkg/mksymlink 1.0.14 → 1.0.15
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/CHANGELOG.md +8 -0
- package/examples/index.js +5 -6
- package/examples/index.mjs +5 -0
- package/package.json +21 -23
- package/src/index.d.mts +149 -0
- package/src/index.d.ts +149 -11
- package/src/index.js +4 -27
- package/src/index.mjs +4 -0
- package/examples/advanced-usage.d.ts +0 -1
- package/examples/advanced-usage.js +0 -38
- package/examples/basic-usage.d.ts +0 -1
- package/examples/basic-usage.js +0 -14
- package/examples/config-usage.d.ts +0 -2
- package/examples/config-usage.js +0 -64
- package/examples/cross-platform.d.ts +0 -1
- package/examples/cross-platform.js +0 -40
- package/examples/index.d.ts +0 -1
- package/src/commands/config/config.command-factory.d.ts +0 -4
- package/src/commands/config/config.command-factory.js +0 -17
- package/src/commands/config/config.command.d.ts +0 -22
- package/src/commands/config/config.command.js +0 -93
- package/src/commands/config/config.option-validator.d.ts +0 -8
- package/src/commands/config/config.option-validator.js +0 -40
- package/src/commands/create/mksymlink.command-factory.d.ts +0 -4
- package/src/commands/create/mksymlink.command-factory.js +0 -18
- package/src/commands/create/mksymlink.command.d.ts +0 -24
- package/src/commands/create/mksymlink.command.js +0 -78
- package/src/commands/create/mksymlink.option-validator.d.ts +0 -8
- package/src/commands/create/mksymlink.option-validator.js +0 -34
- package/src/commands/index.d.ts +0 -2
- package/src/commands/index.js +0 -102
- package/src/services/config.service.d.ts +0 -44
- package/src/services/config.service.js +0 -112
- package/src/services/platform-detector.d.ts +0 -10
- package/src/services/platform-detector.js +0 -35
- package/src/services/symlink-error.d.ts +0 -11
- package/src/services/symlink-error.js +0 -32
- package/src/services/symlink-manager.d.ts +0 -12
- package/src/services/symlink-manager.js +0 -114
- package/src/services/symlink.service.d.ts +0 -12
- package/src/services/symlink.service.js +0 -114
- package/src/types/index.d.ts +0 -39
- package/src/types/index.js +0 -2
package/CHANGELOG.md
CHANGED
package/examples/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// configExamples().catch(console.error);
|
|
1
|
+
var e=(e,t)=>()=>(e&&(t=e(e=0)),t),t=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);let n=require(`os`),r=require(`child_process`),i=require(`util`),a=require(`fs/promises`),o=require(`fs`),s=require(`path`),c=require(`@dx-pkg/logger`);var l=e((()=>{})),u,d=e((()=>{u=class{_platform;constructor(){this._platform=this.normalizePlatform((0,n.platform)())}normalizePlatform(e){switch(e){case`darwin`:return`darwin`;case`win32`:return`win32`;case`linux`:return`linux`;default:return`unknown`}}getPlatform(){return this._platform}isWindows(){return this._platform===`win32`}isMacOS(){return this._platform===`darwin`}isLinux(){return this._platform===`linux`}}})),f,p=e((()=>{f=class extends Error{code;constructor(e,t){super(e),this.name=`SymlinkError`,this.code=t,Error.captureStackTrace(this,this.constructor)}}})),m,h,g=e((()=>{p(),m=(0,i.promisify)(r.exec),h=class{constructor(e,t){this.logger=e,this.osDetector=t}async createSymlink(e){let{source:t,target:n,type:r=`dir`,force:i=!1}=e;try{if(await this.symlinkExists(n)){if(!i)return{success:!1,source:t,target:n,message:`Symlink already exists: ${n}`};this.logger.info(`Force mode enabled. Removing existing symlink: ${n}`),await this.removeSymlink(n)}return this.osDetector.isWindows()?await this.createWindowsSymlink(t,n,r):await this.createUnixSymlink(t,n),{success:!0,source:t,target:n,message:`Symlink created successfully`}}catch(e){return this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),{success:!1,source:t,target:n,error:e instanceof Error?e:Error(String(e))}}}async createWindowsSymlink(e,t,n){let r;switch(n){case`junction`:r=`/J`;break;case`file`:r=``;break;default:r=`/D`;break}let i=r?`mklink ${r} "${t}" "${e}"`:`mklink "${t}" "${e}"`;this.logger.info(`Executing Windows command: ${i}`);try{let{stdout:e,stderr:t}=await m(i,{shell:`cmd.exe`});if(t&&!t.includes(`Junction`)&&!t.includes(`symbolic link`))throw new f(t,`WINDOWS_MKLINK_ERROR`);this.logger.info(`Windows mklink output: ${e}`)}catch(e){throw new f(`Failed to create Windows symlink: ${e instanceof Error?e.message:String(e)}`,`WINDOWS_MKLINK_FAILED`)}}async createUnixSymlink(e,t){try{await(0,a.symlink)(e,t),this.logger.info(`Unix symlink created: ln -s ${e} ${t}`)}catch(e){throw new f(`Failed to create Unix symlink: ${e instanceof Error?e.message:String(e)}`,`UNIX_SYMLINK_FAILED`)}}async symlinkExists(e){try{return(await(0,a.lstat)(e)).isSymbolicLink()}catch{return!1}}async removeSymlink(e){try{await(0,a.access)(e),await(0,a.unlink)(e),this.logger.info(`Symlink removed: ${e}`)}catch(e){throw new f(`Failed to remove symlink: ${e instanceof Error?e.message:String(e)}`,`REMOVE_SYMLINK_FAILED`)}}}})),_,v=e((()=>{_=class{configPath;config={};constructor(e){let t=(0,n.homedir)();this.configPath=e||(0,s.resolve)(t,`.mksymlinkrc`),this.loadConfig()}get(e){return this.config[e]}set(e,t){this.config[e]=t,this.saveConfig()}unset(e){delete this.config[e],this.saveConfig()}list(){return{...this.config}}getDefaultSymlinkDir(){return this.get(`symlink.defaultDir`)}setDefaultSymlinkDir(e){this.set(`symlink.defaultDir`,e)}getConfigInfo(){let e=(0,o.existsSync)(this.configPath),t=Object.keys(this.config).length;if(!e)return{path:this.configPath,exists:!1,entries:t};let n=(0,o.statSync)(this.configPath);return{path:this.configPath,exists:!0,size:n.size,modified:n.mtime,entries:t}}loadConfig(){if(!(0,o.existsSync)(this.configPath)){this.config={};return}try{let e=(0,o.readFileSync)(this.configPath,`utf-8`).split(`
|
|
2
|
+
`).filter(e=>e.trim());this.config={};for(let t of e){let[e,...n]=t.split(`=`);e&&n.length>0&&(this.config[e.trim()]=n.join(`=`).trim())}}catch(e){throw Error(`Failed to load config from ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}saveConfig(){try{let e=(0,s.dirname)(this.configPath);(0,o.existsSync)(e)||(0,o.mkdirSync)(e,{recursive:!0});let t=Object.entries(this.config).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${t}`).join(`
|
|
3
|
+
`);(0,o.writeFileSync)(this.configPath,t+`
|
|
4
|
+
`,`utf-8`)}catch(e){throw Error(`Failed to save config to ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}}})),y,b,x=e((()=>{v(),y=[`file`,`dir`,`junction`],b=class{constructor(e,t,n,r,i=new _){this.optionValidator=e,this.logger=t,this.symlinkManager=n,this.options=r,this.configService=i}async execute(){this.optionValidator.validate(this.options);try{let{source:e,target:t,type:n,force:r}=this.resolveOptions();this.logger.info(`Creating symlink with options:`),this.logger.info(` Source: ${e}`),this.logger.info(` Target: ${t}`),this.logger.info(` Type: ${n}`),this.logger.info(` Force: ${r}`);let i=await this.symlinkManager.createSymlink({source:e,target:t,type:n,force:r});if(!i.success){if(i.error)throw i.error;this.logger.warning(i.message||`Symlink creation failed`);return}this.logger.success(`Symlink created successfully!`),this.logger.info(` Source: ${i.source}`),this.logger.info(` Target: ${i.target}`)}catch(e){throw this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),e}}resolveOptions(){let e=process.cwd();return{source:this.options.source||e,target:this.resolveTarget(this.options)||this.generateDefaultTarget(e),type:this.options.type||`junction`,force:this.options.force||!1}}resolveTarget(e){if(e.target!==`.`&&e.target!==`./`)return e.target;let t=process.cwd();return(0,s.resolve)(t,(0,s.basename)(e.source||t))}generateDefaultTarget(e){let t=(0,s.basename)(e),n=`${(0,s.basename)((0,s.dirname)(e))}--${t}`;return(0,s.resolve)(this.configService.getDefaultSymlinkDir()||e,n)}}})),S,C=e((()=>{p(),x(),S=class{validate(e){this.validateType(e.type),this.validateSource(e.source),this.validateForce(e.force)}validateType(e){if(e&&!y.includes(e))throw new f(`Invalid symlink type: ${e}. Must be one of: ${y.join(`, `)}`,`INVALID_SYMLINK_TYPE`)}validateSource(e){if(!e)return;let t=(0,s.resolve)(e);if(!(0,o.existsSync)(t))throw new f(`Source path does not exist: ${t}`,`SOURCE_NOT_FOUND`)}validateForce(e){if(e!==void 0&&typeof e!=`boolean`)throw new f(`Invalid force option: ${e}. Must be a boolean.`,`INVALID_FORCE_OPTION`)}}})),w,T=e((()=>{x(),g(),d(),C(),w=class{static create(e){let t=new S,n=new c.ConsoleLogger;return new b(t,n,new h(n,new u),e)}}})),E=e((()=>{})),D=e((()=>{})),O=e((()=>{})),k=e((()=>{l(),d(),g(),p(),v(),x(),C(),T(),E(),D(),O()}));t((()=>{k();async function e(){console.log(`=== Basic Symlink Creation ===
|
|
5
|
+
`),await w.create({source:process.cwd(),target:(0,s.join)(process.cwd(),`target-symlink`),type:`dir`}).execute()}e().catch(console.error)}))();
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{homedir as e,platform as t}from"os";import{exec as n}from"child_process";import{promisify as r}from"util";import{access as i,lstat as a,symlink as o,unlink as s}from"fs/promises";import{existsSync as c,mkdirSync as l,readFileSync as u,statSync as d,writeFileSync as f}from"fs";import{basename as p,dirname as m,join as h,resolve as g}from"path";import{ConsoleLogger as _}from"@dx-pkg/logger";var v=(e,t)=>()=>(e&&(t=e(e=0)),t),y=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),b=v((()=>{})),x,S=v((()=>{x=class{_platform;constructor(){this._platform=this.normalizePlatform(t())}normalizePlatform(e){switch(e){case`darwin`:return`darwin`;case`win32`:return`win32`;case`linux`:return`linux`;default:return`unknown`}}getPlatform(){return this._platform}isWindows(){return this._platform===`win32`}isMacOS(){return this._platform===`darwin`}isLinux(){return this._platform===`linux`}}})),C,w=v((()=>{C=class extends Error{code;constructor(e,t){super(e),this.name=`SymlinkError`,this.code=t,Error.captureStackTrace(this,this.constructor)}}})),T,E,D=v((()=>{w(),T=r(n),E=class{constructor(e,t){this.logger=e,this.osDetector=t}async createSymlink(e){let{source:t,target:n,type:r=`dir`,force:i=!1}=e;try{if(await this.symlinkExists(n)){if(!i)return{success:!1,source:t,target:n,message:`Symlink already exists: ${n}`};this.logger.info(`Force mode enabled. Removing existing symlink: ${n}`),await this.removeSymlink(n)}return this.osDetector.isWindows()?await this.createWindowsSymlink(t,n,r):await this.createUnixSymlink(t,n),{success:!0,source:t,target:n,message:`Symlink created successfully`}}catch(e){return this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),{success:!1,source:t,target:n,error:e instanceof Error?e:Error(String(e))}}}async createWindowsSymlink(e,t,n){let r;switch(n){case`junction`:r=`/J`;break;case`file`:r=``;break;default:r=`/D`;break}let i=r?`mklink ${r} "${t}" "${e}"`:`mklink "${t}" "${e}"`;this.logger.info(`Executing Windows command: ${i}`);try{let{stdout:e,stderr:t}=await T(i,{shell:`cmd.exe`});if(t&&!t.includes(`Junction`)&&!t.includes(`symbolic link`))throw new C(t,`WINDOWS_MKLINK_ERROR`);this.logger.info(`Windows mklink output: ${e}`)}catch(e){throw new C(`Failed to create Windows symlink: ${e instanceof Error?e.message:String(e)}`,`WINDOWS_MKLINK_FAILED`)}}async createUnixSymlink(e,t){try{await o(e,t),this.logger.info(`Unix symlink created: ln -s ${e} ${t}`)}catch(e){throw new C(`Failed to create Unix symlink: ${e instanceof Error?e.message:String(e)}`,`UNIX_SYMLINK_FAILED`)}}async symlinkExists(e){try{return(await a(e)).isSymbolicLink()}catch{return!1}}async removeSymlink(e){try{await i(e),await s(e),this.logger.info(`Symlink removed: ${e}`)}catch(e){throw new C(`Failed to remove symlink: ${e instanceof Error?e.message:String(e)}`,`REMOVE_SYMLINK_FAILED`)}}}})),O,k=v((()=>{O=class{configPath;config={};constructor(t){let n=e();this.configPath=t||g(n,`.mksymlinkrc`),this.loadConfig()}get(e){return this.config[e]}set(e,t){this.config[e]=t,this.saveConfig()}unset(e){delete this.config[e],this.saveConfig()}list(){return{...this.config}}getDefaultSymlinkDir(){return this.get(`symlink.defaultDir`)}setDefaultSymlinkDir(e){this.set(`symlink.defaultDir`,e)}getConfigInfo(){let e=c(this.configPath),t=Object.keys(this.config).length;if(!e)return{path:this.configPath,exists:!1,entries:t};let n=d(this.configPath);return{path:this.configPath,exists:!0,size:n.size,modified:n.mtime,entries:t}}loadConfig(){if(!c(this.configPath)){this.config={};return}try{let e=u(this.configPath,`utf-8`).split(`
|
|
2
|
+
`).filter(e=>e.trim());this.config={};for(let t of e){let[e,...n]=t.split(`=`);e&&n.length>0&&(this.config[e.trim()]=n.join(`=`).trim())}}catch(e){throw Error(`Failed to load config from ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}saveConfig(){try{let e=m(this.configPath);c(e)||l(e,{recursive:!0});let t=Object.entries(this.config).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${t}`).join(`
|
|
3
|
+
`);f(this.configPath,t+`
|
|
4
|
+
`,`utf-8`)}catch(e){throw Error(`Failed to save config to ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}}})),A,j,M=v((()=>{k(),A=[`file`,`dir`,`junction`],j=class{constructor(e,t,n,r,i=new O){this.optionValidator=e,this.logger=t,this.symlinkManager=n,this.options=r,this.configService=i}async execute(){this.optionValidator.validate(this.options);try{let{source:e,target:t,type:n,force:r}=this.resolveOptions();this.logger.info(`Creating symlink with options:`),this.logger.info(` Source: ${e}`),this.logger.info(` Target: ${t}`),this.logger.info(` Type: ${n}`),this.logger.info(` Force: ${r}`);let i=await this.symlinkManager.createSymlink({source:e,target:t,type:n,force:r});if(!i.success){if(i.error)throw i.error;this.logger.warning(i.message||`Symlink creation failed`);return}this.logger.success(`Symlink created successfully!`),this.logger.info(` Source: ${i.source}`),this.logger.info(` Target: ${i.target}`)}catch(e){throw this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),e}}resolveOptions(){let e=process.cwd();return{source:this.options.source||e,target:this.resolveTarget(this.options)||this.generateDefaultTarget(e),type:this.options.type||`junction`,force:this.options.force||!1}}resolveTarget(e){if(e.target!==`.`&&e.target!==`./`)return e.target;let t=process.cwd();return g(t,p(e.source||t))}generateDefaultTarget(e){let t=p(e),n=`${p(m(e))}--${t}`;return g(this.configService.getDefaultSymlinkDir()||e,n)}}})),N,P=v((()=>{w(),M(),N=class{validate(e){this.validateType(e.type),this.validateSource(e.source),this.validateForce(e.force)}validateType(e){if(e&&!A.includes(e))throw new C(`Invalid symlink type: ${e}. Must be one of: ${A.join(`, `)}`,`INVALID_SYMLINK_TYPE`)}validateSource(e){if(!e)return;let t=g(e);if(!c(t))throw new C(`Source path does not exist: ${t}`,`SOURCE_NOT_FOUND`)}validateForce(e){if(e!==void 0&&typeof e!=`boolean`)throw new C(`Invalid force option: ${e}. Must be a boolean.`,`INVALID_FORCE_OPTION`)}}})),F,I=v((()=>{M(),D(),S(),P(),F=class{static create(e){let t=new N,n=new _;return new j(t,n,new E(n,new x),e)}}})),L=v((()=>{})),R=v((()=>{})),z=v((()=>{})),B=v((()=>{b(),S(),D(),w(),k(),M(),P(),I(),L(),R(),z()})),V=y((()=>{B();async function e(){console.log(`=== Basic Symlink Creation ===
|
|
5
|
+
`),await F.create({source:process.cwd(),target:h(process.cwd(),`target-symlink`),type:`dir`}).execute()}e().catch(console.error)})),H=y((()=>{V()}));export default H();export{};
|
package/package.json
CHANGED
|
@@ -1,36 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dx-pkg/mksymlink",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "Create symbolic links across platforms (macOS, Windows)",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"main": "./src/index.js",
|
|
8
|
+
"module": "./src/index.mjs",
|
|
8
9
|
"types": "./src/index.d.ts",
|
|
9
10
|
"publishConfig": {
|
|
10
11
|
"access": "public"
|
|
11
12
|
},
|
|
12
13
|
"exports": {
|
|
13
14
|
".": {
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./src/index.d.ts",
|
|
17
|
+
"default": "./src/index.js"
|
|
18
|
+
},
|
|
19
|
+
"import": {
|
|
20
|
+
"types": "./src/index.d.mts",
|
|
21
|
+
"default": "./src/index.mjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"./examples": {
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./examples/index.d.ts",
|
|
27
|
+
"default": "./examples/index.js"
|
|
28
|
+
},
|
|
29
|
+
"import": {
|
|
30
|
+
"types": "./examples/index.d.mts",
|
|
31
|
+
"default": "./examples/index.mjs"
|
|
32
|
+
}
|
|
17
33
|
}
|
|
18
34
|
},
|
|
19
35
|
"bin": {
|
|
20
36
|
"mksymlink": "src/commands/index.js"
|
|
21
37
|
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsc -p tsconfig.prod.json",
|
|
24
|
-
"watch": "tsc -p tsconfig.json --watch",
|
|
25
|
-
"dev": "tsc-watch -b --onSuccess \"npm start\"",
|
|
26
|
-
"start": "node ../../dist/packages/mksymlink/examples/index.js",
|
|
27
|
-
"test": "jest",
|
|
28
|
-
"test:watch": "jest --watch",
|
|
29
|
-
"test:coverage": "jest --coverage",
|
|
30
|
-
"lint": "eslint . --ext .ts",
|
|
31
|
-
"format": "prettier --write \"**/*.{ts,json,md}\"",
|
|
32
|
-
"bin": "node ../../dist/packages/mksymlink/src/commands/index.js"
|
|
33
|
-
},
|
|
34
38
|
"keywords": [
|
|
35
39
|
"symlink",
|
|
36
40
|
"symbolic-link",
|
|
@@ -40,14 +44,8 @@
|
|
|
40
44
|
"cli"
|
|
41
45
|
],
|
|
42
46
|
"dependencies": {
|
|
43
|
-
"@dx-pkg/logger": "^1.0.
|
|
47
|
+
"@dx-pkg/logger": "^1.0.9",
|
|
44
48
|
"chalk": "^5.6.2",
|
|
45
49
|
"commander": "^12.0.0"
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@types/jest": "^30.0.0",
|
|
49
|
-
"@types/node": "^24.10.1",
|
|
50
|
-
"ts-jest": "^29.4.5",
|
|
51
|
-
"tsc-watch": "^7.2.0"
|
|
52
50
|
}
|
|
53
51
|
}
|
package/src/index.d.mts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Logger } from "@dx-pkg/logger";
|
|
2
|
+
type CommandName = string;
|
|
3
|
+
interface CommandOptions {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
interface Command<TOptions extends CommandOptions> {
|
|
7
|
+
execute(options: TOptions): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
interface CommandError extends Error {
|
|
10
|
+
code?: string;
|
|
11
|
+
}
|
|
12
|
+
interface CommandOptionsValidator<TOptions extends CommandOptions> {
|
|
13
|
+
validate(options: TOptions): void;
|
|
14
|
+
}
|
|
15
|
+
type OSPlatform = 'darwin' | 'win32' | 'linux' | 'unknown';
|
|
16
|
+
type WindowsSymlinkType = 'file' | 'dir' | 'junction';
|
|
17
|
+
interface SymlinkOptions {
|
|
18
|
+
source: string;
|
|
19
|
+
target: string;
|
|
20
|
+
type?: WindowsSymlinkType;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface SymlinkResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
source: string;
|
|
26
|
+
target: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
error?: Error;
|
|
29
|
+
}
|
|
30
|
+
interface PlatformInformation {
|
|
31
|
+
getPlatform(): OSPlatform;
|
|
32
|
+
isWindows(): boolean;
|
|
33
|
+
isMacOS(): boolean;
|
|
34
|
+
isLinux(): boolean;
|
|
35
|
+
}
|
|
36
|
+
interface SymlinkOperations {
|
|
37
|
+
createSymlink(options: SymlinkOptions): Promise<SymlinkResult>;
|
|
38
|
+
symlinkExists(path: string): Promise<boolean>;
|
|
39
|
+
removeSymlink(path: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
declare class PlatformDetector implements PlatformInformation {
|
|
42
|
+
private readonly _platform;
|
|
43
|
+
constructor();
|
|
44
|
+
private normalizePlatform;
|
|
45
|
+
getPlatform(): OSPlatform;
|
|
46
|
+
isWindows(): boolean;
|
|
47
|
+
isMacOS(): boolean;
|
|
48
|
+
isLinux(): boolean;
|
|
49
|
+
}
|
|
50
|
+
declare class SymlinkService implements SymlinkOperations {
|
|
51
|
+
private readonly logger;
|
|
52
|
+
private readonly osDetector;
|
|
53
|
+
constructor(logger: Logger, osDetector: PlatformInformation);
|
|
54
|
+
createSymlink(options: SymlinkOptions): Promise<SymlinkResult>;
|
|
55
|
+
private createWindowsSymlink;
|
|
56
|
+
private createUnixSymlink;
|
|
57
|
+
symlinkExists(path: string): Promise<boolean>;
|
|
58
|
+
removeSymlink(path: string): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
declare class SymlinkError extends Error implements CommandError {
|
|
61
|
+
code?: string;
|
|
62
|
+
constructor(message: string, code?: string);
|
|
63
|
+
}
|
|
64
|
+
declare class SymlinkErrorHandler {
|
|
65
|
+
private readonly logger;
|
|
66
|
+
constructor(logger: Logger);
|
|
67
|
+
handle(error: unknown): never;
|
|
68
|
+
}
|
|
69
|
+
interface ConfigData {
|
|
70
|
+
[key: string]: string | undefined;
|
|
71
|
+
}
|
|
72
|
+
declare class ConfigService {
|
|
73
|
+
private readonly configPath;
|
|
74
|
+
private config;
|
|
75
|
+
constructor(configPath?: string);
|
|
76
|
+
get(key: string): string | undefined;
|
|
77
|
+
set(key: string, value: string): void;
|
|
78
|
+
unset(key: string): void;
|
|
79
|
+
list(): ConfigData;
|
|
80
|
+
getDefaultSymlinkDir(): string | undefined;
|
|
81
|
+
setDefaultSymlinkDir(dir: string): void;
|
|
82
|
+
getConfigInfo(): {
|
|
83
|
+
path: string;
|
|
84
|
+
exists: boolean;
|
|
85
|
+
size?: number;
|
|
86
|
+
modified?: Date;
|
|
87
|
+
entries: number;
|
|
88
|
+
};
|
|
89
|
+
private loadConfig;
|
|
90
|
+
private saveConfig;
|
|
91
|
+
}
|
|
92
|
+
declare class MkSymlinkOptionValidator implements CommandOptionsValidator<MkSymlinkCommandOptions> {
|
|
93
|
+
validate(options: MkSymlinkCommandOptions): void;
|
|
94
|
+
private validateType;
|
|
95
|
+
private validateSource;
|
|
96
|
+
private validateForce;
|
|
97
|
+
}
|
|
98
|
+
interface MkSymlinkCommandOptions {
|
|
99
|
+
target?: string;
|
|
100
|
+
source?: string;
|
|
101
|
+
type?: WindowsSymlinkType;
|
|
102
|
+
force?: boolean;
|
|
103
|
+
[key: string]: unknown;
|
|
104
|
+
}
|
|
105
|
+
declare const SYMLINK_TYPES: readonly WindowsSymlinkType[];
|
|
106
|
+
declare class MkSymlinkCommand implements Command<MkSymlinkCommandOptions> {
|
|
107
|
+
private readonly optionValidator;
|
|
108
|
+
private readonly logger;
|
|
109
|
+
private readonly symlinkManager;
|
|
110
|
+
private readonly options;
|
|
111
|
+
private readonly configService;
|
|
112
|
+
constructor(optionValidator: MkSymlinkOptionValidator, logger: Logger, symlinkManager: SymlinkOperations, options: MkSymlinkCommandOptions, configService?: ConfigService);
|
|
113
|
+
execute(): Promise<void>;
|
|
114
|
+
private resolveOptions;
|
|
115
|
+
private resolveTarget;
|
|
116
|
+
private generateDefaultTarget;
|
|
117
|
+
}
|
|
118
|
+
declare class MkSymlinkCommandFactory {
|
|
119
|
+
static create(options: MkSymlinkCommandOptions): MkSymlinkCommand;
|
|
120
|
+
}
|
|
121
|
+
type ConfigAction = 'get' | 'set' | 'unset' | 'list' | 'info';
|
|
122
|
+
interface ConfigCommandOptions {
|
|
123
|
+
action: ConfigAction;
|
|
124
|
+
key?: string;
|
|
125
|
+
value?: string;
|
|
126
|
+
[key: string]: unknown;
|
|
127
|
+
}
|
|
128
|
+
declare class ConfigCommand implements Command<ConfigCommandOptions> {
|
|
129
|
+
private readonly logger;
|
|
130
|
+
private readonly configService;
|
|
131
|
+
private readonly options;
|
|
132
|
+
constructor(logger: Logger, configService: ConfigService, options: ConfigCommandOptions);
|
|
133
|
+
execute(): Promise<void>;
|
|
134
|
+
private handleGet;
|
|
135
|
+
private handleSet;
|
|
136
|
+
private handleUnset;
|
|
137
|
+
private handleList;
|
|
138
|
+
private handleInfo;
|
|
139
|
+
}
|
|
140
|
+
declare class ConfigOptionValidator implements CommandOptionsValidator<ConfigCommandOptions> {
|
|
141
|
+
validate(options: ConfigCommandOptions): void;
|
|
142
|
+
private validateAction;
|
|
143
|
+
private validateKey;
|
|
144
|
+
private validateValue;
|
|
145
|
+
}
|
|
146
|
+
declare class ConfigCommandFactory {
|
|
147
|
+
static create(options: ConfigCommandOptions): ConfigCommand;
|
|
148
|
+
}
|
|
149
|
+
export { Command, CommandError, CommandName, CommandOptions, CommandOptionsValidator, ConfigAction, ConfigCommand, ConfigCommandFactory, ConfigCommandOptions, ConfigData, ConfigOptionValidator, ConfigService, MkSymlinkCommand, MkSymlinkCommandFactory, MkSymlinkCommandOptions, MkSymlinkOptionValidator, OSPlatform, PlatformDetector, PlatformInformation, SYMLINK_TYPES, SymlinkError, SymlinkErrorHandler, SymlinkOperations, SymlinkOptions, SymlinkResult, SymlinkService, WindowsSymlinkType };
|
package/src/index.d.ts
CHANGED
|
@@ -1,11 +1,149 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { Logger } from "@dx-pkg/logger";
|
|
2
|
+
type CommandName = string;
|
|
3
|
+
interface CommandOptions {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
interface Command<TOptions extends CommandOptions> {
|
|
7
|
+
execute(options: TOptions): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
interface CommandError extends Error {
|
|
10
|
+
code?: string;
|
|
11
|
+
}
|
|
12
|
+
interface CommandOptionsValidator<TOptions extends CommandOptions> {
|
|
13
|
+
validate(options: TOptions): void;
|
|
14
|
+
}
|
|
15
|
+
type OSPlatform = 'darwin' | 'win32' | 'linux' | 'unknown';
|
|
16
|
+
type WindowsSymlinkType = 'file' | 'dir' | 'junction';
|
|
17
|
+
interface SymlinkOptions {
|
|
18
|
+
source: string;
|
|
19
|
+
target: string;
|
|
20
|
+
type?: WindowsSymlinkType;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface SymlinkResult {
|
|
24
|
+
success: boolean;
|
|
25
|
+
source: string;
|
|
26
|
+
target: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
error?: Error;
|
|
29
|
+
}
|
|
30
|
+
interface PlatformInformation {
|
|
31
|
+
getPlatform(): OSPlatform;
|
|
32
|
+
isWindows(): boolean;
|
|
33
|
+
isMacOS(): boolean;
|
|
34
|
+
isLinux(): boolean;
|
|
35
|
+
}
|
|
36
|
+
interface SymlinkOperations {
|
|
37
|
+
createSymlink(options: SymlinkOptions): Promise<SymlinkResult>;
|
|
38
|
+
symlinkExists(path: string): Promise<boolean>;
|
|
39
|
+
removeSymlink(path: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
declare class PlatformDetector implements PlatformInformation {
|
|
42
|
+
private readonly _platform;
|
|
43
|
+
constructor();
|
|
44
|
+
private normalizePlatform;
|
|
45
|
+
getPlatform(): OSPlatform;
|
|
46
|
+
isWindows(): boolean;
|
|
47
|
+
isMacOS(): boolean;
|
|
48
|
+
isLinux(): boolean;
|
|
49
|
+
}
|
|
50
|
+
declare class SymlinkService implements SymlinkOperations {
|
|
51
|
+
private readonly logger;
|
|
52
|
+
private readonly osDetector;
|
|
53
|
+
constructor(logger: Logger, osDetector: PlatformInformation);
|
|
54
|
+
createSymlink(options: SymlinkOptions): Promise<SymlinkResult>;
|
|
55
|
+
private createWindowsSymlink;
|
|
56
|
+
private createUnixSymlink;
|
|
57
|
+
symlinkExists(path: string): Promise<boolean>;
|
|
58
|
+
removeSymlink(path: string): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
declare class SymlinkError extends Error implements CommandError {
|
|
61
|
+
code?: string;
|
|
62
|
+
constructor(message: string, code?: string);
|
|
63
|
+
}
|
|
64
|
+
declare class SymlinkErrorHandler {
|
|
65
|
+
private readonly logger;
|
|
66
|
+
constructor(logger: Logger);
|
|
67
|
+
handle(error: unknown): never;
|
|
68
|
+
}
|
|
69
|
+
interface ConfigData {
|
|
70
|
+
[key: string]: string | undefined;
|
|
71
|
+
}
|
|
72
|
+
declare class ConfigService {
|
|
73
|
+
private readonly configPath;
|
|
74
|
+
private config;
|
|
75
|
+
constructor(configPath?: string);
|
|
76
|
+
get(key: string): string | undefined;
|
|
77
|
+
set(key: string, value: string): void;
|
|
78
|
+
unset(key: string): void;
|
|
79
|
+
list(): ConfigData;
|
|
80
|
+
getDefaultSymlinkDir(): string | undefined;
|
|
81
|
+
setDefaultSymlinkDir(dir: string): void;
|
|
82
|
+
getConfigInfo(): {
|
|
83
|
+
path: string;
|
|
84
|
+
exists: boolean;
|
|
85
|
+
size?: number;
|
|
86
|
+
modified?: Date;
|
|
87
|
+
entries: number;
|
|
88
|
+
};
|
|
89
|
+
private loadConfig;
|
|
90
|
+
private saveConfig;
|
|
91
|
+
}
|
|
92
|
+
declare class MkSymlinkOptionValidator implements CommandOptionsValidator<MkSymlinkCommandOptions> {
|
|
93
|
+
validate(options: MkSymlinkCommandOptions): void;
|
|
94
|
+
private validateType;
|
|
95
|
+
private validateSource;
|
|
96
|
+
private validateForce;
|
|
97
|
+
}
|
|
98
|
+
interface MkSymlinkCommandOptions {
|
|
99
|
+
target?: string;
|
|
100
|
+
source?: string;
|
|
101
|
+
type?: WindowsSymlinkType;
|
|
102
|
+
force?: boolean;
|
|
103
|
+
[key: string]: unknown;
|
|
104
|
+
}
|
|
105
|
+
declare const SYMLINK_TYPES: readonly WindowsSymlinkType[];
|
|
106
|
+
declare class MkSymlinkCommand implements Command<MkSymlinkCommandOptions> {
|
|
107
|
+
private readonly optionValidator;
|
|
108
|
+
private readonly logger;
|
|
109
|
+
private readonly symlinkManager;
|
|
110
|
+
private readonly options;
|
|
111
|
+
private readonly configService;
|
|
112
|
+
constructor(optionValidator: MkSymlinkOptionValidator, logger: Logger, symlinkManager: SymlinkOperations, options: MkSymlinkCommandOptions, configService?: ConfigService);
|
|
113
|
+
execute(): Promise<void>;
|
|
114
|
+
private resolveOptions;
|
|
115
|
+
private resolveTarget;
|
|
116
|
+
private generateDefaultTarget;
|
|
117
|
+
}
|
|
118
|
+
declare class MkSymlinkCommandFactory {
|
|
119
|
+
static create(options: MkSymlinkCommandOptions): MkSymlinkCommand;
|
|
120
|
+
}
|
|
121
|
+
type ConfigAction = 'get' | 'set' | 'unset' | 'list' | 'info';
|
|
122
|
+
interface ConfigCommandOptions {
|
|
123
|
+
action: ConfigAction;
|
|
124
|
+
key?: string;
|
|
125
|
+
value?: string;
|
|
126
|
+
[key: string]: unknown;
|
|
127
|
+
}
|
|
128
|
+
declare class ConfigCommand implements Command<ConfigCommandOptions> {
|
|
129
|
+
private readonly logger;
|
|
130
|
+
private readonly configService;
|
|
131
|
+
private readonly options;
|
|
132
|
+
constructor(logger: Logger, configService: ConfigService, options: ConfigCommandOptions);
|
|
133
|
+
execute(): Promise<void>;
|
|
134
|
+
private handleGet;
|
|
135
|
+
private handleSet;
|
|
136
|
+
private handleUnset;
|
|
137
|
+
private handleList;
|
|
138
|
+
private handleInfo;
|
|
139
|
+
}
|
|
140
|
+
declare class ConfigOptionValidator implements CommandOptionsValidator<ConfigCommandOptions> {
|
|
141
|
+
validate(options: ConfigCommandOptions): void;
|
|
142
|
+
private validateAction;
|
|
143
|
+
private validateKey;
|
|
144
|
+
private validateValue;
|
|
145
|
+
}
|
|
146
|
+
declare class ConfigCommandFactory {
|
|
147
|
+
static create(options: ConfigCommandOptions): ConfigCommand;
|
|
148
|
+
}
|
|
149
|
+
export { Command, CommandError, CommandName, CommandOptions, CommandOptionsValidator, ConfigAction, ConfigCommand, ConfigCommandFactory, ConfigCommandOptions, ConfigData, ConfigOptionValidator, ConfigService, MkSymlinkCommand, MkSymlinkCommandFactory, MkSymlinkCommandOptions, MkSymlinkOptionValidator, OSPlatform, PlatformDetector, PlatformInformation, SYMLINK_TYPES, SymlinkError, SymlinkErrorHandler, SymlinkOperations, SymlinkOptions, SymlinkResult, SymlinkService, WindowsSymlinkType };
|
package/src/index.js
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./types"), exports);
|
|
18
|
-
__exportStar(require("./services/platform-detector"), exports);
|
|
19
|
-
__exportStar(require("./services/symlink.service"), exports);
|
|
20
|
-
__exportStar(require("./services/symlink-error"), exports);
|
|
21
|
-
__exportStar(require("./services/config.service"), exports);
|
|
22
|
-
__exportStar(require("./commands/create/mksymlink.command"), exports);
|
|
23
|
-
__exportStar(require("./commands/create/mksymlink.option-validator"), exports);
|
|
24
|
-
__exportStar(require("./commands/create/mksymlink.command-factory"), exports);
|
|
25
|
-
__exportStar(require("./commands/config/config.command"), exports);
|
|
26
|
-
__exportStar(require("./commands/config/config.option-validator"), exports);
|
|
27
|
-
__exportStar(require("./commands/config/config.command-factory"), exports);
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`os`),t=require(`child_process`),n=require(`util`),r=require(`fs/promises`),i=require(`fs`),a=require(`path`),o=require(`@dx-pkg/logger`);var s=class{_platform;constructor(){this._platform=this.normalizePlatform((0,e.platform)())}normalizePlatform(e){switch(e){case`darwin`:return`darwin`;case`win32`:return`win32`;case`linux`:return`linux`;default:return`unknown`}}getPlatform(){return this._platform}isWindows(){return this._platform===`win32`}isMacOS(){return this._platform===`darwin`}isLinux(){return this._platform===`linux`}},c=class extends Error{code;constructor(e,t){super(e),this.name=`SymlinkError`,this.code=t,Error.captureStackTrace(this,this.constructor)}},l=class{constructor(e){this.logger=e}handle(e){throw e instanceof c?(this.logger.error(`Symlink Error [${e.code||`UNKNOWN`}]: ${e.message}`),e):e instanceof Error?(this.logger.error(`Unexpected Error: ${e.message}`),new c(e.message,`UNEXPECTED_ERROR`)):(this.logger.error(`Unknown Error: ${String(e)}`),new c(String(e),`UNKNOWN_ERROR`))}};const u=(0,n.promisify)(t.exec);var d=class{constructor(e,t){this.logger=e,this.osDetector=t}async createSymlink(e){let{source:t,target:n,type:r=`dir`,force:i=!1}=e;try{if(await this.symlinkExists(n)){if(!i)return{success:!1,source:t,target:n,message:`Symlink already exists: ${n}`};this.logger.info(`Force mode enabled. Removing existing symlink: ${n}`),await this.removeSymlink(n)}return this.osDetector.isWindows()?await this.createWindowsSymlink(t,n,r):await this.createUnixSymlink(t,n),{success:!0,source:t,target:n,message:`Symlink created successfully`}}catch(e){return this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),{success:!1,source:t,target:n,error:e instanceof Error?e:Error(String(e))}}}async createWindowsSymlink(e,t,n){let r;switch(n){case`junction`:r=`/J`;break;case`file`:r=``;break;default:r=`/D`;break}let i=r?`mklink ${r} "${t}" "${e}"`:`mklink "${t}" "${e}"`;this.logger.info(`Executing Windows command: ${i}`);try{let{stdout:e,stderr:t}=await u(i,{shell:`cmd.exe`});if(t&&!t.includes(`Junction`)&&!t.includes(`symbolic link`))throw new c(t,`WINDOWS_MKLINK_ERROR`);this.logger.info(`Windows mklink output: ${e}`)}catch(e){throw new c(`Failed to create Windows symlink: ${e instanceof Error?e.message:String(e)}`,`WINDOWS_MKLINK_FAILED`)}}async createUnixSymlink(e,t){try{await(0,r.symlink)(e,t),this.logger.info(`Unix symlink created: ln -s ${e} ${t}`)}catch(e){throw new c(`Failed to create Unix symlink: ${e instanceof Error?e.message:String(e)}`,`UNIX_SYMLINK_FAILED`)}}async symlinkExists(e){try{return(await(0,r.lstat)(e)).isSymbolicLink()}catch{return!1}}async removeSymlink(e){try{await(0,r.access)(e),await(0,r.unlink)(e),this.logger.info(`Symlink removed: ${e}`)}catch(e){throw new c(`Failed to remove symlink: ${e instanceof Error?e.message:String(e)}`,`REMOVE_SYMLINK_FAILED`)}}},f=class{configPath;config={};constructor(t){let n=(0,e.homedir)();this.configPath=t||(0,a.resolve)(n,`.mksymlinkrc`),this.loadConfig()}get(e){return this.config[e]}set(e,t){this.config[e]=t,this.saveConfig()}unset(e){delete this.config[e],this.saveConfig()}list(){return{...this.config}}getDefaultSymlinkDir(){return this.get(`symlink.defaultDir`)}setDefaultSymlinkDir(e){this.set(`symlink.defaultDir`,e)}getConfigInfo(){let e=(0,i.existsSync)(this.configPath),t=Object.keys(this.config).length;if(!e)return{path:this.configPath,exists:!1,entries:t};let n=(0,i.statSync)(this.configPath);return{path:this.configPath,exists:!0,size:n.size,modified:n.mtime,entries:t}}loadConfig(){if(!(0,i.existsSync)(this.configPath)){this.config={};return}try{let e=(0,i.readFileSync)(this.configPath,`utf-8`).split(`
|
|
2
|
+
`).filter(e=>e.trim());this.config={};for(let t of e){let[e,...n]=t.split(`=`);e&&n.length>0&&(this.config[e.trim()]=n.join(`=`).trim())}}catch(e){throw Error(`Failed to load config from ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}saveConfig(){try{let e=(0,a.dirname)(this.configPath);(0,i.existsSync)(e)||(0,i.mkdirSync)(e,{recursive:!0});let t=Object.entries(this.config).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${t}`).join(`
|
|
3
|
+
`);(0,i.writeFileSync)(this.configPath,t+`
|
|
4
|
+
`,`utf-8`)}catch(e){throw Error(`Failed to save config to ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}};const p=[`file`,`dir`,`junction`];var m=class{constructor(e,t,n,r,i=new f){this.optionValidator=e,this.logger=t,this.symlinkManager=n,this.options=r,this.configService=i}async execute(){this.optionValidator.validate(this.options);try{let{source:e,target:t,type:n,force:r}=this.resolveOptions();this.logger.info(`Creating symlink with options:`),this.logger.info(` Source: ${e}`),this.logger.info(` Target: ${t}`),this.logger.info(` Type: ${n}`),this.logger.info(` Force: ${r}`);let i=await this.symlinkManager.createSymlink({source:e,target:t,type:n,force:r});if(!i.success){if(i.error)throw i.error;this.logger.warning(i.message||`Symlink creation failed`);return}this.logger.success(`Symlink created successfully!`),this.logger.info(` Source: ${i.source}`),this.logger.info(` Target: ${i.target}`)}catch(e){throw this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),e}}resolveOptions(){let e=process.cwd();return{source:this.options.source||e,target:this.resolveTarget(this.options)||this.generateDefaultTarget(e),type:this.options.type||`junction`,force:this.options.force||!1}}resolveTarget(e){if(e.target!==`.`&&e.target!==`./`)return e.target;let t=process.cwd();return(0,a.resolve)(t,(0,a.basename)(e.source||t))}generateDefaultTarget(e){let t=(0,a.basename)(e),n=`${(0,a.basename)((0,a.dirname)(e))}--${t}`;return(0,a.resolve)(this.configService.getDefaultSymlinkDir()||e,n)}},h=class{validate(e){this.validateType(e.type),this.validateSource(e.source),this.validateForce(e.force)}validateType(e){if(e&&!p.includes(e))throw new c(`Invalid symlink type: ${e}. Must be one of: ${p.join(`, `)}`,`INVALID_SYMLINK_TYPE`)}validateSource(e){if(!e)return;let t=(0,a.resolve)(e);if(!(0,i.existsSync)(t))throw new c(`Source path does not exist: ${t}`,`SOURCE_NOT_FOUND`)}validateForce(e){if(e!==void 0&&typeof e!=`boolean`)throw new c(`Invalid force option: ${e}. Must be a boolean.`,`INVALID_FORCE_OPTION`)}},g=class{static create(e){let t=new h,n=new o.ConsoleLogger;return new m(t,n,new d(n,new s),e)}},_=class{constructor(e,t,n){this.logger=e,this.configService=t,this.options=n}async execute(){try{let{action:e,key:t,value:n}=this.options;switch(e){case`get`:await this.handleGet(t);break;case`set`:await this.handleSet(t,n);break;case`unset`:await this.handleUnset(t);break;case`list`:await this.handleList();break;case`info`:await this.handleInfo();break;default:throw Error(`Unknown config action: ${e}`)}}catch(e){throw this.logger.error(`Config command failed: ${e instanceof Error?e.message:String(e)}`),e}}async handleGet(e){if(!e)throw Error(`Key is required for get action`);let t=this.configService.get(e);if(t===void 0){this.logger.warning(`Config key '${e}' not found`);return}this.logger.info(t)}async handleSet(e,t){if(!e)throw Error(`Key is required for set action`);if(!t)throw Error(`Value is required for set action`);this.configService.set(e,t),this.logger.success(`Config set: ${e} = ${t}`)}async handleUnset(e){if(!e)throw Error(`Key is required for unset action`);this.configService.unset(e),this.logger.success(`Config unset: ${e}`)}async handleList(){let e=this.configService.list(),t=Object.entries(e);if(t.length===0){this.logger.info(`No configuration found`);return}this.logger.info(`Current configuration:`);for(let[e,n]of t)this.logger.info(` ${e} = ${n}`)}async handleInfo(){let e=this.configService.getConfigInfo();this.logger.info(`Configuration file information:`),this.logger.info(` Path: ${e.path}`),this.logger.info(` Exists: ${e.exists?`Yes`:`No`}`),e.exists&&(this.logger.info(` Size: ${e.size} bytes`),this.logger.info(` Modified: ${e.modified?.toLocaleString()}`)),this.logger.info(` Entries: ${e.entries}`)}};const v=[`get`,`set`,`unset`,`list`,`info`];var y=class{validate(e){this.validateAction(e.action),this.validateKey(e.action,e.key),this.validateValue(e.action,e.value)}validateAction(e){if(!v.includes(e))throw new c(`Invalid config action: ${e}. Must be one of: ${v.join(`, `)}`,`INVALID_CONFIG_ACTION`)}validateKey(e,t){if(!(e===`list`||e===`info`)){if(!t)throw new c(`Key is required for '${e}' action`,`MISSING_CONFIG_KEY`);if(typeof t!=`string`||t.trim().length===0)throw new c(`Invalid config key: ${t}. Key must be a non-empty string.`,`INVALID_CONFIG_KEY`)}}validateValue(e,t){if(e===`set`){if(!t)throw new c(`Value is required for 'set' action`,`MISSING_CONFIG_VALUE`);if(typeof t!=`string`)throw new c(`Invalid config value: ${t}. Value must be a string.`,`INVALID_CONFIG_VALUE`)}}},b=class{static create(e){return new y().validate(e),new _(new o.ConsoleLogger,new f,e)}};exports.ConfigCommand=_,exports.ConfigCommandFactory=b,exports.ConfigOptionValidator=y,exports.ConfigService=f,exports.MkSymlinkCommand=m,exports.MkSymlinkCommandFactory=g,exports.MkSymlinkOptionValidator=h,exports.PlatformDetector=s,exports.SYMLINK_TYPES=p,exports.SymlinkError=c,exports.SymlinkErrorHandler=l,exports.SymlinkService=d;
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{homedir as e,platform as t}from"os";import{exec as n}from"child_process";import{promisify as r}from"util";import{access as i,lstat as a,symlink as o,unlink as s}from"fs/promises";import{existsSync as c,mkdirSync as l,readFileSync as u,statSync as d,writeFileSync as f}from"fs";import{basename as p,dirname as m,resolve as h}from"path";import{ConsoleLogger as g}from"@dx-pkg/logger";var _=class{_platform;constructor(){this._platform=this.normalizePlatform(t())}normalizePlatform(e){switch(e){case`darwin`:return`darwin`;case`win32`:return`win32`;case`linux`:return`linux`;default:return`unknown`}}getPlatform(){return this._platform}isWindows(){return this._platform===`win32`}isMacOS(){return this._platform===`darwin`}isLinux(){return this._platform===`linux`}},v=class extends Error{code;constructor(e,t){super(e),this.name=`SymlinkError`,this.code=t,Error.captureStackTrace(this,this.constructor)}},y=class{constructor(e){this.logger=e}handle(e){throw e instanceof v?(this.logger.error(`Symlink Error [${e.code||`UNKNOWN`}]: ${e.message}`),e):e instanceof Error?(this.logger.error(`Unexpected Error: ${e.message}`),new v(e.message,`UNEXPECTED_ERROR`)):(this.logger.error(`Unknown Error: ${String(e)}`),new v(String(e),`UNKNOWN_ERROR`))}};const b=r(n);var x=class{constructor(e,t){this.logger=e,this.osDetector=t}async createSymlink(e){let{source:t,target:n,type:r=`dir`,force:i=!1}=e;try{if(await this.symlinkExists(n)){if(!i)return{success:!1,source:t,target:n,message:`Symlink already exists: ${n}`};this.logger.info(`Force mode enabled. Removing existing symlink: ${n}`),await this.removeSymlink(n)}return this.osDetector.isWindows()?await this.createWindowsSymlink(t,n,r):await this.createUnixSymlink(t,n),{success:!0,source:t,target:n,message:`Symlink created successfully`}}catch(e){return this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),{success:!1,source:t,target:n,error:e instanceof Error?e:Error(String(e))}}}async createWindowsSymlink(e,t,n){let r;switch(n){case`junction`:r=`/J`;break;case`file`:r=``;break;default:r=`/D`;break}let i=r?`mklink ${r} "${t}" "${e}"`:`mklink "${t}" "${e}"`;this.logger.info(`Executing Windows command: ${i}`);try{let{stdout:e,stderr:t}=await b(i,{shell:`cmd.exe`});if(t&&!t.includes(`Junction`)&&!t.includes(`symbolic link`))throw new v(t,`WINDOWS_MKLINK_ERROR`);this.logger.info(`Windows mklink output: ${e}`)}catch(e){throw new v(`Failed to create Windows symlink: ${e instanceof Error?e.message:String(e)}`,`WINDOWS_MKLINK_FAILED`)}}async createUnixSymlink(e,t){try{await o(e,t),this.logger.info(`Unix symlink created: ln -s ${e} ${t}`)}catch(e){throw new v(`Failed to create Unix symlink: ${e instanceof Error?e.message:String(e)}`,`UNIX_SYMLINK_FAILED`)}}async symlinkExists(e){try{return(await a(e)).isSymbolicLink()}catch{return!1}}async removeSymlink(e){try{await i(e),await s(e),this.logger.info(`Symlink removed: ${e}`)}catch(e){throw new v(`Failed to remove symlink: ${e instanceof Error?e.message:String(e)}`,`REMOVE_SYMLINK_FAILED`)}}},S=class{configPath;config={};constructor(t){let n=e();this.configPath=t||h(n,`.mksymlinkrc`),this.loadConfig()}get(e){return this.config[e]}set(e,t){this.config[e]=t,this.saveConfig()}unset(e){delete this.config[e],this.saveConfig()}list(){return{...this.config}}getDefaultSymlinkDir(){return this.get(`symlink.defaultDir`)}setDefaultSymlinkDir(e){this.set(`symlink.defaultDir`,e)}getConfigInfo(){let e=c(this.configPath),t=Object.keys(this.config).length;if(!e)return{path:this.configPath,exists:!1,entries:t};let n=d(this.configPath);return{path:this.configPath,exists:!0,size:n.size,modified:n.mtime,entries:t}}loadConfig(){if(!c(this.configPath)){this.config={};return}try{let e=u(this.configPath,`utf-8`).split(`
|
|
2
|
+
`).filter(e=>e.trim());this.config={};for(let t of e){let[e,...n]=t.split(`=`);e&&n.length>0&&(this.config[e.trim()]=n.join(`=`).trim())}}catch(e){throw Error(`Failed to load config from ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}saveConfig(){try{let e=m(this.configPath);c(e)||l(e,{recursive:!0});let t=Object.entries(this.config).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}=${t}`).join(`
|
|
3
|
+
`);f(this.configPath,t+`
|
|
4
|
+
`,`utf-8`)}catch(e){throw Error(`Failed to save config to ${this.configPath}: ${e instanceof Error?e.message:String(e)}`)}}};const C=[`file`,`dir`,`junction`];var w=class{constructor(e,t,n,r,i=new S){this.optionValidator=e,this.logger=t,this.symlinkManager=n,this.options=r,this.configService=i}async execute(){this.optionValidator.validate(this.options);try{let{source:e,target:t,type:n,force:r}=this.resolveOptions();this.logger.info(`Creating symlink with options:`),this.logger.info(` Source: ${e}`),this.logger.info(` Target: ${t}`),this.logger.info(` Type: ${n}`),this.logger.info(` Force: ${r}`);let i=await this.symlinkManager.createSymlink({source:e,target:t,type:n,force:r});if(!i.success){if(i.error)throw i.error;this.logger.warning(i.message||`Symlink creation failed`);return}this.logger.success(`Symlink created successfully!`),this.logger.info(` Source: ${i.source}`),this.logger.info(` Target: ${i.target}`)}catch(e){throw this.logger.error(`Failed to create symlink: ${e instanceof Error?e.message:String(e)}`),e}}resolveOptions(){let e=process.cwd();return{source:this.options.source||e,target:this.resolveTarget(this.options)||this.generateDefaultTarget(e),type:this.options.type||`junction`,force:this.options.force||!1}}resolveTarget(e){if(e.target!==`.`&&e.target!==`./`)return e.target;let t=process.cwd();return h(t,p(e.source||t))}generateDefaultTarget(e){let t=p(e),n=`${p(m(e))}--${t}`;return h(this.configService.getDefaultSymlinkDir()||e,n)}},T=class{validate(e){this.validateType(e.type),this.validateSource(e.source),this.validateForce(e.force)}validateType(e){if(e&&!C.includes(e))throw new v(`Invalid symlink type: ${e}. Must be one of: ${C.join(`, `)}`,`INVALID_SYMLINK_TYPE`)}validateSource(e){if(!e)return;let t=h(e);if(!c(t))throw new v(`Source path does not exist: ${t}`,`SOURCE_NOT_FOUND`)}validateForce(e){if(e!==void 0&&typeof e!=`boolean`)throw new v(`Invalid force option: ${e}. Must be a boolean.`,`INVALID_FORCE_OPTION`)}},E=class{static create(e){let t=new T,n=new g;return new w(t,n,new x(n,new _),e)}},D=class{constructor(e,t,n){this.logger=e,this.configService=t,this.options=n}async execute(){try{let{action:e,key:t,value:n}=this.options;switch(e){case`get`:await this.handleGet(t);break;case`set`:await this.handleSet(t,n);break;case`unset`:await this.handleUnset(t);break;case`list`:await this.handleList();break;case`info`:await this.handleInfo();break;default:throw Error(`Unknown config action: ${e}`)}}catch(e){throw this.logger.error(`Config command failed: ${e instanceof Error?e.message:String(e)}`),e}}async handleGet(e){if(!e)throw Error(`Key is required for get action`);let t=this.configService.get(e);if(t===void 0){this.logger.warning(`Config key '${e}' not found`);return}this.logger.info(t)}async handleSet(e,t){if(!e)throw Error(`Key is required for set action`);if(!t)throw Error(`Value is required for set action`);this.configService.set(e,t),this.logger.success(`Config set: ${e} = ${t}`)}async handleUnset(e){if(!e)throw Error(`Key is required for unset action`);this.configService.unset(e),this.logger.success(`Config unset: ${e}`)}async handleList(){let e=this.configService.list(),t=Object.entries(e);if(t.length===0){this.logger.info(`No configuration found`);return}this.logger.info(`Current configuration:`);for(let[e,n]of t)this.logger.info(` ${e} = ${n}`)}async handleInfo(){let e=this.configService.getConfigInfo();this.logger.info(`Configuration file information:`),this.logger.info(` Path: ${e.path}`),this.logger.info(` Exists: ${e.exists?`Yes`:`No`}`),e.exists&&(this.logger.info(` Size: ${e.size} bytes`),this.logger.info(` Modified: ${e.modified?.toLocaleString()}`)),this.logger.info(` Entries: ${e.entries}`)}};const O=[`get`,`set`,`unset`,`list`,`info`];var k=class{validate(e){this.validateAction(e.action),this.validateKey(e.action,e.key),this.validateValue(e.action,e.value)}validateAction(e){if(!O.includes(e))throw new v(`Invalid config action: ${e}. Must be one of: ${O.join(`, `)}`,`INVALID_CONFIG_ACTION`)}validateKey(e,t){if(!(e===`list`||e===`info`)){if(!t)throw new v(`Key is required for '${e}' action`,`MISSING_CONFIG_KEY`);if(typeof t!=`string`||t.trim().length===0)throw new v(`Invalid config key: ${t}. Key must be a non-empty string.`,`INVALID_CONFIG_KEY`)}}validateValue(e,t){if(e===`set`){if(!t)throw new v(`Value is required for 'set' action`,`MISSING_CONFIG_VALUE`);if(typeof t!=`string`)throw new v(`Invalid config value: ${t}. Value must be a string.`,`INVALID_CONFIG_VALUE`)}}},A=class{static create(e){return new k().validate(e),new D(new g,new S,e)}};export{D as ConfigCommand,A as ConfigCommandFactory,k as ConfigOptionValidator,S as ConfigService,w as MkSymlinkCommand,E as MkSymlinkCommandFactory,T as MkSymlinkOptionValidator,_ as PlatformDetector,C as SYMLINK_TYPES,v as SymlinkError,y as SymlinkErrorHandler,x as SymlinkService};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const src_1 = require("../src");
|
|
4
|
-
const logger_1 = require("@dx-pkg/logger");
|
|
5
|
-
async function advancedExample() {
|
|
6
|
-
console.log('=== Advanced Symlink Manager Usage ===\n');
|
|
7
|
-
const logger = new logger_1.ConsoleLogger();
|
|
8
|
-
const osDetector = new src_1.PlatformDetector();
|
|
9
|
-
const symlinkManager = new src_1.SymlinkService(logger, osDetector);
|
|
10
|
-
console.log(`Detected OS: ${osDetector.getPlatform()}\n`);
|
|
11
|
-
const source = process.cwd();
|
|
12
|
-
const target = '/tmp/advanced-symlink';
|
|
13
|
-
console.log('Checking if symlink exists...');
|
|
14
|
-
const exists = await symlinkManager.symlinkExists(target);
|
|
15
|
-
console.log(`Symlink exists: ${exists}\n`);
|
|
16
|
-
if (exists) {
|
|
17
|
-
console.log('Removing existing symlink...');
|
|
18
|
-
await symlinkManager.removeSymlink(target);
|
|
19
|
-
console.log('Removed successfully\n');
|
|
20
|
-
}
|
|
21
|
-
console.log('Creating new symlink...');
|
|
22
|
-
const result = await symlinkManager.createSymlink({
|
|
23
|
-
source,
|
|
24
|
-
target,
|
|
25
|
-
type: osDetector.isWindows() ? 'junction' : 'dir',
|
|
26
|
-
force: false,
|
|
27
|
-
});
|
|
28
|
-
if (result.success) {
|
|
29
|
-
console.log('\nSymlink created successfully!');
|
|
30
|
-
console.log(` Source: ${result.source}`);
|
|
31
|
-
console.log(` Target: ${result.target}`);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
console.error('\nFailed to create symlink:');
|
|
35
|
-
console.error(` ${result.message || result.error?.message}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
advancedExample().catch(console.error);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/examples/basic-usage.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const src_1 = require("../src");
|
|
4
|
-
const path_1 = require("path");
|
|
5
|
-
async function basicExample() {
|
|
6
|
-
console.log('=== Basic Symlink Creation ===\n');
|
|
7
|
-
const command = src_1.MkSymlinkCommandFactory.create({
|
|
8
|
-
source: process.cwd(),
|
|
9
|
-
target: (0, path_1.join)(process.cwd(), 'target-symlink'),
|
|
10
|
-
type: 'dir',
|
|
11
|
-
});
|
|
12
|
-
await command.execute();
|
|
13
|
-
}
|
|
14
|
-
basicExample().catch(console.error);
|
package/examples/config-usage.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.configExamples = configExamples;
|
|
4
|
-
const config_command_factory_1 = require("../src/commands/config/config.command-factory");
|
|
5
|
-
const path_1 = require("path");
|
|
6
|
-
const os_1 = require("os");
|
|
7
|
-
async function configExamples() {
|
|
8
|
-
console.log('=== Config Command Examples ===\n');
|
|
9
|
-
try {
|
|
10
|
-
// Example 1: List all configuration
|
|
11
|
-
console.log('1. List all configuration:');
|
|
12
|
-
const listCommand = config_command_factory_1.ConfigCommandFactory.create({ action: 'list' });
|
|
13
|
-
await listCommand.execute();
|
|
14
|
-
console.log('');
|
|
15
|
-
// Example 2: Set default symlink directory
|
|
16
|
-
console.log('2. Set default symlink directory:');
|
|
17
|
-
const setCommand = config_command_factory_1.ConfigCommandFactory.create({
|
|
18
|
-
action: 'set',
|
|
19
|
-
key: 'symlink.defaultDir',
|
|
20
|
-
value: (0, path_1.join)((0, os_1.homedir)(), 'symlinks'),
|
|
21
|
-
});
|
|
22
|
-
await setCommand.execute();
|
|
23
|
-
console.log('');
|
|
24
|
-
// Example 3: Get a specific config value
|
|
25
|
-
console.log('3. Get default symlink directory:');
|
|
26
|
-
const getCommand = config_command_factory_1.ConfigCommandFactory.create({
|
|
27
|
-
action: 'get',
|
|
28
|
-
key: 'symlink.defaultDir',
|
|
29
|
-
});
|
|
30
|
-
await getCommand.execute();
|
|
31
|
-
console.log('');
|
|
32
|
-
// Example 4: Set a custom config key
|
|
33
|
-
console.log('4. Set a custom config key:');
|
|
34
|
-
const setCustomCommand = config_command_factory_1.ConfigCommandFactory.create({
|
|
35
|
-
action: 'set',
|
|
36
|
-
key: 'user.name',
|
|
37
|
-
value: 'John Doe',
|
|
38
|
-
});
|
|
39
|
-
await setCustomCommand.execute();
|
|
40
|
-
console.log('');
|
|
41
|
-
// Example 5: List all configuration again (to see changes)
|
|
42
|
-
console.log('5. List all configuration (after changes):');
|
|
43
|
-
const listCommand2 = config_command_factory_1.ConfigCommandFactory.create({ action: 'list' });
|
|
44
|
-
await listCommand2.execute();
|
|
45
|
-
console.log('');
|
|
46
|
-
// Example 6: Unset a config value
|
|
47
|
-
console.log('6. Unset user.name:');
|
|
48
|
-
const unsetCommand = config_command_factory_1.ConfigCommandFactory.create({
|
|
49
|
-
action: 'unset',
|
|
50
|
-
key: 'user.name',
|
|
51
|
-
});
|
|
52
|
-
await unsetCommand.execute();
|
|
53
|
-
console.log('');
|
|
54
|
-
// Example 7: List configuration one more time
|
|
55
|
-
console.log('7. List configuration (after unset):');
|
|
56
|
-
const listCommand3 = config_command_factory_1.ConfigCommandFactory.create({ action: 'list' });
|
|
57
|
-
await listCommand3.execute();
|
|
58
|
-
console.log('');
|
|
59
|
-
console.log('=== Config Examples Completed ===\n');
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
console.error('Error running config examples:', error);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|